@lesliechan721/aw 0.1.0-beta.8 → 0.1.0-beta.9

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 (275) hide show
  1. package/dist/authoring/scripts/add-skill.mjs +4 -4
  2. package/dist/authoring/scripts/add-skill.mjs.map +1 -1
  3. package/dist/authoring/scripts/init-plugin.mjs +4 -4
  4. package/dist/authoring/scripts/init-plugin.mjs.map +1 -1
  5. package/dist/authoring/scripts/lib/plugin-version-check.mjs +1 -1
  6. package/dist/authoring/scripts/lib/skill-scaffold.d.mts +77 -90
  7. package/dist/authoring/scripts/lib/skill-scaffold.mjs +99 -120
  8. package/dist/authoring/scripts/lib/skill-scaffold.mjs.map +1 -1
  9. package/dist/authoring/scripts/remove-plugin.mjs +1 -1
  10. package/dist/authoring/scripts/remove-plugin.mjs.map +1 -1
  11. package/dist/authoring/scripts/validate-plugin.mjs +34 -778
  12. package/dist/authoring/scripts/validate-plugin.mjs.map +1 -1
  13. package/dist/scripts/aw-skill-eval-materializer.d.ts +24 -0
  14. package/dist/scripts/{plugin-eval-materializer.js → aw-skill-eval-materializer.js} +34 -145
  15. package/dist/scripts/aw-skill-eval-materializer.js.map +1 -0
  16. package/dist/scripts/bundle-plugins.d.ts +1 -0
  17. package/dist/scripts/bundle-plugins.js +2 -1
  18. package/dist/scripts/bundle-plugins.js.map +1 -1
  19. package/dist/scripts/plugin-staging.d.ts +5 -6
  20. package/dist/scripts/plugin-staging.js +12 -13
  21. package/dist/scripts/plugin-staging.js.map +1 -1
  22. package/dist/src/authoring/workspace-commands.d.ts +2 -1
  23. package/dist/src/authoring/workspace-commands.js.map +1 -1
  24. package/dist/src/commands/aw-capabilities.d.ts +2 -2
  25. package/dist/src/commands/aw-capabilities.js +6 -11
  26. package/dist/src/commands/aw-capabilities.js.map +1 -1
  27. package/dist/src/commands/catalog-dev-source.d.ts +18 -12
  28. package/dist/src/commands/catalog-dev-source.js +241 -305
  29. package/dist/src/commands/catalog-dev-source.js.map +1 -1
  30. package/dist/src/commands/catalog-generation.d.ts +6 -19
  31. package/dist/src/commands/catalog-generation.js +10 -11
  32. package/dist/src/commands/catalog-generation.js.map +1 -1
  33. package/dist/src/commands/catalog-publication-inspection.d.ts +28 -27
  34. package/dist/src/commands/catalog-publication-inspection.js +139 -50
  35. package/dist/src/commands/catalog-publication-inspection.js.map +1 -1
  36. package/dist/src/commands/catalog-publication-journal.d.ts +49 -0
  37. package/dist/src/commands/catalog-publication-journal.js +147 -0
  38. package/dist/src/commands/catalog-publication-journal.js.map +1 -0
  39. package/dist/src/commands/catalog-publication-target.d.ts +2 -1
  40. package/dist/src/commands/catalog-publication-target.js +37 -2
  41. package/dist/src/commands/catalog-publication-target.js.map +1 -1
  42. package/dist/src/commands/catalog-publish.d.ts +51 -15
  43. package/dist/src/commands/catalog-publish.js +576 -219
  44. package/dist/src/commands/catalog-publish.js.map +1 -1
  45. package/dist/src/commands/catalog-source.d.ts +3 -28
  46. package/dist/src/commands/catalog-source.js +29 -140
  47. package/dist/src/commands/catalog-source.js.map +1 -1
  48. package/dist/src/commands/catalog-status.d.ts +6 -26
  49. package/dist/src/commands/catalog-status.js +8 -146
  50. package/dist/src/commands/catalog-status.js.map +1 -1
  51. package/dist/src/commands/catalog-workspace-resolution.d.ts +13 -0
  52. package/dist/src/commands/catalog-workspace-resolution.js +42 -0
  53. package/dist/src/commands/catalog-workspace-resolution.js.map +1 -0
  54. package/dist/src/commands/dependency-operation-plan.d.ts +88 -9
  55. package/dist/src/commands/dependency-operation-plan.js +331 -6
  56. package/dist/src/commands/dependency-operation-plan.js.map +1 -1
  57. package/dist/src/commands/init.d.ts +5 -11
  58. package/dist/src/commands/init.js +30 -51
  59. package/dist/src/commands/init.js.map +1 -1
  60. package/dist/src/commands/offline-cleanup-evidence.d.ts +20 -0
  61. package/dist/src/commands/offline-cleanup-evidence.js +87 -9
  62. package/dist/src/commands/offline-cleanup-evidence.js.map +1 -1
  63. package/dist/src/commands/options.d.ts +6 -1
  64. package/dist/src/commands/options.js +64 -6
  65. package/dist/src/commands/options.js.map +1 -1
  66. package/dist/src/commands/plugin-capabilities.js +4 -0
  67. package/dist/src/commands/plugin-capabilities.js.map +1 -1
  68. package/dist/src/commands/rebuild-command.d.ts +10 -8
  69. package/dist/src/commands/rebuild-command.js +1217 -426
  70. package/dist/src/commands/rebuild-command.js.map +1 -1
  71. package/dist/src/commands/rebuild-integration.d.ts +54 -6
  72. package/dist/src/commands/rebuild-integration.js +691 -364
  73. package/dist/src/commands/rebuild-integration.js.map +1 -1
  74. package/dist/src/commands/rebuild-operations.d.ts +2 -0
  75. package/dist/src/commands/rebuild-operations.js +31 -17
  76. package/dist/src/commands/rebuild-operations.js.map +1 -1
  77. package/dist/src/commands/skill-eval.d.ts +33 -0
  78. package/dist/src/commands/skill-eval.js +363 -0
  79. package/dist/src/commands/skill-eval.js.map +1 -0
  80. package/dist/src/commands/{status-v5.d.ts → status-v6.d.ts} +59 -26
  81. package/dist/src/commands/{status-v5.js → status-v6.js} +882 -79
  82. package/dist/src/commands/status-v6.js.map +1 -0
  83. package/dist/src/commands/sync-command.d.ts +21 -0
  84. package/dist/src/commands/sync-command.js +206 -0
  85. package/dist/src/commands/sync-command.js.map +1 -0
  86. package/dist/src/commands/wizard.d.ts +2 -2
  87. package/dist/src/commands/write-commands.js +1 -43
  88. package/dist/src/commands/write-commands.js.map +1 -1
  89. package/dist/src/constants.d.ts +5 -4
  90. package/dist/src/constants.js +5 -4
  91. package/dist/src/constants.js.map +1 -1
  92. package/dist/src/eval/manifest-v1.d.ts +66 -0
  93. package/dist/src/eval/manifest-v1.js +326 -0
  94. package/dist/src/eval/manifest-v1.js.map +1 -0
  95. package/dist/src/generators/local-plugin.d.ts +3 -0
  96. package/dist/src/generators/local-plugin.js +123 -55
  97. package/dist/src/generators/local-plugin.js.map +1 -1
  98. package/dist/src/index.d.ts +2 -0
  99. package/dist/src/index.js +412 -152
  100. package/dist/src/index.js.map +1 -1
  101. package/dist/src/output/command-receipt.d.ts +58 -8
  102. package/dist/src/output/command-receipt.js +141 -11
  103. package/dist/src/output/command-receipt.js.map +1 -1
  104. package/dist/src/output/model.d.ts +3 -11
  105. package/dist/src/portable/commands.d.ts +2 -2
  106. package/dist/src/portable/commands.js +2 -8
  107. package/dist/src/portable/commands.js.map +1 -1
  108. package/dist/src/portable/materializer.d.ts +1 -4
  109. package/dist/src/portable/materializer.js +0 -2
  110. package/dist/src/portable/materializer.js.map +1 -1
  111. package/dist/src/tui/catalog-generation.d.ts +20 -41
  112. package/dist/src/tui/catalog-generation.js +65 -224
  113. package/dist/src/tui/catalog-generation.js.map +1 -1
  114. package/dist/src/tui/components.js +1 -2
  115. package/dist/src/tui/components.js.map +1 -1
  116. package/dist/src/tui/console-app-v4.js +461 -330
  117. package/dist/src/tui/console-app-v4.js.map +1 -1
  118. package/dist/src/tui/controller-runtime.d.ts +3 -5
  119. package/dist/src/tui/controller-runtime.js +182 -187
  120. package/dist/src/tui/controller-runtime.js.map +1 -1
  121. package/dist/src/tui/controller.d.ts +42 -45
  122. package/dist/src/tui/controller.js +454 -407
  123. package/dist/src/tui/controller.js.map +1 -1
  124. package/dist/src/tui/diagnostics.d.ts +1 -2
  125. package/dist/src/tui/diagnostics.js.map +1 -1
  126. package/dist/src/tui/index.d.ts +1 -1
  127. package/dist/src/tui/index.js +1 -1
  128. package/dist/src/tui/index.js.map +1 -1
  129. package/dist/src/tui/model.d.ts +81 -13
  130. package/dist/src/tui/model.js +378 -95
  131. package/dist/src/tui/model.js.map +1 -1
  132. package/dist/src/tui/router.d.ts +9 -0
  133. package/dist/src/tui/router.js.map +1 -1
  134. package/dist/src/types.d.ts +54 -47
  135. package/dist/src/types.js.map +1 -1
  136. package/dist/src/utils/agent-version.d.ts +4 -1
  137. package/dist/src/utils/agent-version.js +28 -3
  138. package/dist/src/utils/agent-version.js.map +1 -1
  139. package/dist/src/utils/catalog-digests.d.ts +7 -0
  140. package/dist/src/utils/catalog-digests.js +27 -0
  141. package/dist/src/utils/catalog-digests.js.map +1 -1
  142. package/dist/src/utils/catalog-generation-control-snapshot.d.ts +11 -0
  143. package/dist/src/utils/catalog-generation-control-snapshot.js +45 -0
  144. package/dist/src/utils/catalog-generation-control-snapshot.js.map +1 -0
  145. package/dist/src/utils/catalog-generation-error.d.ts +2 -1
  146. package/dist/src/utils/catalog-generation-error.js +12 -0
  147. package/dist/src/utils/catalog-generation-error.js.map +1 -1
  148. package/dist/src/utils/catalog-generation-resolver.d.ts +10 -3
  149. package/dist/src/utils/catalog-generation-resolver.js +90 -76
  150. package/dist/src/utils/catalog-generation-resolver.js.map +1 -1
  151. package/dist/src/utils/catalog-generation-service.d.ts +24 -33
  152. package/dist/src/utils/catalog-generation-service.js +253 -567
  153. package/dist/src/utils/catalog-generation-service.js.map +1 -1
  154. package/dist/src/utils/catalog-generation-state.d.ts +4 -0
  155. package/dist/src/utils/catalog-generation-state.js +73 -106
  156. package/dist/src/utils/catalog-generation-state.js.map +1 -1
  157. package/dist/src/utils/catalog-generation-store.d.ts +16 -26
  158. package/dist/src/utils/catalog-generation-store.js +154 -290
  159. package/dist/src/utils/catalog-generation-store.js.map +1 -1
  160. package/dist/src/utils/catalog-manifest-v6.d.ts +5 -0
  161. package/dist/src/utils/{catalog-manifest-v5.js → catalog-manifest-v6.js} +23 -35
  162. package/dist/src/utils/catalog-manifest-v6.js.map +1 -0
  163. package/dist/src/utils/catalog-operation-context.d.ts +6 -14
  164. package/dist/src/utils/catalog-operation-context.js +68 -169
  165. package/dist/src/utils/catalog-operation-context.js.map +1 -1
  166. package/dist/src/utils/catalog-public-error.js +1 -4
  167. package/dist/src/utils/catalog-public-error.js.map +1 -1
  168. package/dist/src/utils/catalog-runtime-projection.d.ts +3 -0
  169. package/dist/src/utils/catalog-runtime-projection.js +5 -40
  170. package/dist/src/utils/catalog-runtime-projection.js.map +1 -1
  171. package/dist/src/utils/catalog-snapshot.d.ts +2 -2
  172. package/dist/src/utils/catalog-source-references.d.ts +7 -0
  173. package/dist/src/utils/catalog-source-references.js +44 -55
  174. package/dist/src/utils/catalog-source-references.js.map +1 -1
  175. package/dist/src/utils/catalog-sources.js +25 -9
  176. package/dist/src/utils/catalog-sources.js.map +1 -1
  177. package/dist/src/utils/codex-config.d.ts +2 -0
  178. package/dist/src/utils/codex-config.js +22 -1
  179. package/dist/src/utils/codex-config.js.map +1 -1
  180. package/dist/src/utils/codex-manager.d.ts +50 -2
  181. package/dist/src/utils/codex-manager.js +160 -6
  182. package/dist/src/utils/codex-manager.js.map +1 -1
  183. package/dist/src/utils/codex-reconciler.d.ts +131 -0
  184. package/dist/src/utils/codex-reconciler.js +327 -0
  185. package/dist/src/utils/codex-reconciler.js.map +1 -0
  186. package/dist/src/utils/codex-shared-native.d.ts +56 -0
  187. package/dist/src/utils/codex-shared-native.js +87 -0
  188. package/dist/src/utils/codex-shared-native.js.map +1 -0
  189. package/dist/src/utils/codex-surface-analysis.d.ts +44 -0
  190. package/dist/src/utils/codex-surface-analysis.js +247 -0
  191. package/dist/src/utils/codex-surface-analysis.js.map +1 -0
  192. package/dist/src/utils/git-catalog-provider.js +56 -115
  193. package/dist/src/utils/git-catalog-provider.js.map +1 -1
  194. package/dist/src/utils/manifest.d.ts +1 -3
  195. package/dist/src/utils/manifest.js +1 -3
  196. package/dist/src/utils/manifest.js.map +1 -1
  197. package/dist/src/utils/multi-source-catalog.d.ts +1 -10
  198. package/dist/src/utils/multi-source-catalog.js +8 -175
  199. package/dist/src/utils/multi-source-catalog.js.map +1 -1
  200. package/dist/src/utils/native-cli.d.ts +34 -0
  201. package/dist/src/utils/native-cli.js +91 -0
  202. package/dist/src/utils/native-cli.js.map +1 -1
  203. package/dist/src/utils/orphan-marketplace-cleanup.js +1 -0
  204. package/dist/src/utils/orphan-marketplace-cleanup.js.map +1 -1
  205. package/dist/src/utils/ownership.d.ts +0 -10
  206. package/dist/src/utils/ownership.js +3 -88
  207. package/dist/src/utils/ownership.js.map +1 -1
  208. package/dist/src/utils/path-catalog-provider.d.ts +1 -1
  209. package/dist/src/utils/path-catalog-provider.js +45 -62
  210. package/dist/src/utils/path-catalog-provider.js.map +1 -1
  211. package/dist/src/utils/paths.d.ts +0 -1
  212. package/dist/src/utils/paths.js +0 -1
  213. package/dist/src/utils/paths.js.map +1 -1
  214. package/dist/src/utils/plugin-config-write.js +0 -5
  215. package/dist/src/utils/plugin-config-write.js.map +1 -1
  216. package/dist/src/utils/plugin-intent-state.d.ts +39 -0
  217. package/dist/src/utils/plugin-intent-state.js +325 -0
  218. package/dist/src/utils/plugin-intent-state.js.map +1 -0
  219. package/dist/src/utils/target-eligibility.d.ts +3 -2
  220. package/dist/src/utils/target-eligibility.js +4 -3
  221. package/dist/src/utils/target-eligibility.js.map +1 -1
  222. package/package.json +5 -4
  223. package/dist/scripts/aw-skill-eval-engine.d.ts +0 -13
  224. package/dist/scripts/aw-skill-eval-engine.js +0 -31
  225. package/dist/scripts/aw-skill-eval-engine.js.map +0 -1
  226. package/dist/scripts/codex-eval-app-server.d.ts +0 -91
  227. package/dist/scripts/codex-eval-app-server.js +0 -1334
  228. package/dist/scripts/codex-eval-app-server.js.map +0 -1
  229. package/dist/scripts/codex-eval-isolation.d.ts +0 -61
  230. package/dist/scripts/codex-eval-isolation.js +0 -318
  231. package/dist/scripts/codex-eval-isolation.js.map +0 -1
  232. package/dist/scripts/codex-eval-process-management.d.ts +0 -8
  233. package/dist/scripts/codex-eval-process-management.js +0 -69
  234. package/dist/scripts/codex-eval-process-management.js.map +0 -1
  235. package/dist/scripts/codex-eval-process-tree.d.ts +0 -38
  236. package/dist/scripts/codex-eval-process-tree.js +0 -803
  237. package/dist/scripts/codex-eval-process-tree.js.map +0 -1
  238. package/dist/scripts/codex-eval-runtime-config.d.ts +0 -62
  239. package/dist/scripts/codex-eval-runtime-config.js +0 -843
  240. package/dist/scripts/codex-eval-runtime-config.js.map +0 -1
  241. package/dist/scripts/codex-trigger-eval.d.ts +0 -84
  242. package/dist/scripts/codex-trigger-eval.js +0 -968
  243. package/dist/scripts/codex-trigger-eval.js.map +0 -1
  244. package/dist/scripts/eval-plugin-skills-audited.d.ts +0 -6
  245. package/dist/scripts/eval-plugin-skills-audited.js +0 -261
  246. package/dist/scripts/eval-plugin-skills-audited.js.map +0 -1
  247. package/dist/scripts/eval-plugin-skills.d.ts +0 -45
  248. package/dist/scripts/eval-plugin-skills.js +0 -1589
  249. package/dist/scripts/eval-plugin-skills.js.map +0 -1
  250. package/dist/scripts/eval-run-layout.d.ts +0 -17
  251. package/dist/scripts/eval-run-layout.js +0 -26
  252. package/dist/scripts/eval-run-layout.js.map +0 -1
  253. package/dist/scripts/plugin-eval-contract.d.ts +0 -189
  254. package/dist/scripts/plugin-eval-contract.js +0 -745
  255. package/dist/scripts/plugin-eval-contract.js.map +0 -1
  256. package/dist/scripts/plugin-eval-materializer.d.ts +0 -13
  257. package/dist/scripts/plugin-eval-materializer.js.map +0 -1
  258. package/dist/scripts/skill-reporting.d.ts +0 -212
  259. package/dist/scripts/skill-reporting.js +0 -922
  260. package/dist/scripts/skill-reporting.js.map +0 -1
  261. package/dist/src/commands/catalog-context.d.ts +0 -52
  262. package/dist/src/commands/catalog-context.js +0 -156
  263. package/dist/src/commands/catalog-context.js.map +0 -1
  264. package/dist/src/commands/status-v5.js.map +0 -1
  265. package/dist/src/utils/catalog-manifest-v5.d.ts +0 -5
  266. package/dist/src/utils/catalog-manifest-v5.js.map +0 -1
  267. package/dist/src/utils/catalog-source-cache.d.ts +0 -62
  268. package/dist/src/utils/catalog-source-cache.js +0 -321
  269. package/dist/src/utils/catalog-source-cache.js.map +0 -1
  270. package/dist/src/utils/codex-project-surface.d.ts +0 -3
  271. package/dist/src/utils/codex-project-surface.js +0 -49
  272. package/dist/src/utils/codex-project-surface.js.map +0 -1
  273. package/dist/src/utils/plugin-release.d.ts +0 -2
  274. package/dist/src/utils/plugin-release.js +0 -2
  275. package/dist/src/utils/plugin-release.js.map +0 -1
