codex-copilot-dx 0.6.12 → 0.6.13

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.
@@ -17,10 +17,6 @@ import {
17
17
  patchAsarBuffer,
18
18
  sha256Hex,
19
19
  } from "./pm-studio-asar.mjs";
20
- import {
21
- PM_STUDIO_OFFICIAL_REPOSITORY,
22
- verifyOfficialPmStudioProvenance,
23
- } from "./pm-studio-provenance.mjs";
24
20
  import { withPmStudioSetupLock } from "./pm-studio-setup-lock.mjs";
25
21
 
26
22
  export const DEFAULT_PM_STUDIO_APP_PATH = "/Applications/PM Studio.app";
@@ -275,9 +271,7 @@ function defaultInspectCodeSign({ appPath, processRunner }) {
275
271
  : "";
276
272
  return {
277
273
  valid: !verify.error && verify.status === 0
278
- && !display.error && display.status === 0
279
- && !entitlementsResult.error && entitlementsResult.status === 0
280
- && hasEntitlements,
274
+ && !display.error && display.status === 0,
281
275
  verifyValid: !verify.error && verify.status === 0,
282
276
  displayValid: !display.error && display.status === 0,
283
277
  entitlementsState: hasEntitlements
@@ -322,32 +316,19 @@ function defaultInspectExecutableIntegrity({ appPath, infoPlistPath, recipe, pro
322
316
  };
323
317
  }
324
318
 
325
- function defaultReadAppArchitecture({ executablePath, processRunner }) {
326
- const output = runChecked(processRunner, "/usr/bin/lipo", ["-archs", executablePath],
327
- "Reading PM Studio executable architecture").stdout.trim();
328
- const architectures = output.split(/\s+/).filter(Boolean);
329
- if (architectures.length !== 1 || !["arm64", "x86_64"].includes(architectures[0])) {
330
- throw setupError("PM_STUDIO_ARCHITECTURE_UNSUPPORTED",
331
- "PM Studio must contain exactly one supported macOS architecture");
319
+ function defaultSignApp({ appPath, source, processRunner }) {
320
+ const preserve = [];
321
+ if (source?.codeSign?.displayValid === true) {
322
+ if (source.codeSign.entitlementsState === "xml") preserve.push("entitlements");
323
+ if (source.codeSign.flags) preserve.push("flags");
324
+ if (source.codeSign.runtimeVersion) preserve.push("runtime");
332
325
  }
333
- return architectures[0] === "x86_64" ? "x64" : architectures[0];
334
- }
335
-
336
- async function defaultVerifyOfficialProvenance(options) {
337
- return verifyOfficialPmStudioProvenance({
338
- ...options,
339
- extractor: async ({ archivePath, destination }) => {
340
- runChecked(options.processRunner, "/usr/bin/ditto", ["-x", "-k", archivePath, destination],
341
- "Extracting official PM Studio release");
342
- },
343
- });
344
- }
345
-
346
- function defaultSignApp({ appPath, processRunner }) {
347
- runChecked(processRunner, "/usr/bin/codesign", [
326
+ const args = [
348
327
  "--force", "--deep", "--sign", "-", "--timestamp=none",
349
- "--preserve-metadata=identifier,entitlements,flags,runtime", appPath,
350
- ], "Ad-hoc codesigning PM Studio");
328
+ ];
329
+ if (preserve.length > 0) args.push(`--preserve-metadata=${preserve.join(",")}`);
330
+ args.push(appPath);
331
+ runChecked(processRunner, "/usr/bin/codesign", args, "Ad-hoc codesigning PM Studio");
351
332
  }
352
333
 
353
334
  function defaultListBlockingProcesses({ processRunner }) {
@@ -440,8 +421,6 @@ export function createPmStudioSetupOperations(overrides = {}) {
440
421
  inspectCodeSign: defaultInspectCodeSign,
441
422
  inspectBundleContent: defaultInspectBundleContent,
442
423
  inspectExecutableIntegrity: defaultInspectExecutableIntegrity,
443
- readAppArchitecture: defaultReadAppArchitecture,
444
- verifyOfficialProvenance: defaultVerifyOfficialProvenance,
445
424
  withSetupLock: ({ appPath }, fn) => withPmStudioSetupLock({ appPath }, fn),
446
425
  signApp: defaultSignApp,
447
426
  listBlockingProcesses: defaultListBlockingProcesses,
@@ -483,17 +462,6 @@ function bundleContentMatches(actual, expected) {
483
462
  && actual?.xattrCount === expected?.xattrCount;
484
463
  }
485
464
 
486
- function sourceCodeSignatureMatches(actual, expected) {
487
- return actual?.adHoc === false
488
- && actual?.displayValid === true
489
- && actual?.identifier === expected?.identifier
490
- && actual?.teamIdentifier === expected?.teamIdentifier
491
- && actual?.flags === expected?.flags
492
- && actual?.runtimeVersion === expected?.runtimeVersion
493
- && actual?.cdHashFull === expected?.cdHashFull
494
- && actual?.notarizationTicket === expected?.notarizationTicket;
495
- }
496
-
497
465
  export function inspectPmStudioApp({
498
466
  appPath,
499
467
  recipe = PM_STUDIO_2_9_7_RECIPE,
@@ -536,23 +504,14 @@ export function inspectPmStudioApp({
536
504
 
537
505
  const exactSourceBundle = !recipe.sourceBundleContent
538
506
  || bundleContentMatches(bundleContent, recipe.sourceBundleContent);
539
- const strictVendorSignature = codeSign?.valid === true
540
- && codeSign?.adHoc === false
541
- && codeSign?.identifier === recipe.bundleIdentifier
542
- && codeSign?.teamIdentifier === recipe.sourceTeamIdentifier;
543
- const exactInvalidVendorSignature = recipe.sourceBundleContent
544
- && exactSourceBundle
545
- && codeSign?.valid === false
546
- && codeSign?.verifyValid === false
547
- && codeSign?.entitlementsState === "invalid"
548
- && sourceCodeSignatureMatches(codeSign, recipe.sourceCodeSignature);
549
- const sourceSignatureAccepted = strictVendorSignature || exactInvalidVendorSignature;
550
507
  const patchedSignatureAccepted = codeSign?.valid === true
551
508
  && codeSign?.adHoc === true
509
+ && codeSign?.identifier === recipe.bundleIdentifier
552
510
  && (!recipe.patchedSigningMetadata
553
511
  || JSON.stringify(signingMetadata(codeSign)) === JSON.stringify(recipe.patchedSigningMetadata));
554
512
  const predecessorSignatureAccepted = codeSign?.valid === true
555
513
  && codeSign?.adHoc === true
514
+ && codeSign?.identifier === recipe.bundleIdentifier
556
515
  && Boolean(recipe.predecessor?.signingMetadata)
557
516
  && JSON.stringify(signingMetadata(codeSign)) === JSON.stringify(recipe.predecessor.signingMetadata);
558
517
  const clean = issues.length === 0
@@ -560,8 +519,7 @@ export function inspectPmStudioApp({
560
519
  && integrityMatches(plistIntegrity, "SHA256", recipe.sourceHeaderSha256)
561
520
  && executableIntegrity.executableSha256 === recipe.sourceExecutableSha256
562
521
  && executableIntegrity.frameworkSha256 === recipe.sourceElectronFrameworkSha256
563
- && exactSourceBundle
564
- && sourceSignatureAccepted;
522
+ && exactSourceBundle;
565
523
  const patched = issues.length === 0
566
524
  && asar.state === "patched"
567
525
  && integrityMatches(plistIntegrity, "SHA256", recipe.patchedHeaderSha256)
@@ -593,15 +551,15 @@ export function inspectPmStudioApp({
593
551
  if (asar.state === "clean" && recipe.sourceBundleContent && !exactSourceBundle) {
594
552
  issues.push("bundle content does not match the exact clean recipe");
595
553
  }
596
- if (!codeSign?.valid && !(asar.state === "clean" && exactInvalidVendorSignature)) {
554
+ if (asar.state !== "clean" && !codeSign?.valid) {
597
555
  issues.push("codesign verification failed");
598
556
  }
599
- else if (asar.state === "clean" && codeSign.adHoc) issues.push("clean bundle has an unexpected ad-hoc signature");
600
557
  else if (["patched", "predecessor", "legacy"].includes(asar.state) && !codeSign.adHoc) {
601
558
  issues.push(`${asar.state} bundle is not ad-hoc signed`);
602
559
  }
603
- else if (asar.state === "clean" && codeSign.teamIdentifier !== recipe.sourceTeamIdentifier) {
604
- issues.push(`clean bundle TeamIdentifier is ${codeSign.teamIdentifier || "missing"}, expected ${recipe.sourceTeamIdentifier}`);
560
+ else if (["patched", "predecessor", "legacy"].includes(asar.state)
561
+ && codeSign.identifier !== recipe.bundleIdentifier) {
562
+ issues.push(`${asar.state} bundle identifier does not match the recipe`);
605
563
  }
606
564
  if (asar.state === "clean"
607
565
  && executableIntegrity.executableSha256 !== recipe.sourceExecutableSha256) {
@@ -637,7 +595,7 @@ export function inspectPmStudioApp({
637
595
  codeSign,
638
596
  bundleContent,
639
597
  sourceVerification: clean
640
- ? exactInvalidVendorSignature ? "exact-bundle-content" : "codesign"
598
+ ? recipe.sourceBundleContent ? "local-content" : "exact-recipe"
641
599
  : "",
642
600
  paths,
643
601
  issues,
@@ -680,13 +638,13 @@ function selectRecipe(metadata, recipes) {
680
638
  && recipe.bundleIdentifier === String(metadata.bundleIdentifier));
681
639
  }
682
640
 
683
- function compatibleStaticOptions(metadata) {
641
+ function compatibleStaticOptions(metadata, executable) {
684
642
  return {
685
643
  version: String(metadata.version),
686
644
  build: String(metadata.build),
687
645
  bundleIdentifier: String(metadata.bundleIdentifier),
688
- sourceTeamIdentifier: PM_STUDIO_2_9_10_RECIPE.sourceTeamIdentifier,
689
- executable: PM_STUDIO_2_9_10_RECIPE.executable,
646
+ sourceTeamIdentifier: "local-app",
647
+ executable,
690
648
  electronFrameworkPath: PM_STUDIO_2_9_10_RECIPE.electronFrameworkPath,
691
649
  embeddedAsarIntegrity: PM_STUDIO_2_9_10_RECIPE.embeddedAsarIntegrity,
692
650
  asarPath: PM_STUDIO_2_9_10_RECIPE.asarPath,
@@ -710,23 +668,19 @@ function compatibleSourceBundleContent({ appPath, operations }) {
710
668
 
711
669
  function compatibleSourceStructure({ appPath, metadata, operations }) {
712
670
  const paths = appPaths(appPath, PM_STUDIO_2_9_10_RECIPE);
713
- if (String(metadata.bundleIdentifier) !== PM_STUDIO_2_9_10_RECIPE.bundleIdentifier) {
714
- throw setupError("PM_STUDIO_COMPATIBLE_SOURCE_UNTRUSTED",
715
- "PM Studio compatible-version discovery found an unexpected bundle identifier");
716
- }
717
671
  const executableIntegrity = operations.inspectExecutableIntegrity({
718
672
  ...paths,
719
673
  recipe: PM_STUDIO_2_9_10_RECIPE,
720
674
  processRunner: operations.processRunner,
721
675
  });
722
- if (!executableIntegrity?.matchesRecipeName
676
+ if (!executableIntegrity?.executableName
723
677
  || !executableIntegrity?.embeddedIntegrity?.supported
724
678
  || executableIntegrity.embeddedIntegrity.state !== PM_STUDIO_2_9_10_RECIPE.embeddedAsarIntegrity) {
725
- throw setupError("PM_STUDIO_COMPATIBLE_SOURCE_UNTRUSTED",
679
+ throw setupError("PM_STUDIO_ASAR_INCOMPATIBLE",
726
680
  "PM Studio compatible-version discovery found an unsupported executable or embedded ASAR integrity policy");
727
681
  }
728
682
  const compatibleRecipe = createCompatiblePmStudioRecipe(fs.readFileSync(paths.asarPath), {
729
- ...compatibleStaticOptions(metadata),
683
+ ...compatibleStaticOptions(metadata, executableIntegrity.executableName),
730
684
  sourceExecutableSha256: executableIntegrity.executableSha256,
731
685
  sourceElectronFrameworkSha256: executableIntegrity.frameworkSha256,
732
686
  });
@@ -736,7 +690,7 @@ function compatibleSourceStructure({ appPath, metadata, operations }) {
736
690
  processRunner: operations.processRunner,
737
691
  });
738
692
  if (!integrityMatches(plistIntegrity, "SHA256", compatibleRecipe.sourceHeaderSha256)) {
739
- throw setupError("PM_STUDIO_COMPATIBLE_SOURCE_UNTRUSTED",
693
+ throw setupError("PM_STUDIO_ASAR_INCOMPATIBLE",
740
694
  "PM Studio compatible-version discovery found mismatched ElectronAsarIntegrity metadata");
741
695
  }
742
696
  return { paths, executableIntegrity, compatibleRecipe };
@@ -749,31 +703,8 @@ function frozenBundleContent(value) {
749
703
  });
750
704
  }
751
705
 
752
- function sourceCodeSignature(codeSign) {
753
- return Object.freeze({
754
- identifier: codeSign.identifier,
755
- teamIdentifier: codeSign.teamIdentifier,
756
- flags: codeSign.flags,
757
- runtimeVersion: codeSign.runtimeVersion,
758
- cdHashFull: codeSign.cdHashFull,
759
- notarizationTicket: codeSign.notarizationTicket,
760
- });
761
- }
762
-
763
706
  function createCompatibleSourceRecipe({ appPath, metadata, operations }) {
764
- const { paths, compatibleRecipe } = compatibleSourceStructure({ appPath, metadata, operations });
765
- const codeSign = operations.inspectCodeSign({
766
- ...paths,
767
- recipe: PM_STUDIO_2_9_10_RECIPE,
768
- processRunner: operations.processRunner,
769
- });
770
- if (codeSign?.valid !== true
771
- || codeSign?.adHoc !== false
772
- || codeSign?.identifier !== PM_STUDIO_2_9_10_RECIPE.bundleIdentifier
773
- || codeSign?.teamIdentifier !== PM_STUDIO_2_9_10_RECIPE.sourceTeamIdentifier) {
774
- throw setupError("PM_STUDIO_COMPATIBLE_SOURCE_UNTRUSTED",
775
- "PM Studio compatible-version discovery requires an intact vendor signature");
776
- }
707
+ const { compatibleRecipe } = compatibleSourceStructure({ appPath, metadata, operations });
777
708
  const sourceBundleContent = compatibleSourceBundleContent({ appPath, operations });
778
709
  return Object.freeze({
779
710
  ...compatibleRecipe,
@@ -781,134 +712,11 @@ function createCompatibleSourceRecipe({ appPath, metadata, operations }) {
781
712
  });
782
713
  }
783
714
 
784
- function exactInvalidVendorSignature(codeSign) {
785
- return codeSign?.valid === false
786
- && codeSign?.verifyValid === false
787
- && codeSign?.displayValid === true
788
- && codeSign?.entitlementsState === "invalid"
789
- && codeSign?.adHoc === false
790
- && codeSign?.identifier === PM_STUDIO_2_9_10_RECIPE.bundleIdentifier
791
- && codeSign?.teamIdentifier === PM_STUDIO_2_9_10_RECIPE.sourceTeamIdentifier
792
- && typeof codeSign?.flags === "string" && codeSign.flags.length > 0
793
- && typeof codeSign?.runtimeVersion === "string" && codeSign.runtimeVersion.length > 0
794
- && /^[0-9a-f]{64}$/.test(codeSign?.cdHashFull || "")
795
- && codeSign?.notarizationTicket === "stapled";
796
- }
797
-
798
- function officialArtifact(provenance, metadata, architecture) {
799
- if (provenance?.verified !== true
800
- || provenance.repository !== PM_STUDIO_OFFICIAL_REPOSITORY
801
- || provenance.version !== String(metadata.version)
802
- || provenance.tag !== `v${metadata.version}`
803
- || provenance.arch !== architecture
804
- || provenance.comparison?.matched !== true
805
- || typeof provenance.releaseUrl !== "string"
806
- || typeof provenance.asset?.name !== "string"
807
- || !Number.isSafeInteger(provenance.asset?.size)
808
- || provenance.asset.size <= 0
809
- || !/^[0-9a-f]{64}$/.test(provenance.asset?.sha256 || "")) {
810
- throw setupError("PM_STUDIO_COMPATIBLE_SOURCE_UNTRUSTED",
811
- "Official PM Studio release verification returned incomplete evidence");
812
- }
813
- return Object.freeze({
814
- repository: provenance.repository,
815
- tag: provenance.tag,
816
- arch: provenance.arch,
817
- releaseUrl: provenance.releaseUrl,
818
- asset: Object.freeze({
819
- name: provenance.asset.name,
820
- size: provenance.asset.size,
821
- sha256: provenance.asset.sha256,
822
- }),
823
- });
824
- }
825
-
826
- async function createOfficialCompatibleSourceRecipe({ appPath, metadata, operations }) {
827
- const { paths, executableIntegrity, compatibleRecipe } = compatibleSourceStructure({
828
- appPath, metadata, operations,
829
- });
830
- const codeSign = operations.inspectCodeSign({
831
- ...paths,
832
- recipe: PM_STUDIO_2_9_10_RECIPE,
833
- processRunner: operations.processRunner,
834
- });
835
- if (!exactInvalidVendorSignature(codeSign)) {
836
- throw setupError("PM_STUDIO_COMPATIBLE_SOURCE_UNTRUSTED",
837
- "PM Studio has neither an intact vendor signature nor the exact invalid-signature shape accepted for official artifact verification");
838
- }
839
- const architecture = operations.readAppArchitecture({
840
- ...paths,
841
- executablePath: executableIntegrity.executablePath,
842
- processRunner: operations.processRunner,
843
- });
844
- const sourceBundleContent = compatibleSourceBundleContent({ appPath, operations });
845
- const provenance = await operations.verifyOfficialProvenance({
846
- installedAppPath: appPath,
847
- version: String(metadata.version),
848
- arch: architecture,
849
- processRunner: operations.processRunner,
850
- });
851
- return Object.freeze({
852
- ...compatibleRecipe,
853
- sourceBundleContent: frozenBundleContent(sourceBundleContent),
854
- sourceArtifact: officialArtifact(provenance, metadata, architecture),
855
- sourceCodeSignature: sourceCodeSignature(codeSign),
856
- });
857
- }
858
-
859
715
  function sameIgnoredXattrs(value) {
860
716
  return JSON.stringify(value)
861
717
  === JSON.stringify(PM_STUDIO_2_9_10_RECIPE.sourceBundleContent.ignoredXattrs);
862
718
  }
863
719
 
864
- function storedOfficialArtifact(value, metadata) {
865
- const version = String(metadata.version);
866
- const arch = value?.arch;
867
- const assetName = `PM-Studio-${version}-mac-${arch}.zip`;
868
- if (!value || Array.isArray(value)
869
- || JSON.stringify(Object.keys(value).sort())
870
- !== JSON.stringify(["arch", "asset", "releaseUrl", "repository", "tag"])
871
- || value.repository !== PM_STUDIO_OFFICIAL_REPOSITORY
872
- || value.tag !== `v${version}`
873
- || !["arm64", "x64"].includes(arch)
874
- || value.releaseUrl !== `https://github.com/${PM_STUDIO_OFFICIAL_REPOSITORY}/releases/tag/v${version}`
875
- || !value.asset || Array.isArray(value.asset)
876
- || JSON.stringify(Object.keys(value.asset).sort())
877
- !== JSON.stringify(["name", "sha256", "size"])
878
- || value.asset.name !== assetName
879
- || !Number.isSafeInteger(value.asset.size)
880
- || value.asset.size <= 0
881
- || !/^[0-9a-f]{64}$/.test(value.asset.sha256 || "")) {
882
- throw setupError("PM_STUDIO_BACKUP_INVALID",
883
- "Compatible PM Studio backup has invalid official release evidence");
884
- }
885
- return Object.freeze({
886
- ...value,
887
- asset: Object.freeze({ ...value.asset }),
888
- });
889
- }
890
-
891
- function storedSourceCodeSignature(value) {
892
- if (!value || Array.isArray(value)
893
- || JSON.stringify(Object.keys(value).sort()) !== JSON.stringify([
894
- "cdHashFull",
895
- "flags",
896
- "identifier",
897
- "notarizationTicket",
898
- "runtimeVersion",
899
- "teamIdentifier",
900
- ])
901
- || value.identifier !== PM_STUDIO_2_9_10_RECIPE.bundleIdentifier
902
- || value.teamIdentifier !== PM_STUDIO_2_9_10_RECIPE.sourceTeamIdentifier
903
- || typeof value.flags !== "string" || value.flags.length === 0
904
- || typeof value.runtimeVersion !== "string" || value.runtimeVersion.length === 0
905
- || !/^[0-9a-f]{64}$/.test(value.cdHashFull || "")
906
- || value.notarizationTicket !== "stapled") {
907
- throw setupError("PM_STUDIO_BACKUP_INVALID",
908
- "Compatible PM Studio backup has invalid source signing evidence");
909
- }
910
- return Object.freeze({ ...value });
911
- }
912
720
 
913
721
  function compatibleRecipeFromManifest({ backupDir, manifest, metadata, operations }) {
914
722
  if (manifest?.schema_version !== 2
@@ -923,24 +731,20 @@ function compatibleRecipeFromManifest({ backupDir, manifest, metadata, operation
923
731
  const backupAppPath = path.join(backupDir, "PM Studio.app");
924
732
  assertInstalledAppPath(backupAppPath);
925
733
  const sourceAsarPath = path.join(backupAppPath, PM_STUDIO_2_9_10_RECIPE.asarPath);
734
+ const backupPaths = appPaths(backupAppPath, PM_STUDIO_2_9_10_RECIPE);
735
+ const executableIntegrity = operations.inspectExecutableIntegrity({
736
+ ...backupPaths,
737
+ recipe: PM_STUDIO_2_9_10_RECIPE,
738
+ processRunner: operations.processRunner,
739
+ });
926
740
  const compatibleRecipe = createCompatiblePmStudioRecipe(fs.readFileSync(sourceAsarPath), {
927
- ...compatibleStaticOptions(metadata),
741
+ ...compatibleStaticOptions(metadata, executableIntegrity.executableName),
928
742
  sourceExecutableSha256: manifest?.source?.binaries?.main_executable_sha256,
929
743
  sourceElectronFrameworkSha256: manifest?.source?.binaries?.electron_framework_sha256,
930
744
  });
931
- const hasOfficialArtifact = manifest?.source?.artifact !== undefined;
932
- const hasSourceCodeSignature = manifest?.source?.code_signature !== undefined;
933
- if (hasOfficialArtifact !== hasSourceCodeSignature) {
934
- throw setupError("PM_STUDIO_BACKUP_INVALID",
935
- "Compatible PM Studio backup has incomplete official source evidence");
936
- }
937
745
  const recipe = Object.freeze({
938
746
  ...compatibleRecipe,
939
747
  sourceBundleContent: frozenBundleContent(manifest.source.bundle_content),
940
- ...(hasOfficialArtifact ? {
941
- sourceArtifact: storedOfficialArtifact(manifest.source.artifact, metadata),
942
- sourceCodeSignature: storedSourceCodeSignature(manifest.source.code_signature),
943
- } : {}),
944
748
  });
945
749
  if (manifest.compatibility !== recipe.compatibility
946
750
  || manifest.recipe_id !== recipe.id
@@ -952,8 +756,7 @@ function compatibleRecipeFromManifest({ backupDir, manifest, metadata, operation
952
756
  `Compatible PM Studio backup does not match its reconstructed recipe: ${backupDir}`);
953
757
  }
954
758
  const inspection = inspectPmStudioApp({ appPath: backupAppPath, recipe, operations });
955
- const expectedVerification = hasOfficialArtifact ? "exact-bundle-content" : "codesign";
956
- if (inspection.state !== "clean" || inspection.sourceVerification !== expectedVerification) {
759
+ if (inspection.state !== "clean" || inspection.sourceVerification !== "local-content") {
957
760
  throw setupError("PM_STUDIO_BACKUP_INVALID",
958
761
  `Compatible PM Studio backup source verification failed: ${backupDir}`,
959
762
  inspection.issues);
@@ -1036,7 +839,7 @@ function selectCompatibleRecipe({ appPath, backupRoot, metadata, operations }) {
1036
839
  sourceError = error;
1037
840
  }
1038
841
  throw setupError("PM_STUDIO_UNSUPPORTED_VERSION",
1039
- `PM Studio ${metadata.version} build ${metadata.build} is not structurally compatible with the safe patch; no files were changed`,
842
+ `PM Studio ${metadata.version} build ${metadata.build} is not structurally compatible with the safe patch; no files were changed${sourceError?.message ? `: ${sourceError.message}` : ""}`,
1040
843
  sourceError?.message ? [sourceError.message] : undefined);
1041
844
  }
1042
845
 
@@ -1047,16 +850,44 @@ export function resolvePmStudioCompatibleRecipe({
1047
850
  metadata,
1048
851
  recipes = PM_STUDIO_RECIPES,
1049
852
  operations = createPmStudioSetupOperations(),
853
+ inspectApp = inspectPmStudioApp,
1050
854
  } = {}) {
1051
855
  if (!metadata || typeof metadata !== "object") {
1052
856
  throw new TypeError("PM Studio bundle metadata is required");
1053
857
  }
1054
- return selectRecipe(metadata, recipes) || selectCompatibleRecipe({
1055
- appPath,
1056
- backupRoot,
1057
- metadata,
1058
- operations,
1059
- });
858
+ const staticRecipe = selectRecipe(metadata, recipes);
859
+ let staticInspection = null;
860
+ if (staticRecipe) {
861
+ try {
862
+ staticInspection = inspectApp({ appPath, recipe: staticRecipe, operations });
863
+ } catch {
864
+ // A metadata match is not an admission gate. Local structure remains authoritative.
865
+ }
866
+ }
867
+ try {
868
+ return selectCompatibleRecipe({
869
+ appPath,
870
+ backupRoot,
871
+ metadata,
872
+ operations,
873
+ });
874
+ } catch (error) {
875
+ if (staticInspection?.state === "drift" && error?.code === "PM_STUDIO_UNSUPPORTED_VERSION") {
876
+ throw setupError("PM_STUDIO_BUNDLE_DRIFT",
877
+ `PM Studio ${metadata.version} build ${metadata.build} differs from its known local structure; no files were changed`,
878
+ staticInspection.issues);
879
+ }
880
+ const staticSourceCanBeSigned = staticInspection?.state !== "clean"
881
+ || !staticRecipe?.patchedSigningMetadata
882
+ || (staticInspection?.codeSign?.displayValid === true
883
+ && staticInspection.codeSign.entitlementsState === "xml");
884
+ if (error?.code === "PM_STUDIO_UNSUPPORTED_VERSION"
885
+ && staticInspection?.state && staticInspection.state !== "drift"
886
+ && staticSourceCanBeSigned) {
887
+ return staticRecipe;
888
+ }
889
+ throw error;
890
+ }
1060
891
  }
1061
892
 
1062
893
  function backupName(recipe) {
@@ -1100,8 +931,6 @@ function backupManifest(recipe, createdAt) {
1100
931
  embedded_asar_integrity: recipe.embeddedAsarIntegrity,
1101
932
  },
1102
933
  ...(recipe.sourceBundleContent ? { bundle_content: recipe.sourceBundleContent } : {}),
1103
- ...(recipe.sourceArtifact ? { artifact: recipe.sourceArtifact } : {}),
1104
- ...(recipe.sourceCodeSignature ? { code_signature: recipe.sourceCodeSignature } : {}),
1105
934
  },
1106
935
  patched: {
1107
936
  asar_sha256: recipe.patchedAsarSha256,
@@ -1162,10 +991,6 @@ function validateBackup({ backupDir, recipe, operations }) {
1162
991
  || manifest?.source?.binaries?.embedded_asar_integrity !== recipe.embeddedAsarIntegrity
1163
992
  || (recipe.sourceBundleContent
1164
993
  && JSON.stringify(manifest?.source?.bundle_content) !== JSON.stringify(recipe.sourceBundleContent))
1165
- || (recipe.sourceArtifact
1166
- && JSON.stringify(manifest?.source?.artifact) !== JSON.stringify(recipe.sourceArtifact))
1167
- || (recipe.compatibility && recipe.sourceCodeSignature
1168
- && JSON.stringify(manifest?.source?.code_signature) !== JSON.stringify(recipe.sourceCodeSignature))
1169
994
  || (manifest?.predecessor_patched !== undefined
1170
995
  && !patchRecordMatches(manifest.predecessor_patched, recipe, "predecessor"))
1171
996
  || (!patchRecordForState(manifest, recipe, "patched")
@@ -1279,11 +1104,7 @@ export function assertPatchedBinaryRecord({
1279
1104
  || manifest?.source?.binaries?.electron_framework_sha256 !== recipe.sourceElectronFrameworkSha256
1280
1105
  || manifest?.source?.binaries?.embedded_asar_integrity !== recipe.embeddedAsarIntegrity
1281
1106
  || JSON.stringify(manifest?.source?.bundle_content) !== JSON.stringify(recipe.sourceBundleContent)
1282
- ))
1283
- || (recipe.sourceArtifact
1284
- && JSON.stringify(manifest?.source?.artifact) !== JSON.stringify(recipe.sourceArtifact))
1285
- || (recipe.compatibility && recipe.sourceCodeSignature
1286
- && JSON.stringify(manifest?.source?.code_signature) !== JSON.stringify(recipe.sourceCodeSignature)))) {
1107
+ )))) {
1287
1108
  throw setupError("PM_STUDIO_PATCH_RECORD_INVALID", "PM Studio patched-binary record does not match the installed patch recipe");
1288
1109
  }
1289
1110
  const record = patchRecordForState(manifest, recipe, recordState);
@@ -1322,32 +1143,29 @@ function flagsWithoutAdHoc(value) {
1322
1143
  }
1323
1144
 
1324
1145
  function assertSigningMetadataPreserved(source, staged, recipe) {
1146
+ const after = signingMetadata(staged.codeSign);
1147
+ if (after.identifier !== recipe.bundleIdentifier) {
1148
+ throw setupError("PM_STUDIO_SIGNING_METADATA_CHANGED",
1149
+ "Ad-hoc signing did not use the PM Studio bundle identifier");
1150
+ }
1325
1151
  if (recipe.patchedSigningMetadata) {
1326
- if (JSON.stringify(signingMetadata(staged.codeSign))
1327
- !== JSON.stringify(recipe.patchedSigningMetadata)) {
1152
+ if (JSON.stringify(after) !== JSON.stringify(recipe.patchedSigningMetadata)) {
1328
1153
  throw setupError("PM_STUDIO_SIGNING_METADATA_CHANGED",
1329
1154
  "Ad-hoc signing did not produce the exact PM Studio signing metadata required by the recipe");
1330
1155
  }
1331
1156
  return;
1332
1157
  }
1333
- const before = signingMetadata(source.codeSign);
1334
- const after = signingMetadata(staged.codeSign);
1335
- before.flags = flagsWithoutAdHoc(before.flags);
1336
- after.flags = flagsWithoutAdHoc(after.flags);
1337
- if (recipe.compatibility
1338
- && recipe.sourceArtifact
1339
- && source.sourceVerification === "exact-bundle-content"
1340
- && source.codeSign?.entitlementsState === "invalid") {
1341
- if (staged.codeSign?.entitlementsState !== "xml"
1342
- || !/^[0-9a-f]{64}$/.test(after.entitlements_sha256)) {
1343
- throw setupError("PM_STUDIO_SIGNING_METADATA_CHANGED",
1344
- "Ad-hoc signing did not produce verifiable PM Studio entitlements from the official source bundle");
1345
- }
1346
- before.entitlements_sha256 = after.entitlements_sha256;
1347
- }
1348
- if (JSON.stringify(before) !== JSON.stringify(after)) {
1158
+ const sourceSignature = source.codeSign;
1159
+ if (sourceSignature?.displayValid !== true) return;
1160
+ const flagsChanged = sourceSignature.flags
1161
+ && flagsWithoutAdHoc(sourceSignature.flags) !== flagsWithoutAdHoc(after.flags);
1162
+ const runtimeChanged = sourceSignature.runtimeVersion
1163
+ && sourceSignature.runtimeVersion !== after.runtime_version;
1164
+ const entitlementsChanged = sourceSignature.entitlementsState === "xml"
1165
+ && sourceSignature.entitlementsSha256 !== after.entitlements_sha256;
1166
+ if (flagsChanged || runtimeChanged || entitlementsChanged) {
1349
1167
  throw setupError("PM_STUDIO_SIGNING_METADATA_CHANGED",
1350
- "Ad-hoc signing did not preserve PM Studio identifier, entitlements, flags, and runtime metadata");
1168
+ "Ad-hoc signing did not preserve available PM Studio entitlements, flags, and runtime metadata");
1351
1169
  }
1352
1170
  }
1353
1171
 
@@ -1380,7 +1198,7 @@ function replaceVerifiedStage({ appPath, stagePath, operations }) {
1380
1198
  }
1381
1199
 
1382
1200
  function recoveryMessage(backup) {
1383
- return `Verified backup: ${backup.backupAppPath}; manifest: ${backup.manifestPath}. Quit PM Studio, confirm the installed version/build still match, then restore only this version-matched backup or reinstall the official App.`;
1201
+ return `Verified backup: ${backup.backupAppPath}; manifest: ${backup.manifestPath}. Quit PM Studio, confirm the installed version/build still match, then restore only this version-matched backup or reinstall PM Studio.`;
1384
1202
  }
1385
1203
 
1386
1204
  export async function runPmStudioSetup({
@@ -1411,28 +1229,13 @@ export async function runPmStudioSetup({
1411
1229
  processRunner: operations.processRunner,
1412
1230
  };
1413
1231
  const metadata = operations.readBundleMetadata(genericPaths);
1414
- let recipe = selectRecipe(metadata, recipes);
1415
- if (!recipe) {
1416
- try {
1417
- recipe = resolvePmStudioCompatibleRecipe({
1418
- appPath,
1419
- backupRoot,
1420
- metadata,
1421
- recipes,
1422
- operations,
1423
- });
1424
- } catch (error) {
1425
- if (error?.code !== "PM_STUDIO_UNSUPPORTED_VERSION") throw error;
1426
- emit(`[INFO] Verifying PM Studio ${metadata.version} build ${metadata.build} against its official GitHub release before patching.`);
1427
- try {
1428
- recipe = await createOfficialCompatibleSourceRecipe({ appPath, metadata, operations });
1429
- } catch (sourceError) {
1430
- throw setupError("PM_STUDIO_UNSUPPORTED_VERSION",
1431
- `PM Studio ${metadata.version} build ${metadata.build} could not be safely verified as a structurally compatible official release; no files were changed`,
1432
- sourceError?.message ? [sourceError.message] : undefined);
1433
- }
1434
- }
1435
- }
1232
+ const recipe = resolvePmStudioCompatibleRecipe({
1233
+ appPath,
1234
+ backupRoot,
1235
+ metadata,
1236
+ recipes,
1237
+ operations,
1238
+ });
1436
1239
 
1437
1240
  const source = inspectPmStudioApp({ appPath, recipe, operations });
1438
1241
  const finalBackupDir = path.join(backupRoot, backupName(recipe));
@@ -1456,12 +1259,6 @@ export async function runPmStudioSetup({
1456
1259
  `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);
1457
1260
  }
1458
1261
 
1459
- if (source.sourceVerification === "exact-bundle-content") {
1460
- emit(recipe.sourceArtifact
1461
- ? `[WARN] macOS rejected the vendor signature; setup accepted PM Studio ${recipe.version} only after its files matched the SHA-256-verified official GitHub release.`
1462
- : `[WARN] macOS rejected the vendor signature; setup accepted only the exact PM Studio ${recipe.version} official bundle content fingerprint.`);
1463
- }
1464
-
1465
1262
  const backupExists = fs.existsSync(finalBackupDir);
1466
1263
  let verifiedBackup = null;
1467
1264
  if (migratingExistingPatch) {
@@ -1482,7 +1279,7 @@ export async function runPmStudioSetup({
1482
1279
  }
1483
1280
  assertSpace({ appPath, backupRoot, backupExists, operations });
1484
1281
 
1485
- emit("[WARN] PM Studio's vendor signature will be replaced with an ad-hoc signature; an official update or reinstall may overwrite this patch.");
1282
+ emit("[WARN] PM Studio will be ad-hoc signed after patching; an update or reinstall may overwrite this patch.");
1486
1283
  const backup = verifiedBackup || ensureBackup({ appPath, backupRoot, recipe, operations });
1487
1284
  const stagePath = path.join(path.dirname(appPath), `.${path.basename(appPath)}.ccdx-stage-${operations.uuid()}`);
1488
1285
  let preserveStage = false;
@@ -1509,7 +1306,12 @@ export async function runPmStudioSetup({
1509
1306
  hash: recipe.patchedHeaderSha256,
1510
1307
  processRunner: operations.processRunner,
1511
1308
  });
1512
- operations.signApp({ appPath: stagePath, recipe, processRunner: operations.processRunner });
1309
+ operations.signApp({
1310
+ appPath: stagePath,
1311
+ recipe,
1312
+ source: stagedSource,
1313
+ processRunner: operations.processRunner,
1314
+ });
1513
1315
 
1514
1316
  const staged = inspectPmStudioApp({ appPath: stagePath, recipe, operations });
1515
1317
  if (staged.state !== "patched") {