@posthog/agent 2.1.47 → 2.1.48
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/{agent-BJ7Uacyp.d.ts → agent-DcBmoTR4.d.ts} +0 -2
- package/dist/agent.d.ts +1 -1
- package/dist/agent.js +42 -122
- package/dist/agent.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +169 -247
- package/dist/index.js.map +1 -1
- package/dist/server/agent-server.js +169 -246
- package/dist/server/agent-server.js.map +1 -1
- package/dist/server/bin.cjs +169 -246
- package/dist/server/bin.cjs.map +1 -1
- package/package.json +1 -1
- package/src/adapters/acp-connection.ts +1 -6
- package/src/adapters/claude/claude-agent.ts +39 -75
- package/src/agent.ts +0 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { A as AcpConnection, a as AcpConnectionConfig, b as Agent, c as AgentAdapter, C as CodexProcessOptions, I as InProcessAcpConnection, O as OtelLogConfig, d as OtelLogWriter, S as SessionContext, e as SessionLogWriter, f as SessionLogWriterOptions, g as createAcpConnection } from './agent-
|
|
1
|
+
export { A as AcpConnection, a as AcpConnectionConfig, b as Agent, c as AgentAdapter, C as CodexProcessOptions, I as InProcessAcpConnection, O as OtelLogConfig, d as OtelLogWriter, S as SessionContext, e as SessionLogWriter, f as SessionLogWriterOptions, g as createAcpConnection } from './agent-DcBmoTR4.js';
|
|
2
2
|
import { McpServerConfig } from '@anthropic-ai/claude-agent-sdk';
|
|
3
3
|
import { L as Logger } from './logger-DDBiMOOD.js';
|
|
4
4
|
export { a as LoggerConfig } from './logger-DDBiMOOD.js';
|
package/dist/index.js
CHANGED
|
@@ -1169,174 +1169,12 @@ import {
|
|
|
1169
1169
|
import {
|
|
1170
1170
|
query
|
|
1171
1171
|
} from "@anthropic-ai/claude-agent-sdk";
|
|
1172
|
-
|
|
1173
|
-
// ../shared/dist/index.js
|
|
1174
|
-
var consoleLogger = {
|
|
1175
|
-
info: (_message, _data) => {
|
|
1176
|
-
},
|
|
1177
|
-
debug: (_message, _data) => {
|
|
1178
|
-
},
|
|
1179
|
-
error: (_message, _data) => {
|
|
1180
|
-
},
|
|
1181
|
-
warn: (_message, _data) => {
|
|
1182
|
-
}
|
|
1183
|
-
};
|
|
1184
|
-
var Saga = class {
|
|
1185
|
-
completedSteps = [];
|
|
1186
|
-
currentStepName = "unknown";
|
|
1187
|
-
stepTimings = [];
|
|
1188
|
-
log;
|
|
1189
|
-
constructor(logger) {
|
|
1190
|
-
this.log = logger ?? consoleLogger;
|
|
1191
|
-
}
|
|
1192
|
-
/**
|
|
1193
|
-
* Run the saga with the given input.
|
|
1194
|
-
* Returns a discriminated union result - either success with data or failure with error details.
|
|
1195
|
-
*/
|
|
1196
|
-
async run(input) {
|
|
1197
|
-
this.completedSteps = [];
|
|
1198
|
-
this.currentStepName = "unknown";
|
|
1199
|
-
this.stepTimings = [];
|
|
1200
|
-
const sagaStart = performance.now();
|
|
1201
|
-
this.log.info("Starting saga", { sagaName: this.constructor.name });
|
|
1202
|
-
try {
|
|
1203
|
-
const result = await this.execute(input);
|
|
1204
|
-
const totalDuration = performance.now() - sagaStart;
|
|
1205
|
-
this.log.debug("Saga completed successfully", {
|
|
1206
|
-
sagaName: this.constructor.name,
|
|
1207
|
-
stepsCompleted: this.completedSteps.length,
|
|
1208
|
-
totalDurationMs: Math.round(totalDuration),
|
|
1209
|
-
stepTimings: this.stepTimings
|
|
1210
|
-
});
|
|
1211
|
-
return { success: true, data: result };
|
|
1212
|
-
} catch (error) {
|
|
1213
|
-
this.log.error("Saga failed, initiating rollback", {
|
|
1214
|
-
sagaName: this.constructor.name,
|
|
1215
|
-
failedStep: this.currentStepName,
|
|
1216
|
-
error: error instanceof Error ? error.message : String(error)
|
|
1217
|
-
});
|
|
1218
|
-
await this.rollback();
|
|
1219
|
-
return {
|
|
1220
|
-
success: false,
|
|
1221
|
-
error: error instanceof Error ? error.message : String(error),
|
|
1222
|
-
failedStep: this.currentStepName
|
|
1223
|
-
};
|
|
1224
|
-
}
|
|
1225
|
-
}
|
|
1226
|
-
/**
|
|
1227
|
-
* Execute a step with its rollback action.
|
|
1228
|
-
* If the step succeeds, its rollback action is stored for potential rollback.
|
|
1229
|
-
* The step name is automatically tracked for error reporting.
|
|
1230
|
-
*
|
|
1231
|
-
* @param config - Step configuration with name, execute, and rollback functions
|
|
1232
|
-
* @returns The result of the execute function
|
|
1233
|
-
* @throws Re-throws any error from the execute function (triggers rollback)
|
|
1234
|
-
*/
|
|
1235
|
-
async step(config) {
|
|
1236
|
-
this.currentStepName = config.name;
|
|
1237
|
-
this.log.debug(`Executing step: ${config.name}`);
|
|
1238
|
-
const stepStart = performance.now();
|
|
1239
|
-
const result = await config.execute();
|
|
1240
|
-
const durationMs = Math.round(performance.now() - stepStart);
|
|
1241
|
-
this.stepTimings.push({ name: config.name, durationMs });
|
|
1242
|
-
this.log.debug(`Step completed: ${config.name}`, { durationMs });
|
|
1243
|
-
this.completedSteps.push({
|
|
1244
|
-
name: config.name,
|
|
1245
|
-
rollback: () => config.rollback(result)
|
|
1246
|
-
});
|
|
1247
|
-
return result;
|
|
1248
|
-
}
|
|
1249
|
-
/**
|
|
1250
|
-
* Execute a step that doesn't need rollback.
|
|
1251
|
-
* Useful for read-only operations or operations that are idempotent.
|
|
1252
|
-
* The step name is automatically tracked for error reporting.
|
|
1253
|
-
*
|
|
1254
|
-
* @param name - Step name for logging and error tracking
|
|
1255
|
-
* @param execute - The action to execute
|
|
1256
|
-
* @returns The result of the execute function
|
|
1257
|
-
*/
|
|
1258
|
-
async readOnlyStep(name, execute) {
|
|
1259
|
-
this.currentStepName = name;
|
|
1260
|
-
this.log.debug(`Executing read-only step: ${name}`);
|
|
1261
|
-
const stepStart = performance.now();
|
|
1262
|
-
const result = await execute();
|
|
1263
|
-
const durationMs = Math.round(performance.now() - stepStart);
|
|
1264
|
-
this.stepTimings.push({ name, durationMs });
|
|
1265
|
-
this.log.debug(`Read-only step completed: ${name}`, { durationMs });
|
|
1266
|
-
return result;
|
|
1267
|
-
}
|
|
1268
|
-
/**
|
|
1269
|
-
* Roll back all completed steps in reverse order.
|
|
1270
|
-
* Rollback errors are logged but don't stop the rollback of other steps.
|
|
1271
|
-
*/
|
|
1272
|
-
async rollback() {
|
|
1273
|
-
this.log.info("Rolling back saga", {
|
|
1274
|
-
stepsToRollback: this.completedSteps.length
|
|
1275
|
-
});
|
|
1276
|
-
const stepsReversed = [...this.completedSteps].reverse();
|
|
1277
|
-
for (const step of stepsReversed) {
|
|
1278
|
-
try {
|
|
1279
|
-
this.log.debug(`Rolling back step: ${step.name}`);
|
|
1280
|
-
await step.rollback();
|
|
1281
|
-
this.log.debug(`Step rolled back: ${step.name}`);
|
|
1282
|
-
} catch (error) {
|
|
1283
|
-
this.log.error(`Failed to rollback step: ${step.name}`, {
|
|
1284
|
-
error: error instanceof Error ? error.message : String(error)
|
|
1285
|
-
});
|
|
1286
|
-
}
|
|
1287
|
-
}
|
|
1288
|
-
this.log.info("Rollback completed", {
|
|
1289
|
-
stepsAttempted: this.completedSteps.length
|
|
1290
|
-
});
|
|
1291
|
-
}
|
|
1292
|
-
/**
|
|
1293
|
-
* Get the number of completed steps (useful for testing)
|
|
1294
|
-
*/
|
|
1295
|
-
getCompletedStepCount() {
|
|
1296
|
-
return this.completedSteps.length;
|
|
1297
|
-
}
|
|
1298
|
-
};
|
|
1299
|
-
var NOOP_COLLECTOR = {
|
|
1300
|
-
time: (_label, fn) => fn(),
|
|
1301
|
-
timeSync: (_label, fn) => fn(),
|
|
1302
|
-
record: () => {
|
|
1303
|
-
},
|
|
1304
|
-
summarize: () => {
|
|
1305
|
-
}
|
|
1306
|
-
};
|
|
1307
|
-
function createTimingCollector(enabled, log) {
|
|
1308
|
-
if (!enabled) return NOOP_COLLECTOR;
|
|
1309
|
-
const steps = {};
|
|
1310
|
-
return {
|
|
1311
|
-
async time(label, fn) {
|
|
1312
|
-
const start = Date.now();
|
|
1313
|
-
const result = await fn();
|
|
1314
|
-
steps[label] = Date.now() - start;
|
|
1315
|
-
return result;
|
|
1316
|
-
},
|
|
1317
|
-
timeSync(label, fn) {
|
|
1318
|
-
const start = Date.now();
|
|
1319
|
-
const result = fn();
|
|
1320
|
-
steps[label] = Date.now() - start;
|
|
1321
|
-
return result;
|
|
1322
|
-
},
|
|
1323
|
-
record(label, ms) {
|
|
1324
|
-
steps[label] = ms;
|
|
1325
|
-
},
|
|
1326
|
-
summarize(label) {
|
|
1327
|
-
const total = Object.values(steps).reduce((a, b) => a + b, 0);
|
|
1328
|
-
log(`[timing] ${label}: ${total}ms`, steps);
|
|
1329
|
-
}
|
|
1330
|
-
};
|
|
1331
|
-
}
|
|
1332
|
-
|
|
1333
|
-
// src/adapters/claude/claude-agent.ts
|
|
1334
1172
|
import { v7 as uuidv7 } from "uuid";
|
|
1335
1173
|
|
|
1336
1174
|
// package.json
|
|
1337
1175
|
var package_default = {
|
|
1338
1176
|
name: "@posthog/agent",
|
|
1339
|
-
version: "2.1.
|
|
1177
|
+
version: "2.1.48",
|
|
1340
1178
|
repository: "https://github.com/PostHog/twig",
|
|
1341
1179
|
description: "TypeScript agent framework wrapping Claude Agent SDK with Git-based task execution for PostHog",
|
|
1342
1180
|
exports: {
|
|
@@ -3455,12 +3293,10 @@ var ClaudeAcpAgent = class extends BaseAcpAgent {
|
|
|
3455
3293
|
logWriter;
|
|
3456
3294
|
options;
|
|
3457
3295
|
lastSentConfigOptions;
|
|
3458
|
-
debug;
|
|
3459
3296
|
constructor(client, logWriter, options) {
|
|
3460
3297
|
super(client);
|
|
3461
3298
|
this.logWriter = logWriter;
|
|
3462
3299
|
this.options = options;
|
|
3463
|
-
this.debug = options?.debug ?? false;
|
|
3464
3300
|
this.toolUseCache = {};
|
|
3465
3301
|
this.logger = new Logger({ debug: true, prefix: "[ClaudeAcpAgent]" });
|
|
3466
3302
|
}
|
|
@@ -3503,36 +3339,26 @@ var ClaudeAcpAgent = class extends BaseAcpAgent {
|
|
|
3503
3339
|
}
|
|
3504
3340
|
async newSession(params) {
|
|
3505
3341
|
this.checkAuthStatus();
|
|
3506
|
-
const tc = createTimingCollector(
|
|
3507
|
-
this.debug,
|
|
3508
|
-
(msg, data) => this.logger.info(msg, data)
|
|
3509
|
-
);
|
|
3510
3342
|
const meta = params._meta;
|
|
3511
3343
|
const sessionId = uuidv7();
|
|
3512
3344
|
const permissionMode = meta?.permissionMode && TWIG_EXECUTION_MODES.includes(meta.permissionMode) ? meta.permissionMode : "default";
|
|
3513
|
-
const mcpServers =
|
|
3514
|
-
|
|
3515
|
-
|
|
3516
|
-
|
|
3517
|
-
|
|
3518
|
-
|
|
3519
|
-
|
|
3520
|
-
|
|
3521
|
-
|
|
3522
|
-
|
|
3523
|
-
|
|
3524
|
-
|
|
3525
|
-
|
|
3526
|
-
|
|
3527
|
-
|
|
3528
|
-
isResume: false,
|
|
3529
|
-
onModeChange: this.createOnModeChange(sessionId),
|
|
3530
|
-
onProcessSpawned: this.options?.onProcessSpawned,
|
|
3531
|
-
onProcessExited: this.options?.onProcessExited
|
|
3532
|
-
})
|
|
3533
|
-
);
|
|
3345
|
+
const mcpServers = parseMcpServers(params);
|
|
3346
|
+
const options = buildSessionOptions({
|
|
3347
|
+
cwd: params.cwd,
|
|
3348
|
+
mcpServers,
|
|
3349
|
+
permissionMode,
|
|
3350
|
+
canUseTool: this.createCanUseTool(sessionId),
|
|
3351
|
+
logger: this.logger,
|
|
3352
|
+
systemPrompt: buildSystemPrompt(meta?.systemPrompt),
|
|
3353
|
+
userProvidedOptions: meta?.claudeCode?.options,
|
|
3354
|
+
sessionId,
|
|
3355
|
+
isResume: false,
|
|
3356
|
+
onModeChange: this.createOnModeChange(sessionId),
|
|
3357
|
+
onProcessSpawned: this.options?.onProcessSpawned,
|
|
3358
|
+
onProcessExited: this.options?.onProcessExited
|
|
3359
|
+
});
|
|
3534
3360
|
const input = new Pushable();
|
|
3535
|
-
const q =
|
|
3361
|
+
const q = query({ prompt: input, options });
|
|
3536
3362
|
const session = this.createSession(
|
|
3537
3363
|
sessionId,
|
|
3538
3364
|
q,
|
|
@@ -3544,27 +3370,17 @@ var ClaudeAcpAgent = class extends BaseAcpAgent {
|
|
|
3544
3370
|
session.taskRunId = meta?.taskRunId;
|
|
3545
3371
|
this.registerPersistence(sessionId, meta);
|
|
3546
3372
|
if (meta?.taskRunId) {
|
|
3547
|
-
await
|
|
3548
|
-
|
|
3549
|
-
|
|
3550
|
-
|
|
3551
|
-
|
|
3552
|
-
adapter: "claude"
|
|
3553
|
-
})
|
|
3554
|
-
);
|
|
3373
|
+
await this.client.extNotification("_posthog/sdk_session", {
|
|
3374
|
+
taskRunId: meta.taskRunId,
|
|
3375
|
+
sessionId,
|
|
3376
|
+
adapter: "claude"
|
|
3377
|
+
});
|
|
3555
3378
|
}
|
|
3556
|
-
const modelOptions = await
|
|
3557
|
-
|
|
3558
|
-
() => this.getModelConfigOptions()
|
|
3559
|
-
);
|
|
3560
|
-
this.deferBackgroundFetches(tc, q, sessionId, mcpServers);
|
|
3379
|
+
const modelOptions = await this.getModelConfigOptions();
|
|
3380
|
+
this.deferBackgroundFetches(q, sessionId, mcpServers);
|
|
3561
3381
|
session.modelId = modelOptions.currentModelId;
|
|
3562
3382
|
await this.trySetModel(q, modelOptions.currentModelId);
|
|
3563
|
-
const configOptions = await
|
|
3564
|
-
"buildConfigOptions",
|
|
3565
|
-
() => this.buildConfigOptions(modelOptions)
|
|
3566
|
-
);
|
|
3567
|
-
tc.summarize("newSession");
|
|
3383
|
+
const configOptions = await this.buildConfigOptions(modelOptions);
|
|
3568
3384
|
return {
|
|
3569
3385
|
sessionId,
|
|
3570
3386
|
configOptions
|
|
@@ -3574,10 +3390,6 @@ var ClaudeAcpAgent = class extends BaseAcpAgent {
|
|
|
3574
3390
|
return this.resumeSession(params);
|
|
3575
3391
|
}
|
|
3576
3392
|
async resumeSession(params) {
|
|
3577
|
-
const tc = createTimingCollector(
|
|
3578
|
-
this.debug,
|
|
3579
|
-
(msg, data) => this.logger.info(msg, data)
|
|
3580
|
-
);
|
|
3581
3393
|
const meta = params._meta;
|
|
3582
3394
|
const sessionId = meta?.sessionId;
|
|
3583
3395
|
if (!sessionId) {
|
|
@@ -3586,32 +3398,22 @@ var ClaudeAcpAgent = class extends BaseAcpAgent {
|
|
|
3586
3398
|
if (this.sessionId === sessionId) {
|
|
3587
3399
|
return {};
|
|
3588
3400
|
}
|
|
3589
|
-
const mcpServers =
|
|
3590
|
-
"parseMcpServers",
|
|
3591
|
-
() => parseMcpServers(params)
|
|
3592
|
-
);
|
|
3401
|
+
const mcpServers = parseMcpServers(params);
|
|
3593
3402
|
const permissionMode = meta?.permissionMode && TWIG_EXECUTION_MODES.includes(meta.permissionMode) ? meta.permissionMode : "default";
|
|
3594
|
-
const { query: q, session } = await
|
|
3595
|
-
|
|
3596
|
-
|
|
3597
|
-
|
|
3598
|
-
|
|
3599
|
-
|
|
3600
|
-
|
|
3601
|
-
|
|
3602
|
-
|
|
3603
|
-
|
|
3604
|
-
additionalDirectories: meta?.claudeCode?.options?.additionalDirectories
|
|
3605
|
-
})
|
|
3606
|
-
);
|
|
3403
|
+
const { query: q, session } = await this.initializeQuery({
|
|
3404
|
+
cwd: params.cwd,
|
|
3405
|
+
permissionMode,
|
|
3406
|
+
mcpServers,
|
|
3407
|
+
systemPrompt: buildSystemPrompt(meta?.systemPrompt),
|
|
3408
|
+
userProvidedOptions: meta?.claudeCode?.options,
|
|
3409
|
+
sessionId,
|
|
3410
|
+
isResume: true,
|
|
3411
|
+
additionalDirectories: meta?.claudeCode?.options?.additionalDirectories
|
|
3412
|
+
});
|
|
3607
3413
|
session.taskRunId = meta?.taskRunId;
|
|
3608
3414
|
this.registerPersistence(sessionId, meta);
|
|
3609
|
-
this.deferBackgroundFetches(
|
|
3610
|
-
const configOptions = await
|
|
3611
|
-
"buildConfigOptions",
|
|
3612
|
-
() => this.buildConfigOptions()
|
|
3613
|
-
);
|
|
3614
|
-
tc.summarize("resumeSession");
|
|
3415
|
+
this.deferBackgroundFetches(q, sessionId, mcpServers);
|
|
3416
|
+
const configOptions = await this.buildConfigOptions();
|
|
3615
3417
|
return { configOptions };
|
|
3616
3418
|
}
|
|
3617
3419
|
async prompt(params) {
|
|
@@ -3799,13 +3601,10 @@ var ClaudeAcpAgent = class extends BaseAcpAgent {
|
|
|
3799
3601
|
* Fire-and-forget: fetch slash commands and MCP tool metadata in parallel.
|
|
3800
3602
|
* Both populate caches used later — neither is needed to return configOptions.
|
|
3801
3603
|
*/
|
|
3802
|
-
deferBackgroundFetches(
|
|
3604
|
+
deferBackgroundFetches(q, sessionId, mcpServers) {
|
|
3803
3605
|
Promise.all([
|
|
3804
|
-
|
|
3805
|
-
|
|
3806
|
-
"mcpMetadata",
|
|
3807
|
-
() => fetchMcpToolMetadata(mcpServers, this.logger)
|
|
3808
|
-
)
|
|
3606
|
+
getAvailableSlashCommands(q),
|
|
3607
|
+
fetchMcpToolMetadata(mcpServers, this.logger)
|
|
3809
3608
|
]).then(([slashCommands]) => {
|
|
3810
3609
|
this.sendAvailableCommandsUpdate(sessionId, slashCommands);
|
|
3811
3610
|
}).catch((err) => {
|
|
@@ -4099,10 +3898,7 @@ function createClaudeConnection(config) {
|
|
|
4099
3898
|
const agentStream = ndJsonStream(agentWritable, streams.agent.readable);
|
|
4100
3899
|
let agent = null;
|
|
4101
3900
|
const agentConnection = new AgentSideConnection((client) => {
|
|
4102
|
-
agent = new ClaudeAcpAgent(client, logWriter,
|
|
4103
|
-
...config.processCallbacks,
|
|
4104
|
-
debug: config.debug
|
|
4105
|
-
});
|
|
3901
|
+
agent = new ClaudeAcpAgent(client, logWriter, config.processCallbacks);
|
|
4106
3902
|
logger.info(`Created ${agent.adapterName} agent`);
|
|
4107
3903
|
return agent;
|
|
4108
3904
|
}, agentStream);
|
|
@@ -4802,7 +4598,6 @@ var Agent = class {
|
|
|
4802
4598
|
taskId,
|
|
4803
4599
|
deviceType: "local",
|
|
4804
4600
|
logger: this.logger,
|
|
4805
|
-
debug: this.debug,
|
|
4806
4601
|
processCallbacks: options.processCallbacks,
|
|
4807
4602
|
allowedModelIds,
|
|
4808
4603
|
codexOptions: options.adapter === "codex" && gatewayConfig ? {
|
|
@@ -4903,6 +4698,133 @@ var OtelLogWriter = class {
|
|
|
4903
4698
|
}
|
|
4904
4699
|
};
|
|
4905
4700
|
|
|
4701
|
+
// ../shared/dist/index.js
|
|
4702
|
+
var consoleLogger = {
|
|
4703
|
+
info: (_message, _data) => {
|
|
4704
|
+
},
|
|
4705
|
+
debug: (_message, _data) => {
|
|
4706
|
+
},
|
|
4707
|
+
error: (_message, _data) => {
|
|
4708
|
+
},
|
|
4709
|
+
warn: (_message, _data) => {
|
|
4710
|
+
}
|
|
4711
|
+
};
|
|
4712
|
+
var Saga = class {
|
|
4713
|
+
completedSteps = [];
|
|
4714
|
+
currentStepName = "unknown";
|
|
4715
|
+
stepTimings = [];
|
|
4716
|
+
log;
|
|
4717
|
+
constructor(logger) {
|
|
4718
|
+
this.log = logger ?? consoleLogger;
|
|
4719
|
+
}
|
|
4720
|
+
/**
|
|
4721
|
+
* Run the saga with the given input.
|
|
4722
|
+
* Returns a discriminated union result - either success with data or failure with error details.
|
|
4723
|
+
*/
|
|
4724
|
+
async run(input) {
|
|
4725
|
+
this.completedSteps = [];
|
|
4726
|
+
this.currentStepName = "unknown";
|
|
4727
|
+
this.stepTimings = [];
|
|
4728
|
+
const sagaStart = performance.now();
|
|
4729
|
+
this.log.info("Starting saga", { sagaName: this.constructor.name });
|
|
4730
|
+
try {
|
|
4731
|
+
const result = await this.execute(input);
|
|
4732
|
+
const totalDuration = performance.now() - sagaStart;
|
|
4733
|
+
this.log.debug("Saga completed successfully", {
|
|
4734
|
+
sagaName: this.constructor.name,
|
|
4735
|
+
stepsCompleted: this.completedSteps.length,
|
|
4736
|
+
totalDurationMs: Math.round(totalDuration),
|
|
4737
|
+
stepTimings: this.stepTimings
|
|
4738
|
+
});
|
|
4739
|
+
return { success: true, data: result };
|
|
4740
|
+
} catch (error) {
|
|
4741
|
+
this.log.error("Saga failed, initiating rollback", {
|
|
4742
|
+
sagaName: this.constructor.name,
|
|
4743
|
+
failedStep: this.currentStepName,
|
|
4744
|
+
error: error instanceof Error ? error.message : String(error)
|
|
4745
|
+
});
|
|
4746
|
+
await this.rollback();
|
|
4747
|
+
return {
|
|
4748
|
+
success: false,
|
|
4749
|
+
error: error instanceof Error ? error.message : String(error),
|
|
4750
|
+
failedStep: this.currentStepName
|
|
4751
|
+
};
|
|
4752
|
+
}
|
|
4753
|
+
}
|
|
4754
|
+
/**
|
|
4755
|
+
* Execute a step with its rollback action.
|
|
4756
|
+
* If the step succeeds, its rollback action is stored for potential rollback.
|
|
4757
|
+
* The step name is automatically tracked for error reporting.
|
|
4758
|
+
*
|
|
4759
|
+
* @param config - Step configuration with name, execute, and rollback functions
|
|
4760
|
+
* @returns The result of the execute function
|
|
4761
|
+
* @throws Re-throws any error from the execute function (triggers rollback)
|
|
4762
|
+
*/
|
|
4763
|
+
async step(config) {
|
|
4764
|
+
this.currentStepName = config.name;
|
|
4765
|
+
this.log.debug(`Executing step: ${config.name}`);
|
|
4766
|
+
const stepStart = performance.now();
|
|
4767
|
+
const result = await config.execute();
|
|
4768
|
+
const durationMs = Math.round(performance.now() - stepStart);
|
|
4769
|
+
this.stepTimings.push({ name: config.name, durationMs });
|
|
4770
|
+
this.log.debug(`Step completed: ${config.name}`, { durationMs });
|
|
4771
|
+
this.completedSteps.push({
|
|
4772
|
+
name: config.name,
|
|
4773
|
+
rollback: () => config.rollback(result)
|
|
4774
|
+
});
|
|
4775
|
+
return result;
|
|
4776
|
+
}
|
|
4777
|
+
/**
|
|
4778
|
+
* Execute a step that doesn't need rollback.
|
|
4779
|
+
* Useful for read-only operations or operations that are idempotent.
|
|
4780
|
+
* The step name is automatically tracked for error reporting.
|
|
4781
|
+
*
|
|
4782
|
+
* @param name - Step name for logging and error tracking
|
|
4783
|
+
* @param execute - The action to execute
|
|
4784
|
+
* @returns The result of the execute function
|
|
4785
|
+
*/
|
|
4786
|
+
async readOnlyStep(name, execute) {
|
|
4787
|
+
this.currentStepName = name;
|
|
4788
|
+
this.log.debug(`Executing read-only step: ${name}`);
|
|
4789
|
+
const stepStart = performance.now();
|
|
4790
|
+
const result = await execute();
|
|
4791
|
+
const durationMs = Math.round(performance.now() - stepStart);
|
|
4792
|
+
this.stepTimings.push({ name, durationMs });
|
|
4793
|
+
this.log.debug(`Read-only step completed: ${name}`, { durationMs });
|
|
4794
|
+
return result;
|
|
4795
|
+
}
|
|
4796
|
+
/**
|
|
4797
|
+
* Roll back all completed steps in reverse order.
|
|
4798
|
+
* Rollback errors are logged but don't stop the rollback of other steps.
|
|
4799
|
+
*/
|
|
4800
|
+
async rollback() {
|
|
4801
|
+
this.log.info("Rolling back saga", {
|
|
4802
|
+
stepsToRollback: this.completedSteps.length
|
|
4803
|
+
});
|
|
4804
|
+
const stepsReversed = [...this.completedSteps].reverse();
|
|
4805
|
+
for (const step of stepsReversed) {
|
|
4806
|
+
try {
|
|
4807
|
+
this.log.debug(`Rolling back step: ${step.name}`);
|
|
4808
|
+
await step.rollback();
|
|
4809
|
+
this.log.debug(`Step rolled back: ${step.name}`);
|
|
4810
|
+
} catch (error) {
|
|
4811
|
+
this.log.error(`Failed to rollback step: ${step.name}`, {
|
|
4812
|
+
error: error instanceof Error ? error.message : String(error)
|
|
4813
|
+
});
|
|
4814
|
+
}
|
|
4815
|
+
}
|
|
4816
|
+
this.log.info("Rollback completed", {
|
|
4817
|
+
stepsAttempted: this.completedSteps.length
|
|
4818
|
+
});
|
|
4819
|
+
}
|
|
4820
|
+
/**
|
|
4821
|
+
* Get the number of completed steps (useful for testing)
|
|
4822
|
+
*/
|
|
4823
|
+
getCompletedStepCount() {
|
|
4824
|
+
return this.completedSteps.length;
|
|
4825
|
+
}
|
|
4826
|
+
};
|
|
4827
|
+
|
|
4906
4828
|
// ../git/dist/queries.js
|
|
4907
4829
|
import * as fs4 from "fs/promises";
|
|
4908
4830
|
import * as path5 from "path";
|