@@ -1,620 +1,306 @@
1
- import { IMPLEMENTED_AW_CAPABILITIES } from '../commands/aw-capabilities.js';
2
- import { withAwHomeMutationLock, } from './aw-home-mutation-lock.js';
3
- import { CatalogGenerationError } from './catalog-generation-error.js';
4
- import { CatalogProviderCompatibilityError } from './catalog-public-error.js';
1
+ import { CatalogGenerationError, catalogGenerationErrorCode } from './catalog-generation-error.js';
2
+ import { readCatalogGenerationControlSnapshot } from './catalog-generation-control-snapshot.js';
3
+ import { createCatalogStoreKey, publishCatalogStoreEntry, readCatalogSnapshotLogicalIdentity, readCatalogStoreEntry, } from './catalog-generation-store.js';
5
4
  import { readCatalogGenerationState, withCatalogGenerationStateTransaction, } from './catalog-generation-state.js';
6
- import { discardPreparedCatalogGeneration, listCatalogGenerationsForIdentity, prepareCatalogGeneration, publishPreparedCatalogGeneration, readCatalogGeneration, } from './catalog-generation-store.js';
7
- import { calculateCatalogSourceConfigFingerprint } from './catalog-source-identity.js';
5
+ export { removeCatalogSourceGenerationState } from './catalog-generation-state.js';
6
+ import { calculateCatalogSourceConfigFingerprint, calculateCatalogSourceIdentity, } from './catalog-source-identity.js';
8
7
  import { readCatalogSourcesConfigSnapshot } from './catalog-sources.js';
