diff --git a/packages/paperclip-runner/acpx-profiles.json b/packages/paperclip-runner/acpx-profiles.json index b2fe9c04fa..bf7d1c2a08 100644 --- a/packages/paperclip-runner/acpx-profiles.json +++ b/packages/paperclip-runner/acpx-profiles.json @@ -32,12 +32,12 @@ "requiresProviderPolicy": true }, "copilot": { - "agentProfileVersion": 31, + "agentProfileVersion": 32, "agentServerPackage": "@github/copilot", "agentServerVersion": "1.0.88", "agentRuntimePackage": null, "agentRuntimeVersion": null, - "commandDigest": "sha256:4a22e4c50fd213c79cd02fd3c5369aef2256ac719762c62f5b70c691cd47e76b", + "commandDigest": "sha256:3dcc8de3034e32001b0a819a614beca345d314266a70a09e0050a9f5f58275fc", "requiresProviderPolicy": true }, "claude": { diff --git a/packages/paperclip-runner/runner/crates/runner-core/src/acpx_provider_backend.rs b/packages/paperclip-runner/runner/crates/runner-core/src/acpx_provider_backend.rs index 8e49e5df23..a72aa982db 100644 --- a/packages/paperclip-runner/runner/crates/runner-core/src/acpx_provider_backend.rs +++ b/packages/paperclip-runner/runner/crates/runner-core/src/acpx_provider_backend.rs @@ -3620,7 +3620,7 @@ mod tests { descriptor_value["agentRuntimePackage"] = Value::Null; descriptor_value["agentRuntimeVersion"] = Value::Null; descriptor_value["commandDigest"] = serde_json::from_str::(include_str!( - "../../../../test/fixtures/copilot-profile-v31-identity.json" + "../../../../test/fixtures/copilot-profile-v32-identity.json" )) .unwrap()["commandDigest"] .clone(); diff --git a/packages/paperclip-runner/runner/crates/runner-core/src/generated_acpx_profiles.rs b/packages/paperclip-runner/runner/crates/runner-core/src/generated_acpx_profiles.rs index ebd275e8f2..5dd8a81bb6 100644 --- a/packages/paperclip-runner/runner/crates/runner-core/src/generated_acpx_profiles.rs +++ b/packages/paperclip-runner/runner/crates/runner-core/src/generated_acpx_profiles.rs @@ -47,7 +47,7 @@ pub(crate) fn acpx_release_profile(agent: &str) -> Option { agent_runtime_package: None, agent_runtime_version: None, command_digest: - "sha256:4a22e4c50fd213c79cd02fd3c5369aef2256ac719762c62f5b70c691cd47e76b", + "sha256:3dcc8de3034e32001b0a819a614beca345d314266a70a09e0050a9f5f58275fc", requires_provider_policy: true, }, "claude" => AcpxReleaseProfile { diff --git a/packages/paperclip-runner/runner/crates/runner-core/tests/native_provider_backend.rs b/packages/paperclip-runner/runner/crates/runner-core/tests/native_provider_backend.rs index a5169d2644..991f918e27 100644 --- a/packages/paperclip-runner/runner/crates/runner-core/tests/native_provider_backend.rs +++ b/packages/paperclip-runner/runner/crates/runner-core/tests/native_provider_backend.rs @@ -1029,7 +1029,7 @@ fn provider_death_expires_input_and_commits_failure_without_querying_the_dead_pr let mut config = acpx_config(&directory, mode); let mut payload = prepare_payload_with_mode(&directory, "codex", mode); let identity: Value = serde_json::from_str(include_str!( - "../../../../test/fixtures/copilot-profile-v31-identity.json" + "../../../../test/fixtures/copilot-profile-v32-identity.json" )) .unwrap(); let digest = identity["commandDigest"].as_str().unwrap(); diff --git a/packages/paperclip-runner/scripts/build-copilot-distribution.mjs b/packages/paperclip-runner/scripts/build-copilot-distribution.mjs index 755322db5b..c8fd6fe537 100644 --- a/packages/paperclip-runner/scripts/build-copilot-distribution.mjs +++ b/packages/paperclip-runner/scripts/build-copilot-distribution.mjs @@ -7,7 +7,7 @@ import { COPILOT_VERSION, materializePinnedCopilotBinary, resolveCopilotDistribu const MAX_ARCHIVE_BYTES = 128 * 1024 * 1024; const MAX_EXPANDED_BYTES = 384 * 1024 * 1024; -const PROFILE_DIGEST = "sha256:4a22e4c50fd213c79cd02fd3c5369aef2256ac719762c62f5b70c691cd47e76b"; +const PROFILE_DIGEST = "sha256:3dcc8de3034e32001b0a819a614beca345d314266a70a09e0050a9f5f58275fc"; /** Build-time only; outputRoot is the exact runner-owned platform asset directory. */ export async function buildPinnedCopilotDistribution({ outputRoot, platform = process.platform, architecture = process.arch }, { fetchImpl = fetch } = {}) { diff --git a/packages/paperclip-runner/scripts/copilot-profile-identity.mjs b/packages/paperclip-runner/scripts/copilot-profile-identity.mjs index 5c8ab96b8f..a3486ad628 100644 --- a/packages/paperclip-runner/scripts/copilot-profile-identity.mjs +++ b/packages/paperclip-runner/scripts/copilot-profile-identity.mjs @@ -7,9 +7,9 @@ import { fileURLToPath } from "node:url"; import { resolve, dirname } from "node:path"; const root = resolve(dirname(fileURLToPath(import.meta.url)), ".."); -const fixture = resolve(root, "test/fixtures/copilot-profile-v31-identity.json"); +const fixture = resolve(root, "test/fixtures/copilot-profile-v32-identity.json"); const historical = JSON.parse(readFileSync(resolve(root, "test/fixtures/copilot-profile-v12-identity.json"), "utf8")); -const declaration = { ...historical.declaration, agentProfileVersion: 31 }; +const declaration = { ...historical.declaration, agentProfileVersion: 32 }; delete declaration.permissionIdentitySourceSha256; const sources = { displayEventSourceSha256: "src/drivers/acpx/copilot-events.ts", diff --git a/packages/paperclip-runner/scripts/discover-copilot-acp.mjs b/packages/paperclip-runner/scripts/discover-copilot-acp.mjs index dc0b1fc5fe..3cbfc825d1 100644 --- a/packages/paperclip-runner/scripts/discover-copilot-acp.mjs +++ b/packages/paperclip-runner/scripts/discover-copilot-acp.mjs @@ -1,3 +1,4 @@ +import { StringDecoder } from "node:string_decoder"; // Metadata only. Supply an explicit token; this closed protocol client never prompts. // Usage: node discover-copilot-acp.mjs [exact-model-id] import assert from "node:assert/strict"; @@ -24,6 +25,7 @@ export async function withDiscoveryWorkspace(install, callback, filesystem = { m } export function createDiscoveryRpc(child, { deadlineMs = 25_000, maxBytes = 2_097_152 } = {}) { + const decoder = new StringDecoder("utf8"); const pending = new Map(), observedMethods = {}; let nextId = 0, buffer = "", bytes = 0, failure; function fail(code) { @@ -39,7 +41,7 @@ export function createDiscoveryRpc(child, { deadlineMs = 25_000, maxBytes = 2_09 child.stdout.on("data", chunk => { bytes += chunk.length; if (bytes > maxBytes) { fatal("provider_wire_limit"); return; } - buffer += chunk.toString(); + buffer += decoder.write(chunk); while (buffer.includes("\n")) { const end = buffer.indexOf("\n"), line = buffer.slice(0, end); buffer = buffer.slice(end + 1); if (!line.trim()) continue; diff --git a/packages/paperclip-runner/scripts/discover-copilot-acp.test.mjs b/packages/paperclip-runner/scripts/discover-copilot-acp.test.mjs index d33b281700..b8602fe656 100644 --- a/packages/paperclip-runner/scripts/discover-copilot-acp.test.mjs +++ b/packages/paperclip-runner/scripts/discover-copilot-acp.test.mjs @@ -38,3 +38,12 @@ test("closed discovery protocol preserves numeric zero and rejects prompts", asy assert.deepEqual(await pending, { protocolVersion: 1 }); assert.throws(() => rpc.request("session/prompt", {}), /cannot send/); rpc.close(); }); + +test("discovery preserves multibyte model names when every byte arrives separately", async () => { + const child = childFixture(), rpc = createDiscoveryRpc(child); + const result = { models: { availableModels: [{ modelId: "gpt-5.6-luna", name: "東京 🚀 café" }] } }; + const pending = rpc.request("session/new", {}); + const wire = Buffer.from(`${JSON.stringify({ jsonrpc: "2.0", id: 0, result })}\n`); + for (const byte of wire) child.stdout.emit("data", Buffer.from([byte])); + assert.deepEqual(await pending, result); rpc.close(); +}); diff --git a/packages/paperclip-runner/scripts/qualify-copilot-acp.mjs b/packages/paperclip-runner/scripts/qualify-copilot-acp.mjs index 3031419670..c5cbaf13ca 100644 --- a/packages/paperclip-runner/scripts/qualify-copilot-acp.mjs +++ b/packages/paperclip-runner/scripts/qualify-copilot-acp.mjs @@ -1,3 +1,4 @@ +import { StringDecoder } from "node:string_decoder"; // Real-service qualification only. One explicit scenario sends one ACP prompt. // Usage: node qualify-copilot-acp.mjs // Bind only COPILOT_GITHUB_TOKEN. Do not run without a reconciled billing reservation. @@ -75,6 +76,7 @@ export async function runProbe(packInput, output, scenario, token) { backgroundCompletionObservedBeforeTerminal: false, cleanupComplete: false }; let child, exitPromise, sessionId, promptId, nextId = 0, buffer = "", bytes = 0, terminalSeen = false; let outerTimer, markerTimer; + const decoder = new StringDecoder("utf8"); const pending = new Map(); const env = { PATH: "/usr/bin:/bin", COPILOT_GITHUB_TOKEN: token, COPILOT_AUTO_UPDATE: "false", COPILOT_ALLOW_ALL: "false", NO_COLOR: "1" }; async function sampleMarker(phase) { @@ -115,7 +117,7 @@ export async function runProbe(packInput, output, scenario, token) { child.stdout.on("data", chunk => { bytes += chunk.length; if (bytes > 8_388_608) { failPending("wire_limit"); child.kill("SIGTERM"); return; } - buffer += chunk.toString(); + buffer += decoder.write(chunk); while (buffer.includes("\n")) { const index = buffer.indexOf("\n"), line = buffer.slice(0, index); buffer = buffer.slice(index + 1); if (!line.trim()) continue; diff --git a/packages/paperclip-runner/scripts/qualify-copilot-acp.test.mjs b/packages/paperclip-runner/scripts/qualify-copilot-acp.test.mjs index 182520dc45..fb018fe3e0 100644 --- a/packages/paperclip-runner/scripts/qualify-copilot-acp.test.mjs +++ b/packages/paperclip-runner/scripts/qualify-copilot-acp.test.mjs @@ -69,13 +69,19 @@ test("full credential-free protocol fixture preserves numeric-zero denial and re await writeFile(join(moduleRoot, "copilot-events.js"), 'export const COPILOT_ACP_CLIENT_CAPABILITIES = {};'); const childScript = join(root, "child.mjs"); await writeFile(childScript, `import { createInterface } from 'node:readline'; -const send = m => process.stdout.write(JSON.stringify({jsonrpc:'2.0', ...m})+'\\n'); +const send = m => { + const wire=Buffer.from(JSON.stringify({jsonrpc:'2.0', ...m})+'\\n'); + const unicode=wire.indexOf(Buffer.from('🚀')); + if(unicode<0){process.stdout.write(wire);return;} + process.stdout.write(wire.subarray(0,unicode+2)); + setTimeout(()=>process.stdout.write(wire.subarray(unicode+2)),50); +}; let promptId; createInterface({input:process.stdin}).on('line', line => { const m=JSON.parse(line); if(!m.method){if(m.id!==0 || m.result?.outcome?.optionId!=='native-deny-0') process.exit(8); send({id:promptId,result:{stopReason:'end_turn'}});return;} let result={}; - if(m.method==='initialize')result={agentInfo:{version:'1.0.88'},agentCapabilities:{}}; + if(m.method==='initialize')result={agentInfo:{version:'1.0.88'},agentCapabilities:{label:'東京 🚀 café'}}; if(m.method==='session/new')result={sessionId:'fixture-session',models:{availableModels:[{modelId:'gpt-5.6-luna'}]}}; if(m.method==='session/set_config_option')result={configOptions:[{id:'model',currentValue:'gpt-5.6-luna'}]}; if(m.method==='session/prompt'){promptId=m.id;send({id:0,method:'session/request_permission',params:{sessionId:'fixture-session',toolCall:{kind:'edit',rawInput:{fileName:process.cwd()+'/qualification-marker.txt'}},options:${JSON.stringify(options)}}});return;} @@ -86,6 +92,7 @@ createInterface({input:process.stdin}).on('line', line => { const result = await runProbe(root, output, "deny-write", "fixture-token-never-used-for-network"); const evidence = JSON.parse(await readFile(output, "utf8")); assert.equal(result.passed, true); + assert.deepEqual(evidence.agentCapabilities, { label: "東京 🚀 café" }); assert.equal(evidence.permissions[0].requestId, 0); assert.deepEqual(evidence.permissions[0].outcome, { outcome: "selected", optionId: "native-deny-0" }); assert.equal(evidence.cleanupComplete, true); diff --git a/packages/paperclip-runner/src/contracts/native-execution.test.ts b/packages/paperclip-runner/src/contracts/native-execution.test.ts index 80d4187ac8..75f62db7ee 100644 --- a/packages/paperclip-runner/src/contracts/native-execution.test.ts +++ b/packages/paperclip-runner/src/contracts/native-execution.test.ts @@ -391,7 +391,7 @@ describe("NativeExecutionInputV1", () => { })).toThrow("does not match"); }); - it.each([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31] as const)("decodes closed Copilot profile history at version %s without admitting a future version", (agentProfileVersion) => { + it.each([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32] as const)("decodes closed Copilot profile history at version %s without admitting a future version", (agentProfileVersion) => { const { qualificationModel: _qualificationModel, reportedModelId: _reportedModelId, permissionPolicy, qualificationStatus: _qualificationStatus, modelPolicy: _modelPolicy, ...snapshot } = QUALIFIED_ACPX_PROFILES.copilot; @@ -403,7 +403,7 @@ describe("NativeExecutionInputV1", () => { const parsed = parseNativeExecutionInput(value); expect(parsed.provider).toEqual(provider); expect(parseNativeExecutionInput(parsed)).toEqual(parsed); - for (const unsupportedVersion of [0, 32, 1.5, "31", null]) { + for (const unsupportedVersion of [0, 33, 1.5, "32", null]) { expect(() => parseNativeExecutionInput({ ...value, provider: { ...provider, profile: { ...provider.profile, agentProfileVersion: unsupportedVersion } }, })).toThrow("qualified ACPX v1 profile"); diff --git a/packages/paperclip-runner/src/drivers/acpx/copilot-installation.test.ts b/packages/paperclip-runner/src/drivers/acpx/copilot-installation.test.ts index 002b5f29b5..673a1d0c92 100644 --- a/packages/paperclip-runner/src/drivers/acpx/copilot-installation.test.ts +++ b/packages/paperclip-runner/src/drivers/acpx/copilot-installation.test.ts @@ -70,7 +70,7 @@ vi.mock("./installation-integrity.js", () => ({ verifyNativeAcpxInstallation: vi describe("Copilot build-owned installation", () => { it("admits the current declaration and binds its source policy, receipts and patch hashes", () => { - const identity = JSON.parse(readFileSync(new URL("../../../test/fixtures/copilot-profile-v31-identity.json", import.meta.url), "utf8")); + const identity = JSON.parse(readFileSync(new URL("../../../test/fixtures/copilot-profile-v32-identity.json", import.meta.url), "utf8")); expect(identity.declaration.systemInstructionDelivery).toBe(COPILOT_SYSTEM_INSTRUCTION_DELIVERY); expect(identity.declaration.sharedRuntimeContract).toBe("paperclip.acpx-runtime-contract.v1"); expect(identity.declaration.permissionContextContract).toBe(COPILOT_PERMISSION_CONTEXT_CONTRACT); @@ -101,7 +101,7 @@ describe("Copilot build-owned installation", () => { expect([...closure].filter(path => !bound.has(path))).toEqual(["negative-control:unbound-policy"]); }); it.each([...PERMISSION_POLICY_SOURCES, ...COPILOT_DISPLAY_SOURCES, ...SEMANTIC_RECEIPT_SOURCES])("changing %s changes the candidate identity", (_path, field) => { - const identity = JSON.parse(readFileSync(new URL("../../../test/fixtures/copilot-profile-v31-identity.json", import.meta.url), "utf8")); + const identity = JSON.parse(readFileSync(new URL("../../../test/fixtures/copilot-profile-v32-identity.json", import.meta.url), "utf8")); identity.declaration[field] = "0".repeat(64); const sorted = Object.fromEntries(Object.entries(identity.declaration).sort(([a], [b]) => a.localeCompare(b))); expect(`sha256:${createHash("sha256").update(JSON.stringify(sorted)).digest("hex")}`).not.toBe(identity.commandDigest); diff --git a/packages/paperclip-runner/src/drivers/acpx/generated-profiles.ts b/packages/paperclip-runner/src/drivers/acpx/generated-profiles.ts index a283881ca3..d97f526146 100644 --- a/packages/paperclip-runner/src/drivers/acpx/generated-profiles.ts +++ b/packages/paperclip-runner/src/drivers/acpx/generated-profiles.ts @@ -48,12 +48,12 @@ export const QUALIFIED_ACPX_PROFILE_DATA = { "protocolVersion": 1, "acpxVersion": "0.13.1", "agent": "copilot", - "agentProfileVersion": 31, + "agentProfileVersion": 32, "agentServerPackage": "@github/copilot", "agentServerVersion": "1.0.88", "agentRuntimePackage": null, "agentRuntimeVersion": null, - "commandDigest": "sha256:4a22e4c50fd213c79cd02fd3c5369aef2256ac719762c62f5b70c691cd47e76b", + "commandDigest": "sha256:3dcc8de3034e32001b0a819a614beca345d314266a70a09e0050a9f5f58275fc", "permissionPolicy": "interactive" }, "claude": { diff --git a/packages/paperclip-runner/src/drivers/acpx/profile-compatibility.test.ts b/packages/paperclip-runner/src/drivers/acpx/profile-compatibility.test.ts index 13586f1fcd..5b6305a10f 100644 --- a/packages/paperclip-runner/src/drivers/acpx/profile-compatibility.test.ts +++ b/packages/paperclip-runner/src/drivers/acpx/profile-compatibility.test.ts @@ -10,10 +10,10 @@ describe("historical ACPX profile decoding", () => { } }); it("decodes retained Copilot revisions and the current profile without widening other providers", () => { - for (const version of [1, 5, 6, 12, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31]) { + for (const version of [1, 5, 6, 12, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32]) { expect(isSupportedAcpxProfileVersion("copilot", version)).toBe(true); } - expect(isSupportedAcpxProfileVersion("copilot", 32)).toBe(false); + expect(isSupportedAcpxProfileVersion("copilot", 33)).toBe(false); for (const agent of ["cursor", "pi", "claude", "codex", "grok"]) { expect(isSupportedAcpxProfileVersion(agent, 23)).toBe(false); expect(isSupportedAcpxProfileVersion(agent, 24)).toBe(false); diff --git a/packages/paperclip-runner/src/drivers/acpx/profile-compatibility.ts b/packages/paperclip-runner/src/drivers/acpx/profile-compatibility.ts index a4fbcbcbe6..2834a50139 100644 --- a/packages/paperclip-runner/src/drivers/acpx/profile-compatibility.ts +++ b/packages/paperclip-runner/src/drivers/acpx/profile-compatibility.ts @@ -1,9 +1,9 @@ /** Decodable historical profile revisions, not permission to launch them. * Exact current profile/package/digest admission is checked separately. */ -export type AcpxProfileVersion = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31; +export type AcpxProfileVersion = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32; const historicalVersions: Readonly> = { pi: [1, 2, 3, 4, 5], claude: [1, 2, 3, 4, 5], codex: [1, 2, 3, 4, 5], - grok: [1, 2, 3, 4, 5], copilot: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31], + grok: [1, 2, 3, 4, 5], copilot: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32], cursor: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14], }; diff --git a/packages/paperclip-runner/src/drivers/copilot-metadata-probe.test.ts b/packages/paperclip-runner/src/drivers/copilot-metadata-probe.test.ts index 014c7617d5..0b7a3f6926 100644 --- a/packages/paperclip-runner/src/drivers/copilot-metadata-probe.test.ts +++ b/packages/paperclip-runner/src/drivers/copilot-metadata-probe.test.ts @@ -48,6 +48,14 @@ describe("Copilot metadata boundary", () => { expect(await probeCopilotMetadata("token", "missing")).toMatchObject({ status: "failed", code: "COPILOT_MODEL_UNAVAILABLE", promptSent: false }); expect(methods).toEqual(["initialize", "session/new"]); expect(close).toHaveBeenCalledOnce(); }); + it("preserves model labels split inside every UTF-8 character across transport chunks", async () => { + const child = fakeChild(() => undefined), rpc = createMetadataRpc(child); + const result = { models: { availableModels: [{ modelId: "gpt-5.6-luna", name: "東京 🚀 café" }] } }; + const response = rpc.request("session/new", {}); + const wire = Buffer.from(`${JSON.stringify({ jsonrpc: "2.0", id: 0, result })}\n`); + for (const byte of wire) child.stdout.emit("data", Buffer.from([byte])); + await expect(response).resolves.toEqual(result); + }); it("cannot dispatch semantic or prompt methods", () => { const child = fakeChild(() => undefined), rpc = createMetadataRpc(child); expect(() => rpc.request("session/prompt", {})).toThrow("cannot send"); diff --git a/packages/paperclip-runner/src/drivers/copilot-metadata-probe.ts b/packages/paperclip-runner/src/drivers/copilot-metadata-probe.ts index 40ec863653..f5c5b4289e 100644 --- a/packages/paperclip-runner/src/drivers/copilot-metadata-probe.ts +++ b/packages/paperclip-runner/src/drivers/copilot-metadata-probe.ts @@ -1,3 +1,4 @@ +import { StringDecoder } from "node:string_decoder"; import { mkdtemp, mkdir, writeFile, rm } from "node:fs/promises"; import { join } from "node:path"; import { tmpdir } from "node:os"; @@ -90,6 +91,7 @@ export async function probeCopilotMetadata(token: string, model?: string): Promi } export function createMetadataRpc(child: ChildProcessWithoutNullStreams) { + const decoder = new StringDecoder("utf8"); const pending = new Map(); let nextId = 0, bytes = 0, buffer = "", failure: Error | undefined; const fail = (error: Error) => { failure ??= error; for (const call of pending.values()) call.reject(failure); pending.clear(); }; @@ -100,7 +102,7 @@ export function createMetadataRpc(child: ChildProcessWithoutNullStreams) { child.stdout.on("data", (chunk: Buffer) => { bytes += chunk.length; if (bytes > 2 * 1024 * 1024) { fail(new Error("Copilot metadata exceeded its bound")); child.kill("SIGTERM"); return; } - buffer += chunk.toString(); + buffer += decoder.write(chunk); while (buffer.includes("\n")) { const end = buffer.indexOf("\n"), line = buffer.slice(0, end); buffer = buffer.slice(end + 1); if (!line.trim()) continue; diff --git a/packages/paperclip-runner/test/fixtures/copilot-profile-v32-identity.json b/packages/paperclip-runner/test/fixtures/copilot-profile-v32-identity.json new file mode 100644 index 0000000000..d60f725870 --- /dev/null +++ b/packages/paperclip-runner/test/fixtures/copilot-profile-v32-identity.json @@ -0,0 +1,81 @@ +{ + "commandDigest": "sha256:3dcc8de3034e32001b0a819a614beca345d314266a70a09e0050a9f5f58275fc", + "declaration": { + "schema": "paperclip.acpx_profile_declaration.v1", + "agent": "copilot", + "agentProfileVersion": 32, + "acpxVersion": "0.13.1", + "agentServerVersion": "1.0.88", + "protocolPolicyRevision": "copilot-agent-manual-v1", + "acpxPatchSha256": "fedf1e498c1e19daf9c973d475234488aa9acabbf1b9de890245bfac7a534483", + "policySha256": "a4be69be43db84052560420a3ca546a665c9165573c24d543eb33d144ba138a3", + "distributionSourceSha256": "c0a65e247fc47b263bd369a3d5ab505c4b323d4e6493be8a9ecbeb0e9dbb9107", + "agentFilesBinding": "registered-runtime-context-v1", + "systemInstructionDelivery": "COPILOT_HOME/copilot-instructions.md:replace-under-lifetime-lease-before-launch:v1", + "sharedRuntimeContract": "paperclip.acpx-runtime-contract.v1", + "innerDistributionSourceSha256": "9bb08347eed01f1ab44e065c8b06ead9be3a25973d6e6329dc4c0a099096279a", + "upstreamAppSha256": "7b48282a19b5b0814a0c96ad5e3a125173d792cc55f9525b2effea962f6063c0", + "patchedAppSha256": "61f8eebe0c30cc03b311c6818b2acb158a6d16ca58c8bfac5ebd42db095c2679", + "messageIdentityContract": "copilot-native-message-id-v1", + "ownedDistributionDelivery": "COPILOT_CLI_DIST_DIR:lease-owned-guarded-inner-distribution:v1", + "permissionContextContract": "copilot-edit-permission-context-v1", + "permissionContextSourceSha256": "fe1bb611bea289d81b1c7c973fbb01b93de133a7caa8fe78b7ff4ee1f485b224", + "permissionAdapterSourceSha256": "eebcc1ec9bc8caa8d1edf0cbda74bd69f5c55cf8d65a0503e95798b9979a19dc", + "permissionLocationsSourceSha256": "f39a81da395b6e23aa2a1a45572a28846e5e81bfd3d764d9a456f74a79c752e9", + "permissionRedactionSourceSha256": "ad6770c69269087951790e2e87e22ac088e3d432769adf17ebc865ed512e6c4f", + "permissionClassifierSourceSha256": "1161eabd82e26133e3b3db3ab567f65d52808b03f176e93497e02c8330349fb4", + "semanticToolReceiptContract": "paperclip.semantic_tool_receipt.v2", + "semanticReceiptSourceSha256": "b2795726b2234a663fec1a6ca11f0551ae69882fe9e82aa39686e952d036e791", + "semanticBridgeSourceSha256": "cf136da18e2cdbefae8e01d23d2c93f64eb7aebccaec938e84c2887c888f87ee", + "toolEvidenceSourceSha256": "4b517eed447615b3cc820af348ccc360978175149caa0bbc838d1f78332abe75", + "semanticNormalizedInputContract": "validated-forwarded-input-commit-v1", + "semanticSidecarSourceSha256": "49f7cb882fa09dcf879a2234d3e7b43fe72895d2c0f1e9b72fcbe18f012423bb", + "semanticDirectDriverSourceSha256": "3cea77a03c8822d68f77f090457176a9190facbec7d88ddf8c583c0e42245f70", + "semanticValidationSourceSha256": "3b0ac8d3f3cb92747d0bcea472ab0419a140e1cfdc43047e2c22542acc2d105f", + "semanticNormalizationSourceSha256": "8b628b82e8eacc91cdcc6fdca2210ba4cf282f01e9c6f74e95ff271655b5047e", + "semanticCompletionContractSourceSha256": "fa2b0c81cb9a62965839c905db81b930794774d8d557a01bce077dae5830b594", + "semanticValidatorsSourceSha256": "328436d29148e0b79ce36f36c764b3d780913bdb90d174d1ea03cf1f59b5ef13", + "semanticSchemaBundleSourceSha256": "d8cef4a9ebc136a3d37f3d0be7161986e6d65420e2ec734cfd0dfa468c665c97", + "semanticSidecarProtocolSourceSha256": "907b2cdc1a5291c6fb570855bbcc66cb196b5cf64195d5dc201148940678460a", + "semanticSidecarReceiptCommitContract": "correlated-tool-resolve-v1", + "displayEventSourceSha256": "d72f9a6035c247bc6a42c067c05753076c54322c4b58984e93922f3325dc6877", + "displayProjectionSourceSha256": "75952606b26dd93bbc582c1f0a4424487377272ea745fb3a27ceae031fd5dc7e", + "configuredEnvironmentSourceSha256": "a03575b3a737dea60da94cf0fa1feed80719a9aaa7f09456eb57a845d9e8e087", + "configuredEnvironmentRustSourceSha256": "55d44e48e217385b5c64b1b7d8df16dda62319ca3fb524e452fd78c9ed804d3b", + "profileActivitySourceSha256": "4fdb6b0f9125fd8372ba6f27945fa5c8a3d3b2ec891df544092e3dc7a75d5282", + "profileExtensionsSourceSha256": "0565d13d4064ed8c501d6ffda6d7bffca4493552de8aaa7fc12178dabb3ca435", + "profileInstallationSourceSha256": "7c26545922fc85db75a5db6bf3f6e21e381b6e189f4f51243b19ee237b93f8b1", + "attachmentPolicySourceSha256": "ce8027d1f8e2b7fd35df56a75ba162fd9696d1569c016b60bc9f0de1252cd958", + "singleReadEvidenceSourceSha256": "4069393405089bde613cecec04f5123c426594811da4c668bd96f0e7e283550f", + "nativeSessionRuntimeSourceSha256": "aac818c1cf50a25899ae95cafc70f093c8cd8af37d19f88cbb7847b4d202d2b6", + "nativeRuntimeContextSourceSha256": "af192af3fa511347045dfdb86d443be9aa046a4c56bdb48198668cf4d30581b8", + "nativeSessionContractSourceSha256": "93251b1eadc686e9d8339d4dfc50b995a3d0a9e6ad8aedc6f2bdf7e30c16138d", + "harnessSessionContractSourceSha256": "75ae4607312ec13466dd2f4ac87f000302b7b5a952cb6d4b51573fa8b7c35d82", + "harnessBackendSourceSha256": "3b11fd93b82ef13d5e6396217e3f102f900437f4d32efb00a9d75a9d2214e6ff", + "harnessSessionSourceSha256": "a9d748b8530544342bbc9f59968816664872782a0865db76ca15f28a1705697b", + "transportContractSourceSha256": "16f358c75dd4ae80af3ca921394c5899b15942b80b553e43ddfabb41c1bf31d3", + "nativeBackendSourceSha256": "a23afeab7e7094cb7e3df05e7a9eac822d0144d8c44893dbcc8a0e7b2bce0c85", + "nativeBackendFactorySourceSha256": "ce22825a53669f8c2db5aaa890bae94af19ede22295bda4ed7987a31d804cd8a", + "nativeInstructionsSourceSha256": "ea85be2aca8dfbd6b4042dcd7b1ed9db9a57baf8c379649a3f5d7d80ca54a6a2", + "runtimeRequestBridgeSourceSha256": "c449568f8abf7e90d5ae7a83b49809d9166461398f8b3046e4fe5f3367f3b052", + "runtimeRequestFacadeSourceSha256": "3d70c6025169779f7886ddf363a1c6fda4add5d14fa3cd49aea46aa1f6a9d8ec", + "runtimeRequestNotificationSourceSha256": "6196c6175f11c69295dc00fc773201f4fdeca26c500653870253c43b81e65211", + "guardedInstallationSourceSha256": "8afd25df307772e484e179e58bf54ce1510fe92be694482111d589f9f0ae6e77", + "nativeExecutionSourceSha256": "4cdd702c233bf0d086ff2aeea8f02c6db8817ba0c0bcb5e64e355ee7a1c2dd77", + "profileCompatibilitySourceSha256": "fe521686dbd9884eec96ba0963ec00b6b58f4d891aa0292e0dc18b0d84770646", + "installationSourceSha256": "9934653d6983905930099b1691b1f0c05461e04e950bb27dd0f92e64fc8e28e1", + "assetOwnershipSourceSha256": "43005b7e896e0546c1f44cbe4ff3f34ad6d71f275f4b9a8113f73a71e77930c4", + "assetInstallerSourceSha256": "d3bd9514e5920d0cc3567aa50487fb534c57a6f66b8da0d3f22c5f6e499c841f", + "credentialBindingSourceSha256": "d5c200bea2e8ab730eb56e32ce2070c8a1b5407e5907108640f76a463d9b9c9c", + "sidecarErrorSourceSha256": "23f3dbdc1ce488c690d218a854c820f4b4f3edd822bad574d67707314f8c512a", + "profileSourceSha256": "baf0b64371fada6c92331f9f88e915292b2761c029fd86452f6de32e26dc7fd6", + "metadataProbeSourceSha256": "826e74747a89b83a6f546ee1355de64ae5265eb920b50ae498a41dd561a493ee", + "permissionToolIdentitySourceSha256": "770b47305e571a81f344883057d0e4a482a1cd59ac77d045836593a8e739deb1", + "runtimeHostSourceSha256": "83a5ae07c19681ab195f76363661c2381494b243343270ba363d4db2088932a5", + "runtimeAdapterSourceSha256": "a1a8784f5883d2c93df6e3695d5499b83e226efb4f26e558639c4e7dbcc2d67a", + "runtimeSandboxSourceSha256": "4acec4c9757fe5ef5f2788ce20ced8ca4fde8edcfb63b59d0effcfd4316c048d", + "cancellationSourceSha256": "a07d1a9e982dec0ae130c1ad1efa5bc75c6a39e013b730ba3ee45256f09ceeca", + "agentFilesSourceSha256": "fb32f6badc13dfa22f231479509b631b2f0eba0c99b1ab9f3cd5c0c601aa03ba", + "nativeDistributionSourceSha256": "9bbe8329064ee88418528394f8e1cdc716a0b2b35092dc70729b8850e46b7a68" + } +}