@tickernelz/paperclip-pro-adapter-utils 2026.1011.2 → 2026.1012.0
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/acpx-engine/execute.d.ts.map +1 -1
- package/dist/acpx-engine/execute.js +77 -8
- package/dist/acpx-engine/execute.js.map +1 -1
- package/dist/acpx-engine/execute.test.js +186 -14
- package/dist/acpx-engine/execute.test.js.map +1 -1
- package/dist/acpx-engine/filesystem-protocol.test.d.ts +2 -0
- package/dist/acpx-engine/filesystem-protocol.test.d.ts.map +1 -0
- package/dist/acpx-engine/filesystem-protocol.test.js +99 -0
- package/dist/acpx-engine/filesystem-protocol.test.js.map +1 -0
- package/dist/acpx-engine/run-contracts.d.ts +1 -0
- package/dist/acpx-engine/run-contracts.d.ts.map +1 -1
- package/dist/billing.d.ts +7 -0
- package/dist/billing.d.ts.map +1 -1
- package/dist/billing.js +25 -2
- package/dist/billing.js.map +1 -1
- package/dist/billing.test.js +17 -1
- package/dist/billing.test.js.map +1 -1
- package/dist/chat-file-delivery.d.ts +1 -1
- package/dist/chat-file-delivery.d.ts.map +1 -1
- package/dist/chat-file-delivery.js +4 -3
- package/dist/chat-file-delivery.js.map +1 -1
- package/dist/chat-file-delivery.test.js +2 -2
- package/dist/chat-file-delivery.test.js.map +1 -1
- package/dist/command-managed-runtime.d.ts +1 -0
- package/dist/command-managed-runtime.d.ts.map +1 -1
- package/dist/command-managed-runtime.js +3 -1
- package/dist/command-managed-runtime.js.map +1 -1
- package/dist/connection-failure.d.ts +33 -0
- package/dist/connection-failure.d.ts.map +1 -0
- package/dist/connection-failure.js +43 -0
- package/dist/connection-failure.js.map +1 -0
- package/dist/connection-failure.test.d.ts +2 -0
- package/dist/connection-failure.test.d.ts.map +1 -0
- package/dist/connection-failure.test.js +94 -0
- package/dist/connection-failure.test.js.map +1 -0
- package/dist/directory-merge-lock.test.js +4 -2
- package/dist/directory-merge-lock.test.js.map +1 -1
- package/dist/execution-target-sandbox.test.js +228 -0
- package/dist/execution-target-sandbox.test.js.map +1 -1
- package/dist/execution-target.d.ts +4 -0
- package/dist/execution-target.d.ts.map +1 -1
- package/dist/execution-target.js +46 -13
- package/dist/execution-target.js.map +1 -1
- package/dist/execution-target.test.js +1 -1
- package/dist/execution-target.test.js.map +1 -1
- package/dist/github-launcher-environment.test.js +37 -0
- package/dist/github-launcher-environment.test.js.map +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/paperclip-runner-permissions.d.ts +15 -4
- package/dist/paperclip-runner-permissions.d.ts.map +1 -1
- package/dist/paperclip-runner-permissions.js +29 -3
- package/dist/paperclip-runner-permissions.js.map +1 -1
- package/dist/paperclip-runner-permissions.test.js +34 -1
- package/dist/paperclip-runner-permissions.test.js.map +1 -1
- package/dist/remote-managed-runtime.d.ts.map +1 -1
- package/dist/remote-managed-runtime.js +18 -2
- package/dist/remote-managed-runtime.js.map +1 -1
- package/dist/sandbox-callback-bridge.d.ts.map +1 -1
- package/dist/sandbox-callback-bridge.js +1 -0
- package/dist/sandbox-callback-bridge.js.map +1 -1
- package/dist/sandbox-callback-bridge.test.js +113 -16
- 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 +8 -1
- package/dist/sandbox-managed-runtime.js.map +1 -1
- package/dist/server-utils.d.ts +6 -3
- package/dist/server-utils.d.ts.map +1 -1
- package/dist/server-utils.js +39 -9
- package/dist/server-utils.js.map +1 -1
- package/dist/server-utils.test.js +35 -1
- package/dist/server-utils.test.js.map +1 -1
- package/dist/ssh-fixture.test.js +172 -0
- package/dist/ssh-fixture.test.js.map +1 -1
- package/dist/ssh.d.ts +5 -0
- package/dist/ssh.d.ts.map +1 -1
- package/dist/ssh.js +138 -20
- package/dist/ssh.js.map +1 -1
- package/dist/types.d.ts +76 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/usage-checkpoint.d.ts +11 -0
- package/dist/usage-checkpoint.d.ts.map +1 -0
- package/dist/usage-checkpoint.js +165 -0
- package/dist/usage-checkpoint.js.map +1 -0
- package/dist/usage-checkpoint.test.d.ts +2 -0
- package/dist/usage-checkpoint.test.d.ts.map +1 -0
- package/dist/usage-checkpoint.test.js +131 -0
- package/dist/usage-checkpoint.test.js.map +1 -0
- package/dist/workspace-restore-diagnostics.d.ts +8 -1
- package/dist/workspace-restore-diagnostics.d.ts.map +1 -1
- package/dist/workspace-restore-diagnostics.js +35 -8
- package/dist/workspace-restore-diagnostics.js.map +1 -1
- package/dist/workspace-restore-diagnostics.test.js +31 -1
- package/dist/workspace-restore-diagnostics.test.js.map +1 -1
- package/node_modules/acpx/dist/live-checkpoint-ClPCSdrW.js +3 -0
- package/node_modules/zod/package.json +1 -1
- package/node_modules/zod/src/v4/classic/tests/array.test.ts +27 -0
- package/node_modules/zod/src/v4/classic/tests/map.test.ts +7 -0
- package/node_modules/zod/src/v4/classic/tests/set.test.ts +6 -0
- package/node_modules/zod/src/v4/core/compile.ts +9 -0
- package/node_modules/zod/src/v4/core/schemas.ts +35 -1
- package/node_modules/zod/src/v4/core/util.ts +13 -0
- package/node_modules/zod/src/v4/core/versions.ts +1 -1
- package/node_modules/zod/v4/core/compile.cjs +8 -0
- package/node_modules/zod/v4/core/compile.js +8 -0
- package/node_modules/zod/v4/core/schemas.cjs +30 -0
- package/node_modules/zod/v4/core/schemas.d.cts +3 -1
- package/node_modules/zod/v4/core/schemas.d.ts +3 -1
- package/node_modules/zod/v4/core/schemas.js +30 -0
- package/node_modules/zod/v4/core/util.cjs +15 -0
- package/node_modules/zod/v4/core/util.d.cts +2 -0
- package/node_modules/zod/v4/core/util.d.ts +2 -0
- package/node_modules/zod/v4/core/util.js +14 -0
- package/node_modules/zod/v4/core/versions.cjs +1 -1
- package/node_modules/zod/v4/core/versions.js +1 -1
- package/package.json +31 -3
- package/node_modules/@esbuild/linux-x64/README.md +0 -3
- package/node_modules/@esbuild/linux-x64/bin/esbuild +0 -0
- package/node_modules/@esbuild/linux-x64/package.json +0 -20
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { readConnectionFailure } from "./connection-failure.js";
|
|
3
|
+
describe("readConnectionFailure", () => {
|
|
4
|
+
const git = { schemaVersion: 1, provider: "git", operation: "clone", reason: "authentication_failed" };
|
|
5
|
+
const gateway = { schemaVersion: 1, provider: "hermes_gateway", operation: "create_run", reason: "connection_refused" };
|
|
6
|
+
const mcp = { schemaVersion: 1, provider: "mcp_http", operation: "discover_tools", reason: "connection_refused" };
|
|
7
|
+
it.each([
|
|
8
|
+
"authentication_failed", "repository_unavailable", "invalid_remote", "dns_failure", "connection_refused",
|
|
9
|
+
"network_unreachable", "connection_reset", "connection_timeout", "tls_failure", "rate_limited", "remote_unavailable",
|
|
10
|
+
])("accepts the Git clone reason %s", (reason) => {
|
|
11
|
+
const input = { ...git, reason };
|
|
12
|
+
expect(readConnectionFailure(input)).toEqual(input);
|
|
13
|
+
});
|
|
14
|
+
it.each(["endpoint_missing", "endpoint_invalid", "insecure_transport", "credentials_missing"])("accepts the gateway configuration reason %s", (reason) => {
|
|
15
|
+
const input = { ...gateway, operation: "configuration", reason };
|
|
16
|
+
expect(readConnectionFailure(input)).toEqual(input);
|
|
17
|
+
});
|
|
18
|
+
it.each([
|
|
19
|
+
"authentication_failed", "endpoint_not_found", "rate_limited", "remote_unavailable", "connection_refused",
|
|
20
|
+
"dns_failure", "network_unreachable", "connection_reset", "connection_timeout", "tls_failure",
|
|
21
|
+
])("accepts the gateway request reason %s", (reason) => {
|
|
22
|
+
const input = { ...gateway, reason };
|
|
23
|
+
expect(readConnectionFailure(input)).toEqual(input);
|
|
24
|
+
});
|
|
25
|
+
it.each([
|
|
26
|
+
"authentication_failed", "endpoint_not_found", "rate_limited", "remote_unavailable", "connection_refused",
|
|
27
|
+
"dns_failure", "network_unreachable", "connection_reset", "connection_timeout", "tls_failure",
|
|
28
|
+
])("accepts the MCP tool discovery request reason %s", (reason) => {
|
|
29
|
+
const input = { ...mcp, reason };
|
|
30
|
+
expect(readConnectionFailure(input)).toEqual(input);
|
|
31
|
+
});
|
|
32
|
+
it.each([
|
|
33
|
+
{ ...git, operation: "fetch" },
|
|
34
|
+
{ ...git, operation: "create_run" },
|
|
35
|
+
{ ...git, reason: "endpoint_not_found" },
|
|
36
|
+
{ ...gateway, operation: "clone" },
|
|
37
|
+
{ ...gateway, operation: "poll_status" },
|
|
38
|
+
{ ...gateway, operation: "stop_run" },
|
|
39
|
+
{ ...gateway, operation: "configuration" },
|
|
40
|
+
{ ...gateway, reason: "credentials_missing" },
|
|
41
|
+
{ ...gateway, reason: "repository_unavailable" },
|
|
42
|
+
{ ...gateway, reason: "timeout" },
|
|
43
|
+
{ ...gateway, reason: "unknown" },
|
|
44
|
+
{ ...gateway, provider: "other_gateway" },
|
|
45
|
+
{ ...gateway, provider: "hermes_local" },
|
|
46
|
+
{ ...mcp, operation: "create_run" },
|
|
47
|
+
{ ...mcp, operation: "clone" },
|
|
48
|
+
{ ...mcp, operation: "configuration" },
|
|
49
|
+
{ ...mcp, operation: "call_tool" },
|
|
50
|
+
{ ...mcp, reason: "credentials_missing" },
|
|
51
|
+
{ ...mcp, reason: "repository_unavailable" },
|
|
52
|
+
{ ...gateway, operation: "discover_tools" },
|
|
53
|
+
{ ...git, operation: "discover_tools" },
|
|
54
|
+
])("rejects an unsupported provider/operation/reason combination: %j", (input) => {
|
|
55
|
+
expect(readConnectionFailure(input)).toBeNull();
|
|
56
|
+
});
|
|
57
|
+
it.each([
|
|
58
|
+
undefined, null, false, 1, "connection_refused", [], [gateway], {},
|
|
59
|
+
{ ...gateway, schemaVersion: 0 }, { ...gateway, schemaVersion: 2 }, { ...gateway, schemaVersion: "1" },
|
|
60
|
+
{ ...gateway, schemaVersion: null }, { ...gateway, schemaVersion: undefined },
|
|
61
|
+
{ ...gateway, provider: null }, { ...gateway, provider: ["hermes_gateway"] },
|
|
62
|
+
{ ...gateway, operation: null }, { ...gateway, operation: 1 },
|
|
63
|
+
{ ...gateway, reason: null }, { ...gateway, reason: 1 }, { ...gateway, reason: ["connection_refused"] },
|
|
64
|
+
{ ...gateway, reason: { code: "ECONNREFUSED" } },
|
|
65
|
+
{ provider: "hermes_gateway", operation: "create_run", reason: "connection_refused" },
|
|
66
|
+
{ ...gateway, reason: "connection_refused " }, { ...gateway, reason: "CONNECTION_REFUSED" },
|
|
67
|
+
])("rejects unknown versions or malformed values: %j", (input) => {
|
|
68
|
+
expect(readConnectionFailure(input)).toBeNull();
|
|
69
|
+
});
|
|
70
|
+
it.each([
|
|
71
|
+
{ url: "https://private.example.test" },
|
|
72
|
+
{ account: "private-account" },
|
|
73
|
+
{ token: "synthetic-secret" },
|
|
74
|
+
{ remoteRunAccepted: false },
|
|
75
|
+
{ providerWorkStarted: false },
|
|
76
|
+
{ details: { message: "private diagnostics" } },
|
|
77
|
+
{ extra: undefined },
|
|
78
|
+
])("rejects extra metadata instead of broadening the bounded marker: %j", (extra) => {
|
|
79
|
+
expect(readConnectionFailure({ ...gateway, ...extra })).toBeNull();
|
|
80
|
+
});
|
|
81
|
+
it("rejects unknown own fields even when a prototype supplies a valid descriptor", () => {
|
|
82
|
+
const input = Object.assign(Object.create(gateway), { a: 1, b: 2, c: 3, d: 4 });
|
|
83
|
+
expect(readConnectionFailure(input)).toBeNull();
|
|
84
|
+
});
|
|
85
|
+
it("returns an independent bounded value without mutating its producer's input", () => {
|
|
86
|
+
const input = Object.freeze({ ...gateway });
|
|
87
|
+
const output = readConnectionFailure(input);
|
|
88
|
+
expect(output).toEqual(gateway);
|
|
89
|
+
expect(output).not.toBe(input);
|
|
90
|
+
expect(input).toEqual(gateway);
|
|
91
|
+
expect(Object.keys(output ?? {}).sort()).toEqual(["operation", "provider", "reason", "schemaVersion"]);
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
//# sourceMappingURL=connection-failure.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"connection-failure.test.js","sourceRoot":"","sources":["../src/connection-failure.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAEhE,QAAQ,CAAC,uBAAuB,EAAE,GAAG,EAAE;IACrC,MAAM,GAAG,GAAG,EAAE,aAAa,EAAE,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,uBAAuB,EAAE,CAAC;IACvG,MAAM,OAAO,GAAG,EAAE,aAAa,EAAE,CAAC,EAAE,QAAQ,EAAE,gBAAgB,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,EAAE,oBAAoB,EAAE,CAAC;IACxH,MAAM,GAAG,GAAG,EAAE,aAAa,EAAE,CAAC,EAAE,QAAQ,EAAE,UAAU,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,EAAE,oBAAoB,EAAE,CAAC;IAElH,EAAE,CAAC,IAAI,CAAC;QACN,uBAAuB,EAAE,wBAAwB,EAAE,gBAAgB,EAAE,aAAa,EAAE,oBAAoB;QACxG,qBAAqB,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,aAAa,EAAE,cAAc,EAAE,oBAAoB;KACrH,CAAC,CAAC,iCAAiC,EAAE,CAAC,MAAM,EAAE,EAAE;QAC/C,MAAM,KAAK,GAAG,EAAE,GAAG,GAAG,EAAE,MAAM,EAAE,CAAC;QACjC,MAAM,CAAC,qBAAqB,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IACtD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,IAAI,CAAC,CAAC,kBAAkB,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,qBAAqB,CAAC,CAAC,CAC5F,6CAA6C,EAAE,CAAC,MAAM,EAAE,EAAE;QACxD,MAAM,KAAK,GAAG,EAAE,GAAG,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,EAAE,CAAC;QACjE,MAAM,CAAC,qBAAqB,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IACtD,CAAC,CACF,CAAC;IAEF,EAAE,CAAC,IAAI,CAAC;QACN,uBAAuB,EAAE,oBAAoB,EAAE,cAAc,EAAE,oBAAoB,EAAE,oBAAoB;QACzG,aAAa,EAAE,qBAAqB,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,aAAa;KAC9F,CAAC,CAAC,uCAAuC,EAAE,CAAC,MAAM,EAAE,EAAE;QACrD,MAAM,KAAK,GAAG,EAAE,GAAG,OAAO,EAAE,MAAM,EAAE,CAAC;QACrC,MAAM,CAAC,qBAAqB,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IACtD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,IAAI,CAAC;QACN,uBAAuB,EAAE,oBAAoB,EAAE,cAAc,EAAE,oBAAoB,EAAE,oBAAoB;QACzG,aAAa,EAAE,qBAAqB,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,aAAa;KAC9F,CAAC,CAAC,kDAAkD,EAAE,CAAC,MAAM,EAAE,EAAE;QAChE,MAAM,KAAK,GAAG,EAAE,GAAG,GAAG,EAAE,MAAM,EAAE,CAAC;QACjC,MAAM,CAAC,qBAAqB,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IACtD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,IAAI,CAAC;QACN,EAAE,GAAG,GAAG,EAAE,SAAS,EAAE,OAAO,EAAE;QAC9B,EAAE,GAAG,GAAG,EAAE,SAAS,EAAE,YAAY,EAAE;QACnC,EAAE,GAAG,GAAG,EAAE,MAAM,EAAE,oBAAoB,EAAE;QACxC,EAAE,GAAG,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE;QAClC,EAAE,GAAG,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE;QACxC,EAAE,GAAG,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE;QACrC,EAAE,GAAG,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE;QAC1C,EAAE,GAAG,OAAO,EAAE,MAAM,EAAE,qBAAqB,EAAE;QAC7C,EAAE,GAAG,OAAO,EAAE,MAAM,EAAE,wBAAwB,EAAE;QAChD,EAAE,GAAG,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE;QACjC,EAAE,GAAG,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE;QACjC,EAAE,GAAG,OAAO,EAAE,QAAQ,EAAE,eAAe,EAAE;QACzC,EAAE,GAAG,OAAO,EAAE,QAAQ,EAAE,cAAc,EAAE;QACxC,EAAE,GAAG,GAAG,EAAE,SAAS,EAAE,YAAY,EAAE;QACnC,EAAE,GAAG,GAAG,EAAE,SAAS,EAAE,OAAO,EAAE;QAC9B,EAAE,GAAG,GAAG,EAAE,SAAS,EAAE,eAAe,EAAE;QACtC,EAAE,GAAG,GAAG,EAAE,SAAS,EAAE,WAAW,EAAE;QAClC,EAAE,GAAG,GAAG,EAAE,MAAM,EAAE,qBAAqB,EAAE;QACzC,EAAE,GAAG,GAAG,EAAE,MAAM,EAAE,wBAAwB,EAAE;QAC5C,EAAE,GAAG,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAE;QAC3C,EAAE,GAAG,GAAG,EAAE,SAAS,EAAE,gBAAgB,EAAE;KACxC,CAAC,CAAC,kEAAkE,EAAE,CAAC,KAAK,EAAE,EAAE;QAC/E,MAAM,CAAC,qBAAqB,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC;IAClD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,IAAI,CAAC;QACN,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,EAAE,oBAAoB,EAAE,EAAE,EAAE,CAAC,OAAO,CAAC,EAAE,EAAE;QAClE,EAAE,GAAG,OAAO,EAAE,aAAa,EAAE,CAAC,EAAE,EAAE,EAAE,GAAG,OAAO,EAAE,aAAa,EAAE,CAAC,EAAE,EAAE,EAAE,GAAG,OAAO,EAAE,aAAa,EAAE,GAAG,EAAE;QACtG,EAAE,GAAG,OAAO,EAAE,aAAa,EAAE,IAAI,EAAE,EAAE,EAAE,GAAG,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE;QAC7E,EAAE,GAAG,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE,EAAE,GAAG,OAAO,EAAE,QAAQ,EAAE,CAAC,gBAAgB,CAAC,EAAE;QAC5E,EAAE,GAAG,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,EAAE,EAAE,GAAG,OAAO,EAAE,SAAS,EAAE,CAAC,EAAE;QAC7D,EAAE,GAAG,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,GAAG,OAAO,EAAE,MAAM,EAAE,CAAC,EAAE,EAAE,EAAE,GAAG,OAAO,EAAE,MAAM,EAAE,CAAC,oBAAoB,CAAC,EAAE;QACvG,EAAE,GAAG,OAAO,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,cAAc,EAAE,EAAE;QAChD,EAAE,QAAQ,EAAE,gBAAgB,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,EAAE,oBAAoB,EAAE;QACrF,EAAE,GAAG,OAAO,EAAE,MAAM,EAAE,qBAAqB,EAAE,EAAE,EAAE,GAAG,OAAO,EAAE,MAAM,EAAE,oBAAoB,EAAE;KAC5F,CAAC,CAAC,kDAAkD,EAAE,CAAC,KAAK,EAAE,EAAE;QAC/D,MAAM,CAAC,qBAAqB,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC;IAClD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,IAAI,CAAC;QACN,EAAE,GAAG,EAAE,8BAA8B,EAAE;QACvC,EAAE,OAAO,EAAE,iBAAiB,EAAE;QAC9B,EAAE,KAAK,EAAE,kBAAkB,EAAE;QAC7B,EAAE,iBAAiB,EAAE,KAAK,EAAE;QAC5B,EAAE,mBAAmB,EAAE,KAAK,EAAE;QAC9B,EAAE,OAAO,EAAE,EAAE,OAAO,EAAE,qBAAqB,EAAE,EAAE;QAC/C,EAAE,KAAK,EAAE,SAAS,EAAE;KACrB,CAAC,CAAC,qEAAqE,EAAE,CAAC,KAAK,EAAE,EAAE;QAClF,MAAM,CAAC,qBAAqB,CAAC,EAAE,GAAG,OAAO,EAAE,GAAG,KAAK,EAAE,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC;IACrE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8EAA8E,EAAE,GAAG,EAAE;QACtF,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;QAChF,MAAM,CAAC,qBAAqB,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC;IAClD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4EAA4E,EAAE,GAAG,EAAE;QACpF,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC,EAAE,GAAG,OAAO,EAAE,CAAC,CAAC;QAC5C,MAAM,MAAM,GAAG,qBAAqB,CAAC,KAAK,CAAC,CAAC;QAC5C,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QAChC,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC/B,MAAM,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QAC/B,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,WAAW,EAAE,UAAU,EAAE,QAAQ,EAAE,eAAe,CAAC,CAAC,CAAC;IACzG,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -41,7 +41,9 @@ describe("directory merge lock process lifetime", () => {
|
|
|
41
41
|
return { target, env, lock };
|
|
42
42
|
}
|
|
43
43
|
async function holder(target, env) {
|
|
44
|
-
|
|
44
|
+
// Import the loader into the holder itself. The tsx CLI starts another
|
|
45
|
+
// process, so killing that launcher need not retire the SQLite lock holder.
|
|
46
|
+
const child = spawn(process.execPath, ["--import", loader, "--input-type=module", "--eval", `
|
|
45
47
|
import { withDirectoryMergeLock } from ${JSON.stringify(module)};
|
|
46
48
|
withDirectoryMergeLock(${JSON.stringify(target)}, async () => {
|
|
47
49
|
process.send?.("locked");
|
|
@@ -108,7 +110,7 @@ describe("directory merge lock process lifetime", () => {
|
|
|
108
110
|
await expect(withDirectoryMergeLock(target, async () => undefined, env, undefined, TIMEOUT_ASSERTION_WAIT_MS)).rejects.toMatchObject({ code: WORKSPACE_RESTORE_LOCK_TIMEOUT_CODE });
|
|
109
111
|
// A same-process test alone cannot prove that the OS lock survived: on
|
|
110
112
|
// POSIX, closing an unmanaged descriptor can drop process-wide locks.
|
|
111
|
-
const result = await promisify(execFile)(process.execPath, ["--import", loader, "--eval", `
|
|
113
|
+
const result = await promisify(execFile)(process.execPath, ["--import", loader, "--input-type=module", "--eval", `
|
|
112
114
|
import { withDirectoryMergeLock, WORKSPACE_RESTORE_LOCK_TIMEOUT_CODE } from ${JSON.stringify(module)};
|
|
113
115
|
withDirectoryMergeLock(${JSON.stringify(target)}, async () => "entered", undefined, undefined, ${TIMEOUT_ASSERTION_WAIT_MS})
|
|
114
116
|
.then(() => { console.error("Entered a live holder's lock"); process.exit(1); })
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"directory-merge-lock.test.js","sourceRoot":"","sources":["../src/directory-merge-lock.test.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"directory-merge-lock.test.js","sourceRoot":"","sources":["../src/directory-merge-lock.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { generateKeyPairSync, randomBytes, verify } from "node:crypto";
|
|
2
|
+
import { buildAgentIdentityEnv } from "./server-utils.js";
|
|
1
3
|
import { createServer } from "node:http";
|
|
2
4
|
import http2 from "node:http2";
|
|
3
5
|
import net from "node:net";
|
|
@@ -215,6 +217,27 @@ describe("sandbox adapter execution targets", () => {
|
|
|
215
217
|
function combinedStream(events, stream) {
|
|
216
218
|
return events.filter((event) => event.stream === stream).map((event) => event.chunk).join("");
|
|
217
219
|
}
|
|
220
|
+
it("delivers cryptographic identity through a remote sandbox process transport", async () => {
|
|
221
|
+
const rootDir = await mkdtemp(path.join(os.tmpdir(), "identity-remote-process-"));
|
|
222
|
+
cleanupDirs.push(rootDir);
|
|
223
|
+
const keys = generateKeyPairSync("ed25519");
|
|
224
|
+
const identity = {
|
|
225
|
+
keyId: "sha256:remote-identity",
|
|
226
|
+
publicKeyPem: keys.publicKey.export({ type: "spki", format: "pem" }).toString(),
|
|
227
|
+
privateKeyPem: keys.privateKey.export({ type: "pkcs8", format: "pem" }).toString(),
|
|
228
|
+
};
|
|
229
|
+
const target = {
|
|
230
|
+
kind: "remote", transport: "sandbox", providerKey: "local-test", remoteCwd: rootDir,
|
|
231
|
+
timeoutMs: 30_000, runner: createLocalSandboxRunner(),
|
|
232
|
+
};
|
|
233
|
+
const challenge = randomBytes(32);
|
|
234
|
+
const result = await runAdapterExecutionTargetProcess("identity-remote", target, process.execPath, ["-e", `const {sign}=require('node:crypto');process.stdout.write(sign(null,Buffer.from(process.argv[1],'hex'),process.env.PAPERCLIP_AGENT_PRIVATE_KEY).toString('base64'));`, challenge.toString("hex")], {
|
|
235
|
+
cwd: rootDir, env: buildAgentIdentityEnv(identity), timeoutSec: 5, graceSec: 1, onLog: async () => { },
|
|
236
|
+
});
|
|
237
|
+
expect(result.exitCode).toBe(0);
|
|
238
|
+
expect(verify(null, challenge, keys.publicKey, Buffer.from(result.stdout, "base64"))).toBe(true);
|
|
239
|
+
expect((await readRuntimeTextFiles(rootDir)).join("\n")).not.toContain(identity.privateKeyPem.split("\n")[1]);
|
|
240
|
+
});
|
|
218
241
|
it("executes through the provider-neutral runner without a remote spec", async () => {
|
|
219
242
|
const runner = {
|
|
220
243
|
execute: vi.fn(async () => ({
|
|
@@ -917,6 +940,7 @@ describe("sandbox adapter execution targets", () => {
|
|
|
917
940
|
// ACP keeps stdin open while it waits for a handshake. A remote child can
|
|
918
941
|
// exit before replying; that must close the proxy and fail the handshake.
|
|
919
942
|
const output = "final output\n".repeat(16_384);
|
|
943
|
+
const logs = [];
|
|
920
944
|
const bridge = await startAdapterExecutionTargetProcessSessionBridge({
|
|
921
945
|
runId: "run-open-stdin",
|
|
922
946
|
target: {
|
|
@@ -934,11 +958,17 @@ describe("sandbox adapter execution targets", () => {
|
|
|
934
958
|
env: {},
|
|
935
959
|
timeoutSec: 10,
|
|
936
960
|
streamOutputViaSession,
|
|
961
|
+
onLog: async (stream, chunk) => { if (stream === "stderr")
|
|
962
|
+
logs.push(chunk); },
|
|
937
963
|
});
|
|
938
964
|
expect(bridge).not.toBeNull();
|
|
939
965
|
try {
|
|
940
966
|
const result = await runProxyWithInput(bridge.agentCommand, "initialize\n", true);
|
|
941
967
|
expect(result.code).toBe(exitCode ?? 1);
|
|
968
|
+
const terminal = logs.filter((line) => line.includes("ACP process session terminal:"));
|
|
969
|
+
expect(terminal).toEqual([
|
|
970
|
+
`[paperclip] ACP process session terminal: source=remote_event outcome=${exitCode === null ? "error" : "exit"} exitCode=${exitCode ?? "unknown"} signal=unknown.\n`,
|
|
971
|
+
]);
|
|
942
972
|
if (exitCode === null) {
|
|
943
973
|
expect(result.stdout).toBe("");
|
|
944
974
|
expect(result.stderr).toContain("ENOENT");
|
|
@@ -952,6 +982,204 @@ describe("sandbox adapter execution targets", () => {
|
|
|
952
982
|
await bridge?.stop();
|
|
953
983
|
}
|
|
954
984
|
}, 15_000);
|
|
985
|
+
it("flushes remote errors under backpressure and retains only bounded terminal evidence", async () => {
|
|
986
|
+
const rootDir = await mkdtemp(path.join(os.tmpdir(), "paperclip-terminal-flush-"));
|
|
987
|
+
cleanupDirs.push(rootDir);
|
|
988
|
+
const delegate = createLocalSandboxRunner();
|
|
989
|
+
const logs = [];
|
|
990
|
+
let emit;
|
|
991
|
+
let complete;
|
|
992
|
+
let failInput;
|
|
993
|
+
let inputStarted = false;
|
|
994
|
+
const inputFailure = new Promise((_resolve, reject) => { failInput = reject; });
|
|
995
|
+
void inputFailure.catch(() => { });
|
|
996
|
+
const commandComplete = new Promise((resolve) => { complete = resolve; });
|
|
997
|
+
const frame = {
|
|
998
|
+
type: "error", message: "synthetic-private-detail".repeat(200_000),
|
|
999
|
+
code: 1e100, signal: "untrusted-private-signal",
|
|
1000
|
+
};
|
|
1001
|
+
const bridge = await startAdapterExecutionTargetProcessSessionBridge({
|
|
1002
|
+
runId: "terminal-flush", adapterKey: "acpx", runtimeRootDir: rootDir,
|
|
1003
|
+
target: {
|
|
1004
|
+
kind: "remote", transport: "sandbox", remoteCwd: rootDir,
|
|
1005
|
+
runner: { execute: async (input) => {
|
|
1006
|
+
if (!input.useSession) {
|
|
1007
|
+
const script = input.args?.[1] ?? "";
|
|
1008
|
+
if (script.startsWith("mkdir -p") && script.includes("/stdin/000000000001.json")) {
|
|
1009
|
+
inputStarted = true;
|
|
1010
|
+
return inputFailure;
|
|
1011
|
+
}
|
|
1012
|
+
return delegate.execute(input);
|
|
1013
|
+
}
|
|
1014
|
+
emit = async (text) => { await input.onLog?.("stdout", text); };
|
|
1015
|
+
await commandComplete;
|
|
1016
|
+
return { exitCode: 1, stdout: "", stderr: "", timedOut: false, signal: null, pid: null, startedAt: null };
|
|
1017
|
+
} },
|
|
1018
|
+
},
|
|
1019
|
+
command: "cat", args: [], cwd: rootDir, env: {}, streamOutputViaSession: true,
|
|
1020
|
+
onLog: async (stream, chunk) => { if (stream === "stderr")
|
|
1021
|
+
logs.push(chunk); },
|
|
1022
|
+
});
|
|
1023
|
+
let peer;
|
|
1024
|
+
try {
|
|
1025
|
+
const source = await readFile(bridge.agentCommand, "utf8");
|
|
1026
|
+
const port = Number(/port: (\d+)/.exec(source)[1]);
|
|
1027
|
+
const token = JSON.parse(/const token = (".*?");/.exec(source)[1]);
|
|
1028
|
+
peer = net.createConnection({ host: "127.0.0.1", port });
|
|
1029
|
+
peer.on("error", () => { });
|
|
1030
|
+
peer.setEncoding("utf8");
|
|
1031
|
+
let output = "";
|
|
1032
|
+
peer.on("data", (chunk) => { output += chunk; });
|
|
1033
|
+
const closed = new Promise((resolve) => peer.once("close", resolve));
|
|
1034
|
+
await new Promise((resolve) => peer.once("connect", resolve));
|
|
1035
|
+
peer.write(JSON.stringify({ token, type: "hello" }) + "\n");
|
|
1036
|
+
// Confirm authentication by receiving a marker before applying backpressure.
|
|
1037
|
+
await emit(JSON.stringify({ type: "data", stream: "stdout", data: "" }) + "\n");
|
|
1038
|
+
await waitForCondition(() => output.length > 0, "Missing authenticated marker.");
|
|
1039
|
+
output = "";
|
|
1040
|
+
peer.write(JSON.stringify({ token, type: "stdin", data: "aW5wdXQ=" }) + "\n");
|
|
1041
|
+
await waitForCondition(() => inputStarted, "Input write did not start.");
|
|
1042
|
+
peer.pause();
|
|
1043
|
+
// The real wrapper emits error then exit when a child fails to spawn.
|
|
1044
|
+
// A later frame must not write after end() and abort the pending error.
|
|
1045
|
+
await emit([
|
|
1046
|
+
frame,
|
|
1047
|
+
{ type: "exit", code: 1 },
|
|
1048
|
+
{ type: "data", stream: "stdout", data: "bGF0ZQ==" },
|
|
1049
|
+
{ type: "shutdownAck" },
|
|
1050
|
+
].map((event) => JSON.stringify(event) + "\n").join(""));
|
|
1051
|
+
// The reverse race matters too: an already-accepted input write can
|
|
1052
|
+
// reject after the remote error started draining. Its end(data) must
|
|
1053
|
+
// not abort or replace the first terminal frame.
|
|
1054
|
+
failInput(new Error("synthetic-private-input-detail"));
|
|
1055
|
+
await waitForCondition(() => logs.some((line) => line.includes("ACP process session input delivery failed.")), "Input failure was not handled.");
|
|
1056
|
+
peer.resume();
|
|
1057
|
+
await closed;
|
|
1058
|
+
expect(JSON.parse(output)).toEqual(frame);
|
|
1059
|
+
expect(logs.filter((line) => line.includes("ACP process session terminal:"))).toEqual([
|
|
1060
|
+
"[paperclip] ACP process session terminal: source=remote_event outcome=error exitCode=unknown signal=unknown.\n",
|
|
1061
|
+
]);
|
|
1062
|
+
}
|
|
1063
|
+
finally {
|
|
1064
|
+
failInput(new Error("test cleanup"));
|
|
1065
|
+
complete();
|
|
1066
|
+
peer?.destroy();
|
|
1067
|
+
await bridge?.stop();
|
|
1068
|
+
}
|
|
1069
|
+
}, 15_000);
|
|
1070
|
+
it("reports a streamed transport failure even when diagnostic persistence stalls", async () => {
|
|
1071
|
+
const rootDir = await mkdtemp(path.join(os.tmpdir(), "paperclip-terminal-stream-"));
|
|
1072
|
+
cleanupDirs.push(rootDir);
|
|
1073
|
+
const delegate = createLocalSandboxRunner();
|
|
1074
|
+
const logs = [];
|
|
1075
|
+
let releaseLog;
|
|
1076
|
+
const stalledLog = new Promise((resolve) => { releaseLog = resolve; });
|
|
1077
|
+
const bridge = await startAdapterExecutionTargetProcessSessionBridge({
|
|
1078
|
+
runId: "terminal-stream", adapterKey: "acpx", runtimeRootDir: rootDir,
|
|
1079
|
+
target: {
|
|
1080
|
+
kind: "remote", transport: "sandbox", remoteCwd: rootDir,
|
|
1081
|
+
runner: { execute: async (input) => {
|
|
1082
|
+
if (input.useSession)
|
|
1083
|
+
throw new Error("synthetic-private-provider-detail");
|
|
1084
|
+
return delegate.execute(input);
|
|
1085
|
+
} },
|
|
1086
|
+
},
|
|
1087
|
+
command: "cat", args: [], cwd: rootDir, env: {}, streamOutputViaSession: true,
|
|
1088
|
+
onLog: async (stream, chunk) => {
|
|
1089
|
+
if (stream === "stderr") {
|
|
1090
|
+
logs.push(chunk);
|
|
1091
|
+
await stalledLog;
|
|
1092
|
+
}
|
|
1093
|
+
},
|
|
1094
|
+
});
|
|
1095
|
+
try {
|
|
1096
|
+
const result = await runProxyWithInput(bridge.agentCommand, "", true);
|
|
1097
|
+
expect(result.code).toBe(1);
|
|
1098
|
+
expect(logs).toEqual([
|
|
1099
|
+
"[paperclip] ACP process session terminal: source=output_stream outcome=error exitCode=unknown signal=unknown.\n",
|
|
1100
|
+
]);
|
|
1101
|
+
}
|
|
1102
|
+
finally {
|
|
1103
|
+
releaseLog();
|
|
1104
|
+
await bridge?.stop();
|
|
1105
|
+
}
|
|
1106
|
+
}, 10_000);
|
|
1107
|
+
it("closes a failed output poll without waiting for the run log", async () => {
|
|
1108
|
+
const rootDir = await mkdtemp(path.join(os.tmpdir(), "paperclip-terminal-poll-"));
|
|
1109
|
+
cleanupDirs.push(rootDir);
|
|
1110
|
+
const delegate = createLocalSandboxRunner();
|
|
1111
|
+
const logs = [];
|
|
1112
|
+
let releaseLog;
|
|
1113
|
+
const stalledLog = new Promise((resolve) => { releaseLog = resolve; });
|
|
1114
|
+
const bridge = await startAdapterExecutionTargetProcessSessionBridge({
|
|
1115
|
+
runId: "terminal-poll", adapterKey: "acpx", runtimeRootDir: rootDir,
|
|
1116
|
+
target: {
|
|
1117
|
+
kind: "remote", transport: "sandbox", remoteCwd: rootDir,
|
|
1118
|
+
runner: { execute: async (input) => {
|
|
1119
|
+
const script = input.args?.[1] ?? "";
|
|
1120
|
+
if (script.includes("/events'/*.json"))
|
|
1121
|
+
throw new Error("synthetic-private-provider-detail");
|
|
1122
|
+
return delegate.execute(input);
|
|
1123
|
+
} },
|
|
1124
|
+
},
|
|
1125
|
+
command: "cat", args: [], cwd: rootDir, env: {},
|
|
1126
|
+
onLog: async (stream, chunk) => {
|
|
1127
|
+
if (stream === "stderr") {
|
|
1128
|
+
logs.push(chunk);
|
|
1129
|
+
await stalledLog;
|
|
1130
|
+
}
|
|
1131
|
+
},
|
|
1132
|
+
});
|
|
1133
|
+
try {
|
|
1134
|
+
const result = await runProxyWithInput(bridge.agentCommand, "", true);
|
|
1135
|
+
expect(result.code).toBe(1);
|
|
1136
|
+
expect(logs).toEqual([
|
|
1137
|
+
"[paperclip] ACP process session terminal: source=output_poll outcome=error exitCode=unknown signal=unknown.\n",
|
|
1138
|
+
]);
|
|
1139
|
+
}
|
|
1140
|
+
finally {
|
|
1141
|
+
releaseLog();
|
|
1142
|
+
await bridge?.stop();
|
|
1143
|
+
}
|
|
1144
|
+
}, 10_000);
|
|
1145
|
+
it("records an unexpected authenticated proxy close once and ignores unauthenticated peers", async () => {
|
|
1146
|
+
const rootDir = await mkdtemp(path.join(os.tmpdir(), "paperclip-terminal-proxy-"));
|
|
1147
|
+
cleanupDirs.push(rootDir);
|
|
1148
|
+
const logs = [];
|
|
1149
|
+
const bridge = await startAdapterExecutionTargetProcessSessionBridge({
|
|
1150
|
+
runId: "terminal-proxy", adapterKey: "acpx", runtimeRootDir: rootDir,
|
|
1151
|
+
target: { kind: "remote", transport: "sandbox", remoteCwd: rootDir, runner: createLocalSandboxRunner() },
|
|
1152
|
+
command: "cat", args: [], cwd: rootDir, env: {},
|
|
1153
|
+
onLog: async (stream, chunk) => { if (stream === "stderr")
|
|
1154
|
+
logs.push(chunk); },
|
|
1155
|
+
});
|
|
1156
|
+
try {
|
|
1157
|
+
const source = await readFile(bridge.agentCommand, "utf8");
|
|
1158
|
+
const port = Number(/port: (\d+)/.exec(source)[1]);
|
|
1159
|
+
const token = JSON.parse(/const token = (".*?");/.exec(source)[1]);
|
|
1160
|
+
for (const authenticated of [false, true]) {
|
|
1161
|
+
const peer = net.createConnection({ host: "127.0.0.1", port });
|
|
1162
|
+
peer.on("error", () => { });
|
|
1163
|
+
const closed = new Promise((resolve) => peer.once("close", resolve));
|
|
1164
|
+
await new Promise((resolve) => peer.once("connect", resolve));
|
|
1165
|
+
if (authenticated)
|
|
1166
|
+
peer.end(JSON.stringify({ token, type: "hello" }) + "\n");
|
|
1167
|
+
else
|
|
1168
|
+
peer.end();
|
|
1169
|
+
await closed;
|
|
1170
|
+
if (!authenticated)
|
|
1171
|
+
expect(logs).toEqual([]);
|
|
1172
|
+
}
|
|
1173
|
+
await waitForCondition(() => logs.length === 1, "Missing proxy-close diagnostic.");
|
|
1174
|
+
await bridge.stop();
|
|
1175
|
+
expect(logs.filter((line) => line.includes("ACP process session terminal:"))).toEqual([
|
|
1176
|
+
"[paperclip] ACP process session terminal: source=proxy_close outcome=error exitCode=unknown signal=unknown.\n",
|
|
1177
|
+
]);
|
|
1178
|
+
}
|
|
1179
|
+
finally {
|
|
1180
|
+
await bridge?.stop();
|
|
1181
|
+
}
|
|
1182
|
+
}, 10_000);
|
|
955
1183
|
it("buffers sandbox process session output until the local proxy connects", async () => {
|
|
956
1184
|
const rootDir = await mkdtemp(path.join(os.tmpdir(), "paperclip-process-session-buffer-"));
|
|
957
1185
|
cleanupDirs.push(rootDir);
|