9
8
  import { catalogGitProviderInternal } from './git-catalog-provider.js';
10
- import { checkAwCapabilitySupport, compareStrictSemVer } from './manifest.js';
11
9
  import { catalogPathProviderInternal } from './path-catalog-provider.js';
12
- function defaultProviders() {
13
- return {
10
+ function now(runtime) {
11
+ return (runtime?.now?.() ?? new Date()).toISOString();
12
+ }
13
+ async function resolveProvider(options) {
14
+ const providers = options.runtime?.providers ?? {
14
15
  git: catalogGitProviderInternal.resolve,
15
16
  path: catalogPathProviderInternal.resolve,
16
17
  };
18
+ return providers[options.source.type](options.source, {
19
+ cliVersion: options.cliVersion,
20
+ env: options.env,
21
+ signal: options.signal,
22
+ });
17
23
  }
18
- async function resolveSourceForRefresh(options) {
19
- const providers = options.providers ?? defaultProviders();
20
- try {
21
- return options.source.type === 'git'
22
- ? await providers.git(options.source, {
23
- cliVersion: options.cliVersion,
24
- freshnessPolicy: 'forceRemote',
25
- env: options.env,
26
- signal: options.signal,
27
- })
28
- : await providers.path(options.source, {
29
- cliVersion: options.cliVersion,
30
- freshnessPolicy: 'forceRemote',
31
- env: options.env,
32
- signal: options.signal,
33
- });
34
- }
35
- catch (error) {
36
- if (error instanceof CatalogGenerationError)
37
- throw error;
38
- throw new CatalogGenerationError({
39
- code: 'catalogGenerationRefreshFailed',
40
- sourceId: options.source.id,
41
- message: `Cannot refresh Catalog source "${options.source.id}". The previous Active generation is unchanged.`,
42
- cause: error,
43
- });
44
- }
45
- }
46
- function pointerFromGeneration(options) {
24
+ function evidence(resolution, logicalIdentity) {
47
25
  return {
48
- sourceConfigFingerprint: options.sourceConfigFingerprint,
49
- catalogVersion: options.generation.metadata.catalogVersion,
50
- channel: options.generation.metadata.channel,
51
- requestedRef: options.resolution.requestedRef,
52
- resolvedCommit: options.resolution.resolvedCommit,
53
- manifestDigest: options.generation.metadata.manifestDigest,
54
- snapshotDigest: options.generation.metadata.snapshotDigest,
55
- generationKey: options.generation.metadata.generationKey,
56
- ...(options.activatedAt ? { activatedAt: options.activatedAt } : {}),
26
+ sourceIdentity: resolution.sourceIdentity,
27
+ logicalIdentity,
28
+ catalogVersion: resolution.manifest.catalogVersion,
29
+ channel: resolution.manifest.channel,
30
+ requestedRef: resolution.requestedRef,
31
+ resolvedCommit: resolution.resolvedCommit,
32
+ manifestDigest: resolution.manifestDigest,
33
+ snapshotDigest: resolution.snapshotDigest,
57
34
  };
58
35
  }
59
- function candidateFromGeneration(options) {
60
- return {
61
- ...pointerFromGeneration(options),
62
- candidateKind: options.candidateKind,
63
- downloadedAt: options.downloadedAt,
64
- };
36
+ function sameActive(active, next) {
37
+ return Boolean(active)
38
+ && active.sourceConfigFingerprint === next.sourceConfigFingerprint
39
+ && active.sourceIdentity === next.sourceIdentity
40
+ && active.requestedRef === next.requestedRef
41
+ && active.resolvedCommit === next.resolvedCommit
42
+ && active.logicalIdentity === next.logicalIdentity
43
+ && active.manifestDigest === next.manifestDigest
44
+ && active.snapshotDigest === next.snapshotDigest;
65
45
  }
66
- function checked(options) {
67
- return {
68
- checkedAt: options.checkedAt,
69
- state: options.state,
70
- remoteCommit: options.resolution.resolvedCommit,
71
- ...(options.errorCode ? { errorCode: options.errorCode } : {}),
72
- };
46
+ async function assertCurrentSource(options) {
47
+ const current = await readCatalogSourcesConfigSnapshot(options.env);
48
+ const source = current.config.sources.find((entry) => entry.id === options.sourceId);
49
+ if (!source)
50
+ throw new CatalogGenerationError({
51
+ code: 'catalogGenerationSourceMissing',
52
+ sourceId: options.sourceId,
53
+ message: `Catalog source "${options.sourceId}" was removed during sync.`,
54
+ });
55
+ if (calculateCatalogSourceConfigFingerprint(source) !== options.fingerprint) {
56
+ throw new CatalogGenerationError({
57
+ code: 'catalogGenerationIdentityMismatch',
58
+ sourceId: options.sourceId,
59
+ message: `Catalog source "${options.sourceId}" changed during sync. Run sync again.`,
60
+ });
61
+ }
73
62
  }
74
- async function recordRefreshFailure(options) {
75
- await withAwHomeMutationLock({
76
- env: options.env,
77
- token: options.awHomeMutationToken,
78
- action: async () => {
79
- const config = await readCatalogSourcesConfigSnapshot(options.env);
80
- const configured = config.config.sources.find((source) => source.id === options.sourceId);
81
- if (!configured
82
- || calculateCatalogSourceConfigFingerprint(configured) !== options.sourceConfigFingerprint)
83
- return;
84
- await withCatalogGenerationStateTransaction({
85
- env: options.env,
86
- action: async (current) => {
87
- const source = current.sources[options.sourceId];
88
- if (!source)
89
- return { state: current, result: undefined };
90
- return {
91
- state: {
92
- ...current,
93
- sources: {
94
- ...current.sources,
95
- [options.sourceId]: {
96
- ...source,
97
- lastCheck: {
98
- checkedAt: options.checkedAt,
99
- state: 'failed',
100
- errorCode: options.errorCode,
101
- },
102
- },
103
- },
63
+ async function recordFailure(options) {
64
+ try {
65
+ await assertCurrentSource(options);
66
+ const lastSync = {
67
+ syncedAt: now(options.runtime),
68
+ mode: options.mode,
69
+ state: 'failed',
70
+ errorCode: options.errorCode,
71
+ };
72
+ await withCatalogGenerationStateTransaction({
73
+ env: options.env,
74
+ beforeReplace: () => assertCurrentSource(options),
75
+ action: async (current) => ({
76
+ state: {
77
+ schemaVersion: 1,
78
+ sources: {
79
+ ...current.sources,
80
+ [options.sourceId]: {
81
+ ...current.sources[options.sourceId],
82
+ lastSync,
104
83
  },
105
- result: undefined,
106
- };
84
+ },
107
85
  },
108
- });
109
- },
110
- });
86
+ result: undefined,
87
+ }),
88
+ });
89
+ }
90
+ catch {
91
+ // A concurrent source update or removal must not be undone by failure diagnostics.
92
+ }
111
93
  }
112
- function sameGeneration(pointer, generation, sourceConfigFingerprint) {
113
- return pointer?.sourceConfigFingerprint === sourceConfigFingerprint
114
- && pointer.catalogVersion === generation.metadata.catalogVersion
115
- && pointer.snapshotDigest === generation.metadata.snapshotDigest;
94
+ function warnCleanupFailure(sourceId) {
95
+ try {
96
+ process.emitWarning(`Catalog provider staging cleanup failed for source "${sourceId}".`, { code: 'AW_CATALOG_PROVIDER_CLEANUP_FAILED' });
97
+ }
98
+ catch {
99
+ // Cleanup diagnostics cannot replace the sync result.
100
+ }
116
101
  }
117
- export async function refreshCatalogSourceGeneration(options) {
102
+ export async function syncCatalogSourceGeneration(options) {
118
103
  const env = options.env ?? process.env;
119
- const config = await readCatalogSourcesConfigSnapshot(env);
120
- const source = config.config.sources.find((entry) => entry.id === options.sourceId);
121
- if (!source) {
104
+ const mode = options.check ? 'check' : 'sync';
105
+ const control = await readCatalogGenerationControlSnapshot({ env });
106
+ const source = control.configSnapshot.config.sources.find((entry) => entry.id === options.sourceId);
107
+ if (!source)
122
108
  throw new CatalogGenerationError({
123
109
  code: 'catalogGenerationSourceMissing',
124
110
  sourceId: options.sourceId,
125
111
  message: `Catalog source "${options.sourceId}" is not configured.`,
126
112
  });
127
- }
128
- const sourceConfigFingerprint = calculateCatalogSourceConfigFingerprint(source);
129
- const checkedAt = (options.runtime?.now?.() ?? new Date()).toISOString();
113
+ const fingerprint = calculateCatalogSourceConfigFingerprint(source);
130
114
  let resolution;
131
115
  try {
132
- await options.runtime?.onProgress?.({ sourceId: source.id, state: 'checking' });
133
- options.signal?.throwIfAborted();
134
- resolution = await resolveSourceForRefresh({
116
+ resolution = await resolveProvider({
135
117
  source,
136
118
  cliVersion: options.cliVersion,
137
119
  env,
138
120
  signal: options.signal,
139
- providers: options.runtime?.providers,
140
- });
141
- }
142
- catch (error) {
143
- options.signal?.throwIfAborted();
144
- await recordRefreshFailure({
145
- sourceId: source.id,
146
- sourceConfigFingerprint,
147
- env,
148
- checkedAt,
149
- errorCode: error instanceof CatalogGenerationError
150
- ? error.code
151
- : 'catalogGenerationRefreshFailed',
152
- ...(options.awHomeMutationToken
153
- ? { awHomeMutationToken: options.awHomeMutationToken }
154
- : {}),
121
+ runtime: options.runtime,
155
122
  });
156
- throw error;
157
- }
158
- let prepared;
159
- try {
160
- await options.runtime?.onProgress?.({ sourceId: source.id, state: 'validating' });
161
- options.signal?.throwIfAborted();
162
- prepared = await prepareCatalogGeneration({
163
- resolution,
164
- cliVersion: options.cliVersion,
123
+ const expectedIdentity = await calculateCatalogSourceIdentity(source);
124
+ if (resolution.sourceId !== source.id || resolution.sourceIdentity !== expectedIdentity) {
125
+ throw new CatalogGenerationError({
126
+ code: 'catalogGenerationIdentityMismatch',
127
+ sourceId: source.id,
128
+ message: `Catalog provider returned mismatched identity for source "${source.id}".`,
129
+ });
130
+ }
131
+ const logicalIdentity = await readCatalogSnapshotLogicalIdentity(resolution.rootDir);
132
+ const syncEvidence = evidence(resolution, logicalIdentity);
133
+ if (options.check) {
134
+ await assertCurrentSource({ sourceId: source.id, fingerprint, env });
135
+ const lastSync = {
136
+ syncedAt: now(options.runtime),
137
+ mode,
138
+ state: 'succeeded',
139
+ resolvedCommit: resolution.resolvedCommit,
140
+ };
141
+ await withCatalogGenerationStateTransaction({
142
+ env,
143
+ beforeReplace: () => assertCurrentSource({ sourceId: source.id, fingerprint, env }),
144
+ action: async (current) => ({
145
+ state: {
146
+ schemaVersion: 1,
147
+ sources: {
148
+ ...current.sources,
149
+ [source.id]: { ...current.sources[source.id], lastSync },
150
+ },
151
+ },
152
+ result: undefined,
153
+ }),
154
+ });
155
+ return {
156
+ catalogGenerationSchemaVersion: 1,
157
+ sourceId: source.id,
158
+ mode,
159
+ outcome: 'checked',
160
+ activeChanged: false,
161
+ resolution: syncEvidence,
162
+ ...(control.generationState.sources[source.id]?.active
163
+ ? { active: control.generationState.sources[source.id].active }
164
+ : {}),
165
+ lastSync,
166
+ };
167
+ }
168
+ const store = await publishCatalogStoreEntry({ resolution, env, signal: options.signal });
169
+ const activeInput = {
170
+ sourceConfigFingerprint: fingerprint,
171
+ sourceIdentity: resolution.sourceIdentity,
172
+ requestedRef: resolution.requestedRef,
173
+ resolvedCommit: resolution.resolvedCommit,
174
+ logicalIdentity: store.metadata.logicalIdentity,
175
+ manifestDigest: store.metadata.manifestDigest,
176
+ snapshotDigest: store.metadata.snapshotDigest,
177
+ };
178
+ await assertCurrentSource({ sourceId: source.id, fingerprint, env });
179
+ const syncedAt = now(options.runtime);
180
+ return await withCatalogGenerationStateTransaction({
165
181
  env,
166
- now: options.runtime?.now,
167
- signal: options.signal,
182
+ beforeReplace: () => assertCurrentSource({ sourceId: source.id, fingerprint, env }),
183
+ action: async (current) => {
184
+ const previous = current.sources[source.id]?.active;
185
+ const unchanged = sameActive(previous, activeInput);
186
+ const active = unchanged
187
+ ? previous
188
+ : { ...activeInput, activatedAt: syncedAt };
189
+ const lastSync = {
190
+ syncedAt,
191
+ mode,
192
+ state: 'succeeded',
193
+ resolvedCommit: resolution.resolvedCommit,
194
+ };
195
+ return {
196
+ state: {
197
+ schemaVersion: 1,
198
+ sources: { ...current.sources, [source.id]: { active, lastSync } },
199
+ },
200
+ result: {
201
+ catalogGenerationSchemaVersion: 1,
202
+ sourceId: source.id,
203
+ mode,
204
+ outcome: unchanged ? 'unchanged' : 'activated',
205
+ activeChanged: !unchanged,
206
+ resolution: syncEvidence,
207
+ active,
208
+ lastSync,
209
+ },
210
+ };
211
+ },
168
212
  });
169
213
  }
170
214
  catch (error) {
171
- options.signal?.throwIfAborted();
172
- await recordRefreshFailure({
215
+ const code = error instanceof CatalogGenerationError
216
+ ? error.code
217
+ : 'catalogGenerationRefreshFailed';
218
+ await recordFailure({
173
219
  sourceId: source.id,
174
- sourceConfigFingerprint,
175
- env,
176
- checkedAt,
177
- errorCode: error instanceof CatalogGenerationError
178
- ? error.code
179
- : 'catalogGenerationPublishFailed',
180
- ...(options.awHomeMutationToken
181
- ? { awHomeMutationToken: options.awHomeMutationToken }
182
- : {}),
183
- });
184
- throw error;
185
- }
186
- try {
187
- options.signal?.throwIfAborted();
188
- const transaction = await withAwHomeMutationLock({
220
+ fingerprint,
221
+ mode,
222
+ errorCode: code,
189
223
  env,
190
- signal: options.signal,
191
- token: options.awHomeMutationToken,
192
- action: async () => {
193
- options.signal?.throwIfAborted();
194
- const currentConfig = await readCatalogSourcesConfigSnapshot(env);
195
- const currentConfiguredSource = currentConfig.config.sources
196
- .find((entry) => entry.id === source.id);
197
- if (!currentConfiguredSource) {
198
- throw new CatalogGenerationError({
199
- code: 'catalogGenerationSourceMissing',
200
- sourceId: source.id,
201
- message: `Catalog source "${source.id}" was removed while refresh was in progress. The prepared generation was discarded.`,
202
- });
203
- }
204
- if (calculateCatalogSourceConfigFingerprint(currentConfiguredSource)
205
- !== sourceConfigFingerprint) {
206
- throw new CatalogGenerationError({
207
- code: 'catalogGenerationIdentityMismatch',
208
- sourceId: source.id,
209
- message: `Catalog source "${source.id}" changed while refresh was in progress. The prepared generation was discarded.`,
210
- });
211
- }
212
- return withCatalogGenerationStateTransaction({
213
- env,
214
- beforeReplace: () => options.signal?.throwIfAborted(),
215
- action: async (current) => {
216
- options.signal?.throwIfAborted();
217
- const previous = current.sources[source.id];
218
- if (source.type === 'git'
219
- && previous?.active
220
- && previous.logicalIdentity !== prepared.metadata.logicalIdentity) {
221
- return {
222
- state: current,
223
- result: {
224
- error: new CatalogGenerationError({
225
- code: 'catalogGenerationIdentityMismatch',
226
- sourceId: source.id,
227
- message: `Catalog source "${source.id}" returned a different workspace identity. Active and Candidate are unchanged; update the source configuration explicitly before adopting another Catalog identity.`,
228
- }),
229
- },
230
- };
231
- }
232
- const currentSource = previous?.logicalIdentity === prepared.metadata.logicalIdentity
233
- ? previous
234
- : undefined;
235
- const refreshPolicy = currentSource?.refreshPolicy
236
- ?? (source.type === 'path' ? 'manual' : 'startup');
237
- if (source.type === 'git') {
238
- const generations = await listCatalogGenerationsForIdentity({
239
- logicalIdentity: prepared.metadata.logicalIdentity,
240
- env,
241
- });
242
- const violation = generations.find((generation) => generation.metadata.catalogVersion === prepared.metadata.catalogVersion
243
- && generation.metadata.snapshotDigest !== prepared.metadata.snapshotDigest);
244
- if (violation) {
245
- const lastCheck = checked({
246
- checkedAt,
247
- state: 'immutableViolation',
248
- resolution,
249
- errorCode: 'catalogImmutableVersionViolation',
250
- });
251
- const nextSource = currentSource
252
- ? { ...currentSource, lastCheck }
253
- : {
254
- logicalIdentity: prepared.metadata.logicalIdentity,
255
- refreshPolicy,
256
- lastCheck,
257
- };
258
- return {
259
- state: {
260
- ...current,
261
- sources: { ...current.sources, [source.id]: nextSource },
262
- },
263
- result: {
264
- error: new CatalogGenerationError({
265
- code: 'catalogImmutableVersionViolation',
266
- sourceId: source.id,
267
- message: `Catalog source "${source.id}" reused version ${prepared.metadata.catalogVersion} with different content. Active and Candidate are unchanged; publish a higher Catalog version and refresh again.`,
268
- }),
269
- },
270
- };
271
- }
272
- }
273
- options.signal?.throwIfAborted();
274
- const published = await publishPreparedCatalogGeneration(prepared);
275
- options.signal?.throwIfAborted();
276
- if (source.type === 'path' || !currentSource?.active) {
277
- const active = pointerFromGeneration({
278
- generation: published,
279
- resolution,
280
- sourceConfigFingerprint,
281
- activatedAt: checkedAt,
282
- });
283
- const lastCheck = checked({ checkedAt, state: 'activeReady', resolution });
284
- const nextSource = {
285
- logicalIdentity: published.metadata.logicalIdentity,
286
- refreshPolicy,
287
- active,
288
- lastCheck,
289
- };
290
- return {
291
- state: {
292
- ...current,
293
- sources: { ...current.sources, [source.id]: nextSource },
294
- },
295
- result: {
296
- value: {
297
- catalogGenerationSchemaVersion: 1,
298
- sourceId: source.id,
299
- sourceIdentity: resolution.sourceIdentity,
300
- logicalIdentity: published.metadata.logicalIdentity,
301
- outcome: 'activeReady',
302
- active,
303
- lastCheck,
304
- },
305
- },
306
- };
307
- }
308
- if (sameGeneration(currentSource.active, published, sourceConfigFingerprint)) {
309
- const lastCheck = checked({ checkedAt, state: 'upToDate', resolution });
310
- return {
311
- state: {
312
- ...current,
313
- sources: {
314
- ...current.sources,
315
- [source.id]: { ...currentSource, lastCheck },
316
- },
317
- },
318
- result: {
319
- value: {
320
- catalogGenerationSchemaVersion: 1,
321
- sourceId: source.id,
322
- sourceIdentity: resolution.sourceIdentity,
323
- logicalIdentity: published.metadata.logicalIdentity,
324
- outcome: 'upToDate',
325
- active: currentSource.active,
326
- ...(currentSource.candidate ? { candidate: currentSource.candidate } : {}),
327
- lastCheck,
328
- },
329
- },
330
- };
331
- }
332
- const comparison = compareStrictSemVer(published.metadata.catalogVersion, currentSource.active.catalogVersion);
333
- const explicitRefChange = source.refPolicy.type === 'explicit'
334
- && currentSource.active.requestedRef !== resolution.requestedRef;
335
- if (comparison < 0 && !explicitRefChange) {
336
- const lastCheck = checked({ checkedAt, state: 'channelRollback', resolution });
337
- return {
338
- state: {
339
- ...current,
340
- sources: {
341
- ...current.sources,
342
- [source.id]: { ...currentSource, lastCheck },
343
- },
344
- },
345
- result: {
346
- value: {
347
- catalogGenerationSchemaVersion: 1,
348
- sourceId: source.id,
349
- sourceIdentity: resolution.sourceIdentity,
350
- logicalIdentity: published.metadata.logicalIdentity,
351
- outcome: 'channelRollback',
352
- active: currentSource.active,
353
- ...(currentSource.candidate ? { candidate: currentSource.candidate } : {}),
354
- lastCheck,
355
- },
356
- },
357
- };
358
- }
359
- const candidateKind = explicitRefChange
360
- ? 'refChange'
361
- : 'upgrade';
362
- const candidate = sameGeneration(currentSource.candidate, published, sourceConfigFingerprint)
363
- ? currentSource.candidate
364
- : candidateFromGeneration({
365
- generation: published,
366
- resolution,
367
- sourceConfigFingerprint,
368
- candidateKind,
369
- downloadedAt: checkedAt,
370
- });
371
- const lastCheck = checked({ checkedAt, state: 'candidateReady', resolution });
372
- return {
373
- state: {
374
- ...current,
375
- sources: {
376
- ...current.sources,
377
- [source.id]: { ...currentSource, candidate, lastCheck },
378
- },
379
- },
380
- result: {
381
- value: {
382
- catalogGenerationSchemaVersion: 1,
383
- sourceId: source.id,
384
- sourceIdentity: resolution.sourceIdentity,
385
- logicalIdentity: published.metadata.logicalIdentity,
386
- outcome: 'candidateReady',
387
- active: currentSource.active,
388
- candidate,
389
- lastCheck,
390
- },
391
- },
392
- };
393
- },
394
- });
395
- },
224
+ runtime: options.runtime,
396
225
  });
397
- if ('error' in transaction)
398
- throw transaction.error;
399
- return transaction.value;
400
- }
401
- finally {
402
- await discardPreparedCatalogGeneration(prepared);
403
- }
404
- }
405
- async function assertPointerMatchesGeneration(options) {
406
- if (options.sourceConfigFingerprint !== undefined
407
- && options.pointer.sourceConfigFingerprint !== options.sourceConfigFingerprint) {
226
+ if (error instanceof CatalogGenerationError)
227
+ throw error;
408
228
  throw new CatalogGenerationError({
409
- code: 'catalogGenerationIdentityMismatch',
410
- message: 'Catalog generation pointer does not match the current source configuration. Refresh the configured source.',
229
+ code: 'catalogGenerationRefreshFailed',
230
+ sourceId: source.id,
231
+ message: `Cannot sync Catalog source "${source.id}". The previous Active snapshot is unchanged.`,
232
+ cause: error,
411
233
  });
412
234
  }
413
- const generation = await readCatalogGeneration({
414
- logicalIdentity: options.logicalIdentity,
415
- snapshotDigest: options.pointer.snapshotDigest,
416
- env: options.env,
417
- });
418
- if (generation.metadata.catalogVersion !== options.pointer.catalogVersion
419
- || generation.metadata.channel !== options.pointer.channel
420
- || generation.metadata.manifestDigest !== options.pointer.manifestDigest
421
- || generation.metadata.generationKey !== options.pointer.generationKey) {
422
- throw new CatalogGenerationError({
423
- code: 'catalogGenerationIdentityMismatch',
424
- message: 'Catalog generation pointer does not match immutable generation metadata. Refresh the source after repairing catalog-generations.json.',
425
- });
235
+ finally {
236
+ if (resolution)
237
+ await resolution.cleanup().catch(() => warnCleanupFailure(source.id));
426
238
  }
427
- return generation;
428
- }
429
- export async function activateCatalogSourceCandidate(options) {
430
- const env = options.env ?? process.env;
431
- return withAwHomeMutationLock({
432
- env,
433
- token: options.awHomeMutationToken,
434
- action: async () => {
435
- const config = await readCatalogSourcesConfigSnapshot(env);
436
- const configuredSource = config.config.sources
437
- .find((source) => source.id === options.sourceId);
438
- if (!configuredSource) {
439
- throw new CatalogGenerationError({
440
- code: 'catalogGenerationSourceMissing',
441
- sourceId: options.sourceId,
442
- message: `Catalog source "${options.sourceId}" is not configured.`,
443
- });
444
- }
445
- return withCatalogGenerationStateTransaction({
446
- env,
447
- action: async (current) => {
448
- const source = current.sources[options.sourceId];
449
- if (!source?.candidate) {
450
- throw new CatalogGenerationError({
451
- code: 'catalogGenerationCandidateUnavailable',
452
- sourceId: options.sourceId,
453
- message: `Catalog source "${options.sourceId}" has no Candidate generation to activate.`,
454
- });
455
- }
456
- if (options.expectedCandidateGenerationKey
457
- && source.candidate.generationKey !== options.expectedCandidateGenerationKey) {
458
- throw new CatalogGenerationError({
459
- code: 'catalogGenerationCandidateChanged',
460
- sourceId: options.sourceId,
461
- message: `Catalog source "${options.sourceId}" Candidate changed after Review. Review the new Candidate before activation.`,
462
- });
463
- }
464
- const candidateGeneration = await assertPointerMatchesGeneration({
465
- logicalIdentity: source.logicalIdentity,
466
- pointer: source.candidate,
467
- sourceConfigFingerprint: calculateCatalogSourceConfigFingerprint(configuredSource),
468
- env,
469
- });
470
- const requiredCapabilities = candidateGeneration.metadata.requiredAwCapabilities;
471
- const support = checkAwCapabilitySupport(requiredCapabilities, IMPLEMENTED_AW_CAPABILITIES);
472
- if (!support.supported) {
473
- throw new CatalogProviderCompatibilityError({
474
- sourceId: options.sourceId,
475
- requiredCapabilities,
476
- missingCapabilities: support.missing,
477
- availableCapabilities: IMPLEMENTED_AW_CAPABILITIES,
478
- });
479
- }
480
- const active = {
481
- sourceConfigFingerprint: source.candidate.sourceConfigFingerprint,
482
- catalogVersion: source.candidate.catalogVersion,
483
- channel: source.candidate.channel,
484
- requestedRef: source.candidate.requestedRef,
485
- resolvedCommit: source.candidate.resolvedCommit,
486
- manifestDigest: source.candidate.manifestDigest,
487
- snapshotDigest: source.candidate.snapshotDigest,
488
- generationKey: source.candidate.generationKey,
489
- activatedAt: (options.runtime?.now?.() ?? new Date()).toISOString(),
490
- };
491
- const nextSource = {
492
- ...source,
493
- active,
494
- };
495
- delete nextSource.candidate;
496
- return {
497
- state: {
498
- ...current,
499
- sources: { ...current.sources, [options.sourceId]: nextSource },
500
- },
501
- result: {
502
- catalogGenerationSchemaVersion: 1,
503
- sourceId: options.sourceId,
504
- logicalIdentity: source.logicalIdentity,
505
- outcome: 'activated',
506
- active,
507
- },
508
- };
509
- },
510
- });
511
- },
512
- });
513
- }
514
- export async function setCatalogSourceRefreshPolicy(options) {
515
- const env = options.env ?? process.env;
516
- return withAwHomeMutationLock({
517
- env,
518
- action: async () => {
519
- const config = await readCatalogSourcesConfigSnapshot(env);
520
- const configuredSource = config.config.sources.find((source) => source.id === options.sourceId);
521
- if (!configuredSource) {
522
- throw new CatalogGenerationError({
523
- code: 'catalogGenerationSourceMissing',
524
- sourceId: options.sourceId,
525
- message: `Catalog source "${options.sourceId}" is not configured.`,
526
- });
527
- }
528
- if (configuredSource.type === 'path' && options.refreshPolicy !== 'manual') {
529
- throw new CatalogGenerationError({
530
- code: 'catalogGenerationRefreshPolicyInvalid',
531
- sourceId: options.sourceId,
532
- message: `Path Catalog source "${options.sourceId}" only supports manual refresh.`,
533
- });
534
- }
535
- await withCatalogGenerationStateTransaction({
536
- env,
537
- action: async (current) => {
538
- const source = current.sources[options.sourceId];
539
- if (!source) {
540
- throw new CatalogGenerationError({
541
- code: 'catalogGenerationUnavailable',
542
- sourceId: options.sourceId,
543
- message: `Catalog source "${options.sourceId}" has no generation state. Refresh it before changing refresh policy.`,
544
- });
545
- }
546
- return {
547
- state: {
548
- ...current,
549
- sources: {
550
- ...current.sources,
551
- [options.sourceId]: { ...source, refreshPolicy: options.refreshPolicy },
552
- },
553
- },
554
- result: undefined,
555
- };
556
- },
557
- });
558
- return (await readCatalogGenerationStatus({ sourceId: options.sourceId, env })).sources[0];
559
- },
560
- });
561
- }
562
- export async function removeCatalogSourceGenerationState(options) {
563
- return withCatalogGenerationStateTransaction({
564
- env: options.env,
565
- action: async (current) => {
566
- if (!current.sources[options.sourceId])
567
- return { state: current, result: false };
568
- const sources = { ...current.sources };
569
- delete sources[options.sourceId];
570
- return { state: { ...current, sources }, result: true };
571
- },
572
- });
573
239
  }
574
240
  export async function readCatalogGenerationStatus(options = {}) {
575
241
  const env = options.env ?? process.env;
576
- const [config, state] = await Promise.all([
577
- readCatalogSourcesConfigSnapshot(env),
578
- readCatalogGenerationState(env),
579
- ]);
580
- const sources = config.config.sources
581
- .filter((source) => options.sourceId === undefined || source.id === options.sourceId)
582
- .sort((left, right) => left.id < right.id ? -1 : left.id > right.id ? 1 : 0);
583
- if (options.sourceId && sources.length === 0) {
242
+ const config = await readCatalogSourcesConfigSnapshot(env);
243
+ const state = await readCatalogGenerationState(env);
244
+ const selected = options.sourceId
245
+ ? config.config.sources.filter((source) => source.id === options.sourceId)
246
+ : config.config.sources;
247
+ if (options.sourceId && selected.length === 0)
584
248
  throw new CatalogGenerationError({
585
249
  code: 'catalogGenerationSourceMissing',
586
250
  sourceId: options.sourceId,
587
251
  message: `Catalog source "${options.sourceId}" is not configured.`,
588
252
  });
589
- }
590
- const entries = [];
591
- for (const source of sources) {
592
- const selected = state.sources[source.id];
593
- const sourceConfigFingerprint = calculateCatalogSourceConfigFingerprint(source);
594
- if (selected?.active)
595
- await assertPointerMatchesGeneration({
596
- logicalIdentity: selected.logicalIdentity,
597
- pointer: selected.active,
598
- ...(selected.candidate ? {} : { sourceConfigFingerprint }),
253
+ const sources = await Promise.all(selected.map(async (source) => {
254
+ const configuredSourceIdentity = await calculateCatalogSourceIdentity(source);
255
+ const sourceState = state.sources[source.id];
256
+ const active = sourceState?.active;
257
+ const configMatchesActive = Boolean(active)
258
+ && active.sourceIdentity === configuredSourceIdentity
259
+ && active.sourceConfigFingerprint === calculateCatalogSourceConfigFingerprint(source);
260
+ if (!active)
261
+ return {
262
+ sourceId: source.id,
263
+ configuredSourceIdentity,
264
+ activeReady: false,
265
+ configMatchesActive: false,
266
+ lastSync: sourceState?.lastSync,
267
+ };
268
+ try {
269
+ const entry = await readCatalogStoreEntry({
270
+ logicalIdentity: active.logicalIdentity,
271
+ snapshotDigest: active.snapshotDigest,
599
272
  env,
600
273
  });
601
- if (selected?.candidate)
602
- await assertPointerMatchesGeneration({
603
- logicalIdentity: selected.logicalIdentity,
604
- pointer: selected.candidate,
605
- sourceConfigFingerprint,
606
- env,
607
- });
608
- entries.push({
609
- sourceId: source.id,
610
- sourceType: source.type,
611
- refreshPolicy: selected?.refreshPolicy ?? (source.type === 'path' ? 'manual' : 'startup'),
612
- ...(selected ? { logicalIdentity: selected.logicalIdentity } : {}),
613
- ...(selected?.active ? { active: selected.active } : {}),
614
- ...(selected?.candidate ? { candidate: selected.candidate } : {}),
615
- ...(selected?.lastCheck ? { lastCheck: selected.lastCheck } : {}),
616
- });
617
- }
618
- return { catalogGenerationStatusSchemaVersion: 1, sources: entries };
274
+ if (entry.metadata.manifestDigest !== active.manifestDigest) {
275
+ throw new CatalogGenerationError({
276
+ code: 'catalogGenerationIdentityMismatch',
277
+ message: 'Active does not match store metadata.',
278
+ });
279
+ }
280
+ return {
281
+ sourceId: source.id,
282
+ configuredSourceIdentity,
283
+ active,
284
+ activeReady: configMatchesActive,
285
+ configMatchesActive,
286
+ catalogVersion: entry.metadata.catalogVersion,
287
+ channel: entry.metadata.channel,
288
+ storeKey: createCatalogStoreKey(active.logicalIdentity, active.snapshotDigest),
289
+ lastSync: sourceState?.lastSync,
290
+ };
291
+ }
292
+ catch (error) {
293
+ return {
294
+ sourceId: source.id,
295
+ configuredSourceIdentity,
296
+ active,
297
+ activeReady: false,
298
+ configMatchesActive,
299
+ lastSync: sourceState?.lastSync,
300
+ errorCode: catalogGenerationErrorCode(error),
301
+ };
302
+ }
303
+ }));
304
+ return { catalogGenerationStatusSchemaVersion: 1, sources };
619
305
  }
620
306
  //# sourceMappingURL=catalog-generation-service.js.map