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

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 (227) hide show
  1. package/dist/authoring/assets/aw-config.d.mts +1 -50
  2. package/dist/authoring/assets/aw-config.mjs +58 -928
  3. package/dist/authoring/assets/aw-config.mjs.map +1 -1
  4. package/dist/authoring/scripts/init-plugin.mjs +28 -33
  5. package/dist/authoring/scripts/init-plugin.mjs.map +1 -1
  6. package/dist/authoring/scripts/lib/plugin-version-check.d.mts +1 -0
  7. package/dist/authoring/scripts/lib/plugin-version-check.mjs +229 -8
  8. package/dist/authoring/scripts/lib/plugin-version-check.mjs.map +1 -1
  9. package/dist/authoring/scripts/validate-plugin.mjs +159 -48
  10. package/dist/authoring/scripts/validate-plugin.mjs.map +1 -1
  11. package/dist/scripts/bundle-plugins.js +18 -4
  12. package/dist/scripts/bundle-plugins.js.map +1 -1
  13. package/dist/scripts/test-plugin-scripts.d.ts +2 -0
  14. package/dist/scripts/test-plugin-scripts.js +21 -5
  15. package/dist/scripts/test-plugin-scripts.js.map +1 -1
  16. package/dist/src/commands/aw-capabilities.d.ts +1 -1
  17. package/dist/src/commands/aw-capabilities.js +1 -1
  18. package/dist/src/commands/aw-capabilities.js.map +1 -1
  19. package/dist/src/commands/catalog-dev-source.d.ts +6 -3
  20. package/dist/src/commands/catalog-dev-source.js +96 -35
  21. package/dist/src/commands/catalog-dev-source.js.map +1 -1
  22. package/dist/src/commands/catalog-publication-inspection.d.ts +1 -1
  23. package/dist/src/commands/catalog-publication-inspection.js +54 -8
  24. package/dist/src/commands/catalog-publication-inspection.js.map +1 -1
  25. package/dist/src/commands/catalog-publication-journal.js +1 -1
  26. package/dist/src/commands/catalog-publication-journal.js.map +1 -1
  27. package/dist/src/commands/catalog-source.d.ts +19 -4
  28. package/dist/src/commands/catalog-source.js +121 -12
  29. package/dist/src/commands/catalog-source.js.map +1 -1
  30. package/dist/src/commands/catalog-store.d.ts +26 -7
  31. package/dist/src/commands/catalog-store.js +361 -42
  32. package/dist/src/commands/catalog-store.js.map +1 -1
  33. package/dist/src/commands/console.js +28 -17
  34. package/dist/src/commands/console.js.map +1 -1
  35. package/dist/src/commands/operation-plan.d.ts +2 -1
  36. package/dist/src/commands/operation-plan.js +24 -0
  37. package/dist/src/commands/operation-plan.js.map +1 -1
  38. package/dist/src/commands/operation-planner.d.ts +2 -2
  39. package/dist/src/commands/operation-planner.js +22 -20
  40. package/dist/src/commands/operation-planner.js.map +1 -1
  41. package/dist/src/commands/options.d.ts +2 -2
  42. package/dist/src/commands/options.js +18 -4
  43. package/dist/src/commands/options.js.map +1 -1
  44. package/dist/src/commands/plugin-capabilities.js +2 -2
  45. package/dist/src/commands/plugin-capabilities.js.map +1 -1
  46. package/dist/src/commands/rebuild-command.d.ts +19 -0
  47. package/dist/src/commands/rebuild-command.js +828 -283
  48. package/dist/src/commands/rebuild-command.js.map +1 -1
  49. package/dist/src/commands/rebuild-integration.d.ts +25 -47
  50. package/dist/src/commands/rebuild-integration.js +1176 -1016
  51. package/dist/src/commands/rebuild-integration.js.map +1 -1
  52. package/dist/src/commands/rebuild-operations.d.ts +50 -12
  53. package/dist/src/commands/rebuild-operations.js +207 -101
  54. package/dist/src/commands/rebuild-operations.js.map +1 -1
  55. package/dist/src/commands/status-v6.d.ts +21 -2
  56. package/dist/src/commands/status-v6.js +163 -31
  57. package/dist/src/commands/status-v6.js.map +1 -1
  58. package/dist/src/commands/sync-command.d.ts +17 -0
  59. package/dist/src/commands/sync-command.js +45 -37
  60. package/dist/src/commands/sync-command.js.map +1 -1
  61. package/dist/src/commands/write-commands.d.ts +5 -0
  62. package/dist/src/commands/write-commands.js +50 -3
  63. package/dist/src/commands/write-commands.js.map +1 -1
  64. package/dist/src/generators/local-plugin.js +14 -4
  65. package/dist/src/generators/local-plugin.js.map +1 -1
  66. package/dist/src/index.js +260 -91
  67. package/dist/src/index.js.map +1 -1
  68. package/dist/src/output/command-receipt.js +1 -3
  69. package/dist/src/output/command-receipt.js.map +1 -1
  70. package/dist/src/output/rebuild-progress.js +1 -3
  71. package/dist/src/output/rebuild-progress.js.map +1 -1
  72. package/dist/src/portable/materializer.js +10 -8
  73. package/dist/src/portable/materializer.js.map +1 -1
  74. package/dist/src/tui/catalog-generation.js +41 -1
  75. package/dist/src/tui/catalog-generation.js.map +1 -1
  76. package/dist/src/tui/catalog-sources/session.d.ts +1 -0
  77. package/dist/src/tui/catalog-sources/session.js +16 -3
  78. package/dist/src/tui/catalog-sources/session.js.map +1 -1
  79. package/dist/src/tui/catalog-sources/types.d.ts +3 -2
  80. package/dist/src/tui/components.d.ts +4 -0
  81. package/dist/src/tui/components.js +36 -24
  82. package/dist/src/tui/components.js.map +1 -1
  83. package/dist/src/tui/console-app-v4.d.ts +13 -4
  84. package/dist/src/tui/console-app-v4.js +2065 -857
  85. package/dist/src/tui/console-app-v4.js.map +1 -1
  86. package/dist/src/tui/controller-runtime.js +731 -62
  87. package/dist/src/tui/controller-runtime.js.map +1 -1
  88. package/dist/src/tui/controller.d.ts +156 -10
  89. package/dist/src/tui/controller.js +1187 -163
  90. package/dist/src/tui/controller.js.map +1 -1
  91. package/dist/src/tui/diagnostic-projection.d.ts +22 -0
  92. package/dist/src/tui/diagnostic-projection.js +437 -0
  93. package/dist/src/tui/diagnostic-projection.js.map +1 -0
  94. package/dist/src/tui/diagnostics.d.ts +1 -1
  95. package/dist/src/tui/diagnostics.js +7 -2
  96. package/dist/src/tui/diagnostics.js.map +1 -1
  97. package/dist/src/tui/glossary.d.ts +23 -0
  98. package/dist/src/tui/glossary.js +42 -0
  99. package/dist/src/tui/glossary.js.map +1 -0
  100. package/dist/src/tui/index.d.ts +4 -1
  101. package/dist/src/tui/index.js +4 -1
  102. package/dist/src/tui/index.js.map +1 -1
  103. package/dist/src/tui/keys.d.ts +44 -0
  104. package/dist/src/tui/keys.js +43 -15
  105. package/dist/src/tui/keys.js.map +1 -1
  106. package/dist/src/tui/lifecycle-action-view.d.ts +6 -0
  107. package/dist/src/tui/lifecycle-action-view.js +34 -0
  108. package/dist/src/tui/lifecycle-action-view.js.map +1 -0
  109. package/dist/src/tui/model.d.ts +12 -2
  110. package/dist/src/tui/model.js +128 -52
  111. package/dist/src/tui/model.js.map +1 -1
  112. package/dist/src/tui/operation-diagnostic-screens.d.ts +21 -0
  113. package/dist/src/tui/operation-diagnostic-screens.js +101 -0
  114. package/dist/src/tui/operation-diagnostic-screens.js.map +1 -0
  115. package/dist/src/tui/operation-history.d.ts +80 -0
  116. package/dist/src/tui/operation-history.js +130 -0
  117. package/dist/src/tui/operation-history.js.map +1 -0
  118. package/dist/src/tui/operation-review-planner.js +366 -99
  119. package/dist/src/tui/operation-review-planner.js.map +1 -1
  120. package/dist/src/tui/router.d.ts +82 -17
  121. package/dist/src/tui/router.js +186 -38
  122. package/dist/src/tui/router.js.map +1 -1
  123. package/dist/src/tui/screen-registry.d.ts +546 -0
  124. package/dist/src/tui/screen-registry.js +179 -0
  125. package/dist/src/tui/screen-registry.js.map +1 -0
  126. package/dist/src/tui/session-console-app.d.ts +6 -0
  127. package/dist/src/tui/session-console-app.js +13 -0
  128. package/dist/src/tui/session-console-app.js.map +1 -0
  129. package/dist/src/tui/session-host.d.ts +44 -0
  130. package/dist/src/tui/session-host.js +197 -0
  131. package/dist/src/tui/session-host.js.map +1 -0
  132. package/dist/src/types.d.ts +64 -3
  133. package/dist/src/types.js +1 -1
  134. package/dist/src/types.js.map +1 -1
  135. package/dist/src/utils/agent-version.js +1 -1
  136. package/dist/src/utils/agent-version.js.map +1 -1
  137. package/dist/src/utils/artifact-plan.d.ts +2 -2
  138. package/dist/src/utils/artifact-plan.js +8 -6
  139. package/dist/src/utils/artifact-plan.js.map +1 -1
  140. package/dist/src/utils/artifact-renderer.d.ts +2 -1
  141. package/dist/src/utils/artifact-renderer.js +139 -120
  142. package/dist/src/utils/artifact-renderer.js.map +1 -1
  143. package/dist/src/utils/artifact-request.d.ts +5 -0
  144. package/dist/src/utils/artifact-request.js +40 -0
  145. package/dist/src/utils/artifact-request.js.map +1 -1
  146. package/dist/src/utils/bundle-layout.js +4 -4
  147. package/dist/src/utils/bundle-layout.js.map +1 -1
  148. package/dist/src/utils/catalog-capability-projection.d.ts +8 -0
  149. package/dist/src/utils/catalog-capability-projection.js +14 -0
  150. package/dist/src/utils/catalog-capability-projection.js.map +1 -0
  151. package/dist/src/utils/catalog-generation-resolver.d.ts +14 -2
  152. package/dist/src/utils/catalog-generation-resolver.js +49 -27
  153. package/dist/src/utils/catalog-generation-resolver.js.map +1 -1
  154. package/dist/src/utils/catalog-generation-service.d.ts +8 -1
  155. package/dist/src/utils/catalog-generation-service.js +81 -47
  156. package/dist/src/utils/catalog-generation-service.js.map +1 -1
  157. package/dist/src/utils/catalog-generation-store.d.ts +1 -0
  158. package/dist/src/utils/catalog-generation-store.js +60 -5
  159. package/dist/src/utils/catalog-generation-store.js.map +1 -1
  160. package/dist/src/utils/catalog-operation-context.js +1 -0
  161. package/dist/src/utils/catalog-operation-context.js.map +1 -1
  162. package/dist/src/utils/catalog-public-error.js +4 -0
  163. package/dist/src/utils/catalog-public-error.js.map +1 -1
  164. package/dist/src/utils/catalog-source-impact.d.ts +3 -2
  165. package/dist/src/utils/catalog-source-impact.js +142 -20
  166. package/dist/src/utils/catalog-source-impact.js.map +1 -1
  167. package/dist/src/utils/catalog-source-references.js +95 -9
  168. package/dist/src/utils/catalog-source-references.js.map +1 -1
  169. package/dist/src/utils/catalog-sources.d.ts +1 -1
  170. package/dist/src/utils/catalog-sources.js +19 -3
  171. package/dist/src/utils/catalog-sources.js.map +1 -1
  172. package/dist/src/utils/codex-manager.js +8 -0
  173. package/dist/src/utils/codex-manager.js.map +1 -1
  174. package/dist/src/utils/codex-native-observation.d.ts +34 -1
  175. package/dist/src/utils/codex-native-observation.js +132 -0
  176. package/dist/src/utils/codex-native-observation.js.map +1 -1
  177. package/dist/src/utils/codex-reconciler.d.ts +0 -2
  178. package/dist/src/utils/codex-reconciler.js.map +1 -1
  179. package/dist/src/utils/codex-shared-native.d.ts +2 -26
  180. package/dist/src/utils/codex-shared-native.js +8 -82
  181. package/dist/src/utils/codex-shared-native.js.map +1 -1
  182. package/dist/src/utils/git-catalog-provider.d.ts +3 -0
  183. package/dist/src/utils/git-catalog-provider.js +40 -1
  184. package/dist/src/utils/git-catalog-provider.js.map +1 -1
  185. package/dist/src/utils/local-marketplace.d.ts +1 -0
  186. package/dist/src/utils/local-marketplace.js +69 -73
  187. package/dist/src/utils/local-marketplace.js.map +1 -1
  188. package/dist/src/utils/multi-source-catalog.js +1 -0
  189. package/dist/src/utils/multi-source-catalog.js.map +1 -1
  190. package/dist/src/utils/native-cli.d.ts +9 -4
  191. package/dist/src/utils/native-cli.js +280 -34
  192. package/dist/src/utils/native-cli.js.map +1 -1
  193. package/dist/src/utils/path-catalog-provider.js +2 -0
  194. package/dist/src/utils/path-catalog-provider.js.map +1 -1
  195. package/dist/src/utils/plugin-config-impact.d.ts +33 -0
  196. package/dist/src/utils/plugin-config-impact.js +298 -0
  197. package/dist/src/utils/plugin-config-impact.js.map +1 -0
  198. package/dist/src/utils/plugin-config-write.d.ts +36 -14
  199. package/dist/src/utils/plugin-config-write.js +709 -225
  200. package/dist/src/utils/plugin-config-write.js.map +1 -1
  201. package/dist/src/utils/plugin-config.d.ts +58 -4
  202. package/dist/src/utils/plugin-config.js +328 -60
  203. package/dist/src/utils/plugin-config.js.map +1 -1
  204. package/dist/src/utils/plugin-scripts.d.ts +20 -12
  205. package/dist/src/utils/plugin-scripts.js +389 -114
  206. package/dist/src/utils/plugin-scripts.js.map +1 -1
  207. package/dist/src/utils/process-tree.d.ts +2 -2
  208. package/dist/src/utils/process-tree.js +1 -1
  209. package/dist/src/utils/process-tree.js.map +1 -1
  210. package/dist/src/utils/project-boundary.d.ts +11 -1
  211. package/dist/src/utils/project-boundary.js +33 -11
  212. package/dist/src/utils/project-boundary.js.map +1 -1
  213. package/dist/src/utils/safe-operation-diagnostic.d.ts +15 -0
  214. package/dist/src/utils/safe-operation-diagnostic.js +33 -0
  215. package/dist/src/utils/safe-operation-diagnostic.js.map +1 -0
  216. package/dist/src/utils/sensitive-content.d.ts +4 -0
  217. package/dist/src/utils/sensitive-content.js +36 -0
  218. package/dist/src/utils/sensitive-content.js.map +1 -0
  219. package/dist/src/utils/windows-claude-shim.d.ts +9 -0
  220. package/dist/src/utils/windows-claude-shim.js +141 -0
  221. package/dist/src/utils/windows-claude-shim.js.map +1 -0
  222. package/dist/vitest.config.js +91 -10
  223. package/dist/vitest.config.js.map +1 -1
  224. package/package.json +9 -9
  225. package/dist/authoring/templates/aw-config-runtime.d.mts +0 -2
  226. package/dist/authoring/templates/aw-config-runtime.mjs +0 -407
  227. package/dist/authoring/templates/aw-config-runtime.mjs.map +0 -1
