@axhub/genie 0.2.5 → 0.2.7
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/assets/App-BWSqiXAT.js +220 -0
- package/dist/assets/App-DrlLKa8f.css +1 -0
- package/dist/assets/ReviewApp-nz3mbArg.js +1 -0
- package/dist/assets/{_basePickBy-CFRQvihx.js → _basePickBy-C19AekOu.js} +1 -1
- package/dist/assets/{_baseUniq-Dhh8nCvs.js → _baseUniq-JsnevLw_.js} +1 -1
- package/dist/assets/{arc-DQ0v3dU4.js → arc-BLpcuBlf.js} +1 -1
- package/dist/assets/architectureDiagram-2XIMDMQ5-CarjBOOv.js +36 -0
- package/dist/assets/{blockDiagram-WCTKOSBZ-Bbxhj5KC.js → blockDiagram-WCTKOSBZ-DQBLwsUS.js} +3 -3
- package/dist/assets/c4Diagram-IC4MRINW-CGobwBIj.js +10 -0
- package/dist/assets/channel-DkFNxV_H.js +1 -0
- package/dist/assets/{chunk-4BX2VUAB-DlvtrM0q.js → chunk-4BX2VUAB-De63kbgc.js} +1 -1
- package/dist/assets/{chunk-55IACEB6-DJUSHyTa.js → chunk-55IACEB6-DtTDDdM9.js} +1 -1
- package/dist/assets/{chunk-FMBD7UC4-C6Ch-htf.js → chunk-FMBD7UC4-DHuwd8tw.js} +1 -1
- package/dist/assets/{chunk-JSJVCQXG-DzQIht58.js → chunk-JSJVCQXG-BgytFtmO.js} +1 -1
- package/dist/assets/{chunk-KX2RTZJC-C05jARMH.js → chunk-KX2RTZJC-nZdp86aN.js} +1 -1
- package/dist/assets/chunk-NQ4KR5QH-CMH6EDP2.js +220 -0
- package/dist/assets/{chunk-QZHKN3VN-jxti9HTX.js → chunk-QZHKN3VN-DvUQ3mnO.js} +1 -1
- package/dist/assets/chunk-WL4C6EOR-Dn7db_6t.js +189 -0
- package/dist/assets/classDiagram-VBA2DB6C-DtwCEe8S.js +1 -0
- package/dist/assets/classDiagram-v2-RAHNMMFH-DtwCEe8S.js +1 -0
- package/dist/assets/clone-C0lCEIEO.js +1 -0
- package/dist/assets/cose-bilkent-S5V4N54A-DD_nzqsz.js +1 -0
- package/dist/assets/cytoscape.esm-5J0xJHOV.js +321 -0
- package/dist/assets/{dagre-KLK3FWXG-DJ3dNSYk.js → dagre-KLK3FWXG-CHYIvW47.js} +1 -1
- package/dist/assets/diagram-E7M64L7V-TVdvHtGc.js +24 -0
- package/dist/assets/{diagram-IFDJBPK2-Da6K4aP-.js → diagram-IFDJBPK2-Dzsiln_C.js} +1 -1
- package/dist/assets/{diagram-P4PSJMXO-vZZKB92A.js → diagram-P4PSJMXO-DKnGbUpE.js} +1 -1
- package/dist/assets/erDiagram-INFDFZHY-5Kw0bByo.js +70 -0
- package/dist/assets/{flowDiagram-PKNHOUZH-DUV13pHi.js → flowDiagram-PKNHOUZH-BAZ2-jKp.js} +4 -4
- package/dist/assets/ganttDiagram-A5KZAMGK-CsADFkcq.js +292 -0
- package/dist/assets/{gitGraphDiagram-K3NZZRJ6-BZ5gW69I.js → gitGraphDiagram-K3NZZRJ6-BflpyjGy.js} +1 -1
- package/dist/assets/{graph-BbvHswRd.js → graph-suelaXFh.js} +1 -1
- package/dist/assets/highlighted-body-OFNGDK62-CZrBMazC.js +1 -0
- package/dist/assets/index-B01NxbUv.css +1 -0
- package/dist/assets/index-DW5pGgQ_.js +2 -0
- package/dist/assets/{infoDiagram-LFFYTUFH-8auUIPKW.js → infoDiagram-LFFYTUFH-pfD1FA3p.js} +1 -1
- package/dist/assets/ishikawaDiagram-PHBUUO56-ndm9snwO.js +70 -0
- package/dist/assets/journeyDiagram-4ABVD52K-HgF2t7z5.js +139 -0
- package/dist/assets/{kanban-definition-K7BYSVSG-Bappd2YO.js → kanban-definition-K7BYSVSG-FWinmur1.js} +5 -5
- package/dist/assets/{layout-BmbfFZKy.js → layout-vcz43XvZ.js} +1 -1
- package/dist/assets/{linear-WZnF-PT6.js → linear-le4gc0vx.js} +1 -1
- package/dist/assets/mermaid-GHXKKRXX-CK8m3lad.js +870 -0
- package/dist/assets/mindmap-definition-YRQLILUH-CNq9SKj4.js +68 -0
- package/dist/assets/{pieDiagram-SKSYHLDU-uxjlAy1t.js → pieDiagram-SKSYHLDU-C7PKDh3b.js} +2 -2
- package/dist/assets/quadrantDiagram-337W2JSQ-B7FnztNO.js +7 -0
- package/dist/assets/requirementDiagram-Z7DCOOCP-Bl_BM2Th.js +73 -0
- package/dist/assets/{sankeyDiagram-WA2Y5GQK-2-FHHM-R.js → sankeyDiagram-WA2Y5GQK-4gulcOP4.js} +3 -3
- package/dist/assets/sequenceDiagram-2WXFIKYE-VEuJDwyJ.js +145 -0
- package/dist/assets/{stateDiagram-RAJIS63D-DoW8U53H.js → stateDiagram-RAJIS63D-CB4Vl7qM.js} +1 -1
- package/dist/assets/stateDiagram-v2-FVOUBMTO-C85ucl39.js +1 -0
- package/dist/assets/timeline-definition-YZTLITO2-BPGKhi7f.js +61 -0
- package/dist/assets/{treemap-KZPCXAKY-ajdAP-72.js → treemap-KZPCXAKY-DZSEE6Hz.js} +58 -58
- package/dist/assets/vendor-codemirror-CyOKkaQZ.js +31 -0
- package/dist/assets/vendor-react-CP4yFTs7.js +8 -0
- package/dist/assets/vendor-xterm-DfcmCpbH.js +66 -0
- package/dist/assets/{vennDiagram-LZ73GAT5-C9If0AT0.js → vennDiagram-LZ73GAT5-8E_G06fI.js} +4 -4
- package/dist/assets/xychartDiagram-JWTSCODW-CbBk50-O.js +7 -0
- package/dist/favicon.png +0 -0
- package/dist/icons/icon-128x128.png +0 -0
- package/dist/icons/icon-144x144.png +0 -0
- package/dist/icons/icon-152x152.png +0 -0
- package/dist/icons/icon-192x192.png +0 -0
- package/dist/icons/icon-384x384.png +0 -0
- package/dist/icons/icon-512x512.png +0 -0
- package/dist/icons/icon-72x72.png +0 -0
- package/dist/icons/icon-96x96.png +0 -0
- package/dist/index.html +4 -5
- package/dist/logo-128.png +0 -0
- package/dist/logo-256.png +0 -0
- package/dist/logo-32.png +0 -0
- package/dist/logo-512.png +0 -0
- package/dist/logo-64.png +0 -0
- package/package.json +2 -1
- package/server/_legacy-providers/README.md +30 -0
- package/server/_legacy-providers/claude-sdk.js +956 -0
- package/server/_legacy-providers/gemini-cli.js +368 -0
- package/server/_legacy-providers/openai-codex.js +705 -0
- package/server/_legacy-providers/opencode-cli.js +674 -0
- package/server/acp-runtime/client.js +1805 -0
- package/server/acp-runtime/client.test.js +688 -0
- package/server/acp-runtime/index.js +419 -0
- package/server/acp-runtime/registry.js +45 -0
- package/server/acp-runtime/session-store.js +254 -0
- package/server/acp-runtime/session-store.test.js +89 -0
- package/server/channels/runtime/AgentRuntimeAdapter.js +21 -70
- package/server/claude-sdk.js +24 -944
- package/server/cli.js +11 -5
- package/server/external-agent/service.js +77 -63
- package/server/gemini-cli.js +23 -360
- package/server/index.js +54 -46
- package/server/openai-codex.js +24 -698
- package/server/opencode-cli.js +70 -640
- package/server/routes/agent.js +2 -0
- package/server/routes/codex.js +5 -5
- package/server/routes/git.js +3 -20
- package/server/routes/mcp.js +18 -34
- package/server/routes/session-core.js +44 -10
- package/server/session-core/abortSession.js +2 -18
- package/server/session-core/eventStore.js +5 -1
- package/server/session-core/providerAdapters.js +98 -10
- package/server/session-core/providerDiscovery.js +2 -2
- package/server/session-core/runtimeState.js +16 -17
- package/server/session-core/runtimeWriter.js +19 -12
- package/server/utils/codexPath.js +3 -1
- package/server/utils/spawnCommand.js +7 -0
- package/shared/conversationEvents.js +347 -10
- package/shared/conversationEvents.test.js +403 -0
- package/dist/assets/App-BxazfNJn.js +0 -484
- package/dist/assets/App-qxJ8_QYu.css +0 -32
- package/dist/assets/ReviewApp-CsqTAlGU.js +0 -1
- package/dist/assets/architectureDiagram-2XIMDMQ5-DmUHdvQH.js +0 -36
- package/dist/assets/c4Diagram-IC4MRINW-BOivDlQU.js +0 -10
- package/dist/assets/channel-Cj8xVD0X.js +0 -1
- package/dist/assets/chunk-NQ4KR5QH-Ci-n7jfu.js +0 -220
- package/dist/assets/chunk-WL4C6EOR-C559Mk71.js +0 -189
- package/dist/assets/classDiagram-VBA2DB6C-CI2zklxw.js +0 -1
- package/dist/assets/classDiagram-v2-RAHNMMFH-CI2zklxw.js +0 -1
- package/dist/assets/clone-BEVqubrI.js +0 -1
- package/dist/assets/cose-bilkent-S5V4N54A-DNO9ncXL.js +0 -1
- package/dist/assets/cytoscape.esm-2ZfV8NB5.js +0 -331
- package/dist/assets/diagram-E7M64L7V-Ba_LGLun.js +0 -24
- package/dist/assets/erDiagram-INFDFZHY-Csb8dFdP.js +0 -70
- package/dist/assets/ganttDiagram-A5KZAMGK-B5Kv9Wfz.js +0 -292
- package/dist/assets/highlighted-body-TPN3WLV5-DZJajMGm.js +0 -1
- package/dist/assets/index-BFX9lxRB.css +0 -1
- package/dist/assets/index-BiErUGrv.js +0 -2
- package/dist/assets/ishikawaDiagram-PHBUUO56-JmsNlo2I.js +0 -70
- package/dist/assets/journeyDiagram-4ABVD52K-Cuudv7Vv.js +0 -139
- package/dist/assets/mermaid-O7DHMXV3-D-2fQRvw.js +0 -988
- package/dist/assets/mindmap-definition-YRQLILUH-BQHnzzud.js +0 -68
- package/dist/assets/quadrantDiagram-337W2JSQ-DpwZU-f_.js +0 -7
- package/dist/assets/requirementDiagram-Z7DCOOCP-C_9ClOWm.js +0 -73
- package/dist/assets/sequenceDiagram-2WXFIKYE-egns-0XI.js +0 -145
- package/dist/assets/stateDiagram-v2-FVOUBMTO-BoFZZ4Ds.js +0 -1
- package/dist/assets/timeline-definition-YZTLITO2-chPa8ppH.js +0 -61
- package/dist/assets/vendor-codemirror-Dz7_EqNA.js +0 -39
- package/dist/assets/vendor-react-Cpt6D04s.js +0 -59
- package/dist/assets/vendor-xterm-DfaPXD3y.js +0 -66
- package/dist/assets/xychartDiagram-JWTSCODW-DD42U6Or.js +0 -7
package/server/routes/agent.js
CHANGED
|
@@ -97,6 +97,7 @@ router.post('/abort', validateExternalApiKey, async (req, res) => {
|
|
|
97
97
|
return res.json({
|
|
98
98
|
success: false,
|
|
99
99
|
aborted: false,
|
|
100
|
+
runtime: 'acp',
|
|
100
101
|
sessionId: normalized.sessionId,
|
|
101
102
|
provider: normalized.provider,
|
|
102
103
|
error: 'Active session not found'
|
|
@@ -106,6 +107,7 @@ router.post('/abort', validateExternalApiKey, async (req, res) => {
|
|
|
106
107
|
return res.json({
|
|
107
108
|
success: true,
|
|
108
109
|
aborted: true,
|
|
110
|
+
runtime: 'acp',
|
|
109
111
|
sessionId: normalized.sessionId,
|
|
110
112
|
provider: normalized.provider,
|
|
111
113
|
message: 'Session aborted'
|
package/server/routes/codex.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import express from 'express';
|
|
2
|
-
import { spawn } from 'child_process';
|
|
3
2
|
import { promises as fs } from 'fs';
|
|
4
3
|
import path from 'path';
|
|
5
4
|
import os from 'os';
|
|
6
5
|
import TOML from '@iarna/toml';
|
|
7
6
|
import { getCodexSessions, getCodexSessionMessages, deleteCodexSession } from '../projects.js';
|
|
7
|
+
import { spawnCommand } from '../utils/spawnCommand.js';
|
|
8
8
|
|
|
9
9
|
const router = express.Router();
|
|
10
10
|
|
|
@@ -100,7 +100,7 @@ router.delete('/sessions/:sessionId', async (req, res) => {
|
|
|
100
100
|
router.get('/mcp/cli/list', async (req, res) => {
|
|
101
101
|
try {
|
|
102
102
|
const respond = createCliResponder(res);
|
|
103
|
-
const proc =
|
|
103
|
+
const proc = spawnCommand('codex', ['mcp', 'list'], { stdio: ['pipe', 'pipe', 'pipe'] });
|
|
104
104
|
|
|
105
105
|
let stdout = '';
|
|
106
106
|
let stderr = '';
|
|
@@ -151,7 +151,7 @@ router.post('/mcp/cli/add', async (req, res) => {
|
|
|
151
151
|
}
|
|
152
152
|
|
|
153
153
|
const respond = createCliResponder(res);
|
|
154
|
-
const proc =
|
|
154
|
+
const proc = spawnCommand('codex', cliArgs, { stdio: ['pipe', 'pipe', 'pipe'] });
|
|
155
155
|
|
|
156
156
|
let stdout = '';
|
|
157
157
|
let stderr = '';
|
|
@@ -185,7 +185,7 @@ router.delete('/mcp/cli/remove/:name', async (req, res) => {
|
|
|
185
185
|
const { name } = req.params;
|
|
186
186
|
|
|
187
187
|
const respond = createCliResponder(res);
|
|
188
|
-
const proc =
|
|
188
|
+
const proc = spawnCommand('codex', ['mcp', 'remove', name], { stdio: ['pipe', 'pipe', 'pipe'] });
|
|
189
189
|
|
|
190
190
|
let stdout = '';
|
|
191
191
|
let stderr = '';
|
|
@@ -219,7 +219,7 @@ router.get('/mcp/cli/get/:name', async (req, res) => {
|
|
|
219
219
|
const { name } = req.params;
|
|
220
220
|
|
|
221
221
|
const respond = createCliResponder(res);
|
|
222
|
-
const proc =
|
|
222
|
+
const proc = spawnCommand('codex', ['mcp', 'get', name], { stdio: ['pipe', 'pipe', 'pipe'] });
|
|
223
223
|
|
|
224
224
|
let stdout = '';
|
|
225
225
|
let stderr = '';
|
package/server/routes/git.js
CHANGED
|
@@ -610,26 +610,9 @@ Generate the commit message:`;
|
|
|
610
610
|
const parsed = typeof data === 'string' ? JSON.parse(data) : data;
|
|
611
611
|
console.log('🔍 Writer received message type:', parsed.type);
|
|
612
612
|
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
if (parsed.type === '
|
|
616
|
-
const message = parsed.data.message || parsed.data;
|
|
617
|
-
console.log('📦 Claude response message:', JSON.stringify(message, null, 2).substring(0, 500));
|
|
618
|
-
if (message.content && Array.isArray(message.content)) {
|
|
619
|
-
// Extract text from content array
|
|
620
|
-
for (const item of message.content) {
|
|
621
|
-
if (item.type === 'text' && item.text) {
|
|
622
|
-
console.log('✅ Extracted text chunk:', item.text.substring(0, 100));
|
|
623
|
-
responseText += item.text;
|
|
624
|
-
}
|
|
625
|
-
}
|
|
626
|
-
}
|
|
627
|
-
}
|
|
628
|
-
else if (parsed.type === 'claude-response' && parsed.data?.type === 'content_block_delta' && parsed.data?.delta?.text) {
|
|
629
|
-
responseText += parsed.data.delta.text;
|
|
630
|
-
}
|
|
631
|
-
// Also handle direct text messages
|
|
632
|
-
else if (parsed.type === 'text' && parsed.text) {
|
|
613
|
+
if (parsed.type === 'conversation-event' && parsed.event?.kind === 'assistant_text_delta' && parsed.event?.payload?.text) {
|
|
614
|
+
responseText += parsed.event.payload.text;
|
|
615
|
+
} else if (parsed.type === 'text' && parsed.text) {
|
|
633
616
|
console.log('✅ Direct text:', parsed.text.substring(0, 100));
|
|
634
617
|
responseText += parsed.text;
|
|
635
618
|
}
|
package/server/routes/mcp.js
CHANGED
|
@@ -2,13 +2,9 @@ import express from 'express';
|
|
|
2
2
|
import { promises as fs } from 'fs';
|
|
3
3
|
import path from 'path';
|
|
4
4
|
import os from 'os';
|
|
5
|
-
import {
|
|
6
|
-
import { dirname } from 'path';
|
|
7
|
-
import { spawn } from 'child_process';
|
|
5
|
+
import { spawnCommand } from '../utils/spawnCommand.js';
|
|
8
6
|
|
|
9
7
|
const router = express.Router();
|
|
10
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
11
|
-
const __dirname = dirname(__filename);
|
|
12
8
|
|
|
13
9
|
// Claude CLI command routes
|
|
14
10
|
|
|
@@ -16,12 +12,8 @@ const __dirname = dirname(__filename);
|
|
|
16
12
|
router.get('/cli/list', async (req, res) => {
|
|
17
13
|
try {
|
|
18
14
|
console.log('📋 Listing MCP servers using Claude CLI');
|
|
19
|
-
|
|
20
|
-
const
|
|
21
|
-
const { promisify } = await import('util');
|
|
22
|
-
const exec = promisify(spawn);
|
|
23
|
-
|
|
24
|
-
const process = spawn('claude', ['mcp', 'list'], {
|
|
15
|
+
|
|
16
|
+
const process = spawnCommand('claude', ['mcp', 'list'], {
|
|
25
17
|
stdio: ['pipe', 'pipe', 'pipe']
|
|
26
18
|
});
|
|
27
19
|
|
|
@@ -59,11 +51,9 @@ router.get('/cli/list', async (req, res) => {
|
|
|
59
51
|
router.post('/cli/add', async (req, res) => {
|
|
60
52
|
try {
|
|
61
53
|
const { name, type = 'stdio', command, args = [], url, headers = {}, env = {}, scope = 'user', projectPath } = req.body;
|
|
62
|
-
|
|
54
|
+
|
|
63
55
|
console.log(`➕ Adding MCP server using Claude CLI (${scope} scope):`, name);
|
|
64
|
-
|
|
65
|
-
const { spawn } = await import('child_process');
|
|
66
|
-
|
|
56
|
+
|
|
67
57
|
let cliArgs = ['mcp', 'add'];
|
|
68
58
|
|
|
69
59
|
// Add scope flag
|
|
@@ -105,8 +95,8 @@ router.post('/cli/add', async (req, res) => {
|
|
|
105
95
|
spawnOptions.cwd = projectPath;
|
|
106
96
|
console.log('📁 Running in project directory:', projectPath);
|
|
107
97
|
}
|
|
108
|
-
|
|
109
|
-
const process =
|
|
98
|
+
|
|
99
|
+
const process = spawnCommand('claude', cliArgs, spawnOptions);
|
|
110
100
|
|
|
111
101
|
let stdout = '';
|
|
112
102
|
let stderr = '';
|
|
@@ -142,9 +132,9 @@ router.post('/cli/add', async (req, res) => {
|
|
|
142
132
|
router.post('/cli/add-json', async (req, res) => {
|
|
143
133
|
try {
|
|
144
134
|
const { name, jsonConfig, scope = 'user', projectPath } = req.body;
|
|
145
|
-
|
|
135
|
+
|
|
146
136
|
console.log('➕ Adding MCP server using JSON format:', name);
|
|
147
|
-
|
|
137
|
+
|
|
148
138
|
// Validate and parse JSON config
|
|
149
139
|
let parsedConfig;
|
|
150
140
|
try {
|
|
@@ -178,8 +168,6 @@ router.post('/cli/add-json', async (req, res) => {
|
|
|
178
168
|
});
|
|
179
169
|
}
|
|
180
170
|
|
|
181
|
-
const { spawn } = await import('child_process');
|
|
182
|
-
|
|
183
171
|
// Build the command: claude mcp add-json --scope <scope> <name> '<json>'
|
|
184
172
|
const cliArgs = ['mcp', 'add-json', '--scope', scope, name];
|
|
185
173
|
|
|
@@ -198,8 +186,8 @@ router.post('/cli/add-json', async (req, res) => {
|
|
|
198
186
|
spawnOptions.cwd = projectPath;
|
|
199
187
|
console.log('📁 Running in project directory:', projectPath);
|
|
200
188
|
}
|
|
201
|
-
|
|
202
|
-
const process =
|
|
189
|
+
|
|
190
|
+
const process = spawnCommand('claude', cliArgs, spawnOptions);
|
|
203
191
|
|
|
204
192
|
let stdout = '';
|
|
205
193
|
let stderr = '';
|
|
@@ -247,11 +235,9 @@ router.delete('/cli/remove/:name', async (req, res) => {
|
|
|
247
235
|
actualName = serverName;
|
|
248
236
|
actualScope = actualScope || prefix; // Use prefix as scope if not provided in query
|
|
249
237
|
}
|
|
250
|
-
|
|
238
|
+
|
|
251
239
|
console.log('🗑️ Removing MCP server using Claude CLI:', actualName, 'scope:', actualScope);
|
|
252
|
-
|
|
253
|
-
const { spawn } = await import('child_process');
|
|
254
|
-
|
|
240
|
+
|
|
255
241
|
// Build command args based on scope
|
|
256
242
|
let cliArgs = ['mcp', 'remove'];
|
|
257
243
|
|
|
@@ -267,7 +253,7 @@ router.delete('/cli/remove/:name', async (req, res) => {
|
|
|
267
253
|
|
|
268
254
|
console.log('🔧 Running Claude CLI command:', 'claude', cliArgs.join(' '));
|
|
269
255
|
|
|
270
|
-
const process =
|
|
256
|
+
const process = spawnCommand('claude', cliArgs, {
|
|
271
257
|
stdio: ['pipe', 'pipe', 'pipe']
|
|
272
258
|
});
|
|
273
259
|
|
|
@@ -305,12 +291,10 @@ router.delete('/cli/remove/:name', async (req, res) => {
|
|
|
305
291
|
router.get('/cli/get/:name', async (req, res) => {
|
|
306
292
|
try {
|
|
307
293
|
const { name } = req.params;
|
|
308
|
-
|
|
294
|
+
|
|
309
295
|
console.log('📄 Getting MCP server details using Claude CLI:', name);
|
|
310
|
-
|
|
311
|
-
const
|
|
312
|
-
|
|
313
|
-
const process = spawn('claude', ['mcp', 'get', name], {
|
|
296
|
+
|
|
297
|
+
const process = spawnCommand('claude', ['mcp', 'get', name], {
|
|
314
298
|
stdio: ['pipe', 'pipe', 'pipe']
|
|
315
299
|
});
|
|
316
300
|
|
|
@@ -549,4 +533,4 @@ function parseClaudeGetOutput(output) {
|
|
|
549
533
|
}
|
|
550
534
|
}
|
|
551
535
|
|
|
552
|
-
export default router;
|
|
536
|
+
export default router;
|
|
@@ -2,10 +2,17 @@ import express from 'express';
|
|
|
2
2
|
import { getProjects } from '../projects.js';
|
|
3
3
|
import { discoverAllProviders, discoverProvider } from '../session-core/providerDiscovery.js';
|
|
4
4
|
import { getProviderAdapter } from '../session-core/providerAdapters.js';
|
|
5
|
+
import { listAcpSessions } from '../acp-runtime/session-store.js';
|
|
5
6
|
|
|
6
7
|
const router = express.Router();
|
|
7
8
|
|
|
8
|
-
|
|
9
|
+
router.use((req, res, next) => {
|
|
10
|
+
res.setHeader('X-Runtime-Engine', 'acp');
|
|
11
|
+
next();
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
async function flattenProjectSessions(project) {
|
|
15
|
+
const projectPath = project.fullPath || project.path || null;
|
|
9
16
|
const groups = [
|
|
10
17
|
{ provider: 'claude', items: project.sessions || [] },
|
|
11
18
|
{ provider: 'codex', items: project.codexSessions || [] },
|
|
@@ -13,7 +20,12 @@ function flattenProjectSessions(project) {
|
|
|
13
20
|
{ provider: 'opencode', items: project.opencodeSessions || [] }
|
|
14
21
|
];
|
|
15
22
|
|
|
16
|
-
|
|
23
|
+
const acpSessions = await listAcpSessions({ projectPath });
|
|
24
|
+
|
|
25
|
+
return [
|
|
26
|
+
...groups.flatMap(({ provider, items }) => items.map((item) => ({ ...item, provider, __provider: provider, source: item?.source || 'legacy' }))),
|
|
27
|
+
...acpSessions.map((item) => ({ ...item, provider: item.provider, __provider: item.provider, source: 'acp' }))
|
|
28
|
+
]
|
|
17
29
|
.sort((a, b) => new Date(b.lastActivity || b.updated_at || b.createdAt || 0) - new Date(a.lastActivity || a.updated_at || a.createdAt || 0));
|
|
18
30
|
}
|
|
19
31
|
|
|
@@ -42,7 +54,15 @@ router.get('/projects/:projectName/history-index', async (req, res) => {
|
|
|
42
54
|
if (!project) {
|
|
43
55
|
return res.status(404).json({ success: false, error: 'Project not found' });
|
|
44
56
|
}
|
|
45
|
-
res.json({
|
|
57
|
+
res.json({
|
|
58
|
+
success: true,
|
|
59
|
+
project: {
|
|
60
|
+
name: project.name,
|
|
61
|
+
fullPath: project.fullPath || project.path,
|
|
62
|
+
displayName: project.displayName || project.name
|
|
63
|
+
},
|
|
64
|
+
sessions: await flattenProjectSessions(project)
|
|
65
|
+
});
|
|
46
66
|
} catch (error) {
|
|
47
67
|
res.status(500).json({ success: false, error: error.message });
|
|
48
68
|
}
|
|
@@ -66,19 +86,26 @@ router.get('/sessions/:sessionId/resolve', async (req, res) => {
|
|
|
66
86
|
'opencode'
|
|
67
87
|
].filter((provider, index, all) => provider && all.indexOf(provider) === index);
|
|
68
88
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
89
|
+
let directProjectMatch = null;
|
|
90
|
+
let directMatchSessions = [];
|
|
91
|
+
|
|
92
|
+
for (const project of projects) {
|
|
93
|
+
const flattened = await flattenProjectSessions(project);
|
|
94
|
+
if (flattened.some((session) => session.id === requestedSessionId)) {
|
|
95
|
+
directProjectMatch = project;
|
|
96
|
+
directMatchSessions = flattened;
|
|
97
|
+
break;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
73
100
|
|
|
74
101
|
if (directProjectMatch) {
|
|
75
|
-
const
|
|
76
|
-
const matchedSession = flattened.find((session) => session.id === requestedSessionId);
|
|
102
|
+
const matchedSession = directMatchSessions.find((session) => session.id === requestedSessionId);
|
|
77
103
|
|
|
78
104
|
return res.json({
|
|
79
105
|
success: true,
|
|
80
106
|
found: true,
|
|
81
107
|
provider: matchedSession.provider,
|
|
108
|
+
source: matchedSession.source || 'legacy',
|
|
82
109
|
session: matchedSession,
|
|
83
110
|
project: {
|
|
84
111
|
name: directProjectMatch.name,
|
|
@@ -97,7 +124,12 @@ router.get('/sessions/:sessionId/resolve', async (req, res) => {
|
|
|
97
124
|
|
|
98
125
|
try {
|
|
99
126
|
if (provider === 'claude') {
|
|
100
|
-
const result = await adapter.listSessions({
|
|
127
|
+
const result = await adapter.listSessions({
|
|
128
|
+
projectName: project.name,
|
|
129
|
+
projectPath: project.fullPath || project.path,
|
|
130
|
+
limit: 1000,
|
|
131
|
+
offset: 0
|
|
132
|
+
});
|
|
101
133
|
sessions = Array.isArray(result) ? result : [];
|
|
102
134
|
} else {
|
|
103
135
|
sessions = await adapter.listSessions({ projectPath: project.fullPath || project.path, limit: 0 });
|
|
@@ -115,6 +147,7 @@ router.get('/sessions/:sessionId/resolve', async (req, res) => {
|
|
|
115
147
|
success: true,
|
|
116
148
|
found: true,
|
|
117
149
|
provider,
|
|
150
|
+
source: matchedSession.source || 'legacy',
|
|
118
151
|
session: matchedSession,
|
|
119
152
|
project: {
|
|
120
153
|
name: project.name,
|
|
@@ -157,6 +190,7 @@ router.get('/sessions/:provider/:sessionId/events', async (req, res) => {
|
|
|
157
190
|
success: true,
|
|
158
191
|
provider: req.params.provider,
|
|
159
192
|
sessionId: req.params.sessionId,
|
|
193
|
+
source: result?.source || 'legacy',
|
|
160
194
|
events,
|
|
161
195
|
total,
|
|
162
196
|
hasMore,
|
|
@@ -1,7 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { abortCodexSession } from '../openai-codex.js';
|
|
3
|
-
import { abortGeminiSession } from '../gemini-cli.js';
|
|
4
|
-
import { abortOpencodeSession } from '../opencode-cli.js';
|
|
1
|
+
import { abortAgentSession as abortAcpAgentSession } from '../acp-runtime/index.js';
|
|
5
2
|
|
|
6
3
|
export const ABORTABLE_AGENT_PROVIDERS = ['claude', 'codex', 'gemini', 'opencode'];
|
|
7
4
|
|
|
@@ -11,20 +8,7 @@ export function isAbortableAgentProvider(provider) {
|
|
|
11
8
|
|
|
12
9
|
export async function abortAgentSession(provider, sessionId) {
|
|
13
10
|
const normalizedProvider = String(provider || 'claude').trim().toLowerCase();
|
|
14
|
-
|
|
15
|
-
if (normalizedProvider === 'codex') {
|
|
16
|
-
return abortCodexSession(sessionId);
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
if (normalizedProvider === 'gemini') {
|
|
20
|
-
return abortGeminiSession(sessionId);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
if (normalizedProvider === 'opencode') {
|
|
24
|
-
return abortOpencodeSession(sessionId);
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
return abortClaudeSDKSession(sessionId);
|
|
11
|
+
return abortAcpAgentSession(normalizedProvider, sessionId);
|
|
28
12
|
}
|
|
29
13
|
|
|
30
14
|
export async function abortAgentSessionWithWriter({ provider = 'claude', sessionId, writer }) {
|
|
@@ -24,7 +24,11 @@ function normalizePersistedEvents(events = []) {
|
|
|
24
24
|
return events.filter((event) => (
|
|
25
25
|
isConversationEvent(event) &&
|
|
26
26
|
event.sessionId &&
|
|
27
|
-
|
|
27
|
+
(
|
|
28
|
+
event.extensions?.runtimeSource === 'acp' ||
|
|
29
|
+
event.rawRef?.runtime === 'acp' ||
|
|
30
|
+
PERSISTED_EVENT_KINDS.has(event.kind)
|
|
31
|
+
)
|
|
28
32
|
));
|
|
29
33
|
}
|
|
30
34
|
|
|
@@ -10,6 +10,10 @@ import {
|
|
|
10
10
|
getOpencodeSessions,
|
|
11
11
|
getGeminiSessions
|
|
12
12
|
} from '../projects.js';
|
|
13
|
+
import {
|
|
14
|
+
findAcpSessionRecord,
|
|
15
|
+
listAcpSessions
|
|
16
|
+
} from '../acp-runtime/session-store.js';
|
|
13
17
|
|
|
14
18
|
async function flattenLegacyMessages(result) {
|
|
15
19
|
if (Array.isArray(result)) return result;
|
|
@@ -28,47 +32,131 @@ async function normalizeLegacyLoadResult(result, provider, sessionId) {
|
|
|
28
32
|
|
|
29
33
|
return {
|
|
30
34
|
...result,
|
|
31
|
-
events
|
|
35
|
+
events,
|
|
36
|
+
source: 'legacy'
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function mergeSessionLists(legacySessions = [], acpSessions = []) {
|
|
41
|
+
const merged = new Map();
|
|
42
|
+
|
|
43
|
+
legacySessions.forEach((session) => {
|
|
44
|
+
if (session?.id) {
|
|
45
|
+
merged.set(session.id, session);
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
acpSessions.forEach((session) => {
|
|
50
|
+
if (session?.id) {
|
|
51
|
+
merged.set(session.id, session);
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
return Array.from(merged.values()).sort((left, right) => {
|
|
56
|
+
const leftTime = new Date(left?.lastActivity || left?.updatedAt || left?.createdAt || 0).getTime();
|
|
57
|
+
const rightTime = new Date(right?.lastActivity || right?.updatedAt || right?.createdAt || 0).getTime();
|
|
58
|
+
return rightTime - leftTime;
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
async function loadAcpEvents(provider, sessionId) {
|
|
63
|
+
const record = await findAcpSessionRecord(sessionId, provider);
|
|
64
|
+
if (!record) {
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const events = await readMirroredConversationEvents(provider, sessionId);
|
|
69
|
+
return {
|
|
70
|
+
events,
|
|
71
|
+
total: events.length,
|
|
72
|
+
hasMore: false,
|
|
73
|
+
offset: 0,
|
|
74
|
+
limit: null,
|
|
75
|
+
source: 'acp'
|
|
32
76
|
};
|
|
33
77
|
}
|
|
34
78
|
|
|
35
79
|
const PROVIDER_ADAPTERS = {
|
|
36
80
|
claude: {
|
|
37
|
-
async listSessions({ projectName, limit = 50, offset = 0 }) {
|
|
38
|
-
const result = await
|
|
39
|
-
|
|
81
|
+
async listSessions({ projectName, projectPath, limit = 50, offset = 0 }) {
|
|
82
|
+
const [result, acpSessions] = await Promise.all([
|
|
83
|
+
getSessions(projectName, limit, offset),
|
|
84
|
+
listAcpSessions({ provider: 'claude', projectPath: projectPath || null })
|
|
85
|
+
]);
|
|
86
|
+
return mergeSessionLists(
|
|
87
|
+
(result?.sessions || []).map((session) => ({ ...session, provider: 'claude', source: 'legacy' })),
|
|
88
|
+
acpSessions
|
|
89
|
+
);
|
|
40
90
|
},
|
|
41
91
|
async loadEvents({ projectName, sessionId, limit = null, offset = 0 }) {
|
|
92
|
+
const acpResult = await loadAcpEvents('claude', sessionId);
|
|
93
|
+
if (acpResult) {
|
|
94
|
+
return acpResult;
|
|
95
|
+
}
|
|
96
|
+
|
|
42
97
|
const rawMessages = await getSessionMessages(projectName, sessionId, limit, offset);
|
|
43
98
|
return normalizeLegacyLoadResult(rawMessages, 'claude', sessionId);
|
|
44
99
|
}
|
|
45
100
|
},
|
|
46
101
|
codex: {
|
|
47
102
|
async listSessions({ projectPath, limit = 50 }) {
|
|
48
|
-
const sessions = await
|
|
49
|
-
|
|
103
|
+
const [sessions, acpSessions] = await Promise.all([
|
|
104
|
+
getCodexSessions(projectPath, { limit }),
|
|
105
|
+
listAcpSessions({ provider: 'codex', projectPath: projectPath || null })
|
|
106
|
+
]);
|
|
107
|
+
return mergeSessionLists(
|
|
108
|
+
sessions.map((session) => ({ ...session, provider: 'codex', source: 'legacy' })),
|
|
109
|
+
acpSessions
|
|
110
|
+
);
|
|
50
111
|
},
|
|
51
112
|
async loadEvents({ sessionId, limit = null, offset = 0 }) {
|
|
113
|
+
const acpResult = await loadAcpEvents('codex', sessionId);
|
|
114
|
+
if (acpResult) {
|
|
115
|
+
return acpResult;
|
|
116
|
+
}
|
|
117
|
+
|
|
52
118
|
const rawMessages = await getCodexSessionMessages(sessionId, limit, offset);
|
|
53
119
|
return normalizeLegacyLoadResult(rawMessages, 'codex', sessionId);
|
|
54
120
|
}
|
|
55
121
|
},
|
|
56
122
|
gemini: {
|
|
57
123
|
async listSessions({ projectPath, limit = 50 }) {
|
|
58
|
-
const sessions = await
|
|
59
|
-
|
|
124
|
+
const [sessions, acpSessions] = await Promise.all([
|
|
125
|
+
getGeminiSessions(projectPath, { limit }),
|
|
126
|
+
listAcpSessions({ provider: 'gemini', projectPath: projectPath || null })
|
|
127
|
+
]);
|
|
128
|
+
return mergeSessionLists(
|
|
129
|
+
sessions.map((session) => ({ ...session, provider: 'gemini', source: 'legacy' })),
|
|
130
|
+
acpSessions
|
|
131
|
+
);
|
|
60
132
|
},
|
|
61
133
|
async loadEvents({ sessionId, limit = null, offset = 0 }) {
|
|
134
|
+
const acpResult = await loadAcpEvents('gemini', sessionId);
|
|
135
|
+
if (acpResult) {
|
|
136
|
+
return acpResult;
|
|
137
|
+
}
|
|
138
|
+
|
|
62
139
|
const rawMessages = await getGeminiSessionMessages(sessionId, limit, offset);
|
|
63
140
|
return normalizeLegacyLoadResult(rawMessages, 'gemini', sessionId);
|
|
64
141
|
}
|
|
65
142
|
},
|
|
66
143
|
opencode: {
|
|
67
144
|
async listSessions({ projectPath, limit = 50 }) {
|
|
68
|
-
const sessions = await
|
|
69
|
-
|
|
145
|
+
const [sessions, acpSessions] = await Promise.all([
|
|
146
|
+
getOpencodeSessions(projectPath, { limit }),
|
|
147
|
+
listAcpSessions({ provider: 'opencode', projectPath: projectPath || null })
|
|
148
|
+
]);
|
|
149
|
+
return mergeSessionLists(
|
|
150
|
+
sessions.map((session) => ({ ...session, provider: 'opencode', source: 'legacy' })),
|
|
151
|
+
acpSessions
|
|
152
|
+
);
|
|
70
153
|
},
|
|
71
154
|
async loadEvents({ sessionId, limit = null, offset = 0 }) {
|
|
155
|
+
const acpResult = await loadAcpEvents('opencode', sessionId);
|
|
156
|
+
if (acpResult) {
|
|
157
|
+
return acpResult;
|
|
158
|
+
}
|
|
159
|
+
|
|
72
160
|
const rawMessages = await getOpencodeSessionMessages(sessionId, limit, offset);
|
|
73
161
|
return normalizeLegacyLoadResult(rawMessages, 'opencode', sessionId);
|
|
74
162
|
}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { spawn } from 'child_process';
|
|
2
1
|
import { promises as fs } from 'fs';
|
|
3
2
|
import path from 'path';
|
|
4
3
|
import os from 'os';
|
|
@@ -10,6 +9,7 @@ import {
|
|
|
10
9
|
checkOpencodeCredentials
|
|
11
10
|
} from '../routes/cli-auth.js';
|
|
12
11
|
import { listOpencodeModels } from '../opencode-cli.js';
|
|
12
|
+
import { spawnCommand } from '../utils/spawnCommand.js';
|
|
13
13
|
import {
|
|
14
14
|
CLAUDE_MODELS,
|
|
15
15
|
CODEX_MODELS, GEMINI_MODELS,
|
|
@@ -36,7 +36,7 @@ function runCommand(command, args = [], options = {}) {
|
|
|
36
36
|
};
|
|
37
37
|
|
|
38
38
|
try {
|
|
39
|
-
child =
|
|
39
|
+
child = spawnCommand(command, args, {
|
|
40
40
|
cwd: options.cwd || process.cwd(),
|
|
41
41
|
stdio: ['ignore', 'pipe', 'pipe'],
|
|
42
42
|
env: { ...process.env, ...(options.env || {}) }
|
|
@@ -7,10 +7,8 @@ import {
|
|
|
7
7
|
} from './eventStore.js';
|
|
8
8
|
import { getProviderAdapter } from './providerAdapters.js';
|
|
9
9
|
import { getProjects } from '../projects.js';
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import { isGeminiSessionActive } from '../gemini-cli.js';
|
|
13
|
-
import { isOpencodeSessionActive } from '../opencode-cli.js';
|
|
10
|
+
import { findAcpSessionRecord } from '../acp-runtime/session-store.js';
|
|
11
|
+
import { isAgentSessionActive } from '../acp-runtime/index.js';
|
|
14
12
|
|
|
15
13
|
export const AGENT_RUNTIME_PHASES = {
|
|
16
14
|
IDLE: 'idle',
|
|
@@ -86,6 +84,18 @@ async function resolveSessionProjectContext(provider, sessionId) {
|
|
|
86
84
|
return null;
|
|
87
85
|
}
|
|
88
86
|
|
|
87
|
+
const acpRecord = await findAcpSessionRecord(normalizedSessionId, normalizedProvider);
|
|
88
|
+
if (acpRecord) {
|
|
89
|
+
return {
|
|
90
|
+
projectName: null,
|
|
91
|
+
projectPath: acpRecord.projectPath || null,
|
|
92
|
+
session: {
|
|
93
|
+
id: normalizedSessionId,
|
|
94
|
+
source: 'acp'
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
|
|
89
99
|
const projects = await getProjects();
|
|
90
100
|
|
|
91
101
|
for (const project of projects) {
|
|
@@ -149,19 +159,7 @@ function isSessionActive(provider, sessionId) {
|
|
|
149
159
|
return false;
|
|
150
160
|
}
|
|
151
161
|
|
|
152
|
-
|
|
153
|
-
return Boolean(isCodexSessionActive(normalizedSessionId));
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
if (normalizedProvider === 'gemini') {
|
|
157
|
-
return Boolean(isGeminiSessionActive(normalizedSessionId));
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
if (normalizedProvider === 'opencode') {
|
|
161
|
-
return Boolean(isOpencodeSessionActive(normalizedSessionId));
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
return Boolean(isClaudeSDKSessionActive(normalizedSessionId));
|
|
162
|
+
return Boolean(isAgentSessionActive(normalizedProvider, normalizedSessionId));
|
|
165
163
|
}
|
|
166
164
|
|
|
167
165
|
function inferPhaseFromEvents(events = []) {
|
|
@@ -204,6 +202,7 @@ function inferPhaseFromEvents(events = []) {
|
|
|
204
202
|
event.kind === CONVERSATION_EVENT_KINDS.TOOL_CALL_INPUT ||
|
|
205
203
|
event.kind === CONVERSATION_EVENT_KINDS.TOOL_CALL_END ||
|
|
206
204
|
event.kind === CONVERSATION_EVENT_KINDS.TOOL_RESULT ||
|
|
205
|
+
event.kind === CONVERSATION_EVENT_KINDS.PLAN_UPDATE ||
|
|
207
206
|
event.kind === CONVERSATION_EVENT_KINDS.SYSTEM_NOTICE
|
|
208
207
|
) {
|
|
209
208
|
inferredPhase = AGENT_RUNTIME_PHASES.STREAMING;
|
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
isConversationEvent,
|
|
3
|
+
normalizeRealtimePayloadToConversationEvents
|
|
4
|
+
} from '../../shared/conversationEvents.js';
|
|
2
5
|
import { appendMirroredConversationEvents } from './eventStore.js';
|
|
3
6
|
import { publishSessionRuntimeStateChanges } from './runtimeState.js';
|
|
4
7
|
|
|
@@ -18,19 +21,23 @@ export class SessionEventMirrorWriter {
|
|
|
18
21
|
|
|
19
22
|
this.writer.send(data);
|
|
20
23
|
|
|
21
|
-
const normalizedEvents =
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
const normalizedEvents = data?.type === 'conversation-event' && isConversationEvent(data?.event)
|
|
25
|
+
? [data.event]
|
|
26
|
+
: normalizeRealtimePayloadToConversationEvents({
|
|
27
|
+
...data,
|
|
28
|
+
provider: data?.provider || this.provider,
|
|
29
|
+
sessionId: data?.sessionId || this.sessionId
|
|
30
|
+
}, this.provider);
|
|
26
31
|
|
|
27
32
|
normalizedEvents.forEach((event) => {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
33
|
+
if (!(data?.type === 'conversation-event' && data?.event?.eventId === event.eventId)) {
|
|
34
|
+
this.writer.send({
|
|
35
|
+
type: 'conversation-event',
|
|
36
|
+
provider: event.provider,
|
|
37
|
+
sessionId: event.sessionId,
|
|
38
|
+
event
|
|
39
|
+
});
|
|
40
|
+
}
|
|
34
41
|
});
|
|
35
42
|
|
|
36
43
|
if (normalizedEvents.length > 0) {
|
|
@@ -45,7 +45,9 @@ export function getBundledCodexPath() {
|
|
|
45
45
|
|
|
46
46
|
export function getCodexPathOverride() {
|
|
47
47
|
if (process.platform === 'win32') {
|
|
48
|
-
|
|
48
|
+
// The SDK uses child_process.spawn() directly. Handing it a .cmd wrapper
|
|
49
|
+
// is brittle on Windows, so point it at the bundled executable instead.
|
|
50
|
+
return getBundledCodexPath();
|
|
49
51
|
}
|
|
50
52
|
|
|
51
53
|
return path.join(__dirname, '..', 'bin', 'codex-sdk-wrapper.js');
|