@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
package/dist/server/bin.cjs
CHANGED
|
@@ -805,10 +805,10 @@ var require_src2 = __commonJS({
|
|
|
805
805
|
var fs_1 = require("fs");
|
|
806
806
|
var debug_1 = __importDefault(require_src());
|
|
807
807
|
var log = debug_1.default("@kwsites/file-exists");
|
|
808
|
-
function check(
|
|
809
|
-
log(`checking %s`,
|
|
808
|
+
function check(path16, isFile2, isDirectory) {
|
|
809
|
+
log(`checking %s`, path16);
|
|
810
810
|
try {
|
|
811
|
-
const stat4 = fs_1.statSync(
|
|
811
|
+
const stat4 = fs_1.statSync(path16);
|
|
812
812
|
if (stat4.isFile() && isFile2) {
|
|
813
813
|
log(`[OK] path represents a file`);
|
|
814
814
|
return true;
|
|
@@ -828,8 +828,8 @@ var require_src2 = __commonJS({
|
|
|
828
828
|
throw e;
|
|
829
829
|
}
|
|
830
830
|
}
|
|
831
|
-
function exists2(
|
|
832
|
-
return check(
|
|
831
|
+
function exists2(path16, type = exports2.READABLE) {
|
|
832
|
+
return check(path16, (type & exports2.FILE) > 0, (type & exports2.FOLDER) > 0);
|
|
833
833
|
}
|
|
834
834
|
exports2.exists = exists2;
|
|
835
835
|
exports2.FILE = 1;
|
|
@@ -925,11 +925,11 @@ var require_tree_sitter = __commonJS({
|
|
|
925
925
|
throw toThrow;
|
|
926
926
|
};
|
|
927
927
|
var scriptDirectory = "";
|
|
928
|
-
function locateFile(
|
|
928
|
+
function locateFile(path16) {
|
|
929
929
|
if (Module["locateFile"]) {
|
|
930
|
-
return Module["locateFile"](
|
|
930
|
+
return Module["locateFile"](path16, scriptDirectory);
|
|
931
931
|
}
|
|
932
|
-
return scriptDirectory +
|
|
932
|
+
return scriptDirectory + path16;
|
|
933
933
|
}
|
|
934
934
|
var readAsync, readBinary;
|
|
935
935
|
if (ENVIRONMENT_IS_NODE) {
|
|
@@ -3450,8 +3450,8 @@ var require_tree_sitter = __commonJS({
|
|
|
3450
3450
|
} else {
|
|
3451
3451
|
const url = input;
|
|
3452
3452
|
if (typeof process !== "undefined" && process.versions && process.versions.node) {
|
|
3453
|
-
const
|
|
3454
|
-
bytes = Promise.resolve(
|
|
3453
|
+
const fs13 = require("fs");
|
|
3454
|
+
bytes = Promise.resolve(fs13.readFileSync(url));
|
|
3455
3455
|
} else {
|
|
3456
3456
|
bytes = fetch(url).then((response) => response.arrayBuffer().then((buffer) => {
|
|
3457
3457
|
if (response.ok) {
|
|
@@ -3912,8 +3912,8 @@ function isSupportedReasoningEffort(adapter, modelId, value) {
|
|
|
3912
3912
|
}
|
|
3913
3913
|
|
|
3914
3914
|
// src/server/agent-server.ts
|
|
3915
|
-
var
|
|
3916
|
-
var
|
|
3915
|
+
var import_promises5 = require("fs/promises");
|
|
3916
|
+
var import_node_path8 = require("path");
|
|
3917
3917
|
var import_node_url2 = require("url");
|
|
3918
3918
|
var import_sdk5 = require("@agentclientprotocol/sdk");
|
|
3919
3919
|
var import_node_server = require("@hono/node-server");
|
|
@@ -3959,8 +3959,8 @@ function pathspec(...paths) {
|
|
|
3959
3959
|
cache.set(key, paths);
|
|
3960
3960
|
return key;
|
|
3961
3961
|
}
|
|
3962
|
-
function isPathSpec(
|
|
3963
|
-
return
|
|
3962
|
+
function isPathSpec(path16) {
|
|
3963
|
+
return path16 instanceof String && cache.has(path16);
|
|
3964
3964
|
}
|
|
3965
3965
|
function toPaths(pathSpec) {
|
|
3966
3966
|
return cache.get(pathSpec) || [];
|
|
@@ -4049,8 +4049,8 @@ function toLinesWithContent(input = "", trimmed2 = true, separator = "\n") {
|
|
|
4049
4049
|
function forEachLineWithContent(input, callback) {
|
|
4050
4050
|
return toLinesWithContent(input, true).map((line) => callback(line));
|
|
4051
4051
|
}
|
|
4052
|
-
function folderExists(
|
|
4053
|
-
return (0, import_file_exists.exists)(
|
|
4052
|
+
function folderExists(path16) {
|
|
4053
|
+
return (0, import_file_exists.exists)(path16, import_file_exists.FOLDER);
|
|
4054
4054
|
}
|
|
4055
4055
|
function append(target, item) {
|
|
4056
4056
|
if (Array.isArray(target)) {
|
|
@@ -4454,8 +4454,8 @@ function checkIsRepoRootTask() {
|
|
|
4454
4454
|
commands,
|
|
4455
4455
|
format: "utf-8",
|
|
4456
4456
|
onError,
|
|
4457
|
-
parser(
|
|
4458
|
-
return /^\.(git)?$/.test(
|
|
4457
|
+
parser(path16) {
|
|
4458
|
+
return /^\.(git)?$/.test(path16.trim());
|
|
4459
4459
|
}
|
|
4460
4460
|
};
|
|
4461
4461
|
}
|
|
@@ -4889,11 +4889,11 @@ function parseGrep(grep) {
|
|
|
4889
4889
|
const paths = /* @__PURE__ */ new Set();
|
|
4890
4890
|
const results = {};
|
|
4891
4891
|
forEachLineWithContent(grep, (input) => {
|
|
4892
|
-
const [
|
|
4893
|
-
paths.add(
|
|
4894
|
-
(results[
|
|
4892
|
+
const [path16, line, preview] = input.split(NULL);
|
|
4893
|
+
paths.add(path16);
|
|
4894
|
+
(results[path16] = results[path16] || []).push({
|
|
4895
4895
|
line: asNumber(line),
|
|
4896
|
-
path:
|
|
4896
|
+
path: path16,
|
|
4897
4897
|
preview
|
|
4898
4898
|
});
|
|
4899
4899
|
});
|
|
@@ -5658,14 +5658,14 @@ var init_hash_object = __esm({
|
|
|
5658
5658
|
init_task();
|
|
5659
5659
|
}
|
|
5660
5660
|
});
|
|
5661
|
-
function parseInit(bare,
|
|
5661
|
+
function parseInit(bare, path16, text2) {
|
|
5662
5662
|
const response = String(text2).trim();
|
|
5663
5663
|
let result;
|
|
5664
5664
|
if (result = initResponseRegex.exec(response)) {
|
|
5665
|
-
return new InitSummary(bare,
|
|
5665
|
+
return new InitSummary(bare, path16, false, result[1]);
|
|
5666
5666
|
}
|
|
5667
5667
|
if (result = reInitResponseRegex.exec(response)) {
|
|
5668
|
-
return new InitSummary(bare,
|
|
5668
|
+
return new InitSummary(bare, path16, true, result[1]);
|
|
5669
5669
|
}
|
|
5670
5670
|
let gitDir = "";
|
|
5671
5671
|
const tokens = response.split(" ");
|
|
@@ -5676,7 +5676,7 @@ function parseInit(bare, path17, text2) {
|
|
|
5676
5676
|
break;
|
|
5677
5677
|
}
|
|
5678
5678
|
}
|
|
5679
|
-
return new InitSummary(bare,
|
|
5679
|
+
return new InitSummary(bare, path16, /^re/i.test(response), gitDir);
|
|
5680
5680
|
}
|
|
5681
5681
|
var InitSummary;
|
|
5682
5682
|
var initResponseRegex;
|
|
@@ -5685,9 +5685,9 @@ var init_InitSummary = __esm({
|
|
|
5685
5685
|
"src/lib/responses/InitSummary.ts"() {
|
|
5686
5686
|
"use strict";
|
|
5687
5687
|
InitSummary = class {
|
|
5688
|
-
constructor(bare,
|
|
5688
|
+
constructor(bare, path16, existing, gitDir) {
|
|
5689
5689
|
this.bare = bare;
|
|
5690
|
-
this.path =
|
|
5690
|
+
this.path = path16;
|
|
5691
5691
|
this.existing = existing;
|
|
5692
5692
|
this.gitDir = gitDir;
|
|
5693
5693
|
}
|
|
@@ -5699,7 +5699,7 @@ var init_InitSummary = __esm({
|
|
|
5699
5699
|
function hasBareCommand(command) {
|
|
5700
5700
|
return command.includes(bareCommand);
|
|
5701
5701
|
}
|
|
5702
|
-
function initTask(bare = false,
|
|
5702
|
+
function initTask(bare = false, path16, customArgs) {
|
|
5703
5703
|
const commands = ["init", ...customArgs];
|
|
5704
5704
|
if (bare && !hasBareCommand(commands)) {
|
|
5705
5705
|
commands.splice(1, 0, bareCommand);
|
|
@@ -5708,7 +5708,7 @@ function initTask(bare = false, path17, customArgs) {
|
|
|
5708
5708
|
commands,
|
|
5709
5709
|
format: "utf-8",
|
|
5710
5710
|
parser(text2) {
|
|
5711
|
-
return parseInit(commands.includes("--bare"),
|
|
5711
|
+
return parseInit(commands.includes("--bare"), path16, text2);
|
|
5712
5712
|
}
|
|
5713
5713
|
};
|
|
5714
5714
|
}
|
|
@@ -6524,12 +6524,12 @@ var init_FileStatusSummary = __esm({
|
|
|
6524
6524
|
"use strict";
|
|
6525
6525
|
fromPathRegex = /^(.+)\0(.+)$/;
|
|
6526
6526
|
FileStatusSummary = class {
|
|
6527
|
-
constructor(
|
|
6528
|
-
this.path =
|
|
6527
|
+
constructor(path16, index, working_dir) {
|
|
6528
|
+
this.path = path16;
|
|
6529
6529
|
this.index = index;
|
|
6530
6530
|
this.working_dir = working_dir;
|
|
6531
6531
|
if (index === "R" || working_dir === "R") {
|
|
6532
|
-
const detail = fromPathRegex.exec(
|
|
6532
|
+
const detail = fromPathRegex.exec(path16) || [null, path16, path16];
|
|
6533
6533
|
this.from = detail[2] || "";
|
|
6534
6534
|
this.path = detail[1] || "";
|
|
6535
6535
|
}
|
|
@@ -6560,14 +6560,14 @@ function splitLine(result, lineStr) {
|
|
|
6560
6560
|
default:
|
|
6561
6561
|
return;
|
|
6562
6562
|
}
|
|
6563
|
-
function data(index, workingDir,
|
|
6563
|
+
function data(index, workingDir, path16) {
|
|
6564
6564
|
const raw = `${index}${workingDir}`;
|
|
6565
6565
|
const handler = parsers6.get(raw);
|
|
6566
6566
|
if (handler) {
|
|
6567
|
-
handler(result,
|
|
6567
|
+
handler(result, path16);
|
|
6568
6568
|
}
|
|
6569
6569
|
if (raw !== "##" && raw !== "!!") {
|
|
6570
|
-
result.files.push(new FileStatusSummary(
|
|
6570
|
+
result.files.push(new FileStatusSummary(path16, index, workingDir));
|
|
6571
6571
|
}
|
|
6572
6572
|
}
|
|
6573
6573
|
}
|
|
@@ -6880,9 +6880,9 @@ var init_simple_git_api = __esm({
|
|
|
6880
6880
|
next
|
|
6881
6881
|
);
|
|
6882
6882
|
}
|
|
6883
|
-
hashObject(
|
|
6883
|
+
hashObject(path16, write) {
|
|
6884
6884
|
return this._runTask(
|
|
6885
|
-
hashObjectTask(
|
|
6885
|
+
hashObjectTask(path16, write === true),
|
|
6886
6886
|
trailingFunctionArgument(arguments)
|
|
6887
6887
|
);
|
|
6888
6888
|
}
|
|
@@ -7235,8 +7235,8 @@ var init_branch = __esm({
|
|
|
7235
7235
|
}
|
|
7236
7236
|
});
|
|
7237
7237
|
function toPath(input) {
|
|
7238
|
-
const
|
|
7239
|
-
return
|
|
7238
|
+
const path16 = input.trim().replace(/^["']|["']$/g, "");
|
|
7239
|
+
return path16 && (0, import_node_path.normalize)(path16);
|
|
7240
7240
|
}
|
|
7241
7241
|
var parseCheckIgnore;
|
|
7242
7242
|
var init_CheckIgnore = __esm({
|
|
@@ -7550,8 +7550,8 @@ __export(sub_module_exports, {
|
|
|
7550
7550
|
subModuleTask: () => subModuleTask,
|
|
7551
7551
|
updateSubModuleTask: () => updateSubModuleTask
|
|
7552
7552
|
});
|
|
7553
|
-
function addSubModuleTask(repo,
|
|
7554
|
-
return subModuleTask(["add", repo,
|
|
7553
|
+
function addSubModuleTask(repo, path16) {
|
|
7554
|
+
return subModuleTask(["add", repo, path16]);
|
|
7555
7555
|
}
|
|
7556
7556
|
function initSubModuleTask(customArgs) {
|
|
7557
7557
|
return subModuleTask(["init", ...customArgs]);
|
|
@@ -7881,8 +7881,8 @@ var require_git = __commonJS2({
|
|
|
7881
7881
|
}
|
|
7882
7882
|
return this._runTask(straightThroughStringTask2(command, this._trimmed), next);
|
|
7883
7883
|
};
|
|
7884
|
-
Git2.prototype.submoduleAdd = function(repo,
|
|
7885
|
-
return this._runTask(addSubModuleTask2(repo,
|
|
7884
|
+
Git2.prototype.submoduleAdd = function(repo, path16, then) {
|
|
7885
|
+
return this._runTask(addSubModuleTask2(repo, path16), trailingFunctionArgument2(arguments));
|
|
7886
7886
|
};
|
|
7887
7887
|
Git2.prototype.submoduleUpdate = function(args2, then) {
|
|
7888
7888
|
return this._runTask(
|
|
@@ -8715,12 +8715,6 @@ async function listWorktrees(baseDir, options) {
|
|
|
8715
8715
|
return worktrees;
|
|
8716
8716
|
}, { signal: options?.abortSignal });
|
|
8717
8717
|
}
|
|
8718
|
-
async function getHeadSha(baseDir, options) {
|
|
8719
|
-
const manager = getGitOperationManager();
|
|
8720
|
-
return manager.executeRead(baseDir, (git) => git.revparse(["HEAD"]), {
|
|
8721
|
-
signal: options?.abortSignal
|
|
8722
|
-
});
|
|
8723
|
-
}
|
|
8724
8718
|
|
|
8725
8719
|
// src/server/agent-server.ts
|
|
8726
8720
|
var import_hono = require("hono");
|
|
@@ -8729,7 +8723,7 @@ var import_zod3 = require("zod");
|
|
|
8729
8723
|
// package.json
|
|
8730
8724
|
var package_default = {
|
|
8731
8725
|
name: "@posthog/agent",
|
|
8732
|
-
version: "2.3.
|
|
8726
|
+
version: "2.3.403",
|
|
8733
8727
|
repository: "https://github.com/PostHog/code",
|
|
8734
8728
|
description: "TypeScript agent framework wrapping Claude Agent SDK with Git-based task execution for PostHog",
|
|
8735
8729
|
exports: {
|
|
@@ -8797,10 +8791,6 @@ var package_default = {
|
|
|
8797
8791
|
types: "./dist/handoff-checkpoint.d.ts",
|
|
8798
8792
|
import: "./dist/handoff-checkpoint.js"
|
|
8799
8793
|
},
|
|
8800
|
-
"./tree-tracker": {
|
|
8801
|
-
types: "./dist/tree-tracker.d.ts",
|
|
8802
|
-
import: "./dist/tree-tracker.js"
|
|
8803
|
-
},
|
|
8804
8794
|
"./server": {
|
|
8805
8795
|
types: "./dist/server/agent-server.d.ts",
|
|
8806
8796
|
import: "./dist/server/agent-server.js"
|
|
@@ -8896,8 +8886,6 @@ var POSTHOG_NOTIFICATIONS = {
|
|
|
8896
8886
|
CONSOLE: "_posthog/console",
|
|
8897
8887
|
/** Maps taskRunId to agent's sessionId and adapter type (for resumption) */
|
|
8898
8888
|
SDK_SESSION: "_posthog/sdk_session",
|
|
8899
|
-
/** Tree state snapshot captured (git tree hash + file archive) */
|
|
8900
|
-
TREE_SNAPSHOT: "_posthog/tree_snapshot",
|
|
8901
8889
|
/** Git checkpoint captured for handoff */
|
|
8902
8890
|
GIT_CHECKPOINT: "_posthog/git_checkpoint",
|
|
8903
8891
|
/** Agent mode changed (interactive/background) */
|
|
@@ -8936,9 +8924,6 @@ function matchesExt(method, expected) {
|
|
|
8936
8924
|
if (!method) return false;
|
|
8937
8925
|
return method === expected || method === `_${expected}`;
|
|
8938
8926
|
}
|
|
8939
|
-
function isNotification(method, expected) {
|
|
8940
|
-
return matchesExt(method, expected);
|
|
8941
|
-
}
|
|
8942
8927
|
function isMethod(method, expected) {
|
|
8943
8928
|
return matchesExt(method, expected);
|
|
8944
8929
|
}
|
|
@@ -13569,8 +13554,8 @@ var ToolContentBuilder = class {
|
|
|
13569
13554
|
this.items.push({ type: "content", content: image(data, mimeType, uri) });
|
|
13570
13555
|
return this;
|
|
13571
13556
|
}
|
|
13572
|
-
diff(
|
|
13573
|
-
this.items.push({ type: "diff", path:
|
|
13557
|
+
diff(path16, oldText, newText) {
|
|
13558
|
+
this.items.push({ type: "diff", path: path16, oldText, newText });
|
|
13574
13559
|
return this;
|
|
13575
13560
|
}
|
|
13576
13561
|
build() {
|
|
@@ -18453,11 +18438,13 @@ function createCodexConnection(config) {
|
|
|
18453
18438
|
|
|
18454
18439
|
// src/handoff-checkpoint.ts
|
|
18455
18440
|
var import_promises3 = require("fs/promises");
|
|
18441
|
+
var import_node_os2 = require("os");
|
|
18456
18442
|
var import_node_path6 = require("path");
|
|
18457
18443
|
|
|
18458
18444
|
// ../git/dist/handoff.js
|
|
18459
18445
|
var import_node_child_process4 = require("child_process");
|
|
18460
18446
|
var import_promises2 = require("fs/promises");
|
|
18447
|
+
var import_node_os = require("os");
|
|
18461
18448
|
var import_node_path5 = __toESM(require("path"), 1);
|
|
18462
18449
|
|
|
18463
18450
|
// ../git/dist/sagas/checkpoint.js
|
|
@@ -18865,7 +18852,7 @@ var GitHandoffTracker = class {
|
|
|
18865
18852
|
this.repositoryPath = config.repositoryPath;
|
|
18866
18853
|
this.logger = config.logger;
|
|
18867
18854
|
}
|
|
18868
|
-
async captureForHandoff(
|
|
18855
|
+
async captureForHandoff(_localGitState) {
|
|
18869
18856
|
const captureSaga = new CaptureCheckpointSaga(this.logger);
|
|
18870
18857
|
const result = await captureSaga.run({ baseDir: this.repositoryPath });
|
|
18871
18858
|
if (!result.success) {
|
|
@@ -18873,15 +18860,19 @@ var GitHandoffTracker = class {
|
|
|
18873
18860
|
}
|
|
18874
18861
|
const checkpoint = result.data;
|
|
18875
18862
|
const git = createGitClient(this.repositoryPath);
|
|
18876
|
-
const tempDir = await this.
|
|
18863
|
+
const tempDir = await this.createTempDir(checkpoint.checkpointId);
|
|
18877
18864
|
const checkpointRef = `${CHECKPOINT_REF_PREFIX2}${checkpoint.checkpointId}`;
|
|
18878
|
-
const
|
|
18879
|
-
|
|
18865
|
+
const packRefs = [
|
|
18866
|
+
checkpoint.head,
|
|
18867
|
+
checkpoint.indexTree,
|
|
18868
|
+
checkpoint.worktreeTree
|
|
18869
|
+
].filter((ref) => !!ref);
|
|
18870
|
+
const headRef = checkpoint.head ? `${HANDOFF_HEAD_REF_PREFIX}${checkpoint.checkpointId}` : void 0;
|
|
18880
18871
|
const packPrefix = import_node_path5.default.join(tempDir, checkpoint.checkpointId);
|
|
18881
18872
|
try {
|
|
18882
18873
|
const [headPack, indexFile, tracking] = await Promise.all([
|
|
18883
|
-
|
|
18884
|
-
this.copyIndexFile(git, checkpoint.checkpointId),
|
|
18874
|
+
this.captureObjectPack(packPrefix, packRefs),
|
|
18875
|
+
this.copyIndexFile(git, checkpoint.checkpointId, tempDir),
|
|
18885
18876
|
getTrackingMetadata(git, checkpoint.branch)
|
|
18886
18877
|
]);
|
|
18887
18878
|
return {
|
|
@@ -18928,6 +18919,8 @@ var GitHandoffTracker = class {
|
|
|
18928
18919
|
} else if (checkpoint.head) {
|
|
18929
18920
|
await git.checkout(checkpoint.head);
|
|
18930
18921
|
}
|
|
18922
|
+
await git.clean(["f", "d"]);
|
|
18923
|
+
await git.raw(["read-tree", "--reset", "-u", checkpoint.worktreeTree]);
|
|
18931
18924
|
if (indexPath) {
|
|
18932
18925
|
await this.restoreIndexFile(git, indexPath);
|
|
18933
18926
|
}
|
|
@@ -18939,8 +18932,8 @@ var GitHandoffTracker = class {
|
|
|
18939
18932
|
totalBytes: packBytes + indexBytes
|
|
18940
18933
|
};
|
|
18941
18934
|
}
|
|
18942
|
-
async
|
|
18943
|
-
const hash = await this.runGitWithInput(["pack-objects", packPrefix, "--revs"], `${
|
|
18935
|
+
async captureObjectPack(packPrefix, refs) {
|
|
18936
|
+
const hash = await this.runGitWithInput(["pack-objects", packPrefix, "--revs"], `${refs.join("\n")}
|
|
18944
18937
|
`);
|
|
18945
18938
|
const packPath = `${packPrefix}-${hash.trim()}.pack`;
|
|
18946
18939
|
const rawBytes = await this.getFileSize(packPath);
|
|
@@ -18948,9 +18941,8 @@ var GitHandoffTracker = class {
|
|
|
18948
18941
|
});
|
|
18949
18942
|
return { path: packPath, rawBytes };
|
|
18950
18943
|
}
|
|
18951
|
-
async copyIndexFile(git, checkpointId) {
|
|
18944
|
+
async copyIndexFile(git, checkpointId, tempDir) {
|
|
18952
18945
|
const indexPath = await this.getGitPath(git, "index");
|
|
18953
|
-
const tempDir = await this.getTempDir(git);
|
|
18954
18946
|
const copiedIndexPath = import_node_path5.default.join(tempDir, `${checkpointId}.index`);
|
|
18955
18947
|
await (0, import_promises2.copyFile)(indexPath, copiedIndexPath);
|
|
18956
18948
|
return {
|
|
@@ -19078,13 +19070,8 @@ var GitHandoffTracker = class {
|
|
|
19078
19070
|
]);
|
|
19079
19071
|
return exitCode === 0;
|
|
19080
19072
|
}
|
|
19081
|
-
async
|
|
19082
|
-
|
|
19083
|
-
const commonDir = raw.trim() || ".git";
|
|
19084
|
-
const resolved = import_node_path5.default.isAbsolute(commonDir) ? commonDir : import_node_path5.default.resolve(this.repositoryPath, commonDir);
|
|
19085
|
-
const tempDir = import_node_path5.default.join(resolved, "posthog-code-tmp");
|
|
19086
|
-
await (0, import_promises2.mkdir)(tempDir, { recursive: true });
|
|
19087
|
-
return tempDir;
|
|
19073
|
+
async createTempDir(checkpointId) {
|
|
19074
|
+
return (0, import_promises2.mkdtemp)(joinTempPrefix(checkpointId));
|
|
19088
19075
|
}
|
|
19089
19076
|
async getGitPath(git, gitPath) {
|
|
19090
19077
|
const raw = await git.raw(["rev-parse", "--git-path", gitPath]);
|
|
@@ -19151,6 +19138,9 @@ var GitHandoffTracker = class {
|
|
|
19151
19138
|
});
|
|
19152
19139
|
}
|
|
19153
19140
|
};
|
|
19141
|
+
function joinTempPrefix(checkpointId) {
|
|
19142
|
+
return import_node_path5.default.join((0, import_node_os.tmpdir)(), `posthog-code-handoff-${checkpointId}-`);
|
|
19143
|
+
}
|
|
19154
19144
|
async function getCurrentBranchName(git) {
|
|
19155
19145
|
try {
|
|
19156
19146
|
const raw = await git.revparse(["--abbrev-ref", "HEAD"]);
|
|
@@ -19237,8 +19227,11 @@ var HandoffCheckpointTracker = class {
|
|
|
19237
19227
|
indexArtifactPath: uploads.index?.storagePath
|
|
19238
19228
|
};
|
|
19239
19229
|
} finally {
|
|
19230
|
+
const tempDir = capture.headPack?.path ? (0, import_node_path6.dirname)(capture.headPack.path) : (0, import_node_path6.dirname)(capture.indexFile.path);
|
|
19240
19231
|
await this.removeIfPresent(capture.headPack?.path);
|
|
19241
19232
|
await this.removeIfPresent(capture.indexFile.path);
|
|
19233
|
+
await (0, import_promises3.rm)(tempDir, { recursive: true, force: true }).catch(() => {
|
|
19234
|
+
});
|
|
19242
19235
|
}
|
|
19243
19236
|
}
|
|
19244
19237
|
async applyFromHandoff(checkpoint, options) {
|
|
@@ -19248,8 +19241,9 @@ var HandoffCheckpointTracker = class {
|
|
|
19248
19241
|
);
|
|
19249
19242
|
}
|
|
19250
19243
|
const gitTracker = this.createGitTracker();
|
|
19251
|
-
const tmpDir = (0,
|
|
19252
|
-
|
|
19244
|
+
const tmpDir = await (0, import_promises3.mkdtemp)(
|
|
19245
|
+
(0, import_node_path6.join)((0, import_node_os2.tmpdir)(), `posthog-code-handoff-${checkpoint.checkpointId}-`)
|
|
19246
|
+
);
|
|
19253
19247
|
const packPath = (0, import_node_path6.join)(tmpDir, `${checkpoint.checkpointId}.pack`);
|
|
19254
19248
|
const indexPath = (0, import_node_path6.join)(tmpDir, `${checkpoint.checkpointId}.index`);
|
|
19255
19249
|
try {
|
|
@@ -19283,6 +19277,8 @@ var HandoffCheckpointTracker = class {
|
|
|
19283
19277
|
} finally {
|
|
19284
19278
|
await this.removeIfPresent(packPath);
|
|
19285
19279
|
await this.removeIfPresent(indexPath);
|
|
19280
|
+
await (0, import_promises3.rm)(tmpDir, { recursive: true, force: true }).catch(() => {
|
|
19281
|
+
});
|
|
19286
19282
|
}
|
|
19287
19283
|
}
|
|
19288
19284
|
toGitCheckpoint(checkpoint) {
|
|
@@ -19390,50 +19386,24 @@ var HandoffCheckpointTracker = class {
|
|
|
19390
19386
|
}
|
|
19391
19387
|
logCaptureMetrics(checkpoint, uploads) {
|
|
19392
19388
|
this.logger.info("Captured handoff checkpoint", {
|
|
19393
|
-
checkpointId: checkpoint.checkpointId,
|
|
19394
19389
|
branch: checkpoint.branch,
|
|
19395
|
-
head: checkpoint.head,
|
|
19396
|
-
|
|
19397
|
-
indexArtifactPath: uploads.index?.storagePath,
|
|
19398
|
-
...this.buildMetricPayload(uploads)
|
|
19390
|
+
head: checkpoint.head?.slice(0, 7),
|
|
19391
|
+
totalBytes: this.sumRawBytes(uploads.pack, uploads.index)
|
|
19399
19392
|
});
|
|
19400
19393
|
}
|
|
19401
|
-
logApplyMetrics(checkpoint,
|
|
19394
|
+
logApplyMetrics(checkpoint, _downloads, totalBytes) {
|
|
19402
19395
|
this.logger.info("Applied handoff checkpoint", {
|
|
19403
|
-
checkpointId: checkpoint.checkpointId,
|
|
19404
|
-
commit: checkpoint.commit,
|
|
19405
19396
|
branch: checkpoint.branch,
|
|
19406
|
-
head: checkpoint.head,
|
|
19407
|
-
|
|
19408
|
-
packWireBytes: downloads.pack?.wireBytes ?? 0,
|
|
19409
|
-
indexBytes: downloads.index?.rawBytes ?? 0,
|
|
19410
|
-
indexWireBytes: downloads.index?.wireBytes ?? 0,
|
|
19411
|
-
totalBytes,
|
|
19412
|
-
totalWireBytes: this.sumWireBytes(downloads.pack, downloads.index)
|
|
19397
|
+
head: checkpoint.head?.slice(0, 7),
|
|
19398
|
+
totalBytes
|
|
19413
19399
|
});
|
|
19414
19400
|
}
|
|
19415
|
-
buildMetricPayload(metrics) {
|
|
19416
|
-
return {
|
|
19417
|
-
packBytes: metrics.pack?.rawBytes ?? 0,
|
|
19418
|
-
packWireBytes: metrics.pack?.wireBytes ?? 0,
|
|
19419
|
-
indexBytes: metrics.index?.rawBytes ?? 0,
|
|
19420
|
-
indexWireBytes: metrics.index?.wireBytes ?? 0,
|
|
19421
|
-
totalBytes: this.sumRawBytes(metrics.pack, metrics.index),
|
|
19422
|
-
totalWireBytes: this.sumWireBytes(metrics.pack, metrics.index)
|
|
19423
|
-
};
|
|
19424
|
-
}
|
|
19425
19401
|
sumRawBytes(...artifacts) {
|
|
19426
19402
|
return artifacts.reduce(
|
|
19427
19403
|
(total, artifact) => total + (artifact?.rawBytes ?? 0),
|
|
19428
19404
|
0
|
|
19429
19405
|
);
|
|
19430
19406
|
}
|
|
19431
|
-
sumWireBytes(...artifacts) {
|
|
19432
|
-
return artifacts.reduce(
|
|
19433
|
-
(total, artifact) => total + (artifact?.wireBytes ?? 0),
|
|
19434
|
-
0
|
|
19435
|
-
);
|
|
19436
|
-
}
|
|
19437
19407
|
async removeIfPresent(filePath) {
|
|
19438
19408
|
if (!filePath) {
|
|
19439
19409
|
return;
|
|
@@ -19713,21 +19683,10 @@ var ResumeSaga = class extends Saga {
|
|
|
19713
19683
|
return this.emptyResult();
|
|
19714
19684
|
}
|
|
19715
19685
|
this.log.info("Fetched log entries", { count: entries.length });
|
|
19716
|
-
const latestSnapshot = await this.readOnlyStep(
|
|
19717
|
-
"find_snapshot",
|
|
19718
|
-
() => Promise.resolve(this.findLatestTreeSnapshot(entries))
|
|
19719
|
-
);
|
|
19720
19686
|
const latestGitCheckpoint = await this.readOnlyStep(
|
|
19721
19687
|
"find_git_checkpoint",
|
|
19722
19688
|
() => Promise.resolve(this.findLatestGitCheckpoint(entries))
|
|
19723
19689
|
);
|
|
19724
|
-
if (latestSnapshot) {
|
|
19725
|
-
this.log.info("Found tree snapshot", {
|
|
19726
|
-
treeHash: latestSnapshot.treeHash,
|
|
19727
|
-
hasArchiveUrl: !!latestSnapshot.archiveUrl,
|
|
19728
|
-
changes: latestSnapshot.changes?.length ?? 0
|
|
19729
|
-
});
|
|
19730
|
-
}
|
|
19731
19690
|
if (latestGitCheckpoint) {
|
|
19732
19691
|
this.log.info("Found git checkpoint", {
|
|
19733
19692
|
checkpointId: latestGitCheckpoint.checkpointId,
|
|
@@ -19744,15 +19703,13 @@ var ResumeSaga = class extends Saga {
|
|
|
19744
19703
|
);
|
|
19745
19704
|
this.log.info("Resume state rebuilt", {
|
|
19746
19705
|
turns: conversation.length,
|
|
19747
|
-
hasSnapshot: !!latestSnapshot,
|
|
19748
19706
|
hasGitCheckpoint: !!latestGitCheckpoint,
|
|
19749
|
-
interrupted:
|
|
19707
|
+
interrupted: false
|
|
19750
19708
|
});
|
|
19751
19709
|
return {
|
|
19752
19710
|
conversation,
|
|
19753
|
-
latestSnapshot,
|
|
19754
19711
|
latestGitCheckpoint,
|
|
19755
|
-
interrupted:
|
|
19712
|
+
interrupted: false,
|
|
19756
19713
|
lastDevice,
|
|
19757
19714
|
logEntryCount: entries.length
|
|
19758
19715
|
};
|
|
@@ -19760,27 +19717,11 @@ var ResumeSaga = class extends Saga {
|
|
|
19760
19717
|
emptyResult() {
|
|
19761
19718
|
return {
|
|
19762
19719
|
conversation: [],
|
|
19763
|
-
latestSnapshot: null,
|
|
19764
19720
|
latestGitCheckpoint: null,
|
|
19765
19721
|
interrupted: false,
|
|
19766
19722
|
logEntryCount: 0
|
|
19767
19723
|
};
|
|
19768
19724
|
}
|
|
19769
|
-
findLatestTreeSnapshot(entries) {
|
|
19770
|
-
for (let i2 = entries.length - 1; i2 >= 0; i2--) {
|
|
19771
|
-
const entry = entries[i2];
|
|
19772
|
-
if (isNotification(
|
|
19773
|
-
entry.notification?.method,
|
|
19774
|
-
POSTHOG_NOTIFICATIONS.TREE_SNAPSHOT
|
|
19775
|
-
)) {
|
|
19776
|
-
const params = entry.notification.params;
|
|
19777
|
-
if (params?.treeHash) {
|
|
19778
|
-
return params;
|
|
19779
|
-
}
|
|
19780
|
-
}
|
|
19781
|
-
}
|
|
19782
|
-
return null;
|
|
19783
|
-
}
|
|
19784
19725
|
findLatestGitCheckpoint(entries) {
|
|
19785
19726
|
const sdkPrefixedMethod = `_${POSTHOG_NOTIFICATIONS.GIT_CHECKPOINT}`;
|
|
19786
19727
|
for (let i2 = entries.length - 1; i2 >= 0; i2--) {
|
|
@@ -19942,7 +19883,6 @@ async function resumeFromLog(config) {
|
|
|
19942
19883
|
}
|
|
19943
19884
|
return {
|
|
19944
19885
|
conversation: result.data.conversation,
|
|
19945
|
-
latestSnapshot: result.data.latestSnapshot,
|
|
19946
19886
|
latestGitCheckpoint: result.data.latestGitCheckpoint,
|
|
19947
19887
|
interrupted: result.data.interrupted,
|
|
19948
19888
|
lastDevice: result.data.lastDevice,
|
|
@@ -20330,544 +20270,6 @@ var SessionLogWriter = class _SessionLogWriter {
|
|
|
20330
20270
|
}
|
|
20331
20271
|
};
|
|
20332
20272
|
|
|
20333
|
-
// src/sagas/apply-snapshot-saga.ts
|
|
20334
|
-
var import_promises5 = require("fs/promises");
|
|
20335
|
-
var import_node_path8 = require("path");
|
|
20336
|
-
|
|
20337
|
-
// ../git/dist/sagas/tree.js
|
|
20338
|
-
var import_node_fs4 = require("fs");
|
|
20339
|
-
var fs13 = __toESM(require("fs/promises"), 1);
|
|
20340
|
-
var path16 = __toESM(require("path"), 1);
|
|
20341
|
-
var tar = __toESM(require("tar"), 1);
|
|
20342
|
-
var CaptureTreeSaga = class extends GitSaga {
|
|
20343
|
-
sagaName = "CaptureTreeSaga";
|
|
20344
|
-
tempIndexPath = null;
|
|
20345
|
-
async executeGitOperations(input) {
|
|
20346
|
-
const { baseDir, lastTreeHash, archivePath, signal } = input;
|
|
20347
|
-
const tmpDir = path16.join(baseDir, ".git", "posthog-code-tmp");
|
|
20348
|
-
await this.step({
|
|
20349
|
-
name: "create_tmp_dir",
|
|
20350
|
-
execute: () => fs13.mkdir(tmpDir, { recursive: true }),
|
|
20351
|
-
rollback: async () => {
|
|
20352
|
-
}
|
|
20353
|
-
});
|
|
20354
|
-
this.tempIndexPath = path16.join(tmpDir, `index-${Date.now()}`);
|
|
20355
|
-
const tempIndexGit = this.git.env({
|
|
20356
|
-
...process.env,
|
|
20357
|
-
GIT_INDEX_FILE: this.tempIndexPath
|
|
20358
|
-
});
|
|
20359
|
-
await this.step({
|
|
20360
|
-
name: "init_temp_index",
|
|
20361
|
-
execute: () => tempIndexGit.raw(["read-tree", "HEAD"]),
|
|
20362
|
-
rollback: async () => {
|
|
20363
|
-
if (this.tempIndexPath) {
|
|
20364
|
-
await fs13.rm(this.tempIndexPath, { force: true }).catch(() => {
|
|
20365
|
-
});
|
|
20366
|
-
}
|
|
20367
|
-
}
|
|
20368
|
-
});
|
|
20369
|
-
await this.readOnlyStep("stage_files", () => tempIndexGit.raw(["add", "-A"]));
|
|
20370
|
-
const treeHash = await this.readOnlyStep("write_tree", () => tempIndexGit.raw(["write-tree"]));
|
|
20371
|
-
if (lastTreeHash && treeHash === lastTreeHash) {
|
|
20372
|
-
this.log.debug("No changes since last capture", { treeHash });
|
|
20373
|
-
await fs13.rm(this.tempIndexPath, { force: true }).catch(() => {
|
|
20374
|
-
});
|
|
20375
|
-
return { snapshot: null, changed: false };
|
|
20376
|
-
}
|
|
20377
|
-
const baseCommit = await this.readOnlyStep("get_base_commit", async () => {
|
|
20378
|
-
try {
|
|
20379
|
-
return await getHeadSha(baseDir, { abortSignal: signal });
|
|
20380
|
-
} catch {
|
|
20381
|
-
return null;
|
|
20382
|
-
}
|
|
20383
|
-
});
|
|
20384
|
-
const changes = await this.readOnlyStep("get_changes", () => this.getChanges(this.git, baseCommit, treeHash));
|
|
20385
|
-
await fs13.rm(this.tempIndexPath, { force: true }).catch(() => {
|
|
20386
|
-
});
|
|
20387
|
-
const snapshot = {
|
|
20388
|
-
treeHash,
|
|
20389
|
-
baseCommit,
|
|
20390
|
-
changes,
|
|
20391
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
20392
|
-
};
|
|
20393
|
-
let createdArchivePath;
|
|
20394
|
-
if (archivePath) {
|
|
20395
|
-
createdArchivePath = await this.createArchive(baseDir, archivePath, changes);
|
|
20396
|
-
}
|
|
20397
|
-
this.log.info("Tree captured", {
|
|
20398
|
-
treeHash,
|
|
20399
|
-
changes: changes.length,
|
|
20400
|
-
archived: !!createdArchivePath
|
|
20401
|
-
});
|
|
20402
|
-
return { snapshot, archivePath: createdArchivePath, changed: true };
|
|
20403
|
-
}
|
|
20404
|
-
async createArchive(baseDir, archivePath, changes) {
|
|
20405
|
-
const filesToArchive = changes.filter((c) => c.status !== "D").map((c) => c.path);
|
|
20406
|
-
if (filesToArchive.length === 0) {
|
|
20407
|
-
return void 0;
|
|
20408
|
-
}
|
|
20409
|
-
const existingFiles = filesToArchive.filter((f) => (0, import_node_fs4.existsSync)(path16.join(baseDir, f)));
|
|
20410
|
-
if (existingFiles.length === 0) {
|
|
20411
|
-
return void 0;
|
|
20412
|
-
}
|
|
20413
|
-
await this.step({
|
|
20414
|
-
name: "create_archive",
|
|
20415
|
-
execute: async () => {
|
|
20416
|
-
const archiveDir = path16.dirname(archivePath);
|
|
20417
|
-
await fs13.mkdir(archiveDir, { recursive: true });
|
|
20418
|
-
await tar.create({
|
|
20419
|
-
gzip: true,
|
|
20420
|
-
file: archivePath,
|
|
20421
|
-
cwd: baseDir
|
|
20422
|
-
}, existingFiles);
|
|
20423
|
-
},
|
|
20424
|
-
rollback: async () => {
|
|
20425
|
-
await fs13.rm(archivePath, { force: true }).catch(() => {
|
|
20426
|
-
});
|
|
20427
|
-
}
|
|
20428
|
-
});
|
|
20429
|
-
return archivePath;
|
|
20430
|
-
}
|
|
20431
|
-
async getChanges(git, fromRef, toRef) {
|
|
20432
|
-
if (!fromRef) {
|
|
20433
|
-
const stdout2 = await git.raw(["ls-tree", "-r", "--name-only", toRef]);
|
|
20434
|
-
return stdout2.split("\n").filter((p) => p.trim()).map((p) => ({ path: p, status: "A" }));
|
|
20435
|
-
}
|
|
20436
|
-
const stdout = await git.raw([
|
|
20437
|
-
"diff-tree",
|
|
20438
|
-
"-r",
|
|
20439
|
-
"--name-status",
|
|
20440
|
-
fromRef,
|
|
20441
|
-
toRef
|
|
20442
|
-
]);
|
|
20443
|
-
const changes = [];
|
|
20444
|
-
for (const line of stdout.split("\n")) {
|
|
20445
|
-
if (!line.trim())
|
|
20446
|
-
continue;
|
|
20447
|
-
const [status, filePath] = line.split(" ");
|
|
20448
|
-
if (!filePath)
|
|
20449
|
-
continue;
|
|
20450
|
-
let normalizedStatus;
|
|
20451
|
-
if (status === "D") {
|
|
20452
|
-
normalizedStatus = "D";
|
|
20453
|
-
} else if (status === "A") {
|
|
20454
|
-
normalizedStatus = "A";
|
|
20455
|
-
} else {
|
|
20456
|
-
normalizedStatus = "M";
|
|
20457
|
-
}
|
|
20458
|
-
changes.push({ path: filePath, status: normalizedStatus });
|
|
20459
|
-
}
|
|
20460
|
-
return changes;
|
|
20461
|
-
}
|
|
20462
|
-
};
|
|
20463
|
-
var ApplyTreeSaga = class extends GitSaga {
|
|
20464
|
-
sagaName = "ApplyTreeSaga";
|
|
20465
|
-
originalHead = null;
|
|
20466
|
-
originalBranch = null;
|
|
20467
|
-
extractedFiles = [];
|
|
20468
|
-
fileBackups = /* @__PURE__ */ new Map();
|
|
20469
|
-
async executeGitOperations(input) {
|
|
20470
|
-
const { baseDir, treeHash, baseCommit, changes, archivePath } = input;
|
|
20471
|
-
const headInfo = await this.readOnlyStep("get_current_head", async () => {
|
|
20472
|
-
let head = null;
|
|
20473
|
-
let branch = null;
|
|
20474
|
-
try {
|
|
20475
|
-
head = await this.git.revparse(["HEAD"]);
|
|
20476
|
-
} catch {
|
|
20477
|
-
head = null;
|
|
20478
|
-
}
|
|
20479
|
-
try {
|
|
20480
|
-
branch = await this.git.raw(["symbolic-ref", "--short", "HEAD"]);
|
|
20481
|
-
} catch {
|
|
20482
|
-
branch = null;
|
|
20483
|
-
}
|
|
20484
|
-
return { head, branch };
|
|
20485
|
-
});
|
|
20486
|
-
this.originalHead = headInfo.head;
|
|
20487
|
-
this.originalBranch = headInfo.branch;
|
|
20488
|
-
let checkoutPerformed = false;
|
|
20489
|
-
if (baseCommit && baseCommit !== this.originalHead) {
|
|
20490
|
-
await this.readOnlyStep("check_working_tree", async () => {
|
|
20491
|
-
const status = await this.git.status();
|
|
20492
|
-
if (!status.isClean()) {
|
|
20493
|
-
const changedFiles = status.modified.length + status.staged.length + status.deleted.length;
|
|
20494
|
-
throw new Error(`Cannot apply tree: ${changedFiles} uncommitted change(s) exist. Commit or stash your changes first.`);
|
|
20495
|
-
}
|
|
20496
|
-
});
|
|
20497
|
-
await this.step({
|
|
20498
|
-
name: "checkout_base",
|
|
20499
|
-
execute: async () => {
|
|
20500
|
-
await this.git.checkout(baseCommit);
|
|
20501
|
-
checkoutPerformed = true;
|
|
20502
|
-
this.log.warn("Applied tree from different commit - now in detached HEAD state", {
|
|
20503
|
-
originalHead: this.originalHead,
|
|
20504
|
-
originalBranch: this.originalBranch,
|
|
20505
|
-
baseCommit
|
|
20506
|
-
});
|
|
20507
|
-
},
|
|
20508
|
-
rollback: async () => {
|
|
20509
|
-
try {
|
|
20510
|
-
if (this.originalBranch) {
|
|
20511
|
-
await this.git.checkout(this.originalBranch);
|
|
20512
|
-
} else if (this.originalHead) {
|
|
20513
|
-
await this.git.checkout(this.originalHead);
|
|
20514
|
-
}
|
|
20515
|
-
} catch (error) {
|
|
20516
|
-
this.log.warn("Failed to rollback checkout", { error });
|
|
20517
|
-
}
|
|
20518
|
-
}
|
|
20519
|
-
});
|
|
20520
|
-
}
|
|
20521
|
-
if (archivePath) {
|
|
20522
|
-
const filesToExtract = changes.filter((c) => c.status !== "D").map((c) => c.path);
|
|
20523
|
-
await this.readOnlyStep("backup_existing_files", async () => {
|
|
20524
|
-
for (const filePath of filesToExtract) {
|
|
20525
|
-
const fullPath = path16.join(baseDir, filePath);
|
|
20526
|
-
try {
|
|
20527
|
-
const content = await fs13.readFile(fullPath);
|
|
20528
|
-
this.fileBackups.set(filePath, content);
|
|
20529
|
-
} catch {
|
|
20530
|
-
}
|
|
20531
|
-
}
|
|
20532
|
-
});
|
|
20533
|
-
await this.step({
|
|
20534
|
-
name: "extract_archive",
|
|
20535
|
-
execute: async () => {
|
|
20536
|
-
await tar.extract({
|
|
20537
|
-
file: archivePath,
|
|
20538
|
-
cwd: baseDir
|
|
20539
|
-
});
|
|
20540
|
-
this.extractedFiles = filesToExtract;
|
|
20541
|
-
},
|
|
20542
|
-
rollback: async () => {
|
|
20543
|
-
for (const filePath of this.extractedFiles) {
|
|
20544
|
-
const fullPath = path16.join(baseDir, filePath);
|
|
20545
|
-
const backup = this.fileBackups.get(filePath);
|
|
20546
|
-
if (backup) {
|
|
20547
|
-
const dir = path16.dirname(fullPath);
|
|
20548
|
-
await fs13.mkdir(dir, { recursive: true }).catch(() => {
|
|
20549
|
-
});
|
|
20550
|
-
await fs13.writeFile(fullPath, backup).catch(() => {
|
|
20551
|
-
});
|
|
20552
|
-
} else {
|
|
20553
|
-
await fs13.rm(fullPath, { force: true }).catch(() => {
|
|
20554
|
-
});
|
|
20555
|
-
}
|
|
20556
|
-
}
|
|
20557
|
-
}
|
|
20558
|
-
});
|
|
20559
|
-
}
|
|
20560
|
-
for (const change of changes.filter((c) => c.status === "D")) {
|
|
20561
|
-
const fullPath = path16.join(baseDir, change.path);
|
|
20562
|
-
const backupContent = await this.readOnlyStep(`backup_${change.path}`, async () => {
|
|
20563
|
-
try {
|
|
20564
|
-
return await fs13.readFile(fullPath);
|
|
20565
|
-
} catch {
|
|
20566
|
-
return null;
|
|
20567
|
-
}
|
|
20568
|
-
});
|
|
20569
|
-
await this.step({
|
|
20570
|
-
name: `delete_${change.path}`,
|
|
20571
|
-
execute: async () => {
|
|
20572
|
-
await fs13.rm(fullPath, { force: true });
|
|
20573
|
-
this.log.debug(`Deleted file: ${change.path}`);
|
|
20574
|
-
},
|
|
20575
|
-
rollback: async () => {
|
|
20576
|
-
if (backupContent) {
|
|
20577
|
-
const dir = path16.dirname(fullPath);
|
|
20578
|
-
await fs13.mkdir(dir, { recursive: true }).catch(() => {
|
|
20579
|
-
});
|
|
20580
|
-
await fs13.writeFile(fullPath, backupContent).catch(() => {
|
|
20581
|
-
});
|
|
20582
|
-
}
|
|
20583
|
-
}
|
|
20584
|
-
});
|
|
20585
|
-
}
|
|
20586
|
-
const deletedCount = changes.filter((c) => c.status === "D").length;
|
|
20587
|
-
this.log.info("Tree applied", {
|
|
20588
|
-
treeHash,
|
|
20589
|
-
totalChanges: changes.length,
|
|
20590
|
-
deletedFiles: deletedCount,
|
|
20591
|
-
checkoutPerformed
|
|
20592
|
-
});
|
|
20593
|
-
return { treeHash, checkoutPerformed };
|
|
20594
|
-
}
|
|
20595
|
-
};
|
|
20596
|
-
|
|
20597
|
-
// src/sagas/apply-snapshot-saga.ts
|
|
20598
|
-
var ApplySnapshotSaga = class extends Saga {
|
|
20599
|
-
sagaName = "ApplySnapshotSaga";
|
|
20600
|
-
archivePath = null;
|
|
20601
|
-
async execute(input) {
|
|
20602
|
-
const { snapshot, repositoryPath, apiClient, taskId, runId } = input;
|
|
20603
|
-
const tmpDir = (0, import_node_path8.join)(repositoryPath, ".posthog", "tmp");
|
|
20604
|
-
if (!snapshot.archiveUrl) {
|
|
20605
|
-
throw new Error("Cannot apply snapshot: no archive URL");
|
|
20606
|
-
}
|
|
20607
|
-
const archiveUrl = snapshot.archiveUrl;
|
|
20608
|
-
await this.step({
|
|
20609
|
-
name: "create_tmp_dir",
|
|
20610
|
-
execute: () => (0, import_promises5.mkdir)(tmpDir, { recursive: true }),
|
|
20611
|
-
rollback: async () => {
|
|
20612
|
-
}
|
|
20613
|
-
});
|
|
20614
|
-
const archivePath = (0, import_node_path8.join)(tmpDir, `${snapshot.treeHash}.tar.gz`);
|
|
20615
|
-
this.archivePath = archivePath;
|
|
20616
|
-
await this.step({
|
|
20617
|
-
name: "download_archive",
|
|
20618
|
-
execute: async () => {
|
|
20619
|
-
const arrayBuffer = await apiClient.downloadArtifact(
|
|
20620
|
-
taskId,
|
|
20621
|
-
runId,
|
|
20622
|
-
archiveUrl
|
|
20623
|
-
);
|
|
20624
|
-
if (!arrayBuffer) {
|
|
20625
|
-
throw new Error("Failed to download archive");
|
|
20626
|
-
}
|
|
20627
|
-
const base64Content = Buffer.from(arrayBuffer).toString("utf-8");
|
|
20628
|
-
const binaryContent = Buffer.from(base64Content, "base64");
|
|
20629
|
-
await (0, import_promises5.writeFile)(archivePath, binaryContent);
|
|
20630
|
-
this.log.info("Tree archive downloaded", {
|
|
20631
|
-
treeHash: snapshot.treeHash,
|
|
20632
|
-
snapshotBytes: binaryContent.byteLength,
|
|
20633
|
-
snapshotWireBytes: arrayBuffer.byteLength,
|
|
20634
|
-
totalBytes: binaryContent.byteLength,
|
|
20635
|
-
totalWireBytes: arrayBuffer.byteLength
|
|
20636
|
-
});
|
|
20637
|
-
},
|
|
20638
|
-
rollback: async () => {
|
|
20639
|
-
if (this.archivePath) {
|
|
20640
|
-
await (0, import_promises5.rm)(this.archivePath, { force: true }).catch(() => {
|
|
20641
|
-
});
|
|
20642
|
-
}
|
|
20643
|
-
}
|
|
20644
|
-
});
|
|
20645
|
-
const gitApplySaga = new ApplyTreeSaga(this.log);
|
|
20646
|
-
const applyResult = await gitApplySaga.run({
|
|
20647
|
-
baseDir: repositoryPath,
|
|
20648
|
-
treeHash: snapshot.treeHash,
|
|
20649
|
-
baseCommit: snapshot.baseCommit,
|
|
20650
|
-
changes: snapshot.changes,
|
|
20651
|
-
archivePath: this.archivePath
|
|
20652
|
-
});
|
|
20653
|
-
if (!applyResult.success) {
|
|
20654
|
-
throw new Error(`Failed to apply tree: ${applyResult.error}`);
|
|
20655
|
-
}
|
|
20656
|
-
await (0, import_promises5.rm)(this.archivePath, { force: true }).catch(() => {
|
|
20657
|
-
});
|
|
20658
|
-
this.log.info("Tree snapshot applied", {
|
|
20659
|
-
treeHash: snapshot.treeHash,
|
|
20660
|
-
totalChanges: snapshot.changes.length,
|
|
20661
|
-
deletedFiles: snapshot.changes.filter((c) => c.status === "D").length
|
|
20662
|
-
});
|
|
20663
|
-
return { treeHash: snapshot.treeHash };
|
|
20664
|
-
}
|
|
20665
|
-
};
|
|
20666
|
-
|
|
20667
|
-
// src/sagas/capture-tree-saga.ts
|
|
20668
|
-
var import_node_fs5 = require("fs");
|
|
20669
|
-
var import_promises6 = require("fs/promises");
|
|
20670
|
-
var import_node_path9 = require("path");
|
|
20671
|
-
var CaptureTreeSaga2 = class extends Saga {
|
|
20672
|
-
sagaName = "CaptureTreeSaga";
|
|
20673
|
-
async execute(input) {
|
|
20674
|
-
const {
|
|
20675
|
-
repositoryPath,
|
|
20676
|
-
lastTreeHash,
|
|
20677
|
-
interrupted,
|
|
20678
|
-
apiClient,
|
|
20679
|
-
taskId,
|
|
20680
|
-
runId
|
|
20681
|
-
} = input;
|
|
20682
|
-
const tmpDir = (0, import_node_path9.join)(repositoryPath, ".posthog", "tmp");
|
|
20683
|
-
if ((0, import_node_fs5.existsSync)((0, import_node_path9.join)(repositoryPath, ".gitmodules"))) {
|
|
20684
|
-
this.log.warn(
|
|
20685
|
-
"Repository has submodules - snapshot may not capture submodule state"
|
|
20686
|
-
);
|
|
20687
|
-
}
|
|
20688
|
-
const shouldArchive = !!apiClient;
|
|
20689
|
-
const archivePath = shouldArchive ? (0, import_node_path9.join)(tmpDir, `tree-${Date.now()}.tar.gz`) : void 0;
|
|
20690
|
-
const gitCaptureSaga = new CaptureTreeSaga(this.log);
|
|
20691
|
-
const captureResult = await gitCaptureSaga.run({
|
|
20692
|
-
baseDir: repositoryPath,
|
|
20693
|
-
lastTreeHash,
|
|
20694
|
-
archivePath
|
|
20695
|
-
});
|
|
20696
|
-
if (!captureResult.success) {
|
|
20697
|
-
throw new Error(`Failed to capture tree: ${captureResult.error}`);
|
|
20698
|
-
}
|
|
20699
|
-
const {
|
|
20700
|
-
snapshot: gitSnapshot,
|
|
20701
|
-
archivePath: createdArchivePath,
|
|
20702
|
-
changed
|
|
20703
|
-
} = captureResult.data;
|
|
20704
|
-
if (!changed || !gitSnapshot) {
|
|
20705
|
-
this.log.debug("No changes since last capture", { lastTreeHash });
|
|
20706
|
-
return { snapshot: null, newTreeHash: lastTreeHash };
|
|
20707
|
-
}
|
|
20708
|
-
let archiveUrl;
|
|
20709
|
-
if (apiClient && createdArchivePath) {
|
|
20710
|
-
try {
|
|
20711
|
-
archiveUrl = await this.uploadArchive(
|
|
20712
|
-
createdArchivePath,
|
|
20713
|
-
gitSnapshot.treeHash,
|
|
20714
|
-
apiClient,
|
|
20715
|
-
taskId,
|
|
20716
|
-
runId
|
|
20717
|
-
);
|
|
20718
|
-
} finally {
|
|
20719
|
-
await (0, import_promises6.rm)(createdArchivePath, { force: true }).catch(() => {
|
|
20720
|
-
});
|
|
20721
|
-
}
|
|
20722
|
-
}
|
|
20723
|
-
const snapshot = {
|
|
20724
|
-
treeHash: gitSnapshot.treeHash,
|
|
20725
|
-
baseCommit: gitSnapshot.baseCommit,
|
|
20726
|
-
changes: gitSnapshot.changes,
|
|
20727
|
-
timestamp: gitSnapshot.timestamp,
|
|
20728
|
-
interrupted,
|
|
20729
|
-
archiveUrl
|
|
20730
|
-
};
|
|
20731
|
-
this.log.info("Tree captured", {
|
|
20732
|
-
treeHash: snapshot.treeHash,
|
|
20733
|
-
changes: snapshot.changes.length,
|
|
20734
|
-
interrupted,
|
|
20735
|
-
archiveUrl
|
|
20736
|
-
});
|
|
20737
|
-
return { snapshot, newTreeHash: snapshot.treeHash };
|
|
20738
|
-
}
|
|
20739
|
-
async uploadArchive(archivePath, treeHash, apiClient, taskId, runId) {
|
|
20740
|
-
const archiveUrl = await this.step({
|
|
20741
|
-
name: "upload_archive",
|
|
20742
|
-
execute: async () => {
|
|
20743
|
-
const archiveContent = await (0, import_promises6.readFile)(archivePath);
|
|
20744
|
-
const base64Content = archiveContent.toString("base64");
|
|
20745
|
-
const snapshotBytes = archiveContent.byteLength;
|
|
20746
|
-
const snapshotWireBytes = Buffer.byteLength(base64Content, "utf-8");
|
|
20747
|
-
const artifacts = await apiClient.uploadTaskArtifacts(taskId, runId, [
|
|
20748
|
-
{
|
|
20749
|
-
name: `trees/${treeHash}.tar.gz`,
|
|
20750
|
-
type: "tree_snapshot",
|
|
20751
|
-
content: base64Content,
|
|
20752
|
-
content_type: "application/gzip"
|
|
20753
|
-
}
|
|
20754
|
-
]);
|
|
20755
|
-
const uploadedArtifact = artifacts[0];
|
|
20756
|
-
if (uploadedArtifact?.storage_path) {
|
|
20757
|
-
this.log.info("Tree archive uploaded", {
|
|
20758
|
-
storagePath: uploadedArtifact.storage_path,
|
|
20759
|
-
treeHash,
|
|
20760
|
-
snapshotBytes,
|
|
20761
|
-
snapshotWireBytes,
|
|
20762
|
-
totalBytes: snapshotBytes,
|
|
20763
|
-
totalWireBytes: snapshotWireBytes
|
|
20764
|
-
});
|
|
20765
|
-
return uploadedArtifact.storage_path;
|
|
20766
|
-
}
|
|
20767
|
-
return void 0;
|
|
20768
|
-
},
|
|
20769
|
-
rollback: async () => {
|
|
20770
|
-
await (0, import_promises6.rm)(archivePath, { force: true }).catch(() => {
|
|
20771
|
-
});
|
|
20772
|
-
}
|
|
20773
|
-
});
|
|
20774
|
-
return archiveUrl;
|
|
20775
|
-
}
|
|
20776
|
-
};
|
|
20777
|
-
|
|
20778
|
-
// src/tree-tracker.ts
|
|
20779
|
-
var TreeTracker = class {
|
|
20780
|
-
repositoryPath;
|
|
20781
|
-
taskId;
|
|
20782
|
-
runId;
|
|
20783
|
-
apiClient;
|
|
20784
|
-
logger;
|
|
20785
|
-
lastTreeHash = null;
|
|
20786
|
-
constructor(config) {
|
|
20787
|
-
this.repositoryPath = config.repositoryPath;
|
|
20788
|
-
this.taskId = config.taskId;
|
|
20789
|
-
this.runId = config.runId;
|
|
20790
|
-
this.apiClient = config.apiClient;
|
|
20791
|
-
this.logger = config.logger || new Logger({ debug: false, prefix: "[TreeTracker]" });
|
|
20792
|
-
}
|
|
20793
|
-
/**
|
|
20794
|
-
* Capture current working tree state as a snapshot.
|
|
20795
|
-
* Uses a temporary index to avoid modifying user's staging area.
|
|
20796
|
-
* Uses Saga pattern for atomic operation with automatic cleanup on failure.
|
|
20797
|
-
*/
|
|
20798
|
-
async captureTree(options) {
|
|
20799
|
-
const saga = new CaptureTreeSaga2(this.logger);
|
|
20800
|
-
const result = await saga.run({
|
|
20801
|
-
repositoryPath: this.repositoryPath,
|
|
20802
|
-
taskId: this.taskId,
|
|
20803
|
-
runId: this.runId,
|
|
20804
|
-
apiClient: this.apiClient,
|
|
20805
|
-
lastTreeHash: this.lastTreeHash,
|
|
20806
|
-
interrupted: options?.interrupted
|
|
20807
|
-
});
|
|
20808
|
-
if (!result.success) {
|
|
20809
|
-
this.logger.error("Failed to capture tree", {
|
|
20810
|
-
error: result.error,
|
|
20811
|
-
failedStep: result.failedStep
|
|
20812
|
-
});
|
|
20813
|
-
throw new Error(
|
|
20814
|
-
`Failed to capture tree at step '${result.failedStep}': ${result.error}`
|
|
20815
|
-
);
|
|
20816
|
-
}
|
|
20817
|
-
if (result.data.newTreeHash !== null) {
|
|
20818
|
-
this.lastTreeHash = result.data.newTreeHash;
|
|
20819
|
-
}
|
|
20820
|
-
return result.data.snapshot;
|
|
20821
|
-
}
|
|
20822
|
-
/**
|
|
20823
|
-
* Download and apply a tree snapshot.
|
|
20824
|
-
* Uses Saga pattern for atomic operation with rollback on failure.
|
|
20825
|
-
*/
|
|
20826
|
-
async applyTreeSnapshot(snapshot) {
|
|
20827
|
-
if (!this.apiClient) {
|
|
20828
|
-
throw new Error("Cannot apply snapshot: API client not configured");
|
|
20829
|
-
}
|
|
20830
|
-
if (!snapshot.archiveUrl) {
|
|
20831
|
-
this.logger.warn("Cannot apply snapshot: no archive URL", {
|
|
20832
|
-
treeHash: snapshot.treeHash,
|
|
20833
|
-
changes: snapshot.changes.length
|
|
20834
|
-
});
|
|
20835
|
-
throw new Error("Cannot apply snapshot: no archive URL");
|
|
20836
|
-
}
|
|
20837
|
-
const saga = new ApplySnapshotSaga(this.logger);
|
|
20838
|
-
const result = await saga.run({
|
|
20839
|
-
snapshot,
|
|
20840
|
-
repositoryPath: this.repositoryPath,
|
|
20841
|
-
apiClient: this.apiClient,
|
|
20842
|
-
taskId: this.taskId,
|
|
20843
|
-
runId: this.runId
|
|
20844
|
-
});
|
|
20845
|
-
if (!result.success) {
|
|
20846
|
-
this.logger.error("Failed to apply tree snapshot", {
|
|
20847
|
-
error: result.error,
|
|
20848
|
-
failedStep: result.failedStep,
|
|
20849
|
-
treeHash: snapshot.treeHash
|
|
20850
|
-
});
|
|
20851
|
-
throw new Error(
|
|
20852
|
-
`Failed to apply snapshot at step '${result.failedStep}': ${result.error}`
|
|
20853
|
-
);
|
|
20854
|
-
}
|
|
20855
|
-
this.lastTreeHash = result.data.treeHash;
|
|
20856
|
-
}
|
|
20857
|
-
/**
|
|
20858
|
-
* Get the last captured tree hash.
|
|
20859
|
-
*/
|
|
20860
|
-
getLastTreeHash() {
|
|
20861
|
-
return this.lastTreeHash;
|
|
20862
|
-
}
|
|
20863
|
-
/**
|
|
20864
|
-
* Set the last tree hash (used when resuming).
|
|
20865
|
-
*/
|
|
20866
|
-
setLastTreeHash(hash) {
|
|
20867
|
-
this.lastTreeHash = hash;
|
|
20868
|
-
}
|
|
20869
|
-
};
|
|
20870
|
-
|
|
20871
20273
|
// src/server/cloud-prompt.ts
|
|
20872
20274
|
function normalizeCloudPromptContent(content) {
|
|
20873
20275
|
if (typeof content === "string") {
|
|
@@ -21352,7 +20754,6 @@ var AgentServer = class {
|
|
|
21352
20754
|
});
|
|
21353
20755
|
this.logger.debug("Resume state loaded", {
|
|
21354
20756
|
conversationTurns: this.resumeState.conversation.length,
|
|
21355
|
-
hasSnapshot: !!this.resumeState.latestSnapshot,
|
|
21356
20757
|
hasGitCheckpoint: !!this.resumeState.latestGitCheckpoint,
|
|
21357
20758
|
gitCheckpointBranch: this.resumeState.latestGitCheckpoint?.branch ?? null,
|
|
21358
20759
|
logEntries: this.resumeState.logEntryCount
|
|
@@ -21598,13 +20999,6 @@ var AgentServer = class {
|
|
|
21598
20999
|
getApiKey: () => this.config.apiKey,
|
|
21599
21000
|
userAgent: `posthog/cloud.hog.dev; version: ${this.config.version ?? package_default.version}`
|
|
21600
21001
|
});
|
|
21601
|
-
const treeTracker = this.config.repositoryPath ? new TreeTracker({
|
|
21602
|
-
repositoryPath: this.config.repositoryPath,
|
|
21603
|
-
taskId: payload.task_id,
|
|
21604
|
-
runId: payload.run_id,
|
|
21605
|
-
apiClient: posthogAPI,
|
|
21606
|
-
logger: new Logger({ debug: true, prefix: "[TreeTracker]" })
|
|
21607
|
-
}) : null;
|
|
21608
21002
|
const logWriter = new SessionLogWriter({
|
|
21609
21003
|
posthogAPI,
|
|
21610
21004
|
logger: new Logger({ debug: true, prefix: "[SessionLogWriter]" })
|
|
@@ -21697,7 +21091,6 @@ var AgentServer = class {
|
|
|
21697
21091
|
acpSessionId,
|
|
21698
21092
|
acpConnection,
|
|
21699
21093
|
clientConnection,
|
|
21700
|
-
treeTracker,
|
|
21701
21094
|
sseController,
|
|
21702
21095
|
deviceInfo,
|
|
21703
21096
|
logWriter,
|
|
@@ -21824,31 +21217,7 @@ var AgentServer = class {
|
|
|
21824
21217
|
const conversationSummary = formatConversationForResume(
|
|
21825
21218
|
this.resumeState.conversation
|
|
21826
21219
|
);
|
|
21827
|
-
let
|
|
21828
|
-
if (this.resumeState.latestSnapshot?.archiveUrl && this.config.repositoryPath && this.posthogAPI) {
|
|
21829
|
-
try {
|
|
21830
|
-
const treeTracker = new TreeTracker({
|
|
21831
|
-
repositoryPath: this.config.repositoryPath,
|
|
21832
|
-
taskId: payload.task_id,
|
|
21833
|
-
runId: payload.run_id,
|
|
21834
|
-
apiClient: this.posthogAPI,
|
|
21835
|
-
logger: this.logger.child("TreeTracker")
|
|
21836
|
-
});
|
|
21837
|
-
await treeTracker.applyTreeSnapshot(this.resumeState.latestSnapshot);
|
|
21838
|
-
treeTracker.setLastTreeHash(this.resumeState.latestSnapshot.treeHash);
|
|
21839
|
-
snapshotApplied = true;
|
|
21840
|
-
this.logger.info("Tree snapshot applied", {
|
|
21841
|
-
treeHash: this.resumeState.latestSnapshot.treeHash,
|
|
21842
|
-
changes: this.resumeState.latestSnapshot.changes?.length ?? 0,
|
|
21843
|
-
hasArchiveUrl: !!this.resumeState.latestSnapshot.archiveUrl
|
|
21844
|
-
});
|
|
21845
|
-
} catch (error) {
|
|
21846
|
-
this.logger.warn("Failed to apply tree snapshot", {
|
|
21847
|
-
error: error instanceof Error ? error.message : String(error),
|
|
21848
|
-
treeHash: this.resumeState.latestSnapshot.treeHash
|
|
21849
|
-
});
|
|
21850
|
-
}
|
|
21851
|
-
}
|
|
21220
|
+
let checkpointApplied = false;
|
|
21852
21221
|
if (this.resumeState.latestGitCheckpoint && this.config.repositoryPath && this.posthogAPI) {
|
|
21853
21222
|
try {
|
|
21854
21223
|
const checkpointTracker = new HandoffCheckpointTracker({
|
|
@@ -21861,6 +21230,7 @@ var AgentServer = class {
|
|
|
21861
21230
|
const metrics = await checkpointTracker.applyFromHandoff(
|
|
21862
21231
|
this.resumeState.latestGitCheckpoint
|
|
21863
21232
|
);
|
|
21233
|
+
checkpointApplied = true;
|
|
21864
21234
|
this.logger.info("Git checkpoint applied", {
|
|
21865
21235
|
branch: this.resumeState.latestGitCheckpoint.branch,
|
|
21866
21236
|
head: this.resumeState.latestGitCheckpoint.head,
|
|
@@ -21876,7 +21246,7 @@ var AgentServer = class {
|
|
|
21876
21246
|
}
|
|
21877
21247
|
}
|
|
21878
21248
|
const pendingUserPrompt = await this.getPendingUserPrompt(taskRun);
|
|
21879
|
-
const sandboxContext =
|
|
21249
|
+
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.`;
|
|
21880
21250
|
let resumePromptBlocks;
|
|
21881
21251
|
if (pendingUserPrompt?.length) {
|
|
21882
21252
|
resumePromptBlocks = [
|
|
@@ -21917,7 +21287,7 @@ Continue from where you left off. The user is waiting for your response.`
|
|
|
21917
21287
|
conversationTurns: this.resumeState.conversation.length,
|
|
21918
21288
|
promptLength: promptBlocksToText(resumePromptBlocks).length,
|
|
21919
21289
|
hasPendingUserMessage: !!pendingUserPrompt?.length,
|
|
21920
|
-
|
|
21290
|
+
checkpointApplied,
|
|
21921
21291
|
hasGitCheckpoint: !!this.resumeState.latestGitCheckpoint,
|
|
21922
21292
|
gitCheckpointBranch: this.resumeState.latestGitCheckpoint?.branch ?? null
|
|
21923
21293
|
});
|
|
@@ -22063,23 +21433,23 @@ Continue from where you left off. The user is waiting for your response.`
|
|
|
22063
21433
|
throw new Error(`Failed to download artifact ${artifact.name}`);
|
|
22064
21434
|
}
|
|
22065
21435
|
const safeName = this.getSafeArtifactName(artifact.name);
|
|
22066
|
-
const artifactDir = (0,
|
|
21436
|
+
const artifactDir = (0, import_node_path8.join)(
|
|
22067
21437
|
this.config.repositoryPath ?? "/tmp/workspace",
|
|
22068
21438
|
".posthog",
|
|
22069
21439
|
"attachments",
|
|
22070
21440
|
runId,
|
|
22071
21441
|
artifact.id ?? safeName
|
|
22072
21442
|
);
|
|
22073
|
-
await (0,
|
|
22074
|
-
const artifactPath = (0,
|
|
22075
|
-
await (0,
|
|
21443
|
+
await (0, import_promises5.mkdir)(artifactDir, { recursive: true });
|
|
21444
|
+
const artifactPath = (0, import_node_path8.join)(artifactDir, safeName);
|
|
21445
|
+
await (0, import_promises5.writeFile)(artifactPath, Buffer.from(data));
|
|
22076
21446
|
return resourceLink((0, import_node_url2.pathToFileURL)(artifactPath).toString(), artifact.name, {
|
|
22077
21447
|
...artifact.content_type ? { mimeType: artifact.content_type } : {},
|
|
22078
21448
|
...typeof artifact.size === "number" ? { size: artifact.size } : {}
|
|
22079
21449
|
});
|
|
22080
21450
|
}
|
|
22081
21451
|
getSafeArtifactName(name2) {
|
|
22082
|
-
const baseName = (0,
|
|
21452
|
+
const baseName = (0, import_node_path8.basename)(name2).trim();
|
|
22083
21453
|
const normalizedName = baseName.replace(/[^\w.-]/g, "_");
|
|
22084
21454
|
return normalizedName.length > 0 ? normalizedName : "attachment";
|
|
22085
21455
|
}
|
|
@@ -22427,8 +21797,8 @@ ${attributionInstructions}
|
|
|
22427
21797
|
const meta = params.update?._meta?.claudeCode;
|
|
22428
21798
|
const toolName = meta?.toolName;
|
|
22429
21799
|
const toolResponse = meta?.toolResponse;
|
|
22430
|
-
if ((toolName === "Write" || toolName === "Edit") && toolResponse?.filePath) {
|
|
22431
|
-
await this.
|
|
21800
|
+
if ((toolName === "Write" || toolName === "Edit" || toolName === "MultiEdit" || toolName === "Delete" || toolName === "Move") && toolResponse?.filePath) {
|
|
21801
|
+
await this.captureCheckpointState();
|
|
22432
21802
|
}
|
|
22433
21803
|
if (toolName && (toolName.includes("Bash") || toolName.includes("bash"))) {
|
|
22434
21804
|
this.detectAndAttachPrUrl(payload, params.update);
|
|
@@ -22590,14 +21960,9 @@ ${attributionInstructions}
|
|
|
22590
21960
|
if (!this.session) return;
|
|
22591
21961
|
this.logger.debug("Cleaning up session");
|
|
22592
21962
|
try {
|
|
22593
|
-
await this.
|
|
22594
|
-
} catch (error) {
|
|
22595
|
-
this.logger.error("Failed to capture handoff checkpoint", error);
|
|
22596
|
-
}
|
|
22597
|
-
try {
|
|
22598
|
-
await this.captureTreeState();
|
|
21963
|
+
await this.captureCheckpointState(this.session.pendingHandoffGitState);
|
|
22599
21964
|
} catch (error) {
|
|
22600
|
-
this.logger.error("Failed to capture final
|
|
21965
|
+
this.logger.error("Failed to capture final checkpoint state", error);
|
|
22601
21966
|
}
|
|
22602
21967
|
try {
|
|
22603
21968
|
await this.session.logWriter.flush(this.session.payload.run_id, {
|
|
@@ -22625,41 +21990,13 @@ ${attributionInstructions}
|
|
|
22625
21990
|
this.lastReportedBranch = null;
|
|
22626
21991
|
this.session = null;
|
|
22627
21992
|
}
|
|
22628
|
-
async
|
|
22629
|
-
if (!this.session
|
|
22630
|
-
try {
|
|
22631
|
-
const snapshot = await this.session.treeTracker.captureTree({});
|
|
22632
|
-
if (snapshot) {
|
|
22633
|
-
const snapshotWithDevice = {
|
|
22634
|
-
...snapshot,
|
|
22635
|
-
device: this.session.deviceInfo
|
|
22636
|
-
};
|
|
22637
|
-
const notification = {
|
|
22638
|
-
jsonrpc: "2.0",
|
|
22639
|
-
method: POSTHOG_NOTIFICATIONS.TREE_SNAPSHOT,
|
|
22640
|
-
params: snapshotWithDevice
|
|
22641
|
-
};
|
|
22642
|
-
this.broadcastEvent({
|
|
22643
|
-
type: "notification",
|
|
22644
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
22645
|
-
notification
|
|
22646
|
-
});
|
|
22647
|
-
this.session.logWriter.appendRawLine(
|
|
22648
|
-
this.session.payload.run_id,
|
|
22649
|
-
JSON.stringify(notification)
|
|
22650
|
-
);
|
|
22651
|
-
}
|
|
22652
|
-
} catch (error) {
|
|
22653
|
-
this.logger.error("Failed to capture tree state", error);
|
|
22654
|
-
}
|
|
22655
|
-
}
|
|
22656
|
-
async captureHandoffCheckpoint() {
|
|
22657
|
-
if (!this.session?.treeTracker || !this.session.pendingHandoffGitState) {
|
|
21993
|
+
async captureCheckpointState(localGitState) {
|
|
21994
|
+
if (!this.session || !this.config.repositoryPath) {
|
|
22658
21995
|
return;
|
|
22659
21996
|
}
|
|
22660
21997
|
if (!this.posthogAPI) {
|
|
22661
21998
|
this.logger.warn(
|
|
22662
|
-
"Skipping
|
|
21999
|
+
"Skipping checkpoint capture: PostHog API client is not configured"
|
|
22663
22000
|
);
|
|
22664
22001
|
return;
|
|
22665
22002
|
}
|
|
@@ -22670,9 +22007,7 @@ ${attributionInstructions}
|
|
|
22670
22007
|
apiClient: this.posthogAPI,
|
|
22671
22008
|
logger: this.logger.child("HandoffCheckpoint")
|
|
22672
22009
|
});
|
|
22673
|
-
const checkpoint = await tracker.captureForHandoff(
|
|
22674
|
-
this.session.pendingHandoffGitState
|
|
22675
|
-
);
|
|
22010
|
+
const checkpoint = await tracker.captureForHandoff(localGitState);
|
|
22676
22011
|
if (!checkpoint) return;
|
|
22677
22012
|
const checkpointWithDevice = {
|
|
22678
22013
|
...checkpoint,
|