package/dist/src/index.js CHANGED
@@ -7,24 +7,24 @@ import { Command, CommanderError, Option } from 'commander';
7
7
  import { doctorEvalProviders } from '@lesliechan721/agent-skill-eval';
8
8
  import { initCommand } from './commands/init.js';
9
9
  import { resolveCatalogWorkspaceRoot } from './commands/catalog-workspace-resolution.js';
10
- import { addCatalogSourceCommand, explicitRefPolicy, listCatalogSources, removeCatalogSourceCommand, setPrimaryCatalogSourceCommand, updateCatalogSourceCommand, } from './commands/catalog-source.js';
10
+ import { addCatalogSourceCommand, preflightCatalogSourceMutation, explicitRefPolicy, listCatalogSources, removeCatalogSourceCommand, setPrimaryCatalogSourceCommand, updateCatalogSourceCommand, } from './commands/catalog-source.js';
11
11
  import { catalogSourceStatusCommand, syncCatalogSourceCommand, } from './commands/catalog-generation.js';
12
- import { catalogStorePrune, catalogStoreStatus } from './commands/catalog-store.js';
12
+ import { catalogStoreErrorCode, catalogStorePrune, catalogStoreStatus, } from './commands/catalog-store.js';
13
13
  import { cleanupWriteCommand as cleanupCommand, installWriteCommand as installCommand, reinstallWriteCommand as reinstallCommand, uninstallWriteCommand as uninstallCommand, } from './commands/write-commands.js';
14
14
  import { syncCommand } from './commands/sync-command.js';
15
15
  import { formatInteractiveConsoleUnavailableMessage, runConsoleController, } from './commands/console.js';
