@tickernelz/paperclip-pro-adapter-utils 2026.1006.0 → 2026.1006.2
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 +13 -0
- package/dist/acpx-engine/ephemeral-session-environment.d.ts +4 -0
- package/dist/acpx-engine/ephemeral-session-environment.d.ts.map +1 -0
- package/dist/acpx-engine/ephemeral-session-environment.js +29 -0
- package/dist/acpx-engine/ephemeral-session-environment.js.map +1 -0
- package/dist/acpx-engine/ephemeral-session-environment.test.d.ts +2 -0
- package/dist/acpx-engine/ephemeral-session-environment.test.d.ts.map +1 -0
- package/dist/acpx-engine/ephemeral-session-environment.test.js +177 -0
- package/dist/acpx-engine/ephemeral-session-environment.test.js.map +1 -0
- package/dist/acpx-engine/execute.d.ts +2 -6
- package/dist/acpx-engine/execute.d.ts.map +1 -1
- package/dist/acpx-engine/execute.js +125 -62
- package/dist/acpx-engine/execute.js.map +1 -1
- package/dist/acpx-engine/execute.test.js +299 -3
- package/dist/acpx-engine/execute.test.js.map +1 -1
- package/dist/acpx-engine/session-codec.d.ts.map +1 -1
- package/dist/acpx-engine/session-codec.js +1 -0
- package/dist/acpx-engine/session-codec.js.map +1 -1
- package/dist/acpx-engine/settlement-characterization.test.js +105 -0
- package/dist/acpx-engine/settlement-characterization.test.js.map +1 -1
- package/dist/acpx-engine/spawn-smoke.test.js +16 -7
- package/dist/acpx-engine/spawn-smoke.test.js.map +1 -1
- package/dist/acpx-engine/startup-cancellation.d.ts +1 -0
- package/dist/acpx-engine/startup-cancellation.d.ts.map +1 -1
- package/dist/acpx-engine/startup-cancellation.js +7 -2
- package/dist/acpx-engine/startup-cancellation.js.map +1 -1
- package/dist/acpx-engine/terminal-session-failure.d.ts +18 -0
- package/dist/acpx-engine/terminal-session-failure.d.ts.map +1 -0
- package/dist/acpx-engine/terminal-session-failure.js +106 -0
- package/dist/acpx-engine/terminal-session-failure.js.map +1 -0
- package/dist/acpx-engine/terminal-session-failure.test.d.ts +2 -0
- package/dist/acpx-engine/terminal-session-failure.test.d.ts.map +1 -0
- package/dist/acpx-engine/terminal-session-failure.test.js +139 -0
- package/dist/acpx-engine/terminal-session-failure.test.js.map +1 -0
- package/dist/acpx-engine/turn-characterization.test.js +4 -3
- package/dist/acpx-engine/turn-characterization.test.js.map +1 -1
- package/dist/command-managed-runtime.d.ts +2 -0
- package/dist/command-managed-runtime.d.ts.map +1 -1
- package/dist/command-managed-runtime.js +2 -0
- package/dist/command-managed-runtime.js.map +1 -1
- package/dist/command-redaction.d.ts +2 -0
- package/dist/command-redaction.d.ts.map +1 -1
- package/dist/command-redaction.js +20 -10
- package/dist/command-redaction.js.map +1 -1
- package/dist/command-redaction.test.js +20 -1
- package/dist/command-redaction.test.js.map +1 -1
- package/dist/directory-merge-lock.test.d.ts +2 -0
- package/dist/directory-merge-lock.test.d.ts.map +1 -0
- package/dist/directory-merge-lock.test.js +166 -0
- package/dist/directory-merge-lock.test.js.map +1 -0
- package/dist/execution-phase.d.ts +10 -0
- package/dist/execution-phase.d.ts.map +1 -0
- package/dist/execution-phase.js +27 -0
- package/dist/execution-phase.js.map +1 -0
- package/dist/execution-phase.test.d.ts +2 -0
- package/dist/execution-phase.test.d.ts.map +1 -0
- package/dist/execution-phase.test.js +26 -0
- package/dist/execution-phase.test.js.map +1 -0
- package/dist/execution-target-sandbox.test.js +49 -7
- package/dist/execution-target-sandbox.test.js.map +1 -1
- package/dist/execution-target-stdin-race.test.js +245 -2
- package/dist/execution-target-stdin-race.test.js.map +1 -1
- package/dist/execution-target.d.ts +6 -0
- package/dist/execution-target.d.ts.map +1 -1
- package/dist/execution-target.js +74 -22
- package/dist/execution-target.js.map +1 -1
- package/dist/git-workspace-sync.d.ts +15 -5
- package/dist/git-workspace-sync.d.ts.map +1 -1
- package/dist/git-workspace-sync.js +267 -124
- package/dist/git-workspace-sync.js.map +1 -1
- package/dist/git-workspace-sync.test.js +296 -20
- package/dist/git-workspace-sync.test.js.map +1 -1
- package/dist/github-launcher.d.ts.map +1 -1
- package/dist/github-launcher.js +26 -11
- package/dist/github-launcher.js.map +1 -1
- package/dist/github-launcher.test.js +34 -1
- package/dist/github-launcher.test.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/paperclip-runner-permissions.d.ts +28 -1
- package/dist/paperclip-runner-permissions.d.ts.map +1 -1
- package/dist/paperclip-runner-permissions.js +9 -1
- package/dist/paperclip-runner-permissions.js.map +1 -1
- package/dist/prompt-sections.test.d.ts +2 -0
- package/dist/prompt-sections.test.d.ts.map +1 -0
- package/dist/prompt-sections.test.js +53 -0
- package/dist/prompt-sections.test.js.map +1 -0
- package/dist/provider-stopped-boundary.d.ts +7 -0
- package/dist/provider-stopped-boundary.d.ts.map +1 -0
- package/dist/provider-stopped-boundary.js +22 -0
- package/dist/provider-stopped-boundary.js.map +1 -0
- package/dist/provider-stopped-boundary.test.d.ts +2 -0
- package/dist/provider-stopped-boundary.test.d.ts.map +1 -0
- package/dist/provider-stopped-boundary.test.js +76 -0
- package/dist/provider-stopped-boundary.test.js.map +1 -0
- package/dist/remote-managed-runtime.d.ts +2 -0
- package/dist/remote-managed-runtime.d.ts.map +1 -1
- package/dist/remote-managed-runtime.js +3 -1
- package/dist/remote-managed-runtime.js.map +1 -1
- package/dist/remote-managed-runtime.test.js +25 -0
- package/dist/remote-managed-runtime.test.js.map +1 -1
- package/dist/sandbox-callback-bridge.d.ts +2 -0
- package/dist/sandbox-callback-bridge.d.ts.map +1 -1
- package/dist/sandbox-callback-bridge.js +34 -10
- package/dist/sandbox-callback-bridge.js.map +1 -1
- package/dist/sandbox-callback-bridge.test.js +106 -3
- package/dist/sandbox-callback-bridge.test.js.map +1 -1
- package/dist/sandbox-managed-runtime.d.ts +3 -0
- package/dist/sandbox-managed-runtime.d.ts.map +1 -1
- package/dist/sandbox-managed-runtime.js +749 -718
- package/dist/sandbox-managed-runtime.js.map +1 -1
- package/dist/sandbox-managed-runtime.test.js +171 -2
- package/dist/sandbox-managed-runtime.test.js.map +1 -1
- package/dist/server-utils.d.ts +43 -1
- package/dist/server-utils.d.ts.map +1 -1
- package/dist/server-utils.js +103 -31
- package/dist/server-utils.js.map +1 -1
- package/dist/server-utils.test.js +235 -45
- package/dist/server-utils.test.js.map +1 -1
- package/dist/session-compaction.d.ts.map +1 -1
- package/dist/session-compaction.js +6 -0
- package/dist/session-compaction.js.map +1 -1
- package/dist/ssh-fixture.test.js +22 -0
- package/dist/ssh-fixture.test.js.map +1 -1
- package/dist/ssh.d.ts +2 -0
- package/dist/ssh.d.ts.map +1 -1
- package/dist/ssh.js +2 -2
- package/dist/ssh.js.map +1 -1
- package/dist/test-fixtures/prompt-context.d.ts +54 -0
- package/dist/test-fixtures/prompt-context.d.ts.map +1 -0
- package/dist/test-fixtures/prompt-context.js +55 -0
- package/dist/test-fixtures/prompt-context.js.map +1 -0
- package/dist/types.d.ts +12 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/workspace-git-stream.d.ts +19 -0
- package/dist/workspace-git-stream.d.ts.map +1 -0
- package/dist/workspace-git-stream.js +99 -0
- package/dist/workspace-git-stream.js.map +1 -0
- package/dist/workspace-git-stream.test.d.ts +2 -0
- package/dist/workspace-git-stream.test.d.ts.map +1 -0
- package/dist/workspace-git-stream.test.js +71 -0
- package/dist/workspace-git-stream.test.js.map +1 -0
- package/dist/workspace-manifest.d.ts +61 -0
- package/dist/workspace-manifest.d.ts.map +1 -0
- package/dist/workspace-manifest.js +257 -0
- package/dist/workspace-manifest.js.map +1 -0
- package/dist/workspace-manifest.test.d.ts +2 -0
- package/dist/workspace-manifest.test.d.ts.map +1 -0
- package/dist/workspace-manifest.test.js +160 -0
- package/dist/workspace-manifest.test.js.map +1 -0
- package/dist/workspace-restore-diagnostics.d.ts +34 -0
- package/dist/workspace-restore-diagnostics.d.ts.map +1 -0
- package/dist/workspace-restore-diagnostics.js +238 -0
- package/dist/workspace-restore-diagnostics.js.map +1 -0
- package/dist/workspace-restore-diagnostics.test.d.ts +2 -0
- package/dist/workspace-restore-diagnostics.test.d.ts.map +1 -0
- package/dist/workspace-restore-diagnostics.test.js +258 -0
- package/dist/workspace-restore-diagnostics.test.js.map +1 -0
- package/dist/workspace-restore-merge.d.ts +47 -6
- package/dist/workspace-restore-merge.d.ts.map +1 -1
- package/dist/workspace-restore-merge.js +382 -114
- package/dist/workspace-restore-merge.js.map +1 -1
- package/dist/workspace-restore-merge.test.js +253 -4
- package/dist/workspace-restore-merge.test.js.map +1 -1
- package/dist/workspace-restore-result.d.ts +6 -0
- package/dist/workspace-restore-result.d.ts.map +1 -0
- package/dist/workspace-restore-result.js +72 -0
- package/dist/workspace-restore-result.js.map +1 -0
- package/dist/workspace-restore-result.test.d.ts +2 -0
- package/dist/workspace-restore-result.test.d.ts.map +1 -0
- package/dist/workspace-restore-result.test.js +74 -0
- package/dist/workspace-restore-result.test.js.map +1 -0
- package/dist/workspace-restore-teardown.d.ts.map +1 -1
- package/dist/workspace-restore-teardown.js +5 -3
- package/dist/workspace-restore-teardown.js.map +1 -1
- package/dist/workspace-restore-teardown.test.js +24 -0
- package/dist/workspace-restore-teardown.test.js.map +1 -1
- package/node_modules/acpx/dist/live-checkpoint-ClPCSdrW.js +4 -3
- package/package.json +2 -2
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import { execFile, spawn } from "node:child_process";
|
|
2
|
+
import { createHash } from "node:crypto";
|
|
3
|
+
import { once } from "node:events";
|
|
4
|
+
import { access, link, mkdir, mkdtemp, readFile, realpath, rm, stat, symlink, writeFile } from "node:fs/promises";
|
|
5
|
+
import os from "node:os";
|
|
6
|
+
import path from "node:path";
|
|
7
|
+
import { fileURLToPath } from "node:url";
|
|
8
|
+
import { promisify } from "node:util";
|
|
9
|
+
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
10
|
+
import { withDirectoryMergeLock, WORKSPACE_RESTORE_LOCK_TIMEOUT_CODE } from "./workspace-restore-merge.js";
|
|
11
|
+
describe("directory merge lock process lifetime", () => {
|
|
12
|
+
// Load tsx as an --import hook, not tsx's own CLI entry point. The CLI entry
|
|
13
|
+
// point re-spawns the evaluated code in a further child process, so killing
|
|
14
|
+
// the process this file spawns would leave that further child as an orphan
|
|
15
|
+
// that still holds the lock. The --import hook runs the evaluated code in
|
|
16
|
+
// the process this file spawns directly, so killing it really does release
|
|
17
|
+
// the lock.
|
|
18
|
+
const loader = fileURLToPath(new URL("../../../cli/node_modules/tsx/dist/loader.mjs", import.meta.url));
|
|
19
|
+
const module = fileURLToPath(new URL("./workspace-restore-merge.ts", import.meta.url));
|
|
20
|
+
const directories = [];
|
|
21
|
+
const children = [];
|
|
22
|
+
afterEach(async () => {
|
|
23
|
+
vi.restoreAllMocks();
|
|
24
|
+
for (const child of children.splice(0)) {
|
|
25
|
+
if (child.exitCode === null && child.signalCode === null) {
|
|
26
|
+
const exited = once(child, "exit");
|
|
27
|
+
child.kill("SIGKILL");
|
|
28
|
+
await exited;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
await Promise.all(directories.splice(0).map((dir) => rm(dir, { recursive: true, force: true })));
|
|
32
|
+
});
|
|
33
|
+
async function fixture() {
|
|
34
|
+
const root = await mkdtemp(path.join(os.tmpdir(), "paperclip-lock-process-"));
|
|
35
|
+
directories.push(root);
|
|
36
|
+
const target = path.join(root, "target");
|
|
37
|
+
await mkdir(target);
|
|
38
|
+
const env = { ...process.env, PAPERCLIP_HOME: path.join(root, "home"), PAPERCLIP_INSTANCE_ID: "test" };
|
|
39
|
+
const key = createHash("sha256").update(await realpath(target)).digest("hex");
|
|
40
|
+
const lock = path.join(env.PAPERCLIP_HOME, "instances", "test", "locks", "directory-merge", `${key}.lock`);
|
|
41
|
+
return { target, env, lock };
|
|
42
|
+
}
|
|
43
|
+
async function holder(target, env) {
|
|
44
|
+
const child = spawn(process.execPath, ["--import", loader, "--eval", `
|
|
45
|
+
import { withDirectoryMergeLock } from ${JSON.stringify(module)};
|
|
46
|
+
withDirectoryMergeLock(${JSON.stringify(target)}, async () => {
|
|
47
|
+
process.send?.("locked");
|
|
48
|
+
await new Promise(resolve => process.once("message", resolve));
|
|
49
|
+
}).then(() => process.exit(0)).catch(error => { console.error(error); process.exit(1); });
|
|
50
|
+
`], { env, stdio: ["ignore", "ignore", "pipe", "ipc"] });
|
|
51
|
+
children.push(child);
|
|
52
|
+
let stderr = "";
|
|
53
|
+
child.stderr?.on("data", (chunk) => { stderr += chunk; });
|
|
54
|
+
await new Promise((resolve, reject) => {
|
|
55
|
+
const timer = setTimeout(() => reject(new Error(`Child did not acquire lock: ${stderr}`)), 10_000);
|
|
56
|
+
child.once("message", () => { clearTimeout(timer); resolve(); });
|
|
57
|
+
child.once("error", (error) => { clearTimeout(timer); reject(error); });
|
|
58
|
+
child.once("exit", (code) => { clearTimeout(timer); reject(new Error(`Child exited ${code}: ${stderr}`)); });
|
|
59
|
+
});
|
|
60
|
+
return child;
|
|
61
|
+
}
|
|
62
|
+
// Both protocols carry diagnostic owner records. This also lets the crash
|
|
63
|
+
// regression demonstrate the old implementation's PID-reuse failure.
|
|
64
|
+
async function ownerPath(lock) {
|
|
65
|
+
return await access(`${lock}.owner.json`).then(() => `${lock}.owner.json`, () => path.join(lock, "owner.json"));
|
|
66
|
+
}
|
|
67
|
+
// A short real wait budget for a test that asserts a timeout. 200 ms still
|
|
68
|
+
// lets the implementation's 50 ms retry interval run at least 4 retries, so
|
|
69
|
+
// the timeout is reached because the lock is genuinely held, not because
|
|
70
|
+
// the clock was replaced.
|
|
71
|
+
const TIMEOUT_ASSERTION_WAIT_MS = 200;
|
|
72
|
+
// A short real wait budget for the crash-recovery test, which asserts a
|
|
73
|
+
// successful acquisition. It must absorb ordinary scheduling jitter around
|
|
74
|
+
// the crash while still resolving well inside the test timeout below.
|
|
75
|
+
const CRASH_RECOVERY_WAIT_MS = 5_000;
|
|
76
|
+
it("recovers a killed holder even when its recorded PID has been reused", async () => {
|
|
77
|
+
const { target, env, lock } = await fixture();
|
|
78
|
+
const child = await holder(target, env);
|
|
79
|
+
const exited = once(child, "exit");
|
|
80
|
+
child.kill("SIGKILL");
|
|
81
|
+
await exited;
|
|
82
|
+
const recordPath = await ownerPath(lock);
|
|
83
|
+
const record = JSON.parse(await readFile(recordPath, "utf8"));
|
|
84
|
+
await writeFile(recordPath, JSON.stringify({ ...record, pid: process.pid }));
|
|
85
|
+
await expect(withDirectoryMergeLock(target, async () => "restored", env, undefined, CRASH_RECOVERY_WAIT_MS)).resolves.toBe("restored");
|
|
86
|
+
}, 15_000);
|
|
87
|
+
it("protects a live holder in another process regardless of diagnostic PID or age", async () => {
|
|
88
|
+
const { target, env, lock } = await fixture();
|
|
89
|
+
const child = await holder(target, env);
|
|
90
|
+
const recordPath = await ownerPath(lock);
|
|
91
|
+
await writeFile(recordPath, JSON.stringify({ pid: 2_147_483_647, createdAt: "2000-01-01T00:00:00.000Z" }));
|
|
92
|
+
const contender = vi.fn();
|
|
93
|
+
await expect(withDirectoryMergeLock(target, contender, env, undefined, TIMEOUT_ASSERTION_WAIT_MS)).rejects.toMatchObject({ code: WORKSPACE_RESTORE_LOCK_TIMEOUT_CODE });
|
|
94
|
+
expect(contender).not.toHaveBeenCalled();
|
|
95
|
+
const exited = once(child, "exit");
|
|
96
|
+
child.send("release");
|
|
97
|
+
await exited;
|
|
98
|
+
await expect(withDirectoryMergeLock(target, async () => "released", env)).resolves.toBe("released");
|
|
99
|
+
}, 15_000);
|
|
100
|
+
it("releases ownership when the protected operation throws", async () => {
|
|
101
|
+
const { target, env } = await fixture();
|
|
102
|
+
await expect(withDirectoryMergeLock(target, async () => { throw new Error("operation failed"); }, env)).rejects.toThrow("operation failed");
|
|
103
|
+
await expect(withDirectoryMergeLock(target, async () => "next", env)).resolves.toBe("next");
|
|
104
|
+
});
|
|
105
|
+
it("keeps the OS lock when a same-process contender closes its connection", async () => {
|
|
106
|
+
const { target, env } = await fixture();
|
|
107
|
+
await withDirectoryMergeLock(target, async () => {
|
|
108
|
+
await expect(withDirectoryMergeLock(target, async () => undefined, env, undefined, TIMEOUT_ASSERTION_WAIT_MS)).rejects.toMatchObject({ code: WORKSPACE_RESTORE_LOCK_TIMEOUT_CODE });
|
|
109
|
+
// A same-process test alone cannot prove that the OS lock survived: on
|
|
110
|
+
// POSIX, closing an unmanaged descriptor can drop process-wide locks.
|
|
111
|
+
const result = await promisify(execFile)(process.execPath, ["--import", loader, "--eval", `
|
|
112
|
+
import { withDirectoryMergeLock, WORKSPACE_RESTORE_LOCK_TIMEOUT_CODE } from ${JSON.stringify(module)};
|
|
113
|
+
withDirectoryMergeLock(${JSON.stringify(target)}, async () => "entered", undefined, undefined, ${TIMEOUT_ASSERTION_WAIT_MS})
|
|
114
|
+
.then(() => { console.error("Entered a live holder's lock"); process.exit(1); })
|
|
115
|
+
.catch(error => {
|
|
116
|
+
if (error.code !== WORKSPACE_RESTORE_LOCK_TIMEOUT_CODE) { console.error(error); process.exit(1); }
|
|
117
|
+
console.log("blocked");
|
|
118
|
+
});
|
|
119
|
+
`], { env, timeout: 10_000 });
|
|
120
|
+
expect(result.stdout.trim()).toBe("blocked");
|
|
121
|
+
}, env);
|
|
122
|
+
}, 15_000);
|
|
123
|
+
it("does not serialize unrelated target directories", async () => {
|
|
124
|
+
const { target, env } = await fixture();
|
|
125
|
+
const other = `${target}-other`;
|
|
126
|
+
await mkdir(other);
|
|
127
|
+
await withDirectoryMergeLock(target, async () => {
|
|
128
|
+
await expect(withDirectoryMergeLock(other, async () => "independent", env)).resolves.toBe("independent");
|
|
129
|
+
}, env);
|
|
130
|
+
});
|
|
131
|
+
it("retains the same database inode across holders", async () => {
|
|
132
|
+
const { target, env, lock } = await fixture();
|
|
133
|
+
await withDirectoryMergeLock(target, async () => undefined, env);
|
|
134
|
+
const before = await stat(`${lock}.sqlite`);
|
|
135
|
+
await withDirectoryMergeLock(target, async () => undefined, env);
|
|
136
|
+
const after = await stat(`${lock}.sqlite`);
|
|
137
|
+
expect({ dev: after.dev, ino: after.ino }).toEqual({ dev: before.dev, ino: before.ino });
|
|
138
|
+
});
|
|
139
|
+
it("closes the kernel lock when writing diagnostics fails", async () => {
|
|
140
|
+
const { target, env, lock } = await fixture();
|
|
141
|
+
await mkdir(`${lock}.owner.json`, { recursive: true });
|
|
142
|
+
await expect(withDirectoryMergeLock(target, async () => undefined, env)).rejects.toThrow();
|
|
143
|
+
await rm(`${lock}.owner.json`, { recursive: true });
|
|
144
|
+
await expect(withDirectoryMergeLock(target, async () => "next", env)).resolves.toBe("next");
|
|
145
|
+
});
|
|
146
|
+
it.each(["missing", "malformed", "dead PID"])("does not guess ownership of a legacy lock with %s metadata", async (kind) => {
|
|
147
|
+
const { target, env, lock } = await fixture();
|
|
148
|
+
await mkdir(lock, { recursive: true });
|
|
149
|
+
if (kind !== "missing")
|
|
150
|
+
await writeFile(path.join(lock, "owner.json"), kind === "malformed" ? "{broken" : JSON.stringify({ pid: 2_147_483_647, createdAt: "2000-01-01T00:00:00.000Z" }));
|
|
151
|
+
const contender = vi.fn();
|
|
152
|
+
await expect(withDirectoryMergeLock(target, contender, env, undefined, TIMEOUT_ASSERTION_WAIT_MS)).rejects.toMatchObject({ code: WORKSPACE_RESTORE_LOCK_TIMEOUT_CODE });
|
|
153
|
+
expect(contender).not.toHaveBeenCalled();
|
|
154
|
+
expect((await stat(lock)).isDirectory()).toBe(true);
|
|
155
|
+
});
|
|
156
|
+
it.skipIf(process.platform === "win32").each(["symlink", "hard link"])("rejects a lock database that is a %s", async (kind) => {
|
|
157
|
+
const { target, env, lock } = await fixture();
|
|
158
|
+
await mkdir(path.dirname(lock), { recursive: true });
|
|
159
|
+
const decoy = `${target}-decoy`;
|
|
160
|
+
await writeFile(decoy, "keep");
|
|
161
|
+
await (kind === "symlink" ? symlink(decoy, `${lock}.sqlite`) : link(decoy, `${lock}.sqlite`));
|
|
162
|
+
await expect(withDirectoryMergeLock(target, async () => undefined, env)).rejects.toThrow("not a plain, unshared file");
|
|
163
|
+
await expect(readFile(decoy, "utf8")).resolves.toBe("keep");
|
|
164
|
+
});
|
|
165
|
+
});
|
|
166
|
+
//# sourceMappingURL=directory-merge-lock.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"directory-merge-lock.test.js","sourceRoot":"","sources":["../src/directory-merge-lock.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAqB,MAAM,oBAAoB,CAAC;AACxE,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AACnC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAClH,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAC7D,OAAO,EAAE,sBAAsB,EAAE,mCAAmC,EAAE,MAAM,8BAA8B,CAAC;AAE3G,QAAQ,CAAC,uCAAuC,EAAE,GAAG,EAAE;IACrD,6EAA6E;IAC7E,4EAA4E;IAC5E,2EAA2E;IAC3E,0EAA0E;IAC1E,2EAA2E;IAC3E,YAAY;IACZ,MAAM,MAAM,GAAG,aAAa,CAAC,IAAI,GAAG,CAAC,+CAA+C,EAAE,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;IACxG,MAAM,MAAM,GAAG,aAAa,CAAC,IAAI,GAAG,CAAC,8BAA8B,EAAE,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;IACvF,MAAM,WAAW,GAAa,EAAE,CAAC;IACjC,MAAM,QAAQ,GAAmB,EAAE,CAAC;IACpC,SAAS,CAAC,KAAK,IAAI,EAAE;QACnB,EAAE,CAAC,eAAe,EAAE,CAAC;QACrB,KAAK,MAAM,KAAK,IAAI,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC;YACvC,IAAI,KAAK,CAAC,QAAQ,KAAK,IAAI,IAAI,KAAK,CAAC,UAAU,KAAK,IAAI,EAAE,CAAC;gBACzD,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;gBACnC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;gBACtB,MAAM,MAAM,CAAC;YACf,CAAC;QACH,CAAC;QACD,MAAM,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,EAAE,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IACnG,CAAC,CAAC,CAAC;IAEH,KAAK,UAAU,OAAO;QACpB,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,yBAAyB,CAAC,CAAC,CAAC;QAC9E,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACvB,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;QACzC,MAAM,KAAK,CAAC,MAAM,CAAC,CAAC;QACpB,MAAM,GAAG,GAAG,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE,cAAc,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE,qBAAqB,EAAE,MAAM,EAAE,CAAC;QACvG,MAAM,GAAG,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,MAAM,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAC9E,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,cAAc,EAAE,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,iBAAiB,EAAE,GAAG,GAAG,OAAO,CAAC,CAAC;QAC3G,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC;IAC/B,CAAC;IAED,KAAK,UAAU,MAAM,CAAC,MAAc,EAAE,GAAsB;QAC1D,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE;+CAC1B,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC;+BACtC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC;;;;KAIhD,CAAC,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,CAAC,CAAC;QACzD,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACrB,IAAI,MAAM,GAAG,EAAE,CAAC;QAChB,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,EAAE,GAAG,MAAM,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;QAC1D,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YAC1C,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,+BAA+B,MAAM,EAAE,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;YACnG,KAAK,CAAC,IAAI,CAAC,SAAS,EAAE,GAAG,EAAE,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;YACjE,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YACxE,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,gBAAgB,IAAI,KAAK,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAC/G,CAAC,CAAC,CAAC;QACH,OAAO,KAAK,CAAC;IACf,CAAC;IAED,0EAA0E;IAC1E,qEAAqE;IACrE,KAAK,UAAU,SAAS,CAAC,IAAY;QACnC,OAAO,MAAM,MAAM,CAAC,GAAG,IAAI,aAAa,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,GAAG,IAAI,aAAa,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC,CAAC;IAClH,CAAC;IAED,2EAA2E;IAC3E,4EAA4E;IAC5E,yEAAyE;IACzE,0BAA0B;IAC1B,MAAM,yBAAyB,GAAG,GAAG,CAAC;IACtC,wEAAwE;IACxE,2EAA2E;IAC3E,sEAAsE;IACtE,MAAM,sBAAsB,GAAG,KAAK,CAAC;IAErC,EAAE,CAAC,qEAAqE,EAAE,KAAK,IAAI,EAAE;QACnF,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,MAAM,OAAO,EAAE,CAAC;QAC9C,MAAM,KAAK,GAAG,MAAM,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QACxC,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;QACnC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACtB,MAAM,MAAM,CAAC;QACb,MAAM,UAAU,GAAG,MAAM,SAAS,CAAC,IAAI,CAAC,CAAC;QACzC,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC,CAAC;QAC9D,MAAM,SAAS,CAAC,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,GAAG,MAAM,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;QAC7E,MAAM,MAAM,CAAC,sBAAsB,CAAC,MAAM,EAAE,KAAK,IAAI,EAAE,CAAC,UAAU,EAAE,GAAG,EAAE,SAAS,EAAE,sBAAsB,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IACzI,CAAC,EAAE,MAAM,CAAC,CAAC;IAEX,EAAE,CAAC,+EAA+E,EAAE,KAAK,IAAI,EAAE;QAC7F,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,MAAM,OAAO,EAAE,CAAC;QAC9C,MAAM,KAAK,GAAG,MAAM,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QACxC,MAAM,UAAU,GAAG,MAAM,SAAS,CAAC,IAAI,CAAC,CAAC;QACzC,MAAM,SAAS,CAAC,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,GAAG,EAAE,aAAa,EAAE,SAAS,EAAE,0BAA0B,EAAE,CAAC,CAAC,CAAC;QAC3G,MAAM,SAAS,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC;QAC1B,MAAM,MAAM,CAAC,sBAAsB,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,SAAS,EAAE,yBAAyB,CAAC,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC,EAAE,IAAI,EAAE,mCAAmC,EAAE,CAAC,CAAC;QACxK,MAAM,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,gBAAgB,EAAE,CAAC;QACzC,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;QACnC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACtB,MAAM,MAAM,CAAC;QACb,MAAM,MAAM,CAAC,sBAAsB,CAAC,MAAM,EAAE,KAAK,IAAI,EAAE,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IACtG,CAAC,EAAE,MAAM,CAAC,CAAC;IAEX,EAAE,CAAC,wDAAwD,EAAE,KAAK,IAAI,EAAE;QACtE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,MAAM,OAAO,EAAE,CAAC;QACxC,MAAM,MAAM,CAAC,sBAAsB,CAAC,MAAM,EAAE,KAAK,IAAI,EAAE,GAAG,MAAM,IAAI,KAAK,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,kBAAkB,CAAC,CAAC;QAC5I,MAAM,MAAM,CAAC,sBAAsB,CAAC,MAAM,EAAE,KAAK,IAAI,EAAE,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAC9F,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uEAAuE,EAAE,KAAK,IAAI,EAAE;QACrF,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,MAAM,OAAO,EAAE,CAAC;QACxC,MAAM,sBAAsB,CAAC,MAAM,EAAE,KAAK,IAAI,EAAE;YAC9C,MAAM,MAAM,CAAC,sBAAsB,CAAC,MAAM,EAAE,KAAK,IAAI,EAAE,CAAC,SAAS,EAAE,GAAG,EAAE,SAAS,EAAE,yBAAyB,CAAC,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC,EAAE,IAAI,EAAE,mCAAmC,EAAE,CAAC,CAAC;YACpL,uEAAuE;YACvE,sEAAsE;YACtE,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE;sFACV,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC;iCAC3E,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,kDAAkD,yBAAyB;;;;;;OAM3H,CAAC,EAAE,EAAE,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC;YAC9B,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QAC/C,CAAC,EAAE,GAAG,CAAC,CAAC;IACV,CAAC,EAAE,MAAM,CAAC,CAAC;IAEX,EAAE,CAAC,iDAAiD,EAAE,KAAK,IAAI,EAAE;QAC/D,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,MAAM,OAAO,EAAE,CAAC;QACxC,MAAM,KAAK,GAAG,GAAG,MAAM,QAAQ,CAAC;QAChC,MAAM,KAAK,CAAC,KAAK,CAAC,CAAC;QACnB,MAAM,sBAAsB,CAAC,MAAM,EAAE,KAAK,IAAI,EAAE;YAC9C,MAAM,MAAM,CAAC,sBAAsB,CAAC,KAAK,EAAE,KAAK,IAAI,EAAE,CAAC,aAAa,EAAE,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;QAC3G,CAAC,EAAE,GAAG,CAAC,CAAC;IACV,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gDAAgD,EAAE,KAAK,IAAI,EAAE;QAC9D,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,MAAM,OAAO,EAAE,CAAC;QAC9C,MAAM,sBAAsB,CAAC,MAAM,EAAE,KAAK,IAAI,EAAE,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;QACjE,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,GAAG,IAAI,SAAS,CAAC,CAAC;QAC5C,MAAM,sBAAsB,CAAC,MAAM,EAAE,KAAK,IAAI,EAAE,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;QACjE,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,GAAG,IAAI,SAAS,CAAC,CAAC;QAC3C,MAAM,CAAC,EAAE,GAAG,EAAE,KAAK,CAAC,GAAG,EAAE,GAAG,EAAE,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE,GAAG,EAAE,MAAM,CAAC,GAAG,EAAE,GAAG,EAAE,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC;IAC3F,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uDAAuD,EAAE,KAAK,IAAI,EAAE;QACrE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,MAAM,OAAO,EAAE,CAAC;QAC9C,MAAM,KAAK,CAAC,GAAG,IAAI,aAAa,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACvD,MAAM,MAAM,CAAC,sBAAsB,CAAC,MAAM,EAAE,KAAK,IAAI,EAAE,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;QAC3F,MAAM,EAAE,CAAC,GAAG,IAAI,aAAa,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACpD,MAAM,MAAM,CAAC,sBAAsB,CAAC,MAAM,EAAE,KAAK,IAAI,EAAE,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAC9F,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,WAAW,EAAE,UAAU,CAAC,CAAC,CAAC,4DAA4D,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE;QACzH,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,MAAM,OAAO,EAAE,CAAC;QAC9C,MAAM,KAAK,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACvC,IAAI,IAAI,KAAK,SAAS;YAAE,MAAM,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,YAAY,CAAC,EAAE,IAAI,KAAK,WAAW,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,GAAG,EAAE,aAAa,EAAE,SAAS,EAAE,0BAA0B,EAAE,CAAC,CAAC,CAAC;QACzL,MAAM,SAAS,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC;QAC1B,MAAM,MAAM,CAAC,sBAAsB,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,SAAS,EAAE,yBAAyB,CAAC,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC,EAAE,IAAI,EAAE,mCAAmC,EAAE,CAAC,CAAC;QACxK,MAAM,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,gBAAgB,EAAE,CAAC;QACzC,MAAM,CAAC,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACtD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC,CAAC,sCAAsC,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE;QAC5H,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,MAAM,OAAO,EAAE,CAAC;QAC9C,MAAM,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACrD,MAAM,KAAK,GAAG,GAAG,MAAM,QAAQ,CAAC;QAChC,MAAM,SAAS,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;QAC/B,MAAM,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,IAAI,SAAS,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,GAAG,IAAI,SAAS,CAAC,CAAC,CAAC;QAC9F,MAAM,MAAM,CAAC,sBAAsB,CAAC,MAAM,EAAE,KAAK,IAAI,EAAE,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,4BAA4B,CAAC,CAAC;QACvH,MAAM,MAAM,CAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAC9D,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/** Content-free, in-memory diagnostic scopes. These never establish stop proof. */
|
|
2
|
+
export declare const ADAPTER_EXECUTION_PHASES: readonly ["host_execution", "adapter_execution", "end_session", "cancel_turn", "close_session", "settle_reuse", "stop_transport", "sync_back", "instruction_collection", "workspace_restore", "phase_reporting", "instruction_cleanup", "lease_release"];
|
|
3
|
+
export type AdapterExecutionPhase = (typeof ADAPTER_EXECUTION_PHASES)[number];
|
|
4
|
+
export type AdapterExecutionPhaseSink = (phase: AdapterExecutionPhase) => (() => void) | void;
|
|
5
|
+
export declare function isAdapterExecutionPhase(value: unknown): value is AdapterExecutionPhase;
|
|
6
|
+
/** A broken diagnostic sink must not change execution or teardown outcomes. */
|
|
7
|
+
export declare function withAdapterExecutionPhase<T>(context: {
|
|
8
|
+
onExecutionPhase?: AdapterExecutionPhaseSink;
|
|
9
|
+
}, phase: AdapterExecutionPhase, operation: () => T | Promise<T>): Promise<T>;
|
|
10
|
+
//# sourceMappingURL=execution-phase.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"execution-phase.d.ts","sourceRoot":"","sources":["../src/execution-phase.ts"],"names":[],"mappings":"AAAA,mFAAmF;AACnF,eAAO,MAAM,wBAAwB,YACnC,gBAAgB,EAAE,mBAAmB,EAAE,aAAa,EAAE,aAAa,EAAE,eAAe,EACpF,cAAc,EAAE,gBAAgB,EAAE,WAAW,EAAE,wBAAwB,EACvE,mBAAmB,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,eAAe,CACtE,CAAC;AAEX,MAAM,MAAM,qBAAqB,GAAG,CAAC,OAAO,wBAAwB,CAAC,CAAC,MAAM,CAAC,CAAC;AAC9E,MAAM,MAAM,yBAAyB,GAAG,CAAC,KAAK,EAAE,qBAAqB,KAAK,CAAC,MAAM,IAAI,CAAC,GAAG,IAAI,CAAC;AAE9F,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,qBAAqB,CAEtF;AAED,+EAA+E;AAC/E,wBAAsB,yBAAyB,CAAC,CAAC,EAC/C,OAAO,EAAE;IAAE,gBAAgB,CAAC,EAAE,yBAAyB,CAAA;CAAE,EACzD,KAAK,EAAE,qBAAqB,EAC5B,SAAS,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,GAC9B,OAAO,CAAC,CAAC,CAAC,CAQZ"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/** Content-free, in-memory diagnostic scopes. These never establish stop proof. */
|
|
2
|
+
export const ADAPTER_EXECUTION_PHASES = [
|
|
3
|
+
"host_execution", "adapter_execution", "end_session", "cancel_turn", "close_session",
|
|
4
|
+
"settle_reuse", "stop_transport", "sync_back", "instruction_collection",
|
|
5
|
+
"workspace_restore", "phase_reporting", "instruction_cleanup", "lease_release",
|
|
6
|
+
];
|
|
7
|
+
export function isAdapterExecutionPhase(value) {
|
|
8
|
+
return ADAPTER_EXECUTION_PHASES.some((phase) => phase === value);
|
|
9
|
+
}
|
|
10
|
+
/** A broken diagnostic sink must not change execution or teardown outcomes. */
|
|
11
|
+
export async function withAdapterExecutionPhase(context, phase, operation) {
|
|
12
|
+
let release = undefined;
|
|
13
|
+
try {
|
|
14
|
+
release = context.onExecutionPhase?.(phase);
|
|
15
|
+
}
|
|
16
|
+
catch { /* diagnostics only */ }
|
|
17
|
+
try {
|
|
18
|
+
return await operation();
|
|
19
|
+
}
|
|
20
|
+
finally {
|
|
21
|
+
try {
|
|
22
|
+
release?.();
|
|
23
|
+
}
|
|
24
|
+
catch { /* diagnostics only */ }
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=execution-phase.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"execution-phase.js","sourceRoot":"","sources":["../src/execution-phase.ts"],"names":[],"mappings":"AAAA,mFAAmF;AACnF,MAAM,CAAC,MAAM,wBAAwB,GAAG;IACtC,gBAAgB,EAAE,mBAAmB,EAAE,aAAa,EAAE,aAAa,EAAE,eAAe;IACpF,cAAc,EAAE,gBAAgB,EAAE,WAAW,EAAE,wBAAwB;IACvE,mBAAmB,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,eAAe;CACtE,CAAC;AAKX,MAAM,UAAU,uBAAuB,CAAC,KAAc;IACpD,OAAO,wBAAwB,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,KAAK,KAAK,CAAC,CAAC;AACnE,CAAC;AAED,+EAA+E;AAC/E,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAC7C,OAAyD,EACzD,KAA4B,EAC5B,SAA+B;IAE/B,IAAI,OAAO,GAAwB,SAAS,CAAC;IAC7C,IAAI,CAAC;QAAC,OAAO,GAAG,OAAO,CAAC,gBAAgB,EAAE,CAAC,KAAK,CAAC,CAAC;IAAC,CAAC;IAAC,MAAM,CAAC,CAAC,sBAAsB,CAAC,CAAC;IACrF,IAAI,CAAC;QACH,OAAO,MAAM,SAAS,EAAE,CAAC;IAC3B,CAAC;YAAS,CAAC;QACT,IAAI,CAAC;YAAC,OAAO,EAAE,EAAE,CAAC;QAAC,CAAC;QAAC,MAAM,CAAC,CAAC,sBAAsB,CAAC,CAAC;IACvD,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"execution-phase.test.d.ts","sourceRoot":"","sources":["../src/execution-phase.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { expect, it, vi } from "vitest";
|
|
2
|
+
import { withAdapterExecutionPhase } from "./execution-phase.js";
|
|
3
|
+
it("enters before a stalled await and releases only when that operation settles", async () => {
|
|
4
|
+
const release = vi.fn();
|
|
5
|
+
const enter = vi.fn(() => release);
|
|
6
|
+
let resolve;
|
|
7
|
+
const operation = new Promise((done) => { resolve = done; });
|
|
8
|
+
const result = withAdapterExecutionPhase({ onExecutionPhase: enter }, "instruction_collection", () => operation);
|
|
9
|
+
expect(enter).toHaveBeenCalledWith("instruction_collection");
|
|
10
|
+
await Promise.resolve();
|
|
11
|
+
expect(release).not.toHaveBeenCalled();
|
|
12
|
+
resolve(7);
|
|
13
|
+
await expect(result).resolves.toBe(7);
|
|
14
|
+
expect(release).toHaveBeenCalledOnce();
|
|
15
|
+
});
|
|
16
|
+
it.each(["enter", "release"])("preserves values and errors when the %s diagnostic callback throws", async (where) => {
|
|
17
|
+
const context = { onExecutionPhase: () => {
|
|
18
|
+
if (where === "enter")
|
|
19
|
+
throw new Error("diagnostic failure");
|
|
20
|
+
return () => { throw new Error("diagnostic failure"); };
|
|
21
|
+
} };
|
|
22
|
+
await expect(withAdapterExecutionPhase(context, "workspace_restore", () => 3)).resolves.toBe(3);
|
|
23
|
+
const failure = new Error("operation failure");
|
|
24
|
+
await expect(withAdapterExecutionPhase(context, "workspace_restore", () => { throw failure; })).rejects.toBe(failure);
|
|
25
|
+
});
|
|
26
|
+
//# sourceMappingURL=execution-phase.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"execution-phase.test.js","sourceRoot":"","sources":["../src/execution-phase.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AACxC,OAAO,EAAE,yBAAyB,EAAE,MAAM,sBAAsB,CAAC;AAEjE,EAAE,CAAC,6EAA6E,EAAE,KAAK,IAAI,EAAE;IAC3F,MAAM,OAAO,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC;IACxB,MAAM,KAAK,GAAG,EAAE,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,CAAC;IACnC,IAAI,OAAiC,CAAC;IACtC,MAAM,SAAS,GAAG,IAAI,OAAO,CAAS,CAAC,IAAI,EAAE,EAAE,GAAG,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IACrE,MAAM,MAAM,GAAG,yBAAyB,CAAC,EAAE,gBAAgB,EAAE,KAAK,EAAE,EAAE,wBAAwB,EAAE,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;IACjH,MAAM,CAAC,KAAK,CAAC,CAAC,oBAAoB,CAAC,wBAAwB,CAAC,CAAC;IAC7D,MAAM,OAAO,CAAC,OAAO,EAAE,CAAC;IACxB,MAAM,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,gBAAgB,EAAE,CAAC;IACvC,OAAO,CAAC,CAAC,CAAC,CAAC;IACX,MAAM,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACtC,MAAM,CAAC,OAAO,CAAC,CAAC,oBAAoB,EAAE,CAAC;AACzC,CAAC,CAAC,CAAC;AAEH,EAAE,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC,CAAC,oEAAoE,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE;IAClH,MAAM,OAAO,GAAG,EAAE,gBAAgB,EAAE,GAAG,EAAE;YACvC,IAAI,KAAK,KAAK,OAAO;gBAAE,MAAM,IAAI,KAAK,CAAC,oBAAoB,CAAC,CAAC;YAC7D,OAAO,GAAG,EAAE,GAAG,MAAM,IAAI,KAAK,CAAC,oBAAoB,CAAC,CAAC,CAAC,CAAC,CAAC;QAC1D,CAAC,EAAE,CAAC;IACJ,MAAM,MAAM,CAAC,yBAAyB,CAAC,OAAO,EAAE,mBAAmB,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAChG,MAAM,OAAO,GAAG,IAAI,KAAK,CAAC,mBAAmB,CAAC,CAAC;IAC/C,MAAM,MAAM,CAAC,yBAAyB,CAAC,OAAO,EAAE,mBAAmB,EAAE,GAAG,EAAE,GAAG,MAAM,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;AACxH,CAAC,CAAC,CAAC"}
|
|
@@ -480,7 +480,7 @@ describe("sandbox adapter execution targets", () => {
|
|
|
480
480
|
target: {
|
|
481
481
|
kind: "remote", transport: "sandbox", providerKey: "local-test", remoteCwd: rootDir,
|
|
482
482
|
runner: { execute: async (input) => {
|
|
483
|
-
if (input.args?.[1]
|
|
483
|
+
if (/command\.b64\.[^/]+\.paperclip-upload\.b64/.test(input.args?.[1] ?? "") && input.args[1].includes(">>")) {
|
|
484
484
|
throw new Error("Upload interrupted");
|
|
485
485
|
}
|
|
486
486
|
return delegate.execute(input);
|
|
@@ -1569,6 +1569,7 @@ describe("sandbox adapter execution targets", () => {
|
|
|
1569
1569
|
execs.push({
|
|
1570
1570
|
useSession: input.useSession,
|
|
1571
1571
|
bypassSession: input.bypassSession,
|
|
1572
|
+
timeoutMs: input.timeoutMs,
|
|
1572
1573
|
script: input.args?.[1] ?? "",
|
|
1573
1574
|
});
|
|
1574
1575
|
return delegate.execute(input);
|
|
@@ -1591,7 +1592,7 @@ describe("sandbox adapter execution targets", () => {
|
|
|
1591
1592
|
args: [childPath],
|
|
1592
1593
|
cwd: rootDir,
|
|
1593
1594
|
env: {},
|
|
1594
|
-
timeoutSec:
|
|
1595
|
+
timeoutSec: 4 * 60 * 60,
|
|
1595
1596
|
onLog: async () => { },
|
|
1596
1597
|
streamOutputViaSession: true,
|
|
1597
1598
|
});
|
|
@@ -1607,6 +1608,7 @@ describe("sandbox adapter execution targets", () => {
|
|
|
1607
1608
|
const sessionExecs = execs.filter((exec) => exec.useSession === true);
|
|
1608
1609
|
expect(sessionExecs).toHaveLength(1);
|
|
1609
1610
|
expect(sessionExecs[0].bypassSession).not.toBe(true);
|
|
1611
|
+
expect(sessionExecs[0].timeoutMs).toBe(4 * 60 * 60 * 1000);
|
|
1610
1612
|
expect(sessionExecs[0].script).toContain("node ");
|
|
1611
1613
|
// Every other exec is bridge control-plane plumbing. Each must force
|
|
1612
1614
|
// itself off the persistent session so it never queues behind the agent
|
|
@@ -1615,6 +1617,7 @@ describe("sandbox adapter execution targets", () => {
|
|
|
1615
1617
|
expect(controlExecs.length).toBeGreaterThan(0);
|
|
1616
1618
|
for (const exec of controlExecs) {
|
|
1617
1619
|
expect(exec.bypassSession).toBe(true);
|
|
1620
|
+
expect(exec.timeoutMs).toBe(30_000);
|
|
1618
1621
|
}
|
|
1619
1622
|
}
|
|
1620
1623
|
finally {
|
|
@@ -1622,6 +1625,43 @@ describe("sandbox adapter execution targets", () => {
|
|
|
1622
1625
|
}
|
|
1623
1626
|
});
|
|
1624
1627
|
});
|
|
1628
|
+
it.each(["launch", "payload setup"])("bounds a hung process-session %s", async (stage) => {
|
|
1629
|
+
vi.useFakeTimers();
|
|
1630
|
+
try {
|
|
1631
|
+
const runner = {
|
|
1632
|
+
execute: vi.fn(async (input) => {
|
|
1633
|
+
const script = input.args?.[1] ?? "";
|
|
1634
|
+
if ((stage === "launch" && script.includes("nohup")) ||
|
|
1635
|
+
(stage === "payload setup" && script.startsWith("chmod 600"))) {
|
|
1636
|
+
return new Promise(() => { });
|
|
1637
|
+
}
|
|
1638
|
+
return {
|
|
1639
|
+
exitCode: 0, signal: null, timedOut: false, stdout: '{"uploaded":true}', stderr: "",
|
|
1640
|
+
pid: null, startedAt: new Date().toISOString(),
|
|
1641
|
+
};
|
|
1642
|
+
}),
|
|
1643
|
+
};
|
|
1644
|
+
let error;
|
|
1645
|
+
const operation = startAdapterExecutionTargetProcessSessionBridge({
|
|
1646
|
+
runId: "run-hung-setup",
|
|
1647
|
+
runtimeRootDir: "/workspace/runtime",
|
|
1648
|
+
target: { kind: "remote", transport: "sandbox", remoteCwd: "/workspace", runner },
|
|
1649
|
+
adapterKey: "acpx", command: "cat", args: [], cwd: "/workspace",
|
|
1650
|
+
env: stage === "payload setup" ? { LARGE_VALUE: "x".repeat(70_000) } : {},
|
|
1651
|
+
timeoutSec: 4 * 60 * 60,
|
|
1652
|
+
}).catch((caught) => { error = caught; });
|
|
1653
|
+
await vi.advanceTimersByTimeAsync(30_000);
|
|
1654
|
+
expect(error).toEqual(new Error("Sandbox bridge control command timed out after 30000ms."));
|
|
1655
|
+
await operation;
|
|
1656
|
+
expect(runner.execute.mock.calls.filter(([input]) => input.args?.[1]?.includes("nohup")))
|
|
1657
|
+
.toHaveLength(stage === "launch" ? 1 : 0);
|
|
1658
|
+
expect(runner.execute).toHaveBeenLastCalledWith(expect.objectContaining({ timeoutMs: 30_000 }));
|
|
1659
|
+
expect(vi.getTimerCount()).toBe(0);
|
|
1660
|
+
}
|
|
1661
|
+
finally {
|
|
1662
|
+
vi.useRealTimers();
|
|
1663
|
+
}
|
|
1664
|
+
});
|
|
1625
1665
|
it("applies the remote sandbox fallback when adapter timeoutSec is unset", () => {
|
|
1626
1666
|
const sandboxTarget = {
|
|
1627
1667
|
kind: "remote",
|
|
@@ -1629,9 +1669,8 @@ describe("sandbox adapter execution targets", () => {
|
|
|
1629
1669
|
remoteCwd: "/workspace",
|
|
1630
1670
|
runner: createLocalSandboxRunner(),
|
|
1631
1671
|
};
|
|
1632
|
-
// The sandbox default
|
|
1633
|
-
//
|
|
1634
|
-
// the output-inactivity monitor remains the primary hang detector.
|
|
1672
|
+
// The sandbox default stays at four hours independently of the earlier
|
|
1673
|
+
// informational output-silence warnings and bridge control deadlines.
|
|
1635
1674
|
expect(DEFAULT_REMOTE_SANDBOX_ADAPTER_TIMEOUT_SEC).toBe(4 * 60 * 60);
|
|
1636
1675
|
expect(resolveAdapterExecutionTargetTimeoutSec(sandboxTarget, 0)).toBe(DEFAULT_REMOTE_SANDBOX_ADAPTER_TIMEOUT_SEC);
|
|
1637
1676
|
expect(resolveAdapterExecutionTargetTimeoutSec(sandboxTarget, 90)).toBe(90);
|
|
@@ -2319,7 +2358,7 @@ describe("sandbox adapter execution targets", () => {
|
|
|
2319
2358
|
await new Promise((resolve) => apiServer.close(() => resolve()));
|
|
2320
2359
|
}
|
|
2321
2360
|
});
|
|
2322
|
-
it("
|
|
2361
|
+
it("bounds callback bridge operations independently of the adapter run timeout", async () => {
|
|
2323
2362
|
const rootDir = await mkdtemp(path.join(os.tmpdir(), "paperclip-execution-target-bridge-timeout-"));
|
|
2324
2363
|
cleanupDirs.push(rootDir);
|
|
2325
2364
|
const remoteCwd = path.join(rootDir, "workspace");
|
|
@@ -2363,7 +2402,10 @@ describe("sandbox adapter execution targets", () => {
|
|
|
2363
2402
|
try {
|
|
2364
2403
|
expect(bridge).not.toBeNull();
|
|
2365
2404
|
expect(runner.execute).toHaveBeenCalled();
|
|
2366
|
-
|
|
2405
|
+
for (const [input] of runner.execute.mock.calls) {
|
|
2406
|
+
expect(input.timeoutMs).toBeGreaterThan(0);
|
|
2407
|
+
expect(input.timeoutMs).toBeLessThanOrEqual(30_000);
|
|
2408
|
+
}
|
|
2367
2409
|
}
|
|
2368
2410
|
finally {
|
|
2369
2411
|
await bridge?.stop();
|