@posthog/agent 2.3.388 → 2.3.401
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapters/claude/conversion/tool-use-to-acp.js.map +1 -1
- package/dist/adapters/claude/mcp/tool-metadata.d.ts +24 -0
- package/dist/adapters/claude/mcp/tool-metadata.js +165 -0
- package/dist/adapters/claude/mcp/tool-metadata.js.map +1 -0
- package/dist/adapters/claude/tools.js.map +1 -1
- package/dist/agent.js +113 -3
- package/dist/agent.js.map +1 -1
- package/dist/handoff-checkpoint.d.ts +1 -0
- package/dist/handoff-checkpoint.js +17 -1
- package/dist/handoff-checkpoint.js.map +1 -1
- package/dist/index.d.ts +7 -9
- package/dist/index.js.map +1 -1
- package/dist/posthog-api.js +5 -1
- package/dist/posthog-api.js.map +1 -1
- package/dist/server/agent-server.js +258 -101
- package/dist/server/agent-server.js.map +1 -1
- package/dist/server/bin.cjs +248 -98
- package/dist/server/bin.cjs.map +1 -1
- package/dist/tree-tracker.js +128 -97
- package/dist/tree-tracker.js.map +1 -1
- package/package.json +7 -3
- package/src/adapters/claude/claude-agent.ts +5 -0
- package/src/adapters/claude/mcp/tool-metadata.test.ts +93 -0
- package/src/adapters/claude/mcp/tool-metadata.ts +33 -0
- package/src/adapters/claude/permissions/permission-handlers.test.ts +165 -0
- package/src/adapters/claude/permissions/permission-handlers.ts +105 -0
- package/src/adapters/claude/session/instructions.ts +9 -1
- package/src/adapters/claude/types.ts +2 -0
- package/src/handoff-checkpoint.test.ts +1 -0
- package/src/handoff-checkpoint.ts +17 -1
- package/src/sagas/apply-snapshot-saga.test.ts +1 -0
- package/src/sagas/apply-snapshot-saga.ts +68 -54
- package/src/sagas/capture-tree-saga.test.ts +18 -0
- package/src/sagas/capture-tree-saga.ts +64 -49
package/dist/server/bin.cjs
CHANGED
|
@@ -8729,7 +8729,7 @@ var import_zod3 = require("zod");
|
|
|
8729
8729
|
// package.json
|
|
8730
8730
|
var package_default = {
|
|
8731
8731
|
name: "@posthog/agent",
|
|
8732
|
-
version: "2.3.
|
|
8732
|
+
version: "2.3.401",
|
|
8733
8733
|
repository: "https://github.com/PostHog/code",
|
|
8734
8734
|
description: "TypeScript agent framework wrapping Claude Agent SDK with Git-based task execution for PostHog",
|
|
8735
8735
|
exports: {
|
|
@@ -8781,6 +8781,10 @@ var package_default = {
|
|
|
8781
8781
|
types: "./dist/adapters/reasoning-effort.d.ts",
|
|
8782
8782
|
import: "./dist/adapters/reasoning-effort.js"
|
|
8783
8783
|
},
|
|
8784
|
+
"./adapters/claude/mcp/tool-metadata": {
|
|
8785
|
+
types: "./dist/adapters/claude/mcp/tool-metadata.d.ts",
|
|
8786
|
+
import: "./dist/adapters/claude/mcp/tool-metadata.js"
|
|
8787
|
+
},
|
|
8784
8788
|
"./execution-mode": {
|
|
8785
8789
|
types: "./dist/execution-mode.d.ts",
|
|
8786
8790
|
import: "./dist/execution-mode.js"
|
|
@@ -13776,10 +13780,12 @@ async function fetchMcpToolMetadata(q, logger = new Logger({ debug: false, prefi
|
|
|
13776
13780
|
for (const tool of server.tools) {
|
|
13777
13781
|
const toolKey = buildToolKey(server.name, tool.name);
|
|
13778
13782
|
const readOnly = tool.annotations?.readOnly === true;
|
|
13783
|
+
const existing = mcpToolMetadataCache.get(toolKey);
|
|
13779
13784
|
mcpToolMetadataCache.set(toolKey, {
|
|
13780
13785
|
readOnly,
|
|
13781
13786
|
name: tool.name,
|
|
13782
|
-
description: tool.description
|
|
13787
|
+
description: tool.description,
|
|
13788
|
+
approvalState: existing?.approvalState
|
|
13783
13789
|
});
|
|
13784
13790
|
if (readOnly) readOnlyCount++;
|
|
13785
13791
|
}
|
|
@@ -13821,6 +13827,23 @@ function getConnectedMcpServerNames() {
|
|
|
13821
13827
|
}
|
|
13822
13828
|
return [...names];
|
|
13823
13829
|
}
|
|
13830
|
+
function getMcpToolApprovalState(toolName) {
|
|
13831
|
+
return mcpToolMetadataCache.get(toolName)?.approvalState;
|
|
13832
|
+
}
|
|
13833
|
+
function setMcpToolApprovalStates(approvals) {
|
|
13834
|
+
for (const [toolKey, approvalState] of Object.entries(approvals)) {
|
|
13835
|
+
const existing = mcpToolMetadataCache.get(toolKey);
|
|
13836
|
+
if (existing) {
|
|
13837
|
+
existing.approvalState = approvalState;
|
|
13838
|
+
} else {
|
|
13839
|
+
mcpToolMetadataCache.set(toolKey, {
|
|
13840
|
+
readOnly: false,
|
|
13841
|
+
name: toolKey,
|
|
13842
|
+
approvalState
|
|
13843
|
+
});
|
|
13844
|
+
}
|
|
13845
|
+
}
|
|
13846
|
+
}
|
|
13824
13847
|
|
|
13825
13848
|
// src/adapters/claude/conversion/tool-use-to-acp.ts
|
|
13826
13849
|
var SYSTEM_REMINDER_REGEX = /\s*<system-reminder>[\s\S]*?<\/system-reminder>/g;
|
|
@@ -15516,6 +15539,72 @@ async function handleDefaultPermissionFlow(context) {
|
|
|
15516
15539
|
return { behavior: "deny", message, interrupt: !feedback };
|
|
15517
15540
|
}
|
|
15518
15541
|
}
|
|
15542
|
+
function parseMcpToolName(toolName) {
|
|
15543
|
+
const parts2 = toolName.split("__");
|
|
15544
|
+
return {
|
|
15545
|
+
serverName: parts2[1] ?? toolName,
|
|
15546
|
+
tool: parts2.slice(2).join("__") || toolName
|
|
15547
|
+
};
|
|
15548
|
+
}
|
|
15549
|
+
async function handleMcpApprovalFlow(context) {
|
|
15550
|
+
const { toolName, toolInput, toolUseID, client, sessionId } = context;
|
|
15551
|
+
const { serverName, tool: displayTool } = parseMcpToolName(toolName);
|
|
15552
|
+
const metadata2 = getMcpToolMetadata(toolName);
|
|
15553
|
+
const description = metadata2?.description ? `
|
|
15554
|
+
|
|
15555
|
+
${metadata2.description}` : "";
|
|
15556
|
+
const response = await client.requestPermission({
|
|
15557
|
+
options: [
|
|
15558
|
+
{ kind: "allow_once", name: "Yes", optionId: "allow" },
|
|
15559
|
+
{
|
|
15560
|
+
kind: "allow_always",
|
|
15561
|
+
name: "Yes, always allow",
|
|
15562
|
+
optionId: "allow_always"
|
|
15563
|
+
},
|
|
15564
|
+
{
|
|
15565
|
+
kind: "reject_once",
|
|
15566
|
+
name: "Type here to tell the agent what to do differently",
|
|
15567
|
+
optionId: "reject",
|
|
15568
|
+
_meta: { customInput: true }
|
|
15569
|
+
}
|
|
15570
|
+
],
|
|
15571
|
+
sessionId,
|
|
15572
|
+
toolCall: {
|
|
15573
|
+
toolCallId: toolUseID,
|
|
15574
|
+
title: `The agent wants to call ${displayTool} (${serverName})`,
|
|
15575
|
+
kind: "other",
|
|
15576
|
+
content: description ? [{ type: "content", content: text(description) }] : [],
|
|
15577
|
+
rawInput: { ...toolInput, toolName }
|
|
15578
|
+
}
|
|
15579
|
+
});
|
|
15580
|
+
if (context.signal?.aborted || response.outcome?.outcome === "cancelled") {
|
|
15581
|
+
throw new Error("Tool use aborted");
|
|
15582
|
+
}
|
|
15583
|
+
if (response.outcome?.outcome === "selected" && (response.outcome.optionId === "allow" || response.outcome.optionId === "allow_always")) {
|
|
15584
|
+
if (response.outcome.optionId === "allow_always") {
|
|
15585
|
+
return {
|
|
15586
|
+
behavior: "allow",
|
|
15587
|
+
updatedInput: toolInput,
|
|
15588
|
+
updatedPermissions: [
|
|
15589
|
+
{
|
|
15590
|
+
type: "addRules",
|
|
15591
|
+
rules: [{ toolName }],
|
|
15592
|
+
behavior: "allow",
|
|
15593
|
+
destination: "localSettings"
|
|
15594
|
+
}
|
|
15595
|
+
]
|
|
15596
|
+
};
|
|
15597
|
+
}
|
|
15598
|
+
return {
|
|
15599
|
+
behavior: "allow",
|
|
15600
|
+
updatedInput: toolInput
|
|
15601
|
+
};
|
|
15602
|
+
}
|
|
15603
|
+
const feedback = response._meta?.customInput?.trim();
|
|
15604
|
+
const message = feedback ? `User refused permission to run tool with feedback: ${feedback}` : "User refused permission to run tool";
|
|
15605
|
+
await emitToolDenial(context, message);
|
|
15606
|
+
return { behavior: "deny", message, interrupt: !feedback };
|
|
15607
|
+
}
|
|
15519
15608
|
function handlePlanFileException(context) {
|
|
15520
15609
|
const { session, toolName, toolInput } = context;
|
|
15521
15610
|
if (session.permissionMode !== "plan" || !WRITE_TOOLS.has(toolName)) {
|
|
@@ -15586,6 +15675,17 @@ async function canUseTool(context) {
|
|
|
15586
15675
|
}
|
|
15587
15676
|
}
|
|
15588
15677
|
}
|
|
15678
|
+
if (toolName.startsWith("mcp__")) {
|
|
15679
|
+
const approvalState = getMcpToolApprovalState(toolName);
|
|
15680
|
+
if (approvalState === "do_not_use") {
|
|
15681
|
+
const message = "This tool has been blocked. To re-enable it, go to Settings > MCP Servers in PostHog Code.";
|
|
15682
|
+
await emitToolDenial(context, message);
|
|
15683
|
+
return { behavior: "deny", message, interrupt: false };
|
|
15684
|
+
}
|
|
15685
|
+
if (approvalState === "needs_approval") {
|
|
15686
|
+
return handleMcpApprovalFlow(context);
|
|
15687
|
+
}
|
|
15688
|
+
}
|
|
15589
15689
|
if (isToolAllowedForMode(toolName, session.permissionMode)) {
|
|
15590
15690
|
return {
|
|
15591
15691
|
behavior: "allow",
|
|
@@ -15691,7 +15791,14 @@ Only enter plan mode (EnterPlanMode) when the user is requesting a significant c
|
|
|
15691
15791
|
|
|
15692
15792
|
When in doubt, continue executing and incorporate the feedback inline.
|
|
15693
15793
|
`;
|
|
15694
|
-
var
|
|
15794
|
+
var MCP_TOOLS = `
|
|
15795
|
+
# MCP Tool Access
|
|
15796
|
+
|
|
15797
|
+
If an MCP tool call is explicitly denied with a message, relay that denial message to the user exactly as given. Do NOT suggest checking "Claude Code settings."
|
|
15798
|
+
|
|
15799
|
+
If an MCP tool call returns an error, treat it as a normal tool error \u2014 troubleshoot, retry, or inform the user about the specific error. Do NOT assume it is a permissions issue and do NOT direct the user to any settings page.
|
|
15800
|
+
`;
|
|
15801
|
+
var APPENDED_INSTRUCTIONS = BRANCH_NAMING + PLAN_MODE + MCP_TOOLS;
|
|
15695
15802
|
|
|
15696
15803
|
// src/adapters/claude/session/options.ts
|
|
15697
15804
|
function buildSystemPrompt(customPrompt) {
|
|
@@ -17020,6 +17127,9 @@ var ClaudeAcpAgent = class extends BaseAcpAgent {
|
|
|
17020
17127
|
const earlyModelId = settingsManager.getSettings().model || meta?.model || "";
|
|
17021
17128
|
const mcpServers = supportsMcpInjection(earlyModelId) ? parseMcpServers(params) : {};
|
|
17022
17129
|
const systemPrompt = buildSystemPrompt(meta?.systemPrompt);
|
|
17130
|
+
if (meta?.mcpToolApprovals) {
|
|
17131
|
+
setMcpToolApprovalStates(meta.mcpToolApprovals);
|
|
17132
|
+
}
|
|
17023
17133
|
const outputFormat = meta?.jsonSchema && this.options?.onStructuredOutput ? { type: "json_schema", schema: meta.jsonSchema } : void 0;
|
|
17024
17134
|
this.logger.debug(isResume ? "Resuming session" : "Creating new session", {
|
|
17025
17135
|
sessionId,
|
|
@@ -19173,6 +19283,7 @@ var HandoffCheckpointTracker = class {
|
|
|
19173
19283
|
} finally {
|
|
19174
19284
|
await this.removeIfPresent(packPath);
|
|
19175
19285
|
await this.removeIfPresent(indexPath);
|
|
19286
|
+
await this.removeTmpDirIfEmpty(tmpDir);
|
|
19176
19287
|
}
|
|
19177
19288
|
}
|
|
19178
19289
|
toGitCheckpoint(checkpoint) {
|
|
@@ -19331,6 +19442,14 @@ var HandoffCheckpointTracker = class {
|
|
|
19331
19442
|
await (0, import_promises3.rm)(filePath, { force: true }).catch(() => {
|
|
19332
19443
|
});
|
|
19333
19444
|
}
|
|
19445
|
+
async removeTmpDirIfEmpty(tmpDir) {
|
|
19446
|
+
const entries = await (0, import_promises3.readdir)(tmpDir).catch(() => null);
|
|
19447
|
+
if (!entries || entries.length > 0) {
|
|
19448
|
+
return;
|
|
19449
|
+
}
|
|
19450
|
+
await (0, import_promises3.rmdir)(tmpDir).catch(() => {
|
|
19451
|
+
});
|
|
19452
|
+
}
|
|
19334
19453
|
};
|
|
19335
19454
|
|
|
19336
19455
|
// src/utils/gateway.ts
|
|
@@ -20495,62 +20614,77 @@ var ApplySnapshotSaga = class extends Saga {
|
|
|
20495
20614
|
throw new Error("Cannot apply snapshot: no archive URL");
|
|
20496
20615
|
}
|
|
20497
20616
|
const archiveUrl = snapshot.archiveUrl;
|
|
20498
|
-
|
|
20499
|
-
|
|
20500
|
-
|
|
20501
|
-
|
|
20502
|
-
|
|
20503
|
-
});
|
|
20504
|
-
const archivePath = (0, import_node_path8.join)(tmpDir, `${snapshot.treeHash}.tar.gz`);
|
|
20505
|
-
this.archivePath = archivePath;
|
|
20506
|
-
await this.step({
|
|
20507
|
-
name: "download_archive",
|
|
20508
|
-
execute: async () => {
|
|
20509
|
-
const arrayBuffer = await apiClient.downloadArtifact(
|
|
20510
|
-
taskId,
|
|
20511
|
-
runId,
|
|
20512
|
-
archiveUrl
|
|
20513
|
-
);
|
|
20514
|
-
if (!arrayBuffer) {
|
|
20515
|
-
throw new Error("Failed to download archive");
|
|
20617
|
+
try {
|
|
20618
|
+
await this.step({
|
|
20619
|
+
name: "create_tmp_dir",
|
|
20620
|
+
execute: () => (0, import_promises5.mkdir)(tmpDir, { recursive: true }),
|
|
20621
|
+
rollback: async () => {
|
|
20516
20622
|
}
|
|
20517
|
-
|
|
20518
|
-
|
|
20519
|
-
|
|
20520
|
-
|
|
20521
|
-
|
|
20522
|
-
|
|
20523
|
-
|
|
20524
|
-
|
|
20525
|
-
|
|
20526
|
-
|
|
20527
|
-
|
|
20528
|
-
|
|
20529
|
-
|
|
20530
|
-
|
|
20623
|
+
});
|
|
20624
|
+
const archivePath = (0, import_node_path8.join)(tmpDir, `${snapshot.treeHash}.tar.gz`);
|
|
20625
|
+
this.archivePath = archivePath;
|
|
20626
|
+
await this.step({
|
|
20627
|
+
name: "download_archive",
|
|
20628
|
+
execute: async () => {
|
|
20629
|
+
const arrayBuffer = await apiClient.downloadArtifact(
|
|
20630
|
+
taskId,
|
|
20631
|
+
runId,
|
|
20632
|
+
archiveUrl
|
|
20633
|
+
);
|
|
20634
|
+
if (!arrayBuffer) {
|
|
20635
|
+
throw new Error("Failed to download archive");
|
|
20636
|
+
}
|
|
20637
|
+
const base64Content = Buffer.from(arrayBuffer).toString("utf-8");
|
|
20638
|
+
const binaryContent = Buffer.from(base64Content, "base64");
|
|
20639
|
+
await (0, import_promises5.writeFile)(archivePath, binaryContent);
|
|
20640
|
+
this.log.info("Tree archive downloaded", {
|
|
20641
|
+
treeHash: snapshot.treeHash,
|
|
20642
|
+
snapshotBytes: binaryContent.byteLength,
|
|
20643
|
+
snapshotWireBytes: arrayBuffer.byteLength,
|
|
20644
|
+
totalBytes: binaryContent.byteLength,
|
|
20645
|
+
totalWireBytes: arrayBuffer.byteLength
|
|
20531
20646
|
});
|
|
20647
|
+
},
|
|
20648
|
+
rollback: async () => {
|
|
20649
|
+
if (this.archivePath) {
|
|
20650
|
+
await (0, import_promises5.rm)(this.archivePath, { force: true }).catch(() => {
|
|
20651
|
+
});
|
|
20652
|
+
}
|
|
20532
20653
|
}
|
|
20654
|
+
});
|
|
20655
|
+
const gitApplySaga = new ApplyTreeSaga(this.log);
|
|
20656
|
+
const applyResult = await gitApplySaga.run({
|
|
20657
|
+
baseDir: repositoryPath,
|
|
20658
|
+
treeHash: snapshot.treeHash,
|
|
20659
|
+
baseCommit: snapshot.baseCommit,
|
|
20660
|
+
changes: snapshot.changes,
|
|
20661
|
+
archivePath: this.archivePath
|
|
20662
|
+
});
|
|
20663
|
+
if (!applyResult.success) {
|
|
20664
|
+
throw new Error(`Failed to apply tree: ${applyResult.error}`);
|
|
20533
20665
|
}
|
|
20534
|
-
|
|
20535
|
-
|
|
20536
|
-
|
|
20537
|
-
|
|
20538
|
-
|
|
20539
|
-
|
|
20540
|
-
|
|
20541
|
-
|
|
20542
|
-
|
|
20543
|
-
|
|
20544
|
-
|
|
20666
|
+
this.log.info("Tree snapshot applied", {
|
|
20667
|
+
treeHash: snapshot.treeHash,
|
|
20668
|
+
totalChanges: snapshot.changes.length,
|
|
20669
|
+
deletedFiles: snapshot.changes.filter((c) => c.status === "D").length
|
|
20670
|
+
});
|
|
20671
|
+
return { treeHash: snapshot.treeHash };
|
|
20672
|
+
} finally {
|
|
20673
|
+
if (this.archivePath) {
|
|
20674
|
+
await (0, import_promises5.rm)(this.archivePath, { force: true }).catch(() => {
|
|
20675
|
+
});
|
|
20676
|
+
}
|
|
20677
|
+
await this.removeTmpDirIfEmpty(tmpDir);
|
|
20678
|
+
this.archivePath = null;
|
|
20545
20679
|
}
|
|
20546
|
-
|
|
20547
|
-
|
|
20548
|
-
|
|
20549
|
-
|
|
20550
|
-
|
|
20551
|
-
|
|
20680
|
+
}
|
|
20681
|
+
async removeTmpDirIfEmpty(tmpDir) {
|
|
20682
|
+
const entries = await (0, import_promises5.readdir)(tmpDir).catch(() => null);
|
|
20683
|
+
if (!entries || entries.length > 0) {
|
|
20684
|
+
return;
|
|
20685
|
+
}
|
|
20686
|
+
await (0, import_promises5.rmdir)(tmpDir).catch(() => {
|
|
20552
20687
|
});
|
|
20553
|
-
return { treeHash: snapshot.treeHash };
|
|
20554
20688
|
}
|
|
20555
20689
|
};
|
|
20556
20690
|
|
|
@@ -20577,54 +20711,62 @@ var CaptureTreeSaga2 = class extends Saga {
|
|
|
20577
20711
|
}
|
|
20578
20712
|
const shouldArchive = !!apiClient;
|
|
20579
20713
|
const archivePath = shouldArchive ? (0, import_node_path9.join)(tmpDir, `tree-${Date.now()}.tar.gz`) : void 0;
|
|
20580
|
-
|
|
20581
|
-
|
|
20582
|
-
|
|
20583
|
-
|
|
20584
|
-
|
|
20585
|
-
|
|
20586
|
-
|
|
20587
|
-
|
|
20588
|
-
|
|
20589
|
-
|
|
20590
|
-
|
|
20591
|
-
|
|
20592
|
-
|
|
20593
|
-
|
|
20594
|
-
|
|
20595
|
-
|
|
20596
|
-
|
|
20597
|
-
|
|
20598
|
-
|
|
20599
|
-
|
|
20600
|
-
|
|
20601
|
-
|
|
20602
|
-
|
|
20603
|
-
|
|
20604
|
-
|
|
20605
|
-
|
|
20606
|
-
|
|
20607
|
-
|
|
20608
|
-
|
|
20609
|
-
|
|
20714
|
+
try {
|
|
20715
|
+
const gitCaptureSaga = new CaptureTreeSaga(this.log);
|
|
20716
|
+
const captureResult = await gitCaptureSaga.run({
|
|
20717
|
+
baseDir: repositoryPath,
|
|
20718
|
+
lastTreeHash,
|
|
20719
|
+
archivePath
|
|
20720
|
+
});
|
|
20721
|
+
if (!captureResult.success) {
|
|
20722
|
+
throw new Error(`Failed to capture tree: ${captureResult.error}`);
|
|
20723
|
+
}
|
|
20724
|
+
const {
|
|
20725
|
+
snapshot: gitSnapshot,
|
|
20726
|
+
archivePath: createdArchivePath,
|
|
20727
|
+
changed
|
|
20728
|
+
} = captureResult.data;
|
|
20729
|
+
if (!changed || !gitSnapshot) {
|
|
20730
|
+
this.log.debug("No changes since last capture", { lastTreeHash });
|
|
20731
|
+
return { snapshot: null, newTreeHash: lastTreeHash };
|
|
20732
|
+
}
|
|
20733
|
+
let archiveUrl;
|
|
20734
|
+
if (apiClient && createdArchivePath) {
|
|
20735
|
+
try {
|
|
20736
|
+
archiveUrl = await this.uploadArchive(
|
|
20737
|
+
createdArchivePath,
|
|
20738
|
+
gitSnapshot.treeHash,
|
|
20739
|
+
apiClient,
|
|
20740
|
+
taskId,
|
|
20741
|
+
runId
|
|
20742
|
+
);
|
|
20743
|
+
} finally {
|
|
20744
|
+
await (0, import_promises6.rm)(createdArchivePath, { force: true }).catch(() => {
|
|
20745
|
+
});
|
|
20746
|
+
}
|
|
20747
|
+
}
|
|
20748
|
+
const snapshot = {
|
|
20749
|
+
treeHash: gitSnapshot.treeHash,
|
|
20750
|
+
baseCommit: gitSnapshot.baseCommit,
|
|
20751
|
+
changes: gitSnapshot.changes,
|
|
20752
|
+
timestamp: gitSnapshot.timestamp,
|
|
20753
|
+
interrupted,
|
|
20754
|
+
archiveUrl
|
|
20755
|
+
};
|
|
20756
|
+
this.log.info("Tree captured", {
|
|
20757
|
+
treeHash: snapshot.treeHash,
|
|
20758
|
+
changes: snapshot.changes.length,
|
|
20759
|
+
interrupted,
|
|
20760
|
+
archiveUrl
|
|
20761
|
+
});
|
|
20762
|
+
return { snapshot, newTreeHash: snapshot.treeHash };
|
|
20763
|
+
} finally {
|
|
20764
|
+
if (archivePath) {
|
|
20765
|
+
await (0, import_promises6.rm)(archivePath, { force: true }).catch(() => {
|
|
20610
20766
|
});
|
|
20611
20767
|
}
|
|
20768
|
+
await this.removeTmpDirIfEmpty(tmpDir);
|
|
20612
20769
|
}
|
|
20613
|
-
const snapshot = {
|
|
20614
|
-
treeHash: gitSnapshot.treeHash,
|
|
20615
|
-
baseCommit: gitSnapshot.baseCommit,
|
|
20616
|
-
changes: gitSnapshot.changes,
|
|
20617
|
-
timestamp: gitSnapshot.timestamp,
|
|
20618
|
-
interrupted,
|
|
20619
|
-
archiveUrl
|
|
20620
|
-
};
|
|
20621
|
-
this.log.info("Tree captured", {
|
|
20622
|
-
treeHash: snapshot.treeHash,
|
|
20623
|
-
changes: snapshot.changes.length,
|
|
20624
|
-
interrupted,
|
|
20625
|
-
archiveUrl
|
|
20626
|
-
});
|
|
20627
|
-
return { snapshot, newTreeHash: snapshot.treeHash };
|
|
20628
20770
|
}
|
|
20629
20771
|
async uploadArchive(archivePath, treeHash, apiClient, taskId, runId) {
|
|
20630
20772
|
const archiveUrl = await this.step({
|
|
@@ -20663,6 +20805,14 @@ var CaptureTreeSaga2 = class extends Saga {
|
|
|
20663
20805
|
});
|
|
20664
20806
|
return archiveUrl;
|
|
20665
20807
|
}
|
|
20808
|
+
async removeTmpDirIfEmpty(tmpDir) {
|
|
20809
|
+
const entries = await (0, import_promises6.readdir)(tmpDir).catch(() => null);
|
|
20810
|
+
if (!entries || entries.length > 0) {
|
|
20811
|
+
return;
|
|
20812
|
+
}
|
|
20813
|
+
await (0, import_promises6.rmdir)(tmpDir).catch(() => {
|
|
20814
|
+
});
|
|
20815
|
+
}
|
|
20666
20816
|
};
|
|
20667
20817
|
|
|
20668
20818
|
// src/tree-tracker.ts
|