codex-copilot-dx 0.6.9 → 0.6.11
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/package.json +1 -1
- package/src/doctor.mjs +6 -0
- package/src/pm-studio-asar.mjs +75 -16
- package/src/pm-studio-setup.mjs +59 -18
- package/src/pm-studio-status.mjs +10 -2
- package/src/responses-request.mjs +113 -18
package/package.json
CHANGED
package/src/doctor.mjs
CHANGED
|
@@ -590,6 +590,12 @@ export async function collectDoctorChecks({
|
|
|
590
590
|
fix: "stop the running adapter, then run ccdx start",
|
|
591
591
|
});
|
|
592
592
|
}
|
|
593
|
+
} else if (pm.app.state === "predecessor") {
|
|
594
|
+
checks.push({
|
|
595
|
+
kind: "warn",
|
|
596
|
+
message: `PM Studio ${version} has a verified predecessor split patch`,
|
|
597
|
+
fix: "ccdx pms setup",
|
|
598
|
+
});
|
|
593
599
|
} else if (pm.app.state === "clean") {
|
|
594
600
|
checks.push({
|
|
595
601
|
kind: "warn",
|
package/src/pm-studio-asar.mjs
CHANGED
|
@@ -9,7 +9,7 @@ const PM_STUDIO_COPILOT_CONFIG_MODULE_LENGTH = 2_121;
|
|
|
9
9
|
const PM_STUDIO_COPILOT_CONFIG_MODULE_SOURCE_SHA256 = "3da6245d676015ab6cd26e4d6a0d2f54894a687c370aa419c5ad170533d086aa";
|
|
10
10
|
|
|
11
11
|
function splitOriginConfigModule() {
|
|
12
|
-
const source = `47024(I,e,t){"use strict";t.d(e,{qn:()=>l});const l={CLIENT_ID:"Iv1.b507a08c87ecfe98",CLIENT_SECRET:void 0,API_ENDPOINT:"${PM_STUDIO_ORIGIN}",DEVICE_CODE_URL:"https://github.com/login/device/code",ACCESS_TOKEN_URL:"https://github.com/login/oauth/access_token",COPILOT_TOKEN_URL:"https://api.github.com/copilot_internal/v2/token",USER_AGENT:"GitHubCopilotChat/0.26.7",EDITOR_VERSION:"vscode/1.99.3",EDITOR_PLUGIN_VERSION:"copilot-chat/0.26.7",INTEGRATION_ID:"vscode-chat",STANDARD_HEADERS:{Accept:"application/json","Content-Type":"application/json","User-Agent":"GitHubCopilotChat/0.26.7","Editor-Version":"vscode/1.99.3","Editor-Plugin-Version":"copilot-chat/0.26.7","Copilot-Integration-Id":"vscode-chat","X-Request-Id":()=>\`req_\${Date.now()}_\${Math.random().toString(36).substr(2,9)}\`}};const c=fetch.bind(globalThis),n="${CCDX_PM_STUDIO_ORIGIN}",a="${PM_STUDIO_SPLIT_ORIGIN_MARKER}",h="X-CCDX-PM-Relay",d=new Set,m=I=>I.headers.get(h)===a,q=I=>AbortSignal.any([I,AbortSignal.timeout(750)].filter(Boolean)),f=(I,e=400)=>Response.json({error:{code:I}},{status:e,headers:{[h]:a}});globalThis.fetch=async(I,e)=>{const t=I.url||I+"";if(t===\`\${l.API_ENDPOINT}/models\`){try{const t=await c(\`\${n}/models\`,
|
|
12
|
+
const source = `47024(I,e,t){"use strict";t.d(e,{qn:()=>l});const l={CLIENT_ID:"Iv1.b507a08c87ecfe98",CLIENT_SECRET:void 0,API_ENDPOINT:"${PM_STUDIO_ORIGIN}",DEVICE_CODE_URL:"https://github.com/login/device/code",ACCESS_TOKEN_URL:"https://github.com/login/oauth/access_token",COPILOT_TOKEN_URL:"https://api.github.com/copilot_internal/v2/token",USER_AGENT:"GitHubCopilotChat/0.26.7",EDITOR_VERSION:"vscode/1.99.3",EDITOR_PLUGIN_VERSION:"copilot-chat/0.26.7",INTEGRATION_ID:"vscode-chat",STANDARD_HEADERS:{Accept:"application/json","Content-Type":"application/json","User-Agent":"GitHubCopilotChat/0.26.7","Editor-Version":"vscode/1.99.3","Editor-Plugin-Version":"copilot-chat/0.26.7","Copilot-Integration-Id":"vscode-chat","X-Request-Id":()=>\`req_\${Date.now()}_\${Math.random().toString(36).substr(2,9)}\`}};const c=fetch.bind(globalThis),n="${CCDX_PM_STUDIO_ORIGIN}",a="${PM_STUDIO_SPLIT_ORIGIN_MARKER}",h="X-CCDX-PM-Relay",d=new Set,m=I=>I.headers.get(h)===a,q=I=>AbortSignal.any([I,AbortSignal.timeout(750)].filter(Boolean)),f=(I,e=400)=>Response.json({error:{code:I}},{status:e,headers:{[h]:a}});globalThis.fetch=async(I,e)=>{const t=I.url||I+"";if(t===\`\${l.API_ENDPOINT}/models\`){try{const t=await c(\`\${n}/models\`,e);if(t.ok&&m(t))try{let I=await t.clone().json(),e=I.data||I;if(Array.isArray(e)){d.clear();for(const I of e)/anthropic/i.test(I.vendor||I.owned_by)&&d.add(I.id);return t}}catch{}t.body?.cancel?.()?.catch?.(()=>{})}catch(I){if(e?.signal?.aborted)throw e.signal.reason||I}return c(I,e)}const s=t.startsWith(l.API_ENDPOINT)?t.slice(l.API_ENDPOINT.length):"";if("POST"===e?.method&&["/chat/completions","/responses","/embeddings"].includes(s)){let t="";try{t=(JSON.parse(e.body).model||"").trim()}catch{}if(d.has(t)||/^claude-/i.test(t)){if("/chat/completions"!==s)return f("model_not_supported");try{const I=await c(\`\${n}/models\`,{signal:q(e?.signal)}),t=401===I.status&&m(I);await I.text();if(!t)throw 0;const l=await c(\`\${n}\${s}\`,e);if(!m(l)){await l.body?.cancel?.();throw 0}return l}catch(I){if(e?.signal?.aborted)throw e.signal.reason||I;return f("relay_incompatible",503)}}}return c(I,e)}}`;
|
|
13
13
|
if (source.length > PM_STUDIO_COPILOT_CONFIG_MODULE_LENGTH) {
|
|
14
14
|
throw new Error("PM Studio split-origin module exceeds its exact source window");
|
|
15
15
|
}
|
|
@@ -35,8 +35,20 @@ export const PM_STUDIO_2_9_7_RECIPE = Object.freeze({
|
|
|
35
35
|
dataOffset: 3_832_764,
|
|
36
36
|
sourceAsarSha256: "36fb8bf2fc9326ddf49baab5cc0b54b38751a7db041bda3c42a3b01107b54118",
|
|
37
37
|
sourceHeaderSha256: "87746d92e00db2d40c03830ea06de22ec7cba112d07729801ccd02e226ffd961",
|
|
38
|
-
patchedAsarSha256: "
|
|
39
|
-
patchedHeaderSha256: "
|
|
38
|
+
patchedAsarSha256: "799dc18103a4553daefcaaddbe3410a1bfaf68d84407f4c10ef3d996afd71ad0",
|
|
39
|
+
patchedHeaderSha256: "08253795176d5471c6f406a29ccb134875d503bb55bca909b2cd131cd7708510",
|
|
40
|
+
predecessor: Object.freeze({
|
|
41
|
+
id: "split-origin-v1-model-discovery-750ms",
|
|
42
|
+
kind: "split-origin-predecessor",
|
|
43
|
+
asarSha256: "d520d115604225c1a3feb749dbe29ad0d2cd175c5233c010de0e1fade527fa0b",
|
|
44
|
+
headerSha256: "83e5fba3b6751b3098d8f6901db361a9b620ab3b924e0e551d3df612ff412642",
|
|
45
|
+
signingMetadata: Object.freeze({
|
|
46
|
+
identifier: "com.pm-studio.app",
|
|
47
|
+
flags: "0x10002(adhoc,runtime)",
|
|
48
|
+
runtime_version: "26.0.0",
|
|
49
|
+
entitlements_sha256: "9d4ccbda4fe0c81a70df3db93b3e61fe0500f67f14cdcbee4dea230e6512d05c",
|
|
50
|
+
}),
|
|
51
|
+
}),
|
|
40
52
|
targets: Object.freeze([
|
|
41
53
|
Object.freeze({
|
|
42
54
|
path: "dist/main/main.js",
|
|
@@ -44,13 +56,19 @@ export const PM_STUDIO_2_9_7_RECIPE = Object.freeze({
|
|
|
44
56
|
size: 9_909_974,
|
|
45
57
|
blockSize: 4_194_304,
|
|
46
58
|
sourceSha256: "58383be112886becdb8d8e7cce1b3efce07be6716190aa4940627f456eb8edb2",
|
|
47
|
-
patchedSha256: "
|
|
59
|
+
patchedSha256: "b219d08290b208fe41fa29b1e8ac4a1dee789e15f68fd4ff01eb5cd21249099b",
|
|
60
|
+
predecessorSha256: "69156040fb233a835b7be2f86fbe2f653380f03379adfedf46c63ab45de9d39d",
|
|
48
61
|
sourceBlocks: Object.freeze([
|
|
49
62
|
"3ce05a21e8992ccf12966cf9b78fcd28b2f66e6786489b5bb0a06f1d4b2a0c1e",
|
|
50
63
|
"0a4832413d8d8cdda67c8bb318c0e5c25df20c75802d637097ffd045a31cd443",
|
|
51
64
|
"bcc10582d8a74717f8f81b98182d3551f1eaf23eb9cadd908d160ce5e4ef8cba",
|
|
52
65
|
]),
|
|
53
66
|
patchedBlocks: Object.freeze([
|
|
67
|
+
"dcbffb0f3aaa79a5ca8f1ee9170826b874d9db237c230abcdc0490335b2dc6a8",
|
|
68
|
+
"0a4832413d8d8cdda67c8bb318c0e5c25df20c75802d637097ffd045a31cd443",
|
|
69
|
+
"bcc10582d8a74717f8f81b98182d3551f1eaf23eb9cadd908d160ce5e4ef8cba",
|
|
70
|
+
]),
|
|
71
|
+
predecessorBlocks: Object.freeze([
|
|
54
72
|
"f0b5585d2ff0d403e5c4d35e9bd0b8cbfec5c41a9b9057b8cc808107e889cf46",
|
|
55
73
|
"0a4832413d8d8cdda67c8bb318c0e5c25df20c75802d637097ffd045a31cd443",
|
|
56
74
|
"bcc10582d8a74717f8f81b98182d3551f1eaf23eb9cadd908d160ce5e4ef8cba",
|
|
@@ -62,7 +80,8 @@ export const PM_STUDIO_2_9_7_RECIPE = Object.freeze({
|
|
|
62
80
|
anchor: "47024(I,e,t){",
|
|
63
81
|
anchorCount: 1,
|
|
64
82
|
sourceSha256: PM_STUDIO_COPILOT_CONFIG_MODULE_SOURCE_SHA256,
|
|
65
|
-
patchedSha256: "
|
|
83
|
+
patchedSha256: "873d2dd276bd12a7dc2876f5eaf8c67d4ae34749ead8911d0588badf4e9fc0cf",
|
|
84
|
+
predecessorSha256: "a5b9312ed78e8a7fc3bd38f7ea5d4ab008f21bae18ba3dd6aa2d4be6b69191db",
|
|
66
85
|
replacement: PM_STUDIO_SPLIT_ORIGIN_CONFIG_MODULE,
|
|
67
86
|
}),
|
|
68
87
|
}),
|
|
@@ -124,8 +143,20 @@ export const PM_STUDIO_2_9_10_RECIPE = Object.freeze({
|
|
|
124
143
|
dataOffset: 3_833_292,
|
|
125
144
|
sourceAsarSha256: "d243860770e8b1d8044213924f9704d1fc52f900d6c33461eff6358962330b78",
|
|
126
145
|
sourceHeaderSha256: "5fc77d5b61e9647fba10fd2bd5752d0889c14da5a00b21d31bc48fdcccf74a69",
|
|
127
|
-
patchedAsarSha256: "
|
|
128
|
-
patchedHeaderSha256: "
|
|
146
|
+
patchedAsarSha256: "f309fc7e86bb4edaf1fecd9061fb4ddc634357c0ba9299f1d13f8b2ff33efd90",
|
|
147
|
+
patchedHeaderSha256: "98c4af8656e61cc1a1a8b2188592a499a987136f8e6b763b0e83abda788e798d",
|
|
148
|
+
predecessor: Object.freeze({
|
|
149
|
+
id: "split-origin-v1-model-discovery-750ms",
|
|
150
|
+
kind: "split-origin-predecessor",
|
|
151
|
+
asarSha256: "ea28d998056b32ca4115d208a4d81ce629c83f3f5f89c6a66d50749849beb6fc",
|
|
152
|
+
headerSha256: "348d80f5f2d1ebb92e6089195b1703b87467678f80d8946b8ab83b3ead03e5be",
|
|
153
|
+
signingMetadata: Object.freeze({
|
|
154
|
+
identifier: "com.pm-studio.app",
|
|
155
|
+
flags: "0x10002(adhoc,runtime)",
|
|
156
|
+
runtime_version: "26.0.0",
|
|
157
|
+
entitlements_sha256: "9d4ccbda4fe0c81a70df3db93b3e61fe0500f67f14cdcbee4dea230e6512d05c",
|
|
158
|
+
}),
|
|
159
|
+
}),
|
|
129
160
|
targets: Object.freeze([
|
|
130
161
|
Object.freeze({
|
|
131
162
|
path: "dist/main/main.js",
|
|
@@ -133,13 +164,19 @@ export const PM_STUDIO_2_9_10_RECIPE = Object.freeze({
|
|
|
133
164
|
size: 10_150_157,
|
|
134
165
|
blockSize: 4_194_304,
|
|
135
166
|
sourceSha256: "03607bb1edc068396b99f02b9c9e0d8e10388fb658afc112e06e875c123dbc27",
|
|
136
|
-
patchedSha256: "
|
|
167
|
+
patchedSha256: "71e936c79c3560ab5bd9813479f8a66f4a7b06629edca74953feaaf7904a6564",
|
|
168
|
+
predecessorSha256: "b5b5e37af3d06ffc603bdef620fc1e0254580f0ee325f1a77096af6c78379b79",
|
|
137
169
|
sourceBlocks: Object.freeze([
|
|
138
170
|
"3910a9bc5459f493956aafee7b3644e8d242027758f0dcdea97d7c10a324c6bf",
|
|
139
171
|
"49fa64c68425d35b1baff0d5745d856d377e014a7a7829322cd1b39aade9532e",
|
|
140
172
|
"bd7cc14a1d2e02abe66c0ec6fc4e97b263cfc1f67c4ae39e956c06d3bcc2fe67",
|
|
141
173
|
]),
|
|
142
174
|
patchedBlocks: Object.freeze([
|
|
175
|
+
"203ad1efbdcd869314510086632fdb0089196eb25179c46fb4108133cc65412f",
|
|
176
|
+
"49fa64c68425d35b1baff0d5745d856d377e014a7a7829322cd1b39aade9532e",
|
|
177
|
+
"bd7cc14a1d2e02abe66c0ec6fc4e97b263cfc1f67c4ae39e956c06d3bcc2fe67",
|
|
178
|
+
]),
|
|
179
|
+
predecessorBlocks: Object.freeze([
|
|
143
180
|
"63aa15d8c44614a7b2d9656ddba23109d40bab66b66b36339154953bd164da75",
|
|
144
181
|
"49fa64c68425d35b1baff0d5745d856d377e014a7a7829322cd1b39aade9532e",
|
|
145
182
|
"bd7cc14a1d2e02abe66c0ec6fc4e97b263cfc1f67c4ae39e956c06d3bcc2fe67",
|
|
@@ -151,7 +188,8 @@ export const PM_STUDIO_2_9_10_RECIPE = Object.freeze({
|
|
|
151
188
|
anchor: "47024(I,e,t){",
|
|
152
189
|
anchorCount: 1,
|
|
153
190
|
sourceSha256: PM_STUDIO_COPILOT_CONFIG_MODULE_SOURCE_SHA256,
|
|
154
|
-
patchedSha256: "
|
|
191
|
+
patchedSha256: "873d2dd276bd12a7dc2876f5eaf8c67d4ae34749ead8911d0588badf4e9fc0cf",
|
|
192
|
+
predecessorSha256: "a5b9312ed78e8a7fc3bd38f7ea5d4ab008f21bae18ba3dd6aa2d4be6b69191db",
|
|
155
193
|
replacement: PM_STUDIO_SPLIT_ORIGIN_CONFIG_MODULE,
|
|
156
194
|
}),
|
|
157
195
|
}),
|
|
@@ -399,8 +437,13 @@ function targetStateIssues(detail, target, state) {
|
|
|
399
437
|
addMismatch(issues, `${target.path} block size`, detail.integrity?.blockSize, target.blockSize);
|
|
400
438
|
|
|
401
439
|
const patched = state === "patched";
|
|
402
|
-
const
|
|
403
|
-
const
|
|
440
|
+
const predecessor = state === "predecessor";
|
|
441
|
+
const expectedHash = patched
|
|
442
|
+
? target.patchedSha256
|
|
443
|
+
: predecessor ? target.predecessorSha256 : target.sourceSha256;
|
|
444
|
+
const expectedBlocks = patched
|
|
445
|
+
? target.patchedBlocks
|
|
446
|
+
: predecessor ? target.predecessorBlocks : target.sourceBlocks;
|
|
404
447
|
|
|
405
448
|
addMismatch(issues, `${target.path} SHA-256`, detail.sha256, expectedHash);
|
|
406
449
|
addMismatch(issues, `${target.path} integrity hash`, detail.integrity?.hash, expectedHash);
|
|
@@ -411,7 +454,9 @@ function targetStateIssues(detail, target, state) {
|
|
|
411
454
|
addMismatch(issues, `${target.path} absolute edit offset`, detail.edit?.absoluteOffset, target.edit.absoluteOffset);
|
|
412
455
|
addMismatch(issues, `${target.path} edit length`, detail.edit?.length, target.edit.length);
|
|
413
456
|
addMismatch(issues, `${target.path} edit SHA-256`, detail.edit?.sha256,
|
|
414
|
-
patched
|
|
457
|
+
patched
|
|
458
|
+
? target.edit.patchedSha256
|
|
459
|
+
: predecessor ? target.edit.predecessorSha256 : target.edit.sourceSha256);
|
|
415
460
|
if (!sameArray(detail.edit?.anchorPositions, [target.edit.offset])) {
|
|
416
461
|
issues.push(`${target.path} module anchor position/count does not match recipe`);
|
|
417
462
|
}
|
|
@@ -432,11 +477,13 @@ export function inspectAsarBuffer(value, recipe = PM_STUDIO_2_9_7_RECIPE) {
|
|
|
432
477
|
|
|
433
478
|
const issuesFor = (state) => {
|
|
434
479
|
const patched = state === "patched";
|
|
480
|
+
const predecessor = state === "predecessor";
|
|
481
|
+
const expected = predecessor ? recipe.predecessor : null;
|
|
435
482
|
const issues = [...commonIssues];
|
|
436
483
|
addMismatch(issues, "ASAR SHA-256", asarSha256,
|
|
437
|
-
patched ? recipe.patchedAsarSha256 : recipe.sourceAsarSha256);
|
|
484
|
+
patched ? recipe.patchedAsarSha256 : predecessor ? expected?.asarSha256 : recipe.sourceAsarSha256);
|
|
438
485
|
addMismatch(issues, "ASAR header SHA-256", headerSha256,
|
|
439
|
-
patched ? recipe.patchedHeaderSha256 : recipe.sourceHeaderSha256);
|
|
486
|
+
patched ? recipe.patchedHeaderSha256 : predecessor ? expected?.headerSha256 : recipe.sourceHeaderSha256);
|
|
440
487
|
for (let index = 0; index < recipe.targets.length; index += 1) {
|
|
441
488
|
issues.push(...targetStateIssues(targets[index], recipe.targets[index], state));
|
|
442
489
|
}
|
|
@@ -445,6 +492,9 @@ export function inspectAsarBuffer(value, recipe = PM_STUDIO_2_9_7_RECIPE) {
|
|
|
445
492
|
|
|
446
493
|
const cleanIssues = issuesFor("clean");
|
|
447
494
|
const patchedIssues = issuesFor("patched");
|
|
495
|
+
const predecessorIssues = recipe.predecessor
|
|
496
|
+
? issuesFor("predecessor")
|
|
497
|
+
: ["recipe has no recognized predecessor patch"];
|
|
448
498
|
const legacyIssues = [...commonIssues];
|
|
449
499
|
if (!recipe.legacy) {
|
|
450
500
|
legacyIssues.push("recipe has no recognized legacy patch");
|
|
@@ -456,7 +506,9 @@ export function inspectAsarBuffer(value, recipe = PM_STUDIO_2_9_7_RECIPE) {
|
|
|
456
506
|
? "clean"
|
|
457
507
|
: patchedIssues.length === 0
|
|
458
508
|
? "patched"
|
|
459
|
-
:
|
|
509
|
+
: predecessorIssues.length === 0
|
|
510
|
+
? "predecessor"
|
|
511
|
+
: legacyIssues.length === 0 ? "legacy" : "drift";
|
|
460
512
|
return {
|
|
461
513
|
recipeId: recipe.id,
|
|
462
514
|
state,
|
|
@@ -466,6 +518,7 @@ export function inspectAsarBuffer(value, recipe = PM_STUDIO_2_9_7_RECIPE) {
|
|
|
466
518
|
targets,
|
|
467
519
|
cleanIssues,
|
|
468
520
|
patchedIssues,
|
|
521
|
+
predecessorIssues,
|
|
469
522
|
legacyIssues,
|
|
470
523
|
};
|
|
471
524
|
}
|
|
@@ -475,6 +528,12 @@ export function patchAsarBuffer(value, recipe = PM_STUDIO_2_9_7_RECIPE) {
|
|
|
475
528
|
if (before.state === "patched") {
|
|
476
529
|
return { changed: false, buffer: Buffer.from(value), before, after: before };
|
|
477
530
|
}
|
|
531
|
+
if (before.state === "predecessor") {
|
|
532
|
+
const error = new Error("Predecessor PM Studio split-origin patch must be migrated from a verified clean backup");
|
|
533
|
+
error.code = "PM_STUDIO_ASAR_PREDECESSOR";
|
|
534
|
+
error.inspection = before;
|
|
535
|
+
throw error;
|
|
536
|
+
}
|
|
478
537
|
if (before.state === "legacy") {
|
|
479
538
|
const error = new Error("Legacy PM Studio global-origin patch must be migrated from a verified clean backup");
|
|
480
539
|
error.code = "PM_STUDIO_ASAR_LEGACY";
|
|
@@ -482,7 +541,7 @@ export function patchAsarBuffer(value, recipe = PM_STUDIO_2_9_7_RECIPE) {
|
|
|
482
541
|
throw error;
|
|
483
542
|
}
|
|
484
543
|
if (before.state !== "clean") {
|
|
485
|
-
const error = new Error("PM Studio ASAR does not match the clean, split-origin, or legacy recipe");
|
|
544
|
+
const error = new Error("PM Studio ASAR does not match the clean, current split-origin, predecessor, or legacy recipe");
|
|
486
545
|
error.code = "PM_STUDIO_ASAR_DRIFT";
|
|
487
546
|
error.inspection = before;
|
|
488
547
|
throw error;
|
package/src/pm-studio-setup.mjs
CHANGED
|
@@ -519,6 +519,10 @@ export function inspectPmStudioApp({
|
|
|
519
519
|
&& codeSign?.adHoc === true
|
|
520
520
|
&& (!recipe.patchedSigningMetadata
|
|
521
521
|
|| JSON.stringify(signingMetadata(codeSign)) === JSON.stringify(recipe.patchedSigningMetadata));
|
|
522
|
+
const predecessorSignatureAccepted = codeSign?.valid === true
|
|
523
|
+
&& codeSign?.adHoc === true
|
|
524
|
+
&& Boolean(recipe.predecessor?.signingMetadata)
|
|
525
|
+
&& JSON.stringify(signingMetadata(codeSign)) === JSON.stringify(recipe.predecessor.signingMetadata);
|
|
522
526
|
const clean = issues.length === 0
|
|
523
527
|
&& asar.state === "clean"
|
|
524
528
|
&& integrityMatches(plistIntegrity, "SHA256", recipe.sourceHeaderSha256)
|
|
@@ -530,12 +534,16 @@ export function inspectPmStudioApp({
|
|
|
530
534
|
&& asar.state === "patched"
|
|
531
535
|
&& integrityMatches(plistIntegrity, "SHA256", recipe.patchedHeaderSha256)
|
|
532
536
|
&& patchedSignatureAccepted;
|
|
537
|
+
const predecessor = issues.length === 0
|
|
538
|
+
&& asar.state === "predecessor"
|
|
539
|
+
&& integrityMatches(plistIntegrity, "SHA256", recipe.predecessor?.headerSha256)
|
|
540
|
+
&& predecessorSignatureAccepted;
|
|
533
541
|
const legacy = issues.length === 0
|
|
534
542
|
&& asar.state === "legacy"
|
|
535
543
|
&& integrityMatches(plistIntegrity, "SHA256", recipe.legacy?.headerSha256)
|
|
536
544
|
&& patchedSignatureAccepted;
|
|
537
545
|
|
|
538
|
-
if (!clean && !patched && !legacy) {
|
|
546
|
+
if (!clean && !patched && !predecessor && !legacy) {
|
|
539
547
|
if (asar.state === "drift") issues.push("app.asar is unknown drift");
|
|
540
548
|
else if (asar.state === "clean"
|
|
541
549
|
&& !integrityMatches(plistIntegrity, "SHA256", recipe.sourceHeaderSha256)) {
|
|
@@ -543,6 +551,9 @@ export function inspectPmStudioApp({
|
|
|
543
551
|
} else if (asar.state === "patched"
|
|
544
552
|
&& !integrityMatches(plistIntegrity, "SHA256", recipe.patchedHeaderSha256)) {
|
|
545
553
|
issues.push("patched ASAR does not match ElectronAsarIntegrity");
|
|
554
|
+
} else if (asar.state === "predecessor"
|
|
555
|
+
&& !integrityMatches(plistIntegrity, "SHA256", recipe.predecessor?.headerSha256)) {
|
|
556
|
+
issues.push("predecessor ASAR does not match ElectronAsarIntegrity");
|
|
546
557
|
} else if (asar.state === "legacy"
|
|
547
558
|
&& !integrityMatches(plistIntegrity, "SHA256", recipe.legacy?.headerSha256)) {
|
|
548
559
|
issues.push("legacy ASAR does not match ElectronAsarIntegrity");
|
|
@@ -554,7 +565,7 @@ export function inspectPmStudioApp({
|
|
|
554
565
|
issues.push("codesign verification failed");
|
|
555
566
|
}
|
|
556
567
|
else if (asar.state === "clean" && codeSign.adHoc) issues.push("clean bundle has an unexpected ad-hoc signature");
|
|
557
|
-
else if (["patched", "legacy"].includes(asar.state) && !codeSign.adHoc) {
|
|
568
|
+
else if (["patched", "predecessor", "legacy"].includes(asar.state) && !codeSign.adHoc) {
|
|
558
569
|
issues.push(`${asar.state} bundle is not ad-hoc signed`);
|
|
559
570
|
}
|
|
560
571
|
else if (asar.state === "clean" && codeSign.teamIdentifier !== recipe.sourceTeamIdentifier) {
|
|
@@ -573,10 +584,16 @@ export function inspectPmStudioApp({
|
|
|
573
584
|
&& !patchedSignatureAccepted) {
|
|
574
585
|
issues.push(`${asar.state} bundle signing metadata does not match the recipe`);
|
|
575
586
|
}
|
|
587
|
+
if (asar.state === "predecessor" && codeSign?.valid && codeSign?.adHoc
|
|
588
|
+
&& !predecessorSignatureAccepted) {
|
|
589
|
+
issues.push("predecessor bundle signing metadata does not match the recipe");
|
|
590
|
+
}
|
|
576
591
|
}
|
|
577
592
|
|
|
578
593
|
return {
|
|
579
|
-
state: clean
|
|
594
|
+
state: clean
|
|
595
|
+
? "clean"
|
|
596
|
+
: patched ? "patched" : predecessor ? "predecessor" : legacy ? "legacy" : "drift",
|
|
580
597
|
metadata: {
|
|
581
598
|
version: String(metadata.version),
|
|
582
599
|
build: String(metadata.build),
|
|
@@ -688,7 +705,9 @@ function backupManifest(recipe, createdAt) {
|
|
|
688
705
|
function patchRecordMatches(record, recipe, state) {
|
|
689
706
|
const expected = state === "legacy"
|
|
690
707
|
? recipe.legacy
|
|
691
|
-
:
|
|
708
|
+
: state === "predecessor"
|
|
709
|
+
? recipe.predecessor
|
|
710
|
+
: { asarSha256: recipe.patchedAsarSha256, headerSha256: recipe.patchedHeaderSha256 };
|
|
692
711
|
return Boolean(expected)
|
|
693
712
|
&& record?.asar_sha256 === expected.asarSha256
|
|
694
713
|
&& record?.asar_header_sha256 === expected.headerSha256
|
|
@@ -696,8 +715,11 @@ function patchRecordMatches(record, recipe, state) {
|
|
|
696
715
|
}
|
|
697
716
|
|
|
698
717
|
function patchRecordForState(manifest, recipe, state) {
|
|
699
|
-
|
|
700
|
-
|
|
718
|
+
const historicalKey = state === "legacy"
|
|
719
|
+
? "legacy_patched"
|
|
720
|
+
: state === "predecessor" ? "predecessor_patched" : "";
|
|
721
|
+
if (historicalKey && patchRecordMatches(manifest?.[historicalKey], recipe, state)) {
|
|
722
|
+
return manifest[historicalKey];
|
|
701
723
|
}
|
|
702
724
|
return patchRecordMatches(manifest?.patched, recipe, state) ? manifest.patched : null;
|
|
703
725
|
}
|
|
@@ -728,8 +750,11 @@ function validateBackup({ backupDir, recipe, operations }) {
|
|
|
728
750
|
&& JSON.stringify(manifest?.source?.bundle_content) !== JSON.stringify(recipe.sourceBundleContent))
|
|
729
751
|
|| (recipe.sourceArtifact
|
|
730
752
|
&& JSON.stringify(manifest?.source?.artifact) !== JSON.stringify(recipe.sourceArtifact))
|
|
753
|
+
|| (manifest?.predecessor_patched !== undefined
|
|
754
|
+
&& !patchRecordMatches(manifest.predecessor_patched, recipe, "predecessor"))
|
|
731
755
|
|| (!patchRecordForState(manifest, recipe, "patched")
|
|
732
|
-
&& !patchRecordForState(manifest, recipe, "legacy")
|
|
756
|
+
&& !patchRecordForState(manifest, recipe, "legacy")
|
|
757
|
+
&& !patchRecordForState(manifest, recipe, "predecessor"))) {
|
|
733
758
|
throw setupError("PM_STUDIO_BACKUP_INVALID", `Existing PM Studio backup does not match recipe ${recipe.id}`);
|
|
734
759
|
}
|
|
735
760
|
const inspection = inspectPmStudioApp({ appPath: backupAppPath, recipe, operations });
|
|
@@ -775,6 +800,14 @@ function ensureBackup({ appPath, backupRoot, recipe, operations }) {
|
|
|
775
800
|
|
|
776
801
|
function writePatchedBinaryRecord({ backup, inspection, operations, recipe }) {
|
|
777
802
|
const manifest = JSON.parse(fs.readFileSync(backup.manifestPath, "utf8"));
|
|
803
|
+
if (manifest.predecessor_patched !== undefined
|
|
804
|
+
&& !patchRecordMatches(manifest.predecessor_patched, recipe, "predecessor")) {
|
|
805
|
+
throw setupError("PM_STUDIO_BACKUP_INVALID", "Existing PM Studio predecessor record does not match the patch recipe");
|
|
806
|
+
}
|
|
807
|
+
if (manifest.predecessor_patched === undefined
|
|
808
|
+
&& patchRecordMatches(manifest.patched, recipe, "predecessor")) {
|
|
809
|
+
manifest.predecessor_patched = manifest.patched;
|
|
810
|
+
}
|
|
778
811
|
if (!patchRecordMatches(manifest.legacy_patched, recipe, "legacy")
|
|
779
812
|
&& patchRecordMatches(manifest.patched, recipe, "legacy")) {
|
|
780
813
|
manifest.legacy_patched = manifest.patched;
|
|
@@ -804,7 +837,9 @@ export function assertPatchedBinaryRecord({
|
|
|
804
837
|
inspection,
|
|
805
838
|
manifestPath,
|
|
806
839
|
recipe,
|
|
807
|
-
recordState =
|
|
840
|
+
recordState = ["legacy", "predecessor"].includes(inspection?.state)
|
|
841
|
+
? inspection.state
|
|
842
|
+
: "patched",
|
|
808
843
|
}) {
|
|
809
844
|
let manifest;
|
|
810
845
|
try {
|
|
@@ -966,9 +1001,11 @@ export async function runPmStudioSetup({
|
|
|
966
1001
|
return { status: "already_patched", changed: false, recipe: recipe.id, backup, inspection: source, messages };
|
|
967
1002
|
}
|
|
968
1003
|
const migratingLegacy = source.state === "legacy";
|
|
969
|
-
|
|
1004
|
+
const migratingPredecessor = source.state === "predecessor";
|
|
1005
|
+
const migratingExistingPatch = migratingLegacy || migratingPredecessor;
|
|
1006
|
+
if (source.state !== "clean" && !migratingExistingPatch) {
|
|
970
1007
|
throw setupError("PM_STUDIO_BUNDLE_DRIFT",
|
|
971
|
-
`PM Studio ${recipe.version} build ${recipe.build} does not match the clean, split-origin, or legacy recipe; no files were changed`, source.issues);
|
|
1008
|
+
`PM Studio ${recipe.version} build ${recipe.build} does not match the clean, current split-origin, predecessor, or legacy recipe; no files were changed`, source.issues);
|
|
972
1009
|
}
|
|
973
1010
|
|
|
974
1011
|
if (source.sourceVerification === "exact-bundle-content") {
|
|
@@ -977,19 +1014,21 @@ export async function runPmStudioSetup({
|
|
|
977
1014
|
|
|
978
1015
|
const backupExists = fs.existsSync(finalBackupDir);
|
|
979
1016
|
let verifiedBackup = null;
|
|
980
|
-
if (
|
|
1017
|
+
if (migratingExistingPatch) {
|
|
981
1018
|
if (!backupExists) {
|
|
982
1019
|
throw setupError("PM_STUDIO_BACKUP_INVALID",
|
|
983
|
-
"Legacy
|
|
1020
|
+
`${migratingLegacy ? "Legacy global-origin" : "Predecessor split-origin"} PM Studio patch has no matching verified clean backup; no files were changed`);
|
|
984
1021
|
}
|
|
985
1022
|
verifiedBackup = validateBackup({ backupDir: finalBackupDir, recipe, operations });
|
|
986
1023
|
assertPatchedBinaryRecord({
|
|
987
1024
|
inspection: source,
|
|
988
1025
|
manifestPath: verifiedBackup.manifestPath,
|
|
989
1026
|
recipe,
|
|
990
|
-
recordState:
|
|
1027
|
+
recordState: source.state,
|
|
991
1028
|
});
|
|
992
|
-
emit(
|
|
1029
|
+
emit(migratingLegacy
|
|
1030
|
+
? "[WARN] Legacy global-origin patch detected; setup will rebuild from the verified clean backup so GPT and enterprise authentication return to PM Studio's native origin."
|
|
1031
|
+
: "[WARN] Predecessor split-origin patch detected; setup will rebuild from the verified clean backup so delayed Claude model discovery no longer falls back to the native catalog.");
|
|
993
1032
|
}
|
|
994
1033
|
assertSpace({ appPath, backupRoot, backupExists, operations });
|
|
995
1034
|
|
|
@@ -999,13 +1038,13 @@ export async function runPmStudioSetup({
|
|
|
999
1038
|
let preserveStage = false;
|
|
1000
1039
|
try {
|
|
1001
1040
|
operations.copyBundle({
|
|
1002
|
-
source:
|
|
1041
|
+
source: migratingExistingPatch ? backup.backupAppPath : appPath,
|
|
1003
1042
|
destination: stagePath,
|
|
1004
1043
|
processRunner: operations.processRunner,
|
|
1005
1044
|
});
|
|
1006
1045
|
const stagedSource = inspectPmStudioApp({ appPath: stagePath, recipe, operations });
|
|
1007
1046
|
if (stagedSource.state !== "clean"
|
|
1008
|
-
|| (!
|
|
1047
|
+
|| (!migratingExistingPatch && recipe.sourceBundleContent
|
|
1009
1048
|
&& stagedSource.bundleContent?.sha256 !== source.bundleContent?.sha256)) {
|
|
1010
1049
|
throw setupError("PM_STUDIO_STAGE_INVALID", "PM Studio staging copy does not match the exact clean source bundle", stagedSource.issues);
|
|
1011
1050
|
}
|
|
@@ -1078,7 +1117,9 @@ export async function runPmStudioSetup({
|
|
|
1078
1117
|
|
|
1079
1118
|
emit(migratingLegacy
|
|
1080
1119
|
? `[OK] Migrated PM Studio ${recipe.version} build ${recipe.build} from the legacy global-origin patch to the split-origin patch.`
|
|
1081
|
-
:
|
|
1120
|
+
: migratingPredecessor
|
|
1121
|
+
? `[OK] Migrated PM Studio ${recipe.version} build ${recipe.build} from the predecessor split-origin patch to the current split-origin patch.`
|
|
1122
|
+
: `[OK] Patched PM Studio ${recipe.version} build ${recipe.build}.`);
|
|
1082
1123
|
emit(`[OK] app.asar SHA-256: ${installed.asar.asarSha256}`);
|
|
1083
1124
|
emit(`[OK] Verified backup: ${backup.backupAppPath}${backup.reused ? " (reused)" : ""}`);
|
|
1084
1125
|
emit(`[OK] Backup manifest: ${backup.manifestPath}`);
|
|
@@ -1088,7 +1129,7 @@ export async function runPmStudioSetup({
|
|
|
1088
1129
|
emit(`[INFO] Restore step 3/3: move ${appPath} aside, copy ${backup.backupAppPath} to that exact path, and verify its signature before launch.`);
|
|
1089
1130
|
emit(`[INFO] Start ${commandName} before using Claude in PM Studio; GPT remains on PM Studio's native GitHub Copilot path.`);
|
|
1090
1131
|
return {
|
|
1091
|
-
status:
|
|
1132
|
+
status: migratingExistingPatch ? "migrated" : "patched",
|
|
1092
1133
|
changed: true,
|
|
1093
1134
|
recipe: recipe.id,
|
|
1094
1135
|
backup,
|
package/src/pm-studio-status.mjs
CHANGED
|
@@ -170,10 +170,15 @@ export async function inspectPmStudioStatus({
|
|
|
170
170
|
const recipe = selectRecipe(normalized, recipes);
|
|
171
171
|
if (recipe) {
|
|
172
172
|
app = { ...inspectApp({ appPath, recipe, operations }), recipe: recipe.id };
|
|
173
|
-
if (app.state
|
|
173
|
+
if (["patched", "predecessor"].includes(app.state)) {
|
|
174
174
|
const manifestPath = pmStudioPatchManifestPath({ home, backupRoot, recipe });
|
|
175
175
|
try {
|
|
176
|
-
verifyPatchRecord({
|
|
176
|
+
verifyPatchRecord({
|
|
177
|
+
inspection: app,
|
|
178
|
+
manifestPath,
|
|
179
|
+
recipe,
|
|
180
|
+
recordState: app.state,
|
|
181
|
+
});
|
|
177
182
|
app.patchRecord = { valid: true, manifestPath, reason: "" };
|
|
178
183
|
} catch (error) {
|
|
179
184
|
const reason = safeMessage(error);
|
|
@@ -239,6 +244,9 @@ function appStatusItem(result, commandName) {
|
|
|
239
244
|
const reason = app.patchRecord?.reason || "installed patch record is missing";
|
|
240
245
|
return { kind: "err", component: "App patch", detail: `${version}; patch record not verified`, message: `PM Studio ${version} matches the patch recipe, but its installed patch record is not verified: ${reason}` };
|
|
241
246
|
}
|
|
247
|
+
if (app.state === "predecessor" && app.patchRecord?.valid === true) {
|
|
248
|
+
return { kind: "warn", component: "App patch", detail: `${version}; verified predecessor split patch`, message: `PM Studio ${version} has a verified predecessor split patch; run ${commandName} pms setup to migrate` };
|
|
249
|
+
}
|
|
242
250
|
if (app.state === "legacy") {
|
|
243
251
|
return { kind: "err", component: "App patch", detail: `${version}; legacy global-origin patch`, message: `PM Studio ${version} has a legacy global-origin patch; run ${commandName} pms setup to migrate` };
|
|
244
252
|
}
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
rememberResponseHistoryNode,
|
|
7
7
|
responseHistoryRootId,
|
|
8
8
|
} from "./response-history.mjs";
|
|
9
|
+
import { isResponsesToolOutputItem, readResponsesToolOutputParts } from "./responses-content.mjs";
|
|
9
10
|
import { enforceResponsesImageLimit } from "./responses-image-limit.mjs";
|
|
10
11
|
import { status } from "./status.mjs";
|
|
11
12
|
|
|
@@ -69,27 +70,39 @@ function isEncryptedContentPart(value) {
|
|
|
69
70
|
return value && typeof value === "object" && value.type === "encrypted_content";
|
|
70
71
|
}
|
|
71
72
|
|
|
73
|
+
const OMIT_ENCRYPTED_CONTENT = Symbol("omit-encrypted-content");
|
|
74
|
+
const ENCRYPTED_HISTORY_REBASE = Symbol("encrypted-history-rebase");
|
|
75
|
+
const ENCRYPTED_TOOL_OUTPUT_MARKER = "[CCDX: encrypted tool output omitted because upstream could not decrypt it.]";
|
|
76
|
+
|
|
72
77
|
function stripEncryptedReasoningValue(value, state) {
|
|
78
|
+
if (isEncryptedContentPart(value)) {
|
|
79
|
+
state.changed = true;
|
|
80
|
+
return OMIT_ENCRYPTED_CONTENT;
|
|
81
|
+
}
|
|
82
|
+
|
|
73
83
|
if (Array.isArray(value)) {
|
|
74
84
|
const out = [];
|
|
75
85
|
for (const item of value) {
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
continue;
|
|
79
|
-
}
|
|
80
|
-
out.push(stripEncryptedReasoningValue(item, state));
|
|
86
|
+
const stripped = stripEncryptedReasoningValue(item, state);
|
|
87
|
+
if (stripped !== OMIT_ENCRYPTED_CONTENT) out.push(stripped);
|
|
81
88
|
}
|
|
82
89
|
return out;
|
|
83
90
|
}
|
|
84
91
|
|
|
85
92
|
if (value && typeof value === "object") {
|
|
93
|
+
const keys = Object.keys(value);
|
|
94
|
+
if (keys.length === 1 && keys[0] === "encrypted_content") {
|
|
95
|
+
state.changed = true;
|
|
96
|
+
return OMIT_ENCRYPTED_CONTENT;
|
|
97
|
+
}
|
|
86
98
|
const out = {};
|
|
87
99
|
for (const [key, child] of Object.entries(value)) {
|
|
88
100
|
if (key === "encrypted_content") {
|
|
89
101
|
state.changed = true;
|
|
90
102
|
continue;
|
|
91
103
|
}
|
|
92
|
-
|
|
104
|
+
const stripped = stripEncryptedReasoningValue(child, state);
|
|
105
|
+
if (stripped !== OMIT_ENCRYPTED_CONTENT) out[key] = stripped;
|
|
93
106
|
}
|
|
94
107
|
return out;
|
|
95
108
|
}
|
|
@@ -97,28 +110,82 @@ function stripEncryptedReasoningValue(value, state) {
|
|
|
97
110
|
return value;
|
|
98
111
|
}
|
|
99
112
|
|
|
113
|
+
function stripEncryptedReasoningInputValue(item, state) {
|
|
114
|
+
if (!isResponsesToolOutputItem(item)) {
|
|
115
|
+
const out = stripEncryptedReasoningValue(item, state);
|
|
116
|
+
if (item?.type === "message"
|
|
117
|
+
&& Array.isArray(item.content)
|
|
118
|
+
&& item.content.length > 0
|
|
119
|
+
&& Array.isArray(out?.content)
|
|
120
|
+
&& out.content.length === 0) {
|
|
121
|
+
return OMIT_ENCRYPTED_CONTENT;
|
|
122
|
+
}
|
|
123
|
+
return out;
|
|
124
|
+
}
|
|
125
|
+
const hasOutput = Object.prototype.hasOwnProperty.call(item, "output");
|
|
126
|
+
const withoutOutput = { ...item };
|
|
127
|
+
delete withoutOutput.output;
|
|
128
|
+
const out = stripEncryptedReasoningValue(withoutOutput, state);
|
|
129
|
+
if (!hasOutput) return out;
|
|
130
|
+
if (isEncryptedContentPart(item.output)) {
|
|
131
|
+
state.changed = true;
|
|
132
|
+
out.output = ENCRYPTED_TOOL_OUTPUT_MARKER;
|
|
133
|
+
return out;
|
|
134
|
+
}
|
|
135
|
+
out.output = typeof item.output === "string" ? item.output : cloneJson(item.output);
|
|
136
|
+
if (typeof item.output === "string" && !item.output.includes("encrypted_content")) return out;
|
|
137
|
+
const parsed = readResponsesToolOutputParts(out);
|
|
138
|
+
if (parsed) {
|
|
139
|
+
const outputState = { changed: false };
|
|
140
|
+
const parts = stripEncryptedReasoningValue(parsed.parts, outputState);
|
|
141
|
+
if (!outputState.changed) return out;
|
|
142
|
+
state.changed = true;
|
|
143
|
+
if (!parts.length) {
|
|
144
|
+
out.output = ENCRYPTED_TOOL_OUTPUT_MARKER;
|
|
145
|
+
return out;
|
|
146
|
+
}
|
|
147
|
+
parsed.parts.splice(0, parsed.parts.length, ...parts);
|
|
148
|
+
parsed.commit?.();
|
|
149
|
+
return out;
|
|
150
|
+
}
|
|
151
|
+
const output = stripEncryptedReasoningValue(out.output, state);
|
|
152
|
+
out.output = output === OMIT_ENCRYPTED_CONTENT ? ENCRYPTED_TOOL_OUTPUT_MARKER : output;
|
|
153
|
+
return out;
|
|
154
|
+
}
|
|
155
|
+
|
|
100
156
|
function isEncryptedReasoningInputItem(item) {
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
157
|
+
if (!item || typeof item !== "object") return false;
|
|
158
|
+
if (["reasoning", "encrypted_content", "compaction"].includes(item.type)) return true;
|
|
159
|
+
const keys = Object.keys(item);
|
|
160
|
+
return keys.length === 1 && keys[0] === "encrypted_content";
|
|
105
161
|
}
|
|
106
162
|
|
|
107
163
|
export function sanitizeEncryptedReasoningRequest(reqContext) {
|
|
108
164
|
const state = { changed: false };
|
|
109
165
|
let body = cloneJson(reqContext.body);
|
|
110
166
|
let currentInputStart = reqContext.currentInputStart;
|
|
167
|
+
let historicalInputChanged = false;
|
|
111
168
|
if (Array.isArray(body.input)) {
|
|
112
169
|
const input = [];
|
|
113
170
|
let retainedBeforeCurrent = 0;
|
|
114
171
|
for (let index = 0; index < body.input.length; index += 1) {
|
|
115
172
|
const item = body.input[index];
|
|
173
|
+
const historical = Number.isFinite(currentInputStart) && index < currentInputStart;
|
|
116
174
|
if (isEncryptedReasoningInputItem(item)) {
|
|
117
175
|
state.changed = true;
|
|
176
|
+
if (historical) historicalInputChanged = true;
|
|
118
177
|
continue;
|
|
119
178
|
}
|
|
120
|
-
|
|
121
|
-
|
|
179
|
+
const itemState = { changed: false };
|
|
180
|
+
const stripped = stripEncryptedReasoningInputValue(item, itemState);
|
|
181
|
+
if (stripped !== OMIT_ENCRYPTED_CONTENT) input.push(stripped);
|
|
182
|
+
if (itemState.changed) {
|
|
183
|
+
state.changed = true;
|
|
184
|
+
if (historical) historicalInputChanged = true;
|
|
185
|
+
}
|
|
186
|
+
if (stripped !== OMIT_ENCRYPTED_CONTENT
|
|
187
|
+
&& Number.isFinite(currentInputStart)
|
|
188
|
+
&& index < currentInputStart) retainedBeforeCurrent += 1;
|
|
122
189
|
}
|
|
123
190
|
body.input = input;
|
|
124
191
|
if (Number.isFinite(currentInputStart)) currentInputStart = retainedBeforeCurrent;
|
|
@@ -127,12 +194,19 @@ export function sanitizeEncryptedReasoningRequest(reqContext) {
|
|
|
127
194
|
}
|
|
128
195
|
if (!state.changed) return null;
|
|
129
196
|
const historyInputItems = Array.isArray(reqContext.historyInputItems)
|
|
130
|
-
? reqContext.historyInputItems
|
|
131
|
-
|
|
132
|
-
|
|
197
|
+
? reqContext.historyInputItems.flatMap((item) => {
|
|
198
|
+
if (isEncryptedReasoningInputItem(item)) return [];
|
|
199
|
+
const stripped = stripEncryptedReasoningInputValue(item, { changed: false });
|
|
200
|
+
return stripped === OMIT_ENCRYPTED_CONTENT ? [] : [stripped];
|
|
201
|
+
})
|
|
133
202
|
: reqContext.historyInputItems;
|
|
203
|
+
const shouldRebaseHistory = historicalInputChanged
|
|
204
|
+
&& Number.isFinite(reqContext.currentInputStart)
|
|
205
|
+
&& reqContext.historyParentId !== undefined
|
|
206
|
+
&& reqContext.historyParentId !== null;
|
|
134
207
|
return {
|
|
135
208
|
...reqContext,
|
|
209
|
+
...(shouldRebaseHistory ? { [ENCRYPTED_HISTORY_REBASE]: true } : {}),
|
|
136
210
|
body,
|
|
137
211
|
currentInputStart,
|
|
138
212
|
inputItems: Array.isArray(body.input) ? body.input : reqContext.inputItems,
|
|
@@ -140,12 +214,30 @@ export function sanitizeEncryptedReasoningRequest(reqContext) {
|
|
|
140
214
|
};
|
|
141
215
|
}
|
|
142
216
|
|
|
217
|
+
function finalizeEncryptedHistoryRebase(reqContext) {
|
|
218
|
+
if (!reqContext[ENCRYPTED_HISTORY_REBASE]) return reqContext;
|
|
219
|
+
const finalized = {
|
|
220
|
+
...reqContext,
|
|
221
|
+
historyParentId: null,
|
|
222
|
+
historyRootId: null,
|
|
223
|
+
historyInputItems: reqContext.body.input,
|
|
224
|
+
inputItems: reqContext.body.input,
|
|
225
|
+
};
|
|
226
|
+
delete finalized[ENCRYPTED_HISTORY_REBASE];
|
|
227
|
+
return finalized;
|
|
228
|
+
}
|
|
229
|
+
|
|
143
230
|
export function isEncryptedContentVerificationError(statusCode, text) {
|
|
144
231
|
if (statusCode < 400 || !text) return false;
|
|
145
232
|
const lower = String(text).toLowerCase();
|
|
146
|
-
|
|
233
|
+
const reasoningFailure = lower.includes("encrypted content")
|
|
147
234
|
&& lower.includes("could not be verified")
|
|
148
235
|
&& (lower.includes("could not be decrypted") || lower.includes("could not be parsed"));
|
|
236
|
+
const functionOutputFailure = lower.includes("encrypted function output content")
|
|
237
|
+
&& lower.includes("could not be decrypted or decoded");
|
|
238
|
+
const missingEncryptedContent = statusCode < 500
|
|
239
|
+
&& /missing required parameter:\s*(['"]?)input\[\d+\](?:\.[a-z0-9_]+|\[\d+\])*\.encrypted_content\1(?=\.?(?:\s|$|["},\]]))/.test(lower);
|
|
240
|
+
return reasoningFailure || functionOutputFailure || missingEncryptedContent;
|
|
149
241
|
}
|
|
150
242
|
|
|
151
243
|
export function isImageNamespaceCollisionError(statusCode, text) {
|
|
@@ -192,7 +284,10 @@ export async function openCopilotResponse(reqContext, upstream = copilotResponse
|
|
|
192
284
|
});
|
|
193
285
|
options.assertPrepareActive?.();
|
|
194
286
|
payloadPrepared = true;
|
|
195
|
-
if (resp.ok)
|
|
287
|
+
if (resp.ok) {
|
|
288
|
+
reqContext = finalizeEncryptedHistoryRebase(reqContext);
|
|
289
|
+
return { resp, reqContext };
|
|
290
|
+
}
|
|
196
291
|
|
|
197
292
|
const errorText = await resp.text();
|
|
198
293
|
options.assertPrepareActive?.();
|
|
@@ -210,7 +305,7 @@ export async function openCopilotResponse(reqContext, upstream = copilotResponse
|
|
|
210
305
|
if (retryContext) {
|
|
211
306
|
encryptedRetried = true;
|
|
212
307
|
reqContext = retryContext;
|
|
213
|
-
console.warn(status("warn", "encrypted
|
|
308
|
+
console.warn(status("warn", "encrypted replay content rejected by upstream; retrying without unavailable encrypted content"));
|
|
214
309
|
continue;
|
|
215
310
|
}
|
|
216
311
|
}
|