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

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 (237) hide show
  1. package/dist/authoring/scripts/init-plugin.mjs +4 -33
  2. package/dist/authoring/scripts/init-plugin.mjs.map +1 -1
  3. package/dist/authoring/scripts/lib/plugin-version-check.mjs +1 -1
  4. package/dist/authoring/scripts/plugin-status.mjs +8 -11
  5. package/dist/authoring/scripts/plugin-status.mjs.map +1 -1
  6. package/dist/authoring/scripts/remove-plugin.mjs +1 -0
  7. package/dist/authoring/scripts/remove-plugin.mjs.map +1 -1
  8. package/dist/authoring/scripts/validate-plugin.mjs +104 -54
  9. package/dist/authoring/scripts/validate-plugin.mjs.map +1 -1
  10. package/dist/scripts/codex-eval-app-server.d.ts +2 -0
  11. package/dist/scripts/codex-eval-app-server.js +107 -1
  12. package/dist/scripts/codex-eval-app-server.js.map +1 -1
  13. package/dist/scripts/eval-plugin-skills.js +5 -2
  14. package/dist/scripts/eval-plugin-skills.js.map +1 -1
  15. package/dist/scripts/plugin-eval-contract.d.ts +5 -1
  16. package/dist/scripts/plugin-eval-contract.js +54 -4
  17. package/dist/scripts/plugin-eval-contract.js.map +1 -1
  18. package/dist/scripts/plugin-staging.d.ts +6 -7
  19. package/dist/scripts/plugin-staging.js +11 -23
  20. package/dist/scripts/plugin-staging.js.map +1 -1
  21. package/dist/scripts/test-plugin-scripts.js +2 -33
  22. package/dist/scripts/test-plugin-scripts.js.map +1 -1
  23. package/dist/src/adapters/helpers.js +2 -2
  24. package/dist/src/adapters/helpers.js.map +1 -1
  25. package/dist/src/authoring/workspace-commands.d.ts +17 -2
  26. package/dist/src/authoring/workspace-commands.js +21 -4
  27. package/dist/src/authoring/workspace-commands.js.map +1 -1
  28. package/dist/src/commands/aw-capabilities.d.ts +78 -0
  29. package/dist/src/commands/aw-capabilities.js +259 -0
  30. package/dist/src/commands/aw-capabilities.js.map +1 -0
  31. package/dist/src/commands/catalog-context.d.ts +52 -0
  32. package/dist/src/commands/catalog-context.js +156 -0
  33. package/dist/src/commands/catalog-context.js.map +1 -0
  34. package/dist/src/commands/catalog-dev-source.d.ts +112 -0
  35. package/dist/src/commands/catalog-dev-source.js +481 -0
  36. package/dist/src/commands/catalog-dev-source.js.map +1 -0
  37. package/dist/src/commands/catalog-generation.d.ts +26 -0
  38. package/dist/src/commands/catalog-generation.js +14 -0
  39. package/dist/src/commands/catalog-generation.js.map +1 -0
  40. package/dist/src/commands/catalog-publication-inspection.d.ts +1 -1
  41. package/dist/src/commands/catalog-publication-inspection.js +4 -5
  42. package/dist/src/commands/catalog-publication-inspection.js.map +1 -1
  43. package/dist/src/commands/catalog-publication-target.d.ts +17 -0
  44. package/dist/src/commands/catalog-publication-target.js +60 -0
  45. package/dist/src/commands/catalog-publication-target.js.map +1 -0
  46. package/dist/src/commands/catalog-publish.d.ts +8 -1
  47. package/dist/src/commands/catalog-publish.js +25 -2
  48. package/dist/src/commands/catalog-publish.js.map +1 -1
  49. package/dist/src/commands/catalog-source.d.ts +23 -1
  50. package/dist/src/commands/catalog-source.js +126 -40
  51. package/dist/src/commands/catalog-source.js.map +1 -1
  52. package/dist/src/commands/catalog-status.d.ts +18 -2
  53. package/dist/src/commands/catalog-status.js +122 -18
  54. package/dist/src/commands/catalog-status.js.map +1 -1
  55. package/dist/src/commands/init.js +1 -1
  56. package/dist/src/commands/init.js.map +1 -1
  57. package/dist/src/commands/offline-cleanup-evidence.d.ts +23 -0
  58. package/dist/src/commands/offline-cleanup-evidence.js +38 -0
  59. package/dist/src/commands/offline-cleanup-evidence.js.map +1 -0
  60. package/dist/src/commands/options.d.ts +1 -0
  61. package/dist/src/commands/options.js +1 -0
  62. package/dist/src/commands/options.js.map +1 -1
  63. package/dist/src/commands/plugin-capabilities.js +1 -1
  64. package/dist/src/commands/plugin-capabilities.js.map +1 -1
  65. package/dist/src/commands/rebuild-command.d.ts +19 -7
  66. package/dist/src/commands/rebuild-command.js +415 -205
  67. package/dist/src/commands/rebuild-command.js.map +1 -1
  68. package/dist/src/commands/rebuild-integration.d.ts +10 -3
  69. package/dist/src/commands/rebuild-integration.js +71 -76
  70. package/dist/src/commands/rebuild-integration.js.map +1 -1
  71. package/dist/src/commands/rebuild-operations.d.ts +0 -8
  72. package/dist/src/commands/rebuild-operations.js +17 -115
  73. package/dist/src/commands/rebuild-operations.js.map +1 -1
  74. package/dist/src/commands/runtime.js +21 -34
  75. package/dist/src/commands/runtime.js.map +1 -1
  76. package/dist/src/commands/{status-v4.d.ts → status-v5.d.ts} +67 -21
  77. package/dist/src/commands/{status-v4.js → status-v5.js} +260 -30
  78. package/dist/src/commands/status-v5.js.map +1 -0
  79. package/dist/src/commands/wizard.d.ts +2 -2
  80. package/dist/src/commands/wizard.js +2 -2
  81. package/dist/src/commands/wizard.js.map +1 -1
  82. package/dist/src/commands/write-commands.js +73 -17
  83. package/dist/src/commands/write-commands.js.map +1 -1
  84. package/dist/src/constants.d.ts +6 -1
  85. package/dist/src/constants.js +6 -1
  86. package/dist/src/constants.js.map +1 -1
  87. package/dist/src/generators/local-plugin.js +57 -3
  88. package/dist/src/generators/local-plugin.js.map +1 -1
  89. package/dist/src/index.d.ts +4 -1
  90. package/dist/src/index.js +562 -85
  91. package/dist/src/index.js.map +1 -1
  92. package/dist/src/output/model.d.ts +1 -34
  93. package/dist/src/output/model.js +1 -144
  94. package/dist/src/output/model.js.map +1 -1
  95. package/dist/src/output/rebuild-progress.js +0 -3
  96. package/dist/src/output/rebuild-progress.js.map +1 -1
  97. package/dist/src/portable/commands.d.ts +4 -0
  98. package/dist/src/portable/commands.js +61 -4
  99. package/dist/src/portable/commands.js.map +1 -1
  100. package/dist/src/portable/materializer.d.ts +3 -0
  101. package/dist/src/portable/materializer.js +61 -10
  102. package/dist/src/portable/materializer.js.map +1 -1
  103. package/dist/src/tui/catalog-generation.d.ts +56 -0
  104. package/dist/src/tui/catalog-generation.js +244 -0
  105. package/dist/src/tui/catalog-generation.js.map +1 -0
  106. package/dist/src/tui/console-app-v4.d.ts +1 -1
  107. package/dist/src/tui/console-app-v4.js +446 -126
  108. package/dist/src/tui/console-app-v4.js.map +1 -1
  109. package/dist/src/tui/controller-runtime.d.ts +8 -2
  110. package/dist/src/tui/controller-runtime.js +606 -92
  111. package/dist/src/tui/controller-runtime.js.map +1 -1
  112. package/dist/src/tui/controller.d.ts +71 -6
  113. package/dist/src/tui/controller.js +377 -83
  114. package/dist/src/tui/controller.js.map +1 -1
  115. package/dist/src/tui/index.d.ts +1 -0
  116. package/dist/src/tui/index.js +1 -0
  117. package/dist/src/tui/index.js.map +1 -1
  118. package/dist/src/tui/input-display.d.ts +8 -0
  119. package/dist/src/tui/input-display.js +36 -0
  120. package/dist/src/tui/input-display.js.map +1 -0
  121. package/dist/src/tui/model.d.ts +27 -7
  122. package/dist/src/tui/model.js +273 -65
  123. package/dist/src/tui/model.js.map +1 -1
  124. package/dist/src/tui/router.d.ts +26 -0
  125. package/dist/src/tui/router.js.map +1 -1
  126. package/dist/src/tui/source-ref-presets.d.ts +3 -0
  127. package/dist/src/tui/source-ref-presets.js +11 -0
  128. package/dist/src/tui/source-ref-presets.js.map +1 -0
  129. package/dist/src/tui/views.js +31 -3
  130. package/dist/src/tui/views.js.map +1 -1
  131. package/dist/src/types.d.ts +90 -6
  132. package/dist/src/types.js.map +1 -1
  133. package/dist/src/utils/agent-version.d.ts +3 -0
  134. package/dist/src/utils/agent-version.js +13 -5
  135. package/dist/src/utils/agent-version.js.map +1 -1
  136. package/dist/src/utils/aw-home-mutation-lock.d.ts +1 -0
  137. package/dist/src/utils/aw-home-mutation-lock.js +32 -4
  138. package/dist/src/utils/aw-home-mutation-lock.js.map +1 -1
  139. package/dist/src/utils/bundle-integrity.d.ts +0 -1
  140. package/dist/src/utils/bundle-integrity.js +0 -25
  141. package/dist/src/utils/bundle-integrity.js.map +1 -1
  142. package/dist/src/utils/bundle-layout.js +8 -6
  143. package/dist/src/utils/bundle-layout.js.map +1 -1
  144. package/dist/src/utils/catalog-digests.js +13 -2
  145. package/dist/src/utils/catalog-digests.js.map +1 -1
  146. package/dist/src/utils/catalog-generation-error.d.ts +12 -0
  147. package/dist/src/utils/catalog-generation-error.js +16 -0
  148. package/dist/src/utils/catalog-generation-error.js.map +1 -0
  149. package/dist/src/utils/catalog-generation-resolver.d.ts +13 -0
  150. package/dist/src/utils/catalog-generation-resolver.js +129 -0
  151. package/dist/src/utils/catalog-generation-resolver.js.map +1 -0
  152. package/dist/src/utils/catalog-generation-service.d.ts +52 -0
  153. package/dist/src/utils/catalog-generation-service.js +620 -0
  154. package/dist/src/utils/catalog-generation-service.js.map +1 -0
  155. package/dist/src/utils/catalog-generation-state.d.ts +13 -0
  156. package/dist/src/utils/catalog-generation-state.js +201 -0
  157. package/dist/src/utils/catalog-generation-state.js.map +1 -0
  158. package/dist/src/utils/catalog-generation-store.d.ts +44 -0
  159. package/dist/src/utils/catalog-generation-store.js +387 -0
  160. package/dist/src/utils/catalog-generation-store.js.map +1 -0
  161. package/dist/src/utils/catalog-manifest-v5.d.ts +5 -0
  162. package/dist/src/utils/{catalog-manifest-v4.js → catalog-manifest-v5.js} +39 -35
  163. package/dist/src/utils/{catalog-manifest-v4.js.map → catalog-manifest-v5.js.map} +1 -1
  164. package/dist/src/utils/catalog-operation-context.d.ts +28 -0
  165. package/dist/src/utils/catalog-operation-context.js +242 -0
  166. package/dist/src/utils/catalog-operation-context.js.map +1 -0
  167. package/dist/src/utils/catalog-public-error.d.ts +7 -3
  168. package/dist/src/utils/catalog-public-error.js +20 -4
  169. package/dist/src/utils/catalog-public-error.js.map +1 -1
  170. package/dist/src/utils/catalog-snapshot.d.ts +5 -3
  171. package/dist/src/utils/catalog-snapshot.js +11 -3
  172. package/dist/src/utils/catalog-snapshot.js.map +1 -1
  173. package/dist/src/utils/catalog-source-cache.d.ts +1 -1
  174. package/dist/src/utils/catalog-source-cache.js +37 -12
  175. package/dist/src/utils/catalog-source-cache.js.map +1 -1
  176. package/dist/src/utils/catalog-source-identity.d.ts +1 -0
  177. package/dist/src/utils/catalog-source-identity.js +21 -2
  178. package/dist/src/utils/catalog-source-identity.js.map +1 -1
  179. package/dist/src/utils/catalog-sources.d.ts +1 -0
  180. package/dist/src/utils/catalog-sources.js +30 -11
  181. package/dist/src/utils/catalog-sources.js.map +1 -1
  182. package/dist/src/utils/codex-config.js +4 -4
  183. package/dist/src/utils/codex-config.js.map +1 -1
  184. package/dist/src/utils/codex-manager.d.ts +33 -0
  185. package/dist/src/utils/codex-manager.js +656 -0
  186. package/dist/src/utils/codex-manager.js.map +1 -0
  187. package/dist/src/utils/codex-skill-staging.d.ts +2 -0
  188. package/dist/src/utils/codex-skill-staging.js.map +1 -1
  189. package/dist/src/utils/dynamic-skill-tree.d.ts +4 -0
  190. package/dist/src/utils/dynamic-skill-tree.js +35 -5
  191. package/dist/src/utils/dynamic-skill-tree.js.map +1 -1
  192. package/dist/src/utils/git-catalog-provider.js +10 -25
  193. package/dist/src/utils/git-catalog-provider.js.map +1 -1
  194. package/dist/src/utils/lifecycle-active-store.d.ts +0 -28
  195. package/dist/src/utils/lifecycle-active-store.js +35 -247
  196. package/dist/src/utils/lifecycle-active-store.js.map +1 -1
  197. package/dist/src/utils/multi-source-catalog.d.ts +3 -0
  198. package/dist/src/utils/multi-source-catalog.js +120 -10
  199. package/dist/src/utils/multi-source-catalog.js.map +1 -1
  200. package/dist/src/utils/native-cli.d.ts +15 -6
  201. package/dist/src/utils/native-cli.js +31 -39
  202. package/dist/src/utils/native-cli.js.map +1 -1
  203. package/dist/src/utils/orphan-marketplace-cleanup.js +0 -3
  204. package/dist/src/utils/orphan-marketplace-cleanup.js.map +1 -1
  205. package/dist/src/utils/ownership.d.ts +10 -1
  206. package/dist/src/utils/ownership.js +52 -24
  207. package/dist/src/utils/ownership.js.map +1 -1
  208. package/dist/src/utils/path-catalog-provider.js +12 -8
  209. package/dist/src/utils/path-catalog-provider.js.map +1 -1
  210. package/dist/src/utils/plugin-config-write.js +18 -35
  211. package/dist/src/utils/plugin-config-write.js.map +1 -1
  212. package/dist/src/utils/plugin-config.d.ts +1 -12
  213. package/dist/src/utils/plugin-config.js +107 -226
  214. package/dist/src/utils/plugin-config.js.map +1 -1
  215. package/dist/src/utils/plugin-scripts.d.ts +1 -1
  216. package/dist/src/utils/plugin-scripts.js +1 -1
  217. package/dist/src/utils/plugin-scripts.js.map +1 -1
  218. package/dist/src/utils/state-paths.js +7 -2
  219. package/dist/src/utils/state-paths.js.map +1 -1
  220. package/dist/src/utils/target-eligibility.d.ts +7 -2
  221. package/dist/src/utils/target-eligibility.js +6 -3
  222. package/dist/src/utils/target-eligibility.js.map +1 -1
  223. package/package.json +4 -3
  224. package/dist/authoring/scripts/check-plugin-versions.d.mts +0 -2
  225. package/dist/authoring/scripts/check-plugin-versions.mjs +0 -5
  226. package/dist/authoring/scripts/check-plugin-versions.mjs.map +0 -1
  227. package/dist/src/commands/status-v4.js.map +0 -1
  228. package/dist/src/commands/status.d.ts +0 -93
  229. package/dist/src/commands/status.js +0 -442
  230. package/dist/src/commands/status.js.map +0 -1
  231. package/dist/src/utils/active-marketplace-runtime-lock.d.ts +0 -12
  232. package/dist/src/utils/active-marketplace-runtime-lock.js +0 -133
  233. package/dist/src/utils/active-marketplace-runtime-lock.js.map +0 -1
  234. package/dist/src/utils/catalog-manifest-v3.d.ts +0 -2
  235. package/dist/src/utils/catalog-manifest-v3.js +0 -3
  236. package/dist/src/utils/catalog-manifest-v3.js.map +0 -1
  237. package/dist/src/utils/catalog-manifest-v4.d.ts +0 -5
