@posthog/agent 2.3.398 → 2.3.403
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/README.md +11 -14
- package/dist/agent.js +1 -7
- package/dist/agent.js.map +1 -1
- package/dist/handoff-checkpoint.d.ts +0 -2
- package/dist/handoff-checkpoint.js +38 -53
- package/dist/handoff-checkpoint.js.map +1 -1
- package/dist/index.d.ts +0 -2
- package/dist/index.js +0 -2
- package/dist/index.js.map +1 -1
- package/dist/posthog-api.js +1 -5
- package/dist/posthog-api.js.map +1 -1
- package/dist/resume.d.ts +5 -6
- package/dist/resume.js +2 -41
- package/dist/resume.js.map +1 -1
- package/dist/server/agent-server.d.ts +1 -2
- package/dist/server/agent-server.js +103 -768
- package/dist/server/agent-server.js.map +1 -1
- package/dist/server/bin.cjs +101 -766
- package/dist/server/bin.cjs.map +1 -1
- package/dist/types.d.ts +2 -13
- package/dist/types.js.map +1 -1
- package/package.json +3 -7
- package/src/acp-extensions.ts +0 -3
- package/src/handoff-checkpoint.test.ts +3 -17
- package/src/handoff-checkpoint.ts +15 -45
- package/src/resume.ts +5 -11
- package/src/sagas/resume-saga.test.ts +27 -77
- package/src/sagas/resume-saga.ts +3 -44
- package/src/sagas/test-fixtures.ts +17 -76
- package/src/server/agent-server.ts +22 -103
- package/src/test/fixtures/api.ts +2 -15
- package/src/types.ts +0 -16
- package/dist/tree-tracker.d.ts +0 -68
- package/dist/tree-tracker.js +0 -6431
- package/dist/tree-tracker.js.map +0 -1
- package/src/sagas/apply-snapshot-saga.test.ts +0 -690
- package/src/sagas/apply-snapshot-saga.ts +0 -100
- package/src/sagas/capture-tree-saga.test.ts +0 -892
- package/src/sagas/capture-tree-saga.ts +0 -150
- package/src/tree-tracker.ts +0 -173
|
@@ -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(path16, isFile2, isDirectory) {
|
|
813
|
+
log(`checking %s`, path16);
|
|
814
814
|
try {
|
|
815
|
-
const stat4 = fs_1.statSync(
|
|
815
|
+
const stat4 = fs_1.statSync(path16);
|
|
816
816
|
if (stat4.isFile() && isFile2) {
|
|
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(path16, type = exports2.READABLE) {
|
|
836
|
+
return check(path16, (type & exports2.FILE) > 0, (type & exports2.FOLDER) > 0);
|
|
837
837
|
}
|
|
838
838
|
exports2.exists = exists2;
|
|
839
839
|
exports2.FILE = 1;
|
|
@@ -929,11 +929,11 @@ var require_tree_sitter = __commonJS({
|
|
|
929
929
|
throw toThrow;
|
|
930
930
|
};
|
|
931
931
|
var scriptDirectory = "";
|
|
932
|
-
function locateFile(
|
|
932
|
+
function locateFile(path16) {
|
|
933
933
|
if (Module["locateFile"]) {
|
|
934
|
-
return Module["locateFile"](
|
|
934
|
+
return Module["locateFile"](path16, scriptDirectory);
|
|
935
935
|
}
|
|
936
|
-
return scriptDirectory +
|
|
936
|
+
return scriptDirectory + path16;
|
|
937
937
|
}
|
|
938
938
|
var readAsync, readBinary;
|
|
939
939
|
if (ENVIRONMENT_IS_NODE) {
|
|
@@ -3454,8 +3454,8 @@ var require_tree_sitter = __commonJS({
|
|
|
3454
3454
|
} else {
|
|
3455
3455
|
const url = input;
|
|
3456
3456
|
if (typeof process !== "undefined" && process.versions && process.versions.node) {
|
|
3457
|
-
const
|
|
3458
|
-
bytes = Promise.resolve(
|
|
3457
|
+
const fs13 = __require("fs");
|
|
3458
|
+
bytes = Promise.resolve(fs13.readFileSync(url));
|
|
3459
3459
|
} else {
|
|
3460
3460
|
bytes = fetch(url).then((response) => response.arrayBuffer().then((buffer) => {
|
|
3461
3461
|
if (response.ok) {
|
|
@@ -3784,8 +3784,8 @@ ${JSON.stringify(symbolNames, null, 2)}`);
|
|
|
3784
3784
|
});
|
|
3785
3785
|
|
|
3786
3786
|
// src/server/agent-server.ts
|
|
3787
|
-
import { mkdir as
|
|
3788
|
-
import { basename as basename2, join as
|
|
3787
|
+
import { mkdir as mkdir4, writeFile as writeFile4 } from "fs/promises";
|
|
3788
|
+
import { basename as basename2, join as join11 } from "path";
|
|
3789
3789
|
import { pathToFileURL } from "url";
|
|
3790
3790
|
import {
|
|
3791
3791
|
ClientSideConnection as ClientSideConnection2,
|
|
@@ -3835,8 +3835,8 @@ function pathspec(...paths) {
|
|
|
3835
3835
|
cache.set(key, paths);
|
|
3836
3836
|
return key;
|
|
3837
3837
|
}
|
|
3838
|
-
function isPathSpec(
|
|
3839
|
-
return
|
|
3838
|
+
function isPathSpec(path16) {
|
|
3839
|
+
return path16 instanceof String && cache.has(path16);
|
|
3840
3840
|
}
|
|
3841
3841
|
function toPaths(pathSpec) {
|
|
3842
3842
|
return cache.get(pathSpec) || [];
|
|
@@ -3925,8 +3925,8 @@ function toLinesWithContent(input = "", trimmed2 = true, separator = "\n") {
|
|
|
3925
3925
|
function forEachLineWithContent(input, callback) {
|
|
3926
3926
|
return toLinesWithContent(input, true).map((line) => callback(line));
|
|
3927
3927
|
}
|
|
3928
|
-
function folderExists(
|
|
3929
|
-
return (0, import_file_exists.exists)(
|
|
3928
|
+
function folderExists(path16) {
|
|
3929
|
+
return (0, import_file_exists.exists)(path16, import_file_exists.FOLDER);
|
|
3930
3930
|
}
|
|
3931
3931
|
function append(target, item) {
|
|
3932
3932
|
if (Array.isArray(target)) {
|
|
@@ -4330,8 +4330,8 @@ function checkIsRepoRootTask() {
|
|
|
4330
4330
|
commands,
|
|
4331
4331
|
format: "utf-8",
|
|
4332
4332
|
onError,
|
|
4333
|
-
parser(
|
|
4334
|
-
return /^\.(git)?$/.test(
|
|
4333
|
+
parser(path16) {
|
|
4334
|
+
return /^\.(git)?$/.test(path16.trim());
|
|
4335
4335
|
}
|
|
4336
4336
|
};
|
|
4337
4337
|
}
|
|
@@ -4765,11 +4765,11 @@ function parseGrep(grep) {
|
|
|
4765
4765
|
const paths = /* @__PURE__ */ new Set();
|
|
4766
4766
|
const results = {};
|
|
4767
4767
|
forEachLineWithContent(grep, (input) => {
|
|
4768
|
-
const [
|
|
4769
|
-
paths.add(
|
|
4770
|
-
(results[
|
|
4768
|
+
const [path16, line, preview] = input.split(NULL);
|
|
4769
|
+
paths.add(path16);
|
|
4770
|
+
(results[path16] = results[path16] || []).push({
|
|
4771
4771
|
line: asNumber(line),
|
|
4772
|
-
path:
|
|
4772
|
+
path: path16,
|
|
4773
4773
|
preview
|
|
4774
4774
|
});
|
|
4775
4775
|
});
|
|
@@ -5534,14 +5534,14 @@ var init_hash_object = __esm({
|
|
|
5534
5534
|
init_task();
|
|
5535
5535
|
}
|
|
5536
5536
|
});
|
|
5537
|
-
function parseInit(bare,
|
|
5537
|
+
function parseInit(bare, path16, text2) {
|
|
5538
5538
|
const response = String(text2).trim();
|
|
5539
5539
|
let result;
|
|
5540
5540
|
if (result = initResponseRegex.exec(response)) {
|
|
5541
|
-
return new InitSummary(bare,
|
|
5541
|
+
return new InitSummary(bare, path16, false, result[1]);
|
|
5542
5542
|
}
|
|
5543
5543
|
if (result = reInitResponseRegex.exec(response)) {
|
|
5544
|
-
return new InitSummary(bare,
|
|
5544
|
+
return new InitSummary(bare, path16, true, result[1]);
|
|
5545
5545
|
}
|
|
5546
5546
|
let gitDir = "";
|
|
5547
5547
|
const tokens = response.split(" ");
|
|
@@ -5552,7 +5552,7 @@ function parseInit(bare, path17, text2) {
|
|
|
5552
5552
|
break;
|
|
5553
5553
|
}
|
|
5554
5554
|
}
|
|
5555
|
-
return new InitSummary(bare,
|
|
5555
|
+
return new InitSummary(bare, path16, /^re/i.test(response), gitDir);
|
|
5556
5556
|
}
|
|
5557
5557
|
var InitSummary;
|
|
5558
5558
|
var initResponseRegex;
|
|
@@ -5561,9 +5561,9 @@ var init_InitSummary = __esm({
|
|
|
5561
5561
|
"src/lib/responses/InitSummary.ts"() {
|
|
5562
5562
|
"use strict";
|
|
5563
5563
|
InitSummary = class {
|
|
5564
|
-
constructor(bare,
|
|
5564
|
+
constructor(bare, path16, existing, gitDir) {
|
|
5565
5565
|
this.bare = bare;
|
|
5566
|
-
this.path =
|
|
5566
|
+
this.path = path16;
|
|
5567
5567
|
this.existing = existing;
|
|
5568
5568
|
this.gitDir = gitDir;
|
|
5569
5569
|
}
|
|
@@ -5575,7 +5575,7 @@ var init_InitSummary = __esm({
|
|
|
5575
5575
|
function hasBareCommand(command) {
|
|
5576
5576
|
return command.includes(bareCommand);
|
|
5577
5577
|
}
|
|
5578
|
-
function initTask(bare = false,
|
|
5578
|
+
function initTask(bare = false, path16, customArgs) {
|
|
5579
5579
|
const commands = ["init", ...customArgs];
|
|
5580
5580
|
if (bare && !hasBareCommand(commands)) {
|
|
5581
5581
|
commands.splice(1, 0, bareCommand);
|
|
@@ -5584,7 +5584,7 @@ function initTask(bare = false, path17, customArgs) {
|
|
|
5584
5584
|
commands,
|
|
5585
5585
|
format: "utf-8",
|
|
5586
5586
|
parser(text2) {
|
|
5587
|
-
return parseInit(commands.includes("--bare"),
|
|
5587
|
+
return parseInit(commands.includes("--bare"), path16, text2);
|
|
5588
5588
|
}
|
|
5589
5589
|
};
|
|
5590
5590
|
}
|
|
@@ -6400,12 +6400,12 @@ var init_FileStatusSummary = __esm({
|
|
|
6400
6400
|
"use strict";
|
|
6401
6401
|
fromPathRegex = /^(.+)\0(.+)$/;
|
|
6402
6402
|
FileStatusSummary = class {
|
|
6403
|
-
constructor(
|
|
6404
|
-
this.path =
|
|
6403
|
+
constructor(path16, index, working_dir) {
|
|
6404
|
+
this.path = path16;
|
|
6405
6405
|
this.index = index;
|
|
6406
6406
|
this.working_dir = working_dir;
|
|
6407
6407
|
if (index === "R" || working_dir === "R") {
|
|
6408
|
-
const detail = fromPathRegex.exec(
|
|
6408
|
+
const detail = fromPathRegex.exec(path16) || [null, path16, path16];
|
|
6409
6409
|
this.from = detail[2] || "";
|
|
6410
6410
|
this.path = detail[1] || "";
|
|
6411
6411
|
}
|
|
@@ -6436,14 +6436,14 @@ function splitLine(result, lineStr) {
|
|
|
6436
6436
|
default:
|
|
6437
6437
|
return;
|
|
6438
6438
|
}
|
|
6439
|
-
function data(index, workingDir,
|
|
6439
|
+
function data(index, workingDir, path16) {
|
|
6440
6440
|
const raw = `${index}${workingDir}`;
|
|
6441
6441
|
const handler = parsers6.get(raw);
|
|
6442
6442
|
if (handler) {
|
|
6443
|
-
handler(result,
|
|
6443
|
+
handler(result, path16);
|
|
6444
6444
|
}
|
|
6445
6445
|
if (raw !== "##" && raw !== "!!") {
|
|
6446
|
-
result.files.push(new FileStatusSummary(
|
|
6446
|
+
result.files.push(new FileStatusSummary(path16, index, workingDir));
|
|
6447
6447
|
}
|
|
6448
6448
|
}
|
|
6449
6449
|
}
|
|
@@ -6756,9 +6756,9 @@ var init_simple_git_api = __esm({
|
|
|
6756
6756
|
next
|
|
6757
6757
|
);
|
|
6758
6758
|
}
|
|
6759
|
-
hashObject(
|
|
6759
|
+
hashObject(path16, write) {
|
|
6760
6760
|
return this._runTask(
|
|
6761
|
-
hashObjectTask(
|
|
6761
|
+
hashObjectTask(path16, write === true),
|
|
6762
6762
|
trailingFunctionArgument(arguments)
|
|
6763
6763
|
);
|
|
6764
6764
|
}
|
|
@@ -7111,8 +7111,8 @@ var init_branch = __esm({
|
|
|
7111
7111
|
}
|
|
7112
7112
|
});
|
|
7113
7113
|
function toPath(input) {
|
|
7114
|
-
const
|
|
7115
|
-
return
|
|
7114
|
+
const path16 = input.trim().replace(/^["']|["']$/g, "");
|
|
7115
|
+
return path16 && normalize(path16);
|
|
7116
7116
|
}
|
|
7117
7117
|
var parseCheckIgnore;
|
|
7118
7118
|
var init_CheckIgnore = __esm({
|
|
@@ -7426,8 +7426,8 @@ __export(sub_module_exports, {
|
|
|
7426
7426
|
subModuleTask: () => subModuleTask,
|
|
7427
7427
|
updateSubModuleTask: () => updateSubModuleTask
|
|
7428
7428
|
});
|
|
7429
|
-
function addSubModuleTask(repo,
|
|
7430
|
-
return subModuleTask(["add", repo,
|
|
7429
|
+
function addSubModuleTask(repo, path16) {
|
|
7430
|
+
return subModuleTask(["add", repo, path16]);
|
|
7431
7431
|
}
|
|
7432
7432
|
function initSubModuleTask(customArgs) {
|
|
7433
7433
|
return subModuleTask(["init", ...customArgs]);
|
|
@@ -7757,8 +7757,8 @@ var require_git = __commonJS2({
|
|
|
7757
7757
|
}
|
|
7758
7758
|
return this._runTask(straightThroughStringTask2(command, this._trimmed), next);
|
|
7759
7759
|
};
|
|
7760
|
-
Git2.prototype.submoduleAdd = function(repo,
|
|
7761
|
-
return this._runTask(addSubModuleTask2(repo,
|
|
7760
|
+
Git2.prototype.submoduleAdd = function(repo, path16, then) {
|
|
7761
|
+
return this._runTask(addSubModuleTask2(repo, path16), trailingFunctionArgument2(arguments));
|
|
7762
7762
|
};
|
|
7763
7763
|
Git2.prototype.submoduleUpdate = function(args2, then) {
|
|
7764
7764
|
return this._runTask(
|
|
@@ -8591,12 +8591,6 @@ async function listWorktrees(baseDir, options) {
|
|
|
8591
8591
|
return worktrees;
|
|
8592
8592
|
}, { signal: options?.abortSignal });
|
|
8593
8593
|
}
|
|
8594
|
-
async function getHeadSha(baseDir, options) {
|
|
8595
|
-
const manager = getGitOperationManager();
|
|
8596
|
-
return manager.executeRead(baseDir, (git) => git.revparse(["HEAD"]), {
|
|
8597
|
-
signal: options?.abortSignal
|
|
8598
|
-
});
|
|
8599
|
-
}
|
|
8600
8594
|
|
|
8601
8595
|
// src/server/agent-server.ts
|
|
8602
8596
|
import { Hono } from "hono";
|
|
@@ -8605,7 +8599,7 @@ import { z as z4 } from "zod";
|
|
|
8605
8599
|
// package.json
|
|
8606
8600
|
var package_default = {
|
|
8607
8601
|
name: "@posthog/agent",
|
|
8608
|
-
version: "2.3.
|
|
8602
|
+
version: "2.3.403",
|
|
8609
8603
|
repository: "https://github.com/PostHog/code",
|
|
8610
8604
|
description: "TypeScript agent framework wrapping Claude Agent SDK with Git-based task execution for PostHog",
|
|
8611
8605
|
exports: {
|
|
@@ -8673,10 +8667,6 @@ var package_default = {
|
|
|
8673
8667
|
types: "./dist/handoff-checkpoint.d.ts",
|
|
8674
8668
|
import: "./dist/handoff-checkpoint.js"
|
|
8675
8669
|
},
|
|
8676
|
-
"./tree-tracker": {
|
|
8677
|
-
types: "./dist/tree-tracker.d.ts",
|
|
8678
|
-
import: "./dist/tree-tracker.js"
|
|
8679
|
-
},
|
|
8680
8670
|
"./server": {
|
|
8681
8671
|
types: "./dist/server/agent-server.d.ts",
|
|
8682
8672
|
import: "./dist/server/agent-server.js"
|
|
@@ -8772,8 +8762,6 @@ var POSTHOG_NOTIFICATIONS = {
|
|
|
8772
8762
|
CONSOLE: "_posthog/console",
|
|
8773
8763
|
/** Maps taskRunId to agent's sessionId and adapter type (for resumption) */
|
|
8774
8764
|
SDK_SESSION: "_posthog/sdk_session",
|
|
8775
|
-
/** Tree state snapshot captured (git tree hash + file archive) */
|
|
8776
|
-
TREE_SNAPSHOT: "_posthog/tree_snapshot",
|
|
8777
8765
|
/** Git checkpoint captured for handoff */
|
|
8778
8766
|
GIT_CHECKPOINT: "_posthog/git_checkpoint",
|
|
8779
8767
|
/** Agent mode changed (interactive/background) */
|
|
@@ -8812,9 +8800,6 @@ function matchesExt(method, expected) {
|
|
|
8812
8800
|
if (!method) return false;
|
|
8813
8801
|
return method === expected || method === `_${expected}`;
|
|
8814
8802
|
}
|
|
8815
|
-
function isNotification(method, expected) {
|
|
8816
|
-
return matchesExt(method, expected);
|
|
8817
|
-
}
|
|
8818
8803
|
function isMethod(method, expected) {
|
|
8819
8804
|
return matchesExt(method, expected);
|
|
8820
8805
|
}
|
|
@@ -13450,8 +13435,8 @@ var ToolContentBuilder = class {
|
|
|
13450
13435
|
this.items.push({ type: "content", content: image(data, mimeType, uri) });
|
|
13451
13436
|
return this;
|
|
13452
13437
|
}
|
|
13453
|
-
diff(
|
|
13454
|
-
this.items.push({ type: "diff", path:
|
|
13438
|
+
diff(path16, oldText, newText) {
|
|
13439
|
+
this.items.push({ type: "diff", path: path16, oldText, newText });
|
|
13455
13440
|
return this;
|
|
13456
13441
|
}
|
|
13457
13442
|
build() {
|
|
@@ -18444,12 +18429,14 @@ function createCodexConnection(config) {
|
|
|
18444
18429
|
}
|
|
18445
18430
|
|
|
18446
18431
|
// src/handoff-checkpoint.ts
|
|
18447
|
-
import {
|
|
18448
|
-
import {
|
|
18432
|
+
import { mkdtemp as mkdtemp2, readFile as readFile4, rm as rm4, writeFile as writeFile2 } from "fs/promises";
|
|
18433
|
+
import { tmpdir as tmpdir2 } from "os";
|
|
18434
|
+
import { dirname as dirname6, join as join9 } from "path";
|
|
18449
18435
|
|
|
18450
18436
|
// ../git/dist/handoff.js
|
|
18451
18437
|
import { spawn as spawn4 } from "child_process";
|
|
18452
|
-
import { copyFile,
|
|
18438
|
+
import { copyFile, mkdtemp, readFile as readFile3, rm as rm3, stat as stat3 } from "fs/promises";
|
|
18439
|
+
import { tmpdir } from "os";
|
|
18453
18440
|
import path13 from "path";
|
|
18454
18441
|
|
|
18455
18442
|
// ../git/dist/sagas/checkpoint.js
|
|
@@ -18857,7 +18844,7 @@ var GitHandoffTracker = class {
|
|
|
18857
18844
|
this.repositoryPath = config.repositoryPath;
|
|
18858
18845
|
this.logger = config.logger;
|
|
18859
18846
|
}
|
|
18860
|
-
async captureForHandoff(
|
|
18847
|
+
async captureForHandoff(_localGitState) {
|
|
18861
18848
|
const captureSaga = new CaptureCheckpointSaga(this.logger);
|
|
18862
18849
|
const result = await captureSaga.run({ baseDir: this.repositoryPath });
|
|
18863
18850
|
if (!result.success) {
|
|
@@ -18865,15 +18852,19 @@ var GitHandoffTracker = class {
|
|
|
18865
18852
|
}
|
|
18866
18853
|
const checkpoint = result.data;
|
|
18867
18854
|
const git = createGitClient(this.repositoryPath);
|
|
18868
|
-
const tempDir = await this.
|
|
18855
|
+
const tempDir = await this.createTempDir(checkpoint.checkpointId);
|
|
18869
18856
|
const checkpointRef = `${CHECKPOINT_REF_PREFIX2}${checkpoint.checkpointId}`;
|
|
18870
|
-
const
|
|
18871
|
-
|
|
18857
|
+
const packRefs = [
|
|
18858
|
+
checkpoint.head,
|
|
18859
|
+
checkpoint.indexTree,
|
|
18860
|
+
checkpoint.worktreeTree
|
|
18861
|
+
].filter((ref) => !!ref);
|
|
18862
|
+
const headRef = checkpoint.head ? `${HANDOFF_HEAD_REF_PREFIX}${checkpoint.checkpointId}` : void 0;
|
|
18872
18863
|
const packPrefix = path13.join(tempDir, checkpoint.checkpointId);
|
|
18873
18864
|
try {
|
|
18874
18865
|
const [headPack, indexFile, tracking] = await Promise.all([
|
|
18875
|
-
|
|
18876
|
-
this.copyIndexFile(git, checkpoint.checkpointId),
|
|
18866
|
+
this.captureObjectPack(packPrefix, packRefs),
|
|
18867
|
+
this.copyIndexFile(git, checkpoint.checkpointId, tempDir),
|
|
18877
18868
|
getTrackingMetadata(git, checkpoint.branch)
|
|
18878
18869
|
]);
|
|
18879
18870
|
return {
|
|
@@ -18920,6 +18911,8 @@ var GitHandoffTracker = class {
|
|
|
18920
18911
|
} else if (checkpoint.head) {
|
|
18921
18912
|
await git.checkout(checkpoint.head);
|
|
18922
18913
|
}
|
|
18914
|
+
await git.clean(["f", "d"]);
|
|
18915
|
+
await git.raw(["read-tree", "--reset", "-u", checkpoint.worktreeTree]);
|
|
18923
18916
|
if (indexPath) {
|
|
18924
18917
|
await this.restoreIndexFile(git, indexPath);
|
|
18925
18918
|
}
|
|
@@ -18931,8 +18924,8 @@ var GitHandoffTracker = class {
|
|
|
18931
18924
|
totalBytes: packBytes + indexBytes
|
|
18932
18925
|
};
|
|
18933
18926
|
}
|
|
18934
|
-
async
|
|
18935
|
-
const hash = await this.runGitWithInput(["pack-objects", packPrefix, "--revs"], `${
|
|
18927
|
+
async captureObjectPack(packPrefix, refs) {
|
|
18928
|
+
const hash = await this.runGitWithInput(["pack-objects", packPrefix, "--revs"], `${refs.join("\n")}
|
|
18936
18929
|
`);
|
|
18937
18930
|
const packPath = `${packPrefix}-${hash.trim()}.pack`;
|
|
18938
18931
|
const rawBytes = await this.getFileSize(packPath);
|
|
@@ -18940,9 +18933,8 @@ var GitHandoffTracker = class {
|
|
|
18940
18933
|
});
|
|
18941
18934
|
return { path: packPath, rawBytes };
|
|
18942
18935
|
}
|
|
18943
|
-
async copyIndexFile(git, checkpointId) {
|
|
18936
|
+
async copyIndexFile(git, checkpointId, tempDir) {
|
|
18944
18937
|
const indexPath = await this.getGitPath(git, "index");
|
|
18945
|
-
const tempDir = await this.getTempDir(git);
|
|
18946
18938
|
const copiedIndexPath = path13.join(tempDir, `${checkpointId}.index`);
|
|
18947
18939
|
await copyFile(indexPath, copiedIndexPath);
|
|
18948
18940
|
return {
|
|
@@ -19070,13 +19062,8 @@ var GitHandoffTracker = class {
|
|
|
19070
19062
|
]);
|
|
19071
19063
|
return exitCode === 0;
|
|
19072
19064
|
}
|
|
19073
|
-
async
|
|
19074
|
-
|
|
19075
|
-
const commonDir = raw.trim() || ".git";
|
|
19076
|
-
const resolved = path13.isAbsolute(commonDir) ? commonDir : path13.resolve(this.repositoryPath, commonDir);
|
|
19077
|
-
const tempDir = path13.join(resolved, "posthog-code-tmp");
|
|
19078
|
-
await mkdir3(tempDir, { recursive: true });
|
|
19079
|
-
return tempDir;
|
|
19065
|
+
async createTempDir(checkpointId) {
|
|
19066
|
+
return mkdtemp(joinTempPrefix(checkpointId));
|
|
19080
19067
|
}
|
|
19081
19068
|
async getGitPath(git, gitPath) {
|
|
19082
19069
|
const raw = await git.raw(["rev-parse", "--git-path", gitPath]);
|
|
@@ -19143,6 +19130,9 @@ var GitHandoffTracker = class {
|
|
|
19143
19130
|
});
|
|
19144
19131
|
}
|
|
19145
19132
|
};
|
|
19133
|
+
function joinTempPrefix(checkpointId) {
|
|
19134
|
+
return path13.join(tmpdir(), `posthog-code-handoff-${checkpointId}-`);
|
|
19135
|
+
}
|
|
19146
19136
|
async function getCurrentBranchName(git) {
|
|
19147
19137
|
try {
|
|
19148
19138
|
const raw = await git.revparse(["--abbrev-ref", "HEAD"]);
|
|
@@ -19229,8 +19219,11 @@ var HandoffCheckpointTracker = class {
|
|
|
19229
19219
|
indexArtifactPath: uploads.index?.storagePath
|
|
19230
19220
|
};
|
|
19231
19221
|
} finally {
|
|
19222
|
+
const tempDir = capture.headPack?.path ? dirname6(capture.headPack.path) : dirname6(capture.indexFile.path);
|
|
19232
19223
|
await this.removeIfPresent(capture.headPack?.path);
|
|
19233
19224
|
await this.removeIfPresent(capture.indexFile.path);
|
|
19225
|
+
await rm4(tempDir, { recursive: true, force: true }).catch(() => {
|
|
19226
|
+
});
|
|
19234
19227
|
}
|
|
19235
19228
|
}
|
|
19236
19229
|
async applyFromHandoff(checkpoint, options) {
|
|
@@ -19240,8 +19233,9 @@ var HandoffCheckpointTracker = class {
|
|
|
19240
19233
|
);
|
|
19241
19234
|
}
|
|
19242
19235
|
const gitTracker = this.createGitTracker();
|
|
19243
|
-
const tmpDir =
|
|
19244
|
-
|
|
19236
|
+
const tmpDir = await mkdtemp2(
|
|
19237
|
+
join9(tmpdir2(), `posthog-code-handoff-${checkpoint.checkpointId}-`)
|
|
19238
|
+
);
|
|
19245
19239
|
const packPath = join9(tmpDir, `${checkpoint.checkpointId}.pack`);
|
|
19246
19240
|
const indexPath = join9(tmpDir, `${checkpoint.checkpointId}.index`);
|
|
19247
19241
|
try {
|
|
@@ -19275,6 +19269,8 @@ var HandoffCheckpointTracker = class {
|
|
|
19275
19269
|
} finally {
|
|
19276
19270
|
await this.removeIfPresent(packPath);
|
|
19277
19271
|
await this.removeIfPresent(indexPath);
|
|
19272
|
+
await rm4(tmpDir, { recursive: true, force: true }).catch(() => {
|
|
19273
|
+
});
|
|
19278
19274
|
}
|
|
19279
19275
|
}
|
|
19280
19276
|
toGitCheckpoint(checkpoint) {
|
|
@@ -19382,50 +19378,24 @@ var HandoffCheckpointTracker = class {
|
|
|
19382
19378
|
}
|
|
19383
19379
|
logCaptureMetrics(checkpoint, uploads) {
|
|
19384
19380
|
this.logger.info("Captured handoff checkpoint", {
|
|
19385
|
-
checkpointId: checkpoint.checkpointId,
|
|
19386
19381
|
branch: checkpoint.branch,
|
|
19387
|
-
head: checkpoint.head,
|
|
19388
|
-
|
|
19389
|
-
indexArtifactPath: uploads.index?.storagePath,
|
|
19390
|
-
...this.buildMetricPayload(uploads)
|
|
19382
|
+
head: checkpoint.head?.slice(0, 7),
|
|
19383
|
+
totalBytes: this.sumRawBytes(uploads.pack, uploads.index)
|
|
19391
19384
|
});
|
|
19392
19385
|
}
|
|
19393
|
-
logApplyMetrics(checkpoint,
|
|
19386
|
+
logApplyMetrics(checkpoint, _downloads, totalBytes) {
|
|
19394
19387
|
this.logger.info("Applied handoff checkpoint", {
|
|
19395
|
-
checkpointId: checkpoint.checkpointId,
|
|
19396
|
-
commit: checkpoint.commit,
|
|
19397
19388
|
branch: checkpoint.branch,
|
|
19398
|
-
head: checkpoint.head,
|
|
19399
|
-
|
|
19400
|
-
packWireBytes: downloads.pack?.wireBytes ?? 0,
|
|
19401
|
-
indexBytes: downloads.index?.rawBytes ?? 0,
|
|
19402
|
-
indexWireBytes: downloads.index?.wireBytes ?? 0,
|
|
19403
|
-
totalBytes,
|
|
19404
|
-
totalWireBytes: this.sumWireBytes(downloads.pack, downloads.index)
|
|
19389
|
+
head: checkpoint.head?.slice(0, 7),
|
|
19390
|
+
totalBytes
|
|
19405
19391
|
});
|
|
19406
19392
|
}
|
|
19407
|
-
buildMetricPayload(metrics) {
|
|
19408
|
-
return {
|
|
19409
|
-
packBytes: metrics.pack?.rawBytes ?? 0,
|
|
19410
|
-
packWireBytes: metrics.pack?.wireBytes ?? 0,
|
|
19411
|
-
indexBytes: metrics.index?.rawBytes ?? 0,
|
|
19412
|
-
indexWireBytes: metrics.index?.wireBytes ?? 0,
|
|
19413
|
-
totalBytes: this.sumRawBytes(metrics.pack, metrics.index),
|
|
19414
|
-
totalWireBytes: this.sumWireBytes(metrics.pack, metrics.index)
|
|
19415
|
-
};
|
|
19416
|
-
}
|
|
19417
19393
|
sumRawBytes(...artifacts) {
|
|
19418
19394
|
return artifacts.reduce(
|
|
19419
19395
|
(total, artifact) => total + (artifact?.rawBytes ?? 0),
|
|
19420
19396
|
0
|
|
19421
19397
|
);
|
|
19422
19398
|
}
|
|
19423
|
-
sumWireBytes(...artifacts) {
|
|
19424
|
-
return artifacts.reduce(
|
|
19425
|
-
(total, artifact) => total + (artifact?.wireBytes ?? 0),
|
|
19426
|
-
0
|
|
19427
|
-
);
|
|
19428
|
-
}
|
|
19429
19399
|
async removeIfPresent(filePath) {
|
|
19430
19400
|
if (!filePath) {
|
|
19431
19401
|
return;
|
|
@@ -19705,21 +19675,10 @@ var ResumeSaga = class extends Saga {
|
|
|
19705
19675
|
return this.emptyResult();
|
|
19706
19676
|
}
|
|
19707
19677
|
this.log.info("Fetched log entries", { count: entries.length });
|
|
19708
|
-
const latestSnapshot = await this.readOnlyStep(
|
|
19709
|
-
"find_snapshot",
|
|
19710
|
-
() => Promise.resolve(this.findLatestTreeSnapshot(entries))
|
|
19711
|
-
);
|
|
19712
19678
|
const latestGitCheckpoint = await this.readOnlyStep(
|
|
19713
19679
|
"find_git_checkpoint",
|
|
19714
19680
|
() => Promise.resolve(this.findLatestGitCheckpoint(entries))
|
|
19715
19681
|
);
|
|
19716
|
-
if (latestSnapshot) {
|
|
19717
|
-
this.log.info("Found tree snapshot", {
|
|
19718
|
-
treeHash: latestSnapshot.treeHash,
|
|
19719
|
-
hasArchiveUrl: !!latestSnapshot.archiveUrl,
|
|
19720
|
-
changes: latestSnapshot.changes?.length ?? 0
|
|
19721
|
-
});
|
|
19722
|
-
}
|
|
19723
19682
|
if (latestGitCheckpoint) {
|
|
19724
19683
|
this.log.info("Found git checkpoint", {
|
|
19725
19684
|
checkpointId: latestGitCheckpoint.checkpointId,
|
|
@@ -19736,15 +19695,13 @@ var ResumeSaga = class extends Saga {
|
|
|
19736
19695
|
);
|
|
19737
19696
|
this.log.info("Resume state rebuilt", {
|
|
19738
19697
|
turns: conversation.length,
|
|
19739
|
-
hasSnapshot: !!latestSnapshot,
|
|
19740
19698
|
hasGitCheckpoint: !!latestGitCheckpoint,
|
|
19741
|
-
interrupted:
|
|
19699
|
+
interrupted: false
|
|
19742
19700
|
});
|
|
19743
19701
|
return {
|
|
19744
19702
|
conversation,
|
|
19745
|
-
latestSnapshot,
|
|
19746
19703
|
latestGitCheckpoint,
|
|
19747
|
-
interrupted:
|
|
19704
|
+
interrupted: false,
|
|
19748
19705
|
lastDevice,
|
|
19749
19706
|
logEntryCount: entries.length
|
|
19750
19707
|
};
|
|
@@ -19752,27 +19709,11 @@ var ResumeSaga = class extends Saga {
|
|
|
19752
19709
|
emptyResult() {
|
|
19753
19710
|
return {
|
|
19754
19711
|
conversation: [],
|
|
19755
|
-
latestSnapshot: null,
|
|
19756
19712
|
latestGitCheckpoint: null,
|
|
19757
19713
|
interrupted: false,
|
|
19758
19714
|
logEntryCount: 0
|
|
19759
19715
|
};
|
|
19760
19716
|
}
|
|
19761
|
-
findLatestTreeSnapshot(entries) {
|
|
19762
|
-
for (let i2 = entries.length - 1; i2 >= 0; i2--) {
|
|
19763
|
-
const entry = entries[i2];
|
|
19764
|
-
if (isNotification(
|
|
19765
|
-
entry.notification?.method,
|
|
19766
|
-
POSTHOG_NOTIFICATIONS.TREE_SNAPSHOT
|
|
19767
|
-
)) {
|
|
19768
|
-
const params = entry.notification.params;
|
|
19769
|
-
if (params?.treeHash) {
|
|
19770
|
-
return params;
|
|
19771
|
-
}
|
|
19772
|
-
}
|
|
19773
|
-
}
|
|
19774
|
-
return null;
|
|
19775
|
-
}
|
|
19776
19717
|
findLatestGitCheckpoint(entries) {
|
|
19777
19718
|
const sdkPrefixedMethod = `_${POSTHOG_NOTIFICATIONS.GIT_CHECKPOINT}`;
|
|
19778
19719
|
for (let i2 = entries.length - 1; i2 >= 0; i2--) {
|
|
@@ -19934,7 +19875,6 @@ async function resumeFromLog(config) {
|
|
|
19934
19875
|
}
|
|
19935
19876
|
return {
|
|
19936
19877
|
conversation: result.data.conversation,
|
|
19937
|
-
latestSnapshot: result.data.latestSnapshot,
|
|
19938
19878
|
latestGitCheckpoint: result.data.latestGitCheckpoint,
|
|
19939
19879
|
interrupted: result.data.interrupted,
|
|
19940
19880
|
lastDevice: result.data.lastDevice,
|
|
@@ -20322,544 +20262,6 @@ var SessionLogWriter = class _SessionLogWriter {
|
|
|
20322
20262
|
}
|
|
20323
20263
|
};
|
|
20324
20264
|
|
|
20325
|
-
// src/sagas/apply-snapshot-saga.ts
|
|
20326
|
-
import { mkdir as mkdir7, rm as rm6, writeFile as writeFile5 } from "fs/promises";
|
|
20327
|
-
import { join as join12 } from "path";
|
|
20328
|
-
|
|
20329
|
-
// ../git/dist/sagas/tree.js
|
|
20330
|
-
import { existsSync as existsSync5 } from "fs";
|
|
20331
|
-
import * as fs13 from "fs/promises";
|
|
20332
|
-
import * as path16 from "path";
|
|
20333
|
-
import * as tar from "tar";
|
|
20334
|
-
var CaptureTreeSaga = class extends GitSaga {
|
|
20335
|
-
sagaName = "CaptureTreeSaga";
|
|
20336
|
-
tempIndexPath = null;
|
|
20337
|
-
async executeGitOperations(input) {
|
|
20338
|
-
const { baseDir, lastTreeHash, archivePath, signal } = input;
|
|
20339
|
-
const tmpDir = path16.join(baseDir, ".git", "posthog-code-tmp");
|
|
20340
|
-
await this.step({
|
|
20341
|
-
name: "create_tmp_dir",
|
|
20342
|
-
execute: () => fs13.mkdir(tmpDir, { recursive: true }),
|
|
20343
|
-
rollback: async () => {
|
|
20344
|
-
}
|
|
20345
|
-
});
|
|
20346
|
-
this.tempIndexPath = path16.join(tmpDir, `index-${Date.now()}`);
|
|
20347
|
-
const tempIndexGit = this.git.env({
|
|
20348
|
-
...process.env,
|
|
20349
|
-
GIT_INDEX_FILE: this.tempIndexPath
|
|
20350
|
-
});
|
|
20351
|
-
await this.step({
|
|
20352
|
-
name: "init_temp_index",
|
|
20353
|
-
execute: () => tempIndexGit.raw(["read-tree", "HEAD"]),
|
|
20354
|
-
rollback: async () => {
|
|
20355
|
-
if (this.tempIndexPath) {
|
|
20356
|
-
await fs13.rm(this.tempIndexPath, { force: true }).catch(() => {
|
|
20357
|
-
});
|
|
20358
|
-
}
|
|
20359
|
-
}
|
|
20360
|
-
});
|
|
20361
|
-
await this.readOnlyStep("stage_files", () => tempIndexGit.raw(["add", "-A"]));
|
|
20362
|
-
const treeHash = await this.readOnlyStep("write_tree", () => tempIndexGit.raw(["write-tree"]));
|
|
20363
|
-
if (lastTreeHash && treeHash === lastTreeHash) {
|
|
20364
|
-
this.log.debug("No changes since last capture", { treeHash });
|
|
20365
|
-
await fs13.rm(this.tempIndexPath, { force: true }).catch(() => {
|
|
20366
|
-
});
|
|
20367
|
-
return { snapshot: null, changed: false };
|
|
20368
|
-
}
|
|
20369
|
-
const baseCommit = await this.readOnlyStep("get_base_commit", async () => {
|
|
20370
|
-
try {
|
|
20371
|
-
return await getHeadSha(baseDir, { abortSignal: signal });
|
|
20372
|
-
} catch {
|
|
20373
|
-
return null;
|
|
20374
|
-
}
|
|
20375
|
-
});
|
|
20376
|
-
const changes = await this.readOnlyStep("get_changes", () => this.getChanges(this.git, baseCommit, treeHash));
|
|
20377
|
-
await fs13.rm(this.tempIndexPath, { force: true }).catch(() => {
|
|
20378
|
-
});
|
|
20379
|
-
const snapshot = {
|
|
20380
|
-
treeHash,
|
|
20381
|
-
baseCommit,
|
|
20382
|
-
changes,
|
|
20383
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
20384
|
-
};
|
|
20385
|
-
let createdArchivePath;
|
|
20386
|
-
if (archivePath) {
|
|
20387
|
-
createdArchivePath = await this.createArchive(baseDir, archivePath, changes);
|
|
20388
|
-
}
|
|
20389
|
-
this.log.info("Tree captured", {
|
|
20390
|
-
treeHash,
|
|
20391
|
-
changes: changes.length,
|
|
20392
|
-
archived: !!createdArchivePath
|
|
20393
|
-
});
|
|
20394
|
-
return { snapshot, archivePath: createdArchivePath, changed: true };
|
|
20395
|
-
}
|
|
20396
|
-
async createArchive(baseDir, archivePath, changes) {
|
|
20397
|
-
const filesToArchive = changes.filter((c) => c.status !== "D").map((c) => c.path);
|
|
20398
|
-
if (filesToArchive.length === 0) {
|
|
20399
|
-
return void 0;
|
|
20400
|
-
}
|
|
20401
|
-
const existingFiles = filesToArchive.filter((f) => existsSync5(path16.join(baseDir, f)));
|
|
20402
|
-
if (existingFiles.length === 0) {
|
|
20403
|
-
return void 0;
|
|
20404
|
-
}
|
|
20405
|
-
await this.step({
|
|
20406
|
-
name: "create_archive",
|
|
20407
|
-
execute: async () => {
|
|
20408
|
-
const archiveDir = path16.dirname(archivePath);
|
|
20409
|
-
await fs13.mkdir(archiveDir, { recursive: true });
|
|
20410
|
-
await tar.create({
|
|
20411
|
-
gzip: true,
|
|
20412
|
-
file: archivePath,
|
|
20413
|
-
cwd: baseDir
|
|
20414
|
-
}, existingFiles);
|
|
20415
|
-
},
|
|
20416
|
-
rollback: async () => {
|
|
20417
|
-
await fs13.rm(archivePath, { force: true }).catch(() => {
|
|
20418
|
-
});
|
|
20419
|
-
}
|
|
20420
|
-
});
|
|
20421
|
-
return archivePath;
|
|
20422
|
-
}
|
|
20423
|
-
async getChanges(git, fromRef, toRef) {
|
|
20424
|
-
if (!fromRef) {
|
|
20425
|
-
const stdout2 = await git.raw(["ls-tree", "-r", "--name-only", toRef]);
|
|
20426
|
-
return stdout2.split("\n").filter((p) => p.trim()).map((p) => ({ path: p, status: "A" }));
|
|
20427
|
-
}
|
|
20428
|
-
const stdout = await git.raw([
|
|
20429
|
-
"diff-tree",
|
|
20430
|
-
"-r",
|
|
20431
|
-
"--name-status",
|
|
20432
|
-
fromRef,
|
|
20433
|
-
toRef
|
|
20434
|
-
]);
|
|
20435
|
-
const changes = [];
|
|
20436
|
-
for (const line of stdout.split("\n")) {
|
|
20437
|
-
if (!line.trim())
|
|
20438
|
-
continue;
|
|
20439
|
-
const [status, filePath] = line.split(" ");
|
|
20440
|
-
if (!filePath)
|
|
20441
|
-
continue;
|
|
20442
|
-
let normalizedStatus;
|
|
20443
|
-
if (status === "D") {
|
|
20444
|
-
normalizedStatus = "D";
|
|
20445
|
-
} else if (status === "A") {
|
|
20446
|
-
normalizedStatus = "A";
|
|
20447
|
-
} else {
|
|
20448
|
-
normalizedStatus = "M";
|
|
20449
|
-
}
|
|
20450
|
-
changes.push({ path: filePath, status: normalizedStatus });
|
|
20451
|
-
}
|
|
20452
|
-
return changes;
|
|
20453
|
-
}
|
|
20454
|
-
};
|
|
20455
|
-
var ApplyTreeSaga = class extends GitSaga {
|
|
20456
|
-
sagaName = "ApplyTreeSaga";
|
|
20457
|
-
originalHead = null;
|
|
20458
|
-
originalBranch = null;
|
|
20459
|
-
extractedFiles = [];
|
|
20460
|
-
fileBackups = /* @__PURE__ */ new Map();
|
|
20461
|
-
async executeGitOperations(input) {
|
|
20462
|
-
const { baseDir, treeHash, baseCommit, changes, archivePath } = input;
|
|
20463
|
-
const headInfo = await this.readOnlyStep("get_current_head", async () => {
|
|
20464
|
-
let head = null;
|
|
20465
|
-
let branch = null;
|
|
20466
|
-
try {
|
|
20467
|
-
head = await this.git.revparse(["HEAD"]);
|
|
20468
|
-
} catch {
|
|
20469
|
-
head = null;
|
|
20470
|
-
}
|
|
20471
|
-
try {
|
|
20472
|
-
branch = await this.git.raw(["symbolic-ref", "--short", "HEAD"]);
|
|
20473
|
-
} catch {
|
|
20474
|
-
branch = null;
|
|
20475
|
-
}
|
|
20476
|
-
return { head, branch };
|
|
20477
|
-
});
|
|
20478
|
-
this.originalHead = headInfo.head;
|
|
20479
|
-
this.originalBranch = headInfo.branch;
|
|
20480
|
-
let checkoutPerformed = false;
|
|
20481
|
-
if (baseCommit && baseCommit !== this.originalHead) {
|
|
20482
|
-
await this.readOnlyStep("check_working_tree", async () => {
|
|
20483
|
-
const status = await this.git.status();
|
|
20484
|
-
if (!status.isClean()) {
|
|
20485
|
-
const changedFiles = status.modified.length + status.staged.length + status.deleted.length;
|
|
20486
|
-
throw new Error(`Cannot apply tree: ${changedFiles} uncommitted change(s) exist. Commit or stash your changes first.`);
|
|
20487
|
-
}
|
|
20488
|
-
});
|
|
20489
|
-
await this.step({
|
|
20490
|
-
name: "checkout_base",
|
|
20491
|
-
execute: async () => {
|
|
20492
|
-
await this.git.checkout(baseCommit);
|
|
20493
|
-
checkoutPerformed = true;
|
|
20494
|
-
this.log.warn("Applied tree from different commit - now in detached HEAD state", {
|
|
20495
|
-
originalHead: this.originalHead,
|
|
20496
|
-
originalBranch: this.originalBranch,
|
|
20497
|
-
baseCommit
|
|
20498
|
-
});
|
|
20499
|
-
},
|
|
20500
|
-
rollback: async () => {
|
|
20501
|
-
try {
|
|
20502
|
-
if (this.originalBranch) {
|
|
20503
|
-
await this.git.checkout(this.originalBranch);
|
|
20504
|
-
} else if (this.originalHead) {
|
|
20505
|
-
await this.git.checkout(this.originalHead);
|
|
20506
|
-
}
|
|
20507
|
-
} catch (error) {
|
|
20508
|
-
this.log.warn("Failed to rollback checkout", { error });
|
|
20509
|
-
}
|
|
20510
|
-
}
|
|
20511
|
-
});
|
|
20512
|
-
}
|
|
20513
|
-
if (archivePath) {
|
|
20514
|
-
const filesToExtract = changes.filter((c) => c.status !== "D").map((c) => c.path);
|
|
20515
|
-
await this.readOnlyStep("backup_existing_files", async () => {
|
|
20516
|
-
for (const filePath of filesToExtract) {
|
|
20517
|
-
const fullPath = path16.join(baseDir, filePath);
|
|
20518
|
-
try {
|
|
20519
|
-
const content = await fs13.readFile(fullPath);
|
|
20520
|
-
this.fileBackups.set(filePath, content);
|
|
20521
|
-
} catch {
|
|
20522
|
-
}
|
|
20523
|
-
}
|
|
20524
|
-
});
|
|
20525
|
-
await this.step({
|
|
20526
|
-
name: "extract_archive",
|
|
20527
|
-
execute: async () => {
|
|
20528
|
-
await tar.extract({
|
|
20529
|
-
file: archivePath,
|
|
20530
|
-
cwd: baseDir
|
|
20531
|
-
});
|
|
20532
|
-
this.extractedFiles = filesToExtract;
|
|
20533
|
-
},
|
|
20534
|
-
rollback: async () => {
|
|
20535
|
-
for (const filePath of this.extractedFiles) {
|
|
20536
|
-
const fullPath = path16.join(baseDir, filePath);
|
|
20537
|
-
const backup = this.fileBackups.get(filePath);
|
|
20538
|
-
if (backup) {
|
|
20539
|
-
const dir = path16.dirname(fullPath);
|
|
20540
|
-
await fs13.mkdir(dir, { recursive: true }).catch(() => {
|
|
20541
|
-
});
|
|
20542
|
-
await fs13.writeFile(fullPath, backup).catch(() => {
|
|
20543
|
-
});
|
|
20544
|
-
} else {
|
|
20545
|
-
await fs13.rm(fullPath, { force: true }).catch(() => {
|
|
20546
|
-
});
|
|
20547
|
-
}
|
|
20548
|
-
}
|
|
20549
|
-
}
|
|
20550
|
-
});
|
|
20551
|
-
}
|
|
20552
|
-
for (const change of changes.filter((c) => c.status === "D")) {
|
|
20553
|
-
const fullPath = path16.join(baseDir, change.path);
|
|
20554
|
-
const backupContent = await this.readOnlyStep(`backup_${change.path}`, async () => {
|
|
20555
|
-
try {
|
|
20556
|
-
return await fs13.readFile(fullPath);
|
|
20557
|
-
} catch {
|
|
20558
|
-
return null;
|
|
20559
|
-
}
|
|
20560
|
-
});
|
|
20561
|
-
await this.step({
|
|
20562
|
-
name: `delete_${change.path}`,
|
|
20563
|
-
execute: async () => {
|
|
20564
|
-
await fs13.rm(fullPath, { force: true });
|
|
20565
|
-
this.log.debug(`Deleted file: ${change.path}`);
|
|
20566
|
-
},
|
|
20567
|
-
rollback: async () => {
|
|
20568
|
-
if (backupContent) {
|
|
20569
|
-
const dir = path16.dirname(fullPath);
|
|
20570
|
-
await fs13.mkdir(dir, { recursive: true }).catch(() => {
|
|
20571
|
-
});
|
|
20572
|
-
await fs13.writeFile(fullPath, backupContent).catch(() => {
|
|
20573
|
-
});
|
|
20574
|
-
}
|
|
20575
|
-
}
|
|
20576
|
-
});
|
|
20577
|
-
}
|
|
20578
|
-
const deletedCount = changes.filter((c) => c.status === "D").length;
|
|
20579
|
-
this.log.info("Tree applied", {
|
|
20580
|
-
treeHash,
|
|
20581
|
-
totalChanges: changes.length,
|
|
20582
|
-
deletedFiles: deletedCount,
|
|
20583
|
-
checkoutPerformed
|
|
20584
|
-
});
|
|
20585
|
-
return { treeHash, checkoutPerformed };
|
|
20586
|
-
}
|
|
20587
|
-
};
|
|
20588
|
-
|
|
20589
|
-
// src/sagas/apply-snapshot-saga.ts
|
|
20590
|
-
var ApplySnapshotSaga = class extends Saga {
|
|
20591
|
-
sagaName = "ApplySnapshotSaga";
|
|
20592
|
-
archivePath = null;
|
|
20593
|
-
async execute(input) {
|
|
20594
|
-
const { snapshot, repositoryPath, apiClient, taskId, runId } = input;
|
|
20595
|
-
const tmpDir = join12(repositoryPath, ".posthog", "tmp");
|
|
20596
|
-
if (!snapshot.archiveUrl) {
|
|
20597
|
-
throw new Error("Cannot apply snapshot: no archive URL");
|
|
20598
|
-
}
|
|
20599
|
-
const archiveUrl = snapshot.archiveUrl;
|
|
20600
|
-
await this.step({
|
|
20601
|
-
name: "create_tmp_dir",
|
|
20602
|
-
execute: () => mkdir7(tmpDir, { recursive: true }),
|
|
20603
|
-
rollback: async () => {
|
|
20604
|
-
}
|
|
20605
|
-
});
|
|
20606
|
-
const archivePath = join12(tmpDir, `${snapshot.treeHash}.tar.gz`);
|
|
20607
|
-
this.archivePath = archivePath;
|
|
20608
|
-
await this.step({
|
|
20609
|
-
name: "download_archive",
|
|
20610
|
-
execute: async () => {
|
|
20611
|
-
const arrayBuffer = await apiClient.downloadArtifact(
|
|
20612
|
-
taskId,
|
|
20613
|
-
runId,
|
|
20614
|
-
archiveUrl
|
|
20615
|
-
);
|
|
20616
|
-
if (!arrayBuffer) {
|
|
20617
|
-
throw new Error("Failed to download archive");
|
|
20618
|
-
}
|
|
20619
|
-
const base64Content = Buffer.from(arrayBuffer).toString("utf-8");
|
|
20620
|
-
const binaryContent = Buffer.from(base64Content, "base64");
|
|
20621
|
-
await writeFile5(archivePath, binaryContent);
|
|
20622
|
-
this.log.info("Tree archive downloaded", {
|
|
20623
|
-
treeHash: snapshot.treeHash,
|
|
20624
|
-
snapshotBytes: binaryContent.byteLength,
|
|
20625
|
-
snapshotWireBytes: arrayBuffer.byteLength,
|
|
20626
|
-
totalBytes: binaryContent.byteLength,
|
|
20627
|
-
totalWireBytes: arrayBuffer.byteLength
|
|
20628
|
-
});
|
|
20629
|
-
},
|
|
20630
|
-
rollback: async () => {
|
|
20631
|
-
if (this.archivePath) {
|
|
20632
|
-
await rm6(this.archivePath, { force: true }).catch(() => {
|
|
20633
|
-
});
|
|
20634
|
-
}
|
|
20635
|
-
}
|
|
20636
|
-
});
|
|
20637
|
-
const gitApplySaga = new ApplyTreeSaga(this.log);
|
|
20638
|
-
const applyResult = await gitApplySaga.run({
|
|
20639
|
-
baseDir: repositoryPath,
|
|
20640
|
-
treeHash: snapshot.treeHash,
|
|
20641
|
-
baseCommit: snapshot.baseCommit,
|
|
20642
|
-
changes: snapshot.changes,
|
|
20643
|
-
archivePath: this.archivePath
|
|
20644
|
-
});
|
|
20645
|
-
if (!applyResult.success) {
|
|
20646
|
-
throw new Error(`Failed to apply tree: ${applyResult.error}`);
|
|
20647
|
-
}
|
|
20648
|
-
await rm6(this.archivePath, { force: true }).catch(() => {
|
|
20649
|
-
});
|
|
20650
|
-
this.log.info("Tree snapshot applied", {
|
|
20651
|
-
treeHash: snapshot.treeHash,
|
|
20652
|
-
totalChanges: snapshot.changes.length,
|
|
20653
|
-
deletedFiles: snapshot.changes.filter((c) => c.status === "D").length
|
|
20654
|
-
});
|
|
20655
|
-
return { treeHash: snapshot.treeHash };
|
|
20656
|
-
}
|
|
20657
|
-
};
|
|
20658
|
-
|
|
20659
|
-
// src/sagas/capture-tree-saga.ts
|
|
20660
|
-
import { existsSync as existsSync6 } from "fs";
|
|
20661
|
-
import { readFile as readFile6, rm as rm7 } from "fs/promises";
|
|
20662
|
-
import { join as join13 } from "path";
|
|
20663
|
-
var CaptureTreeSaga2 = class extends Saga {
|
|
20664
|
-
sagaName = "CaptureTreeSaga";
|
|
20665
|
-
async execute(input) {
|
|
20666
|
-
const {
|
|
20667
|
-
repositoryPath,
|
|
20668
|
-
lastTreeHash,
|
|
20669
|
-
interrupted,
|
|
20670
|
-
apiClient,
|
|
20671
|
-
taskId,
|
|
20672
|
-
runId
|
|
20673
|
-
} = input;
|
|
20674
|
-
const tmpDir = join13(repositoryPath, ".posthog", "tmp");
|
|
20675
|
-
if (existsSync6(join13(repositoryPath, ".gitmodules"))) {
|
|
20676
|
-
this.log.warn(
|
|
20677
|
-
"Repository has submodules - snapshot may not capture submodule state"
|
|
20678
|
-
);
|
|
20679
|
-
}
|
|
20680
|
-
const shouldArchive = !!apiClient;
|
|
20681
|
-
const archivePath = shouldArchive ? join13(tmpDir, `tree-${Date.now()}.tar.gz`) : void 0;
|
|
20682
|
-
const gitCaptureSaga = new CaptureTreeSaga(this.log);
|
|
20683
|
-
const captureResult = await gitCaptureSaga.run({
|
|
20684
|
-
baseDir: repositoryPath,
|
|
20685
|
-
lastTreeHash,
|
|
20686
|
-
archivePath
|
|
20687
|
-
});
|
|
20688
|
-
if (!captureResult.success) {
|
|
20689
|
-
throw new Error(`Failed to capture tree: ${captureResult.error}`);
|
|
20690
|
-
}
|
|
20691
|
-
const {
|
|
20692
|
-
snapshot: gitSnapshot,
|
|
20693
|
-
archivePath: createdArchivePath,
|
|
20694
|
-
changed
|
|
20695
|
-
} = captureResult.data;
|
|
20696
|
-
if (!changed || !gitSnapshot) {
|
|
20697
|
-
this.log.debug("No changes since last capture", { lastTreeHash });
|
|
20698
|
-
return { snapshot: null, newTreeHash: lastTreeHash };
|
|
20699
|
-
}
|
|
20700
|
-
let archiveUrl;
|
|
20701
|
-
if (apiClient && createdArchivePath) {
|
|
20702
|
-
try {
|
|
20703
|
-
archiveUrl = await this.uploadArchive(
|
|
20704
|
-
createdArchivePath,
|
|
20705
|
-
gitSnapshot.treeHash,
|
|
20706
|
-
apiClient,
|
|
20707
|
-
taskId,
|
|
20708
|
-
runId
|
|
20709
|
-
);
|
|
20710
|
-
} finally {
|
|
20711
|
-
await rm7(createdArchivePath, { force: true }).catch(() => {
|
|
20712
|
-
});
|
|
20713
|
-
}
|
|
20714
|
-
}
|
|
20715
|
-
const snapshot = {
|
|
20716
|
-
treeHash: gitSnapshot.treeHash,
|
|
20717
|
-
baseCommit: gitSnapshot.baseCommit,
|
|
20718
|
-
changes: gitSnapshot.changes,
|
|
20719
|
-
timestamp: gitSnapshot.timestamp,
|
|
20720
|
-
interrupted,
|
|
20721
|
-
archiveUrl
|
|
20722
|
-
};
|
|
20723
|
-
this.log.info("Tree captured", {
|
|
20724
|
-
treeHash: snapshot.treeHash,
|
|
20725
|
-
changes: snapshot.changes.length,
|
|
20726
|
-
interrupted,
|
|
20727
|
-
archiveUrl
|
|
20728
|
-
});
|
|
20729
|
-
return { snapshot, newTreeHash: snapshot.treeHash };
|
|
20730
|
-
}
|
|
20731
|
-
async uploadArchive(archivePath, treeHash, apiClient, taskId, runId) {
|
|
20732
|
-
const archiveUrl = await this.step({
|
|
20733
|
-
name: "upload_archive",
|
|
20734
|
-
execute: async () => {
|
|
20735
|
-
const archiveContent = await readFile6(archivePath);
|
|
20736
|
-
const base64Content = archiveContent.toString("base64");
|
|
20737
|
-
const snapshotBytes = archiveContent.byteLength;
|
|
20738
|
-
const snapshotWireBytes = Buffer.byteLength(base64Content, "utf-8");
|
|
20739
|
-
const artifacts = await apiClient.uploadTaskArtifacts(taskId, runId, [
|
|
20740
|
-
{
|
|
20741
|
-
name: `trees/${treeHash}.tar.gz`,
|
|
20742
|
-
type: "tree_snapshot",
|
|
20743
|
-
content: base64Content,
|
|
20744
|
-
content_type: "application/gzip"
|
|
20745
|
-
}
|
|
20746
|
-
]);
|
|
20747
|
-
const uploadedArtifact = artifacts[0];
|
|
20748
|
-
if (uploadedArtifact?.storage_path) {
|
|
20749
|
-
this.log.info("Tree archive uploaded", {
|
|
20750
|
-
storagePath: uploadedArtifact.storage_path,
|
|
20751
|
-
treeHash,
|
|
20752
|
-
snapshotBytes,
|
|
20753
|
-
snapshotWireBytes,
|
|
20754
|
-
totalBytes: snapshotBytes,
|
|
20755
|
-
totalWireBytes: snapshotWireBytes
|
|
20756
|
-
});
|
|
20757
|
-
return uploadedArtifact.storage_path;
|
|
20758
|
-
}
|
|
20759
|
-
return void 0;
|
|
20760
|
-
},
|
|
20761
|
-
rollback: async () => {
|
|
20762
|
-
await rm7(archivePath, { force: true }).catch(() => {
|
|
20763
|
-
});
|
|
20764
|
-
}
|
|
20765
|
-
});
|
|
20766
|
-
return archiveUrl;
|
|
20767
|
-
}
|
|
20768
|
-
};
|
|
20769
|
-
|
|
20770
|
-
// src/tree-tracker.ts
|
|
20771
|
-
var TreeTracker = class {
|
|
20772
|
-
repositoryPath;
|
|
20773
|
-
taskId;
|
|
20774
|
-
runId;
|
|
20775
|
-
apiClient;
|
|
20776
|
-
logger;
|
|
20777
|
-
lastTreeHash = null;
|
|
20778
|
-
constructor(config) {
|
|
20779
|
-
this.repositoryPath = config.repositoryPath;
|
|
20780
|
-
this.taskId = config.taskId;
|
|
20781
|
-
this.runId = config.runId;
|
|
20782
|
-
this.apiClient = config.apiClient;
|
|
20783
|
-
this.logger = config.logger || new Logger({ debug: false, prefix: "[TreeTracker]" });
|
|
20784
|
-
}
|
|
20785
|
-
/**
|
|
20786
|
-
* Capture current working tree state as a snapshot.
|
|
20787
|
-
* Uses a temporary index to avoid modifying user's staging area.
|
|
20788
|
-
* Uses Saga pattern for atomic operation with automatic cleanup on failure.
|
|
20789
|
-
*/
|
|
20790
|
-
async captureTree(options) {
|
|
20791
|
-
const saga = new CaptureTreeSaga2(this.logger);
|
|
20792
|
-
const result = await saga.run({
|
|
20793
|
-
repositoryPath: this.repositoryPath,
|
|
20794
|
-
taskId: this.taskId,
|
|
20795
|
-
runId: this.runId,
|
|
20796
|
-
apiClient: this.apiClient,
|
|
20797
|
-
lastTreeHash: this.lastTreeHash,
|
|
20798
|
-
interrupted: options?.interrupted
|
|
20799
|
-
});
|
|
20800
|
-
if (!result.success) {
|
|
20801
|
-
this.logger.error("Failed to capture tree", {
|
|
20802
|
-
error: result.error,
|
|
20803
|
-
failedStep: result.failedStep
|
|
20804
|
-
});
|
|
20805
|
-
throw new Error(
|
|
20806
|
-
`Failed to capture tree at step '${result.failedStep}': ${result.error}`
|
|
20807
|
-
);
|
|
20808
|
-
}
|
|
20809
|
-
if (result.data.newTreeHash !== null) {
|
|
20810
|
-
this.lastTreeHash = result.data.newTreeHash;
|
|
20811
|
-
}
|
|
20812
|
-
return result.data.snapshot;
|
|
20813
|
-
}
|
|
20814
|
-
/**
|
|
20815
|
-
* Download and apply a tree snapshot.
|
|
20816
|
-
* Uses Saga pattern for atomic operation with rollback on failure.
|
|
20817
|
-
*/
|
|
20818
|
-
async applyTreeSnapshot(snapshot) {
|
|
20819
|
-
if (!this.apiClient) {
|
|
20820
|
-
throw new Error("Cannot apply snapshot: API client not configured");
|
|
20821
|
-
}
|
|
20822
|
-
if (!snapshot.archiveUrl) {
|
|
20823
|
-
this.logger.warn("Cannot apply snapshot: no archive URL", {
|
|
20824
|
-
treeHash: snapshot.treeHash,
|
|
20825
|
-
changes: snapshot.changes.length
|
|
20826
|
-
});
|
|
20827
|
-
throw new Error("Cannot apply snapshot: no archive URL");
|
|
20828
|
-
}
|
|
20829
|
-
const saga = new ApplySnapshotSaga(this.logger);
|
|
20830
|
-
const result = await saga.run({
|
|
20831
|
-
snapshot,
|
|
20832
|
-
repositoryPath: this.repositoryPath,
|
|
20833
|
-
apiClient: this.apiClient,
|
|
20834
|
-
taskId: this.taskId,
|
|
20835
|
-
runId: this.runId
|
|
20836
|
-
});
|
|
20837
|
-
if (!result.success) {
|
|
20838
|
-
this.logger.error("Failed to apply tree snapshot", {
|
|
20839
|
-
error: result.error,
|
|
20840
|
-
failedStep: result.failedStep,
|
|
20841
|
-
treeHash: snapshot.treeHash
|
|
20842
|
-
});
|
|
20843
|
-
throw new Error(
|
|
20844
|
-
`Failed to apply snapshot at step '${result.failedStep}': ${result.error}`
|
|
20845
|
-
);
|
|
20846
|
-
}
|
|
20847
|
-
this.lastTreeHash = result.data.treeHash;
|
|
20848
|
-
}
|
|
20849
|
-
/**
|
|
20850
|
-
* Get the last captured tree hash.
|
|
20851
|
-
*/
|
|
20852
|
-
getLastTreeHash() {
|
|
20853
|
-
return this.lastTreeHash;
|
|
20854
|
-
}
|
|
20855
|
-
/**
|
|
20856
|
-
* Set the last tree hash (used when resuming).
|
|
20857
|
-
*/
|
|
20858
|
-
setLastTreeHash(hash) {
|
|
20859
|
-
this.lastTreeHash = hash;
|
|
20860
|
-
}
|
|
20861
|
-
};
|
|
20862
|
-
|
|
20863
20265
|
// src/server/cloud-prompt.ts
|
|
20864
20266
|
function normalizeCloudPromptContent(content) {
|
|
20865
20267
|
if (typeof content === "string") {
|
|
@@ -21344,7 +20746,6 @@ var AgentServer = class {
|
|
|
21344
20746
|
});
|
|
21345
20747
|
this.logger.debug("Resume state loaded", {
|
|
21346
20748
|
conversationTurns: this.resumeState.conversation.length,
|
|
21347
|
-
hasSnapshot: !!this.resumeState.latestSnapshot,
|
|
21348
20749
|
hasGitCheckpoint: !!this.resumeState.latestGitCheckpoint,
|
|
21349
20750
|
gitCheckpointBranch: this.resumeState.latestGitCheckpoint?.branch ?? null,
|
|
21350
20751
|
logEntries: this.resumeState.logEntryCount
|
|
@@ -21590,13 +20991,6 @@ var AgentServer = class {
|
|
|
21590
20991
|
getApiKey: () => this.config.apiKey,
|
|
21591
20992
|
userAgent: `posthog/cloud.hog.dev; version: ${this.config.version ?? package_default.version}`
|
|
21592
20993
|
});
|
|
21593
|
-
const treeTracker = this.config.repositoryPath ? new TreeTracker({
|
|
21594
|
-
repositoryPath: this.config.repositoryPath,
|
|
21595
|
-
taskId: payload.task_id,
|
|
21596
|
-
runId: payload.run_id,
|
|
21597
|
-
apiClient: posthogAPI,
|
|
21598
|
-
logger: new Logger({ debug: true, prefix: "[TreeTracker]" })
|
|
21599
|
-
}) : null;
|
|
21600
20994
|
const logWriter = new SessionLogWriter({
|
|
21601
20995
|
posthogAPI,
|
|
21602
20996
|
logger: new Logger({ debug: true, prefix: "[SessionLogWriter]" })
|
|
@@ -21689,7 +21083,6 @@ var AgentServer = class {
|
|
|
21689
21083
|
acpSessionId,
|
|
21690
21084
|
acpConnection,
|
|
21691
21085
|
clientConnection,
|
|
21692
|
-
treeTracker,
|
|
21693
21086
|
sseController,
|
|
21694
21087
|
deviceInfo,
|
|
21695
21088
|
logWriter,
|
|
@@ -21816,31 +21209,7 @@ var AgentServer = class {
|
|
|
21816
21209
|
const conversationSummary = formatConversationForResume(
|
|
21817
21210
|
this.resumeState.conversation
|
|
21818
21211
|
);
|
|
21819
|
-
let
|
|
21820
|
-
if (this.resumeState.latestSnapshot?.archiveUrl && this.config.repositoryPath && this.posthogAPI) {
|
|
21821
|
-
try {
|
|
21822
|
-
const treeTracker = new TreeTracker({
|
|
21823
|
-
repositoryPath: this.config.repositoryPath,
|
|
21824
|
-
taskId: payload.task_id,
|
|
21825
|
-
runId: payload.run_id,
|
|
21826
|
-
apiClient: this.posthogAPI,
|
|
21827
|
-
logger: this.logger.child("TreeTracker")
|
|
21828
|
-
});
|
|
21829
|
-
await treeTracker.applyTreeSnapshot(this.resumeState.latestSnapshot);
|
|
21830
|
-
treeTracker.setLastTreeHash(this.resumeState.latestSnapshot.treeHash);
|
|
21831
|
-
snapshotApplied = true;
|
|
21832
|
-
this.logger.info("Tree snapshot applied", {
|
|
21833
|
-
treeHash: this.resumeState.latestSnapshot.treeHash,
|
|
21834
|
-
changes: this.resumeState.latestSnapshot.changes?.length ?? 0,
|
|
21835
|
-
hasArchiveUrl: !!this.resumeState.latestSnapshot.archiveUrl
|
|
21836
|
-
});
|
|
21837
|
-
} catch (error) {
|
|
21838
|
-
this.logger.warn("Failed to apply tree snapshot", {
|
|
21839
|
-
error: error instanceof Error ? error.message : String(error),
|
|
21840
|
-
treeHash: this.resumeState.latestSnapshot.treeHash
|
|
21841
|
-
});
|
|
21842
|
-
}
|
|
21843
|
-
}
|
|
21212
|
+
let checkpointApplied = false;
|
|
21844
21213
|
if (this.resumeState.latestGitCheckpoint && this.config.repositoryPath && this.posthogAPI) {
|
|
21845
21214
|
try {
|
|
21846
21215
|
const checkpointTracker = new HandoffCheckpointTracker({
|
|
@@ -21853,6 +21222,7 @@ var AgentServer = class {
|
|
|
21853
21222
|
const metrics = await checkpointTracker.applyFromHandoff(
|
|
21854
21223
|
this.resumeState.latestGitCheckpoint
|
|
21855
21224
|
);
|
|
21225
|
+
checkpointApplied = true;
|
|
21856
21226
|
this.logger.info("Git checkpoint applied", {
|
|
21857
21227
|
branch: this.resumeState.latestGitCheckpoint.branch,
|
|
21858
21228
|
head: this.resumeState.latestGitCheckpoint.head,
|
|
@@ -21868,7 +21238,7 @@ var AgentServer = class {
|
|
|
21868
21238
|
}
|
|
21869
21239
|
}
|
|
21870
21240
|
const pendingUserPrompt = await this.getPendingUserPrompt(taskRun);
|
|
21871
|
-
const sandboxContext =
|
|
21241
|
+
const sandboxContext = checkpointApplied ? `The workspace environment (all files, packages, and code changes) has been fully restored from the latest checkpoint.` : `The workspace from the previous session was not restored from a checkpoint, so you are starting with a fresh environment. Your conversation history is fully preserved below.`;
|
|
21872
21242
|
let resumePromptBlocks;
|
|
21873
21243
|
if (pendingUserPrompt?.length) {
|
|
21874
21244
|
resumePromptBlocks = [
|
|
@@ -21909,7 +21279,7 @@ Continue from where you left off. The user is waiting for your response.`
|
|
|
21909
21279
|
conversationTurns: this.resumeState.conversation.length,
|
|
21910
21280
|
promptLength: promptBlocksToText(resumePromptBlocks).length,
|
|
21911
21281
|
hasPendingUserMessage: !!pendingUserPrompt?.length,
|
|
21912
|
-
|
|
21282
|
+
checkpointApplied,
|
|
21913
21283
|
hasGitCheckpoint: !!this.resumeState.latestGitCheckpoint,
|
|
21914
21284
|
gitCheckpointBranch: this.resumeState.latestGitCheckpoint?.branch ?? null
|
|
21915
21285
|
});
|
|
@@ -22055,16 +21425,16 @@ Continue from where you left off. The user is waiting for your response.`
|
|
|
22055
21425
|
throw new Error(`Failed to download artifact ${artifact.name}`);
|
|
22056
21426
|
}
|
|
22057
21427
|
const safeName = this.getSafeArtifactName(artifact.name);
|
|
22058
|
-
const artifactDir =
|
|
21428
|
+
const artifactDir = join11(
|
|
22059
21429
|
this.config.repositoryPath ?? "/tmp/workspace",
|
|
22060
21430
|
".posthog",
|
|
22061
21431
|
"attachments",
|
|
22062
21432
|
runId,
|
|
22063
21433
|
artifact.id ?? safeName
|
|
22064
21434
|
);
|
|
22065
|
-
await
|
|
22066
|
-
const artifactPath =
|
|
22067
|
-
await
|
|
21435
|
+
await mkdir4(artifactDir, { recursive: true });
|
|
21436
|
+
const artifactPath = join11(artifactDir, safeName);
|
|
21437
|
+
await writeFile4(artifactPath, Buffer.from(data));
|
|
22068
21438
|
return resourceLink(pathToFileURL(artifactPath).toString(), artifact.name, {
|
|
22069
21439
|
...artifact.content_type ? { mimeType: artifact.content_type } : {},
|
|
22070
21440
|
...typeof artifact.size === "number" ? { size: artifact.size } : {}
|
|
@@ -22419,8 +21789,8 @@ ${attributionInstructions}
|
|
|
22419
21789
|
const meta = params.update?._meta?.claudeCode;
|
|
22420
21790
|
const toolName = meta?.toolName;
|
|
22421
21791
|
const toolResponse = meta?.toolResponse;
|
|
22422
|
-
if ((toolName === "Write" || toolName === "Edit") && toolResponse?.filePath) {
|
|
22423
|
-
await this.
|
|
21792
|
+
if ((toolName === "Write" || toolName === "Edit" || toolName === "MultiEdit" || toolName === "Delete" || toolName === "Move") && toolResponse?.filePath) {
|
|
21793
|
+
await this.captureCheckpointState();
|
|
22424
21794
|
}
|
|
22425
21795
|
if (toolName && (toolName.includes("Bash") || toolName.includes("bash"))) {
|
|
22426
21796
|
this.detectAndAttachPrUrl(payload, params.update);
|
|
@@ -22582,14 +21952,9 @@ ${attributionInstructions}
|
|
|
22582
21952
|
if (!this.session) return;
|
|
22583
21953
|
this.logger.debug("Cleaning up session");
|
|
22584
21954
|
try {
|
|
22585
|
-
await this.
|
|
22586
|
-
} catch (error) {
|
|
22587
|
-
this.logger.error("Failed to capture handoff checkpoint", error);
|
|
22588
|
-
}
|
|
22589
|
-
try {
|
|
22590
|
-
await this.captureTreeState();
|
|
21955
|
+
await this.captureCheckpointState(this.session.pendingHandoffGitState);
|
|
22591
21956
|
} catch (error) {
|
|
22592
|
-
this.logger.error("Failed to capture final
|
|
21957
|
+
this.logger.error("Failed to capture final checkpoint state", error);
|
|
22593
21958
|
}
|
|
22594
21959
|
try {
|
|
22595
21960
|
await this.session.logWriter.flush(this.session.payload.run_id, {
|
|
@@ -22617,41 +21982,13 @@ ${attributionInstructions}
|
|
|
22617
21982
|
this.lastReportedBranch = null;
|
|
22618
21983
|
this.session = null;
|
|
22619
21984
|
}
|
|
22620
|
-
async
|
|
22621
|
-
if (!this.session
|
|
22622
|
-
try {
|
|
22623
|
-
const snapshot = await this.session.treeTracker.captureTree({});
|
|
22624
|
-
if (snapshot) {
|
|
22625
|
-
const snapshotWithDevice = {
|
|
22626
|
-
...snapshot,
|
|
22627
|
-
device: this.session.deviceInfo
|
|
22628
|
-
};
|
|
22629
|
-
const notification = {
|
|
22630
|
-
jsonrpc: "2.0",
|
|
22631
|
-
method: POSTHOG_NOTIFICATIONS.TREE_SNAPSHOT,
|
|
22632
|
-
params: snapshotWithDevice
|
|
22633
|
-
};
|
|
22634
|
-
this.broadcastEvent({
|
|
22635
|
-
type: "notification",
|
|
22636
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
22637
|
-
notification
|
|
22638
|
-
});
|
|
22639
|
-
this.session.logWriter.appendRawLine(
|
|
22640
|
-
this.session.payload.run_id,
|
|
22641
|
-
JSON.stringify(notification)
|
|
22642
|
-
);
|
|
22643
|
-
}
|
|
22644
|
-
} catch (error) {
|
|
22645
|
-
this.logger.error("Failed to capture tree state", error);
|
|
22646
|
-
}
|
|
22647
|
-
}
|
|
22648
|
-
async captureHandoffCheckpoint() {
|
|
22649
|
-
if (!this.session?.treeTracker || !this.session.pendingHandoffGitState) {
|
|
21985
|
+
async captureCheckpointState(localGitState) {
|
|
21986
|
+
if (!this.session || !this.config.repositoryPath) {
|
|
22650
21987
|
return;
|
|
22651
21988
|
}
|
|
22652
21989
|
if (!this.posthogAPI) {
|
|
22653
21990
|
this.logger.warn(
|
|
22654
|
-
"Skipping
|
|
21991
|
+
"Skipping checkpoint capture: PostHog API client is not configured"
|
|
22655
21992
|
);
|
|
22656
21993
|
return;
|
|
22657
21994
|
}
|
|
@@ -22662,9 +21999,7 @@ ${attributionInstructions}
|
|
|
22662
21999
|
apiClient: this.posthogAPI,
|
|
22663
22000
|
logger: this.logger.child("HandoffCheckpoint")
|
|
22664
22001
|
});
|
|
22665
|
-
const checkpoint = await tracker.captureForHandoff(
|
|
22666
|
-
this.session.pendingHandoffGitState
|
|
22667
|
-
);
|
|
22002
|
+
const checkpoint = await tracker.captureForHandoff(localGitState);
|
|
22668
22003
|
if (!checkpoint) return;
|
|
22669
22004
|
const checkpointWithDevice = {
|
|
22670
22005
|
...checkpoint,
|