16
16
  import { runCommandWizard, toWizardCandidates, WizardExecutionError, } from './commands/wizard.js';
17
17
  import { createCliExecutionContext, emitCommandEvent, } from './commands/runtime.js';
18
18
  import { loadConsoleItemsResult, statusCommandV7 } from './commands/status-v6.js';
19
- import { normalizeUninstallCommandOptions, normalizeCleanupCommandOptions, resolveConfigReadResolution, resolveConfigWriteScope, normalizeInstallCommandOptions, normalizeReinstallCommandOptions, } from './commands/options.js';
19
+ import { normalizeUninstallCommandOptions, normalizeCleanupCommandOptions, resolveConfigReadResolution, resolveConfigWriteScope, normalizeInstallCommandOptions, normalizeReinstallCommandOptions, resolveScriptTimeoutMs, } from './commands/options.js';
20
20
  import { isCommandWarningError, } from './types.js';
21
21
  import { formatWarnings } from './output/reporter.js';
22
22
  import { redactString, redactValue } from './output/redact.js';
23
23
  import { renderShellCommand, } from './output/equivalent-command.js';
24
24
  import { buildRebuildReceiptJson, buildInitReceiptJson, renderRebuildReceipt, renderInitReceipt, } from './output/command-receipt.js';
25
25
  import { resolveCliPackageRoot } from './utils/paths.js';
26
- import { findConfigFieldEntry, listNamespacedPluginConfigStores, listPluginConfigStorePluginNames, readPluginConfigStore, renderPluginConfigValueForDisplay, resolveConfigRead, } from './utils/plugin-config.js';
27
- import { applyPluginConfigWrite, buildConfigMutationReceipt, describeResetAffectedFields, resetPluginConfigWithHelper, } from './utils/plugin-config-write.js';
26
+ import { findConfigFieldEntry, formatPluginConfigSetRecoveryCommand, listNamespacedPluginConfigStores, listPluginConfigStorePluginNames, readPluginConfigStore, renderPluginConfigValueForDisplay, resolveConfigRead, } from './utils/plugin-config.js';
27
+ import { applyPluginConfigWrite, buildConfigMutationReceipt, configWriteStateForError, describeResetAffectedFields, resetPluginConfigWithHelper, } from './utils/plugin-config-write.js';
28
28
  import { assertStrictSemVer } from './utils/manifest.js';
29
29
  import { writeCandidateEligibility } from './utils/target-eligibility.js';
30
30
  import { assertCatalogSourceReferencesSupported, inventoryLegacyConfigReferences, } from './utils/catalog-source-references.js';
@@ -269,10 +269,12 @@ function jsonConfigMutationRequest(argv) {
269
269
  };
270
270
  }
271
271
  function configMutationFailure(error, env, cwd) {
272
+ const configWrite = configWriteStateForError(error);
272
273
  if (error instanceof CommanderError) {
273
274
  return {
274
275
  code: 'invalidArguments',
275
276
  message: 'error: invalid config mutation arguments',
277
+ configWrite,
276
278
  };
277
279
  }
278
280
  const message = catalogPublicationFailure({
@@ -281,29 +283,29 @@ function configMutationFailure(error, env, cwd) {
281
283
  sensitiveRoots: [cwd],
282
284
  }).message;
283
285
  if (message.includes('Usage:'))
284
- return { code: 'invalidArguments', message };
286
+ return { code: 'invalidArguments', message, configWrite };
285
287
  const generationCode = catalogGenerationErrorCode(error);
286
288
  if (generationCode === 'catalogGenerationUnavailable'
287
289
  || generationCode === 'catalogGenerationSourceMissing') {
288
- return { code: 'catalogSourceUnavailable', message };
290
+ return { code: 'catalogSourceUnavailable', message, configWrite };
289
291
  }
290
292
  if (generationCode !== 'catalogGenerationFailed')
291
- return { code: generationCode, message };
293
+ return { code: generationCode, message, configWrite };
292
294
  const explicitCode = error?.code;
293
295
  if (typeof explicitCode === 'string' && /^[A-Za-z][A-Za-z0-9]*$/u.test(explicitCode)) {
294
- return { code: explicitCode, message };
296
+ return { code: explicitCode, message, configWrite };
295
297
  }
296
298
  if (message.includes('legacyStateUnsupported'))
297
- return { code: 'legacyStateUnsupported', message };
299
+ return { code: 'legacyStateUnsupported', message, configWrite };
298
300
  if (message.includes('sourceChanged'))
299
- return { code: 'sourceChanged', message };
301
+ return { code: 'sourceChanged', message, configWrite };
300
302
  if (message.includes('sourceMissing'))
301
- return { code: 'sourceMissing', message };
303
+ return { code: 'sourceMissing', message, configWrite };
302
304
  if (message.startsWith('Cannot resolve required catalog sources:')) {
303
- return { code: 'catalogSourceUnavailable', message };
305
+ return { code: 'catalogSourceUnavailable', message, configWrite };
304
306
  }
305
307
  const prefix = message.match(/^([A-Za-z][A-Za-z0-9]*):/u)?.[1];
306
- return { code: prefix ?? 'configMutationFailed', message };
308
+ return { code: prefix ?? 'configMutationFailed', message, configWrite };
307
309
  }
308
310
  function writeConfigMutationFailureReceipt(write, request, failure) {
309
311
  let plugin;
@@ -319,6 +321,7 @@ function writeConfigMutationFailureReceipt(write, request, failure) {
319
321
  writeJsonReceipt(write, buildConfigMutationReceipt(request.command, {
320
322
  ok: false,
321
323
  overallState: 'failed',
324
+ configWrite: failure.configWrite,
322
325
  ...(plugin ? { plugin } : {}),
323
326
  errors: [failure],
324
327
  }));
@@ -374,7 +377,7 @@ function configCommandUsage(command) {
374
377
  const argumentsByCommand = {
375
378
  list: '<plugin>',
376
379
  get: '<plugin> [key]',
377
- set: '<plugin> <field> --scope <project|user> (--value-json <json> | --preset <id>)',
380
+ set: '<plugin> <field> --scope <project|user> (--value-json <json> | --value-stdin | --preset <id>)',
378
381
  unset: '<plugin> <key>',
379
382
  reset: '<plugin> --scope <project|user> --yes',
380
383
  };
@@ -384,6 +387,13 @@ function configCommandUsage(command) {
384
387
  `Example: aw config ${command} example-plugin${command === 'set' ? ' mode --scope user --value-json \'"safe"\'' : command === 'unset' ? ' key' : command === 'reset' ? ' --scope user --yes' : ''}`,
385
388
  ].join('\n');
386
389
  }
390
+ async function readUtf8Stdin(stdin) {
391
+ const chunks = [];
392
+ for await (const chunk of stdin) {
393
+ chunks.push(typeof chunk === 'string' ? Buffer.from(chunk, 'utf8') : Buffer.from(chunk));
394
+ }
395
+ return Buffer.concat(chunks).toString('utf8');
396
+ }
387
397
  function equivalentWriteCommand(command, selection, rawOptions) {
388
398
  return shellCommand(buildEquivalentWriteCommandTokens(command, selection, rawOptions));
389
399
  }
@@ -401,7 +411,9 @@ export function buildEquivalentWriteCommandTokens(command, selection, rawOptions
401
411
  ...(command === 'install'
402
412
  ? (rawOptions.dependencyScope ?? []).flatMap((value) => ['--dependency-scope', value])
403
413
  : []),
404
- ...(command === 'cleanup' ? [] : optionTokens('--script-timeout', rawOptions.scriptTimeout)),
414
+ ...((command === 'install' || command === 'reinstall')
415
+ ? optionTokens('--script-timeout', rawOptions.scriptTimeout)
416
+ : []),
405
417
  ...(selection.plugins.length > 0 ? ['--', ...selection.plugins] : []),
406
418
  ];
407
419
  }
@@ -478,12 +490,11 @@ async function loadStoredConfigWizardCandidates(context, locations, options = {}
478
490
  continue;
479
491
  const existing = storesByPlugin.get(store.pluginId) ?? {
480
492
  sourceId: store.sourceId,
481
- sourceIdentity: store.sourceIdentity,
493
+ ...(store.binding.kind === 'source'
494
+ ? { sourceIdentity: store.binding.sourceIdentity }
495
+ : {}),
482
496
  keys: new Set(),
483
497
  };
484
- if (existing.sourceIdentity !== store.sourceIdentity) {
485
- throw new Error(`sourceChanged: ${store.pluginId} config stores have different source identities.`);
486
- }
487
498
  for (const key of keys)
488
499
  existing.keys.add(key);
489
500
  storesByPlugin.set(store.pluginId, existing);
@@ -495,7 +506,7 @@ async function loadStoredConfigWizardCandidates(context, locations, options = {}
495
506
  pluginName: pluginId,
496
507
  pluginId,
497
508
  sourceId: store.sourceId,
498
- sourceIdentity: store.sourceIdentity,
509
+ ...(store.sourceIdentity ? { sourceIdentity: store.sourceIdentity } : {}),
499
510
  targets: [],
500
511
  configKeys: [...store.keys].sort((left, right) => left.localeCompare(right)),
501
512
  }));
@@ -538,7 +549,9 @@ async function resolveStoredConfigResetIdentity(options) {
538
549
  pluginName: match.pluginName,
539
550
  pluginId: match.pluginId,
540
551
  sourceId: match.sourceId,
541
- sourceIdentity: match.sourceIdentity,
552
+ ...(match.binding.kind === 'source'
553
+ ? { sourceIdentity: match.binding.sourceIdentity }
554
+ : { logicalIdentity: match.binding.logicalIdentity }),
542
555
  };
543
556
  }
