@posthog/agent 2.1.47 → 2.1.53
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-9gv5HohC.d.ts} +4 -2
- package/dist/agent.d.ts +1 -1
- package/dist/agent.js +91 -132
- package/dist/agent.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +288 -327
- package/dist/index.js.map +1 -1
- package/dist/server/agent-server.js +286 -325
- package/dist/server/agent-server.js.map +1 -1
- package/dist/server/bin.cjs +293 -332
- package/dist/server/bin.cjs.map +1 -1
- package/dist/types.d.ts +2 -0
- 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 +1 -1
- package/src/session-log-writer.ts +50 -0
- package/src/types.ts +2 -0
package/dist/index.js
CHANGED
|
@@ -809,10 +809,10 @@ var require_src2 = __commonJS({
|
|
|
809
809
|
var fs_1 = __require("fs");
|
|
810
810
|
var debug_1 = __importDefault(require_src());
|
|
811
811
|
var log = debug_1.default("@kwsites/file-exists");
|
|
812
|
-
function check(
|
|
813
|
-
log(`checking %s`,
|
|
812
|
+
function check(path8, isFile, isDirectory) {
|
|
813
|
+
log(`checking %s`, path8);
|
|
814
814
|
try {
|
|
815
|
-
const stat = fs_1.statSync(
|
|
815
|
+
const stat = fs_1.statSync(path8);
|
|
816
816
|
if (stat.isFile() && isFile) {
|
|
817
817
|
log(`[OK] path represents a file`);
|
|
818
818
|
return true;
|
|
@@ -832,8 +832,8 @@ var require_src2 = __commonJS({
|
|
|
832
832
|
throw e;
|
|
833
833
|
}
|
|
834
834
|
}
|
|
835
|
-
function exists2(
|
|
836
|
-
return check(
|
|
835
|
+
function exists2(path8, type = exports.READABLE) {
|
|
836
|
+
return check(path8, (type & exports.FILE) > 0, (type & exports.FOLDER) > 0);
|
|
837
837
|
}
|
|
838
838
|
exports.exists = exists2;
|
|
839
839
|
exports.FILE = 1;
|
|
@@ -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.53",
|
|
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: {
|
|
@@ -1758,8 +1596,8 @@ var ToolContentBuilder = class {
|
|
|
1758
1596
|
this.items.push({ type: "content", content: image(data, mimeType, uri) });
|
|
1759
1597
|
return this;
|
|
1760
1598
|
}
|
|
1761
|
-
diff(
|
|
1762
|
-
this.items.push({ type: "diff", path:
|
|
1599
|
+
diff(path8, oldText, newText) {
|
|
1600
|
+
this.items.push({ type: "diff", path: path8, oldText, newText });
|
|
1763
1601
|
return this;
|
|
1764
1602
|
}
|
|
1765
1603
|
build() {
|
|
@@ -1949,13 +1787,13 @@ function toolInfoFromToolUse(toolUse, cachedFileContent, logger = new Logger({ d
|
|
|
1949
1787
|
locations: []
|
|
1950
1788
|
};
|
|
1951
1789
|
case "Edit": {
|
|
1952
|
-
const
|
|
1790
|
+
const path8 = input?.file_path ? String(input.file_path) : void 0;
|
|
1953
1791
|
let oldText = input?.old_string ? String(input.old_string) : null;
|
|
1954
1792
|
let newText = input?.new_string ? String(input.new_string) : "";
|
|
1955
1793
|
let affectedLines = [];
|
|
1956
|
-
if (
|
|
1794
|
+
if (path8 && oldText) {
|
|
1957
1795
|
try {
|
|
1958
|
-
const oldContent = cachedFileContent[
|
|
1796
|
+
const oldContent = cachedFileContent[path8] || "";
|
|
1959
1797
|
const newContent = replaceAndCalculateLocation(oldContent, [
|
|
1960
1798
|
{
|
|
1961
1799
|
oldText,
|
|
@@ -1971,17 +1809,17 @@ function toolInfoFromToolUse(toolUse, cachedFileContent, logger = new Logger({ d
|
|
|
1971
1809
|
}
|
|
1972
1810
|
}
|
|
1973
1811
|
return {
|
|
1974
|
-
title:
|
|
1812
|
+
title: path8 ? `Edit \`${path8}\`` : "Edit",
|
|
1975
1813
|
kind: "edit",
|
|
1976
|
-
content: input &&
|
|
1814
|
+
content: input && path8 ? [
|
|
1977
1815
|
{
|
|
1978
1816
|
type: "diff",
|
|
1979
|
-
path:
|
|
1817
|
+
path: path8,
|
|
1980
1818
|
oldText,
|
|
1981
1819
|
newText
|
|
1982
1820
|
}
|
|
1983
1821
|
] : [],
|
|
1984
|
-
locations:
|
|
1822
|
+
locations: path8 ? affectedLines.length > 0 ? affectedLines.map((line) => ({ line, path: path8 })) : [{ path: path8 }] : []
|
|
1985
1823
|
};
|
|
1986
1824
|
}
|
|
1987
1825
|
case "Write": {
|
|
@@ -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);
|
|
@@ -4517,6 +4313,8 @@ var PostHogAPIClient = class {
|
|
|
4517
4313
|
};
|
|
4518
4314
|
|
|
4519
4315
|
// src/session-log-writer.ts
|
|
4316
|
+
import fs3 from "fs";
|
|
4317
|
+
import path4 from "path";
|
|
4520
4318
|
var SessionLogWriter = class _SessionLogWriter {
|
|
4521
4319
|
static FLUSH_DEBOUNCE_MS = 500;
|
|
4522
4320
|
static FLUSH_MAX_INTERVAL_MS = 5e3;
|
|
@@ -4530,8 +4328,10 @@ var SessionLogWriter = class _SessionLogWriter {
|
|
|
4530
4328
|
sessions = /* @__PURE__ */ new Map();
|
|
4531
4329
|
messageCounts = /* @__PURE__ */ new Map();
|
|
4532
4330
|
logger;
|
|
4331
|
+
localCachePath;
|
|
4533
4332
|
constructor(options = {}) {
|
|
4534
4333
|
this.posthogAPI = options.posthogAPI;
|
|
4334
|
+
this.localCachePath = options.localCachePath;
|
|
4535
4335
|
this.logger = options.logger ?? new Logger({ debug: false, prefix: "[SessionLogWriter]" });
|
|
4536
4336
|
}
|
|
4537
4337
|
async flushAll() {
|
|
@@ -4561,6 +4361,21 @@ var SessionLogWriter = class _SessionLogWriter {
|
|
|
4561
4361
|
});
|
|
4562
4362
|
this.sessions.set(sessionId, { context });
|
|
4563
4363
|
this.lastFlushAttemptTime.set(sessionId, Date.now());
|
|
4364
|
+
if (this.localCachePath) {
|
|
4365
|
+
const sessionDir = path4.join(
|
|
4366
|
+
this.localCachePath,
|
|
4367
|
+
"sessions",
|
|
4368
|
+
context.runId
|
|
4369
|
+
);
|
|
4370
|
+
try {
|
|
4371
|
+
fs3.mkdirSync(sessionDir, { recursive: true });
|
|
4372
|
+
} catch (error) {
|
|
4373
|
+
this.logger.warn("Failed to create local cache directory", {
|
|
4374
|
+
sessionDir,
|
|
4375
|
+
error
|
|
4376
|
+
});
|
|
4377
|
+
}
|
|
4378
|
+
}
|
|
4564
4379
|
}
|
|
4565
4380
|
isRegistered(sessionId) {
|
|
4566
4381
|
return this.sessions.has(sessionId);
|
|
@@ -4598,6 +4413,7 @@ var SessionLogWriter = class _SessionLogWriter {
|
|
|
4598
4413
|
timestamp,
|
|
4599
4414
|
notification: message
|
|
4600
4415
|
};
|
|
4416
|
+
this.writeToLocalCache(sessionId, entry);
|
|
4601
4417
|
if (this.posthogAPI) {
|
|
4602
4418
|
const pending = this.pendingEntries.get(sessionId) ?? [];
|
|
4603
4419
|
pending.push(entry);
|
|
@@ -4698,6 +4514,7 @@ var SessionLogWriter = class _SessionLogWriter {
|
|
|
4698
4514
|
}
|
|
4699
4515
|
}
|
|
4700
4516
|
};
|
|
4517
|
+
this.writeToLocalCache(sessionId, entry);
|
|
4701
4518
|
if (this.posthogAPI) {
|
|
4702
4519
|
const pending = this.pendingEntries.get(sessionId) ?? [];
|
|
4703
4520
|
pending.push(entry);
|
|
@@ -4725,6 +4542,23 @@ var SessionLogWriter = class _SessionLogWriter {
|
|
|
4725
4542
|
const timeout = setTimeout(() => this.flush(sessionId), delay2);
|
|
4726
4543
|
this.flushTimeouts.set(sessionId, timeout);
|
|
4727
4544
|
}
|
|
4545
|
+
writeToLocalCache(sessionId, entry) {
|
|
4546
|
+
if (!this.localCachePath) return;
|
|
4547
|
+
const session = this.sessions.get(sessionId);
|
|
4548
|
+
if (!session) return;
|
|
4549
|
+
const logPath = path4.join(
|
|
4550
|
+
this.localCachePath,
|
|
4551
|
+
"sessions",
|
|
4552
|
+
session.context.runId,
|
|
4553
|
+
"logs.ndjson"
|
|
4554
|
+
);
|
|
4555
|
+
try {
|
|
4556
|
+
fs3.appendFileSync(logPath, `${JSON.stringify(entry)}
|
|
4557
|
+
`);
|
|
4558
|
+
} catch (error) {
|
|
4559
|
+
this.logger.warn("Failed to write to local cache", { logPath, error });
|
|
4560
|
+
}
|
|
4561
|
+
}
|
|
4728
4562
|
};
|
|
4729
4563
|
|
|
4730
4564
|
// src/agent.ts
|
|
@@ -4748,7 +4582,8 @@ var Agent = class {
|
|
|
4748
4582
|
if (config.posthog && !config.skipLogPersistence) {
|
|
4749
4583
|
this.sessionLogWriter = new SessionLogWriter({
|
|
4750
4584
|
posthogAPI: this.posthogAPI,
|
|
4751
|
-
logger: this.logger.child("SessionLogWriter")
|
|
4585
|
+
logger: this.logger.child("SessionLogWriter"),
|
|
4586
|
+
localCachePath: config.localCachePath
|
|
4752
4587
|
});
|
|
4753
4588
|
}
|
|
4754
4589
|
}
|
|
@@ -4802,7 +4637,6 @@ var Agent = class {
|
|
|
4802
4637
|
taskId,
|
|
4803
4638
|
deviceType: "local",
|
|
4804
4639
|
logger: this.logger,
|
|
4805
|
-
debug: this.debug,
|
|
4806
4640
|
processCallbacks: options.processCallbacks,
|
|
4807
4641
|
allowedModelIds,
|
|
4808
4642
|
codexOptions: options.adapter === "codex" && gatewayConfig ? {
|
|
@@ -4903,9 +4737,136 @@ var OtelLogWriter = class {
|
|
|
4903
4737
|
}
|
|
4904
4738
|
};
|
|
4905
4739
|
|
|
4740
|
+
// ../shared/dist/index.js
|
|
4741
|
+
var consoleLogger = {
|
|
4742
|
+
info: (_message, _data) => {
|
|
4743
|
+
},
|
|
4744
|
+
debug: (_message, _data) => {
|
|
4745
|
+
},
|
|
4746
|
+
error: (_message, _data) => {
|
|
4747
|
+
},
|
|
4748
|
+
warn: (_message, _data) => {
|
|
4749
|
+
}
|
|
4750
|
+
};
|
|
4751
|
+
var Saga = class {
|
|
4752
|
+
completedSteps = [];
|
|
4753
|
+
currentStepName = "unknown";
|
|
4754
|
+
stepTimings = [];
|
|
4755
|
+
log;
|
|
4756
|
+
constructor(logger) {
|
|
4757
|
+
this.log = logger ?? consoleLogger;
|
|
4758
|
+
}
|
|
4759
|
+
/**
|
|
4760
|
+
* Run the saga with the given input.
|
|
4761
|
+
* Returns a discriminated union result - either success with data or failure with error details.
|
|
4762
|
+
*/
|
|
4763
|
+
async run(input) {
|
|
4764
|
+
this.completedSteps = [];
|
|
4765
|
+
this.currentStepName = "unknown";
|
|
4766
|
+
this.stepTimings = [];
|
|
4767
|
+
const sagaStart = performance.now();
|
|
4768
|
+
this.log.info("Starting saga", { sagaName: this.constructor.name });
|
|
4769
|
+
try {
|
|
4770
|
+
const result = await this.execute(input);
|
|
4771
|
+
const totalDuration = performance.now() - sagaStart;
|
|
4772
|
+
this.log.debug("Saga completed successfully", {
|
|
4773
|
+
sagaName: this.constructor.name,
|
|
4774
|
+
stepsCompleted: this.completedSteps.length,
|
|
4775
|
+
totalDurationMs: Math.round(totalDuration),
|
|
4776
|
+
stepTimings: this.stepTimings
|
|
4777
|
+
});
|
|
4778
|
+
return { success: true, data: result };
|
|
4779
|
+
} catch (error) {
|
|
4780
|
+
this.log.error("Saga failed, initiating rollback", {
|
|
4781
|
+
sagaName: this.constructor.name,
|
|
4782
|
+
failedStep: this.currentStepName,
|
|
4783
|
+
error: error instanceof Error ? error.message : String(error)
|
|
4784
|
+
});
|
|
4785
|
+
await this.rollback();
|
|
4786
|
+
return {
|
|
4787
|
+
success: false,
|
|
4788
|
+
error: error instanceof Error ? error.message : String(error),
|
|
4789
|
+
failedStep: this.currentStepName
|
|
4790
|
+
};
|
|
4791
|
+
}
|
|
4792
|
+
}
|
|
4793
|
+
/**
|
|
4794
|
+
* Execute a step with its rollback action.
|
|
4795
|
+
* If the step succeeds, its rollback action is stored for potential rollback.
|
|
4796
|
+
* The step name is automatically tracked for error reporting.
|
|
4797
|
+
*
|
|
4798
|
+
* @param config - Step configuration with name, execute, and rollback functions
|
|
4799
|
+
* @returns The result of the execute function
|
|
4800
|
+
* @throws Re-throws any error from the execute function (triggers rollback)
|
|
4801
|
+
*/
|
|
4802
|
+
async step(config) {
|
|
4803
|
+
this.currentStepName = config.name;
|
|
4804
|
+
this.log.debug(`Executing step: ${config.name}`);
|
|
4805
|
+
const stepStart = performance.now();
|
|
4806
|
+
const result = await config.execute();
|
|
4807
|
+
const durationMs = Math.round(performance.now() - stepStart);
|
|
4808
|
+
this.stepTimings.push({ name: config.name, durationMs });
|
|
4809
|
+
this.log.debug(`Step completed: ${config.name}`, { durationMs });
|
|
4810
|
+
this.completedSteps.push({
|
|
4811
|
+
name: config.name,
|
|
4812
|
+
rollback: () => config.rollback(result)
|
|
4813
|
+
});
|
|
4814
|
+
return result;
|
|
4815
|
+
}
|
|
4816
|
+
/**
|
|
4817
|
+
* Execute a step that doesn't need rollback.
|
|
4818
|
+
* Useful for read-only operations or operations that are idempotent.
|
|
4819
|
+
* The step name is automatically tracked for error reporting.
|
|
4820
|
+
*
|
|
4821
|
+
* @param name - Step name for logging and error tracking
|
|
4822
|
+
* @param execute - The action to execute
|
|
4823
|
+
* @returns The result of the execute function
|
|
4824
|
+
*/
|
|
4825
|
+
async readOnlyStep(name, execute) {
|
|
4826
|
+
this.currentStepName = name;
|
|
4827
|
+
this.log.debug(`Executing read-only step: ${name}`);
|
|
4828
|
+
const stepStart = performance.now();
|
|
4829
|
+
const result = await execute();
|
|
4830
|
+
const durationMs = Math.round(performance.now() - stepStart);
|
|
4831
|
+
this.stepTimings.push({ name, durationMs });
|
|
4832
|
+
this.log.debug(`Read-only step completed: ${name}`, { durationMs });
|
|
4833
|
+
return result;
|
|
4834
|
+
}
|
|
4835
|
+
/**
|
|
4836
|
+
* Roll back all completed steps in reverse order.
|
|
4837
|
+
* Rollback errors are logged but don't stop the rollback of other steps.
|
|
4838
|
+
*/
|
|
4839
|
+
async rollback() {
|
|
4840
|
+
this.log.info("Rolling back saga", {
|
|
4841
|
+
stepsToRollback: this.completedSteps.length
|
|
4842
|
+
});
|
|
4843
|
+
const stepsReversed = [...this.completedSteps].reverse();
|
|
4844
|
+
for (const step of stepsReversed) {
|
|
4845
|
+
try {
|
|
4846
|
+
this.log.debug(`Rolling back step: ${step.name}`);
|
|
4847
|
+
await step.rollback();
|
|
4848
|
+
this.log.debug(`Step rolled back: ${step.name}`);
|
|
4849
|
+
} catch (error) {
|
|
4850
|
+
this.log.error(`Failed to rollback step: ${step.name}`, {
|
|
4851
|
+
error: error instanceof Error ? error.message : String(error)
|
|
4852
|
+
});
|
|
4853
|
+
}
|
|
4854
|
+
}
|
|
4855
|
+
this.log.info("Rollback completed", {
|
|
4856
|
+
stepsAttempted: this.completedSteps.length
|
|
4857
|
+
});
|
|
4858
|
+
}
|
|
4859
|
+
/**
|
|
4860
|
+
* Get the number of completed steps (useful for testing)
|
|
4861
|
+
*/
|
|
4862
|
+
getCompletedStepCount() {
|
|
4863
|
+
return this.completedSteps.length;
|
|
4864
|
+
}
|
|
4865
|
+
};
|
|
4866
|
+
|
|
4906
4867
|
// ../git/dist/queries.js
|
|
4907
|
-
import * as
|
|
4908
|
-
import * as
|
|
4868
|
+
import * as fs5 from "fs/promises";
|
|
4869
|
+
import * as path6 from "path";
|
|
4909
4870
|
|
|
4910
4871
|
// ../../node_modules/simple-git/dist/esm/index.js
|
|
4911
4872
|
var import_file_exists = __toESM(require_dist(), 1);
|
|
@@ -4944,8 +4905,8 @@ function pathspec(...paths) {
|
|
|
4944
4905
|
cache.set(key, paths);
|
|
4945
4906
|
return key;
|
|
4946
4907
|
}
|
|
4947
|
-
function isPathSpec(
|
|
4948
|
-
return
|
|
4908
|
+
function isPathSpec(path8) {
|
|
4909
|
+
return path8 instanceof String && cache.has(path8);
|
|
4949
4910
|
}
|
|
4950
4911
|
function toPaths(pathSpec) {
|
|
4951
4912
|
return cache.get(pathSpec) || [];
|
|
@@ -5034,8 +4995,8 @@ function toLinesWithContent(input = "", trimmed2 = true, separator = "\n") {
|
|
|
5034
4995
|
function forEachLineWithContent(input, callback) {
|
|
5035
4996
|
return toLinesWithContent(input, true).map((line) => callback(line));
|
|
5036
4997
|
}
|
|
5037
|
-
function folderExists(
|
|
5038
|
-
return (0, import_file_exists.exists)(
|
|
4998
|
+
function folderExists(path8) {
|
|
4999
|
+
return (0, import_file_exists.exists)(path8, import_file_exists.FOLDER);
|
|
5039
5000
|
}
|
|
5040
5001
|
function append(target, item) {
|
|
5041
5002
|
if (Array.isArray(target)) {
|
|
@@ -5439,8 +5400,8 @@ function checkIsRepoRootTask() {
|
|
|
5439
5400
|
commands,
|
|
5440
5401
|
format: "utf-8",
|
|
5441
5402
|
onError,
|
|
5442
|
-
parser(
|
|
5443
|
-
return /^\.(git)?$/.test(
|
|
5403
|
+
parser(path8) {
|
|
5404
|
+
return /^\.(git)?$/.test(path8.trim());
|
|
5444
5405
|
}
|
|
5445
5406
|
};
|
|
5446
5407
|
}
|
|
@@ -5874,11 +5835,11 @@ function parseGrep(grep) {
|
|
|
5874
5835
|
const paths = /* @__PURE__ */ new Set();
|
|
5875
5836
|
const results = {};
|
|
5876
5837
|
forEachLineWithContent(grep, (input) => {
|
|
5877
|
-
const [
|
|
5878
|
-
paths.add(
|
|
5879
|
-
(results[
|
|
5838
|
+
const [path8, line, preview] = input.split(NULL);
|
|
5839
|
+
paths.add(path8);
|
|
5840
|
+
(results[path8] = results[path8] || []).push({
|
|
5880
5841
|
line: asNumber(line),
|
|
5881
|
-
path:
|
|
5842
|
+
path: path8,
|
|
5882
5843
|
preview
|
|
5883
5844
|
});
|
|
5884
5845
|
});
|
|
@@ -6643,14 +6604,14 @@ var init_hash_object = __esm({
|
|
|
6643
6604
|
init_task();
|
|
6644
6605
|
}
|
|
6645
6606
|
});
|
|
6646
|
-
function parseInit(bare,
|
|
6607
|
+
function parseInit(bare, path8, text2) {
|
|
6647
6608
|
const response = String(text2).trim();
|
|
6648
6609
|
let result;
|
|
6649
6610
|
if (result = initResponseRegex.exec(response)) {
|
|
6650
|
-
return new InitSummary(bare,
|
|
6611
|
+
return new InitSummary(bare, path8, false, result[1]);
|
|
6651
6612
|
}
|
|
6652
6613
|
if (result = reInitResponseRegex.exec(response)) {
|
|
6653
|
-
return new InitSummary(bare,
|
|
6614
|
+
return new InitSummary(bare, path8, true, result[1]);
|
|
6654
6615
|
}
|
|
6655
6616
|
let gitDir = "";
|
|
6656
6617
|
const tokens = response.split(" ");
|
|
@@ -6661,7 +6622,7 @@ function parseInit(bare, path7, text2) {
|
|
|
6661
6622
|
break;
|
|
6662
6623
|
}
|
|
6663
6624
|
}
|
|
6664
|
-
return new InitSummary(bare,
|
|
6625
|
+
return new InitSummary(bare, path8, /^re/i.test(response), gitDir);
|
|
6665
6626
|
}
|
|
6666
6627
|
var InitSummary;
|
|
6667
6628
|
var initResponseRegex;
|
|
@@ -6670,9 +6631,9 @@ var init_InitSummary = __esm({
|
|
|
6670
6631
|
"src/lib/responses/InitSummary.ts"() {
|
|
6671
6632
|
"use strict";
|
|
6672
6633
|
InitSummary = class {
|
|
6673
|
-
constructor(bare,
|
|
6634
|
+
constructor(bare, path8, existing, gitDir) {
|
|
6674
6635
|
this.bare = bare;
|
|
6675
|
-
this.path =
|
|
6636
|
+
this.path = path8;
|
|
6676
6637
|
this.existing = existing;
|
|
6677
6638
|
this.gitDir = gitDir;
|
|
6678
6639
|
}
|
|
@@ -6684,7 +6645,7 @@ var init_InitSummary = __esm({
|
|
|
6684
6645
|
function hasBareCommand(command) {
|
|
6685
6646
|
return command.includes(bareCommand);
|
|
6686
6647
|
}
|
|
6687
|
-
function initTask(bare = false,
|
|
6648
|
+
function initTask(bare = false, path8, customArgs) {
|
|
6688
6649
|
const commands = ["init", ...customArgs];
|
|
6689
6650
|
if (bare && !hasBareCommand(commands)) {
|
|
6690
6651
|
commands.splice(1, 0, bareCommand);
|
|
@@ -6693,7 +6654,7 @@ function initTask(bare = false, path7, customArgs) {
|
|
|
6693
6654
|
commands,
|
|
6694
6655
|
format: "utf-8",
|
|
6695
6656
|
parser(text2) {
|
|
6696
|
-
return parseInit(commands.includes("--bare"),
|
|
6657
|
+
return parseInit(commands.includes("--bare"), path8, text2);
|
|
6697
6658
|
}
|
|
6698
6659
|
};
|
|
6699
6660
|
}
|
|
@@ -7509,12 +7470,12 @@ var init_FileStatusSummary = __esm({
|
|
|
7509
7470
|
"use strict";
|
|
7510
7471
|
fromPathRegex = /^(.+)\0(.+)$/;
|
|
7511
7472
|
FileStatusSummary = class {
|
|
7512
|
-
constructor(
|
|
7513
|
-
this.path =
|
|
7473
|
+
constructor(path8, index, working_dir) {
|
|
7474
|
+
this.path = path8;
|
|
7514
7475
|
this.index = index;
|
|
7515
7476
|
this.working_dir = working_dir;
|
|
7516
7477
|
if (index === "R" || working_dir === "R") {
|
|
7517
|
-
const detail = fromPathRegex.exec(
|
|
7478
|
+
const detail = fromPathRegex.exec(path8) || [null, path8, path8];
|
|
7518
7479
|
this.from = detail[2] || "";
|
|
7519
7480
|
this.path = detail[1] || "";
|
|
7520
7481
|
}
|
|
@@ -7545,14 +7506,14 @@ function splitLine(result, lineStr) {
|
|
|
7545
7506
|
default:
|
|
7546
7507
|
return;
|
|
7547
7508
|
}
|
|
7548
|
-
function data(index, workingDir,
|
|
7509
|
+
function data(index, workingDir, path8) {
|
|
7549
7510
|
const raw = `${index}${workingDir}`;
|
|
7550
7511
|
const handler = parsers6.get(raw);
|
|
7551
7512
|
if (handler) {
|
|
7552
|
-
handler(result,
|
|
7513
|
+
handler(result, path8);
|
|
7553
7514
|
}
|
|
7554
7515
|
if (raw !== "##" && raw !== "!!") {
|
|
7555
|
-
result.files.push(new FileStatusSummary(
|
|
7516
|
+
result.files.push(new FileStatusSummary(path8, index, workingDir));
|
|
7556
7517
|
}
|
|
7557
7518
|
}
|
|
7558
7519
|
}
|
|
@@ -7865,9 +7826,9 @@ var init_simple_git_api = __esm({
|
|
|
7865
7826
|
next
|
|
7866
7827
|
);
|
|
7867
7828
|
}
|
|
7868
|
-
hashObject(
|
|
7829
|
+
hashObject(path8, write) {
|
|
7869
7830
|
return this._runTask(
|
|
7870
|
-
hashObjectTask(
|
|
7831
|
+
hashObjectTask(path8, write === true),
|
|
7871
7832
|
trailingFunctionArgument(arguments)
|
|
7872
7833
|
);
|
|
7873
7834
|
}
|
|
@@ -8220,8 +8181,8 @@ var init_branch = __esm({
|
|
|
8220
8181
|
}
|
|
8221
8182
|
});
|
|
8222
8183
|
function toPath(input) {
|
|
8223
|
-
const
|
|
8224
|
-
return
|
|
8184
|
+
const path8 = input.trim().replace(/^["']|["']$/g, "");
|
|
8185
|
+
return path8 && normalize(path8);
|
|
8225
8186
|
}
|
|
8226
8187
|
var parseCheckIgnore;
|
|
8227
8188
|
var init_CheckIgnore = __esm({
|
|
@@ -8535,8 +8496,8 @@ __export(sub_module_exports, {
|
|
|
8535
8496
|
subModuleTask: () => subModuleTask,
|
|
8536
8497
|
updateSubModuleTask: () => updateSubModuleTask
|
|
8537
8498
|
});
|
|
8538
|
-
function addSubModuleTask(repo,
|
|
8539
|
-
return subModuleTask(["add", repo,
|
|
8499
|
+
function addSubModuleTask(repo, path8) {
|
|
8500
|
+
return subModuleTask(["add", repo, path8]);
|
|
8540
8501
|
}
|
|
8541
8502
|
function initSubModuleTask(customArgs) {
|
|
8542
8503
|
return subModuleTask(["init", ...customArgs]);
|
|
@@ -8866,8 +8827,8 @@ var require_git = __commonJS2({
|
|
|
8866
8827
|
}
|
|
8867
8828
|
return this._runTask(straightThroughStringTask2(command, this._trimmed), next);
|
|
8868
8829
|
};
|
|
8869
|
-
Git2.prototype.submoduleAdd = function(repo,
|
|
8870
|
-
return this._runTask(addSubModuleTask2(repo,
|
|
8830
|
+
Git2.prototype.submoduleAdd = function(repo, path8, then) {
|
|
8831
|
+
return this._runTask(addSubModuleTask2(repo, path8), trailingFunctionArgument2(arguments));
|
|
8871
8832
|
};
|
|
8872
8833
|
Git2.prototype.submoduleUpdate = function(args, then) {
|
|
8873
8834
|
return this._runTask(
|
|
@@ -9468,22 +9429,22 @@ function createGitClient(baseDir, options) {
|
|
|
9468
9429
|
|
|
9469
9430
|
// ../git/dist/lock-detector.js
|
|
9470
9431
|
import { execFile } from "child_process";
|
|
9471
|
-
import
|
|
9472
|
-
import
|
|
9432
|
+
import fs4 from "fs/promises";
|
|
9433
|
+
import path5 from "path";
|
|
9473
9434
|
import { promisify } from "util";
|
|
9474
9435
|
var execFileAsync = promisify(execFile);
|
|
9475
9436
|
async function getIndexLockPath(repoPath) {
|
|
9476
9437
|
try {
|
|
9477
9438
|
const { stdout } = await execFileAsync("git", ["rev-parse", "--git-path", "index.lock"], { cwd: repoPath });
|
|
9478
|
-
return
|
|
9439
|
+
return path5.resolve(repoPath, stdout.trim());
|
|
9479
9440
|
} catch {
|
|
9480
|
-
return
|
|
9441
|
+
return path5.join(repoPath, ".git", "index.lock");
|
|
9481
9442
|
}
|
|
9482
9443
|
}
|
|
9483
9444
|
async function getLockInfo(repoPath) {
|
|
9484
9445
|
const lockPath = await getIndexLockPath(repoPath);
|
|
9485
9446
|
try {
|
|
9486
|
-
const stat = await
|
|
9447
|
+
const stat = await fs4.stat(lockPath);
|
|
9487
9448
|
return {
|
|
9488
9449
|
path: lockPath,
|
|
9489
9450
|
ageMs: Date.now() - stat.mtimeMs
|
|
@@ -9494,7 +9455,7 @@ async function getLockInfo(repoPath) {
|
|
|
9494
9455
|
}
|
|
9495
9456
|
async function removeLock(repoPath) {
|
|
9496
9457
|
const lockPath = await getIndexLockPath(repoPath);
|
|
9497
|
-
await
|
|
9458
|
+
await fs4.rm(lockPath, { force: true });
|
|
9498
9459
|
}
|
|
9499
9460
|
async function isLocked(repoPath) {
|
|
9500
9461
|
return await getLockInfo(repoPath) !== null;
|
|
@@ -9674,8 +9635,8 @@ import { join as join5 } from "path";
|
|
|
9674
9635
|
|
|
9675
9636
|
// ../git/dist/sagas/tree.js
|
|
9676
9637
|
import { existsSync as existsSync4 } from "fs";
|
|
9677
|
-
import * as
|
|
9678
|
-
import * as
|
|
9638
|
+
import * as fs6 from "fs/promises";
|
|
9639
|
+
import * as path7 from "path";
|
|
9679
9640
|
import * as tar from "tar";
|
|
9680
9641
|
|
|
9681
9642
|
// ../git/dist/git-saga.js
|
|
@@ -9701,14 +9662,14 @@ var CaptureTreeSaga = class extends GitSaga {
|
|
|
9701
9662
|
tempIndexPath = null;
|
|
9702
9663
|
async executeGitOperations(input) {
|
|
9703
9664
|
const { baseDir, lastTreeHash, archivePath, signal } = input;
|
|
9704
|
-
const tmpDir =
|
|
9665
|
+
const tmpDir = path7.join(baseDir, ".git", "twig-tmp");
|
|
9705
9666
|
await this.step({
|
|
9706
9667
|
name: "create_tmp_dir",
|
|
9707
|
-
execute: () =>
|
|
9668
|
+
execute: () => fs6.mkdir(tmpDir, { recursive: true }),
|
|
9708
9669
|
rollback: async () => {
|
|
9709
9670
|
}
|
|
9710
9671
|
});
|
|
9711
|
-
this.tempIndexPath =
|
|
9672
|
+
this.tempIndexPath = path7.join(tmpDir, `index-${Date.now()}`);
|
|
9712
9673
|
const tempIndexGit = this.git.env({
|
|
9713
9674
|
...process.env,
|
|
9714
9675
|
GIT_INDEX_FILE: this.tempIndexPath
|
|
@@ -9718,7 +9679,7 @@ var CaptureTreeSaga = class extends GitSaga {
|
|
|
9718
9679
|
execute: () => tempIndexGit.raw(["read-tree", "HEAD"]),
|
|
9719
9680
|
rollback: async () => {
|
|
9720
9681
|
if (this.tempIndexPath) {
|
|
9721
|
-
await
|
|
9682
|
+
await fs6.rm(this.tempIndexPath, { force: true }).catch(() => {
|
|
9722
9683
|
});
|
|
9723
9684
|
}
|
|
9724
9685
|
}
|
|
@@ -9727,7 +9688,7 @@ var CaptureTreeSaga = class extends GitSaga {
|
|
|
9727
9688
|
const treeHash = await this.readOnlyStep("write_tree", () => tempIndexGit.raw(["write-tree"]));
|
|
9728
9689
|
if (lastTreeHash && treeHash === lastTreeHash) {
|
|
9729
9690
|
this.log.debug("No changes since last capture", { treeHash });
|
|
9730
|
-
await
|
|
9691
|
+
await fs6.rm(this.tempIndexPath, { force: true }).catch(() => {
|
|
9731
9692
|
});
|
|
9732
9693
|
return { snapshot: null, changed: false };
|
|
9733
9694
|
}
|
|
@@ -9739,7 +9700,7 @@ var CaptureTreeSaga = class extends GitSaga {
|
|
|
9739
9700
|
}
|
|
9740
9701
|
});
|
|
9741
9702
|
const changes = await this.readOnlyStep("get_changes", () => this.getChanges(this.git, baseCommit, treeHash));
|
|
9742
|
-
await
|
|
9703
|
+
await fs6.rm(this.tempIndexPath, { force: true }).catch(() => {
|
|
9743
9704
|
});
|
|
9744
9705
|
const snapshot = {
|
|
9745
9706
|
treeHash,
|
|
@@ -9763,15 +9724,15 @@ var CaptureTreeSaga = class extends GitSaga {
|
|
|
9763
9724
|
if (filesToArchive.length === 0) {
|
|
9764
9725
|
return void 0;
|
|
9765
9726
|
}
|
|
9766
|
-
const existingFiles = filesToArchive.filter((f) => existsSync4(
|
|
9727
|
+
const existingFiles = filesToArchive.filter((f) => existsSync4(path7.join(baseDir, f)));
|
|
9767
9728
|
if (existingFiles.length === 0) {
|
|
9768
9729
|
return void 0;
|
|
9769
9730
|
}
|
|
9770
9731
|
await this.step({
|
|
9771
9732
|
name: "create_archive",
|
|
9772
9733
|
execute: async () => {
|
|
9773
|
-
const archiveDir =
|
|
9774
|
-
await
|
|
9734
|
+
const archiveDir = path7.dirname(archivePath);
|
|
9735
|
+
await fs6.mkdir(archiveDir, { recursive: true });
|
|
9775
9736
|
await tar.create({
|
|
9776
9737
|
gzip: true,
|
|
9777
9738
|
file: archivePath,
|
|
@@ -9779,7 +9740,7 @@ var CaptureTreeSaga = class extends GitSaga {
|
|
|
9779
9740
|
}, existingFiles);
|
|
9780
9741
|
},
|
|
9781
9742
|
rollback: async () => {
|
|
9782
|
-
await
|
|
9743
|
+
await fs6.rm(archivePath, { force: true }).catch(() => {
|
|
9783
9744
|
});
|
|
9784
9745
|
}
|
|
9785
9746
|
});
|
|
@@ -9878,9 +9839,9 @@ var ApplyTreeSaga = class extends GitSaga {
|
|
|
9878
9839
|
const filesToExtract = changes.filter((c) => c.status !== "D").map((c) => c.path);
|
|
9879
9840
|
await this.readOnlyStep("backup_existing_files", async () => {
|
|
9880
9841
|
for (const filePath of filesToExtract) {
|
|
9881
|
-
const fullPath =
|
|
9842
|
+
const fullPath = path7.join(baseDir, filePath);
|
|
9882
9843
|
try {
|
|
9883
|
-
const content = await
|
|
9844
|
+
const content = await fs6.readFile(fullPath);
|
|
9884
9845
|
this.fileBackups.set(filePath, content);
|
|
9885
9846
|
} catch {
|
|
9886
9847
|
}
|
|
@@ -9897,16 +9858,16 @@ var ApplyTreeSaga = class extends GitSaga {
|
|
|
9897
9858
|
},
|
|
9898
9859
|
rollback: async () => {
|
|
9899
9860
|
for (const filePath of this.extractedFiles) {
|
|
9900
|
-
const fullPath =
|
|
9861
|
+
const fullPath = path7.join(baseDir, filePath);
|
|
9901
9862
|
const backup = this.fileBackups.get(filePath);
|
|
9902
9863
|
if (backup) {
|
|
9903
|
-
const dir =
|
|
9904
|
-
await
|
|
9864
|
+
const dir = path7.dirname(fullPath);
|
|
9865
|
+
await fs6.mkdir(dir, { recursive: true }).catch(() => {
|
|
9905
9866
|
});
|
|
9906
|
-
await
|
|
9867
|
+
await fs6.writeFile(fullPath, backup).catch(() => {
|
|
9907
9868
|
});
|
|
9908
9869
|
} else {
|
|
9909
|
-
await
|
|
9870
|
+
await fs6.rm(fullPath, { force: true }).catch(() => {
|
|
9910
9871
|
});
|
|
9911
9872
|
}
|
|
9912
9873
|
}
|
|
@@ -9914,10 +9875,10 @@ var ApplyTreeSaga = class extends GitSaga {
|
|
|
9914
9875
|
});
|
|
9915
9876
|
}
|
|
9916
9877
|
for (const change of changes.filter((c) => c.status === "D")) {
|
|
9917
|
-
const fullPath =
|
|
9878
|
+
const fullPath = path7.join(baseDir, change.path);
|
|
9918
9879
|
const backupContent = await this.readOnlyStep(`backup_${change.path}`, async () => {
|
|
9919
9880
|
try {
|
|
9920
|
-
return await
|
|
9881
|
+
return await fs6.readFile(fullPath);
|
|
9921
9882
|
} catch {
|
|
9922
9883
|
return null;
|
|
9923
9884
|
}
|
|
@@ -9925,15 +9886,15 @@ var ApplyTreeSaga = class extends GitSaga {
|
|
|
9925
9886
|
await this.step({
|
|
9926
9887
|
name: `delete_${change.path}`,
|
|
9927
9888
|
execute: async () => {
|
|
9928
|
-
await
|
|
9889
|
+
await fs6.rm(fullPath, { force: true });
|
|
9929
9890
|
this.log.debug(`Deleted file: ${change.path}`);
|
|
9930
9891
|
},
|
|
9931
9892
|
rollback: async () => {
|
|
9932
9893
|
if (backupContent) {
|
|
9933
|
-
const dir =
|
|
9934
|
-
await
|
|
9894
|
+
const dir = path7.dirname(fullPath);
|
|
9895
|
+
await fs6.mkdir(dir, { recursive: true }).catch(() => {
|
|
9935
9896
|
});
|
|
9936
|
-
await
|
|
9897
|
+
await fs6.writeFile(fullPath, backupContent).catch(() => {
|
|
9937
9898
|
});
|
|
9938
9899
|
}
|
|
9939
9900
|
}
|