@@ -1264,44 +1264,94 @@ export class IpcMain {
12641264 const session = this . getOrCreateSession ( workspaceId ) ;
12651265 const signal = session . startScriptExecution ( ) ;
12661266
1267+ let scriptMessage : MuxMessage | null = null ;
1268+ let scriptMessagePersisted = false ;
1269+ let scriptExecutionStartMs : number | null = null ;
1270+
1271+ const buildScriptFailureResult = (
1272+ errorMessage : string ,
1273+ elapsedMs : number
1274+ ) : BashToolResult => ( {
1275+ success : false ,
1276+ error : errorMessage ,
1277+ output : "" ,
1278+ exitCode : 1 ,
1279+ wall_duration_ms : elapsedMs >= 0 ? elapsedMs : 0 ,
1280+ } ) ;
1281+
1282+ const persistScriptResult = async ( result : BashToolResult ) : Promise < void > => {
1283+ assert (
1284+ scriptMessagePersisted ,
1285+ "Script message must be appended before persisting result"
1286+ ) ;
1287+ assert ( scriptMessage , "Script message must exist before persisting result" ) ;
1288+ const metadata = scriptMessage . metadata ?. muxMetadata ;
1289+ assert (
1290+ metadata ?. type === "script-execution" ,
1291+ "Unexpected script message metadata type"
1292+ ) ;
1293+
1294+ metadata . result = result ;
1295+
1296+ const updateResult = await this . historyService . updateHistory (
1297+ workspaceId ,
1298+ scriptMessage
1299+ ) ;
1300+ if ( ! updateResult . success ) {
1301+ log . error (
1302+ `Failed to update script execution history for workspace ${ workspaceId } : ${ updateResult . error } `
1303+ ) ;
1304+ }
1305+
1306+ if ( this . mainWindow ) {
1307+ const channel = getChatChannel ( workspaceId ) ;
1308+ this . mainWindow . webContents . send ( channel , scriptMessage ) ;
1309+ }
1310+ } ;
1311+
12671312 try {
12681313 // 1. Create and persist script execution message immediately
12691314 // This ensures the user sees "Executing script..." in the timeline while it runs
12701315 const command = `/script ${ scriptName } ${ args . length > 0 ? " " + args . join ( " " ) : "" } ` ;
1271- const scriptMessage : MuxMessage = {
1272- id : `script-${ Date . now ( ) } ` , // Generate a unique ID
1316+ const scriptMessageId = `script-${ Date . now ( ) } ` ;
1317+ const scriptTimestamp = Date . now ( ) ;
1318+ const newScriptMessage : MuxMessage = {
1319+ id : scriptMessageId ,
12731320 role : "user" ,
12741321 parts : [ { type : "text" , text : `Executed script: ${ command } ` } ] ,
12751322 metadata : {
1276- timestamp : Date . now ( ) ,
1323+ timestamp : scriptTimestamp ,
12771324 muxMetadata : {
12781325 type : "script-execution" ,
1279- id : `script- ${ Date . now ( ) } ` , // Can match message ID
1280- timestamp : Date . now ( ) ,
1281- command : command ,
1282- scriptName : scriptName ,
1283- args : args ,
1326+ id : scriptMessageId ,
1327+ timestamp : scriptTimestamp ,
1328+ command,
1329+ scriptName,
1330+ args,
12841331 } ,
12851332 } ,
12861333 } ;
1334+ scriptMessage = newScriptMessage ;
12871335
12881336 const appendResult = await this . historyService . appendToHistory (
12891337 workspaceId ,
1290- scriptMessage
1338+ newScriptMessage
12911339 ) ;
12921340
12931341 if ( appendResult . success ) {
1342+ scriptMessagePersisted = true ;
12941343 // Broadcast the new message to the frontend immediately
12951344 const channel = getChatChannel ( workspaceId ) ;
12961345 if ( this . mainWindow ) {
1297- this . mainWindow . webContents . send ( channel , scriptMessage ) ;
1346+ this . mainWindow . webContents . send ( channel , newScriptMessage ) ;
12981347 }
12991348 } else {
13001349 log . error ( "Failed to persist script execution:" , appendResult . error ) ;
13011350 return Err ( `Failed to persist script execution: ${ appendResult . error } ` ) ;
13021351 }
13031352
13041353 // 2. Execute the script
1354+ scriptExecutionStartMs = Date . now ( ) ;
13051355 const execResult = await runWorkspaceScript (
13061356 runtimeInstance ,
13071357 workspacePath ,
@@ -1312,8 +1362,11 @@ export class IpcMain {
13121362 300 , // timeout
13131363 signal
13141364 ) ;
1365+ const elapsedMs = scriptExecutionStartMs ? Date . now ( ) - scriptExecutionStartMs : 0 ;
1366+ scriptExecutionStartMs = null ;
13151367
13161368 if ( ! execResult . success ) {
1369+ await persistScriptResult ( buildScriptFailureResult ( execResult . error , elapsedMs ) ) ;
13171370 return Err ( execResult . error ) ;
13181371 }
13191372
@@ -1327,22 +1380,22 @@ export class IpcMain {
13271380 } ;
13281381
13291382 // 4. Update the history message with the result
1330- if ( scriptMessage . metadata ?. muxMetadata ?. type === "script-execution" ) {
1331- scriptMessage . metadata . muxMetadata . result = enhancedResult ;
1332- }
1333-
1334- // Update history file
1335- await this . historyService . updateHistory ( workspaceId , scriptMessage ) ;
1336-
1337- // Broadcast the updated message (this puts the result in the UI)
1338- if ( this . mainWindow ) {
1339- const channel = getChatChannel ( workspaceId ) ;
1340- this . mainWindow . webContents . send ( channel , scriptMessage ) ;
1341- }
1383+ await persistScriptResult ( enhancedResult ) ;
13421384
13431385 return Ok ( enhancedResult ) ;
13441386 } catch ( error ) {
13451387 const message = error instanceof Error ? error . message : String ( error ) ;
1388+ const elapsedMs = scriptExecutionStartMs ? Date . now ( ) - scriptExecutionStartMs : 0 ;
1389+ if ( scriptMessagePersisted ) {
1390+ try {
1391+ await persistScriptResult ( buildScriptFailureResult ( message , elapsedMs ) ) ;
1392+ } catch ( persistError ) {
1393+ log . error (
1394+ `Failed to persist script execution failure result for workspace ${ workspaceId } :` ,
1395+ persistError
1396+ ) ;
1397+ }
1398+ }
13461399 return Err ( `Failed to execute script: ${ message } ` ) ;
13471400 } finally {
13481401 session . endScriptExecution ( ) ;
0 commit comments