@getpaseo/server 0.1.2 → 0.1.3
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/server/client/daemon-client.d.ts +11 -5
- package/dist/server/client/daemon-client.d.ts.map +1 -1
- package/dist/server/client/daemon-client.js +54 -46
- package/dist/server/client/daemon-client.js.map +1 -1
- package/dist/server/server/agent/agent-manager.d.ts +7 -0
- package/dist/server/server/agent/agent-manager.d.ts.map +1 -1
- package/dist/server/server/agent/agent-manager.js +41 -1
- package/dist/server/server/agent/agent-manager.js.map +1 -1
- package/dist/server/server/agent/providers/claude/tool-call-detail-parser.d.ts.map +1 -1
- package/dist/server/server/agent/providers/claude/tool-call-detail-parser.js +62 -12
- package/dist/server/server/agent/providers/claude/tool-call-detail-parser.js.map +1 -1
- package/dist/server/server/agent/providers/claude/tool-call-mapper.d.ts +4 -4
- package/dist/server/server/agent/providers/claude/tool-call-mapper.d.ts.map +1 -1
- package/dist/server/server/agent/providers/claude/tool-call-mapper.js +99 -50
- package/dist/server/server/agent/providers/claude/tool-call-mapper.js.map +1 -1
- package/dist/server/server/agent/providers/claude-agent.d.ts.map +1 -1
- package/dist/server/server/agent/providers/claude-agent.js +17 -10
- package/dist/server/server/agent/providers/claude-agent.js.map +1 -1
- package/dist/server/server/agent/providers/codex/tool-call-detail-parser.d.ts +0 -1
- package/dist/server/server/agent/providers/codex/tool-call-detail-parser.d.ts.map +1 -1
- package/dist/server/server/agent/providers/codex/tool-call-detail-parser.js +67 -30
- package/dist/server/server/agent/providers/codex/tool-call-detail-parser.js.map +1 -1
- package/dist/server/server/agent/providers/codex/tool-call-mapper.d.ts +1 -1
- package/dist/server/server/agent/providers/codex/tool-call-mapper.d.ts.map +1 -1
- package/dist/server/server/agent/providers/codex/tool-call-mapper.js +293 -266
- package/dist/server/server/agent/providers/codex/tool-call-mapper.js.map +1 -1
- package/dist/server/server/agent/providers/codex-app-server-agent.d.ts +1 -1
- package/dist/server/server/agent/providers/codex-app-server-agent.d.ts.map +1 -1
- package/dist/server/server/agent/providers/codex-app-server-agent.js +24 -14
- package/dist/server/server/agent/providers/codex-app-server-agent.js.map +1 -1
- package/dist/server/server/agent/providers/codex-rollout-timeline.d.ts.map +1 -1
- package/dist/server/server/agent/providers/codex-rollout-timeline.js +5 -4
- package/dist/server/server/agent/providers/codex-rollout-timeline.js.map +1 -1
- package/dist/server/server/agent/providers/opencode/tool-call-detail-parser.d.ts.map +1 -1
- package/dist/server/server/agent/providers/opencode/tool-call-detail-parser.js +8 -2
- package/dist/server/server/agent/providers/opencode/tool-call-detail-parser.js.map +1 -1
- package/dist/server/server/agent/providers/opencode/tool-call-mapper.d.ts +1 -1
- package/dist/server/server/agent/providers/opencode/tool-call-mapper.d.ts.map +1 -1
- package/dist/server/server/agent/providers/opencode/tool-call-mapper.js +121 -45
- package/dist/server/server/agent/providers/opencode/tool-call-mapper.js.map +1 -1
- package/dist/server/server/agent/providers/opencode-agent.d.ts.map +1 -1
- package/dist/server/server/agent/providers/opencode-agent.js +87 -35
- package/dist/server/server/agent/providers/opencode-agent.js.map +1 -1
- package/dist/server/server/agent/providers/tool-call-detail-primitives.d.ts +2 -2
- package/dist/server/server/agent/providers/tool-call-detail-primitives.d.ts.map +1 -1
- package/dist/server/server/agent/providers/tool-call-detail-primitives.js +23 -6
- package/dist/server/server/agent/providers/tool-call-detail-primitives.js.map +1 -1
- package/dist/server/server/agent/providers/tool-call-mapper-utils.d.ts +0 -1
- package/dist/server/server/agent/providers/tool-call-mapper-utils.d.ts.map +1 -1
- package/dist/server/server/agent/providers/tool-call-mapper-utils.js +0 -10
- package/dist/server/server/agent/providers/tool-call-mapper-utils.js.map +1 -1
- package/dist/server/server/agent/tts-manager.d.ts.map +1 -1
- package/dist/server/server/agent/tts-manager.js +0 -14
- package/dist/server/server/agent/tts-manager.js.map +1 -1
- package/dist/server/server/bootstrap.d.ts.map +1 -1
- package/dist/server/server/bootstrap.js +0 -2
- package/dist/server/server/bootstrap.js.map +1 -1
- package/dist/server/server/dictation/dictation-stream-manager.d.ts.map +1 -1
- package/dist/server/server/dictation/dictation-stream-manager.js +2 -13
- package/dist/server/server/dictation/dictation-stream-manager.js.map +1 -1
- package/dist/server/server/exports.d.ts +1 -0
- package/dist/server/server/exports.d.ts.map +1 -1
- package/dist/server/server/exports.js +1 -0
- package/dist/server/server/exports.js.map +1 -1
- package/dist/server/server/persisted-config.d.ts +32 -18
- package/dist/server/server/persisted-config.d.ts.map +1 -1
- package/dist/server/server/persisted-config.js +2 -0
- package/dist/server/server/persisted-config.js.map +1 -1
- package/dist/server/server/relay-transport.d.ts.map +1 -1
- package/dist/server/server/relay-transport.js +78 -11
- package/dist/server/server/relay-transport.js.map +1 -1
- package/dist/server/server/session.d.ts +2 -8
- package/dist/server/server/session.d.ts.map +1 -1
- package/dist/server/server/session.js +120 -249
- package/dist/server/server/session.js.map +1 -1
- package/dist/server/server/speech/providers/local/config.d.ts.map +1 -1
- package/dist/server/server/speech/providers/local/config.js +11 -8
- package/dist/server/server/speech/providers/local/config.js.map +1 -1
- package/dist/server/server/speech/providers/local/runtime.d.ts.map +1 -1
- package/dist/server/server/speech/providers/local/runtime.js +9 -6
- package/dist/server/server/speech/providers/local/runtime.js.map +1 -1
- package/dist/server/server/speech/providers/local/sherpa/model-downloader.d.ts.map +1 -1
- package/dist/server/server/speech/providers/local/sherpa/model-downloader.js +134 -52
- package/dist/server/server/speech/providers/local/sherpa/model-downloader.js.map +1 -1
- package/dist/server/server/speech/providers/openai/config.d.ts.map +1 -1
- package/dist/server/server/speech/providers/openai/config.js +10 -5
- package/dist/server/server/speech/providers/openai/config.js.map +1 -1
- package/dist/server/server/speech/providers/openai/runtime.d.ts.map +1 -1
- package/dist/server/server/speech/providers/openai/runtime.js +17 -6
- package/dist/server/server/speech/providers/openai/runtime.js.map +1 -1
- package/dist/server/server/speech/speech-config-resolver.d.ts.map +1 -1
- package/dist/server/server/speech/speech-config-resolver.js +25 -4
- package/dist/server/server/speech/speech-config-resolver.js.map +1 -1
- package/dist/server/server/speech/speech-runtime.d.ts.map +1 -1
- package/dist/server/server/speech/speech-runtime.js +44 -15
- package/dist/server/server/speech/speech-runtime.js.map +1 -1
- package/dist/server/server/speech/speech-types.d.ts +3 -0
- package/dist/server/server/speech/speech-types.d.ts.map +1 -1
- package/dist/server/server/speech/speech-types.js +1 -0
- package/dist/server/server/speech/speech-types.js.map +1 -1
- package/dist/server/server/websocket-server.d.ts.map +1 -1
- package/dist/server/server/websocket-server.js +2 -40
- package/dist/server/server/websocket-server.js.map +1 -1
- package/dist/server/shared/messages.d.ts +680 -1328
- package/dist/server/shared/messages.d.ts.map +1 -1
- package/dist/server/shared/messages.js +41 -32
- package/dist/server/shared/messages.js.map +1 -1
- package/dist/server/utils/checkout-git.d.ts +5 -1
- package/dist/server/utils/checkout-git.d.ts.map +1 -1
- package/dist/server/utils/checkout-git.js +222 -75
- package/dist/server/utils/checkout-git.js.map +1 -1
- package/package.json +2 -2
|
@@ -6,7 +6,6 @@ import { promisify } from "util";
|
|
|
6
6
|
import { join, resolve, sep } from "path";
|
|
7
7
|
import { z } from "zod";
|
|
8
8
|
import { serializeAgentStreamEvent, } from "./messages.js";
|
|
9
|
-
import { parseAndHighlightDiff } from "./utils/diff-highlighter.js";
|
|
10
9
|
import { TTSManager } from "./agent/tts-manager.js";
|
|
11
10
|
import { STTManager } from "./agent/stt-manager.js";
|
|
12
11
|
import { maybePersistTtsDebugAudio } from "./agent/tts-debug.js";
|
|
@@ -261,7 +260,7 @@ export class Session {
|
|
|
261
260
|
// Initialize agent MCP client asynchronously
|
|
262
261
|
void this.initializeAgentMcp();
|
|
263
262
|
this.subscribeToAgentEvents();
|
|
264
|
-
this.sessionLogger.
|
|
263
|
+
this.sessionLogger.trace("Session created");
|
|
265
264
|
}
|
|
266
265
|
/**
|
|
267
266
|
* Get the client's current activity state
|
|
@@ -331,11 +330,11 @@ export class Session {
|
|
|
331
330
|
/**
|
|
332
331
|
* Start streaming an agent run and forward results via the websocket broadcast
|
|
333
332
|
*/
|
|
334
|
-
startAgentStream(agentId, prompt) {
|
|
333
|
+
startAgentStream(agentId, prompt, runOptions) {
|
|
335
334
|
this.sessionLogger.info({ agentId }, `Starting agent stream for ${agentId}`);
|
|
336
335
|
let iterator;
|
|
337
336
|
try {
|
|
338
|
-
iterator = this.agentManager.streamAgent(agentId, prompt);
|
|
337
|
+
iterator = this.agentManager.streamAgent(agentId, prompt, runOptions);
|
|
339
338
|
}
|
|
340
339
|
catch (error) {
|
|
341
340
|
this.handleAgentRunError(agentId, error, "Failed to start agent run");
|
|
@@ -379,7 +378,7 @@ export class Session {
|
|
|
379
378
|
});
|
|
380
379
|
this.agentTools = (await this.agentMcpClient.tools());
|
|
381
380
|
const agentToolCount = Object.keys(this.agentTools ?? {}).length;
|
|
382
|
-
this.sessionLogger.
|
|
381
|
+
this.sessionLogger.trace({ agentToolCount }, `Agent MCP initialized with ${agentToolCount} tools`);
|
|
383
382
|
}
|
|
384
383
|
catch (error) {
|
|
385
384
|
this.sessionLogger.error({ err: error }, "Failed to initialize Agent MCP");
|
|
@@ -534,10 +533,12 @@ export class Session {
|
|
|
534
533
|
let snapshot;
|
|
535
534
|
if (handle) {
|
|
536
535
|
snapshot = await this.agentManager.resumeAgentFromPersistence(handle, buildConfigOverrides(record), agentId, extractTimestamps(record));
|
|
536
|
+
this.sessionLogger.info({ agentId, provider: record.provider }, "Agent resumed from persistence");
|
|
537
537
|
}
|
|
538
538
|
else {
|
|
539
539
|
const config = buildSessionConfig(record);
|
|
540
540
|
snapshot = await this.agentManager.createAgent(config, agentId, { labels: record.labels });
|
|
541
|
+
this.sessionLogger.info({ agentId, provider: record.provider }, "Agent created from stored config");
|
|
541
542
|
}
|
|
542
543
|
await this.agentManager.hydrateTimelineFromProvider(agentId);
|
|
543
544
|
return this.agentManager.getAgent(agentId) ?? snapshot;
|
|
@@ -685,6 +686,9 @@ export class Session {
|
|
|
685
686
|
case "archive_agent_request":
|
|
686
687
|
await this.handleArchiveAgentRequest(msg.agentId, msg.requestId);
|
|
687
688
|
break;
|
|
689
|
+
case "update_agent_request":
|
|
690
|
+
await this.handleUpdateAgentRequest(msg.agentId, msg.name, msg.labels, msg.requestId);
|
|
691
|
+
break;
|
|
688
692
|
case "set_voice_mode":
|
|
689
693
|
await this.handleSetVoiceMode(msg.enabled, msg.agentId, msg.requestId);
|
|
690
694
|
break;
|
|
@@ -741,9 +745,6 @@ export class Session {
|
|
|
741
745
|
case "agent_permission_response":
|
|
742
746
|
await this.handleAgentPermissionResponse(msg.agentId, msg.requestId, msg.response);
|
|
743
747
|
break;
|
|
744
|
-
case "git_diff_request":
|
|
745
|
-
await this.handleGitDiffRequest(msg.agentId, msg.requestId);
|
|
746
|
-
break;
|
|
747
748
|
case "checkout_status_request":
|
|
748
749
|
await this.handleCheckoutStatusRequest(msg);
|
|
749
750
|
break;
|
|
@@ -780,9 +781,6 @@ export class Session {
|
|
|
780
781
|
case "paseo_worktree_archive_request":
|
|
781
782
|
await this.handlePaseoWorktreeArchiveRequest(msg);
|
|
782
783
|
break;
|
|
783
|
-
case "highlighted_diff_request":
|
|
784
|
-
await this.handleHighlightedDiffRequest(msg.agentId, msg.requestId);
|
|
785
|
-
break;
|
|
786
784
|
case "file_explorer_request":
|
|
787
785
|
await this.handleFileExplorerRequest(msg);
|
|
788
786
|
break;
|
|
@@ -795,6 +793,9 @@ export class Session {
|
|
|
795
793
|
case "list_provider_models_request":
|
|
796
794
|
await this.handleListProviderModelsRequest(msg);
|
|
797
795
|
break;
|
|
796
|
+
case "list_available_providers_request":
|
|
797
|
+
await this.handleListAvailableProvidersRequest(msg);
|
|
798
|
+
break;
|
|
798
799
|
case "speech_models_list_request":
|
|
799
800
|
await this.handleSpeechModelsListRequest(msg);
|
|
800
801
|
break;
|
|
@@ -965,6 +966,72 @@ export class Session {
|
|
|
965
966
|
},
|
|
966
967
|
});
|
|
967
968
|
}
|
|
969
|
+
async handleUpdateAgentRequest(agentId, name, labels, requestId) {
|
|
970
|
+
this.sessionLogger.info({ agentId, requestId, hasName: typeof name === "string", labelCount: labels ? Object.keys(labels).length : 0 }, "session: update_agent_request");
|
|
971
|
+
const normalizedName = name?.trim();
|
|
972
|
+
const normalizedLabels = labels && Object.keys(labels).length > 0 ? labels : undefined;
|
|
973
|
+
if (!normalizedName && !normalizedLabels) {
|
|
974
|
+
this.emit({
|
|
975
|
+
type: "update_agent_response",
|
|
976
|
+
payload: {
|
|
977
|
+
requestId,
|
|
978
|
+
agentId,
|
|
979
|
+
accepted: false,
|
|
980
|
+
error: "Nothing to update (provide name and/or labels)",
|
|
981
|
+
},
|
|
982
|
+
});
|
|
983
|
+
return;
|
|
984
|
+
}
|
|
985
|
+
try {
|
|
986
|
+
const liveAgent = this.agentManager.getAgent(agentId);
|
|
987
|
+
if (liveAgent) {
|
|
988
|
+
if (normalizedName) {
|
|
989
|
+
await this.agentManager.setTitle(agentId, normalizedName);
|
|
990
|
+
}
|
|
991
|
+
if (normalizedLabels) {
|
|
992
|
+
await this.agentManager.setLabels(agentId, normalizedLabels);
|
|
993
|
+
}
|
|
994
|
+
}
|
|
995
|
+
else {
|
|
996
|
+
const existing = await this.agentStorage.get(agentId);
|
|
997
|
+
if (!existing) {
|
|
998
|
+
throw new Error(`Agent not found: ${agentId}`);
|
|
999
|
+
}
|
|
1000
|
+
await this.agentStorage.upsert({
|
|
1001
|
+
...existing,
|
|
1002
|
+
...(normalizedName ? { title: normalizedName } : {}),
|
|
1003
|
+
...(normalizedLabels
|
|
1004
|
+
? { labels: { ...existing.labels, ...normalizedLabels } }
|
|
1005
|
+
: {}),
|
|
1006
|
+
});
|
|
1007
|
+
}
|
|
1008
|
+
this.emit({
|
|
1009
|
+
type: "update_agent_response",
|
|
1010
|
+
payload: { requestId, agentId, accepted: true, error: null },
|
|
1011
|
+
});
|
|
1012
|
+
}
|
|
1013
|
+
catch (error) {
|
|
1014
|
+
this.sessionLogger.error({ err: error, agentId, requestId }, "session: update_agent_request error");
|
|
1015
|
+
this.emit({
|
|
1016
|
+
type: "activity_log",
|
|
1017
|
+
payload: {
|
|
1018
|
+
id: uuidv4(),
|
|
1019
|
+
timestamp: new Date(),
|
|
1020
|
+
type: "error",
|
|
1021
|
+
content: `Failed to update agent: ${error.message}`,
|
|
1022
|
+
},
|
|
1023
|
+
});
|
|
1024
|
+
this.emit({
|
|
1025
|
+
type: "update_agent_response",
|
|
1026
|
+
payload: {
|
|
1027
|
+
requestId,
|
|
1028
|
+
agentId,
|
|
1029
|
+
accepted: false,
|
|
1030
|
+
error: error?.message ? String(error.message) : "Failed to update agent",
|
|
1031
|
+
},
|
|
1032
|
+
});
|
|
1033
|
+
}
|
|
1034
|
+
}
|
|
968
1035
|
/**
|
|
969
1036
|
* Handle voice mode toggle
|
|
970
1037
|
*/
|
|
@@ -1318,7 +1385,7 @@ export class Session {
|
|
|
1318
1385
|
/**
|
|
1319
1386
|
* Handle text message to agent (with optional image attachments)
|
|
1320
1387
|
*/
|
|
1321
|
-
async handleSendAgentMessage(agentId, text, messageId, images) {
|
|
1388
|
+
async handleSendAgentMessage(agentId, text, messageId, images, runOptions) {
|
|
1322
1389
|
this.sessionLogger.info({ agentId, textPreview: text.substring(0, 50), imageCount: images?.length ?? 0 }, `Sending text to agent ${agentId}${images && images.length > 0 ? ` with ${images.length} image attachment(s)` : ''}`);
|
|
1323
1390
|
try {
|
|
1324
1391
|
await this.ensureAgentLoaded(agentId);
|
|
@@ -1341,13 +1408,12 @@ export class Session {
|
|
|
1341
1408
|
catch (error) {
|
|
1342
1409
|
this.sessionLogger.error({ err: error, agentId }, `Failed to record user message for agent ${agentId}`);
|
|
1343
1410
|
}
|
|
1344
|
-
this.startAgentStream(agentId, prompt);
|
|
1411
|
+
this.startAgentStream(agentId, prompt, runOptions);
|
|
1345
1412
|
}
|
|
1346
1413
|
/**
|
|
1347
1414
|
* Handle on-demand agent initialization request from client
|
|
1348
1415
|
*/
|
|
1349
1416
|
async handleInitializeAgentRequest(agentId, requestId) {
|
|
1350
|
-
this.sessionLogger.info({ agentId }, `Initializing agent ${agentId} on demand`);
|
|
1351
1417
|
try {
|
|
1352
1418
|
const snapshot = await this.ensureAgentLoaded(agentId);
|
|
1353
1419
|
await this.forwardAgentUpdate(snapshot);
|
|
@@ -1362,7 +1428,6 @@ export class Session {
|
|
|
1362
1428
|
requestId,
|
|
1363
1429
|
},
|
|
1364
1430
|
});
|
|
1365
|
-
this.sessionLogger.info({ agentId, timelineSize, status: snapshot.lifecycle }, `Agent ${agentId} initialized with ${timelineSize} timeline item(s); status=${snapshot.lifecycle}`);
|
|
1366
1431
|
}
|
|
1367
1432
|
catch (error) {
|
|
1368
1433
|
this.sessionLogger.error({ err: error, agentId }, `Failed to initialize agent ${agentId}`);
|
|
@@ -1380,7 +1445,7 @@ export class Session {
|
|
|
1380
1445
|
* Handle create agent request
|
|
1381
1446
|
*/
|
|
1382
1447
|
async handleCreateAgentRequest(msg) {
|
|
1383
|
-
const { config, worktreeName, requestId, initialPrompt, git, images, labels } = msg;
|
|
1448
|
+
const { config, worktreeName, requestId, initialPrompt, outputSchema, git, images, labels } = msg;
|
|
1384
1449
|
this.sessionLogger.info({ cwd: config.cwd, provider: config.provider, worktreeName }, `Creating agent in ${config.cwd} (${config.provider})${worktreeName ? ` with worktree ${worktreeName}` : ""}`);
|
|
1385
1450
|
try {
|
|
1386
1451
|
const { sessionConfig, worktreeConfig } = await this.buildAgentSessionConfig(config, git, worktreeName, labels);
|
|
@@ -1398,7 +1463,7 @@ export class Session {
|
|
|
1398
1463
|
logger: this.sessionLogger,
|
|
1399
1464
|
});
|
|
1400
1465
|
try {
|
|
1401
|
-
await this.handleSendAgentMessage(snapshot.id, trimmedPrompt, uuidv4(), images);
|
|
1466
|
+
await this.handleSendAgentMessage(snapshot.id, trimmedPrompt, uuidv4(), images, outputSchema ? { outputSchema } : undefined);
|
|
1402
1467
|
}
|
|
1403
1468
|
catch (promptError) {
|
|
1404
1469
|
this.sessionLogger.error({ err: promptError, agentId: snapshot.id }, `Failed to run initial prompt for agent ${snapshot.id}`);
|
|
@@ -1752,6 +1817,33 @@ export class Session {
|
|
|
1752
1817
|
});
|
|
1753
1818
|
}
|
|
1754
1819
|
}
|
|
1820
|
+
async handleListAvailableProvidersRequest(msg) {
|
|
1821
|
+
const fetchedAt = new Date().toISOString();
|
|
1822
|
+
try {
|
|
1823
|
+
const providers = await this.agentManager.listProviderAvailability();
|
|
1824
|
+
this.emit({
|
|
1825
|
+
type: "list_available_providers_response",
|
|
1826
|
+
payload: {
|
|
1827
|
+
providers,
|
|
1828
|
+
error: null,
|
|
1829
|
+
fetchedAt,
|
|
1830
|
+
requestId: msg.requestId,
|
|
1831
|
+
},
|
|
1832
|
+
});
|
|
1833
|
+
}
|
|
1834
|
+
catch (error) {
|
|
1835
|
+
this.sessionLogger.error({ err: error }, "Failed to list provider availability");
|
|
1836
|
+
this.emit({
|
|
1837
|
+
type: "list_available_providers_response",
|
|
1838
|
+
payload: {
|
|
1839
|
+
providers: [],
|
|
1840
|
+
error: error?.message ?? String(error),
|
|
1841
|
+
fetchedAt,
|
|
1842
|
+
requestId: msg.requestId,
|
|
1843
|
+
},
|
|
1844
|
+
});
|
|
1845
|
+
}
|
|
1846
|
+
}
|
|
1755
1847
|
async handleSpeechModelsListRequest(msg) {
|
|
1756
1848
|
const modelsDir = this.localSpeechModelsDir;
|
|
1757
1849
|
const models = await Promise.all(listLocalSpeechModels().map(async (model) => {
|
|
@@ -2377,52 +2469,6 @@ export class Session {
|
|
|
2377
2469
|
throw error;
|
|
2378
2470
|
}
|
|
2379
2471
|
}
|
|
2380
|
-
/**
|
|
2381
|
-
* Handle git diff request for an agent
|
|
2382
|
-
*/
|
|
2383
|
-
async handleGitDiffRequest(agentId, requestId) {
|
|
2384
|
-
this.sessionLogger.debug({ agentId }, `Handling git diff request for agent ${agentId}`);
|
|
2385
|
-
try {
|
|
2386
|
-
const agents = this.agentManager.listAgents();
|
|
2387
|
-
const agent = agents.find((a) => a.id === agentId);
|
|
2388
|
-
if (!agent) {
|
|
2389
|
-
this.emit({
|
|
2390
|
-
type: "git_diff_response",
|
|
2391
|
-
payload: {
|
|
2392
|
-
agentId,
|
|
2393
|
-
diff: "",
|
|
2394
|
-
error: `Agent not found: ${agentId}`,
|
|
2395
|
-
requestId,
|
|
2396
|
-
},
|
|
2397
|
-
});
|
|
2398
|
-
return;
|
|
2399
|
-
}
|
|
2400
|
-
const diffResult = await getCheckoutDiff(agent.cwd, { mode: "uncommitted" }, { paseoHome: this.paseoHome });
|
|
2401
|
-
const combinedDiff = diffResult.diff;
|
|
2402
|
-
this.emit({
|
|
2403
|
-
type: "git_diff_response",
|
|
2404
|
-
payload: {
|
|
2405
|
-
agentId,
|
|
2406
|
-
diff: combinedDiff,
|
|
2407
|
-
error: null,
|
|
2408
|
-
requestId,
|
|
2409
|
-
},
|
|
2410
|
-
});
|
|
2411
|
-
this.sessionLogger.debug({ agentId, diffBytes: combinedDiff.length }, `Git diff for agent ${agentId} completed (${combinedDiff.length} bytes)`);
|
|
2412
|
-
}
|
|
2413
|
-
catch (error) {
|
|
2414
|
-
this.sessionLogger.error({ err: error, agentId }, `Failed to get git diff for agent ${agentId}`);
|
|
2415
|
-
this.emit({
|
|
2416
|
-
type: "git_diff_response",
|
|
2417
|
-
payload: {
|
|
2418
|
-
agentId,
|
|
2419
|
-
diff: "",
|
|
2420
|
-
error: error.message,
|
|
2421
|
-
requestId,
|
|
2422
|
-
},
|
|
2423
|
-
});
|
|
2424
|
-
}
|
|
2425
|
-
}
|
|
2426
2472
|
async handleCheckoutStatusRequest(msg) {
|
|
2427
2473
|
const { cwd, requestId } = msg;
|
|
2428
2474
|
try {
|
|
@@ -3051,12 +3097,13 @@ export class Session {
|
|
|
3051
3097
|
async handleCheckoutPrStatusRequest(msg) {
|
|
3052
3098
|
const { cwd, requestId } = msg;
|
|
3053
3099
|
try {
|
|
3054
|
-
const
|
|
3100
|
+
const prStatus = await getPullRequestStatus(cwd);
|
|
3055
3101
|
this.emit({
|
|
3056
3102
|
type: "checkout_pr_status_response",
|
|
3057
3103
|
payload: {
|
|
3058
3104
|
cwd,
|
|
3059
|
-
status,
|
|
3105
|
+
status: prStatus.status,
|
|
3106
|
+
githubFeaturesEnabled: prStatus.githubFeaturesEnabled,
|
|
3060
3107
|
error: null,
|
|
3061
3108
|
requestId,
|
|
3062
3109
|
},
|
|
@@ -3068,6 +3115,7 @@ export class Session {
|
|
|
3068
3115
|
payload: {
|
|
3069
3116
|
cwd,
|
|
3070
3117
|
status: null,
|
|
3118
|
+
githubFeaturesEnabled: true,
|
|
3071
3119
|
error: this.toCheckoutError(error),
|
|
3072
3120
|
requestId,
|
|
3073
3121
|
},
|
|
@@ -3223,185 +3271,6 @@ export class Session {
|
|
|
3223
3271
|
});
|
|
3224
3272
|
}
|
|
3225
3273
|
}
|
|
3226
|
-
/**
|
|
3227
|
-
* Handle highlighted diff request - returns parsed and syntax-highlighted diff
|
|
3228
|
-
*/
|
|
3229
|
-
async handleHighlightedDiffRequest(agentId, requestId) {
|
|
3230
|
-
this.sessionLogger.debug({ agentId }, `Handling highlighted diff request for agent ${agentId}`);
|
|
3231
|
-
// Maximum lines changed before we skip showing the diff content
|
|
3232
|
-
const MAX_DIFF_LINES = 5000;
|
|
3233
|
-
try {
|
|
3234
|
-
const agents = this.agentManager.listAgents();
|
|
3235
|
-
const agent = agents.find((a) => a.id === agentId);
|
|
3236
|
-
if (!agent) {
|
|
3237
|
-
this.emit({
|
|
3238
|
-
type: "highlighted_diff_response",
|
|
3239
|
-
payload: {
|
|
3240
|
-
agentId,
|
|
3241
|
-
files: [],
|
|
3242
|
-
error: `Agent not found: ${agentId}`,
|
|
3243
|
-
requestId,
|
|
3244
|
-
},
|
|
3245
|
-
});
|
|
3246
|
-
return;
|
|
3247
|
-
}
|
|
3248
|
-
// Step 1: Get the list of changed files with their stats (numstat gives additions/deletions per file)
|
|
3249
|
-
const { stdout: numstatOutput } = await execAsync("git diff --numstat HEAD", { cwd: agent.cwd });
|
|
3250
|
-
// Get file statuses (A=added, D=deleted, M=modified) to detect deleted files
|
|
3251
|
-
const { stdout: nameStatusOutput } = await execAsync("git diff --name-status HEAD", { cwd: agent.cwd });
|
|
3252
|
-
const deletedFiles = new Set();
|
|
3253
|
-
const addedFiles = new Set();
|
|
3254
|
-
for (const line of nameStatusOutput.trim().split("\n").filter(Boolean)) {
|
|
3255
|
-
const [status, ...pathParts] = line.split("\t");
|
|
3256
|
-
const path = pathParts.join("\t");
|
|
3257
|
-
if (status === "D") {
|
|
3258
|
-
deletedFiles.add(path);
|
|
3259
|
-
}
|
|
3260
|
-
else if (status === "A") {
|
|
3261
|
-
addedFiles.add(path);
|
|
3262
|
-
}
|
|
3263
|
-
}
|
|
3264
|
-
const fileStats = [];
|
|
3265
|
-
for (const line of numstatOutput.trim().split("\n").filter(Boolean)) {
|
|
3266
|
-
const parts = line.split("\t");
|
|
3267
|
-
if (parts.length >= 3) {
|
|
3268
|
-
const [addStr, delStr, ...pathParts] = parts;
|
|
3269
|
-
const path = pathParts.join("\t"); // Handle paths with tabs
|
|
3270
|
-
const isBinary = addStr === "-" && delStr === "-";
|
|
3271
|
-
fileStats.push({
|
|
3272
|
-
path,
|
|
3273
|
-
additions: isBinary ? 0 : parseInt(addStr, 10),
|
|
3274
|
-
deletions: isBinary ? 0 : parseInt(delStr, 10),
|
|
3275
|
-
isBinary,
|
|
3276
|
-
isTracked: true,
|
|
3277
|
-
isDeleted: deletedFiles.has(path),
|
|
3278
|
-
isNew: addedFiles.has(path),
|
|
3279
|
-
});
|
|
3280
|
-
}
|
|
3281
|
-
}
|
|
3282
|
-
// Step 2: Get untracked files
|
|
3283
|
-
try {
|
|
3284
|
-
const { stdout: untrackedFiles } = await execAsync("git ls-files --others --exclude-standard", { cwd: agent.cwd });
|
|
3285
|
-
for (const filePath of untrackedFiles.trim().split("\n").filter(Boolean)) {
|
|
3286
|
-
// Use git's numstat with --no-index to detect binary files (cross-platform)
|
|
3287
|
-
// Binary files show as "-\t-\tfilepath", text files show line counts
|
|
3288
|
-
try {
|
|
3289
|
-
const { stdout: numstatLine } = await execAsync(`git diff --numstat --no-index /dev/null "${filePath}" || true`, { cwd: agent.cwd });
|
|
3290
|
-
const parts = numstatLine.trim().split("\t");
|
|
3291
|
-
const isBinary = parts[0] === "-" && parts[1] === "-";
|
|
3292
|
-
const additions = isBinary ? 0 : (parseInt(parts[0], 10) || 0);
|
|
3293
|
-
fileStats.push({
|
|
3294
|
-
path: filePath,
|
|
3295
|
-
additions,
|
|
3296
|
-
deletions: 0,
|
|
3297
|
-
isBinary,
|
|
3298
|
-
isTracked: false,
|
|
3299
|
-
isDeleted: false,
|
|
3300
|
-
isNew: true,
|
|
3301
|
-
});
|
|
3302
|
-
}
|
|
3303
|
-
catch {
|
|
3304
|
-
// If we can't determine, assume text and try to get it
|
|
3305
|
-
fileStats.push({
|
|
3306
|
-
path: filePath,
|
|
3307
|
-
additions: 0,
|
|
3308
|
-
deletions: 0,
|
|
3309
|
-
isBinary: false,
|
|
3310
|
-
isTracked: false,
|
|
3311
|
-
isDeleted: false,
|
|
3312
|
-
isNew: true,
|
|
3313
|
-
});
|
|
3314
|
-
}
|
|
3315
|
-
}
|
|
3316
|
-
}
|
|
3317
|
-
catch {
|
|
3318
|
-
// Ignore errors getting untracked files
|
|
3319
|
-
}
|
|
3320
|
-
// Step 3: Fetch diffs per-file, respecting limits
|
|
3321
|
-
const allFiles = [];
|
|
3322
|
-
for (const stats of fileStats) {
|
|
3323
|
-
const totalLines = stats.additions + stats.deletions;
|
|
3324
|
-
// Handle binary files
|
|
3325
|
-
if (stats.isBinary) {
|
|
3326
|
-
allFiles.push({
|
|
3327
|
-
path: stats.path,
|
|
3328
|
-
isNew: stats.isNew,
|
|
3329
|
-
isDeleted: stats.isDeleted,
|
|
3330
|
-
additions: 0,
|
|
3331
|
-
deletions: 0,
|
|
3332
|
-
hunks: [],
|
|
3333
|
-
status: "binary",
|
|
3334
|
-
});
|
|
3335
|
-
continue;
|
|
3336
|
-
}
|
|
3337
|
-
// Handle files that are too large
|
|
3338
|
-
if (totalLines > MAX_DIFF_LINES) {
|
|
3339
|
-
allFiles.push({
|
|
3340
|
-
path: stats.path,
|
|
3341
|
-
isNew: stats.isNew,
|
|
3342
|
-
isDeleted: stats.isDeleted,
|
|
3343
|
-
additions: stats.additions,
|
|
3344
|
-
deletions: stats.deletions,
|
|
3345
|
-
hunks: [],
|
|
3346
|
-
status: "too_large",
|
|
3347
|
-
});
|
|
3348
|
-
continue;
|
|
3349
|
-
}
|
|
3350
|
-
// Fetch the actual diff for this file
|
|
3351
|
-
try {
|
|
3352
|
-
let fileDiff;
|
|
3353
|
-
if (stats.isTracked) {
|
|
3354
|
-
const { stdout } = await execAsync(`git diff HEAD -- "${stats.path}"`, { cwd: agent.cwd });
|
|
3355
|
-
fileDiff = stdout;
|
|
3356
|
-
}
|
|
3357
|
-
else {
|
|
3358
|
-
const { stdout } = await execAsync(`git diff --no-index /dev/null "${stats.path}" || true`, { cwd: agent.cwd });
|
|
3359
|
-
fileDiff = stdout;
|
|
3360
|
-
}
|
|
3361
|
-
if (fileDiff) {
|
|
3362
|
-
const parsedFiles = await parseAndHighlightDiff(fileDiff, agent.cwd);
|
|
3363
|
-
for (const file of parsedFiles) {
|
|
3364
|
-
allFiles.push({ ...file, status: "ok" });
|
|
3365
|
-
}
|
|
3366
|
-
}
|
|
3367
|
-
}
|
|
3368
|
-
catch {
|
|
3369
|
-
// If diff fails for this file, add it with empty hunks
|
|
3370
|
-
allFiles.push({
|
|
3371
|
-
path: stats.path,
|
|
3372
|
-
isNew: stats.isNew,
|
|
3373
|
-
isDeleted: stats.isDeleted,
|
|
3374
|
-
additions: stats.additions,
|
|
3375
|
-
deletions: stats.deletions,
|
|
3376
|
-
hunks: [],
|
|
3377
|
-
status: "ok",
|
|
3378
|
-
});
|
|
3379
|
-
}
|
|
3380
|
-
}
|
|
3381
|
-
this.emit({
|
|
3382
|
-
type: "highlighted_diff_response",
|
|
3383
|
-
payload: {
|
|
3384
|
-
agentId,
|
|
3385
|
-
files: allFiles,
|
|
3386
|
-
error: null,
|
|
3387
|
-
requestId,
|
|
3388
|
-
},
|
|
3389
|
-
});
|
|
3390
|
-
this.sessionLogger.debug({ agentId, fileCount: allFiles.length }, `Highlighted diff for agent ${agentId} completed (${allFiles.length} files)`);
|
|
3391
|
-
}
|
|
3392
|
-
catch (error) {
|
|
3393
|
-
this.sessionLogger.error({ err: error, agentId }, `Failed to get highlighted diff for agent ${agentId}`);
|
|
3394
|
-
this.emit({
|
|
3395
|
-
type: "highlighted_diff_response",
|
|
3396
|
-
payload: {
|
|
3397
|
-
agentId,
|
|
3398
|
-
files: [],
|
|
3399
|
-
error: error.message,
|
|
3400
|
-
requestId,
|
|
3401
|
-
},
|
|
3402
|
-
});
|
|
3403
|
-
}
|
|
3404
|
-
}
|
|
3405
3274
|
/**
|
|
3406
3275
|
* Handle read-only file explorer requests scoped to an agent's cwd
|
|
3407
3276
|
*/
|
|
@@ -3825,7 +3694,7 @@ export class Session {
|
|
|
3825
3694
|
if (!resolved.ok) {
|
|
3826
3695
|
this.emit({
|
|
3827
3696
|
type: "wait_for_finish_response",
|
|
3828
|
-
payload: { requestId, status: "error", final: null, error: resolved.error },
|
|
3697
|
+
payload: { requestId, status: "error", final: null, error: resolved.error, lastMessage: null },
|
|
3829
3698
|
});
|
|
3830
3699
|
return;
|
|
3831
3700
|
}
|
|
@@ -3841,6 +3710,7 @@ export class Session {
|
|
|
3841
3710
|
status: "error",
|
|
3842
3711
|
final: null,
|
|
3843
3712
|
error: `Agent not found: ${agentId}`,
|
|
3713
|
+
lastMessage: null,
|
|
3844
3714
|
},
|
|
3845
3715
|
});
|
|
3846
3716
|
return;
|
|
@@ -3853,7 +3723,7 @@ export class Session {
|
|
|
3853
3723
|
: "idle";
|
|
3854
3724
|
this.emit({
|
|
3855
3725
|
type: "wait_for_finish_response",
|
|
3856
|
-
payload: { requestId, status, final, error: null },
|
|
3726
|
+
payload: { requestId, status, final, error: null, lastMessage: null },
|
|
3857
3727
|
});
|
|
3858
3728
|
return;
|
|
3859
3729
|
}
|
|
@@ -3877,7 +3747,7 @@ export class Session {
|
|
|
3877
3747
|
: "idle";
|
|
3878
3748
|
this.emit({
|
|
3879
3749
|
type: "wait_for_finish_response",
|
|
3880
|
-
payload: { requestId, status, final, error: null },
|
|
3750
|
+
payload: { requestId, status, final, error: null, lastMessage: result.lastMessage },
|
|
3881
3751
|
});
|
|
3882
3752
|
}
|
|
3883
3753
|
catch (error) {
|
|
@@ -3894,6 +3764,7 @@ export class Session {
|
|
|
3894
3764
|
status: "error",
|
|
3895
3765
|
final,
|
|
3896
3766
|
error: message,
|
|
3767
|
+
lastMessage: null,
|
|
3897
3768
|
},
|
|
3898
3769
|
});
|
|
3899
3770
|
return;
|
|
@@ -3904,7 +3775,7 @@ export class Session {
|
|
|
3904
3775
|
}
|
|
3905
3776
|
this.emit({
|
|
3906
3777
|
type: "wait_for_finish_response",
|
|
3907
|
-
payload: { requestId, status: "timeout", final, error: null },
|
|
3778
|
+
payload: { requestId, status: "timeout", final, error: null, lastMessage: null },
|
|
3908
3779
|
});
|
|
3909
3780
|
}
|
|
3910
3781
|
finally {
|
|
@@ -4390,7 +4261,7 @@ export class Session {
|
|
|
4390
4261
|
* Clean up session resources
|
|
4391
4262
|
*/
|
|
4392
4263
|
async cleanup() {
|
|
4393
|
-
this.sessionLogger.
|
|
4264
|
+
this.sessionLogger.trace("Cleaning up");
|
|
4394
4265
|
if (this.unsubscribeAgentEvents) {
|
|
4395
4266
|
this.unsubscribeAgentEvents();
|
|
4396
4267
|
this.unsubscribeAgentEvents = null;
|