@@ -1,5 +1,5 @@
1
1
  import type { PlatformName, PluginConfigFieldType, PluginConfigPresentationPreset, PluginConfigSchema, Scope } from '../types.js';
2
- import type { StatusV4Payload, StatusV4PluginSummary, StatusV4Target, StatusV4Component, StatusTargetRevision, TargetRevisionState } from '../commands/status-v4.js';
2
+ import type { StatusV5Payload, StatusV5PluginSummary, StatusV5Target, StatusV5Component, StatusTargetRevision, TargetRevisionState } from '../commands/status-v5.js';
3
3
  import type { ResolvedConfigRead } from '../utils/plugin-config.js';
4
4
  import { type DiagnosticSummaryViewModel } from './diagnostics.js';
5
5
  export type SourceHealthState = 'ready' | 'cache' | 'path' | 'checking' | 'degraded' | 'unavailable';
@@ -54,13 +54,19 @@ export interface PluginListItemViewModel {
54
54
  supportedPlatforms: PlatformName[];
55
55
  installedPlacements: PlatformPlacementSummary[];
56
56
  aggregateStatus: 'available' | 'installed' | 'needsAttention' | 'unavailable';
57
+ primaryAttention?: {
58
+ severity: 'warning' | 'error';
59
+ code: string;
60
+ message: string;
61
+ };
57
62
  portableSkills: boolean;
63
+ missingCapabilities?: string[];
58
64
  dependencySummary?: PluginDependencySummaryViewModel;
59
65
  technicalComponents: Array<{
60
66
  platform: PlatformName;
61
67
  scope: Scope;
62
68
  key: string;
63
- state: StatusV4Component['state'];
69
+ state: StatusV5Component['state'];
64
70
  errorCode?: string;
65
71
  }>;
66
72
  }
