@lesliechan721/aw 0.1.0-beta.12 → 0.1.0-beta.14

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.
Files changed (72) hide show
  1. package/dist/src/commands/catalog-dev-source.d.ts +31 -0
  2. package/dist/src/commands/catalog-dev-source.js +165 -5
  3. package/dist/src/commands/catalog-dev-source.js.map +1 -1
  4. package/dist/src/commands/catalog-generation.d.ts +5 -0
  5. package/dist/src/commands/catalog-generation.js.map +1 -1
  6. package/dist/src/commands/catalog-publication-journal.d.ts +12 -0
  7. package/dist/src/commands/catalog-publication-journal.js +77 -0
  8. package/dist/src/commands/catalog-publication-journal.js.map +1 -1
  9. package/dist/src/commands/catalog-store.d.ts +5 -0
  10. package/dist/src/commands/catalog-store.js +19 -1
  11. package/dist/src/commands/catalog-store.js.map +1 -1
  12. package/dist/src/commands/dependency-operation-plan.d.ts +7 -0
  13. package/dist/src/commands/dependency-operation-plan.js +63 -27
  14. package/dist/src/commands/dependency-operation-plan.js.map +1 -1
  15. package/dist/src/commands/rebuild-command.d.ts +22 -8
  16. package/dist/src/commands/rebuild-command.js +562 -250
  17. package/dist/src/commands/rebuild-command.js.map +1 -1
  18. package/dist/src/commands/rebuild-integration.js +188 -67
  19. package/dist/src/commands/rebuild-integration.js.map +1 -1
  20. package/dist/src/commands/reconcile-operation-plan.d.ts +11 -9
  21. package/dist/src/commands/reconcile-operation-plan.js +25 -6
  22. package/dist/src/commands/reconcile-operation-plan.js.map +1 -1
  23. package/dist/src/commands/status-v6.js +2 -2
  24. package/dist/src/commands/status-v6.js.map +1 -1
  25. package/dist/src/commands/write-commands.d.ts +2 -1
  26. package/dist/src/commands/write-commands.js +24 -1
  27. package/dist/src/commands/write-commands.js.map +1 -1
  28. package/dist/src/tui/catalog-management-screens.d.ts +45 -0
  29. package/dist/src/tui/catalog-management-screens.js +25 -0
  30. package/dist/src/tui/catalog-management-screens.js.map +1 -0
  31. package/dist/src/tui/catalog-management.d.ts +240 -0
  32. package/dist/src/tui/catalog-management.js +856 -0
  33. package/dist/src/tui/catalog-management.js.map +1 -0
  34. package/dist/src/tui/catalog-sources/session.d.ts +5 -0
  35. package/dist/src/tui/catalog-sources/session.js +49 -1
  36. package/dist/src/tui/catalog-sources/session.js.map +1 -1
  37. package/dist/src/tui/catalog-sources/types.d.ts +11 -0
  38. package/dist/src/tui/console-app-v4.d.ts +1 -1
  39. package/dist/src/tui/console-app-v4.js +2184 -564
  40. package/dist/src/tui/console-app-v4.js.map +1 -1
  41. package/dist/src/tui/controller-runtime.js +609 -13
  42. package/dist/src/tui/controller-runtime.js.map +1 -1
  43. package/dist/src/tui/controller.d.ts +121 -6
  44. package/dist/src/tui/controller.js +667 -17
  45. package/dist/src/tui/controller.js.map +1 -1
  46. package/dist/src/tui/dependency-graph.d.ts +67 -0
  47. package/dist/src/tui/dependency-graph.js +399 -0
  48. package/dist/src/tui/dependency-graph.js.map +1 -0
  49. package/dist/src/tui/lifecycle-action-view.js +4 -2
  50. package/dist/src/tui/lifecycle-action-view.js.map +1 -1
  51. package/dist/src/tui/model.d.ts +37 -0
  52. package/dist/src/tui/model.js +179 -17
  53. package/dist/src/tui/model.js.map +1 -1
  54. package/dist/src/tui/operation-review-planner.js +244 -8
  55. package/dist/src/tui/operation-review-planner.js.map +1 -1
  56. package/dist/src/tui/plugin-write-task.d.ts +66 -0
  57. package/dist/src/tui/plugin-write-task.js +265 -0
  58. package/dist/src/tui/plugin-write-task.js.map +1 -0
  59. package/dist/src/tui/router.d.ts +38 -2
  60. package/dist/src/tui/router.js.map +1 -1
  61. package/dist/src/tui/screen-registry.d.ts +105 -6
  62. package/dist/src/tui/screen-registry.js +31 -4
  63. package/dist/src/tui/screen-registry.js.map +1 -1
  64. package/dist/src/utils/catalog-generation-service.d.ts +4 -0
  65. package/dist/src/utils/catalog-generation-service.js.map +1 -1
  66. package/dist/src/utils/codex-shared-native.d.ts +4 -0
  67. package/dist/src/utils/codex-shared-native.js +13 -0
  68. package/dist/src/utils/codex-shared-native.js.map +1 -1
  69. package/dist/src/utils/local-marketplace.d.ts +14 -1
  70. package/dist/src/utils/local-marketplace.js +242 -14
  71. package/dist/src/utils/local-marketplace.js.map +1 -1
  72. package/package.json +3 -3
