Merge branch 'codex/work-folders-storybook-refresh' into codex/work-folders-runtime-hardening-refresh

* codex/work-folders-storybook-refresh:
  fix: keep supported ACPX profiles available in the Pi layer
  test: wait for active Daytona transfers before teardown
This commit is contained in:
Dotta 2026-09-11 16:07:02 -05:00
commit b79f09ef24
3 changed files with 28 additions and 11 deletions

View File

@ -4854,15 +4854,21 @@ describe("daytona native file-sync hooks", () => {
// Hold the inbound upload and the outbound download open at the same time, so
// the shared lease has two active sync calls when teardown starts.
let releaseUpload!: () => void;
let uploadStarted!: () => void;
const uploadReady = new Promise<void>((resolve) => { uploadStarted = resolve; });
sandbox.fs.uploadFiles.mockImplementation(async () => {
await new Promise<void>((resolve) => {
releaseUpload = resolve;
uploadStarted();
});
});
let releaseDownload!: () => void;
let downloadStarted!: () => void;
const downloadReady = new Promise<void>((resolve) => { downloadStarted = resolve; });
sandbox.fs.downloadFiles.mockImplementation(async (requests: Array<{ source: string; destination: string }>) => {
await new Promise<void>((resolve) => {
releaseDownload = resolve;
downloadStarted();
});
return Promise.all(
requests.map(async (request) => {
@ -4879,9 +4885,9 @@ describe("daytona native file-sync hooks", () => {
const outboundCall = plugin.definition.onEnvironmentSyncOut?.(
syncOutParams({ operationId: "out-active", sourcePath: `${REMOTE_DIR}/out.txt`, targetPath: outboundTarget }),
);
// Let both sync calls register on the activity gate and reach their hung
// transfer, so teardown sees a refCount of two.
await new Promise((resolve) => setTimeout(resolve, 0));
// Wait for both actual transfers, rather than assuming one event-loop tick
// completes the asynchronous filesystem preparation on a busy runner.
await Promise.all([uploadReady, downloadReady]);
const destroyCall = plugin.definition.onEnvironmentDestroyLease?.({
driverKey: "daytona",

View File

@ -279,6 +279,8 @@ describe("server adapter registry", () => {
it.each([
["claude", "claude-sonnet-5"],
["codex", "gpt-5.6-sol"],
["pi", "openrouter/deepseek/deepseek-v4-flash-0731"],
] as const)("does not claim runtime readiness from the remote ACPX %s platform alone", async (acpxAgent, model) => {
const result = await requireServerAdapter("paperclip_runner").testEnvironment({
companyId: "company-1",
@ -315,20 +317,23 @@ describe("server adapter registry", () => {
});
});
it("accepts the qualified ACPX Pi profile", async () => {
it.each([
["codex", "gpt-5.6-sol"],
["pi", "openrouter/deepseek/deepseek-v4-flash-0731"],
])("accepts qualified ACPX %s without claiming installation readiness", async (acpxAgent, model) => {
const result = await requireServerAdapter("paperclip_runner").testEnvironment({
companyId: "company-1",
adapterType: "paperclip_runner",
config: {
provider: "acpx",
acpxAgent: "pi",
model: "openrouter/deepseek/deepseek-v4-flash-0731",
acpxAgent,
model,
},
});
expect(result).toMatchObject({
status: "pass",
checks: [{ code: "acpx_profile_qualified", level: "info" }],
status: "warn",
checks: [{ code: "acpx_runtime_unverified", level: "warn" }],
});
});
it("wraps built-in npm runtime installs with the sandbox-aware install helper", () => {

View File

@ -405,7 +405,6 @@ const paperclipRunnerAdapter: ServerAdapterModule = {
}
if (profile.provider === "acpx") {
try {
if (profile.acpxAgent !== "claude") throw new Error("Select Codex to use the native Codex runner.");
const target = context.executionTarget;
if (target?.kind === "remote") {
const probe = await runAdapterExecutionTargetShellCommand(
@ -414,8 +413,8 @@ const paperclipRunnerAdapter: ServerAdapterModule = {
);
if (probe.timedOut || probe.exitCode !== 0) throw new Error("Could not verify the remote ACPX runner platform.");
const [os, arch] = probe.stdout.trim().split(/\s+/);
if (!((os === "Linux" && arch === "x86_64") || (os === "Darwin" && ["arm64", "x86_64"].includes(arch ?? "")))) {
throw new Error("ACPX Claude requires Linux x64 or macOS ARM64/x64.");
if (!((os === "Linux" && arch === "x86_64") || (profile.acpxAgent === "claude" && os === "Darwin" && ["arm64", "x86_64"].includes(arch ?? "")))) {
throw new Error(`ACPX ${profile.acpxAgent} requires Linux x64${profile.acpxAgent === "claude" ? " or macOS ARM64/x64" : ""}.`);
}
return {
adapterType: "paperclip_runner", status: "warn" as const, testedAt: new Date().toISOString(),
@ -423,6 +422,13 @@ const paperclipRunnerAdapter: ServerAdapterModule = {
message: "The remote platform is supported. Runtime package integrity and readiness must still be verified by the remote runner before launch." }],
};
}
if (profile.acpxAgent !== "claude") {
return {
adapterType: "paperclip_runner", status: "warn" as const, testedAt: new Date().toISOString(),
checks: [{ code: "acpx_runtime_unverified", level: "warn" as const,
message: `The ACPX ${profile.acpxAgent} profile is qualified. Runtime package integrity, platform support, and readiness must still be verified by the runner before launch.` }],
};
}
const { probeAcpxClaudeInstallation } = await import("@paperclipai/paperclip-runner/live");
await probeAcpxClaudeInstallation(profile.model);
return {