@@ -157,6 +163,8 @@ export interface ConfigFieldViewModel {
157
163
  sourceLabel: string;
158
164
  effectiveDisplayValue: string;
159
165
  effectiveSourceLabel: string;
166
+ fallbackDisplayValue?: string;
167
+ fallbackSourceLabel?: string;
160
168
  value?: string | number | boolean;
161
169
  effectiveValue?: string | number | boolean;
162
170
  defaultValue?: string | number | boolean;
@@ -190,7 +198,8 @@ export interface ConfigPageViewModel {
190
198
  presets: ConfigPresetViewModel[];
191
199
  storedCount: number;
192
200
  }
193
- export type UserIssueCategory = 'incompleteInstallation' | 'sourceDegraded' | 'sourceUnavailable' | 'sourceMissing' | 'sourceIdentityChanged' | 'requiredConfigMissing' | 'scopeConflict' | 'dependencyMissing' | 'dependencyNotReady' | 'dependencyTargetUnsupported' | 'dependencyStillRequired' | 'dependencyGraphInvalid' | 'legacyState' | 'diagnostic';
201
+ export type UserIssueCategory = 'incompleteInstallation' | 'artifactCollision' | 'sourceDegraded' | 'sourceUnavailable' | 'sourceMissing' | 'sourceIdentityChanged' | 'requiredConfigMissing' | 'scopeConflict' | 'dependencyMissing' | 'dependencyNotReady' | 'dependencyTargetUnsupported' | 'dependencyStillRequired' | 'dependencyGraphInvalid' | 'legacyState' | 'diagnostic';
202
+ export type UserIssueGroup = 'sourceRemoved' | 'artifactCollision' | 'sourceUnavailable' | 'dependency' | 'scope' | 'config' | 'installation' | 'diagnostic';
194
203
  export type UserIssueActionId = 'reinstall' | 'cleanup' | 'remove' | 'refreshSource' | 'continueWithCache' | 'editSource' | 'retryLater' | 'reAddSource' | 'viewSourceChange' | 'openConfig' | 'keepUserScope' | 'keepProjectScope' | 'viewTechnical' | 'manualMigration' | 'installDependency' | 'reinstallDependency' | 'viewDependencyIssue' | 'viewDependencies';
195
204
  export interface UserIssueActionViewModel {
196
205
  id: UserIssueActionId;
@@ -202,10 +211,11 @@ export interface UserIssueActionViewModel {
202
211
  project?: 'current' | 'other' | null;
203
212
  writeAction?: 'install' | 'upgrade' | 'reinstall' | 'cleanup';
204
213
  }
205
- export type TargetIssueRootCode = 'partial' | 'sourceMissing' | 'sourceChanged' | 'catalogSourceUnavailable' | 'bundleUnavailable' | 'dependencyMissing' | 'dependencyNotReady' | 'dependencyTargetUnsupported' | 'dependencyStillRequired' | 'dependencyGraphInvalid' | 'targetDiagnostic';
214
+ export type TargetIssueRootCode = 'partial' | 'artifactCollision' | 'sourceMissing' | 'sourceChanged' | 'catalogSourceUnavailable' | 'bundleUnavailable' | 'dependencyMissing' | 'dependencyNotReady' | 'dependencyTargetUnsupported' | 'dependencyStillRequired' | 'dependencyGraphInvalid' | 'targetDiagnostic';
206
215
  export interface UserIssueViewModel {
207
216
  issueId: string;
208
217
  category: UserIssueCategory;
218
+ group: UserIssueGroup;
209
219
  title: string;
210
220
  explanation: string;
211
221
  impact: string[];
@@ -280,14 +290,14 @@ export interface PortableSkillSelectionViewModel {
280
290
  };
281
291
  canContinue: boolean;
282
292
  }
283
- export declare function projectPlatformPlacement(platform: PlatformName, targets: StatusV4Target[], revisions?: StatusTargetRevision[]): PlatformPlacementSummary;
293
+ export declare function projectPlatformPlacement(platform: PlatformName, targets: StatusV5Target[], revisions?: StatusTargetRevision[]): PlatformPlacementSummary;
284
294
  export declare function buildPluginPreviewActions(plugin: PluginListItemViewModel): PluginMenuAction[];
285
295
  export declare function buildPluginDetailActions(plugin: PluginListItemViewModel): PluginMenuAction[];
286
296
  export declare function buildPlatformActions(plugin: PluginListItemViewModel, platform: PlatformName): PluginMenuAction[];
287
297
  export declare function hasInstalledPlacement(plugin: PluginListItemViewModel): boolean;
288
298
  export declare function buildTuiViewModel(options: {
289
- status: StatusV4Payload;
290
- pluginSummaries: StatusV4PluginSummary[];
299
+ status: StatusV5Payload;
300
+ pluginSummaries: StatusV5PluginSummary[];
291
301
  targetRevisions?: StatusTargetRevision[];
292
302
  sourceHealth?: ReadonlyMap<string, SourceHealthViewModel>;
293
303
  sourceDetails?: SourceDetailViewModel[];
@@ -298,6 +308,11 @@ export declare function buildConfigGroups(options: {
298
308
  schema: PluginConfigSchema;
299
309
  read: ResolvedConfigRead;
300
310
  effectiveRead?: ResolvedConfigRead;
311
+ layerReads?: {
312
+ user: ResolvedConfigRead;
313
+ project: ResolvedConfigRead;
314
+ local: ResolvedConfigRead;
315
+ };
301
316
  dirtyKeys?: ReadonlySet<string>;
302
317
  }): ConfigGroupViewModel[];
303
318
  export declare function buildConfigPage(options: {
@@ -305,4 +320,9 @@ export declare function buildConfigPage(options: {
305
320
  schema: PluginConfigSchema;
306
321
  read: ResolvedConfigRead;
307
322
  effectiveRead?: ResolvedConfigRead;
323
+ layerReads?: {
324
+ user: ResolvedConfigRead;
325
+ project: ResolvedConfigRead;
326
+ local: ResolvedConfigRead;
327
+ };
308
328
  }): ConfigPageViewModel;
@@ -190,7 +190,8 @@ function targetIssues(payload) {
190
190
  for (const target of payload.targets) {
191
191
  const key = `${target.pluginId}\0${target.platform}`;
192
192
  byPlacement.set(key, [...(byPlacement.get(key) ?? []), target]);
193
- if (target.state !== 'partial' && target.state !== 'error')
193
+ if (target.state !== 'partial' && target.state !== 'error'
194
+ && !target.errors.some((error) => error.code === 'artifactCollision'))
194
195
  continue;
195
196
  const codes = new Set(target.errors.map((error) => error.code));
196
197
  const dependencyCodes = [
@@ -200,41 +201,66 @@ function targetIssues(payload) {
200
201
  'dependencyStillRequired',
201
202
  'dependencyGraphInvalid',
202
203
  ];
203
- const dependencyRoots = [...new Map(target.errors.flatMap((error) => {
204
- if (!dependencyCodes.includes(error.code))
205
- return [];
206
- const code = error.code;
207
- const dependencyPluginId = dependencyPluginIdFromMessage(error.message);
208
- return [[`${code}\0${dependencyPluginId ?? ''}`, {
209
- code,
210
- category: code,
211
- mergeEligible: false,
212
- error,
213
- dependencyPluginId,
214
- }]];
215
- })).values()];
216
- const roots = dependencyRoots.length > 0
217
- ? dependencyRoots
218
- : target.state === 'partial'
219
- ? [{ code: 'partial', category: 'incompleteInstallation', mergeEligible: false }]
220
- : codes.has('sourceMissing')
221
- ? [{ code: 'sourceMissing', category: 'sourceMissing', mergeEligible: false }]
222
- : codes.has('sourceChanged')
223
- ? [{ code: 'sourceChanged', category: 'sourceIdentityChanged', mergeEligible: false }]
224
- : [
204
+ const dependencyRootMap = new Map();
205
+ for (const error of target.errors) {
206
+ if (!dependencyCodes.includes(error.code))
207
+ continue;
208
+ if (error.rootIssueCode === 'artifactCollision') {
209
+ dependencyRootMap.set(error.rootIssueId ?? `artifactCollision\0${error.dependencyPluginId ?? ''}`, {
210
+ code: 'artifactCollision',
211
+ category: 'artifactCollision',
212
+ mergeEligible: false,
213
+ error,
214
+ dependencyPluginId: error.dependencyPluginId,
215
+ });
216
+ continue;
217
+ }
218
+ const code = error.code;
219
+ const dependencyPluginId = error.dependencyPluginId ?? dependencyPluginIdFromMessage(error.message);
220
+ dependencyRootMap.set(`${code}\0${dependencyPluginId ?? ''}`, {
221
+ code,
222
+ category: code,
223
+ mergeEligible: false,
224
+ error,
225
+ dependencyPluginId,
226
+ });
227
+ }
228
+ const dependencyRoots = [...dependencyRootMap.values()];
229
+ const directCollision = target.errors.find((error) => error.code === 'artifactCollision');
230
+ const projectedCollisionRoots = dependencyRoots.filter((root) => root.code === 'artifactCollision');
231
+ const ordinaryDependencyRoots = dependencyRoots.filter((root) => root.code !== 'artifactCollision');
232
+ const roots = codes.has('sourceMissing')
233
+ ? [{ code: 'sourceMissing', category: 'sourceMissing', mergeEligible: false }]
234
+ : directCollision || projectedCollisionRoots.length > 0
235
+ ? [{
236
+ code: 'artifactCollision',
237
+ category: 'artifactCollision',
238
+ mergeEligible: false,
239
+ error: directCollision ?? projectedCollisionRoots[0].error,
240
+ dependencyPluginId: projectedCollisionRoots[0]?.dependencyPluginId,
241
+ }]
242
+ : codes.has('sourceChanged')
243
+ ? [{ code: 'sourceChanged', category: 'sourceIdentityChanged', mergeEligible: false }]
244
+ : codes.has('catalogSourceUnavailable') || codes.has('bundleUnavailable')
245
+ ? [
225
246
  ...(codes.has('catalogSourceUnavailable')
226
247
  ? [{ code: 'catalogSourceUnavailable', category: 'sourceUnavailable', mergeEligible: true }]
227
248
  : []),
228
249
  ...(codes.has('bundleUnavailable')
229
250
  ? [{ code: 'bundleUnavailable', category: 'sourceUnavailable', mergeEligible: false }]
230
251
  : []),
231
- ...(!codes.has('catalogSourceUnavailable') && !codes.has('bundleUnavailable')
232
- ? [{ code: 'targetDiagnostic', category: 'diagnostic', mergeEligible: false }]
233
- : []),
234
- ];
252
+ ]
253
+ : ordinaryDependencyRoots.length > 0
254
+ ? ordinaryDependencyRoots
255
+ : target.state === 'partial'
256
+ ? [{ code: 'partial', category: 'incompleteInstallation', mergeEligible: false }]
257
+ : [
258
+ { code: 'targetDiagnostic', category: 'diagnostic', mergeEligible: false },
259
+ ];
235
260
  for (const root of roots) {
236
261
  const rootError = root.error ?? target.errors.find((error) => error.code === root.code);
237
262
  const dependencyPluginId = root.dependencyPluginId
263
+ ?? rootError?.dependencyPluginId
238
264
  ?? (rootError ? dependencyPluginIdFromMessage(rootError.message) : undefined);
239
265
  const dependencyCategory = root.category.startsWith('dependency');
240
266
  const actions = root.category === 'dependencyMissing'
@@ -259,60 +285,71 @@ function targetIssues(payload) {
259
285
  { id: 'viewDependencies', label: '查看依赖关系' },
260
286
  { id: 'viewTechnical', label: '技术详情' },
261
287
  ]
262
- : root.category === 'incompleteInstallation'
288
+ : root.category === 'artifactCollision'
263
289
  ? [
264
- { id: 'reinstall', label: '重新安装', description: '保留插件设置,重新生成缺失内容' },
265
- { id: 'remove', label: '移除安装', description: '保留插件设置' },
266
- { id: 'viewTechnical', label: '技术详情' },
290
+ { id: 'viewTechnical', label: '查看冲突原因' },
291
+ { id: 'retryLater', label: '处理冲突后重试' },
267
292
  ]
268
- : root.category === 'sourceMissing'
293
+ : root.category === 'incompleteInstallation'
269
294
  ? [
270
- { id: 'reAddSource', label: '重新添加同一来源', description: '保留来源 ID;来源类型和位置由你选择' },
295
+ { id: 'reinstall', label: '重新安装', description: '保留插件设置,重新生成缺失内容' },
296
+ { id: 'remove', label: '移除安装', description: '保留插件设置' },
271
297
  { id: 'viewTechnical', label: '技术详情' },
272
298
  ]
273
- : root.category === 'sourceIdentityChanged'
299
+ : root.category === 'sourceMissing'
274
300
  ? [
275
- { id: 'viewSourceChange', label: '查看来源变更', description: '不会自动覆盖现场状态' },
301
+ { id: 'cleanup', label: '清理已安装内容', description: '只清理 matching owner 的现场内容;保留插件设置', writeAction: 'cleanup' },
302
+ { id: 'reAddSource', label: '重新添加同一来源', description: '保留来源 ID;来源类型和位置由你选择' },
276
303
  { id: 'viewTechnical', label: '技术详情' },
277
304
  ]
278
- : root.category === 'sourceUnavailable'
305
+ : root.category === 'sourceIdentityChanged'
279
306
  ? [
280
- ...(root.code === 'bundleUnavailable' ? [{
281
- id: 'cleanup',
282
- label: '清理已安装内容',
283
- description: '只清理 AW 管理的现场内容;保留插件设置',
284
- writeAction: 'cleanup',
285
- }] : []),
286
- { id: 'editSource', label: '查看来源', description: root.code === 'bundleUnavailable' ? '检查当前 Catalog 或稍后重试' : '修复来源配置或稍后重试' },
307
+ { id: 'viewSourceChange', label: '查看来源变更', description: '不会自动覆盖现场状态' },
287
308
  { id: 'viewTechnical', label: '技术详情' },
288
309
  ]
289
- : [{ id: 'viewTechnical', label: '技术详情' }, { id: 'retryLater', label: '稍后重试' }];
290
- const issueId = `target:${target.pluginId}:${target.platform}:${target.scope}:${target.state}${roots.length > 1 ? `:${root.code}` : ''}${dependencyPluginId ? `:${dependencyPluginId}` : ''}`;
310
+ : root.category === 'sourceUnavailable'
311
+ ? [
312
+ ...(root.code === 'bundleUnavailable' ? [{
313
+ id: 'cleanup',
314
+ label: '清理已安装内容',
315
+ description: '只清理 AW 管理的现场内容;保留插件设置',
316
+ writeAction: 'cleanup',
317
+ }] : []),
318
+ { id: 'editSource', label: '查看来源', description: root.code === 'bundleUnavailable' ? '检查当前 Catalog 或稍后重试' : '修复来源配置或稍后重试' },
319
+ { id: 'viewTechnical', label: '技术详情' },
320
+ ]
321
+ : [{ id: 'viewTechnical', label: '技术详情' }, { id: 'retryLater', label: '稍后重试' }];
322
+ const issueId = rootError?.rootIssueId
323
+ ?? `target:${target.pluginId}:${target.platform}:${target.scope}:${target.state}${roots.length > 1 ? `:${root.code}` : ''}${dependencyPluginId ? `:${dependencyPluginId}` : ''}`;
291
324
  const bundleUnavailable = root.code === 'bundleUnavailable';
292
325
  issues.push({
293
326
  issueId,
294
327
  category: root.category,
295
328
  rootCode: root.code,
296
329
  mergeEligible: root.mergeEligible,
297
- title: `${target.pluginId} · ${target.platform === 'codex' ? 'Codex' : 'Claude Code'} · ${dependencyCategory ? {
330
+ title: `${target.pluginId} · ${target.platform === 'codex' ? 'Codex' : 'Claude Code'} · ${root.category === 'artifactCollision' ? '输出冲突' : dependencyCategory ? {
298
331
  dependencyMissing: '缺少依赖',
299
332
  dependencyNotReady: '依赖安装不完整',
300
333
  dependencyTargetUnsupported: '依赖目标不兼容',
301
334
  dependencyStillRequired: '依赖仍被使用',
302
335
  dependencyGraphInvalid: '依赖关系无效',
303
336
  }[root.category] : target.state === 'partial' ? '安装不完整' : bundleUnavailable ? '当前 Catalog 不再包含此插件' : '检查失败'}`,
304
- explanation: dependencyCategory
305
- ? dependencyPluginId
306
- ? `${dependencyPluginId} 导致当前依赖检查不能通过。`
307
- : '当前依赖检查不能安全通过。'
308
- : target.state === 'partial'
309
- ? '必要内容缺失,插件可能不能稳定运行。'
337
+ explanation: root.category === 'artifactCollision'
338
+ ? '目标位置已有不属于当前插件的内容。AW 不会覆盖或删除这些内容。'
339
+ : dependencyCategory
340
+ ? dependencyPluginId
341
+ ? `${dependencyPluginId} 导致当前依赖检查不能通过。`
342
+ : '当前依赖检查不能安全通过。'
343
+ : target.state === 'partial'
344
+ ? '必要内容缺失,插件可能不能稳定运行。'
345
+ : bundleUnavailable
346
+ ? '当前 Catalog 不再包含此插件,但仍发现 AW 管理的已安装内容。'
347
+ : '当前目标不能安全分类为正常安装。',
348
+ impact: [root.category === 'artifactCollision'
349
+ ? '请先移除或迁移冲突内容,然后重试安装或重新安装。'
310
350
  : bundleUnavailable
311
- ? '当前 Catalog 不再包含此插件,但仍发现 AW 管理的已安装内容。'
312
- : '当前目标不能安全分类为正常安装。',
313
- impact: [bundleUnavailable
314
- ? '可以清理可信的 AW 现场;这不表示来源缓存整体不可用。'
315
- : '写操作前需要重新检查这个目标。'],
351
+ ? '可以清理可信的 AW 现场;这不表示来源缓存整体不可用。'
352
+ : '写操作前需要重新检查这个目标。'],
316
353
  entity: { kind: 'plugin', id: target.pluginId },
317
354
  pluginId: target.pluginId,
318
355
  ...(dependencyPluginId ? { dependencyPluginId } : {}),
@@ -324,8 +361,18 @@ function targetIssues(payload) {
324
361
  technicalDetails: target.errors.length > 0
325
362
  ? target.errors.filter((error) => root.code === 'targetDiagnostic'
326
363
  || root.code === 'partial'
327
- || error.code === root.code)
328
- .map((error) => ({ code: error.code, message: '状态检查报告了这个安全错误代码。' }))
364
+ || error.code === root.code
365
+ || error.rootIssueId === issueId)
366
+ .map((error) => ({
367
+ code: error.code,
368
+ message: error.collision
369
+ ? ({
370
+ ownerMismatch: '目标由其他 owner 占用。',
371
+ unownedContent: '目标包含没有 AW owner 标记的内容。',
372
+ typeMismatch: '目标节点类型不符合预期。',
373
+ })[error.collision.reason]
374
+ : '状态检查报告了这个安全错误代码。',
375
+ }))
329
376
  : [{ code: 'targetStateError', message: '目标状态异常。' }],
330
377
  });
331
378
  }
@@ -459,6 +506,39 @@ function configIssues(pluginSummaries) {
459
506
  }];
460
507
  });
461
508
  }
509
+ function dependencyOverviewIssues(overviews, pluginSummaries, status) {
510
+ const summaryById = new Map(pluginSummaries.map((summary) => [summary.pluginId, summary]));
511
+ return overviews.flatMap((overview) => overview.blockers.flatMap((blocker) => {
512
+ if (blocker.code !== 'dependencyGraphInvalid'
513
+ && blocker.code !== 'dependencyTargetUnsupported')
514
+ return [];
515
+ if (status.targets.some((target) => target.pluginId === overview.pluginId
516
+ && target.errors.some((error) => error.code === blocker.code)))
517
+ return [];
518
+ const summary = summaryById.get(overview.pluginId);
519
+ const sourceId = overview.pluginId.slice(0, overview.pluginId.indexOf('/'));
520
+ const category = blocker.code;
521
+ return [{
522
+ issueId: `dependency:${overview.pluginId}:${blocker.code}`,
523
+ category,
524
+ rootCode: category,
525
+ mergeEligible: false,
526
+ title: `${summary?.displayName ?? summary?.pluginName ?? overview.pluginId} · ${blocker.title}`,
527
+ explanation: blocker.explanation,
528
+ impact: [category === 'dependencyGraphInvalid'
529
+ ? '修复依赖关系后才能安全计算安装顺序。'
530
+ : '当前不能在所有声明的平台上安全安装这个插件。'],
531
+ entity: { kind: 'plugin', id: overview.pluginId },
532
+ pluginId: overview.pluginId,
533
+ sourceId,
534
+ actions: [
535
+ { id: 'viewDependencies', label: '查看依赖关系' },
536
+ { id: 'viewTechnical', label: '技术详情' },
537
+ ],
538
+ technicalDetails: [{ code: blocker.code, message: blocker.explanation }],
539
+ }];
540
+ }));
541
+ }
462
542
  function enrichDependencyIssuePlacements(issues, overviews) {
463
543
  const overviewById = new Map(overviews.map((overview) => [overview.pluginId, overview]));
464
544
  return issues.map((issue) => {
@@ -602,6 +682,86 @@ function issueDiagnostic(issue, sourceDetails) {
602
682
  },
603
683
  };
604
684
  }
685
+ const issueGroupOrder = {
686
+ sourceRemoved: 0,
687
+ artifactCollision: 1,
688
+ sourceUnavailable: 2,
689
+ dependency: 3,
690
+ scope: 4,
691
+ config: 5,
692
+ installation: 6,
693
+ diagnostic: 7,
694
+ };
695
+ function issueGroup(issue) {
696
+ if (issue.category === 'sourceMissing')
697
+ return 'sourceRemoved';
698
+ if (issue.category === 'artifactCollision')
699
+ return 'artifactCollision';
700
+ if (issue.category === 'sourceUnavailable'
701
+ || issue.category === 'sourceDegraded'
702
+ || issue.category === 'sourceIdentityChanged')
703
+ return 'sourceUnavailable';
704
+ if (issue.category.startsWith('dependency'))
705
+ return 'dependency';
706
+ if (issue.category === 'scopeConflict')
707
+ return 'scope';
708
+ if (issue.category === 'requiredConfigMissing')
709
+ return 'config';
710
+ if (issue.category === 'incompleteInstallation')
711
+ return 'installation';
712
+ return 'diagnostic';
713
+ }
714
+ function primaryAttentionCode(issue) {
715
+ if (issue.category === 'requiredConfigMissing') {
716
+ return issue.requiredFields?.some((field) => field.type === 'invalid-config')
717
+ ? 'invalidConfig'
718
+ : 'requiredConfigMissing';
719
+ }
720
+ if (issue.category === 'incompleteInstallation')
721
+ return 'incompleteInstallation';
722
+ if (issue.category === 'sourceDegraded')
723
+ return 'sourceUnavailable';
724
+ if (issue.category === 'sourceIdentityChanged')
725
+ return 'sourceUnavailable';
726
+ return issue.rootCode ?? issue.category;
727
+ }
728
+ function issueReasonPriority(issue) {
729
+ const code = primaryAttentionCode(issue);
730
+ return {
731
+ sourceMissing: 0,
732
+ artifactCollision: 1,
733
+ sourceUnavailable: 2,
734
+ catalogSourceUnavailable: 2,
735
+ bundleUnavailable: 2,
736
+ dependencyGraphInvalid: 3,
737
+ dependencyTargetUnsupported: 4,
738
+ dependencyNotReady: 5,
739
+ dependencyMissing: 5,
740
+ scopeConflict: 6,
741
+ requiredConfigMissing: 7,
742
+ invalidConfig: 7,
743
+ incompleteInstallation: 8,
744
+ diagnostic: 9,
745
+ }[code] ?? 9;
746
+ }
747
+ function collapseRootIssues(issues) {
748
+ const byId = new Map();
749
+ for (const issue of issues) {
750
+ const existing = byId.get(issue.issueId);
751
+ if (!existing) {
752
+ byId.set(issue.issueId, issue);
753
+ continue;
754
+ }
755
+ const primary = issue.dependencyPluginId ? issue : existing;
756
+ byId.set(issue.issueId, {
757
+ ...primary,
758
+ impact: [...new Set([...existing.impact, ...issue.impact])],
759
+ technicalDetails: [...new Map([...existing.technicalDetails, ...issue.technicalDetails]
760
+ .map((detail) => [`${detail.code}\0${detail.message}`, detail])).values()],
761
+ });
762
+ }
763
+ return [...byId.values()];
764
+ }
605
765
  export function buildTuiViewModel(options) {
606
766
  const dependencyById = new Map((options.dependencyOverviews ?? [])
607
767
  .map((overview) => [overview.pluginId, overview]));
@@ -624,7 +784,8 @@ export function buildTuiViewModel(options) {
624
784
  const attention = placements.some((placement) => placement.state === 'scopeConflict'
625
785
  || (placement.state === 'installed' && placement.health !== 'ready'));
626
786
  const installed = placements.some((placement) => placement.state !== 'notInstalled');
627
- const unavailable = options.sourceHealth?.get(sourceId)?.state === 'unavailable';
787
+ const unavailable = options.sourceHealth?.get(sourceId)?.state === 'unavailable'
788
+ || (summary?.missingCapabilities?.length ?? 0) > 0;
628
789
  return {
629
790
  pluginId,
630
791
  sourceId,
@@ -642,6 +803,9 @@ export function buildTuiViewModel(options) {
642
803
  installedPlacements: placements,
643
804
  aggregateStatus: unavailable ? 'unavailable' : attention ? 'needsAttention' : installed ? 'installed' : 'available',
644
805
  portableSkills: options.portablePluginIds?.includes(pluginId) ?? false,
806
+ ...(summary?.missingCapabilities
807
+ ? { missingCapabilities: summary.missingCapabilities }
808
+ : {}),
645
809
  ...(dependencyById.get(pluginId)
646
810
  ? { dependencySummary: dependencyById.get(pluginId).summary }
647
811
  : summary && (summary.dependencyTotalCount ?? 0) > 0
@@ -687,24 +851,48 @@ export function buildTuiViewModel(options) {
687
851
  || !issue.sourceId || !sourceRootIds.has(issue.sourceId)),
688
852
  ...statusIssues(options.status),
689
853
  ...configIssues(options.pluginSummaries),
854
+ ...dependencyOverviewIssues(options.dependencyOverviews ?? [], options.pluginSummaries, options.status),
690
855
  ...[...(options.sourceHealth?.values() ?? [])].flatMap((health) => sourceIssue(health, targetImpactCounts.get(health.sourceId) ?? 0) ?? []),
691
856
  ], options.dependencyOverviews ?? []);
692
- const issues = issueDrafts.map((issue) => ({
857
+ const stableIssueDrafts = collapseRootIssues(issueDrafts).sort((left, right) => issueGroupOrder[issueGroup(left)] - issueGroupOrder[issueGroup(right)]
858
+ || issueReasonPriority(left) - issueReasonPriority(right)
859
+ || compareText(primaryAttentionCode(left), primaryAttentionCode(right))
860
+ || compareText(left.issueId, right.issueId));
861
+ const issues = stableIssueDrafts.map((issue) => ({
693
862
  ...issue,
863
+ group: issueGroup(issue),
694
864
  diagnostic: issueDiagnostic(issue, sourceDetails),
695
865
  }));
866
+ const pluginsWithAttention = plugins.map((plugin) => {
867
+ const primary = stableIssueDrafts.filter((issue) => issue.pluginId === plugin.pluginId
868
+ || issue.dependencyPluginId === plugin.pluginId
869
+ || issue.entity.kind === 'source' && issue.sourceId === plugin.sourceId)
870
+ .sort((left, right) => issueReasonPriority(left) - issueReasonPriority(right)
871
+ || compareText(primaryAttentionCode(left), primaryAttentionCode(right))
872
+ || compareText(left.issueId, right.issueId))[0];
873
+ if (!primary)
874
+ return plugin;
875
+ return {
876
+ ...plugin,
877
+ primaryAttention: {
878
+ severity: primary.category === 'sourceDegraded' ? 'warning' : 'error',
879
+ code: primaryAttentionCode(primary),
880
+ message: primary.explanation,
881
+ },
882
+ };
883
+ });
696
884
  return {
697
- plugins,
885
+ plugins: pluginsWithAttention,
698
886
  sourceTabs,
699
887
  sourceDetails: (options.sourceDetails ?? []).map((detail) => ({
700
888
  ...detail,
701
- pluginCount: plugins.filter((plugin) => plugin.sourceId === detail.id).length,
889
+ pluginCount: pluginsWithAttention.filter((plugin) => plugin.sourceId === detail.id).length,
702
890
  })),
703
891
  issues,
704
892
  dependencyOverviews: options.dependencyOverviews ?? [],
705
893
  home: {
706
- availablePlugins: plugins.filter((plugin) => plugin.aggregateStatus === 'available').length,
707
- installedPlugins: plugins.filter(hasInstalledPlacement).length,
894
+ availablePlugins: pluginsWithAttention.filter((plugin) => plugin.aggregateStatus === 'available').length,
895
+ installedPlugins: pluginsWithAttention.filter(hasInstalledPlacement).length,
708
896
  issueCount: issues.length,
709
897
  sourceCount: sourceTabs.length,
710
898
  cachedSourceCount: sourceTabs.filter((source) => source.state === 'cache').length,
@@ -737,6 +925,7 @@ export function buildConfigGroups(options) {
737
925
  const entryByKey = new Map(options.read.fields.map((field) => [field.key, field]));
738
926
  const effectiveEntryByKey = new Map((options.effectiveRead ?? options.read).fields.map((field) => [field.key, field]));
739
927
  const effectivePage = options.read.scope === 'effective';
928
+ const layerEntry = (layer, key) => options.layerReads?.[layer].fields.find((field) => field.key === key);
740
929
  const fieldModel = (key) => {
741
930
  const schema = options.schema.schema[key];
742
931
  const entry = entryByKey.get(key);
@@ -762,6 +951,16 @@ export function buildConfigGroups(options) {
762
951
  && effectiveEntry.effectiveValue !== undefined
763
952
  && effectiveEntry.effectiveValue !== null
764
953
  && (effectiveEntry.valueState === 'configured' || effectiveEntry.valueState === 'default');
954
+ const omittedLayer = options.read.scope === 'user'
955
+ ? 'user'
956
+ : options.read.projectLayer === 'local' ? 'local' : 'project';
957
+ const fallback = ['local', 'project', 'user']
958
+ .filter((layer) => layer !== omittedLayer)
959
+ .map((layer) => ({ layer, entry: layerEntry(layer, key) }))
960
+ .find((candidate) => candidate.entry?.storedSourceLayer !== undefined);
961
+ const fallbackValue = fallback?.entry?.storedValue ?? schema.default;
962
+ const fallbackConfigured = fallback !== undefined || schema.default !== undefined;
963
+ const fallbackSource = fallback?.layer ?? (schema.default !== undefined ? 'default' : undefined);
765
964
  return {
766
965
  key,
767
966
  title: schema.title ?? key,
@@ -788,6 +987,15 @@ export function buildConfigGroups(options) {
788
987
  value: effectiveEntry?.effectiveValue,
789
988
  }),
790
989
  effectiveSourceLabel: configSourceLabel(effectiveEntry?.sourceLayer ?? null),
990
+ ...(!effectivePage && configured ? {
991
+ fallbackDisplayValue: displayConfigValue({
992
+ privateValue,
993
+ inherited: false,
994
+ configured: fallbackConfigured,
995
+ value: fallbackValue,
996
+ }),
997
+ fallbackSourceLabel: fallbackSource ? configSourceLabel(fallbackSource) : '未设置',
998
+ } : {}),
791
999
  ...(!privateValue && selectedValue !== undefined
792
1000
  ? { value: selectedValue }
793
1001
  : {}),