@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/server/bin.cjs
CHANGED
|
@@ -1170,174 +1170,12 @@ var os3 = __toESM(require("os"), 1);
|
|
|
1170
1170
|
var path3 = __toESM(require("path"), 1);
|
|
1171
1171
|
var import_sdk2 = require("@agentclientprotocol/sdk");
|
|
1172
1172
|
var import_claude_agent_sdk = require("@anthropic-ai/claude-agent-sdk");
|
|
1173
|
-
|
|
1174
|
-
// ../shared/dist/index.js
|
|
1175
|
-
var consoleLogger = {
|
|
1176
|
-
info: (_message, _data) => {
|
|
1177
|
-
},
|
|
1178
|
-
debug: (_message, _data) => {
|
|
1179
|
-
},
|
|
1180
|
-
error: (_message, _data) => {
|
|
1181
|
-
},
|
|
1182
|
-
warn: (_message, _data) => {
|
|
1183
|
-
}
|
|
1184
|
-
};
|
|
1185
|
-
var Saga = class {
|
|
1186
|
-
completedSteps = [];
|
|
1187
|
-
currentStepName = "unknown";
|
|
1188
|
-
stepTimings = [];
|
|
1189
|
-
log;
|
|
1190
|
-
constructor(logger) {
|
|
1191
|
-
this.log = logger ?? consoleLogger;
|
|
1192
|
-
}
|
|
1193
|
-
/**
|
|
1194
|
-
* Run the saga with the given input.
|
|
1195
|
-
* Returns a discriminated union result - either success with data or failure with error details.
|
|
1196
|
-
*/
|
|
1197
|
-
async run(input) {
|
|
1198
|
-
this.completedSteps = [];
|
|
1199
|
-
this.currentStepName = "unknown";
|
|
1200
|
-
this.stepTimings = [];
|
|
1201
|
-
const sagaStart = performance.now();
|
|
1202
|
-
this.log.info("Starting saga", { sagaName: this.constructor.name });
|
|
1203
|
-
try {
|
|
1204
|
-
const result = await this.execute(input);
|
|
1205
|
-
const totalDuration = performance.now() - sagaStart;
|
|
1206
|
-
this.log.debug("Saga completed successfully", {
|
|
1207
|
-
sagaName: this.constructor.name,
|
|
1208
|
-
stepsCompleted: this.completedSteps.length,
|
|
1209
|
-
totalDurationMs: Math.round(totalDuration),
|
|
1210
|
-
stepTimings: this.stepTimings
|
|
1211
|
-
});
|
|
1212
|
-
return { success: true, data: result };
|
|
1213
|
-
} catch (error) {
|
|
1214
|
-
this.log.error("Saga failed, initiating rollback", {
|
|
1215
|
-
sagaName: this.constructor.name,
|
|
1216
|
-
failedStep: this.currentStepName,
|
|
1217
|
-
error: error instanceof Error ? error.message : String(error)
|
|
1218
|
-
});
|
|
1219
|
-
await this.rollback();
|
|
1220
|
-
return {
|
|
1221
|
-
success: false,
|
|
1222
|
-
error: error instanceof Error ? error.message : String(error),
|
|
1223
|
-
failedStep: this.currentStepName
|
|
1224
|
-
};
|
|
1225
|
-
}
|
|
1226
|
-
}
|
|
1227
|
-
/**
|
|
1228
|
-
* Execute a step with its rollback action.
|
|
1229
|
-
* If the step succeeds, its rollback action is stored for potential rollback.
|
|
1230
|
-
* The step name is automatically tracked for error reporting.
|
|
1231
|
-
*
|
|
1232
|
-
* @param config - Step configuration with name, execute, and rollback functions
|
|
1233
|
-
* @returns The result of the execute function
|
|
1234
|
-
* @throws Re-throws any error from the execute function (triggers rollback)
|
|
1235
|
-
*/
|
|
1236
|
-
async step(config) {
|
|
1237
|
-
this.currentStepName = config.name;
|
|
1238
|
-
this.log.debug(`Executing step: ${config.name}`);
|
|
1239
|
-
const stepStart = performance.now();
|
|
1240
|
-
const result = await config.execute();
|
|
1241
|
-
const durationMs = Math.round(performance.now() - stepStart);
|
|
1242
|
-
this.stepTimings.push({ name: config.name, durationMs });
|
|
1243
|
-
this.log.debug(`Step completed: ${config.name}`, { durationMs });
|
|
1244
|
-
this.completedSteps.push({
|
|
1245
|
-
name: config.name,
|
|
1246
|
-
rollback: () => config.rollback(result)
|
|
1247
|
-
});
|
|
1248
|
-
return result;
|
|
1249
|
-
}
|
|
1250
|
-
/**
|
|
1251
|
-
* Execute a step that doesn't need rollback.
|
|
1252
|
-
* Useful for read-only operations or operations that are idempotent.
|
|
1253
|
-
* The step name is automatically tracked for error reporting.
|
|
1254
|
-
*
|
|
1255
|
-
* @param name - Step name for logging and error tracking
|
|
1256
|
-
* @param execute - The action to execute
|
|
1257
|
-
* @returns The result of the execute function
|
|
1258
|
-
*/
|
|
1259
|
-
async readOnlyStep(name, execute) {
|
|
1260
|
-
this.currentStepName = name;
|
|
1261
|
-
this.log.debug(`Executing read-only step: ${name}`);
|
|
1262
|
-
const stepStart = performance.now();
|
|
1263
|
-
const result = await execute();
|
|
1264
|
-
const durationMs = Math.round(performance.now() - stepStart);
|
|
1265
|
-
this.stepTimings.push({ name, durationMs });
|
|
1266
|
-
this.log.debug(`Read-only step completed: ${name}`, { durationMs });
|
|
1267
|
-
return result;
|
|
1268
|
-
}
|
|
1269
|
-
/**
|
|
1270
|
-
* Roll back all completed steps in reverse order.
|
|
1271
|
-
* Rollback errors are logged but don't stop the rollback of other steps.
|
|
1272
|
-
*/
|
|
1273
|
-
async rollback() {
|
|
1274
|
-
this.log.info("Rolling back saga", {
|
|
1275
|
-
stepsToRollback: this.completedSteps.length
|
|
1276
|
-
});
|
|
1277
|
-
const stepsReversed = [...this.completedSteps].reverse();
|
|
1278
|
-
for (const step of stepsReversed) {
|
|
1279
|
-
try {
|
|
1280
|
-
this.log.debug(`Rolling back step: ${step.name}`);
|
|
1281
|
-
await step.rollback();
|
|
1282
|
-
this.log.debug(`Step rolled back: ${step.name}`);
|
|
1283
|
-
} catch (error) {
|
|
1284
|
-
this.log.error(`Failed to rollback step: ${step.name}`, {
|
|
1285
|
-
error: error instanceof Error ? error.message : String(error)
|
|
1286
|
-
});
|
|
1287
|
-
}
|
|
1288
|
-
}
|
|
1289
|
-
this.log.info("Rollback completed", {
|
|
1290
|
-
stepsAttempted: this.completedSteps.length
|
|
1291
|
-
});
|
|
1292
|
-
}
|
|
1293
|
-
/**
|
|
1294
|
-
* Get the number of completed steps (useful for testing)
|
|
1295
|
-
*/
|
|
1296
|
-
getCompletedStepCount() {
|
|
1297
|
-
return this.completedSteps.length;
|
|
1298
|
-
}
|
|
1299
|
-
};
|
|
1300
|
-
var NOOP_COLLECTOR = {
|
|
1301
|
-
time: (_label, fn) => fn(),
|
|
1302
|
-
timeSync: (_label, fn) => fn(),
|
|
1303
|
-
record: () => {
|
|
1304
|
-
},
|
|
1305
|
-
summarize: () => {
|
|
1306
|
-
}
|
|
1307
|
-
};
|
|
1308
|
-
function createTimingCollector(enabled, log) {
|
|
1309
|
-
if (!enabled) return NOOP_COLLECTOR;
|
|
1310
|
-
const steps = {};
|
|
1311
|
-
return {
|
|
1312
|
-
async time(label, fn) {
|
|
1313
|
-
const start = Date.now();
|
|
1314
|
-
const result = await fn();
|
|
1315
|
-
steps[label] = Date.now() - start;
|
|
1316
|
-
return result;
|
|
1317
|
-
},
|
|
1318
|
-
timeSync(label, fn) {
|
|
1319
|
-
const start = Date.now();
|
|
1320
|
-
const result = fn();
|
|
1321
|
-
steps[label] = Date.now() - start;
|
|
1322
|
-
return result;
|
|
1323
|
-
},
|
|
1324
|
-
record(label, ms) {
|
|
1325
|
-
steps[label] = ms;
|
|
1326
|
-
},
|
|
1327
|
-
summarize(label) {
|
|
1328
|
-
const total = Object.values(steps).reduce((a, b) => a + b, 0);
|
|
1329
|
-
log(`[timing] ${label}: ${total}ms`, steps);
|
|
1330
|
-
}
|
|
1331
|
-
};
|
|
1332
|
-
}
|
|
1333
|
-
|
|
1334
|
-
// src/adapters/claude/claude-agent.ts
|
|
1335
1173
|
var import_uuid = require("uuid");
|
|
1336
1174
|
|
|
1337
1175
|
// package.json
|
|
1338
1176
|
var package_default = {
|
|
1339
1177
|
name: "@posthog/agent",
|
|
1340
|
-
version: "2.1.
|
|
1178
|
+
version: "2.1.48",
|
|
1341
1179
|
repository: "https://github.com/PostHog/twig",
|
|
1342
1180
|
description: "TypeScript agent framework wrapping Claude Agent SDK with Git-based task execution for PostHog",
|
|
1343
1181
|
exports: {
|
|
@@ -3412,12 +3250,10 @@ var ClaudeAcpAgent = class extends BaseAcpAgent {
|
|
|
3412
3250
|
logWriter;
|
|
3413
3251
|
options;
|
|
3414
3252
|
lastSentConfigOptions;
|
|
3415
|
-
debug;
|
|
3416
3253
|
constructor(client, logWriter, options) {
|
|
3417
3254
|
super(client);
|
|
3418
3255
|
this.logWriter = logWriter;
|
|
3419
3256
|
this.options = options;
|
|
3420
|
-
this.debug = options?.debug ?? false;
|
|
3421
3257
|
this.toolUseCache = {};
|
|
3422
3258
|
this.logger = new Logger({ debug: true, prefix: "[ClaudeAcpAgent]" });
|
|
3423
3259
|
}
|
|
@@ -3460,36 +3296,26 @@ var ClaudeAcpAgent = class extends BaseAcpAgent {
|
|
|
3460
3296
|
}
|
|
3461
3297
|
async newSession(params) {
|
|
3462
3298
|
this.checkAuthStatus();
|
|
3463
|
-
const tc = createTimingCollector(
|
|
3464
|
-
this.debug,
|
|
3465
|
-
(msg, data) => this.logger.info(msg, data)
|
|
3466
|
-
);
|
|
3467
3299
|
const meta = params._meta;
|
|
3468
3300
|
const sessionId = (0, import_uuid.v7)();
|
|
3469
3301
|
const permissionMode = meta?.permissionMode && TWIG_EXECUTION_MODES.includes(meta.permissionMode) ? meta.permissionMode : "default";
|
|
3470
|
-
const mcpServers =
|
|
3471
|
-
|
|
3472
|
-
|
|
3473
|
-
|
|
3474
|
-
|
|
3475
|
-
|
|
3476
|
-
|
|
3477
|
-
|
|
3478
|
-
|
|
3479
|
-
|
|
3480
|
-
|
|
3481
|
-
|
|
3482
|
-
|
|
3483
|
-
|
|
3484
|
-
|
|
3485
|
-
isResume: false,
|
|
3486
|
-
onModeChange: this.createOnModeChange(sessionId),
|
|
3487
|
-
onProcessSpawned: this.options?.onProcessSpawned,
|
|
3488
|
-
onProcessExited: this.options?.onProcessExited
|
|
3489
|
-
})
|
|
3490
|
-
);
|
|
3302
|
+
const mcpServers = parseMcpServers(params);
|
|
3303
|
+
const options = buildSessionOptions({
|
|
3304
|
+
cwd: params.cwd,
|
|
3305
|
+
mcpServers,
|
|
3306
|
+
permissionMode,
|
|
3307
|
+
canUseTool: this.createCanUseTool(sessionId),
|
|
3308
|
+
logger: this.logger,
|
|
3309
|
+
systemPrompt: buildSystemPrompt(meta?.systemPrompt),
|
|
3310
|
+
userProvidedOptions: meta?.claudeCode?.options,
|
|
3311
|
+
sessionId,
|
|
3312
|
+
isResume: false,
|
|
3313
|
+
onModeChange: this.createOnModeChange(sessionId),
|
|
3314
|
+
onProcessSpawned: this.options?.onProcessSpawned,
|
|
3315
|
+
onProcessExited: this.options?.onProcessExited
|
|
3316
|
+
});
|
|
3491
3317
|
const input = new Pushable();
|
|
3492
|
-
const q =
|
|
3318
|
+
const q = (0, import_claude_agent_sdk.query)({ prompt: input, options });
|
|
3493
3319
|
const session = this.createSession(
|
|
3494
3320
|
sessionId,
|
|
3495
3321
|
q,
|
|
@@ -3501,27 +3327,17 @@ var ClaudeAcpAgent = class extends BaseAcpAgent {
|
|
|
3501
3327
|
session.taskRunId = meta?.taskRunId;
|
|
3502
3328
|
this.registerPersistence(sessionId, meta);
|
|
3503
3329
|
if (meta?.taskRunId) {
|
|
3504
|
-
await
|
|
3505
|
-
|
|
3506
|
-
|
|
3507
|
-
|
|
3508
|
-
|
|
3509
|
-
adapter: "claude"
|
|
3510
|
-
})
|
|
3511
|
-
);
|
|
3330
|
+
await this.client.extNotification("_posthog/sdk_session", {
|
|
3331
|
+
taskRunId: meta.taskRunId,
|
|
3332
|
+
sessionId,
|
|
3333
|
+
adapter: "claude"
|
|
3334
|
+
});
|
|
3512
3335
|
}
|
|
3513
|
-
const modelOptions = await
|
|
3514
|
-
|
|
3515
|
-
() => this.getModelConfigOptions()
|
|
3516
|
-
);
|
|
3517
|
-
this.deferBackgroundFetches(tc, q, sessionId, mcpServers);
|
|
3336
|
+
const modelOptions = await this.getModelConfigOptions();
|
|
3337
|
+
this.deferBackgroundFetches(q, sessionId, mcpServers);
|
|
3518
3338
|
session.modelId = modelOptions.currentModelId;
|
|
3519
3339
|
await this.trySetModel(q, modelOptions.currentModelId);
|
|
3520
|
-
const configOptions = await
|
|
3521
|
-
"buildConfigOptions",
|
|
3522
|
-
() => this.buildConfigOptions(modelOptions)
|
|
3523
|
-
);
|
|
3524
|
-
tc.summarize("newSession");
|
|
3340
|
+
const configOptions = await this.buildConfigOptions(modelOptions);
|
|
3525
3341
|
return {
|
|
3526
3342
|
sessionId,
|
|
3527
3343
|
configOptions
|
|
@@ -3531,10 +3347,6 @@ var ClaudeAcpAgent = class extends BaseAcpAgent {
|
|
|
3531
3347
|
return this.resumeSession(params);
|
|
3532
3348
|
}
|
|
3533
3349
|
async resumeSession(params) {
|
|
3534
|
-
const tc = createTimingCollector(
|
|
3535
|
-
this.debug,
|
|
3536
|
-
(msg, data) => this.logger.info(msg, data)
|
|
3537
|
-
);
|
|
3538
3350
|
const meta = params._meta;
|
|
3539
3351
|
const sessionId = meta?.sessionId;
|
|
3540
3352
|
if (!sessionId) {
|
|
@@ -3543,32 +3355,22 @@ var ClaudeAcpAgent = class extends BaseAcpAgent {
|
|
|
3543
3355
|
if (this.sessionId === sessionId) {
|
|
3544
3356
|
return {};
|
|
3545
3357
|
}
|
|
3546
|
-
const mcpServers =
|
|
3547
|
-
"parseMcpServers",
|
|
3548
|
-
() => parseMcpServers(params)
|
|
3549
|
-
);
|
|
3358
|
+
const mcpServers = parseMcpServers(params);
|
|
3550
3359
|
const permissionMode = meta?.permissionMode && TWIG_EXECUTION_MODES.includes(meta.permissionMode) ? meta.permissionMode : "default";
|
|
3551
|
-
const { query: q, session } = await
|
|
3552
|
-
|
|
3553
|
-
|
|
3554
|
-
|
|
3555
|
-
|
|
3556
|
-
|
|
3557
|
-
|
|
3558
|
-
|
|
3559
|
-
|
|
3560
|
-
|
|
3561
|
-
additionalDirectories: meta?.claudeCode?.options?.additionalDirectories
|
|
3562
|
-
})
|
|
3563
|
-
);
|
|
3360
|
+
const { query: q, session } = await this.initializeQuery({
|
|
3361
|
+
cwd: params.cwd,
|
|
3362
|
+
permissionMode,
|
|
3363
|
+
mcpServers,
|
|
3364
|
+
systemPrompt: buildSystemPrompt(meta?.systemPrompt),
|
|
3365
|
+
userProvidedOptions: meta?.claudeCode?.options,
|
|
3366
|
+
sessionId,
|
|
3367
|
+
isResume: true,
|
|
3368
|
+
additionalDirectories: meta?.claudeCode?.options?.additionalDirectories
|
|
3369
|
+
});
|
|
3564
3370
|
session.taskRunId = meta?.taskRunId;
|
|
3565
3371
|
this.registerPersistence(sessionId, meta);
|
|
3566
|
-
this.deferBackgroundFetches(
|
|
3567
|
-
const configOptions = await
|
|
3568
|
-
"buildConfigOptions",
|
|
3569
|
-
() => this.buildConfigOptions()
|
|
3570
|
-
);
|
|
3571
|
-
tc.summarize("resumeSession");
|
|
3372
|
+
this.deferBackgroundFetches(q, sessionId, mcpServers);
|
|
3373
|
+
const configOptions = await this.buildConfigOptions();
|
|
3572
3374
|
return { configOptions };
|
|
3573
3375
|
}
|
|
3574
3376
|
async prompt(params) {
|
|
@@ -3756,13 +3558,10 @@ var ClaudeAcpAgent = class extends BaseAcpAgent {
|
|
|
3756
3558
|
* Fire-and-forget: fetch slash commands and MCP tool metadata in parallel.
|
|
3757
3559
|
* Both populate caches used later — neither is needed to return configOptions.
|
|
3758
3560
|
*/
|
|
3759
|
-
deferBackgroundFetches(
|
|
3561
|
+
deferBackgroundFetches(q, sessionId, mcpServers) {
|
|
3760
3562
|
Promise.all([
|
|
3761
|
-
|
|
3762
|
-
|
|
3763
|
-
"mcpMetadata",
|
|
3764
|
-
() => fetchMcpToolMetadata(mcpServers, this.logger)
|
|
3765
|
-
)
|
|
3563
|
+
getAvailableSlashCommands(q),
|
|
3564
|
+
fetchMcpToolMetadata(mcpServers, this.logger)
|
|
3766
3565
|
]).then(([slashCommands]) => {
|
|
3767
3566
|
this.sendAvailableCommandsUpdate(sessionId, slashCommands);
|
|
3768
3567
|
}).catch((err) => {
|
|
@@ -4056,10 +3855,7 @@ function createClaudeConnection(config) {
|
|
|
4056
3855
|
const agentStream = (0, import_sdk3.ndJsonStream)(agentWritable, streams.agent.readable);
|
|
4057
3856
|
let agent = null;
|
|
4058
3857
|
const agentConnection = new import_sdk3.AgentSideConnection((client) => {
|
|
4059
|
-
agent = new ClaudeAcpAgent(client, logWriter,
|
|
4060
|
-
...config.processCallbacks,
|
|
4061
|
-
debug: config.debug
|
|
4062
|
-
});
|
|
3858
|
+
agent = new ClaudeAcpAgent(client, logWriter, config.processCallbacks);
|
|
4063
3859
|
logger.info(`Created ${agent.adapterName} agent`);
|
|
4064
3860
|
return agent;
|
|
4065
3861
|
}, agentStream);
|
|
@@ -9442,6 +9238,133 @@ async function getHeadSha(baseDir, options) {
|
|
|
9442
9238
|
var import_promises2 = require("fs/promises");
|
|
9443
9239
|
var import_node_path3 = require("path");
|
|
9444
9240
|
|
|
9241
|
+
// ../shared/dist/index.js
|
|
9242
|
+
var consoleLogger = {
|
|
9243
|
+
info: (_message, _data) => {
|
|
9244
|
+
},
|
|
9245
|
+
debug: (_message, _data) => {
|
|
9246
|
+
},
|
|
9247
|
+
error: (_message, _data) => {
|
|
9248
|
+
},
|
|
9249
|
+
warn: (_message, _data) => {
|
|
9250
|
+
}
|
|
9251
|
+
};
|
|
9252
|
+
var Saga = class {
|
|
9253
|
+
completedSteps = [];
|
|
9254
|
+
currentStepName = "unknown";
|
|
9255
|
+
stepTimings = [];
|
|
9256
|
+
log;
|
|
9257
|
+
constructor(logger) {
|
|
9258
|
+
this.log = logger ?? consoleLogger;
|
|
9259
|
+
}
|
|
9260
|
+
/**
|
|
9261
|
+
* Run the saga with the given input.
|
|
9262
|
+
* Returns a discriminated union result - either success with data or failure with error details.
|
|
9263
|
+
*/
|
|
9264
|
+
async run(input) {
|
|
9265
|
+
this.completedSteps = [];
|
|
9266
|
+
this.currentStepName = "unknown";
|
|
9267
|
+
this.stepTimings = [];
|
|
9268
|
+
const sagaStart = performance.now();
|
|
9269
|
+
this.log.info("Starting saga", { sagaName: this.constructor.name });
|
|
9270
|
+
try {
|
|
9271
|
+
const result = await this.execute(input);
|
|
9272
|
+
const totalDuration = performance.now() - sagaStart;
|
|
9273
|
+
this.log.debug("Saga completed successfully", {
|
|
9274
|
+
sagaName: this.constructor.name,
|
|
9275
|
+
stepsCompleted: this.completedSteps.length,
|
|
9276
|
+
totalDurationMs: Math.round(totalDuration),
|
|
9277
|
+
stepTimings: this.stepTimings
|
|
9278
|
+
});
|
|
9279
|
+
return { success: true, data: result };
|
|
9280
|
+
} catch (error) {
|
|
9281
|
+
this.log.error("Saga failed, initiating rollback", {
|
|
9282
|
+
sagaName: this.constructor.name,
|
|
9283
|
+
failedStep: this.currentStepName,
|
|
9284
|
+
error: error instanceof Error ? error.message : String(error)
|
|
9285
|
+
});
|
|
9286
|
+
await this.rollback();
|
|
9287
|
+
return {
|
|
9288
|
+
success: false,
|
|
9289
|
+
error: error instanceof Error ? error.message : String(error),
|
|
9290
|
+
failedStep: this.currentStepName
|
|
9291
|
+
};
|
|
9292
|
+
}
|
|
9293
|
+
}
|
|
9294
|
+
/**
|
|
9295
|
+
* Execute a step with its rollback action.
|
|
9296
|
+
* If the step succeeds, its rollback action is stored for potential rollback.
|
|
9297
|
+
* The step name is automatically tracked for error reporting.
|
|
9298
|
+
*
|
|
9299
|
+
* @param config - Step configuration with name, execute, and rollback functions
|
|
9300
|
+
* @returns The result of the execute function
|
|
9301
|
+
* @throws Re-throws any error from the execute function (triggers rollback)
|
|
9302
|
+
*/
|
|
9303
|
+
async step(config) {
|
|
9304
|
+
this.currentStepName = config.name;
|
|
9305
|
+
this.log.debug(`Executing step: ${config.name}`);
|
|
9306
|
+
const stepStart = performance.now();
|
|
9307
|
+
const result = await config.execute();
|
|
9308
|
+
const durationMs = Math.round(performance.now() - stepStart);
|
|
9309
|
+
this.stepTimings.push({ name: config.name, durationMs });
|
|
9310
|
+
this.log.debug(`Step completed: ${config.name}`, { durationMs });
|
|
9311
|
+
this.completedSteps.push({
|
|
9312
|
+
name: config.name,
|
|
9313
|
+
rollback: () => config.rollback(result)
|
|
9314
|
+
});
|
|
9315
|
+
return result;
|
|
9316
|
+
}
|
|
9317
|
+
/**
|
|
9318
|
+
* Execute a step that doesn't need rollback.
|
|
9319
|
+
* Useful for read-only operations or operations that are idempotent.
|
|
9320
|
+
* The step name is automatically tracked for error reporting.
|
|
9321
|
+
*
|
|
9322
|
+
* @param name - Step name for logging and error tracking
|
|
9323
|
+
* @param execute - The action to execute
|
|
9324
|
+
* @returns The result of the execute function
|
|
9325
|
+
*/
|
|
9326
|
+
async readOnlyStep(name, execute) {
|
|
9327
|
+
this.currentStepName = name;
|
|
9328
|
+
this.log.debug(`Executing read-only step: ${name}`);
|
|
9329
|
+
const stepStart = performance.now();
|
|
9330
|
+
const result = await execute();
|
|
9331
|
+
const durationMs = Math.round(performance.now() - stepStart);
|
|
9332
|
+
this.stepTimings.push({ name, durationMs });
|
|
9333
|
+
this.log.debug(`Read-only step completed: ${name}`, { durationMs });
|
|
9334
|
+
return result;
|
|
9335
|
+
}
|
|
9336
|
+
/**
|
|
9337
|
+
* Roll back all completed steps in reverse order.
|
|
9338
|
+
* Rollback errors are logged but don't stop the rollback of other steps.
|
|
9339
|
+
*/
|
|
9340
|
+
async rollback() {
|
|
9341
|
+
this.log.info("Rolling back saga", {
|
|
9342
|
+
stepsToRollback: this.completedSteps.length
|
|
9343
|
+
});
|
|
9344
|
+
const stepsReversed = [...this.completedSteps].reverse();
|
|
9345
|
+
for (const step of stepsReversed) {
|
|
9346
|
+
try {
|
|
9347
|
+
this.log.debug(`Rolling back step: ${step.name}`);
|
|
9348
|
+
await step.rollback();
|
|
9349
|
+
this.log.debug(`Step rolled back: ${step.name}`);
|
|
9350
|
+
} catch (error) {
|
|
9351
|
+
this.log.error(`Failed to rollback step: ${step.name}`, {
|
|
9352
|
+
error: error instanceof Error ? error.message : String(error)
|
|
9353
|
+
});
|
|
9354
|
+
}
|
|
9355
|
+
}
|
|
9356
|
+
this.log.info("Rollback completed", {
|
|
9357
|
+
stepsAttempted: this.completedSteps.length
|
|
9358
|
+
});
|
|
9359
|
+
}
|
|
9360
|
+
/**
|
|
9361
|
+
* Get the number of completed steps (useful for testing)
|
|
9362
|
+
*/
|
|
9363
|
+
getCompletedStepCount() {
|
|
9364
|
+
return this.completedSteps.length;
|
|
9365
|
+
}
|
|
9366
|
+
};
|
|
9367
|
+
|
|
9445
9368
|
// ../git/dist/sagas/tree.js
|
|
9446
9369
|
var import_node_fs2 = require("fs");
|
|
9447
9370
|
var fs5 = __toESM(require("fs/promises"), 1);
|