@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.
- package/dist/{agent-DcBmoTR4.d.ts → agent-BJ7Uacyp.d.ts} +2 -0
- package/dist/agent.d.ts +1 -1
- package/dist/agent.js +161 -60
- package/dist/agent.js.map +1 -1
- package/dist/gateway-models.js +21 -2
- package/dist/gateway-models.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +292 -193
- package/dist/index.js.map +1 -1
- package/dist/server/agent-server.js +282 -193
- package/dist/server/agent-server.js.map +1 -1
- package/dist/server/bin.cjs +276 -187
- package/dist/server/bin.cjs.map +1 -1
- package/package.json +1 -1
- package/src/adapters/acp-connection.ts +6 -1
- package/src/adapters/claude/claude-agent.ts +107 -50
- package/src/adapters/claude/session/options.ts +3 -7
- package/src/agent.ts +1 -0
- package/src/gateway-models.ts +42 -2
|
@@ -1178,12 +1178,174 @@ import {
|
|
|
1178
1178
|
import {
|
|
1179
1179
|
query
|
|
1180
1180
|
} from "@anthropic-ai/claude-agent-sdk";
|
|
1181
|
+
|
|
1182
|
+
// ../shared/dist/index.js
|
|
1183
|
+
var consoleLogger = {
|
|
1184
|
+
info: (_message, _data) => {
|
|
1185
|
+
},
|
|
1186
|
+
debug: (_message, _data) => {
|
|
1187
|
+
},
|
|
1188
|
+
error: (_message, _data) => {
|
|
1189
|
+
},
|
|
1190
|
+
warn: (_message, _data) => {
|
|
1191
|
+
}
|
|
1192
|
+
};
|
|
1193
|
+
var Saga = class {
|
|
1194
|
+
completedSteps = [];
|
|
1195
|
+
currentStepName = "unknown";
|
|
1196
|
+
stepTimings = [];
|
|
1197
|
+
log;
|
|
1198
|
+
constructor(logger) {
|
|
1199
|
+
this.log = logger ?? consoleLogger;
|
|
1200
|
+
}
|
|
1201
|
+
/**
|
|
1202
|
+
* Run the saga with the given input.
|
|
1203
|
+
* Returns a discriminated union result - either success with data or failure with error details.
|
|
1204
|
+
*/
|
|
1205
|
+
async run(input) {
|
|
1206
|
+
this.completedSteps = [];
|
|
1207
|
+
this.currentStepName = "unknown";
|
|
1208
|
+
this.stepTimings = [];
|
|
1209
|
+
const sagaStart = performance.now();
|
|
1210
|
+
this.log.info("Starting saga", { sagaName: this.constructor.name });
|
|
1211
|
+
try {
|
|
1212
|
+
const result = await this.execute(input);
|
|
1213
|
+
const totalDuration = performance.now() - sagaStart;
|
|
1214
|
+
this.log.debug("Saga completed successfully", {
|
|
1215
|
+
sagaName: this.constructor.name,
|
|
1216
|
+
stepsCompleted: this.completedSteps.length,
|
|
1217
|
+
totalDurationMs: Math.round(totalDuration),
|
|
1218
|
+
stepTimings: this.stepTimings
|
|
1219
|
+
});
|
|
1220
|
+
return { success: true, data: result };
|
|
1221
|
+
} catch (error) {
|
|
1222
|
+
this.log.error("Saga failed, initiating rollback", {
|
|
1223
|
+
sagaName: this.constructor.name,
|
|
1224
|
+
failedStep: this.currentStepName,
|
|
1225
|
+
error: error instanceof Error ? error.message : String(error)
|
|
1226
|
+
});
|
|
1227
|
+
await this.rollback();
|
|
1228
|
+
return {
|
|
1229
|
+
success: false,
|
|
1230
|
+
error: error instanceof Error ? error.message : String(error),
|
|
1231
|
+
failedStep: this.currentStepName
|
|
1232
|
+
};
|
|
1233
|
+
}
|
|
1234
|
+
}
|
|
1235
|
+
/**
|
|
1236
|
+
* Execute a step with its rollback action.
|
|
1237
|
+
* If the step succeeds, its rollback action is stored for potential rollback.
|
|
1238
|
+
* The step name is automatically tracked for error reporting.
|
|
1239
|
+
*
|
|
1240
|
+
* @param config - Step configuration with name, execute, and rollback functions
|
|
1241
|
+
* @returns The result of the execute function
|
|
1242
|
+
* @throws Re-throws any error from the execute function (triggers rollback)
|
|
1243
|
+
*/
|
|
1244
|
+
async step(config) {
|
|
1245
|
+
this.currentStepName = config.name;
|
|
1246
|
+
this.log.debug(`Executing step: ${config.name}`);
|
|
1247
|
+
const stepStart = performance.now();
|
|
1248
|
+
const result = await config.execute();
|
|
1249
|
+
const durationMs = Math.round(performance.now() - stepStart);
|
|
1250
|
+
this.stepTimings.push({ name: config.name, durationMs });
|
|
1251
|
+
this.log.debug(`Step completed: ${config.name}`, { durationMs });
|
|
1252
|
+
this.completedSteps.push({
|
|
1253
|
+
name: config.name,
|
|
1254
|
+
rollback: () => config.rollback(result)
|
|
1255
|
+
});
|
|
1256
|
+
return result;
|
|
1257
|
+
}
|
|
1258
|
+
/**
|
|
1259
|
+
* Execute a step that doesn't need rollback.
|
|
1260
|
+
* Useful for read-only operations or operations that are idempotent.
|
|
1261
|
+
* The step name is automatically tracked for error reporting.
|
|
1262
|
+
*
|
|
1263
|
+
* @param name - Step name for logging and error tracking
|
|
1264
|
+
* @param execute - The action to execute
|
|
1265
|
+
* @returns The result of the execute function
|
|
1266
|
+
*/
|
|
1267
|
+
async readOnlyStep(name, execute) {
|
|
1268
|
+
this.currentStepName = name;
|
|
1269
|
+
this.log.debug(`Executing read-only step: ${name}`);
|
|
1270
|
+
const stepStart = performance.now();
|
|
1271
|
+
const result = await execute();
|
|
1272
|
+
const durationMs = Math.round(performance.now() - stepStart);
|
|
1273
|
+
this.stepTimings.push({ name, durationMs });
|
|
1274
|
+
this.log.debug(`Read-only step completed: ${name}`, { durationMs });
|
|
1275
|
+
return result;
|
|
1276
|
+
}
|
|
1277
|
+
/**
|
|
1278
|
+
* Roll back all completed steps in reverse order.
|
|
1279
|
+
* Rollback errors are logged but don't stop the rollback of other steps.
|
|
1280
|
+
*/
|
|
1281
|
+
async rollback() {
|
|
1282
|
+
this.log.info("Rolling back saga", {
|
|
1283
|
+
stepsToRollback: this.completedSteps.length
|
|
1284
|
+
});
|
|
1285
|
+
const stepsReversed = [...this.completedSteps].reverse();
|
|
1286
|
+
for (const step of stepsReversed) {
|
|
1287
|
+
try {
|
|
1288
|
+
this.log.debug(`Rolling back step: ${step.name}`);
|
|
1289
|
+
await step.rollback();
|
|
1290
|
+
this.log.debug(`Step rolled back: ${step.name}`);
|
|
1291
|
+
} catch (error) {
|
|
1292
|
+
this.log.error(`Failed to rollback step: ${step.name}`, {
|
|
1293
|
+
error: error instanceof Error ? error.message : String(error)
|
|
1294
|
+
});
|
|
1295
|
+
}
|
|
1296
|
+
}
|
|
1297
|
+
this.log.info("Rollback completed", {
|
|
1298
|
+
stepsAttempted: this.completedSteps.length
|
|
1299
|
+
});
|
|
1300
|
+
}
|
|
1301
|
+
/**
|
|
1302
|
+
* Get the number of completed steps (useful for testing)
|
|
1303
|
+
*/
|
|
1304
|
+
getCompletedStepCount() {
|
|
1305
|
+
return this.completedSteps.length;
|
|
1306
|
+
}
|
|
1307
|
+
};
|
|
1308
|
+
var NOOP_COLLECTOR = {
|
|
1309
|
+
time: (_label, fn) => fn(),
|
|
1310
|
+
timeSync: (_label, fn) => fn(),
|
|
1311
|
+
record: () => {
|
|
1312
|
+
},
|
|
1313
|
+
summarize: () => {
|
|
1314
|
+
}
|
|
1315
|
+
};
|
|
1316
|
+
function createTimingCollector(enabled, log) {
|
|
1317
|
+
if (!enabled) return NOOP_COLLECTOR;
|
|
1318
|
+
const steps = {};
|
|
1319
|
+
return {
|
|
1320
|
+
async time(label, fn) {
|
|
1321
|
+
const start = Date.now();
|
|
1322
|
+
const result = await fn();
|
|
1323
|
+
steps[label] = Date.now() - start;
|
|
1324
|
+
return result;
|
|
1325
|
+
},
|
|
1326
|
+
timeSync(label, fn) {
|
|
1327
|
+
const start = Date.now();
|
|
1328
|
+
const result = fn();
|
|
1329
|
+
steps[label] = Date.now() - start;
|
|
1330
|
+
return result;
|
|
1331
|
+
},
|
|
1332
|
+
record(label, ms) {
|
|
1333
|
+
steps[label] = ms;
|
|
1334
|
+
},
|
|
1335
|
+
summarize(label) {
|
|
1336
|
+
const total = Object.values(steps).reduce((a, b) => a + b, 0);
|
|
1337
|
+
log(`[timing] ${label}: ${total}ms`, steps);
|
|
1338
|
+
}
|
|
1339
|
+
};
|
|
1340
|
+
}
|
|
1341
|
+
|
|
1342
|
+
// src/adapters/claude/claude-agent.ts
|
|
1181
1343
|
import { v7 as uuidv7 } from "uuid";
|
|
1182
1344
|
|
|
1183
1345
|
// package.json
|
|
1184
1346
|
var package_default = {
|
|
1185
1347
|
name: "@posthog/agent",
|
|
1186
|
-
version: "2.1.
|
|
1348
|
+
version: "2.1.47",
|
|
1187
1349
|
repository: "https://github.com/PostHog/twig",
|
|
1188
1350
|
description: "TypeScript agent framework wrapping Claude Agent SDK with Git-based task execution for PostHog",
|
|
1189
1351
|
exports: {
|
|
@@ -1314,11 +1476,16 @@ function unreachable(value, logger) {
|
|
|
1314
1476
|
// src/gateway-models.ts
|
|
1315
1477
|
var DEFAULT_GATEWAY_MODEL = "claude-opus-4-6";
|
|
1316
1478
|
var BLOCKED_MODELS = /* @__PURE__ */ new Set(["gpt-5-mini", "openai/gpt-5-mini"]);
|
|
1479
|
+
var CACHE_TTL = 10 * 60 * 1e3;
|
|
1480
|
+
var gatewayModelsCache = null;
|
|
1317
1481
|
async function fetchGatewayModels(options) {
|
|
1318
1482
|
const gatewayUrl = options?.gatewayUrl ?? process.env.ANTHROPIC_BASE_URL;
|
|
1319
1483
|
if (!gatewayUrl) {
|
|
1320
1484
|
return [];
|
|
1321
1485
|
}
|
|
1486
|
+
if (gatewayModelsCache && gatewayModelsCache.url === gatewayUrl && Date.now() < gatewayModelsCache.expiry) {
|
|
1487
|
+
return gatewayModelsCache.models;
|
|
1488
|
+
}
|
|
1322
1489
|
const modelsUrl = `${gatewayUrl}/v1/models`;
|
|
1323
1490
|
try {
|
|
1324
1491
|
const response = await fetch(modelsUrl);
|
|
@@ -1326,8 +1493,13 @@ async function fetchGatewayModels(options) {
|
|
|
1326
1493
|
return [];
|
|
1327
1494
|
}
|
|
1328
1495
|
const data = await response.json();
|
|
1329
|
-
const models = data.data ?? [];
|
|
1330
|
-
|
|
1496
|
+
const models = (data.data ?? []).filter((m) => !BLOCKED_MODELS.has(m.id));
|
|
1497
|
+
gatewayModelsCache = {
|
|
1498
|
+
models,
|
|
1499
|
+
expiry: Date.now() + CACHE_TTL,
|
|
1500
|
+
url: gatewayUrl
|
|
1501
|
+
};
|
|
1502
|
+
return models;
|
|
1331
1503
|
} catch {
|
|
1332
1504
|
return [];
|
|
1333
1505
|
}
|
|
@@ -3235,12 +3407,8 @@ function clearStatsigCache() {
|
|
|
3235
3407
|
process.env.CLAUDE_CONFIG_DIR || path2.join(os2.homedir(), ".claude"),
|
|
3236
3408
|
"statsig"
|
|
3237
3409
|
);
|
|
3238
|
-
|
|
3239
|
-
|
|
3240
|
-
fs.rmSync(statsigPath, { recursive: true, force: true });
|
|
3241
|
-
}
|
|
3242
|
-
} catch {
|
|
3243
|
-
}
|
|
3410
|
+
fs.rm(statsigPath, { recursive: true, force: true }, () => {
|
|
3411
|
+
});
|
|
3244
3412
|
}
|
|
3245
3413
|
|
|
3246
3414
|
// src/adapters/claude/claude-agent.ts
|
|
@@ -3250,12 +3418,14 @@ var ClaudeAcpAgent = class extends BaseAcpAgent {
|
|
|
3250
3418
|
backgroundTerminals = {};
|
|
3251
3419
|
clientCapabilities;
|
|
3252
3420
|
logWriter;
|
|
3253
|
-
|
|
3421
|
+
options;
|
|
3254
3422
|
lastSentConfigOptions;
|
|
3255
|
-
|
|
3423
|
+
debug;
|
|
3424
|
+
constructor(client, logWriter, options) {
|
|
3256
3425
|
super(client);
|
|
3257
3426
|
this.logWriter = logWriter;
|
|
3258
|
-
this.
|
|
3427
|
+
this.options = options;
|
|
3428
|
+
this.debug = options?.debug ?? false;
|
|
3259
3429
|
this.toolUseCache = {};
|
|
3260
3430
|
this.logger = new Logger({ debug: true, prefix: "[ClaudeAcpAgent]" });
|
|
3261
3431
|
}
|
|
@@ -3298,27 +3468,36 @@ var ClaudeAcpAgent = class extends BaseAcpAgent {
|
|
|
3298
3468
|
}
|
|
3299
3469
|
async newSession(params) {
|
|
3300
3470
|
this.checkAuthStatus();
|
|
3471
|
+
const tc = createTimingCollector(
|
|
3472
|
+
this.debug,
|
|
3473
|
+
(msg, data) => this.logger.info(msg, data)
|
|
3474
|
+
);
|
|
3301
3475
|
const meta = params._meta;
|
|
3302
3476
|
const sessionId = uuidv7();
|
|
3303
3477
|
const permissionMode = meta?.permissionMode && TWIG_EXECUTION_MODES.includes(meta.permissionMode) ? meta.permissionMode : "default";
|
|
3304
|
-
const mcpServers =
|
|
3305
|
-
|
|
3306
|
-
|
|
3307
|
-
|
|
3308
|
-
|
|
3309
|
-
|
|
3310
|
-
|
|
3311
|
-
|
|
3312
|
-
|
|
3313
|
-
|
|
3314
|
-
|
|
3315
|
-
|
|
3316
|
-
|
|
3317
|
-
|
|
3318
|
-
|
|
3319
|
-
|
|
3478
|
+
const mcpServers = tc.timeSync(
|
|
3479
|
+
"parseMcpServers",
|
|
3480
|
+
() => parseMcpServers(params)
|
|
3481
|
+
);
|
|
3482
|
+
const options = tc.timeSync(
|
|
3483
|
+
"buildSessionOptions",
|
|
3484
|
+
() => buildSessionOptions({
|
|
3485
|
+
cwd: params.cwd,
|
|
3486
|
+
mcpServers,
|
|
3487
|
+
permissionMode,
|
|
3488
|
+
canUseTool: this.createCanUseTool(sessionId),
|
|
3489
|
+
logger: this.logger,
|
|
3490
|
+
systemPrompt: buildSystemPrompt(meta?.systemPrompt),
|
|
3491
|
+
userProvidedOptions: meta?.claudeCode?.options,
|
|
3492
|
+
sessionId,
|
|
3493
|
+
isResume: false,
|
|
3494
|
+
onModeChange: this.createOnModeChange(sessionId),
|
|
3495
|
+
onProcessSpawned: this.options?.onProcessSpawned,
|
|
3496
|
+
onProcessExited: this.options?.onProcessExited
|
|
3497
|
+
})
|
|
3498
|
+
);
|
|
3320
3499
|
const input = new Pushable();
|
|
3321
|
-
const q = query({ prompt: input, options });
|
|
3500
|
+
const q = tc.timeSync("sdkQuery", () => query({ prompt: input, options }));
|
|
3322
3501
|
const session = this.createSession(
|
|
3323
3502
|
sessionId,
|
|
3324
3503
|
q,
|
|
@@ -3330,28 +3509,40 @@ var ClaudeAcpAgent = class extends BaseAcpAgent {
|
|
|
3330
3509
|
session.taskRunId = meta?.taskRunId;
|
|
3331
3510
|
this.registerPersistence(sessionId, meta);
|
|
3332
3511
|
if (meta?.taskRunId) {
|
|
3333
|
-
await
|
|
3334
|
-
|
|
3335
|
-
|
|
3336
|
-
|
|
3337
|
-
|
|
3512
|
+
await tc.time(
|
|
3513
|
+
"extNotification",
|
|
3514
|
+
() => this.client.extNotification("_posthog/sdk_session", {
|
|
3515
|
+
taskRunId: meta.taskRunId,
|
|
3516
|
+
sessionId,
|
|
3517
|
+
adapter: "claude"
|
|
3518
|
+
})
|
|
3519
|
+
);
|
|
3338
3520
|
}
|
|
3339
|
-
const modelOptions = await
|
|
3521
|
+
const modelOptions = await tc.time(
|
|
3522
|
+
"fetchModels",
|
|
3523
|
+
() => this.getModelConfigOptions()
|
|
3524
|
+
);
|
|
3525
|
+
this.deferBackgroundFetches(tc, q, sessionId, mcpServers);
|
|
3340
3526
|
session.modelId = modelOptions.currentModelId;
|
|
3341
3527
|
await this.trySetModel(q, modelOptions.currentModelId);
|
|
3342
|
-
|
|
3343
|
-
|
|
3344
|
-
|
|
3528
|
+
const configOptions = await tc.time(
|
|
3529
|
+
"buildConfigOptions",
|
|
3530
|
+
() => this.buildConfigOptions(modelOptions)
|
|
3345
3531
|
);
|
|
3532
|
+
tc.summarize("newSession");
|
|
3346
3533
|
return {
|
|
3347
3534
|
sessionId,
|
|
3348
|
-
configOptions
|
|
3535
|
+
configOptions
|
|
3349
3536
|
};
|
|
3350
3537
|
}
|
|
3351
3538
|
async loadSession(params) {
|
|
3352
3539
|
return this.resumeSession(params);
|
|
3353
3540
|
}
|
|
3354
3541
|
async resumeSession(params) {
|
|
3542
|
+
const tc = createTimingCollector(
|
|
3543
|
+
this.debug,
|
|
3544
|
+
(msg, data) => this.logger.info(msg, data)
|
|
3545
|
+
);
|
|
3355
3546
|
const meta = params._meta;
|
|
3356
3547
|
const sessionId = meta?.sessionId;
|
|
3357
3548
|
if (!sessionId) {
|
|
@@ -3360,28 +3551,33 @@ var ClaudeAcpAgent = class extends BaseAcpAgent {
|
|
|
3360
3551
|
if (this.sessionId === sessionId) {
|
|
3361
3552
|
return {};
|
|
3362
3553
|
}
|
|
3363
|
-
const mcpServers =
|
|
3364
|
-
|
|
3554
|
+
const mcpServers = tc.timeSync(
|
|
3555
|
+
"parseMcpServers",
|
|
3556
|
+
() => parseMcpServers(params)
|
|
3557
|
+
);
|
|
3365
3558
|
const permissionMode = meta?.permissionMode && TWIG_EXECUTION_MODES.includes(meta.permissionMode) ? meta.permissionMode : "default";
|
|
3366
|
-
const { query: q, session } = await
|
|
3367
|
-
|
|
3368
|
-
|
|
3369
|
-
|
|
3370
|
-
|
|
3371
|
-
|
|
3372
|
-
|
|
3373
|
-
|
|
3374
|
-
|
|
3375
|
-
|
|
3559
|
+
const { query: q, session } = await tc.time(
|
|
3560
|
+
"initializeQuery",
|
|
3561
|
+
() => this.initializeQuery({
|
|
3562
|
+
cwd: params.cwd,
|
|
3563
|
+
permissionMode,
|
|
3564
|
+
mcpServers,
|
|
3565
|
+
systemPrompt: buildSystemPrompt(meta?.systemPrompt),
|
|
3566
|
+
userProvidedOptions: meta?.claudeCode?.options,
|
|
3567
|
+
sessionId,
|
|
3568
|
+
isResume: true,
|
|
3569
|
+
additionalDirectories: meta?.claudeCode?.options?.additionalDirectories
|
|
3570
|
+
})
|
|
3571
|
+
);
|
|
3376
3572
|
session.taskRunId = meta?.taskRunId;
|
|
3377
3573
|
this.registerPersistence(sessionId, meta);
|
|
3378
|
-
this.
|
|
3379
|
-
|
|
3380
|
-
|
|
3574
|
+
this.deferBackgroundFetches(tc, q, sessionId, mcpServers);
|
|
3575
|
+
const configOptions = await tc.time(
|
|
3576
|
+
"buildConfigOptions",
|
|
3577
|
+
() => this.buildConfigOptions()
|
|
3381
3578
|
);
|
|
3382
|
-
|
|
3383
|
-
|
|
3384
|
-
};
|
|
3579
|
+
tc.summarize("resumeSession");
|
|
3580
|
+
return { configOptions };
|
|
3385
3581
|
}
|
|
3386
3582
|
async prompt(params) {
|
|
3387
3583
|
this.session.cancelled = false;
|
|
@@ -3453,8 +3649,8 @@ var ClaudeAcpAgent = class extends BaseAcpAgent {
|
|
|
3453
3649
|
isResume: config.isResume,
|
|
3454
3650
|
additionalDirectories: config.additionalDirectories,
|
|
3455
3651
|
onModeChange: this.createOnModeChange(config.sessionId),
|
|
3456
|
-
onProcessSpawned: this.
|
|
3457
|
-
onProcessExited: this.
|
|
3652
|
+
onProcessSpawned: this.options?.onProcessSpawned,
|
|
3653
|
+
onProcessExited: this.options?.onProcessExited
|
|
3458
3654
|
});
|
|
3459
3655
|
const q = query({ prompt: input, options });
|
|
3460
3656
|
const abortController = options.abortController;
|
|
@@ -3564,6 +3760,23 @@ var ClaudeAcpAgent = class extends BaseAcpAgent {
|
|
|
3564
3760
|
await q.setModel(fallback);
|
|
3565
3761
|
}
|
|
3566
3762
|
}
|
|
3763
|
+
/**
|
|
3764
|
+
* Fire-and-forget: fetch slash commands and MCP tool metadata in parallel.
|
|
3765
|
+
* Both populate caches used later — neither is needed to return configOptions.
|
|
3766
|
+
*/
|
|
3767
|
+
deferBackgroundFetches(tc, q, sessionId, mcpServers) {
|
|
3768
|
+
Promise.all([
|
|
3769
|
+
tc.time("slashCommands", () => getAvailableSlashCommands(q)),
|
|
3770
|
+
tc.time(
|
|
3771
|
+
"mcpMetadata",
|
|
3772
|
+
() => fetchMcpToolMetadata(mcpServers, this.logger)
|
|
3773
|
+
)
|
|
3774
|
+
]).then(([slashCommands]) => {
|
|
3775
|
+
this.sendAvailableCommandsUpdate(sessionId, slashCommands);
|
|
3776
|
+
}).catch((err) => {
|
|
3777
|
+
this.logger.warn("Failed to fetch deferred session data", { err });
|
|
3778
|
+
});
|
|
3779
|
+
}
|
|
3567
3780
|
registerPersistence(sessionId, meta) {
|
|
3568
3781
|
const persistence = meta?.persistence;
|
|
3569
3782
|
if (persistence && this.logWriter) {
|
|
@@ -3851,7 +4064,10 @@ function createClaudeConnection(config) {
|
|
|
3851
4064
|
const agentStream = ndJsonStream(agentWritable, streams.agent.readable);
|
|
3852
4065
|
let agent = null;
|
|
3853
4066
|
const agentConnection = new AgentSideConnection((client) => {
|
|
3854
|
-
agent = new ClaudeAcpAgent(client, logWriter,
|
|
4067
|
+
agent = new ClaudeAcpAgent(client, logWriter, {
|
|
4068
|
+
...config.processCallbacks,
|
|
4069
|
+
debug: config.debug
|
|
4070
|
+
});
|
|
3855
4071
|
logger.info(`Created ${agent.adapterName} agent`);
|
|
3856
4072
|
return agent;
|
|
3857
4073
|
}, agentStream);
|
|
@@ -9231,136 +9447,9 @@ async function getHeadSha(baseDir, options) {
|
|
|
9231
9447
|
}
|
|
9232
9448
|
|
|
9233
9449
|
// src/sagas/apply-snapshot-saga.ts
|
|
9234
|
-
import { mkdir as mkdir3, rm as
|
|
9450
|
+
import { mkdir as mkdir3, rm as rm3, writeFile as writeFile3 } from "fs/promises";
|
|
9235
9451
|
import { join as join5 } from "path";
|
|
9236
9452
|
|
|
9237
|
-
// ../shared/dist/index.js
|
|
9238
|
-
var consoleLogger = {
|
|
9239
|
-
info: (_message, _data) => {
|
|
9240
|
-
},
|
|
9241
|
-
debug: (_message, _data) => {
|
|
9242
|
-
},
|
|
9243
|
-
error: (_message, _data) => {
|
|
9244
|
-
},
|
|
9245
|
-
warn: (_message, _data) => {
|
|
9246
|
-
}
|
|
9247
|
-
};
|
|
9248
|
-
var Saga = class {
|
|
9249
|
-
completedSteps = [];
|
|
9250
|
-
currentStepName = "unknown";
|
|
9251
|
-
stepTimings = [];
|
|
9252
|
-
log;
|
|
9253
|
-
constructor(logger) {
|
|
9254
|
-
this.log = logger ?? consoleLogger;
|
|
9255
|
-
}
|
|
9256
|
-
/**
|
|
9257
|
-
* Run the saga with the given input.
|
|
9258
|
-
* Returns a discriminated union result - either success with data or failure with error details.
|
|
9259
|
-
*/
|
|
9260
|
-
async run(input) {
|
|
9261
|
-
this.completedSteps = [];
|
|
9262
|
-
this.currentStepName = "unknown";
|
|
9263
|
-
this.stepTimings = [];
|
|
9264
|
-
const sagaStart = performance.now();
|
|
9265
|
-
this.log.info("Starting saga", { sagaName: this.constructor.name });
|
|
9266
|
-
try {
|
|
9267
|
-
const result = await this.execute(input);
|
|
9268
|
-
const totalDuration = performance.now() - sagaStart;
|
|
9269
|
-
this.log.debug("Saga completed successfully", {
|
|
9270
|
-
sagaName: this.constructor.name,
|
|
9271
|
-
stepsCompleted: this.completedSteps.length,
|
|
9272
|
-
totalDurationMs: Math.round(totalDuration),
|
|
9273
|
-
stepTimings: this.stepTimings
|
|
9274
|
-
});
|
|
9275
|
-
return { success: true, data: result };
|
|
9276
|
-
} catch (error) {
|
|
9277
|
-
this.log.error("Saga failed, initiating rollback", {
|
|
9278
|
-
sagaName: this.constructor.name,
|
|
9279
|
-
failedStep: this.currentStepName,
|
|
9280
|
-
error: error instanceof Error ? error.message : String(error)
|
|
9281
|
-
});
|
|
9282
|
-
await this.rollback();
|
|
9283
|
-
return {
|
|
9284
|
-
success: false,
|
|
9285
|
-
error: error instanceof Error ? error.message : String(error),
|
|
9286
|
-
failedStep: this.currentStepName
|
|
9287
|
-
};
|
|
9288
|
-
}
|
|
9289
|
-
}
|
|
9290
|
-
/**
|
|
9291
|
-
* Execute a step with its rollback action.
|
|
9292
|
-
* If the step succeeds, its rollback action is stored for potential rollback.
|
|
9293
|
-
* The step name is automatically tracked for error reporting.
|
|
9294
|
-
*
|
|
9295
|
-
* @param config - Step configuration with name, execute, and rollback functions
|
|
9296
|
-
* @returns The result of the execute function
|
|
9297
|
-
* @throws Re-throws any error from the execute function (triggers rollback)
|
|
9298
|
-
*/
|
|
9299
|
-
async step(config) {
|
|
9300
|
-
this.currentStepName = config.name;
|
|
9301
|
-
this.log.debug(`Executing step: ${config.name}`);
|
|
9302
|
-
const stepStart = performance.now();
|
|
9303
|
-
const result = await config.execute();
|
|
9304
|
-
const durationMs = Math.round(performance.now() - stepStart);
|
|
9305
|
-
this.stepTimings.push({ name: config.name, durationMs });
|
|
9306
|
-
this.log.debug(`Step completed: ${config.name}`, { durationMs });
|
|
9307
|
-
this.completedSteps.push({
|
|
9308
|
-
name: config.name,
|
|
9309
|
-
rollback: () => config.rollback(result)
|
|
9310
|
-
});
|
|
9311
|
-
return result;
|
|
9312
|
-
}
|
|
9313
|
-
/**
|
|
9314
|
-
* Execute a step that doesn't need rollback.
|
|
9315
|
-
* Useful for read-only operations or operations that are idempotent.
|
|
9316
|
-
* The step name is automatically tracked for error reporting.
|
|
9317
|
-
*
|
|
9318
|
-
* @param name - Step name for logging and error tracking
|
|
9319
|
-
* @param execute - The action to execute
|
|
9320
|
-
* @returns The result of the execute function
|
|
9321
|
-
*/
|
|
9322
|
-
async readOnlyStep(name, execute) {
|
|
9323
|
-
this.currentStepName = name;
|
|
9324
|
-
this.log.debug(`Executing read-only step: ${name}`);
|
|
9325
|
-
const stepStart = performance.now();
|
|
9326
|
-
const result = await execute();
|
|
9327
|
-
const durationMs = Math.round(performance.now() - stepStart);
|
|
9328
|
-
this.stepTimings.push({ name, durationMs });
|
|
9329
|
-
this.log.debug(`Read-only step completed: ${name}`, { durationMs });
|
|
9330
|
-
return result;
|
|
9331
|
-
}
|
|
9332
|
-
/**
|
|
9333
|
-
* Roll back all completed steps in reverse order.
|
|
9334
|
-
* Rollback errors are logged but don't stop the rollback of other steps.
|
|
9335
|
-
*/
|
|
9336
|
-
async rollback() {
|
|
9337
|
-
this.log.info("Rolling back saga", {
|
|
9338
|
-
stepsToRollback: this.completedSteps.length
|
|
9339
|
-
});
|
|
9340
|
-
const stepsReversed = [...this.completedSteps].reverse();
|
|
9341
|
-
for (const step of stepsReversed) {
|
|
9342
|
-
try {
|
|
9343
|
-
this.log.debug(`Rolling back step: ${step.name}`);
|
|
9344
|
-
await step.rollback();
|
|
9345
|
-
this.log.debug(`Step rolled back: ${step.name}`);
|
|
9346
|
-
} catch (error) {
|
|
9347
|
-
this.log.error(`Failed to rollback step: ${step.name}`, {
|
|
9348
|
-
error: error instanceof Error ? error.message : String(error)
|
|
9349
|
-
});
|
|
9350
|
-
}
|
|
9351
|
-
}
|
|
9352
|
-
this.log.info("Rollback completed", {
|
|
9353
|
-
stepsAttempted: this.completedSteps.length
|
|
9354
|
-
});
|
|
9355
|
-
}
|
|
9356
|
-
/**
|
|
9357
|
-
* Get the number of completed steps (useful for testing)
|
|
9358
|
-
*/
|
|
9359
|
-
getCompletedStepCount() {
|
|
9360
|
-
return this.completedSteps.length;
|
|
9361
|
-
}
|
|
9362
|
-
};
|
|
9363
|
-
|
|
9364
9453
|
// ../git/dist/sagas/tree.js
|
|
9365
9454
|
import { existsSync as existsSync4 } from "fs";
|
|
9366
9455
|
import * as fs5 from "fs/promises";
|
|
@@ -9672,7 +9761,7 @@ var ApplySnapshotSaga = class extends Saga {
|
|
|
9672
9761
|
},
|
|
9673
9762
|
rollback: async () => {
|
|
9674
9763
|
if (this.archivePath) {
|
|
9675
|
-
await
|
|
9764
|
+
await rm3(this.archivePath, { force: true }).catch(() => {
|
|
9676
9765
|
});
|
|
9677
9766
|
}
|
|
9678
9767
|
}
|
|
@@ -9688,7 +9777,7 @@ var ApplySnapshotSaga = class extends Saga {
|
|
|
9688
9777
|
if (!applyResult.success) {
|
|
9689
9778
|
throw new Error(`Failed to apply tree: ${applyResult.error}`);
|
|
9690
9779
|
}
|
|
9691
|
-
await
|
|
9780
|
+
await rm3(this.archivePath, { force: true }).catch(() => {
|
|
9692
9781
|
});
|
|
9693
9782
|
this.log.info("Tree snapshot applied", {
|
|
9694
9783
|
treeHash: snapshot.treeHash,
|
|
@@ -9701,7 +9790,7 @@ var ApplySnapshotSaga = class extends Saga {
|
|
|
9701
9790
|
|
|
9702
9791
|
// src/sagas/capture-tree-saga.ts
|
|
9703
9792
|
import { existsSync as existsSync5 } from "fs";
|
|
9704
|
-
import { readFile as readFile3, rm as
|
|
9793
|
+
import { readFile as readFile3, rm as rm4 } from "fs/promises";
|
|
9705
9794
|
import { join as join6 } from "path";
|
|
9706
9795
|
var CaptureTreeSaga2 = class extends Saga {
|
|
9707
9796
|
async execute(input) {
|
|
@@ -9750,7 +9839,7 @@ var CaptureTreeSaga2 = class extends Saga {
|
|
|
9750
9839
|
runId
|
|
9751
9840
|
);
|
|
9752
9841
|
} finally {
|
|
9753
|
-
await
|
|
9842
|
+
await rm4(createdArchivePath, { force: true }).catch(() => {
|
|
9754
9843
|
});
|
|
9755
9844
|
}
|
|
9756
9845
|
}
|
|
@@ -9794,7 +9883,7 @@ var CaptureTreeSaga2 = class extends Saga {
|
|
|
9794
9883
|
return void 0;
|
|
9795
9884
|
},
|
|
9796
9885
|
rollback: async () => {
|
|
9797
|
-
await
|
|
9886
|
+
await rm4(archivePath, { force: true }).catch(() => {
|
|
9798
9887
|
});
|
|
9799
9888
|
}
|
|
9800
9889
|
});
|