@@ -15,14 +15,14 @@ import { OWNED_TEXT_HEADER_PREFIX, createSharedOwnerToken, createSkillOwnerMarke
15
15
  import { resolveArtifactRenderConfig, resolveArtifactRendererTarget, runArtifactRenderer, } from '../utils/artifact-renderer.js';
16
16
  import { createArtifactConfigDigest, validateArtifactPlan, } from '../utils/artifact-plan.js';
17
17
  import { resolveAwDeliveredArtifactRequestBatches } from '../utils/artifact-request.js';
18
- import { createAwPluginRequirementsReceipt, parseAwPluginRequirementsReceipt, } from '../utils/manifest.js';
18
+ import { createAwPluginRequirementsReceipt, parseAwPluginRequirementsReceipt, tryParseStrictSemVer, } from '../utils/manifest.js';
19
19
  import { resolvePlatformEntries } from '../utils/platform-entries.js';
20
20
  import { resolveAwHome, resolveClaudePaths, resolveCodexPaths, resolveRepoRoot, getCodexHome, } from '../utils/paths.js';
21
21
  import { assertNoSensitiveConfigInFiles, collectSensitivePluginConfigValues, runPreApplyScript, } from '../utils/plugin-scripts.js';
22
22
  import { findSensitiveTokenPath } from '../utils/sensitive-content.js';
23
23
  import { atomicRemoveConfigFile, atomicReplaceConfigFile, withConfigFileMutation, } from '../utils/plugin-config.js';
24
24
  import { readCatalogSourcesConfigSnapshot } from '../utils/catalog-sources.js';
25
- import { getNamespacedMarketplaceName, projectMarketplaceManifestForPlatform, readStrictNamespacedMarketplaceRoot, replayNamespacedCodexSkillOverlays, } from '../utils/local-marketplace.js';
25
+ import { getNamespacedMarketplaceName, MarketplaceRootValidationError, projectMarketplaceManifestForPlatform, readStrictNamespacedMarketplaceRoot, replayNamespacedCodexNativeRenderProjections, replayNamespacedCodexSkillOverlays, } from '../utils/local-marketplace.js';
26
26
  import { commitMarketplaceGenerationBackup } from '../utils/orphan-marketplace-cleanup.js';
27
27
  import { readClaudeSettings, writeClaudeSettings } from '../adapters/helpers.js';
28
28
  import { analyzeCodexSurface } from '../utils/codex-surface-analysis.js';
@@ -1813,6 +1813,8 @@ async function codexPayloadPathSafe(payloadRoot, allowedRoot = payloadRoot) {
1813
1813
  }
1814
1814
  return true;
1815
1815
  }
