@posthog/agent 2.3.510 → 2.3.517
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.js +131 -104
- package/dist/agent.js.map +1 -1
- package/dist/handoff-checkpoint.js +212 -18
- package/dist/handoff-checkpoint.js.map +1 -1
- package/dist/posthog-api.js +1 -1
- package/dist/posthog-api.js.map +1 -1
- package/dist/server/agent-server.d.ts +2 -1
- package/dist/server/agent-server.js +409 -160
- package/dist/server/agent-server.js.map +1 -1
- package/dist/server/bin.cjs +389 -141
- package/dist/server/bin.cjs.map +1 -1
- package/package.json +3 -3
- package/src/adapters/claude/session/mcp-config.test.ts +112 -0
- package/src/adapters/claude/session/mcp-config.ts +45 -0
- package/src/adapters/claude/session/options.ts +4 -0
- package/src/server/agent-server.test.ts +59 -1
- package/src/server/agent-server.ts +54 -20
|
@@ -5955,6 +5955,7 @@ async function getGitBusyState(git) {
|
|
|
5955
5955
|
}
|
|
5956
5956
|
return { busy: false };
|
|
5957
5957
|
}
|
|
5958
|
+
var MAX_WORKTREE_FILE_BYTES = 1024 * 1024;
|
|
5958
5959
|
async function createWorktreeTree(git, baseDir, head) {
|
|
5959
5960
|
const { tempGit, tempIndexPath } = await createTempIndexGit(git, baseDir, "checkpoint-worktree");
|
|
5960
5961
|
try {
|
|
@@ -5964,6 +5965,7 @@ async function createWorktreeTree(git, baseDir, head) {
|
|
|
5964
5965
|
await tempGit.raw(["read-tree", "--empty"]);
|
|
5965
5966
|
}
|
|
5966
5967
|
await tempGit.raw(["add", "-A", "--", "."]);
|
|
5968
|
+
await reconcileLargeBlobs(tempGit, head, MAX_WORKTREE_FILE_BYTES);
|
|
5967
5969
|
const treeHash = await tempGit.raw(["write-tree"]);
|
|
5968
5970
|
return treeHash.trim();
|
|
5969
5971
|
} finally {
|
|
@@ -5971,6 +5973,77 @@ async function createWorktreeTree(git, baseDir, head) {
|
|
|
5971
5973
|
});
|
|
5972
5974
|
}
|
|
5973
5975
|
}
|
|
5976
|
+
async function reconcileLargeBlobs(tempGit, head, maxBytes) {
|
|
5977
|
+
const intermediateTree = (await tempGit.raw(["write-tree"])).trim();
|
|
5978
|
+
const largePaths = await listLargeBlobPaths(tempGit, intermediateTree, maxBytes);
|
|
5979
|
+
if (largePaths.length === 0)
|
|
5980
|
+
return;
|
|
5981
|
+
const headEntries = head ? await readHeadBlobEntries(tempGit, head, largePaths) : /* @__PURE__ */ new Map();
|
|
5982
|
+
for (const filePath of largePaths) {
|
|
5983
|
+
const headEntry = headEntries.get(filePath);
|
|
5984
|
+
if (headEntry) {
|
|
5985
|
+
await tempGit.raw([
|
|
5986
|
+
"update-index",
|
|
5987
|
+
"--cacheinfo",
|
|
5988
|
+
`${headEntry.mode},${headEntry.hash},${filePath}`
|
|
5989
|
+
]);
|
|
5990
|
+
} else {
|
|
5991
|
+
await tempGit.raw(["update-index", "--force-remove", filePath]).catch(() => {
|
|
5992
|
+
});
|
|
5993
|
+
}
|
|
5994
|
+
}
|
|
5995
|
+
}
|
|
5996
|
+
async function listLargeBlobPaths(tempGit, tree, maxBytes) {
|
|
5997
|
+
const output = await tempGit.raw(["ls-tree", "-r", "-l", tree]);
|
|
5998
|
+
const result = [];
|
|
5999
|
+
for (const line of output.split("\n")) {
|
|
6000
|
+
if (!line)
|
|
6001
|
+
continue;
|
|
6002
|
+
const tabIndex = line.indexOf(" ");
|
|
6003
|
+
if (tabIndex < 0)
|
|
6004
|
+
continue;
|
|
6005
|
+
const meta = line.slice(0, tabIndex);
|
|
6006
|
+
const filePath = line.slice(tabIndex + 1);
|
|
6007
|
+
const parts = meta.split(/\s+/);
|
|
6008
|
+
if (parts.length < 4)
|
|
6009
|
+
continue;
|
|
6010
|
+
const [, type, , sizeStr] = parts;
|
|
6011
|
+
if (type !== "blob")
|
|
6012
|
+
continue;
|
|
6013
|
+
if (sizeStr === "-")
|
|
6014
|
+
continue;
|
|
6015
|
+
const size = Number.parseInt(sizeStr, 10);
|
|
6016
|
+
if (Number.isFinite(size) && size > maxBytes) {
|
|
6017
|
+
result.push(filePath);
|
|
6018
|
+
}
|
|
6019
|
+
}
|
|
6020
|
+
return result;
|
|
6021
|
+
}
|
|
6022
|
+
async function readHeadBlobEntries(tempGit, head, paths) {
|
|
6023
|
+
const result = /* @__PURE__ */ new Map();
|
|
6024
|
+
const CHUNK_SIZE = 100;
|
|
6025
|
+
for (let i = 0; i < paths.length; i += CHUNK_SIZE) {
|
|
6026
|
+
const chunk = paths.slice(i, i + CHUNK_SIZE);
|
|
6027
|
+
const output = await tempGit.raw(["ls-tree", "-r", head, "--", ...chunk]).catch(() => "");
|
|
6028
|
+
for (const line of output.split("\n")) {
|
|
6029
|
+
if (!line)
|
|
6030
|
+
continue;
|
|
6031
|
+
const tabIndex = line.indexOf(" ");
|
|
6032
|
+
if (tabIndex < 0)
|
|
6033
|
+
continue;
|
|
6034
|
+
const meta = line.slice(0, tabIndex);
|
|
6035
|
+
const filePath = line.slice(tabIndex + 1);
|
|
6036
|
+
const parts = meta.split(/\s+/);
|
|
6037
|
+
if (parts.length < 3)
|
|
6038
|
+
continue;
|
|
6039
|
+
const [mode, type, hash] = parts;
|
|
6040
|
+
if (type !== "blob")
|
|
6041
|
+
continue;
|
|
6042
|
+
result.set(filePath, { mode, hash });
|
|
6043
|
+
}
|
|
6044
|
+
}
|
|
6045
|
+
return result;
|
|
6046
|
+
}
|
|
5974
6047
|
async function createMetaTree(git, baseDir, indexTree, worktreeTree) {
|
|
5975
6048
|
const { tempGit, tempIndexPath } = await createTempIndexGit(git, baseDir, "checkpoint-meta");
|
|
5976
6049
|
try {
|
|
@@ -6043,6 +6116,7 @@ async function deleteCheckpoint(git, checkpointId) {
|
|
|
6043
6116
|
// ../git/dist/handoff.js
|
|
6044
6117
|
var HANDOFF_HEAD_REF_PREFIX = "refs/posthog-code-handoff/head/";
|
|
6045
6118
|
var CHECKPOINT_REF_PREFIX2 = "refs/posthog-code-checkpoint/";
|
|
6119
|
+
var MAX_HANDOFF_FILE_BYTES = 1024 * 1024;
|
|
6046
6120
|
var GitHandoffTracker = class {
|
|
6047
6121
|
repositoryPath;
|
|
6048
6122
|
logger;
|
|
@@ -6050,7 +6124,7 @@ var GitHandoffTracker = class {
|
|
|
6050
6124
|
this.repositoryPath = config.repositoryPath;
|
|
6051
6125
|
this.logger = config.logger;
|
|
6052
6126
|
}
|
|
6053
|
-
async captureForHandoff(
|
|
6127
|
+
async captureForHandoff(localGitState) {
|
|
6054
6128
|
const captureSaga = new CaptureCheckpointSaga(this.logger);
|
|
6055
6129
|
const result = await captureSaga.run({ baseDir: this.repositoryPath });
|
|
6056
6130
|
if (!result.success) {
|
|
@@ -6060,17 +6134,20 @@ var GitHandoffTracker = class {
|
|
|
6060
6134
|
const git = createGitClient(this.repositoryPath);
|
|
6061
6135
|
const tempDir = await this.createTempDir(checkpoint.checkpointId);
|
|
6062
6136
|
const checkpointRef = `${CHECKPOINT_REF_PREFIX2}${checkpoint.checkpointId}`;
|
|
6063
|
-
const packRefs = [
|
|
6064
|
-
checkpoint.head,
|
|
6065
|
-
checkpoint.indexTree,
|
|
6066
|
-
checkpoint.worktreeTree
|
|
6067
|
-
].filter((ref) => !!ref);
|
|
6068
|
-
const headRef = checkpoint.head ? `${HANDOFF_HEAD_REF_PREFIX}${checkpoint.checkpointId}` : void 0;
|
|
6069
|
-
const packPrefix = path3.join(tempDir, checkpoint.checkpointId);
|
|
6070
6137
|
try {
|
|
6138
|
+
const reconciledIndex = await this.reconcileHandoffIndex(git, checkpoint.head, checkpoint.indexTree, tempDir, checkpoint.checkpointId);
|
|
6139
|
+
const packBaseline = localGitState?.upstreamHead ?? null;
|
|
6140
|
+
const packRefs = [
|
|
6141
|
+
checkpoint.head,
|
|
6142
|
+
reconciledIndex.indexTree,
|
|
6143
|
+
checkpoint.worktreeTree,
|
|
6144
|
+
packBaseline ? `^${packBaseline}` : null
|
|
6145
|
+
].filter((ref) => !!ref);
|
|
6146
|
+
const headRef = checkpoint.head ? `${HANDOFF_HEAD_REF_PREFIX}${checkpoint.checkpointId}` : void 0;
|
|
6147
|
+
const packPrefix = path3.join(tempDir, checkpoint.checkpointId);
|
|
6071
6148
|
const [headPack, indexFile, tracking] = await Promise.all([
|
|
6072
6149
|
this.captureObjectPack(packPrefix, packRefs),
|
|
6073
|
-
this.
|
|
6150
|
+
this.statFileArtifact(reconciledIndex.indexFilePath),
|
|
6074
6151
|
getTrackingMetadata(git, checkpoint.branch)
|
|
6075
6152
|
]);
|
|
6076
6153
|
return {
|
|
@@ -6081,7 +6158,7 @@ var GitHandoffTracker = class {
|
|
|
6081
6158
|
headRef,
|
|
6082
6159
|
head: checkpoint.head,
|
|
6083
6160
|
branch: checkpoint.branch,
|
|
6084
|
-
indexTree:
|
|
6161
|
+
indexTree: reconciledIndex.indexTree,
|
|
6085
6162
|
worktreeTree: checkpoint.worktreeTree,
|
|
6086
6163
|
timestamp: checkpoint.timestamp,
|
|
6087
6164
|
upstreamRemote: tracking.upstreamRemote,
|
|
@@ -6101,6 +6178,7 @@ var GitHandoffTracker = class {
|
|
|
6101
6178
|
const { checkpoint, headPackPath, indexPath, localGitState, onDivergedBranch } = input;
|
|
6102
6179
|
const git = createGitClient(this.repositoryPath);
|
|
6103
6180
|
if (headPackPath) {
|
|
6181
|
+
await this.ensureBaselineForApply(git, checkpoint, localGitState);
|
|
6104
6182
|
await this.unpackPackFile(headPackPath);
|
|
6105
6183
|
}
|
|
6106
6184
|
if (checkpoint.branch && checkpoint.head) {
|
|
@@ -6139,14 +6217,89 @@ var GitHandoffTracker = class {
|
|
|
6139
6217
|
});
|
|
6140
6218
|
return { path: packPath, rawBytes };
|
|
6141
6219
|
}
|
|
6142
|
-
async
|
|
6143
|
-
const
|
|
6144
|
-
const
|
|
6145
|
-
await copyFile(
|
|
6146
|
-
|
|
6147
|
-
|
|
6148
|
-
|
|
6149
|
-
}
|
|
6220
|
+
async reconcileHandoffIndex(git, head, indexTree, tempDir, checkpointId) {
|
|
6221
|
+
const realIndexPath = await this.getGitPath(git, "index");
|
|
6222
|
+
const tempIndexPath = path3.join(tempDir, `${checkpointId}.index`);
|
|
6223
|
+
await copyFile(realIndexPath, tempIndexPath);
|
|
6224
|
+
const largePaths = await this.listLargeBlobsInTree(indexTree, MAX_HANDOFF_FILE_BYTES);
|
|
6225
|
+
if (largePaths.length === 0) {
|
|
6226
|
+
return { indexTree, indexFilePath: tempIndexPath };
|
|
6227
|
+
}
|
|
6228
|
+
const headBlobs = head ? await this.readHeadBlobsForPaths(head, largePaths) : /* @__PURE__ */ new Map();
|
|
6229
|
+
const env = { ...process.env, GIT_INDEX_FILE: tempIndexPath };
|
|
6230
|
+
for (const filePath of largePaths) {
|
|
6231
|
+
const headBlob = headBlobs.get(filePath);
|
|
6232
|
+
if (headBlob) {
|
|
6233
|
+
await this.runGitWithEnv(env, [
|
|
6234
|
+
"update-index",
|
|
6235
|
+
"--cacheinfo",
|
|
6236
|
+
`${headBlob.mode},${headBlob.hash},${filePath}`
|
|
6237
|
+
]);
|
|
6238
|
+
} else {
|
|
6239
|
+
await this.runGitWithEnv(env, [
|
|
6240
|
+
"update-index",
|
|
6241
|
+
"--force-remove",
|
|
6242
|
+
filePath
|
|
6243
|
+
]).catch(() => {
|
|
6244
|
+
});
|
|
6245
|
+
}
|
|
6246
|
+
}
|
|
6247
|
+
const reconciledTree = (await this.runGitWithEnv(env, ["write-tree"])).trim();
|
|
6248
|
+
return { indexTree: reconciledTree, indexFilePath: tempIndexPath };
|
|
6249
|
+
}
|
|
6250
|
+
async listLargeBlobsInTree(tree, maxBytes) {
|
|
6251
|
+
const { stdout } = await this.runGitProcess(["ls-tree", "-r", "-l", tree], "");
|
|
6252
|
+
const result = [];
|
|
6253
|
+
for (const line of stdout.split("\n")) {
|
|
6254
|
+
if (!line)
|
|
6255
|
+
continue;
|
|
6256
|
+
const tabIndex = line.indexOf(" ");
|
|
6257
|
+
if (tabIndex < 0)
|
|
6258
|
+
continue;
|
|
6259
|
+
const meta = line.slice(0, tabIndex);
|
|
6260
|
+
const filePath = line.slice(tabIndex + 1);
|
|
6261
|
+
const parts = meta.split(/\s+/);
|
|
6262
|
+
if (parts.length < 4)
|
|
6263
|
+
continue;
|
|
6264
|
+
const [, type, , sizeStr] = parts;
|
|
6265
|
+
if (type !== "blob")
|
|
6266
|
+
continue;
|
|
6267
|
+
if (sizeStr === "-")
|
|
6268
|
+
continue;
|
|
6269
|
+
const size = Number.parseInt(sizeStr, 10);
|
|
6270
|
+
if (Number.isFinite(size) && size > maxBytes) {
|
|
6271
|
+
result.push(filePath);
|
|
6272
|
+
}
|
|
6273
|
+
}
|
|
6274
|
+
return result;
|
|
6275
|
+
}
|
|
6276
|
+
async readHeadBlobsForPaths(head, paths) {
|
|
6277
|
+
const result = /* @__PURE__ */ new Map();
|
|
6278
|
+
const CHUNK_SIZE = 100;
|
|
6279
|
+
for (let i = 0; i < paths.length; i += CHUNK_SIZE) {
|
|
6280
|
+
const chunk = paths.slice(i, i + CHUNK_SIZE);
|
|
6281
|
+
const { stdout } = await this.runGitProcess(["ls-tree", "-r", head, "--", ...chunk], "").catch(() => ({ stdout: "", stderr: "" }));
|
|
6282
|
+
for (const line of stdout.split("\n")) {
|
|
6283
|
+
if (!line)
|
|
6284
|
+
continue;
|
|
6285
|
+
const tabIndex = line.indexOf(" ");
|
|
6286
|
+
if (tabIndex < 0)
|
|
6287
|
+
continue;
|
|
6288
|
+
const meta = line.slice(0, tabIndex);
|
|
6289
|
+
const filePath = line.slice(tabIndex + 1);
|
|
6290
|
+
const parts = meta.split(/\s+/);
|
|
6291
|
+
if (parts.length < 3)
|
|
6292
|
+
continue;
|
|
6293
|
+
const [mode, type, hash] = parts;
|
|
6294
|
+
if (type !== "blob")
|
|
6295
|
+
continue;
|
|
6296
|
+
result.set(filePath, { mode, hash });
|
|
6297
|
+
}
|
|
6298
|
+
}
|
|
6299
|
+
return result;
|
|
6300
|
+
}
|
|
6301
|
+
async statFileArtifact(filePath) {
|
|
6302
|
+
return { path: filePath, rawBytes: await this.getFileSize(filePath) };
|
|
6150
6303
|
}
|
|
6151
6304
|
async restoreIndexFile(git, indexPath) {
|
|
6152
6305
|
const gitIndexPath = await this.getGitPath(git, "index");
|
|
@@ -6174,6 +6327,20 @@ var GitHandoffTracker = class {
|
|
|
6174
6327
|
shouldRestoreTracking(branchStatus2, localGitState, tracking) {
|
|
6175
6328
|
return branchStatus2.kind === "missing" || !hasTrackingConfig(localGitState) && (tracking.upstreamRemote !== null || tracking.upstreamMergeRef !== null);
|
|
6176
6329
|
}
|
|
6330
|
+
async ensureBaselineForApply(git, checkpoint, localGitState) {
|
|
6331
|
+
const tracking = this.getPreferredTracking(localGitState, checkpoint);
|
|
6332
|
+
if (!tracking.upstreamRemote || !tracking.upstreamMergeRef)
|
|
6333
|
+
return;
|
|
6334
|
+
await this.ensureRemoteForTracking(git, tracking).catch(() => {
|
|
6335
|
+
});
|
|
6336
|
+
await git.raw(["fetch", tracking.upstreamRemote, tracking.upstreamMergeRef]).catch((err) => {
|
|
6337
|
+
this.logger?.error("Handoff baseline fetch failed; if the pack excludes commits the receiver does not already have, the subsequent unpack/read-tree will fail with an object-missing error", {
|
|
6338
|
+
err: String(err),
|
|
6339
|
+
remote: tracking.upstreamRemote,
|
|
6340
|
+
ref: tracking.upstreamMergeRef
|
|
6341
|
+
});
|
|
6342
|
+
});
|
|
6343
|
+
}
|
|
6177
6344
|
async ensureRemoteForTracking(git, tracking) {
|
|
6178
6345
|
if (!tracking.upstreamRemote || !tracking.remoteUrl)
|
|
6179
6346
|
return;
|
|
@@ -6310,6 +6477,31 @@ var GitHandoffTracker = class {
|
|
|
6310
6477
|
});
|
|
6311
6478
|
});
|
|
6312
6479
|
}
|
|
6480
|
+
async runGitWithEnv(env, args) {
|
|
6481
|
+
return new Promise((resolve2, reject) => {
|
|
6482
|
+
const child = spawn2("git", args, {
|
|
6483
|
+
cwd: this.repositoryPath,
|
|
6484
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
6485
|
+
env
|
|
6486
|
+
});
|
|
6487
|
+
let stdout = "";
|
|
6488
|
+
let stderr = "";
|
|
6489
|
+
child.stdout.on("data", (chunk) => {
|
|
6490
|
+
stdout += chunk.toString();
|
|
6491
|
+
});
|
|
6492
|
+
child.stderr.on("data", (chunk) => {
|
|
6493
|
+
stderr += chunk.toString();
|
|
6494
|
+
});
|
|
6495
|
+
child.on("error", reject);
|
|
6496
|
+
child.on("close", (code) => {
|
|
6497
|
+
if (code === 0) {
|
|
6498
|
+
resolve2(stdout);
|
|
6499
|
+
return;
|
|
6500
|
+
}
|
|
6501
|
+
reject(new Error(stderr || `git ${args.join(" ")} failed with code ${code}`));
|
|
6502
|
+
});
|
|
6503
|
+
});
|
|
6504
|
+
}
|
|
6313
6505
|
runGitProcess(args, input) {
|
|
6314
6506
|
return new Promise((resolve2, reject) => {
|
|
6315
6507
|
const child = spawn2("git", args, {
|
|
@@ -6332,6 +6524,8 @@ var GitHandoffTracker = class {
|
|
|
6332
6524
|
}
|
|
6333
6525
|
reject(new Error(stderr || `git ${args.join(" ")} failed with code ${code}`));
|
|
6334
6526
|
});
|
|
6527
|
+
child.stdin.on("error", () => {
|
|
6528
|
+
});
|
|
6335
6529
|
child.stdin.end(input);
|
|
6336
6530
|
});
|
|
6337
6531
|
}
|