@posthog/agent 2.1.35 → 2.1.47

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.
@@ -1170,12 +1170,174 @@ 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
1173
1335
  var import_uuid = require("uuid");
1174
1336
 
1175
1337
  // package.json
1176
1338
  var package_default = {
1177
1339
  name: "@posthog/agent",
1178
- version: "2.1.35",
1340
+ version: "2.1.47",
1179
1341
  repository: "https://github.com/PostHog/twig",
1180
1342
  description: "TypeScript agent framework wrapping Claude Agent SDK with Git-based task execution for PostHog",
1181
1343
  exports: {
@@ -1306,11 +1468,16 @@ function unreachable(value, logger) {
1306
1468
  // src/gateway-models.ts
1307
1469
  var DEFAULT_GATEWAY_MODEL = "claude-opus-4-6";
1308
1470
  var BLOCKED_MODELS = /* @__PURE__ */ new Set(["gpt-5-mini", "openai/gpt-5-mini"]);
1471
+ var CACHE_TTL = 10 * 60 * 1e3;
1472
+ var gatewayModelsCache = null;
1309
1473
  async function fetchGatewayModels(options) {
1310
1474
  const gatewayUrl = options?.gatewayUrl ?? process.env.ANTHROPIC_BASE_URL;
1311
1475
  if (!gatewayUrl) {
1312
1476
  return [];
1313
1477
  }
1478
+ if (gatewayModelsCache && gatewayModelsCache.url === gatewayUrl && Date.now() < gatewayModelsCache.expiry) {
1479
+ return gatewayModelsCache.models;
1480
+ }
1314
1481
  const modelsUrl = `${gatewayUrl}/v1/models`;
1315
1482
  try {
1316
1483
  const response = await fetch(modelsUrl);
@@ -1318,8 +1485,13 @@ async function fetchGatewayModels(options) {
1318
1485
  return [];
1319
1486
  }
1320
1487
  const data = await response.json();
1321
- const models = data.data ?? [];
1322
- return models.filter((m) => !BLOCKED_MODELS.has(m.id));
1488
+ const models = (data.data ?? []).filter((m) => !BLOCKED_MODELS.has(m.id));
1489
+ gatewayModelsCache = {
1490
+ models,
1491
+ expiry: Date.now() + CACHE_TTL,
1492
+ url: gatewayUrl
1493
+ };
1494
+ return models;
1323
1495
  } catch {
1324
1496
  return [];
1325
1497
  }
@@ -3227,12 +3399,8 @@ function clearStatsigCache() {
3227
3399
  process.env.CLAUDE_CONFIG_DIR || path2.join(os2.homedir(), ".claude"),
3228
3400
  "statsig"
3229
3401
  );
3230
- try {
3231
- if (fs.existsSync(statsigPath)) {
3232
- fs.rmSync(statsigPath, { recursive: true, force: true });
3233
- }
3234
- } catch {
3235
- }
3402
+ fs.rm(statsigPath, { recursive: true, force: true }, () => {
3403
+ });
3236
3404
  }
3237
3405
 
3238
3406
  // src/adapters/claude/claude-agent.ts
@@ -3242,12 +3410,14 @@ var ClaudeAcpAgent = class extends BaseAcpAgent {
3242
3410
  backgroundTerminals = {};
3243
3411
  clientCapabilities;
3244
3412
  logWriter;
3245
- processCallbacks;
3413
+ options;
3246
3414
  lastSentConfigOptions;
3247
- constructor(client, logWriter, processCallbacks) {
3415
+ debug;
3416
+ constructor(client, logWriter, options) {
3248
3417
  super(client);
3249
3418
  this.logWriter = logWriter;
3250
- this.processCallbacks = processCallbacks;
3419
+ this.options = options;
3420
+ this.debug = options?.debug ?? false;
3251
3421
  this.toolUseCache = {};
3252
3422
  this.logger = new Logger({ debug: true, prefix: "[ClaudeAcpAgent]" });
3253
3423
  }
@@ -3290,27 +3460,36 @@ var ClaudeAcpAgent = class extends BaseAcpAgent {
3290
3460
  }
3291
3461
  async newSession(params) {
3292
3462
  this.checkAuthStatus();
3463
+ const tc = createTimingCollector(
3464
+ this.debug,
3465
+ (msg, data) => this.logger.info(msg, data)
3466
+ );
3293
3467
  const meta = params._meta;
3294
3468
  const sessionId = (0, import_uuid.v7)();
3295
3469
  const permissionMode = meta?.permissionMode && TWIG_EXECUTION_MODES.includes(meta.permissionMode) ? meta.permissionMode : "default";
3296
- const mcpServers = parseMcpServers(params);
3297
- await fetchMcpToolMetadata(mcpServers, this.logger);
3298
- const options = buildSessionOptions({
3299
- cwd: params.cwd,
3300
- mcpServers,
3301
- permissionMode,
3302
- canUseTool: this.createCanUseTool(sessionId),
3303
- logger: this.logger,
3304
- systemPrompt: buildSystemPrompt(meta?.systemPrompt),
3305
- userProvidedOptions: meta?.claudeCode?.options,
3306
- sessionId,
3307
- isResume: false,
3308
- onModeChange: this.createOnModeChange(sessionId),
3309
- onProcessSpawned: this.processCallbacks?.onProcessSpawned,
3310
- onProcessExited: this.processCallbacks?.onProcessExited
3311
- });
3470
+ const mcpServers = tc.timeSync(
3471
+ "parseMcpServers",
3472
+ () => parseMcpServers(params)
3473
+ );
3474
+ const options = tc.timeSync(
3475
+ "buildSessionOptions",
3476
+ () => buildSessionOptions({
3477
+ cwd: params.cwd,
3478
+ mcpServers,
3479
+ permissionMode,
3480
+ canUseTool: this.createCanUseTool(sessionId),
3481
+ logger: this.logger,
3482
+ systemPrompt: buildSystemPrompt(meta?.systemPrompt),
3483
+ userProvidedOptions: meta?.claudeCode?.options,
3484
+ sessionId,
3485
+ isResume: false,
3486
+ onModeChange: this.createOnModeChange(sessionId),
3487
+ onProcessSpawned: this.options?.onProcessSpawned,
3488
+ onProcessExited: this.options?.onProcessExited
3489
+ })
3490
+ );
3312
3491
  const input = new Pushable();
3313
- const q = (0, import_claude_agent_sdk.query)({ prompt: input, options });
3492
+ const q = tc.timeSync("sdkQuery", () => (0, import_claude_agent_sdk.query)({ prompt: input, options }));
3314
3493
  const session = this.createSession(
3315
3494
  sessionId,
3316
3495
  q,
@@ -3322,28 +3501,40 @@ var ClaudeAcpAgent = class extends BaseAcpAgent {
3322
3501
  session.taskRunId = meta?.taskRunId;
3323
3502
  this.registerPersistence(sessionId, meta);
3324
3503
  if (meta?.taskRunId) {
3325
- await this.client.extNotification("_posthog/sdk_session", {
3326
- taskRunId: meta.taskRunId,
3327
- sessionId,
3328
- adapter: "claude"
3329
- });
3504
+ await tc.time(
3505
+ "extNotification",
3506
+ () => this.client.extNotification("_posthog/sdk_session", {
3507
+ taskRunId: meta.taskRunId,
3508
+ sessionId,
3509
+ adapter: "claude"
3510
+ })
3511
+ );
3330
3512
  }
3331
- const modelOptions = await this.getModelConfigOptions();
3513
+ const modelOptions = await tc.time(
3514
+ "fetchModels",
3515
+ () => this.getModelConfigOptions()
3516
+ );
3517
+ this.deferBackgroundFetches(tc, q, sessionId, mcpServers);
3332
3518
  session.modelId = modelOptions.currentModelId;
3333
3519
  await this.trySetModel(q, modelOptions.currentModelId);
3334
- this.sendAvailableCommandsUpdate(
3335
- sessionId,
3336
- await getAvailableSlashCommands(q)
3520
+ const configOptions = await tc.time(
3521
+ "buildConfigOptions",
3522
+ () => this.buildConfigOptions(modelOptions)
3337
3523
  );
3524
+ tc.summarize("newSession");
3338
3525
  return {
3339
3526
  sessionId,
3340
- configOptions: await this.buildConfigOptions(modelOptions)
3527
+ configOptions
3341
3528
  };
3342
3529
  }
3343
3530
  async loadSession(params) {
3344
3531
  return this.resumeSession(params);
3345
3532
  }
3346
3533
  async resumeSession(params) {
3534
+ const tc = createTimingCollector(
3535
+ this.debug,
3536
+ (msg, data) => this.logger.info(msg, data)
3537
+ );
3347
3538
  const meta = params._meta;
3348
3539
  const sessionId = meta?.sessionId;
3349
3540
  if (!sessionId) {
@@ -3352,28 +3543,33 @@ var ClaudeAcpAgent = class extends BaseAcpAgent {
3352
3543
  if (this.sessionId === sessionId) {
3353
3544
  return {};
3354
3545
  }
3355
- const mcpServers = parseMcpServers(params);
3356
- await fetchMcpToolMetadata(mcpServers, this.logger);
3546
+ const mcpServers = tc.timeSync(
3547
+ "parseMcpServers",
3548
+ () => parseMcpServers(params)
3549
+ );
3357
3550
  const permissionMode = meta?.permissionMode && TWIG_EXECUTION_MODES.includes(meta.permissionMode) ? meta.permissionMode : "default";
3358
- const { query: q, session } = await this.initializeQuery({
3359
- cwd: params.cwd,
3360
- permissionMode,
3361
- mcpServers,
3362
- systemPrompt: buildSystemPrompt(meta?.systemPrompt),
3363
- userProvidedOptions: meta?.claudeCode?.options,
3364
- sessionId,
3365
- isResume: true,
3366
- additionalDirectories: meta?.claudeCode?.options?.additionalDirectories
3367
- });
3551
+ const { query: q, session } = await tc.time(
3552
+ "initializeQuery",
3553
+ () => this.initializeQuery({
3554
+ cwd: params.cwd,
3555
+ permissionMode,
3556
+ mcpServers,
3557
+ systemPrompt: buildSystemPrompt(meta?.systemPrompt),
3558
+ userProvidedOptions: meta?.claudeCode?.options,
3559
+ sessionId,
3560
+ isResume: true,
3561
+ additionalDirectories: meta?.claudeCode?.options?.additionalDirectories
3562
+ })
3563
+ );
3368
3564
  session.taskRunId = meta?.taskRunId;
3369
3565
  this.registerPersistence(sessionId, meta);
3370
- this.sendAvailableCommandsUpdate(
3371
- sessionId,
3372
- await getAvailableSlashCommands(q)
3566
+ this.deferBackgroundFetches(tc, q, sessionId, mcpServers);
3567
+ const configOptions = await tc.time(
3568
+ "buildConfigOptions",
3569
+ () => this.buildConfigOptions()
3373
3570
  );
3374
- return {
3375
- configOptions: await this.buildConfigOptions()
3376
- };
3571
+ tc.summarize("resumeSession");
3572
+ return { configOptions };
3377
3573
  }
3378
3574
  async prompt(params) {
3379
3575
  this.session.cancelled = false;
@@ -3445,8 +3641,8 @@ var ClaudeAcpAgent = class extends BaseAcpAgent {
3445
3641
  isResume: config.isResume,
3446
3642
  additionalDirectories: config.additionalDirectories,
3447
3643
  onModeChange: this.createOnModeChange(config.sessionId),
3448
- onProcessSpawned: this.processCallbacks?.onProcessSpawned,
3449
- onProcessExited: this.processCallbacks?.onProcessExited
3644
+ onProcessSpawned: this.options?.onProcessSpawned,
3645
+ onProcessExited: this.options?.onProcessExited
3450
3646
  });
3451
3647
  const q = (0, import_claude_agent_sdk.query)({ prompt: input, options });
3452
3648
  const abortController = options.abortController;
@@ -3556,6 +3752,23 @@ var ClaudeAcpAgent = class extends BaseAcpAgent {
3556
3752
  await q.setModel(fallback);
3557
3753
  }
3558
3754
  }
3755
+ /**
3756
+ * Fire-and-forget: fetch slash commands and MCP tool metadata in parallel.
3757
+ * Both populate caches used later — neither is needed to return configOptions.
3758
+ */
3759
+ deferBackgroundFetches(tc, q, sessionId, mcpServers) {
3760
+ Promise.all([
3761
+ tc.time("slashCommands", () => getAvailableSlashCommands(q)),
3762
+ tc.time(
3763
+ "mcpMetadata",
3764
+ () => fetchMcpToolMetadata(mcpServers, this.logger)
3765
+ )
3766
+ ]).then(([slashCommands]) => {
3767
+ this.sendAvailableCommandsUpdate(sessionId, slashCommands);
3768
+ }).catch((err) => {
3769
+ this.logger.warn("Failed to fetch deferred session data", { err });
3770
+ });
3771
+ }
3559
3772
  registerPersistence(sessionId, meta) {
3560
3773
  const persistence = meta?.persistence;
3561
3774
  if (persistence && this.logWriter) {
@@ -3843,7 +4056,10 @@ function createClaudeConnection(config) {
3843
4056
  const agentStream = (0, import_sdk3.ndJsonStream)(agentWritable, streams.agent.readable);
3844
4057
  let agent = null;
3845
4058
  const agentConnection = new import_sdk3.AgentSideConnection((client) => {
3846
- agent = new ClaudeAcpAgent(client, logWriter, config.processCallbacks);
4059
+ agent = new ClaudeAcpAgent(client, logWriter, {
4060
+ ...config.processCallbacks,
4061
+ debug: config.debug
4062
+ });
3847
4063
  logger.info(`Created ${agent.adapterName} agent`);
3848
4064
  return agent;
3849
4065
  }, agentStream);
@@ -9226,133 +9442,6 @@ async function getHeadSha(baseDir, options) {
9226
9442
  var import_promises2 = require("fs/promises");
9227
9443
  var import_node_path3 = require("path");
9228
9444
 
9229
- // ../shared/dist/index.js
9230
- var consoleLogger = {
9231
- info: (_message, _data) => {
9232
- },
9233
- debug: (_message, _data) => {
9234
- },
9235
- error: (_message, _data) => {
9236
- },
9237
- warn: (_message, _data) => {
9238
- }
9239
- };
9240
- var Saga = class {
9241
- completedSteps = [];
9242
- currentStepName = "unknown";
9243
- stepTimings = [];
9244
- log;
9245
- constructor(logger) {
9246
- this.log = logger ?? consoleLogger;
9247
- }
9248
- /**
9249
- * Run the saga with the given input.
9250
- * Returns a discriminated union result - either success with data or failure with error details.
9251
- */
9252
- async run(input) {
9253
- this.completedSteps = [];
9254
- this.currentStepName = "unknown";
9255
- this.stepTimings = [];
9256
- const sagaStart = performance.now();
9257
- this.log.info("Starting saga", { sagaName: this.constructor.name });
9258
- try {
9259
- const result = await this.execute(input);
9260
- const totalDuration = performance.now() - sagaStart;
9261
- this.log.debug("Saga completed successfully", {
9262
- sagaName: this.constructor.name,
9263
- stepsCompleted: this.completedSteps.length,
9264
- totalDurationMs: Math.round(totalDuration),
9265
- stepTimings: this.stepTimings
9266
- });
9267
- return { success: true, data: result };
9268
- } catch (error) {
9269
- this.log.error("Saga failed, initiating rollback", {
9270
- sagaName: this.constructor.name,
9271
- failedStep: this.currentStepName,
9272
- error: error instanceof Error ? error.message : String(error)
9273
- });
9274
- await this.rollback();
9275
- return {
9276
- success: false,
9277
- error: error instanceof Error ? error.message : String(error),
9278
- failedStep: this.currentStepName
9279
- };
9280
- }
9281
- }
9282
- /**
9283
- * Execute a step with its rollback action.
9284
- * If the step succeeds, its rollback action is stored for potential rollback.
9285
- * The step name is automatically tracked for error reporting.
9286
- *
9287
- * @param config - Step configuration with name, execute, and rollback functions
9288
- * @returns The result of the execute function
9289
- * @throws Re-throws any error from the execute function (triggers rollback)
9290
- */
9291
- async step(config) {
9292
- this.currentStepName = config.name;
9293
- this.log.debug(`Executing step: ${config.name}`);
9294
- const stepStart = performance.now();
9295
- const result = await config.execute();
9296
- const durationMs = Math.round(performance.now() - stepStart);
9297
- this.stepTimings.push({ name: config.name, durationMs });
9298
- this.log.debug(`Step completed: ${config.name}`, { durationMs });
9299
- this.completedSteps.push({
9300
- name: config.name,
9301
- rollback: () => config.rollback(result)
9302
- });
9303
- return result;
9304
- }
9305
- /**
9306
- * Execute a step that doesn't need rollback.
9307
- * Useful for read-only operations or operations that are idempotent.
9308
- * The step name is automatically tracked for error reporting.
9309
- *
9310
- * @param name - Step name for logging and error tracking
9311
- * @param execute - The action to execute
9312
- * @returns The result of the execute function
9313
- */
9314
- async readOnlyStep(name, execute) {
9315
- this.currentStepName = name;
9316
- this.log.debug(`Executing read-only step: ${name}`);
9317
- const stepStart = performance.now();
9318
- const result = await execute();
9319
- const durationMs = Math.round(performance.now() - stepStart);
9320
- this.stepTimings.push({ name, durationMs });
9321
- this.log.debug(`Read-only step completed: ${name}`, { durationMs });
9322
- return result;
9323
- }
9324
- /**
9325
- * Roll back all completed steps in reverse order.
9326
- * Rollback errors are logged but don't stop the rollback of other steps.
9327
- */
9328
- async rollback() {
9329
- this.log.info("Rolling back saga", {
9330
- stepsToRollback: this.completedSteps.length
9331
- });
9332
- const stepsReversed = [...this.completedSteps].reverse();
9333
- for (const step of stepsReversed) {
9334
- try {
9335
- this.log.debug(`Rolling back step: ${step.name}`);
9336
- await step.rollback();
9337
- this.log.debug(`Step rolled back: ${step.name}`);
9338
- } catch (error) {
9339
- this.log.error(`Failed to rollback step: ${step.name}`, {
9340
- error: error instanceof Error ? error.message : String(error)
9341
- });
9342
- }
9343
- }
9344
- this.log.info("Rollback completed", {
9345
- stepsAttempted: this.completedSteps.length
9346
- });
9347
- }
9348
- /**
9349
- * Get the number of completed steps (useful for testing)
9350
- */
9351
- getCompletedStepCount() {
9352
- return this.completedSteps.length;
9353
- }
9354
- };
9355
-
9356
9445
  // ../git/dist/sagas/tree.js
9357
9446
  var import_node_fs2 = require("fs");
9358
9447
  var fs5 = __toESM(require("fs/promises"), 1);