1816
+ class CodexNativeProjectionUnsafeError extends Error {
1817
+ }
1816
1818
  async function resolveCodexSkillsRoot(payloadRoot, rawSkillsRoot) {
1817
1819
  const normalizedSeparators = rawSkillsRoot.replace(/\\/gu, '/');
1818
1820
  const relativeRoot = path.posix.normalize(normalizedSeparators.replace(/^\.\//u, ''));
@@ -1822,11 +1824,11 @@ async function resolveCodexSkillsRoot(payloadRoot, rawSkillsRoot) {
1822
1824
  || relativeRoot.startsWith('../')
1823
1825
  || path.posix.isAbsolute(normalizedSeparators)
1824
1826
  || path.win32.isAbsolute(rawSkillsRoot)) {
1825
- throw new Error('codexNativeSkillsRootInvalid: Codex native Skills root is invalid.');
1827
+ throw new CodexNativeProjectionUnsafeError('codexNativeSkillsRootInvalid: Codex native Skills root is invalid.');
1826
1828
  }
1827
1829
  const root = path.join(payloadRoot, ...relativeRoot.split('/'));
1828
1830
  if (!await codexReadPathSafe(payloadRoot, root)) {
1829
- throw new Error('codexNativeSkillsRootInvalid: Codex native Skills root is unsafe.');
1831
+ throw new CodexNativeProjectionUnsafeError('codexNativeSkillsRootInvalid: Codex native Skills root is unsafe.');
1830
1832
  }
1831
1833
  return { relativeRoot, root };
1832
1834
  }
@@ -1842,16 +1844,45 @@ async function readCodexNativeRenderReceiptEvidence(payloadRoot) {
1842
1844
  return { state: 'absent' };
1843
1845
  if (!stats.isFile() || stats.isSymbolicLink())
1844
1846
  return { state: 'unsafe' };
1847
+ let content;
1845
1848
  try {
1846
- return {
1847
- state: 'present',
1848
- receipt: parseCodexNativeRenderReceipt(await fs.readFile(receiptPath, 'utf8')),
1849
- };
1849
+ content = await fs.readFile(receiptPath, 'utf8');
1850
+ }
1851
+ catch {
1852
+ return { state: 'unreadable' };
1853
+ }
1854
+ try {
1855
+ return { state: 'present', receipt: parseCodexNativeRenderReceipt(content) };
1850
1856
  }
1851
1857
  catch {
1852
1858
  return { state: 'invalid' };
1853
1859
  }
1854
1860
  }
1861
+ function codexNativeRenderEvidenceIssue(reason, diagnostic) {
1862
+ return { state: 'issue', reason, diagnostic };
1863
+ }
1864
+ async function readCodexNativeProjectionManifest(manifestPath) {
1865
+ let stats;
1866
+ try {
1867
+ stats = await lstatIfPresent(manifestPath);
1868
+ }
1869
+ catch {
1870
+ return { state: 'unreadable' };
1871
+ }
1872
+ if (!stats)
1873
+ return { state: 'missing' };
1874
+ if (!stats.isFile() || stats.isSymbolicLink())
1875
+ return { state: 'unsafe' };
1876
+ try {
1877
+ const value = await fs.readJson(manifestPath);
1878
+ return typeof value === 'object' && value !== null && !Array.isArray(value)
1879
+ ? { state: 'present', value: value }
1880
+ : { state: 'invalid' };
1881
+ }
1882
+ catch (error) {
1883
+ return { state: error instanceof SyntaxError ? 'invalid' : 'unreadable' };
1884
+ }
1885
+ }
1855
1886
  async function resolveCodexNativeRenderExpectedEvidence(options) {
1856
1887
  const logicalPluginId = options.plugin.pluginId
1857
1888
  ?? (options.plugin.sourceId ? `${options.plugin.sourceId}/${options.plugin.manifest.name}` : undefined);
@@ -1861,54 +1892,101 @@ async function resolveCodexNativeRenderExpectedEvidence(options) {
1861
1892
  const marketplace = await readStrictNamespacedMarketplaceRoot({
1862
1893
  trustedMarketplaceRoot: path.join(resolveAwHome(options.env), 'marketplaces'),
1863
1894
  rootDir: options.marketplaceRoot,
1864
- sourceId: options.plugin.sourceId,
1865
- marketplaceName: options.marketplaceName,
1866
1895
  });
1867
1896
  if (!marketplace) {
1868
- throw new Error('Codex native render canonical marketplace generation is missing.');
1897
+ return codexNativeRenderEvidenceIssue('damaged', 'projectionReceiptMissing');
1869
1898
  }
1870
- if (marketplace.config.sourceIdentity !== options.plugin.sourceIdentity) {
1871
- return { state: 'foreign' };
1899
+ if (marketplace.config.sourceId !== options.plugin.sourceId
1900
+ || marketplace.config.sourceIdentity !== options.plugin.sourceIdentity
1901
+ || marketplace.config.marketplaceName !== options.marketplaceName) {
1902
+ return codexNativeRenderEvidenceIssue('foreign', 'projectionReceiptIdentityMismatch');
1872
1903
  }
1873
1904
  const payloadRoot = path.join(options.marketplaceRoot, 'plugins', options.plugin.manifest.name);
1874
- if (!await codexPayloadPathSafe(payloadRoot, options.marketplaceRoot)) {
1875
- throw new Error('Codex native render canonical marketplace payload path is unsafe.');
1876
- }
1877
- const receiptEvidence = await readCodexNativeRenderReceiptEvidence(payloadRoot);
1878
- if (receiptEvidence.state !== 'present') {
1879
- throw new Error('Codex native render canonical marketplace receipt is missing or unreadable.');
1905
+ const payloadStats = await lstatIfPresent(payloadRoot);
1906
+ if (!payloadStats) {
1907
+ return codexNativeRenderEvidenceIssue('damaged', 'projectionReceiptMissing');
1880
1908
  }
1881
- const receipt = receiptEvidence.receipt;
1882
- if (receipt.logicalPluginId !== logicalPluginId
1883
- || receipt.strategy !== 'shared-user'
1884
- || receipt.sourceIdentity !== marketplace.config.sourceIdentity) {
1885
- throw new Error('Codex native render canonical marketplace receipt identity is invalid.');
1909
+ if (!payloadStats.isDirectory() || payloadStats.isSymbolicLink()) {
1910
+ return codexNativeRenderEvidenceIssue('foreign', 'payloadPathUnsafe');
1886
1911
  }
1887
- const payloadDigest = await calculateCodexNativeRenderPayloadDigest(payloadRoot);
1888
- if (payloadDigest !== receipt.payloadDigest) {
1889
- throw new Error('Codex native render canonical marketplace payload does not match its receipt.');
1890
- }
1891
- const sourceManifestPath = path.join(payloadRoot, '.agents-plugin', 'plugin.json');
1892
- const sourceManifestStats = await lstatIfPresent(sourceManifestPath);
1893
- const sourceManifest = sourceManifestStats?.isFile() && !sourceManifestStats.isSymbolicLink()
1894
- ? await fs.readJson(sourceManifestPath).catch(() => null)
1895
- : null;
1896
- if (sourceManifest?.name !== options.plugin.manifest.name
1897
- || sourceManifest.version !== receipt.pluginVersion) {
1898
- throw new Error('Codex native render canonical marketplace plugin identity is invalid.');
1912
+ if (!await codexPayloadPathSafe(payloadRoot, options.marketplaceRoot)) {
1913
+ return codexNativeRenderEvidenceIssue('foreign', 'payloadPathUnsafe');
1899
1914
  }
1900
1915
  const codexManifestPath = path.join(payloadRoot, '.codex-plugin', 'plugin.json');
1901
- const codexManifestStats = await lstatIfPresent(codexManifestPath);
1902
- const codexManifest = codexManifestStats?.isFile() && !codexManifestStats.isSymbolicLink()
1903
- ? await fs.readJson(codexManifestPath).catch(() => null)
1904
- : null;
1905
- if (!codexManifest) {
1906
- throw new Error('Codex native render canonical marketplace manifest is invalid.');
1916
+ const [sourceManifestEvidence, codexManifestEvidence] = await Promise.all([
1917
+ readCodexNativeProjectionManifest(path.join(payloadRoot, '.agents-plugin', 'plugin.json')),
1918
+ readCodexNativeProjectionManifest(codexManifestPath),
1919
+ ]);
1920
+ if (sourceManifestEvidence.state === 'unsafe'
1921
+ || codexManifestEvidence.state === 'unsafe') {
1922
+ return codexNativeRenderEvidenceIssue('foreign', 'payloadPathUnsafe');
1923
+ }
1924
+ if ((sourceManifestEvidence.state === 'present'
1925
+ && sourceManifestEvidence.value.name !== options.plugin.manifest.name)
1926
+ || (codexManifestEvidence.state === 'present'
1927
+ && codexManifestEvidence.value.name !== options.plugin.manifest.name)
1928
+ || (sourceManifestEvidence.state === 'present'
1929
+ && codexManifestEvidence.state === 'present'
1930
+ && sourceManifestEvidence.value.version !== codexManifestEvidence.value.version)) {
1931
+ return codexNativeRenderEvidenceIssue('foreign', 'manifestIdentityMismatch');
1932
+ }
1933
+ if (sourceManifestEvidence.state === 'unreadable'
1934
+ || codexManifestEvidence.state === 'unreadable') {
1935
+ return codexNativeRenderEvidenceIssue('unreadable', 'manifestUnreadable');
1936
+ }
1937
+ if (sourceManifestEvidence.state === 'missing'
1938
+ || codexManifestEvidence.state === 'missing') {
1939
+ return codexNativeRenderEvidenceIssue('damaged', 'manifestMissing');
1940
+ }
1941
+ if (sourceManifestEvidence.state === 'invalid'
1942
+ || codexManifestEvidence.state === 'invalid') {
1943
+ return codexNativeRenderEvidenceIssue('damaged', 'manifestUnreadable');
1944
+ }
1945
+ if (sourceManifestEvidence.state !== 'present'
1946
+ || codexManifestEvidence.state !== 'present') {
1947
+ return codexNativeRenderEvidenceIssue('damaged', 'manifestUnreadable');
1948
+ }
1949
+ const sourceManifest = sourceManifestEvidence.value;
1950
+ const codexManifest = codexManifestEvidence.value;
1951
+ if (typeof sourceManifest.version !== 'string'
1952
+ || !tryParseStrictSemVer(sourceManifest.version)) {
1953
+ return codexNativeRenderEvidenceIssue('damaged', 'manifestVersionInvalid');
1907
1954
  }
1908
1955
  const rawSkillsRoot = typeof codexManifest.skills === 'string' && codexManifest.skills.trim() !== ''
1909
1956
  ? codexManifest.skills
1910
1957
  : './codex/skills';
1911
1958
  const { relativeRoot: skillsRelativeRoot } = await resolveCodexSkillsRoot(payloadRoot, rawSkillsRoot);
1959
+ const skillsRoot = path.join(payloadRoot, ...skillsRelativeRoot.split('/'));
1960
+ const skillsRootStats = await lstatIfPresent(skillsRoot);
1961
+ if (skillsRootStats && (!skillsRootStats.isDirectory() || skillsRootStats.isSymbolicLink())) {
1962
+ return codexNativeRenderEvidenceIssue('foreign', 'payloadPathUnsafe');
1963
+ }
1964
+ const targets = codexNativeRenderTargets(options.plugin);
1965
+ for (const target of targets) {
1966
+ if (await lstatIfPresent(path.join(skillsRoot, target.skillKey, '.agent-workflows-owner.json'))) {
1967
+ return codexNativeRenderEvidenceIssue('foreign', 'payloadPathUnsafe');
1968
+ }
1969
+ }
1970
+ const receiptEvidence = await readCodexNativeRenderReceiptEvidence(payloadRoot);
1971
+ if (receiptEvidence.state === 'absent') {
1972
+ return codexNativeRenderEvidenceIssue('damaged', 'projectionReceiptMissing');
1973
+ }
1974
+ if (receiptEvidence.state === 'unsafe') {
1975
+ return codexNativeRenderEvidenceIssue('foreign', 'payloadPathUnsafe');
1976
+ }
1977
+ if (receiptEvidence.state === 'invalid') {
1978
+ return codexNativeRenderEvidenceIssue('damaged', 'projectionReceiptUnreadable');
1979
+ }
1980
+ if (receiptEvidence.state === 'unreadable') {
1981
+ return codexNativeRenderEvidenceIssue('unreadable', 'projectionReceiptUnreadable');
1982
+ }
1983
+ const receipt = receiptEvidence.receipt;
1984
+ if (receipt.logicalPluginId !== logicalPluginId
1985
+ || receipt.strategy !== 'shared-user'
1986
+ || receipt.sourceIdentity !== marketplace.config.sourceIdentity
1987
+ || receipt.pluginVersion !== sourceManifest.version) {
1988
+ return codexNativeRenderEvidenceIssue('foreign', 'projectionReceiptIdentityMismatch');
1989
+ }
1912
1990
  const emptyArtifactDigest = createCodexSkillStagingTreeContentDigest({
1913
1991
  skillKey: 'empty',
1914
1992
  files: {},
@@ -1916,17 +1994,32 @@ async function resolveCodexNativeRenderExpectedEvidence(options) {
1916
1994
  for (const receiptTarget of receipt.targets) {
1917
1995
  const skillRoot = path.join(payloadRoot, ...skillsRelativeRoot.split('/'), receiptTarget.skillKey);
1918
1996
  if (await lstatIfPresent(path.join(skillRoot, '.agent-workflows-owner.json'))) {
1919
- throw new Error('Codex native render canonical marketplace Skill has an AW owner marker.');
1997
+ return codexNativeRenderEvidenceIssue('foreign', 'payloadPathUnsafe');
1998
+ }
1999
+ const skillStats = await lstatIfPresent(skillRoot);
2000
+ if (skillStats && (!skillStats.isDirectory() || skillStats.isSymbolicLink())) {
2001
+ return codexNativeRenderEvidenceIssue('foreign', 'payloadPathUnsafe');
2002
+ }
2003
+ let tree;
2004
+ try {
2005
+ tree = skillStats ? await readDynamicSkillTree(skillRoot, 'codex.skill') : null;
2006
+ }
2007
+ catch (error) {
2008
+ return codexNativeRenderEvidenceIssue(error instanceof Error && typeof error.code !== 'string'
2009
+ ? 'damaged'
2010
+ : 'unreadable', 'projectionPayloadDigestMismatch');
1920
2011
  }
1921
- const tree = await readDynamicSkillTree(skillRoot, 'codex.skill');
1922
2012
  const artifactDigest = tree
1923
2013
  ? createCodexSkillStagingTreeContentDigest(tree)
1924
2014
  : emptyArtifactDigest;
1925
2015
  if (artifactDigest !== receiptTarget.artifactDigest) {
1926
- throw new Error('Codex native render canonical marketplace Skill does not match its receipt.');
2016
+ return codexNativeRenderEvidenceIssue('damaged', 'projectionPayloadDigestMismatch');
1927
2017
  }
1928
2018
  }
1929
- const targets = codexNativeRenderTargets(options.plugin);
2019
+ const payloadDigest = await calculateCodexNativeRenderPayloadDigest(payloadRoot);
2020
+ if (payloadDigest !== receipt.payloadDigest) {
2021
+ return codexNativeRenderEvidenceIssue('damaged', 'projectionPayloadDigestMismatch');
2022
+ }
1930
2023
  const receiptTargets = new Map(receipt.targets.map((target) => [target.id, target]));
1931
2024
  if (targets.length === 0
1932
2025
  || targets.length !== receipt.targets.length
@@ -2105,7 +2198,7 @@ export async function inspectCodexSharedNativeLive(options) {
2105
2198
  });
2106
2199
  let expectedPayloadDigest = dynamicProjectionExpected ? undefined : options.expectedPayloadDigest;
2107
2200
  let sourceProjection;
2108
- let expectedMarketplaceForeign = false;
2201
+ let sourceProjectionIssue;
2109
2202
  const installed = pluginList.observation.state === 'observed'
2110
2203
  && pluginList.observation.value === 'installed';
2111
2204
  if (installed && dynamicProjectionExpected && options.nativeRenderPlugin) {
@@ -2116,32 +2209,48 @@ export async function inspectCodexSharedNativeLive(options) {
2116
2209
  marketplaceName,
2117
2210
  env: options.env,
2118
2211
  });
2119
- if (expected.state === 'foreign') {
2120
- expectedMarketplaceForeign = true;
2212
+ if (expected.state === 'issue') {
2213
+ sourceProjectionIssue = expected;
2121
2214
  }
2122
2215
  else {
2123
2216
  expectedPayloadDigest = expected.payloadDigest;
2124
2217
  sourceProjection = expected.sourceProjection;
2125
2218
  }
2126
2219
  }
2127
- catch {
2128
- sourceProjection = 'drifted';
2220
+ catch (error) {
2221
+ if (error instanceof MarketplaceRootValidationError) {
2222
+ sourceProjectionIssue = {
2223
+ reason: error.reason === 'unsafe'
2224
+ ? 'foreign'
2225
+ : error.reason === 'invalid' ? 'damaged' : 'unreadable',
2226
+ diagnostic: error.reason === 'unsafe'
2227
+ ? 'payloadPathUnsafe'
2228
+ : 'projectionReceiptUnreadable',
2229
+ };
2230
+ }
2231
+ else {
2232
+ sourceProjectionIssue = {
2233
+ reason: error instanceof CodexNativeProjectionUnsafeError ? 'foreign' : 'unreadable',
2234
+ diagnostic: error instanceof CodexNativeProjectionUnsafeError
2235
+ ? 'payloadPathUnsafe'
2236
+ : 'projectionReceiptUnreadable',
2237
+ };
2238
+ }
2129
2239
  }
2130
2240
  }
2131
- const sharedNative = expectedMarketplaceForeign
2132
- ? { state: 'blocked', reason: 'foreign', diagnostic: 'marketplaceRegistrationForeign' }
2133
- : inspectCodexSharedNative({
2134
- pluginName: options.pluginName,
2135
- pluginId,
2136
- marketplaceName,
2137
- canonicalMarketplaceRoot: marketplaceRoot,
2138
- desiredVersion: options.desiredVersion,
2139
- expectedPayloadDigest,
2140
- marketplaceRegistration: config.snapshot.marketplaces[marketplaceName],
2141
- marketplacePathSafe,
2142
- observation: pluginList.observation,
2143
- ...(sourceProjection ? { sourceProjection } : {}),
2144
- });
2241
+ const sharedNative = inspectCodexSharedNative({
2242
+ pluginName: options.pluginName,
2243
+ pluginId,
2244
+ marketplaceName,
2245
+ canonicalMarketplaceRoot: marketplaceRoot,
2246
+ desiredVersion: options.desiredVersion,
2247
+ expectedPayloadDigest,
2248
+ marketplaceRegistration: config.snapshot.marketplaces[marketplaceName],
2249
+ marketplacePathSafe,
2250
+ observation: pluginList.observation,
2251
+ ...(sourceProjection ? { sourceProjection } : {}),
2252
+ ...(sourceProjectionIssue ? { sourceProjectionIssue } : {}),
2253
+ });
2145
2254
  return {
2146
2255
  sharedNative,
2147
2256
  ...(expectedPayloadDigest ? { expectedPayloadDigest } : {}),
@@ -2762,7 +2871,7 @@ async function materializeCodexNativeRender(options) {
2762
2871
  targetSkillKeys: options.prepared.targetSkillKeys,
2763
2872
  };
2764
2873
  }
2765
- async function mirrorCatalog(catalog, env, target, logicalIdentity, prepareStaging) {
2874
+ async function mirrorCatalog(catalog, env, target, logicalIdentity, prepareStaging, rematerializedCodexNativePluginIds = new Set()) {
2766
2875
  if (!target?.sourceId || !target.marketplaceRoot) {
2767
2876
  const rootDir = resolveAwHome(env);
2768
2877
  await fs.ensureDir(rootDir);
@@ -2826,6 +2935,14 @@ async function mirrorCatalog(catalog, env, target, logicalIdentity, prepareStagi
2826
2935
  sourceIdentity: target.sourceIdentity,
2827
2936
  marketplaceName,
2828
2937
  });
2938
+ await replayNamespacedCodexNativeRenderProjections({
2939
+ sourceRoot: destination,
2940
+ stagingRoot: staging,
2941
+ sourceId: target.sourceId,
2942
+ sourceIdentity: target.sourceIdentity,
2943
+ marketplaceName,
2944
+ rematerializedPluginIds: rematerializedCodexNativePluginIds,
2945
+ });
2829
2946
  }
2830
2947
  await prepareStaging?.(staging);
2831
2948
  const backup = `${destination}.backup-${crypto.randomUUID()}`;
@@ -3154,7 +3271,11 @@ function createNativeDriver(options) {
3154
3271
  });
3155
3272
  }
3156
3273
  }
3157
- } : undefined);
3274
+ } : undefined, new Set(first.identity.platform === 'codex'
3275
+ ? materializationTargets.flatMap((candidate) => pluginHasCodexNativeSkillSurface(candidate.plugin)
3276
+ ? [candidate.identity.pluginId ?? `${candidate.identity.sourceId}/${candidate.identity.pluginName}`]
3277
+ : [])
3278
+ : []));
3158
3279
  try {
3159
3280
  await transaction.commit();
3160
3281
  }