Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .github/workflows/personal-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,13 @@ jobs:
- run: npm install --global @github/copilot@1.0.101
- name: Test release compatibility normalization
run: node --test scripts/personal-release-random.node-check.ts
- name: Test ACP load compatibility
run: |
node --test scripts/personal-release-load.node-check.ts
temp="$(mktemp -d)"
trap 'rm -rf "$temp"' EXIT
cp scripts/personal-release.ts scripts/personal-release-load.ts "$temp/"
node --input-type=module -e 'await import(process.argv[1])' "$temp/personal-release.ts"
- name: Prepare official source with pending fixes
id: prepare
env:
Expand All @@ -57,6 +64,7 @@ jobs:
run: |
gh auth setup-git
cp scripts/personal-release.ts "$RUNNER_TEMP/personal-release.ts"
cp scripts/personal-release-load.ts "$RUNNER_TEMP/"
cp scripts/personal-return.* "$RUNNER_TEMP/"
node "$RUNNER_TEMP/personal-release.ts"
- uses: actions/upload-artifact@v7
Expand Down
38 changes: 38 additions & 0 deletions scripts/personal-release-load.node-check.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import * as NodeAssert from "node:assert/strict";
import * as NodeTest from "node:test";
import { normalizeLoadResponse } from "./personal-release-load.ts";

const legacy = ` waitForSessionLoadReplayIdle,
const runLoadSessionWithReplayIdle = (
const idleFiber = yield* waitForSessionLoadReplayIdle({
gateRef: sessionLoadGateRef,
}).pipe(Effect.forkIn(runtimeScope));
const loaded = yield* Effect.raceFirst(
acp.agent.loadSession(loadPayload),
Fiber.join(idleFiber),
).pipe(
Effect.ensuring(Fiber.interrupt(idleFiber).pipe(Effect.ignore)),
detail: "session/load timed out waiting for RPC response or replay idle gap",
`;
NodeTest.test("restores response-bound session loading", () => {
const result = normalizeLoadResponse(legacy);
NodeAssert.match(result, /yield\* acp\.agent\.loadSession\(loadPayload\)\.pipe/);
NodeAssert.doesNotMatch(result, /Fiber\.join\(idleFiber\)|waitForSessionLoadReplayIdle/);
NodeAssert.match(result, /timed out waiting for RPC response"/);
NodeAssert.equal(normalizeLoadResponse(result), result);
});
NodeTest.test("leaves already-correct runtime alone", () => {
const current = "const runLoadSession = () => acp.agent.loadSession(loadPayload);";
NodeAssert.equal(normalizeLoadResponse(current), current);
});
NodeTest.test("rejects unrecognized race shape", () => {
NodeAssert.throws(() =>
normalizeLoadResponse(legacy.replace("Fiber.join(idleFiber)", "Fiber.join(otherFiber)")),
);
NodeAssert.throws(() =>
normalizeLoadResponse(legacy.replace("runLoadSessionWithReplayIdle", "runLoadSessionChanged")),
);
NodeAssert.throws(() =>
normalizeLoadResponse(legacy + "\nconst extra = waitForSessionLoadReplayIdle;"),
);
});
49 changes: 49 additions & 0 deletions scripts/personal-release-load.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// Preserve the carried fix: replay silence is not a session/load response.
export function normalizeLoadResponse(source: string): string {
const marker = " const runLoadSessionWithReplayIdle = (";
if (!source.includes(marker)) {
if (
source.includes("waitForSessionLoadReplayIdle") ||
source.includes("runLoadSessionWithReplayIdle")
)
throw new Error("Unexpected ACP load compatibility shape");
return source;
}
if (!source.includes("waitForSessionLoadReplayIdle")) {
const directLoad = " const loaded = yield* acp.agent.loadSession(loadPayload).pipe(";
if (
source.split(directLoad).length === 2 &&
!source.includes("Fiber.join(idleFiber)") &&
!source.includes("RPC response or replay idle gap")
)
return source;
throw new Error("Unexpected ACP load compatibility shape: missing idle helper");
}
const before = ` const idleFiber = yield* waitForSessionLoadReplayIdle({
gateRef: sessionLoadGateRef,
}).pipe(Effect.forkIn(runtimeScope));
const loaded = yield* Effect.raceFirst(
acp.agent.loadSession(loadPayload),
Fiber.join(idleFiber),
).pipe(
Effect.ensuring(Fiber.interrupt(idleFiber).pipe(Effect.ignore)),`;
const after = ` // Replay silence does not acknowledge session/load or its configuration.
const loaded = yield* acp.agent.loadSession(loadPayload).pipe(`;
const replacements: ReadonlyArray<readonly [string, string]> = [
[" waitForSessionLoadReplayIdle,\n", ""],
[before, after],
[
"session/load timed out waiting for RPC response or replay idle gap",
"session/load timed out waiting for RPC response",
],
];
let result = source;
for (const [from, to] of replacements) {
if (result.split(from).length !== 2)
throw new Error(`Unexpected ACP load compatibility shape: ${from}`);
result = result.replace(from, to);
}
if (result.includes("waitForSessionLoadReplayIdle") || result.includes("Fiber.join(idleFiber)"))
throw new Error("Unexpected ACP load compatibility shape: residual idle race");
return result;
}
10 changes: 10 additions & 0 deletions scripts/personal-release.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import * as NodeChildProcess from "node:child_process";
import * as NodeFS from "node:fs";

import { normalizeLoadResponse } from "./personal-release-load.ts";
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Resolved

const upstream = "pingdotgg/t3code";
const fork = "Microck/t3code";
const fixes: ReadonlyArray<{
Expand Down Expand Up @@ -377,6 +379,14 @@ function prepare() {
git("add", acpDriver);
git("commit", "-m", "fix(acp): retain current random and digest services");
}
const acpRuntime = "packages/provider-acp/src/server/AcpSessionRuntime.ts";
const runtimeSource = NodeFS.readFileSync(acpRuntime, "utf8");
const normalizedRuntime = normalizeLoadResponse(runtimeSource);
if (normalizedRuntime !== runtimeSource) {
NodeFS.writeFileSync(acpRuntime, normalizedRuntime);
git("add", acpRuntime);
git("commit", "-m", "fix(acp): await the session load response");
}
// The CLI release index and downloads must point at the same distribution.
replaceRequired(
"packages/shared/src/cliRelease.ts",
Expand Down
Loading