544
557
  async function resolveStoredOnlyConfigIdentity(options) {
@@ -552,12 +565,14 @@ async function resolveStoredOnlyConfigIdentity(options) {
552
565
  })))).flat().filter((store) => store.pluginId === options.selector);
553
566
  if (stores.length === 0)
554
567
  throw new Error(`Plugin "${options.selector}" does not have a namespaced config store.`);
555
- const identities = new Set(stores.map((store) => store.sourceIdentity));
556
- if (identities.size !== 1) {
557
- throw new Error(`sourceChanged: ${options.selector} config stores have different source identities.`);
568
+ const sourceBindings = stores.flatMap((store) => store.binding.kind === 'source'
569
+ ? [store.binding.sourceIdentity] : []);
570
+ const catalogBindings = stores.flatMap((store) => store.binding.kind === 'catalog'
571
+ ? [store.binding.logicalIdentity] : []);
572
+ if (new Set(sourceBindings).size > 1 || new Set(catalogBindings).size > 1) {
573
+ throw new Error(`identityMismatch: ${options.selector} config stores have different bindings.`);
558
574
  }
559
- const sourceIdentity = [...identities][0];
560
- await withResolvedMultiSourceCatalog({
575
+ const currentSource = await withResolvedMultiSourceCatalog({
561
576
  cliVersion: resolveCliVersion(),
562
577
  sourceIds: [parsed.sourceId],
563
578
  env: options.context.env,
@@ -566,16 +581,24 @@ async function resolveStoredOnlyConfigIdentity(options) {
566
581
  if (!source?.resolution) {
567
582
  throw source?.error ?? new Error(`Catalog source "${parsed.sourceId}" is unavailable.`);
568
583
  }
569
- if (source.resolution.sourceIdentity !== sourceIdentity) {
570
- throw new Error(`sourceChanged: ${options.selector} config source identity does not match the current source.`);
571
- }
584
+ return {
585
+ sourceIdentity: source.resolution.sourceIdentity,
586
+ logicalIdentity: source.resolution.logicalIdentity,
587
+ };
572
588
  },
573
589
  });
590
+ if (sourceBindings[0] && sourceBindings[0] !== currentSource.sourceIdentity) {
591
+ throw new Error(`identityMismatch: ${options.selector} user config does not match the current source identity.`);
592
+ }
593
+ if (catalogBindings[0] && catalogBindings[0] !== currentSource.logicalIdentity) {
594
+ throw new Error(`identityMismatch: ${options.selector} project config does not match the current Catalog logical identity.`);
595
+ }
574
596
  return {
575
597
  pluginName: parsed.pluginName,
576
598
  pluginId: options.selector,
577
599
  sourceId: parsed.sourceId,
578
- sourceIdentity,
600
+ sourceIdentity: currentSource.sourceIdentity,
601
+ logicalIdentity: currentSource.logicalIdentity,
579
602
  };
580
603
  }
581
604
  async function resolveMultiSourceConfigRead(options) {
@@ -624,6 +647,7 @@ async function resolveMultiSourceConfigRead(options) {
624
647
  const result = await resolveConfigRead({
625
648
  sourceId: stored.sourceId,
626
649
  sourceIdentity: stored.sourceIdentity,
650
+ logicalIdentity: stored.logicalIdentity,
627
651
  pluginName: stored.pluginName,
628
652
  plugin: null,
629
653
  scope: resolveConfigReadResolution(options.rawOptions.scope),
@@ -670,6 +694,7 @@ async function executeWriteCommand(command, pluginNames, rawOptions, context, di
670
694
  const runtime = {
671
695
  ...context,
672
696
  directCli,
697
+ preApplyConfirmed: rawOptions.yes === true,
673
698
  ...(managedCodexAuthorizer ? { managedCodexAuthorizer } : {}),
674
699
  };
675
700
  switch (command) {
@@ -860,26 +885,70 @@ function configLayerLabel(scope) {
860
885
  return '当前项目';
861
886
  }
862
887
  function writeConfigApplyNotice(write, receipt) {
863
- if (receipt.targetResults.length === 0) {
864
- const message = receipt.applySkippedReason === 'noConfigChange'
888
+ const sanitizeMessage = (message) => redactString(message)
889
+ .replace(/https?:\/\/\S+/giu, '[REDACTED URL]')
890
+ .replace(/(?:file:\/\/)?(?:\/[\w.@+-]+){2,}/gu, '[REDACTED PATH]')
891
+ .replace(/[A-Za-z]:\\(?:[^\s\\]+\\)+[^\s\\]*/gu, '[REDACTED PATH]');
892
+ const writeTargetFailures = () => {
893
+ for (const entry of receipt.apply.targetResults.filter((target) => target.state === 'failed' || target.state === 'skipped')) {
894
+ const reason = entry.message
895
+ ? `${entry.errorCode ? `[${entry.errorCode}] ` : ''}${sanitizeMessage(entry.message)}`
896
+ : entry.errorCode
897
+ ? `失败原因:${entry.errorCode}。`
898
+ : '未提供安全失败原因。';
899
+ const command = `aw reinstall ${receipt.plugin} -p ${entry.target.platform} -s ${entry.target.scope}`;
900
+ const recovery = entry.errorCode === 'invalidConfig'
901
+ ? ' 请修复无效配置后运行 aw sync。'
902
+ : entry.errorCode === 'preApplyAuthorizationRequired'
903
+ || entry.errorCode === 'sharedNativeConfigApplyConfirmationRequired'
904
+ || entry.errorCode === 'sharedNativeImpactAuthorizationRequired'
905
+ ? ` 请运行 ${command} --yes 重试。`
906
+ : entry.state === 'failed'
907
+ ? ` 请在解决失败原因后运行 ${command}。`
908
+ : '';
909
+ writeLine(write, `${entry.target.platform}/${entry.target.scope}:${reason}${recovery}`);
910
+ }
911
+ };
912
+ const targetResults = receipt.apply.targetResults;
913
+ if (receipt.apply.state === 'skipped') {
914
+ const message = receipt.apply.reason === 'noConfigChange'
865
915
  ? '配置内容没有变化,因此没有运行 reinstall。'
866
- : receipt.applySkippedReason === 'invalidConfig'
867
- ? '配置已保存,但当前配置无效,因此没有运行 reinstall。请先修复无效字段。'
868
- : '配置已保存。当前没有可见的 AW 安装目标,因此没有应用配置。';
916
+ : receipt.apply.reason === 'noEffectiveConfigChange'
917
+ ? '配置存储已更新,但有效配置没有变化,因此没有运行 reinstall。'
918
+ : receipt.apply.reason === 'notRequested'
919
+ ? '配置已保存,但未请求应用配置。'
920
+ : '配置已保存。当前没有可见的 AW 安装目标,因此没有应用配置。';
869
921
  writeLine(write, message);
870
922
  }
871
- else {
872
- const completed = receipt.targetResults.filter((entry) => entry.state === 'completed').length;
873
- const failed = receipt.targetResults.filter((entry) => entry.state === 'failed');
874
- writeLine(write, `配置已保存。已重装 ${completed} 个当前可见目标;失败 ${failed.length} 个。`);
875
- for (const entry of failed) {
876
- writeLine(write, `${entry.target.platform}/${entry.target.scope}:${entry.message ?? 'reinstall 失败。'} `
877
- + `请重试 aw reinstall ${receipt.plugin} -p ${entry.target.platform} -s ${entry.target.scope}。`);
878
- }
923
+ else if (receipt.apply.state === 'unavailable') {
924
+ const fallbackMessages = {
925
+ invalidConfig: '可见目标的有效配置无效。',
926
+ schemaUnavailable: '配置 schema 不可用。',
927
+ sourceUnavailable: '插件来源不可用。',
928
+ effectiveConfigUnavailable: '无法读取有效配置。',
929
+ targetDiscoveryFailed: '无法发现可应用配置的目标。',
930
+ };
931
+ const detail = receipt.apply.error
932
+ ? `${receipt.apply.error.code}:${sanitizeMessage(receipt.apply.error.message)}`
933
+ : `${receipt.apply.reason}:${fallbackMessages[receipt.apply.reason]}`;
934
+ const recovery = receipt.apply.reason === 'invalidConfig'
935
+ ? '请修复无效配置后运行 aw sync。'
936
+ : receipt.apply.reason === 'effectiveConfigUnavailable'
937
+ ? '请修复配置后运行 aw sync。'
938
+ : receipt.apply.reason === 'schemaUnavailable' || receipt.apply.reason === 'sourceUnavailable'
939
+ ? '请修复插件来源或配置后运行 aw sync。'
940
+ : '请修复来源或配置后运行 aw sync。';
941
+ writeLine(write, `配置已保存,但当前无法应用配置。${detail} ${recovery}`);
942
+ writeTargetFailures();
879
943
  }
880
- if (receipt.otherProjectsRequireReinstall) {
881
- writeLine(write, '其它项目没有被扫描。请进入每个项目目录并运行对应的 aw reinstall 命令。');
944
+ else {
945
+ const completed = targetResults.filter((entry) => entry.state === 'completed').length;
946
+ const failed = targetResults.filter((entry) => entry.state === 'failed').length;
947
+ const skipped = targetResults.filter((entry) => entry.state === 'skipped').length;
948
+ writeLine(write, `配置已保存。已重装 ${completed} 个当前可见目标;失败 ${failed} 个;跳过 ${skipped} 个。`);
949
+ writeTargetFailures();
882
950
  }
951
+ writeWarnings(write, receipt.warnings);
883
952
  }
884
953
  function renderConfigFieldState(field) {
885
954
  if (field.valueState === 'invalid') {
@@ -899,11 +968,15 @@ function writeConfigReadHuman(write, resolved, pluginName) {
899
968
  }
900
969
  if (field.kind === 'manifest' && field.valueState === 'invalid') {
901
970
  const sourceScope = field.sourceLayer === 'project'
902
- ? ' -s project'
903
- : ' -s user';
904
- writeLine(write, ` aw config set ${pluginName} ${field.key}${sourceScope} --value-json '<json>'`);
905
- writeLine(write, ` aw config unset ${pluginName} ${field.key}${sourceScope}`);
906
- writeLine(write, ` aw config reset ${pluginName}${sourceScope}`);
971
+ ? 'project'
972
+ : 'user';
973
+ const definition = resolved.fieldDefinitions?.[field.key];
974
+ if (definition) {
975
+ writeLine(write, ` ${formatPluginConfigSetRecoveryCommand(pluginName, field.key, definition, sourceScope)}`);
976
+ }
977
+ const scopeOption = ` -s ${sourceScope}`;
978
+ writeLine(write, ` aw config unset ${pluginName} ${field.key}${scopeOption}`);
979
+ writeLine(write, ` aw config reset ${pluginName}${scopeOption}`);
907
980
  }
908
981
  }
909
982
  }
@@ -963,7 +1036,7 @@ export function buildProgram(options = {}) {
963
1036
  plugin
964
1037
  .command('capabilities')
965
1038
  .description('Show the current plugin manifest authoring surface')
966
- .option('--surface <surface>', 'manifest | build-config | extensions | slash-commands | mcp-apps | config | post-apply | artifacts')
1039
+ .option('--surface <surface>', 'manifest | build-config | extensions | slash-commands | mcp-apps | config | pre-apply | artifacts')
967
1040
  .option('--json', 'emit one machine-readable JSON object', false)
968
1041
  .action((rawOptions) => {
969
1042
  try {
@@ -1447,7 +1520,7 @@ export function buildProgram(options = {}) {
1447
1520
  .option('--with-mcp', 'add a minimal .mcp.json', false)
1448
1521
  .option('--with-apps', 'add a minimal .app.json', false)
1449
1522
  .option('--with-config-api', 'add AW config schema and helper', false)
1450
- .option('--with-post-apply', 'add a Node postApply script sample', false);
1523
+ .option('--with-pre-apply', 'add an idempotent Node preApply environment check', false);
1451
1524
  plugin
1452
1525
  .command('add-skill')
1453
1526
  .description('Add one static Skill scaffold to an existing plugin')
@@ -1833,7 +1906,7 @@ export function buildProgram(options = {}) {
1833
1906
  catalogDev
1834
1907
  .command('status')
1835
1908
  .option('--workspace-root <path>', 'explicit Catalog Workspace root')
1836
- .requiredOption('--json', 'emit one schema 3 JSON receipt')
1909
+ .requiredOption('--json', 'emit one schema 4 JSON receipt')
1837
1910
  .action(async (rawOptions) => {
1838
1911
  const receipt = await getCatalogDevSourceStatus({
1839
1912
  cwd,
@@ -1849,8 +1922,8 @@ export function buildProgram(options = {}) {
1849
1922
  .option('--workspace-root <path>', 'explicit Catalog Workspace root')
1850
1923
  .option('--source-id <id>', 'recover one managed source by exact ID')
1851
1924
  .option('--replacement-primary <id>', 'replacement when the target source is primary')
1852
- .option('-y, --yes', 'confirm recovery by source ID', false)
1853
- .requiredOption('--json', 'emit one schema 2 JSON receipt')
1925
+ .option('-y, --yes', 'confirm source impact or recovery by source ID', false)
1926
+ .requiredOption('--json', 'emit one schema 4 JSON receipt')
1854
1927
  .action(async (rawOptions) => {
1855
1928
  try {
1856
1929
  const receipt = await deactivateCatalogDevSource({
@@ -1881,11 +1954,12 @@ export function buildProgram(options = {}) {
1881
1954
  const message = failure instanceof Error ? failure.message : String(error);
1882
1955
  if (json) {
1883
1956
  writeJsonReceipt(io.stdout, {
1884
- receiptSchemaVersion: 5,
1957
+ receiptSchemaVersion: 6,
1885
1958
  command,
1886
1959
  ok: false,
1887
1960
  changed: false,
1888
1961
  sourceId,
1962
+ primaryChange: failure.impact?.primaryChange ?? null,
1889
1963
  references: failure.impact?.references ?? failure.inventory?.references ?? [],
1890
1964
  errors: [{ code: failure.code ?? failure.name ?? 'catalogSourceMutationFailed', message }],
1891
1965
  });
@@ -1900,7 +1974,7 @@ export function buildProgram(options = {}) {
1900
1974
  writeJsonReceipt(io.stdout, {
1901
1975
  ...(command === 'catalog:source:sync'
1902
1976
  ? { catalogGenerationSchemaVersion: 1 }
1903
- : { catalogGenerationStatusSchemaVersion: 1 }),
1977
+ : { catalogGenerationStatusSchemaVersion: 2 }),
1904
1978
  command,
1905
1979
  ok: false,
1906
1980
  ...(sourceId ? { sourceId } : {}),
@@ -1999,7 +2073,7 @@ export function buildProgram(options = {}) {
1999
2073
  catalogSource
2000
2074
  .command('status')
2001
2075
  .argument('[id]')
2002
- .option('-j, --json', 'print offline Catalog source status as JSON', false)
2076
+ .option('-j, --json', 'print offline Catalog source status schema 2 as JSON', false)
2003
2077
  .action(async (id, rawOptions) => {
2004
2078
  try {
2005
2079
  const result = await catalogSourceStatusCommand({ sourceId: id, env });
@@ -2011,7 +2085,9 @@ export function buildProgram(options = {}) {
2011
2085
  const active = source.active
2012
2086
  ? `Active ${source.active.snapshotDigest}`
2013
2087
  : 'no Active';
2014
- const readiness = source.activeReady ? 'ready' : 'not ready';
2088
+ const readiness = source.compatibility?.state === 'unsupported'
2089
+ ? `incompatible (required: ${source.compatibility.requiredCapabilities.join(', ')}; missing: ${source.compatibility.missingCapabilities.join(', ')})`
2090
+ : source.activeReady ? 'ready' : 'not ready';
2015
2091
  writeLine(io.stdout, `${source.sourceId}: ${active}, ${readiness}`);
2016
2092
  }
2017
2093
  }
@@ -2030,6 +2106,7 @@ export function buildProgram(options = {}) {
2030
2106
  .option('--subdir <path>', 'use a catalog snapshot below the Git repository root')
2031
2107
  .option('--no-auto-check', 'disable automatic update checks for this source')
2032
2108
  .option('--primary', 'make this source primary', false)
2109
+ .option('-y, --yes', 'confirm affected or unknown primary source references', false)
2033
2110
  .option('-j, --json', 'print mutation receipt as JSON', false)
2034
2111
  .action(async (id, rawOptions) => {
2035
2112
  try {
@@ -2040,7 +2117,7 @@ export function buildProgram(options = {}) {
2040
2117
  throw new Error('Git catalog source add requires exactly one of `--ref` or `--default-ref`.');
2041
2118
  }
2042
2119
  if (rawOptions.path !== undefined && (rawOptions.ref !== undefined || rawOptions.defaultRef === true || rawOptions.subdir !== undefined)) {
2043
- throw new Error('Path catalog source add only accepts `--path`, `--primary`, and `--no-auto-check`.');
2120
+ throw new Error('Path catalog source add only accepts `--path`, `--primary`, `--no-auto-check`, and `--yes`.');
2044
2121
  }
2045
2122
  const source = rawOptions.git !== undefined
2046
2123
  ? {
@@ -2059,11 +2136,23 @@ export function buildProgram(options = {}) {
2059
2136
  path: rawOptions.path,
2060
2137
  ...(rawOptions.autoCheck === false ? { autoCheck: false } : {}),
2061
2138
  };
2139
+ const preview = source.primary
2140
+ ? await preflightCatalogSourceMutation({
2141
+ request: { action: 'add', source }, cwd, env,
2142
+ })
2143
+ : undefined;
2062
2144
  const receipt = await addCatalogSourceCommand({
2063
2145
  source,
2064
2146
  cliVersion: resolveCliVersion(),
2065
2147
  cwd,
2066
2148
  env,
2149
+ ...(preview ? {
2150
+ expectedConfigDigest: preview.configDigest,
2151
+ expectedProposedConfigDigest: preview.proposedConfigDigest,
2152
+ expectedImpactDigest: preview.impactDigest,
2153
+ } : {}),
2154
+ requireImpactConfirmation: true,
2155
+ confirmImpact: rawOptions.yes === true,
2067
2156
  });
2068
2157
  if (rawOptions.json)
2069
2158
  writeJsonReceipt(io.stdout, receipt);
@@ -2129,12 +2218,18 @@ export function buildProgram(options = {}) {
2129
2218
  : {}),
2130
2219
  }
2131
2220
  : { autoCheck: rawOptions.autoCheck };
2221
+ const preview = await preflightCatalogSourceMutation({
2222
+ request: { action: 'update', sourceId: id, update }, cwd, env,
2223
+ });
2132
2224
  const receipt = await updateCatalogSourceCommand({
2133
2225
  sourceId: id,
2134
2226
  update,
2135
2227
  cliVersion: resolveCliVersion(),
2136
2228
  cwd,
2137
2229
  env,
2230
+ expectedConfigDigest: preview.configDigest,
2231
+ expectedProposedConfigDigest: preview.proposedConfigDigest,
2232
+ expectedImpactDigest: preview.impactDigest,
2138
2233
  requireIdentityChangeConfirmation: true,
2139
2234
  confirmIdentityChange: rawOptions.yes === true,
2140
2235
  });
@@ -2152,10 +2247,17 @@ export function buildProgram(options = {}) {
2152
2247
  catalogSource
2153
2248
  .command('set-primary')
2154
2249
  .argument('<id>')
2250
+ .option('-y, --yes', 'confirm affected or unknown primary source references', false)
2155
2251
  .option('-j, --json', 'print mutation receipt as JSON', false)
2156
2252
  .action(async (id, rawOptions) => {
2157
2253
  try {
2158
- const receipt = await setPrimaryCatalogSourceCommand({ sourceId: id, cwd, env });
2254
+ const receipt = await setPrimaryCatalogSourceCommand({
2255
+ sourceId: id,
2256
+ cwd,
2257
+ env,
2258
+ requireImpactConfirmation: true,
2259
+ confirmImpact: rawOptions.yes === true,
2260
+ });
2159
2261
  if (rawOptions.json)
2160
2262
  writeJsonReceipt(io.stdout, receipt);
2161
2263
  else
@@ -2209,18 +2311,22 @@ export function buildProgram(options = {}) {
2209
2311
  writeLine(io.stdout, `${entry.storeKey}: ${entry.category}, ${entry.status}, ${entry.reason}, ${bytes}`);
2210
2312
  }
2211
2313
  writeLine(io.stdout, `Reclaimable: ${result.totals.reclaimableEntries} item(s).`);
2314
+ if (result.errors.length > 0) {
2315
+ writeLine(io.stderr, `${result.errors.length} item(s) could not be fully inspected and were retained.`);
2316
+ }
2212
2317
  }
2318
+ commandExitState.exitCode = result.ok ? 0 : 1;
2213
2319
  }
2214
2320
  catch (error) {
2215
2321
  const failure = sanitizeCatalogSourceError(error, env);
2216
2322
  const message = redactString(failure.message);
2217
2323
  if (rawOptions.json)
2218
2324
  writeJsonReceipt(io.stdout, {
2219
- catalogStoreSchemaVersion: 1,
2325
+ catalogStoreSchemaVersion: 2,
2220
2326
  command: 'catalog:store:status',
2221
2327
  ok: false,
2222
2328
  entries: [],
2223
- errors: [{ code: catalogGenerationErrorCode(error), message }],
2329
+ errors: [{ code: catalogStoreErrorCode(error), message }],
2224
2330
  });
2225
2331
  writeLine(io.stderr, message);
2226
2332
  commandExitState.exitCode = 1;
@@ -2246,24 +2352,23 @@ export function buildProgram(options = {}) {
2246
2352
  else if (dryRun) {
2247
2353
  writeLine(io.stdout, `Dry run: ${result.entries.filter((entry) => entry.status === 'reclaimable').length} item(s) are reclaimable.`);
2248
2354
  writeLine(io.stdout, 'Run `aw catalog store prune --yes` to delete them.');
2355
+ if (result.errors.length > 0)
2356
+ writeLine(io.stderr, `${result.errors.length} item(s) could not be fully inspected and were retained.`);
2249
2357
  }
2250
2358
  else {
2251
2359
  writeLine(io.stdout, `Deleted ${result.deleted.length} Catalog store item(s) (${result.deletedBytes} bytes).`);
2252
2360
  if (result.errors.length > 0)
2253
- writeLine(io.stderr, `${result.errors.length} item(s) could not be deleted and were retained.`);
2361
+ writeLine(io.stderr, `${result.errors.length} item(s) could not be fully inspected or deleted and were retained.`);
2254
2362
  }
2255
2363
  commandExitState.exitCode = result.ok ? 0 : 1;
2256
2364
  }
2257
2365
  catch (error) {
2258
2366
  const failure = sanitizeCatalogSourceError(error, env);
2259
2367
  const message = redactString(failure.message);
2260
- const explicitCode = error.code;
2261
- const code = typeof explicitCode === 'string'
2262
- ? explicitCode
2263
- : catalogGenerationErrorCode(error);
2368
+ const code = catalogStoreErrorCode(error);
2264
2369
  if (rawOptions.json)
2265
2370
  writeJsonReceipt(io.stdout, {
2266
- catalogStoreSchemaVersion: 1,
2371
+ catalogStoreSchemaVersion: 2,
2267
2372
  command: 'catalog:store:prune',
2268
2373
  ok: false,
2269
2374
  overallState: 'failed',
@@ -2312,7 +2417,8 @@ export function buildProgram(options = {}) {
2312
2417
  .requiredOption('-p, --platform <platform>', 'codex, claude, or both')
2313
2418
  .option('-a, --all', 'reconcile every desired plugin in the selected scope', false)
2314
2419
  .option('--refresh', 'refresh only Catalog sources required by selected intent roots', false)
2315
- .option('-y, --yes', 'authorize shared native replacement or forced repair', false)
2420
+ .option('--script-timeout <ms>', 'override plugin preApply script timeout in milliseconds')
2421
+ .option('-y, --yes', 'authorize preApply and shared native replacement or forced repair', false)
2316
2422
  .option('--allow-managed-codex-install', 'allow this command to acquire or rebuild the pinned AW-managed Codex runtime', false)
2317
2423
  .option('-j, --json', 'print sync receipt as JSON', false)
2318
2424
  .option('-v, --verbose', 'show command diagnostics', false)
@@ -2324,6 +2430,7 @@ export function buildProgram(options = {}) {
2324
2430
  cwd: context.cwd,
2325
2431
  scope: rawOptions.scope,
2326
2432
  platform: rawOptions.platform,
2433
+ scriptTimeout: rawOptions.scriptTimeout,
2327
2434
  allowManagedCodexInstall: rawOptions.allowManagedCodexInstall,
2328
2435
  }));
2329
2436
  const syncPlatform = normalized.platform;
@@ -2340,6 +2447,7 @@ export function buildProgram(options = {}) {
2340
2447
  interactive: context.interactive && context.isTty && !context.isCi,
2341
2448
  prompt: context.prompt,
2342
2449
  allowManagedCodexInstall: rawOptions.allowManagedCodexInstall,
2450
+ scriptTimeoutMs: normalized.scriptTimeoutMs,
2343
2451
  }, context));
2344
2452
  if (rawOptions.json) {
2345
2453
  writeJsonReceipt(io.stdout, buildRebuildReceiptJson('sync', result));
@@ -2357,9 +2465,9 @@ export function buildProgram(options = {}) {
2357
2465
  .option('-s, --scope <scope>', 'project or user')
2358
2466
  .option('-p, --platform <platform>', 'codex | claude | both')
2359
2467
  .option('--dependency-scope <pluginId[#platform]=scope>', 'place one dependency at project or user scope; repeat for more dependencies', (value, previous) => [...previous, value], [])
2360
- .option('--script-timeout <ms>', 'override plugin postApply script timeout in milliseconds')
2468
+ .option('--script-timeout <ms>', 'override plugin preApply script timeout in milliseconds')
2361
2469
  .option('--allow-managed-codex-install', 'allow this command to acquire or rebuild the pinned AW-managed Codex runtime', false)
2362
- .option('-y, --yes', 'authorize shared Codex native replacement', false)
2470
+ .option('-y, --yes', 'authorize preApply and shared Codex native replacement', false)
2363
2471
  .option('-j, --json', 'print receipt as JSON', false)
2364
2472
  .option('-v, --verbose', 'show command diagnostics', false)
2365
2473
  .option('-D, --debug', 'write debug diagnostics to a log file', false)
@@ -2386,7 +2494,6 @@ export function buildProgram(options = {}) {
2386
2494
  .argument('[plugins...]')
2387
2495
  .option('-s, --scope <scope>', 'project or user')
2388
2496
  .option('-p, --platform <platform>', 'codex | claude | both')
2389
- .option('--script-timeout <ms>', 'override plugin postApply script timeout in milliseconds')
2390
2497
  .option('--allow-managed-codex-install', 'allow this command to acquire or rebuild the pinned AW-managed Codex runtime', false)
2391
2498
  .option('-j, --json', 'print receipt as JSON', false)
2392
2499
  .option('-v, --verbose', 'show command diagnostics', false)
@@ -2442,9 +2549,9 @@ export function buildProgram(options = {}) {
2442
2549
  .argument('[plugins...]')
2443
2550
  .option('-s, --scope <scope>', 'project or user')
2444
2551
  .option('-p, --platform <platform>', 'codex | claude | both')
2445
- .option('--script-timeout <ms>', 'override plugin postApply script timeout in milliseconds')
2552
+ .option('--script-timeout <ms>', 'override plugin preApply script timeout in milliseconds')
2446
2553
  .option('--allow-managed-codex-install', 'allow this command to acquire or rebuild the pinned AW-managed Codex runtime', false)
2447
- .option('-y, --yes', 'authorize shared Codex native replacement or forced reinstall', false)
2554
+ .option('-y, --yes', 'authorize preApply and shared Codex native replacement or forced reinstall', false)
2448
2555
  .option('-j, --json', 'print receipt as JSON', false)
2449
2556
  .option('-v, --verbose', 'show command diagnostics', false)
2450
2557
  .option('-D, --debug', 'write debug diagnostics to a log file', false)
@@ -2612,9 +2719,11 @@ export function buildProgram(options = {}) {
2612
2719
  .argument('[field]')
2613
2720
  .option('-s, --scope <scope>', 'project or user')
2614
2721
  .option('--value-json <json>', 'set the field to an exact JSON value')
2722
+ .option('--value-stdin', 'read the exact string value from stdin until EOF', false)
2615
2723
  .option('--preset <id>', 'set the field to the current manifest preset value')
2616
2724
  .option('--apply', 'apply the saved config to visible desired placements', false)
2617
- .option('-y, --yes', 'confirm shared Codex native config apply', false)
2725
+ .option('--script-timeout <ms>', 'override plugin preApply script timeout in milliseconds')
2726
+ .option('-y, --yes', 'confirm preApply and shared Codex native config apply', false)
2618
2727
  .option('-j, --json', 'print receipt as JSON', false)
2619
2728
  .option('-v, --verbose', 'show command diagnostics', false)
2620
2729
  .option('-D, --debug', 'write debug diagnostics to a log file', false)
@@ -2627,8 +2736,16 @@ export function buildProgram(options = {}) {
2627
2736
  try {
2628
2737
  outcome = await runActionWithContext(context, async () => {
2629
2738
  const scope = resolveConfigWriteScope(rawOptions.scope);
2630
- if ((rawOptions.valueJson === undefined) === (rawOptions.preset === undefined)) {
2631
- throw new Error('Use exactly one of --value-json <json> or --preset <id>.');
2739
+ const scriptTimeoutMs = resolveScriptTimeoutMs(rawOptions);
2740
+ const explicitValueCount = [
2741
+ rawOptions.valueJson !== undefined,
2742
+ rawOptions.valueStdin === true,
2743
+ rawOptions.preset !== undefined,
2744
+ ].filter(Boolean).length;
2745
+ if (explicitValueCount > 1
2746
+ || (explicitValueCount === 0
2747
+ && !(context.interactive && context.isTty && !context.isCi && rawOptions.json !== true))) {
2748
+ throw new Error('Use exactly one of --value-json <json>, --value-stdin, or --preset <id>.');
2632
2749
  }
2633
2750
  return withResolvedConfigMutationPlugin(context, pluginName, async ({ pluginId, source, plugin }, awHomeMutationToken, catalogOperationContext) => {
2634
2751
  if (!plugin.manifest.config?.fields) {
@@ -2638,8 +2755,43 @@ export function buildProgram(options = {}) {
2638
2755
  if (!field) {
2639
2756
  throw new Error(`Unknown config key "${key}".`);
2640
2757
  }
2758
+ const sensitive = field.sensitive === true;
2759
+ if (sensitive && scope !== 'user') {
2760
+ const error = new Error('sensitiveProjectConfigUnsupported: Sensitive config can only be set in user scope.');
2761
+ error.code = 'sensitiveProjectConfigUnsupported';
2762
+ throw error;
2763
+ }
2764
+ if (sensitive && (rawOptions.valueJson !== undefined || rawOptions.preset !== undefined)) {
2765
+ const error = new Error('sensitiveConfigInputUnsupported: Sensitive config cannot use --value-json or --preset.');
2766
+ error.code = 'sensitiveConfigInputUnsupported';
2767
+ throw error;
2768
+ }
2769
+ if (!sensitive && explicitValueCount !== 1) {
2770
+ throw new Error('Use exactly one of --value-json <json>, --value-stdin, or --preset <id>.');
2771
+ }
2641
2772
  let inputValue;
2642
- if (rawOptions.valueJson !== undefined) {
2773
+ if (rawOptions.valueStdin === true) {
2774
+ inputValue = await readUtf8Stdin(context.stdin);
2775
+ }
2776
+ else if (sensitive) {
2777
+ if (!(context.interactive && context.isTty && !context.isCi && rawOptions.json !== true)
2778
+ || !context.prompt.password) {
2779
+ const error = new Error('sensitiveConfigStdinRequired: Use --value-stdin for sensitive config outside an interactive terminal.');
2780
+ error.code = 'sensitiveConfigStdinRequired';
2781
+ throw error;
2782
+ }
2783
+ const response = await context.prompt.password({
2784
+ message: `输入 ${field.title ?? key}`,
2785
+ mask: true,
2786
+ });
2787
+ if (response.cancelled || response.action !== 'select' || response.value === undefined) {
2788
+ const error = new Error('sensitiveConfigInputCancelled: Sensitive config input was cancelled.');
2789
+ error.code = 'sensitiveConfigInputCancelled';
2790
+ throw error;
2791
+ }
2792
+ inputValue = response.value;
2793
+ }
2794
+ else if (rawOptions.valueJson !== undefined) {
2643
2795
  try {
2644
2796
  inputValue = JSON.parse(rawOptions.valueJson);
2645
2797
  }
@@ -2665,6 +2817,7 @@ export function buildProgram(options = {}) {
2665
2817
  awHomeMutationToken,
2666
2818
  catalogOperationContext,
2667
2819
  expectedGenerationSetDigest: catalogOperationContext.generationSetDigest,
2820
+ ...(scriptTimeoutMs === undefined ? {} : { scriptTimeoutMs }),
2668
2821
  },
2669
2822
  awHomeMutationToken,
2670
2823
  request: {
@@ -2672,6 +2825,7 @@ export function buildProgram(options = {}) {
2672
2825
  },
2673
2826
  apply: rawOptions.apply === true,
2674
2827
  sharedNativeApplyConfirmed: rawOptions.yes === true,
2828
+ preApplyConfirmed: rawOptions.yes === true,
2675
2829
  });
2676
2830
  return buildConfigMutationReceipt('config:set', {
2677
2831
  ok: writeReceipt.overallState === 'succeeded',
@@ -2713,7 +2867,8 @@ export function buildProgram(options = {}) {
2713
2867
  .argument('[key]')
2714
2868
  .option('-s, --scope <scope>', 'project or user')
2715
2869
  .option('--apply', 'apply the saved config to visible desired placements', false)
2716
- .option('-y, --yes', 'confirm shared Codex native config apply', false)
2870
+ .option('--script-timeout <ms>', 'override plugin preApply script timeout in milliseconds')
2871
+ .option('-y, --yes', 'confirm preApply and shared Codex native config apply', false)
2717
2872
  .option('-j, --json', 'print receipt as JSON', false)
2718
2873
  .option('-v, --verbose', 'show command diagnostics', false)
2719
2874
  .option('-D, --debug', 'write debug diagnostics to a log file', false)
@@ -2724,13 +2879,12 @@ export function buildProgram(options = {}) {
2724
2879
  try {
2725
2880
  outcome = await runActionWithContext(context, async () => {
2726
2881
  const scope = resolveConfigWriteScope(rawOptions.scope);
2727
- const execute = async (selectedPlugin, selectedKey) => withResolvedConfigMutationPlugin(context, selectedPlugin, async ({ pluginId, source, plugin }, awHomeMutationToken, catalogOperationContext) => {
2728
- if (plugin.manifest.config?.fields && !plugin.manifest.config.fields[selectedKey]) {
2729
- throw new Error(`Unknown config key "${selectedKey}".`);
2730
- }
2882
+ const scriptTimeoutMs = resolveScriptTimeoutMs(rawOptions);
2883
+ const execute = async (selectedPlugin, selectedKey, confirmed) => withResolvedConfigMutationPlugin(context, selectedPlugin, async ({ pluginId, source, plugin }, awHomeMutationToken, catalogOperationContext) => {
2731
2884
  const store = await readPluginConfigStore({
2732
2885
  sourceId: source.sourceId,
2733
2886
  sourceIdentity: source.sourceIdentity,
2887
+ logicalIdentity: source.logicalIdentity,
2734
2888
  pluginName: plugin.manifest.name,
2735
2889
  scope,
2736
2890
  cwd: context.cwd,
@@ -2752,13 +2906,15 @@ export function buildProgram(options = {}) {
2752
2906
  awHomeMutationToken,
2753
2907
  catalogOperationContext,
2754
2908
  expectedGenerationSetDigest: catalogOperationContext.generationSetDigest,
2909
+ ...(scriptTimeoutMs === undefined ? {} : { scriptTimeoutMs }),
2755
2910
  },
2756
2911
  awHomeMutationToken,
2757
2912
  request: {
2758
2913
  removeKeys: [selectedKey],
2759
2914
  },
2760
2915
  apply: rawOptions.apply === true,
2761
- sharedNativeApplyConfirmed: rawOptions.yes === true,
2916
+ sharedNativeApplyConfirmed: confirmed,
2917
+ preApplyConfirmed: rawOptions.yes === true,
2762
2918
  });
2763
2919
  return buildConfigMutationReceipt('config:unset', {
2764
2920
  ok: writeReceipt.overallState === 'succeeded',
@@ -2777,11 +2933,15 @@ export function buildProgram(options = {}) {
2777
2933
  reserved: false,
2778
2934
  action: 'unset',
2779
2935
  scope,
2936
+ ...(!plugin.manifest.config?.fields?.[selectedKey] ? { stale: true } : {}),
2780
2937
  }],
2781
2938
  });
2782
2939
  });
2783
2940
  if (pluginName && key) {
2784
- return { cancelled: false, value: await execute(pluginName, key) };
2941
+ return {
2942
+ cancelled: false,
2943
+ value: await execute(pluginName, key, rawOptions.yes === true),
2944
+ };
2785
2945
  }
2786
2946
  if (!isWizardAvailable(context, rawOptions))
2787
2947
  throw new Error(configCommandUsage('unset'));
@@ -2808,7 +2968,7 @@ export function buildProgram(options = {}) {
2808
2968
  scope: selection.scope ?? 'user',
2809
2969
  })),
2810
2970
  resultState: overallResultState,
2811
- execute: (selection) => execute(selection.plugins[0], selection.key),
2971
+ execute: (selection) => execute(selection.plugins[0], selection.key, true),
2812
2972
  });
2813
2973
  return result.cancelled
2814
2974
  ? { cancelled: true }
@@ -2838,7 +2998,8 @@ export function buildProgram(options = {}) {
2838
2998
  .argument('[plugin]')
2839
2999
  .option('-s, --scope <scope>', 'project or user')
2840
3000
  .option('--apply', 'apply the saved config to visible desired placements', false)
2841
- .option('-y, --yes', 'confirm destructive reset', false)
3001
+ .option('--script-timeout <ms>', 'override plugin preApply script timeout in milliseconds')
3002
+ .option('-y, --yes', 'confirm destructive reset and preApply/shared Codex native config apply', false)
2842
3003
  .option('-j, --json', 'print receipt as JSON', false)
2843
3004
  .option('-v, --verbose', 'show command diagnostics', false)
2844
3005
  .option('-D, --debug', 'write debug diagnostics to a log file', false)
@@ -2849,6 +3010,7 @@ export function buildProgram(options = {}) {
2849
3010
  try {
2850
3011
  outcome = await runActionWithContext(context, async () => {
2851
3012
  const execute = async (selectedPlugin, selectedScope, confirmed) => {
3013
+ const scriptTimeoutMs = resolveScriptTimeoutMs(rawOptions);
2852
3014
  if (!confirmed) {
2853
3015
  throw new Error(`Reset requires confirmation. Re-run \`aw config reset ${selectedPlugin} -s ${selectedScope} --yes\` to delete this store.`);
2854
3016
  }
@@ -2861,6 +3023,7 @@ export function buildProgram(options = {}) {
2861
3023
  const affectedFields = await describeResetAffectedFields({
2862
3024
  sourceId: located.sourceId,
2863
3025
  sourceIdentity: located.sourceIdentity,
3026
+ logicalIdentity: located.logicalIdentity,
2864
3027
  pluginName: located.pluginName,
2865
3028
  plugin,
2866
3029
  pluginError,
@@ -2871,6 +3034,7 @@ export function buildProgram(options = {}) {
2871
3034
  const resetReceipt = await resetPluginConfigWithHelper({
2872
3035
  sourceId: located.sourceId,
2873
3036
  sourceIdentity: located.sourceIdentity,
3037
+ logicalIdentity: located.logicalIdentity,
2874
3038
  pluginName: located.pluginName,
2875
3039
  scope: selectedScope,
2876
3040
  cwd: context.cwd,
@@ -2879,6 +3043,9 @@ export function buildProgram(options = {}) {
2879
3043
  plugin,
2880
3044
  pluginError,
2881
3045
  apply: rawOptions.apply === true,
3046
+ rebuildRuntime: scriptTimeoutMs === undefined ? undefined : { scriptTimeoutMs },
3047
+ sharedNativeApplyConfirmed: confirmed,
3048
+ preApplyConfirmed: rawOptions.yes === true,
2882
3049
  });
2883
3050
  return buildConfigMutationReceipt('config:reset', {
2884
3051
  ok: resetReceipt.overallState === 'succeeded',
@@ -3115,11 +3282,12 @@ export async function runCli(argv, options = {}) {
3115
3282
  const message = 'option --subdir cannot be used with option --no-subdir';
3116
3283
  if (argv.includes('--json') && argv[0] === 'catalog' && argv[1] === 'source' && argv[2] === 'update') {
3117
3284
  writeJsonReceipt(io.stdout, {
3118
- receiptSchemaVersion: 5,
3285
+ receiptSchemaVersion: 6,
3119
3286
  command: 'catalog:source:update',
3120
3287
  ok: false,
3121
3288
  changed: false,
3122
3289
  sourceId: argv[3] ?? '',
3290
+ primaryChange: null,
3123
3291
  references: [],
3124
3292
  errors: [{ code: 'catalogSourceOptionConflict', message }],
3125
3293
  });
@@ -3132,11 +3300,12 @@ export async function runCli(argv, options = {}) {
3132
3300
  const message = 'option --auto-check cannot be used with option --no-auto-check';
3133
3301
  if (argv.includes('--json') || argv.includes('-j')) {
3134
3302
  writeJsonReceipt(io.stdout, {
3135
- receiptSchemaVersion: 5,
3303
+ receiptSchemaVersion: 6,
3136
3304
  command: 'catalog:source:update',
3137
3305
  ok: false,
3138
3306
  changed: false,
3139
3307
  sourceId: argv[3] ?? '',
3308
+ primaryChange: null,
3140
3309
  references: [],
3141
3310
  errors: [{ code: 'catalogSourceOptionConflict', message }],
3142
3311
  });