@exreve/exk 1.0.30 → 1.0.31
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/agentSession.js +2 -96
- package/dist/app-child.js +0 -41
- package/dist/index.js +0 -50
- package/dist/moduleMcpServer.js +3 -78
- package/dist/ttc-cli.tar.gz +0 -0
- package/package.json +1 -1
package/dist/agentSession.js
CHANGED
|
@@ -320,26 +320,15 @@ export class AgentSessionManager {
|
|
|
320
320
|
existingSession.model = model;
|
|
321
321
|
}
|
|
322
322
|
// Update enabled modules and settings if provided
|
|
323
|
-
const newModules = handler.enabledModules;
|
|
324
|
-
if (newModules) {
|
|
325
|
-
existingSession.enabledModules = newModules;
|
|
326
|
-
}
|
|
327
|
-
const newModuleSettings = handler.moduleSettings;
|
|
328
|
-
if (newModuleSettings) {
|
|
329
|
-
existingSession.moduleSettings = newModuleSettings;
|
|
330
|
-
}
|
|
331
|
-
existingSession.userChoiceEnabled = handler.userChoiceEnabled || false;
|
|
332
323
|
// Ensure abort controller is fresh for new queries
|
|
333
324
|
existingSession.abortController = new AbortController();
|
|
334
|
-
// Update handler
|
|
325
|
+
// Update handler reference
|
|
335
326
|
this.sessionHandlers.set(sessionId, handler);
|
|
336
327
|
return;
|
|
337
328
|
}
|
|
338
329
|
// Store the handler for this session
|
|
339
330
|
this.sessionHandlers.set(sessionId, handler);
|
|
340
331
|
const abortController = new AbortController();
|
|
341
|
-
const enabledModules = handler.enabledModules || [];
|
|
342
|
-
const moduleSettings = handler.moduleSettings || {};
|
|
343
332
|
// Restore claudeSessionId from disk (survives CLI restart)
|
|
344
333
|
const persistedState = loadSessionState(sessionId);
|
|
345
334
|
const restoredClaudeSessionId = persistedState?.claudeSessionId;
|
|
@@ -359,9 +348,6 @@ export class AgentSessionManager {
|
|
|
359
348
|
claudeProcessGroupId: undefined,
|
|
360
349
|
currentPromptId: undefined,
|
|
361
350
|
model: sessionModel,
|
|
362
|
-
userChoiceEnabled: handler.userChoiceEnabled || false,
|
|
363
|
-
enabledModules,
|
|
364
|
-
moduleSettings
|
|
365
351
|
});
|
|
366
352
|
// Auto-regenerate CLAUDE.md for fresh project context
|
|
367
353
|
await this.regenerateClaudeMd(projectPath);
|
|
@@ -1228,11 +1214,6 @@ export class AgentSessionManager {
|
|
|
1228
1214
|
session.currentPromptId = undefined;
|
|
1229
1215
|
// 8. Remove from emergency stop tracking
|
|
1230
1216
|
this.emergencyStopInProgress.delete(sessionId);
|
|
1231
|
-
// 9. Resolve any pending choice request with null (cancelled)
|
|
1232
|
-
if (session.pendingChoice) {
|
|
1233
|
-
session.pendingChoice.resolve({ choiceId: session.pendingChoice.request.choiceId, selectedValue: null });
|
|
1234
|
-
session.pendingChoice = undefined;
|
|
1235
|
-
}
|
|
1236
1217
|
const message = currentPromptId
|
|
1237
1218
|
? `Emergency stop: Cancelled prompt '${currentPromptId}' and cleared ${queueSize} queued prompts`
|
|
1238
1219
|
: `Emergency stop: Cleared ${queueSize} queued prompts`;
|
|
@@ -1256,84 +1237,9 @@ export class AgentSessionManager {
|
|
|
1256
1237
|
console.log(`[buildMcpServer] No session found for ${sessionId}`);
|
|
1257
1238
|
return undefined;
|
|
1258
1239
|
}
|
|
1259
|
-
|
|
1260
|
-
console.log(`[buildMcpServer] Session ${sessionId}: enabledModules=${JSON.stringify(enabledModules)}, attachmentDir=${attachmentDir || 'none'}`);
|
|
1261
|
-
if (enabledModules.length === 0 && !attachmentDir) {
|
|
1262
|
-
console.log(`[buildMcpServer] No enabled modules and no attachments, skipping MCP server creation`);
|
|
1263
|
-
return undefined;
|
|
1264
|
-
}
|
|
1265
|
-
const handler = this.sessionHandlers.get(sessionId);
|
|
1240
|
+
console.log(`[buildMcpServer] Session ${sessionId}: attachmentDir=${attachmentDir || 'none'}`);
|
|
1266
1241
|
return createModuleMcpServer({
|
|
1267
|
-
enabledModules,
|
|
1268
|
-
moduleSettings: session.moduleSettings || {},
|
|
1269
1242
|
attachmentDir,
|
|
1270
|
-
onChoiceRequest: handler?.onChoiceRequest
|
|
1271
|
-
? async (request) => {
|
|
1272
|
-
return new Promise((resolve) => {
|
|
1273
|
-
const sess = this.sessions.get(sessionId);
|
|
1274
|
-
if (sess) {
|
|
1275
|
-
sess.pendingChoice = { request, resolve };
|
|
1276
|
-
handler.onChoiceRequest(request);
|
|
1277
|
-
}
|
|
1278
|
-
else {
|
|
1279
|
-
resolve({ choiceId: request.choiceId, selectedValue: null });
|
|
1280
|
-
}
|
|
1281
|
-
});
|
|
1282
|
-
}
|
|
1283
|
-
: undefined
|
|
1284
|
-
});
|
|
1285
|
-
}
|
|
1286
|
-
/**
|
|
1287
|
-
* Handle user choice response from frontend
|
|
1288
|
-
*/
|
|
1289
|
-
async handleChoiceResponse(sessionId, response) {
|
|
1290
|
-
const session = this.sessions.get(sessionId);
|
|
1291
|
-
if (!session) {
|
|
1292
|
-
console.error(`[agentSession] Session ${sessionId} not found for choice response`);
|
|
1293
|
-
return;
|
|
1294
|
-
}
|
|
1295
|
-
if (!session.pendingChoice) {
|
|
1296
|
-
console.warn(`[agentSession] No pending choice for session ${sessionId}`);
|
|
1297
|
-
return;
|
|
1298
|
-
}
|
|
1299
|
-
if (session.pendingChoice.request.choiceId !== response.choiceId) {
|
|
1300
|
-
console.warn(`[agentSession] Choice ID mismatch: expected ${session.pendingChoice.request.choiceId}, got ${response.choiceId}`);
|
|
1301
|
-
return;
|
|
1302
|
-
}
|
|
1303
|
-
// Resolve the pending choice promise
|
|
1304
|
-
session.pendingChoice.resolve(response);
|
|
1305
|
-
session.pendingChoice = undefined;
|
|
1306
|
-
}
|
|
1307
|
-
/**
|
|
1308
|
-
* Request user choice during agent execution
|
|
1309
|
-
*/
|
|
1310
|
-
async requestUserChoice(sessionId, request) {
|
|
1311
|
-
const session = this.sessions.get(sessionId);
|
|
1312
|
-
if (!session) {
|
|
1313
|
-
throw new Error(`Session ${sessionId} not found`);
|
|
1314
|
-
}
|
|
1315
|
-
// Check if user choice is enabled for this session
|
|
1316
|
-
if (!session.userChoiceEnabled) {
|
|
1317
|
-
throw new Error('User choice is not enabled for this session');
|
|
1318
|
-
}
|
|
1319
|
-
// Create a promise that will be resolved when the user responds
|
|
1320
|
-
return new Promise((resolve) => {
|
|
1321
|
-
session.pendingChoice = { request, resolve };
|
|
1322
|
-
// Emit the choice request through the onOutput callback
|
|
1323
|
-
// This will be picked up by the CLI and sent to the frontend
|
|
1324
|
-
const handler = this.sessionHandlers.get(sessionId);
|
|
1325
|
-
if (handler?.onChoiceRequest) {
|
|
1326
|
-
handler.onChoiceRequest(request);
|
|
1327
|
-
}
|
|
1328
|
-
// Set timeout if specified
|
|
1329
|
-
if (request.timeout) {
|
|
1330
|
-
setTimeout(() => {
|
|
1331
|
-
if (session.pendingChoice?.request.choiceId === request.choiceId) {
|
|
1332
|
-
session.pendingChoice.resolve({ choiceId: request.choiceId, selectedValue: null });
|
|
1333
|
-
session.pendingChoice = undefined;
|
|
1334
|
-
}
|
|
1335
|
-
}, request.timeout);
|
|
1336
|
-
}
|
|
1337
1243
|
});
|
|
1338
1244
|
}
|
|
1339
1245
|
}
|
package/dist/app-child.js
CHANGED
|
@@ -1341,15 +1341,6 @@ async function runDaemon(foreground = false, email) {
|
|
|
1341
1341
|
socket.emit('session:error', { sessionId, error: 'Session not found or projectPath missing' });
|
|
1342
1342
|
return;
|
|
1343
1343
|
}
|
|
1344
|
-
// Check if user choice is enabled from the prompt data (sent by backend)
|
|
1345
|
-
// Backend now includes enabledModules in the session:prompt event
|
|
1346
|
-
const enabledModules = data.enabledModules || [];
|
|
1347
|
-
const moduleSettings = data.moduleSettings || {};
|
|
1348
|
-
const userChoiceEnabled = enabledModules.includes('user-choice') || false;
|
|
1349
|
-
if (foreground) {
|
|
1350
|
-
console.log(`[CLI] Enabled modules: ${enabledModules.join(', ') || 'none'}`);
|
|
1351
|
-
console.log(`[CLI] User choice enabled: ${userChoiceEnabled}`);
|
|
1352
|
-
}
|
|
1353
1344
|
// Store in activeSessions with promptId and model
|
|
1354
1345
|
activeSessions.set(sessionId, { projectPath, currentPromptId: promptId, model });
|
|
1355
1346
|
// Capture promptId in closure to prevent race conditions when multiple prompts arrive quickly
|
|
@@ -1363,9 +1354,6 @@ async function runDaemon(foreground = false, email) {
|
|
|
1363
1354
|
await agentSessionManager.createSession({
|
|
1364
1355
|
sessionId,
|
|
1365
1356
|
projectPath,
|
|
1366
|
-
userChoiceEnabled, // Pass user choice enabled setting from backend
|
|
1367
|
-
enabledModules, // Pass enabled modules for MCP server
|
|
1368
|
-
moduleSettings, // Pass module settings for MCP server
|
|
1369
1357
|
onOutput: (output) => {
|
|
1370
1358
|
// Serialize data to string if it's an object
|
|
1371
1359
|
const dataString = typeof output.data === 'string'
|
|
@@ -1393,16 +1381,6 @@ async function runDaemon(foreground = false, email) {
|
|
|
1393
1381
|
// The actual session:result is emitted from sendPrompt handler below
|
|
1394
1382
|
// This handler is kept for backward compatibility but may not be used
|
|
1395
1383
|
},
|
|
1396
|
-
onChoiceRequest: (request) => {
|
|
1397
|
-
// Emit choice request to frontend
|
|
1398
|
-
socket.emit('user:choice:request', {
|
|
1399
|
-
sessionId,
|
|
1400
|
-
choiceId: request.choiceId,
|
|
1401
|
-
question: request.question,
|
|
1402
|
-
options: request.options,
|
|
1403
|
-
timeout: request.timeout
|
|
1404
|
-
});
|
|
1405
|
-
}
|
|
1406
1384
|
});
|
|
1407
1385
|
// Send prompt - status updates will be emitted from agentSession when processing starts/completes
|
|
1408
1386
|
await agentSessionManager.sendPrompt(sessionId, prompt, enhancers || [], {
|
|
@@ -1555,25 +1533,6 @@ async function runDaemon(foreground = false, email) {
|
|
|
1555
1533
|
callback?.({ success: false, message: error.message });
|
|
1556
1534
|
}
|
|
1557
1535
|
});
|
|
1558
|
-
// Handle user choice response from frontend
|
|
1559
|
-
socket.on('user:choice:response', async (data) => {
|
|
1560
|
-
try {
|
|
1561
|
-
const { sessionId, choiceId, selectedValue } = data;
|
|
1562
|
-
if (foreground) {
|
|
1563
|
-
console.log(`[CLI] 📝 Received user choice response: choiceId=${choiceId}, selectedValue=${selectedValue}`);
|
|
1564
|
-
}
|
|
1565
|
-
// Forward the response to the agent session manager
|
|
1566
|
-
await agentSessionManager.handleChoiceResponse(sessionId, {
|
|
1567
|
-
choiceId,
|
|
1568
|
-
selectedValue
|
|
1569
|
-
});
|
|
1570
|
-
}
|
|
1571
|
-
catch (error) {
|
|
1572
|
-
if (foreground) {
|
|
1573
|
-
console.error(`✗ Error handling user choice response: ${error.message}`);
|
|
1574
|
-
}
|
|
1575
|
-
}
|
|
1576
|
-
});
|
|
1577
1536
|
socket.on('connect', () => {
|
|
1578
1537
|
if (foreground) {
|
|
1579
1538
|
console.log(`✓ Connected to backend at ${config.apiUrl}`);
|
package/dist/index.js
CHANGED
|
@@ -1286,24 +1286,6 @@ async function runDaemon(foreground = false, email) {
|
|
|
1286
1286
|
socket.emit('session:error', { sessionId, error: 'Session not found or projectPath missing' });
|
|
1287
1287
|
return;
|
|
1288
1288
|
}
|
|
1289
|
-
// Check if user choice is enabled from the prompt data (sent by backend)
|
|
1290
|
-
// Backend now includes enabledModules in the session:prompt event
|
|
1291
|
-
const enabledModules = data.enabledModules || [];
|
|
1292
|
-
const moduleSettings = data.moduleSettings || {};
|
|
1293
|
-
const userChoiceEnabled = enabledModules.includes('user-choice') || false;
|
|
1294
|
-
if (foreground) {
|
|
1295
|
-
console.log(`[CLI] Enabled modules: ${enabledModules.join(', ') || 'none'}`);
|
|
1296
|
-
console.log(`[CLI] User choice enabled: ${userChoiceEnabled}`);
|
|
1297
|
-
}
|
|
1298
|
-
// Store in activeSessions with promptId and model
|
|
1299
|
-
activeSessions.set(sessionId, { projectPath, currentPromptId: promptId, model });
|
|
1300
|
-
if (!projectPath) {
|
|
1301
|
-
if (foreground) {
|
|
1302
|
-
console.error(`✗ Session not found: ${sessionId} (missing projectPath)`);
|
|
1303
|
-
}
|
|
1304
|
-
socket.emit('session:error', { sessionId, error: 'Session not found or projectPath missing' });
|
|
1305
|
-
return;
|
|
1306
|
-
}
|
|
1307
1289
|
// Store in activeSessions with promptId and model
|
|
1308
1290
|
activeSessions.set(sessionId, { projectPath, currentPromptId: promptId, model });
|
|
1309
1291
|
// Capture promptId in closure to prevent race conditions when multiple prompts arrive quickly
|
|
@@ -1317,9 +1299,6 @@ async function runDaemon(foreground = false, email) {
|
|
|
1317
1299
|
await agentSessionManager.createSession({
|
|
1318
1300
|
sessionId,
|
|
1319
1301
|
projectPath,
|
|
1320
|
-
userChoiceEnabled, // Pass user choice enabled setting from backend
|
|
1321
|
-
enabledModules, // Pass enabled modules for MCP server
|
|
1322
|
-
moduleSettings, // Pass module settings for MCP server
|
|
1323
1302
|
onOutput: (output) => {
|
|
1324
1303
|
// Serialize data to string if it's an object
|
|
1325
1304
|
const dataString = typeof output.data === 'string'
|
|
@@ -1347,16 +1326,6 @@ async function runDaemon(foreground = false, email) {
|
|
|
1347
1326
|
// The actual session:result is emitted from sendPrompt handler below
|
|
1348
1327
|
// This handler is kept for backward compatibility but may not be used
|
|
1349
1328
|
},
|
|
1350
|
-
onChoiceRequest: (request) => {
|
|
1351
|
-
// Emit choice request to frontend
|
|
1352
|
-
socket.emit('user:choice:request', {
|
|
1353
|
-
sessionId,
|
|
1354
|
-
choiceId: request.choiceId,
|
|
1355
|
-
question: request.question,
|
|
1356
|
-
options: request.options,
|
|
1357
|
-
timeout: request.timeout
|
|
1358
|
-
});
|
|
1359
|
-
}
|
|
1360
1329
|
});
|
|
1361
1330
|
// Send prompt - status updates will be emitted from agentSession when processing starts/completes
|
|
1362
1331
|
await agentSessionManager.sendPrompt(sessionId, prompt, enhancers || [], {
|
|
@@ -1509,25 +1478,6 @@ async function runDaemon(foreground = false, email) {
|
|
|
1509
1478
|
callback?.({ success: false, message: error.message });
|
|
1510
1479
|
}
|
|
1511
1480
|
});
|
|
1512
|
-
// Handle user choice response from frontend
|
|
1513
|
-
socket.on('user:choice:response', async (data) => {
|
|
1514
|
-
try {
|
|
1515
|
-
const { sessionId, choiceId, selectedValue } = data;
|
|
1516
|
-
if (foreground) {
|
|
1517
|
-
console.log(`[CLI] 📝 Received user choice response: choiceId=${choiceId}, selectedValue=${selectedValue}`);
|
|
1518
|
-
}
|
|
1519
|
-
// Forward the response to the agent session manager
|
|
1520
|
-
await agentSessionManager.handleChoiceResponse(sessionId, {
|
|
1521
|
-
choiceId,
|
|
1522
|
-
selectedValue
|
|
1523
|
-
});
|
|
1524
|
-
}
|
|
1525
|
-
catch (error) {
|
|
1526
|
-
if (foreground) {
|
|
1527
|
-
console.error(`✗ Error handling user choice response: ${error.message}`);
|
|
1528
|
-
}
|
|
1529
|
-
}
|
|
1530
|
-
});
|
|
1531
1481
|
// Handle image save request - saves base64 images to tmp directory
|
|
1532
1482
|
socket.on('image:save', async (data) => {
|
|
1533
1483
|
try {
|
package/dist/moduleMcpServer.js
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Module MCP Server
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
* This allows the agent to interact with modules like user-choice through standard tool calls.
|
|
6
|
-
* Also provides built-in tools like analyze_image for vision capabilities.
|
|
4
|
+
* Provides built-in tools like analyze_image for vision capabilities.
|
|
7
5
|
*/
|
|
8
6
|
import { createSdkMcpServer, tool } from '@anthropic-ai/claude-agent-sdk';
|
|
9
7
|
import { z } from 'zod';
|
|
@@ -11,67 +9,6 @@ import * as fs from 'fs';
|
|
|
11
9
|
import * as path from 'path';
|
|
12
10
|
import * as os from 'os';
|
|
13
11
|
import { getOpenrouterApiKey } from './agentSession.js';
|
|
14
|
-
/**
|
|
15
|
-
* Create a tool for the user-choice module
|
|
16
|
-
*/
|
|
17
|
-
function createUserChoiceTool(onChoiceRequest) {
|
|
18
|
-
const schema = {
|
|
19
|
-
question: z.string(),
|
|
20
|
-
options: z.array(z.object({ label: z.string(), value: z.string() })),
|
|
21
|
-
timeout: z.number().optional()
|
|
22
|
-
};
|
|
23
|
-
return tool('user_choice_request', 'Request user input when making decisions. Use this when you need the user to choose between options or provide input on a decision. This tool will present a modal to the user with your question and wait for their response.', schema, async (args, _extra) => {
|
|
24
|
-
if (!onChoiceRequest) {
|
|
25
|
-
return {
|
|
26
|
-
content: [
|
|
27
|
-
{
|
|
28
|
-
type: 'text',
|
|
29
|
-
text: 'Error: User choice is not enabled. Please use an alternative approach or ask the user directly.'
|
|
30
|
-
}
|
|
31
|
-
],
|
|
32
|
-
isError: true
|
|
33
|
-
};
|
|
34
|
-
}
|
|
35
|
-
const choiceId = `choice-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;
|
|
36
|
-
try {
|
|
37
|
-
const response = await onChoiceRequest({
|
|
38
|
-
choiceId,
|
|
39
|
-
question: args.question,
|
|
40
|
-
options: args.options,
|
|
41
|
-
timeout: args.timeout
|
|
42
|
-
});
|
|
43
|
-
if (response.selectedValue === null) {
|
|
44
|
-
return {
|
|
45
|
-
content: [
|
|
46
|
-
{
|
|
47
|
-
type: 'text',
|
|
48
|
-
text: 'The user did not respond within the timeout period. Please proceed with a reasonable default or ask again.'
|
|
49
|
-
}
|
|
50
|
-
]
|
|
51
|
-
};
|
|
52
|
-
}
|
|
53
|
-
return {
|
|
54
|
-
content: [
|
|
55
|
-
{
|
|
56
|
-
type: 'text',
|
|
57
|
-
text: `The user selected: ${response.selectedValue}`
|
|
58
|
-
}
|
|
59
|
-
]
|
|
60
|
-
};
|
|
61
|
-
}
|
|
62
|
-
catch (error) {
|
|
63
|
-
return {
|
|
64
|
-
content: [
|
|
65
|
-
{
|
|
66
|
-
type: 'text',
|
|
67
|
-
text: `Error requesting user choice: ${error instanceof Error ? error.message : String(error)}`
|
|
68
|
-
}
|
|
69
|
-
],
|
|
70
|
-
isError: true
|
|
71
|
-
};
|
|
72
|
-
}
|
|
73
|
-
});
|
|
74
|
-
}
|
|
75
12
|
/**
|
|
76
13
|
* Convert a file to a data URI for vision API consumption
|
|
77
14
|
*/
|
|
@@ -141,24 +78,12 @@ function createAnalyzeImageTool(attachmentDir) {
|
|
|
141
78
|
});
|
|
142
79
|
}
|
|
143
80
|
/**
|
|
144
|
-
*
|
|
81
|
+
* Create the MCP server with built-in tools (always includes analyze_image)
|
|
145
82
|
*/
|
|
146
|
-
function
|
|
83
|
+
export function createModuleMcpServer(config) {
|
|
147
84
|
const tools = [];
|
|
148
|
-
// User choice module
|
|
149
|
-
if (config.enabledModules.includes('user-choice')) {
|
|
150
|
-
tools.push(createUserChoiceTool(config.onChoiceRequest));
|
|
151
|
-
}
|
|
152
85
|
// Always add analyze_image tool (uses OpenRouter key from ai-config via backend)
|
|
153
86
|
tools.push(createAnalyzeImageTool(config.attachmentDir));
|
|
154
|
-
// Add more module tools here as they are implemented
|
|
155
|
-
return tools;
|
|
156
|
-
}
|
|
157
|
-
/**
|
|
158
|
-
* Create the module MCP server
|
|
159
|
-
*/
|
|
160
|
-
export function createModuleMcpServer(config) {
|
|
161
|
-
const tools = getModuleTools(config);
|
|
162
87
|
const server = createSdkMcpServer({
|
|
163
88
|
name: 'claude-voice-modules',
|
|
164
89
|
version: '1.0.0',
|
package/dist/ttc-cli.tar.gz
CHANGED
|
Binary file
|