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

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 (218) 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 +165 -45
  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 +11 -19
  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 +7 -0
  47. package/dist/src/commands/rebuild-command.js +769 -279
  48. package/dist/src/commands/rebuild-command.js.map +1 -1
  49. package/dist/src/commands/rebuild-integration.d.ts +24 -47
  50. package/dist/src/commands/rebuild-integration.js +1074 -1011
  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 +216 -85
  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 +6 -6
  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 +2067 -839
  85. package/dist/src/tui/console-app-v4.js.map +1 -1
  86. package/dist/src/tui/controller-runtime.js +585 -33
  87. package/dist/src/tui/controller-runtime.js.map +1 -1
  88. package/dist/src/tui/controller.d.ts +152 -6
  89. package/dist/src/tui/controller.js +1168 -156
  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 +6 -1
  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 +306 -86
  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-renderer.d.ts +2 -1
  138. package/dist/src/utils/artifact-renderer.js +52 -52
  139. package/dist/src/utils/artifact-renderer.js.map +1 -1
  140. package/dist/src/utils/bundle-layout.js +4 -4
  141. package/dist/src/utils/bundle-layout.js.map +1 -1
  142. package/dist/src/utils/catalog-capability-projection.d.ts +8 -0
  143. package/dist/src/utils/catalog-capability-projection.js +14 -0
  144. package/dist/src/utils/catalog-capability-projection.js.map +1 -0
  145. package/dist/src/utils/catalog-generation-resolver.d.ts +14 -2
  146. package/dist/src/utils/catalog-generation-resolver.js +49 -27
  147. package/dist/src/utils/catalog-generation-resolver.js.map +1 -1
  148. package/dist/src/utils/catalog-generation-service.d.ts +8 -1
  149. package/dist/src/utils/catalog-generation-service.js +81 -47
  150. package/dist/src/utils/catalog-generation-service.js.map +1 -1
  151. package/dist/src/utils/catalog-generation-store.d.ts +1 -0
  152. package/dist/src/utils/catalog-generation-store.js +60 -5
  153. package/dist/src/utils/catalog-generation-store.js.map +1 -1
  154. package/dist/src/utils/catalog-operation-context.js +1 -0
  155. package/dist/src/utils/catalog-operation-context.js.map +1 -1
  156. package/dist/src/utils/catalog-public-error.js +4 -0
  157. package/dist/src/utils/catalog-public-error.js.map +1 -1
  158. package/dist/src/utils/catalog-source-impact.d.ts +3 -2
  159. package/dist/src/utils/catalog-source-impact.js +142 -20
  160. package/dist/src/utils/catalog-source-impact.js.map +1 -1
  161. package/dist/src/utils/catalog-source-references.js +95 -9
  162. package/dist/src/utils/catalog-source-references.js.map +1 -1
  163. package/dist/src/utils/catalog-sources.d.ts +1 -1
  164. package/dist/src/utils/catalog-sources.js +19 -3
  165. package/dist/src/utils/catalog-sources.js.map +1 -1
  166. package/dist/src/utils/codex-manager.js +8 -0
  167. package/dist/src/utils/codex-manager.js.map +1 -1
  168. package/dist/src/utils/codex-native-observation.d.ts +34 -1
  169. package/dist/src/utils/codex-native-observation.js +132 -0
  170. package/dist/src/utils/codex-native-observation.js.map +1 -1
  171. package/dist/src/utils/codex-reconciler.d.ts +0 -2
  172. package/dist/src/utils/codex-reconciler.js.map +1 -1
  173. package/dist/src/utils/codex-shared-native.d.ts +2 -26
  174. package/dist/src/utils/codex-shared-native.js +8 -82
  175. package/dist/src/utils/codex-shared-native.js.map +1 -1
  176. package/dist/src/utils/git-catalog-provider.d.ts +3 -0
  177. package/dist/src/utils/git-catalog-provider.js +40 -1
  178. package/dist/src/utils/git-catalog-provider.js.map +1 -1
  179. package/dist/src/utils/local-marketplace.d.ts +1 -0
  180. package/dist/src/utils/local-marketplace.js +69 -73
  181. package/dist/src/utils/local-marketplace.js.map +1 -1
  182. package/dist/src/utils/multi-source-catalog.js +1 -0
  183. package/dist/src/utils/multi-source-catalog.js.map +1 -1
  184. package/dist/src/utils/native-cli.d.ts +9 -4
  185. package/dist/src/utils/native-cli.js +280 -34
  186. package/dist/src/utils/native-cli.js.map +1 -1
  187. package/dist/src/utils/path-catalog-provider.js +2 -0
  188. package/dist/src/utils/path-catalog-provider.js.map +1 -1
  189. package/dist/src/utils/plugin-config-write.d.ts +15 -13
  190. package/dist/src/utils/plugin-config-write.js +418 -198
  191. package/dist/src/utils/plugin-config-write.js.map +1 -1
  192. package/dist/src/utils/plugin-config.d.ts +48 -4
  193. package/dist/src/utils/plugin-config.js +289 -38
  194. package/dist/src/utils/plugin-config.js.map +1 -1
  195. package/dist/src/utils/plugin-scripts.d.ts +20 -12
  196. package/dist/src/utils/plugin-scripts.js +376 -109
  197. package/dist/src/utils/plugin-scripts.js.map +1 -1
  198. package/dist/src/utils/process-tree.d.ts +2 -2
  199. package/dist/src/utils/process-tree.js +1 -1
  200. package/dist/src/utils/process-tree.js.map +1 -1
  201. package/dist/src/utils/project-boundary.d.ts +11 -1
  202. package/dist/src/utils/project-boundary.js +17 -8
  203. package/dist/src/utils/project-boundary.js.map +1 -1
  204. package/dist/src/utils/safe-operation-diagnostic.d.ts +15 -0
  205. package/dist/src/utils/safe-operation-diagnostic.js +33 -0
  206. package/dist/src/utils/safe-operation-diagnostic.js.map +1 -0
  207. package/dist/src/utils/sensitive-content.d.ts +1 -0
  208. package/dist/src/utils/sensitive-content.js +15 -0
  209. package/dist/src/utils/sensitive-content.js.map +1 -0
  210. package/dist/src/utils/windows-claude-shim.d.ts +9 -0
  211. package/dist/src/utils/windows-claude-shim.js +141 -0
  212. package/dist/src/utils/windows-claude-shim.js.map +1 -0
  213. package/dist/vitest.config.js +91 -10
  214. package/dist/vitest.config.js.map +1 -1
  215. package/package.json +9 -9
  216. package/dist/authoring/templates/aw-config-runtime.d.mts +0 -2
  217. package/dist/authoring/templates/aw-config-runtime.mjs +0 -407
  218. 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),
@@ -860,25 +884,35 @@ function configLayerLabel(scope) {
860
884
  return '当前项目';
861
885
  }
862
886
  function writeConfigApplyNotice(write, receipt) {
863
- if (receipt.targetResults.length === 0) {
864
- const message = receipt.applySkippedReason === 'noConfigChange'
887
+ const targetResults = receipt.apply.targetResults;
888
+ if (receipt.apply.state === 'skipped') {
889
+ const message = receipt.apply.reason === 'noConfigChange'
865
890
  ? '配置内容没有变化,因此没有运行 reinstall。'
866
- : receipt.applySkippedReason === 'invalidConfig'
867
- ? '配置已保存,但当前配置无效,因此没有运行 reinstall。请先修复无效字段。'
868
- : '配置已保存。当前没有可见的 AW 安装目标,因此没有应用配置。';
891
+ : receipt.apply.reason === 'noEffectiveConfigChange'
892
+ ? '配置存储已更新,但有效配置没有变化,因此没有运行 reinstall。'
893
+ : receipt.apply.reason === 'notRequested'
894
+ ? '配置已保存,但未请求应用配置。'
895
+ : '配置已保存。当前没有可见的 AW 安装目标,因此没有应用配置。';
896
+ writeLine(write, message);
897
+ }
898
+ else if (receipt.apply.state === 'unavailable') {
899
+ const message = receipt.apply.reason === 'invalidConfig'
900
+ ? '配置已保存,但可见目标的配置无效,因此没有应用。请先修复无效字段。'
901
+ : '配置已保存,但当前无法应用配置。请修复报告的问题后运行 aw sync。';
869
902
  writeLine(write, message);
870
903
  }
871
904
  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} 个。`);
905
+ const completed = targetResults.filter((entry) => entry.state === 'completed').length;
906
+ const failed = targetResults.filter((entry) => entry.state === 'failed');
907
+ const skipped = targetResults.filter((entry) => entry.state === 'skipped').length;
908
+ writeLine(write, `配置已保存。已重装 ${completed} 个当前可见目标;失败 ${failed.length} 个;跳过 ${skipped} 个。`);
875
909
  for (const entry of failed) {
876
910
  writeLine(write, `${entry.target.platform}/${entry.target.scope}:${entry.message ?? 'reinstall 失败。'} `
877
911
  + `请重试 aw reinstall ${receipt.plugin} -p ${entry.target.platform} -s ${entry.target.scope}。`);
878
912
  }
879
913
  }
880
- if (receipt.otherProjectsRequireReinstall) {
881
- writeLine(write, '其它项目没有被扫描。请进入每个项目目录并运行对应的 aw reinstall 命令。');
914
+ if (receipt.otherProjectsMayRequireSync) {
915
+ writeLine(write, '其它项目没有被扫描,可能需要在对应项目目录中运行 aw sync。');
882
916
  }
883
917
  }
884
918
  function renderConfigFieldState(field) {
@@ -899,11 +933,15 @@ function writeConfigReadHuman(write, resolved, pluginName) {
899
933
  }
900
934
  if (field.kind === 'manifest' && field.valueState === 'invalid') {
901
935
  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}`);
936
+ ? 'project'
937
+ : 'user';
938
+ const definition = resolved.fieldDefinitions?.[field.key];
939
+ if (definition) {
940
+ writeLine(write, ` ${formatPluginConfigSetRecoveryCommand(pluginName, field.key, definition, sourceScope)}`);
941
+ }
942
+ const scopeOption = ` -s ${sourceScope}`;
943
+ writeLine(write, ` aw config unset ${pluginName} ${field.key}${scopeOption}`);
944
+ writeLine(write, ` aw config reset ${pluginName}${scopeOption}`);
907
945
  }
908
946
  }
909
947
  }
@@ -963,7 +1001,7 @@ export function buildProgram(options = {}) {
963
1001
  plugin
964
1002
  .command('capabilities')
965
1003
  .description('Show the current plugin manifest authoring surface')
966
- .option('--surface <surface>', 'manifest | build-config | extensions | slash-commands | mcp-apps | config | post-apply | artifacts')
1004
+ .option('--surface <surface>', 'manifest | build-config | extensions | slash-commands | mcp-apps | config | pre-apply | artifacts')
967
1005
  .option('--json', 'emit one machine-readable JSON object', false)
968
1006
  .action((rawOptions) => {
969
1007
  try {
@@ -1447,7 +1485,7 @@ export function buildProgram(options = {}) {
1447
1485
  .option('--with-mcp', 'add a minimal .mcp.json', false)
1448
1486
  .option('--with-apps', 'add a minimal .app.json', false)
1449
1487
  .option('--with-config-api', 'add AW config schema and helper', false)
1450
- .option('--with-post-apply', 'add a Node postApply script sample', false);
1488
+ .option('--with-pre-apply', 'add an idempotent Node preApply environment check', false);
1451
1489
  plugin
1452
1490
  .command('add-skill')
1453
1491
  .description('Add one static Skill scaffold to an existing plugin')
@@ -1833,7 +1871,7 @@ export function buildProgram(options = {}) {
1833
1871
  catalogDev
1834
1872
  .command('status')
1835
1873
  .option('--workspace-root <path>', 'explicit Catalog Workspace root')
1836
- .requiredOption('--json', 'emit one schema 3 JSON receipt')
1874
+ .requiredOption('--json', 'emit one schema 4 JSON receipt')
1837
1875
  .action(async (rawOptions) => {
1838
1876
  const receipt = await getCatalogDevSourceStatus({
1839
1877
  cwd,
@@ -1849,8 +1887,8 @@ export function buildProgram(options = {}) {
1849
1887
  .option('--workspace-root <path>', 'explicit Catalog Workspace root')
1850
1888
  .option('--source-id <id>', 'recover one managed source by exact ID')
1851
1889
  .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')
1890
+ .option('-y, --yes', 'confirm source impact or recovery by source ID', false)
1891
+ .requiredOption('--json', 'emit one schema 4 JSON receipt')
1854
1892
  .action(async (rawOptions) => {
1855
1893
  try {
1856
1894
  const receipt = await deactivateCatalogDevSource({
@@ -1881,11 +1919,12 @@ export function buildProgram(options = {}) {
1881
1919
  const message = failure instanceof Error ? failure.message : String(error);
1882
1920
  if (json) {
1883
1921
  writeJsonReceipt(io.stdout, {
1884
- receiptSchemaVersion: 5,
1922
+ receiptSchemaVersion: 6,
1885
1923
  command,
1886
1924
  ok: false,
1887
1925
  changed: false,
1888
1926
  sourceId,
1927
+ primaryChange: failure.impact?.primaryChange ?? null,
1889
1928
  references: failure.impact?.references ?? failure.inventory?.references ?? [],
1890
1929
  errors: [{ code: failure.code ?? failure.name ?? 'catalogSourceMutationFailed', message }],
1891
1930
  });
@@ -1900,7 +1939,7 @@ export function buildProgram(options = {}) {
1900
1939
  writeJsonReceipt(io.stdout, {
1901
1940
  ...(command === 'catalog:source:sync'
1902
1941
  ? { catalogGenerationSchemaVersion: 1 }
1903
- : { catalogGenerationStatusSchemaVersion: 1 }),
1942
+ : { catalogGenerationStatusSchemaVersion: 2 }),
1904
1943
  command,
1905
1944
  ok: false,
1906
1945
  ...(sourceId ? { sourceId } : {}),
@@ -1999,7 +2038,7 @@ export function buildProgram(options = {}) {
1999
2038
  catalogSource
2000
2039
  .command('status')
2001
2040
  .argument('[id]')
2002
- .option('-j, --json', 'print offline Catalog source status as JSON', false)
2041
+ .option('-j, --json', 'print offline Catalog source status schema 2 as JSON', false)
2003
2042
  .action(async (id, rawOptions) => {
2004
2043
  try {
2005
2044
  const result = await catalogSourceStatusCommand({ sourceId: id, env });
@@ -2011,7 +2050,9 @@ export function buildProgram(options = {}) {
2011
2050
  const active = source.active
2012
2051
  ? `Active ${source.active.snapshotDigest}`
2013
2052
  : 'no Active';
2014
- const readiness = source.activeReady ? 'ready' : 'not ready';
2053
+ const readiness = source.compatibility?.state === 'unsupported'
2054
+ ? `incompatible (required: ${source.compatibility.requiredCapabilities.join(', ')}; missing: ${source.compatibility.missingCapabilities.join(', ')})`
2055
+ : source.activeReady ? 'ready' : 'not ready';
2015
2056
  writeLine(io.stdout, `${source.sourceId}: ${active}, ${readiness}`);
2016
2057
  }
2017
2058
  }
@@ -2030,6 +2071,7 @@ export function buildProgram(options = {}) {
2030
2071
  .option('--subdir <path>', 'use a catalog snapshot below the Git repository root')
2031
2072
  .option('--no-auto-check', 'disable automatic update checks for this source')
2032
2073
  .option('--primary', 'make this source primary', false)
2074
+ .option('-y, --yes', 'confirm affected or unknown primary source references', false)
2033
2075
  .option('-j, --json', 'print mutation receipt as JSON', false)
2034
2076
  .action(async (id, rawOptions) => {
2035
2077
  try {
@@ -2040,7 +2082,7 @@ export function buildProgram(options = {}) {
2040
2082
  throw new Error('Git catalog source add requires exactly one of `--ref` or `--default-ref`.');
2041
2083
  }
2042
2084
  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`.');
2085
+ throw new Error('Path catalog source add only accepts `--path`, `--primary`, `--no-auto-check`, and `--yes`.');
2044
2086
  }
2045
2087
  const source = rawOptions.git !== undefined
2046
2088
  ? {
@@ -2059,11 +2101,23 @@ export function buildProgram(options = {}) {
2059
2101
  path: rawOptions.path,
2060
2102
  ...(rawOptions.autoCheck === false ? { autoCheck: false } : {}),
2061
2103
  };
2104
+ const preview = source.primary
2105
+ ? await preflightCatalogSourceMutation({
2106
+ request: { action: 'add', source }, cwd, env,
2107
+ })
2108
+ : undefined;
2062
2109
  const receipt = await addCatalogSourceCommand({
2063
2110
  source,
2064
2111
  cliVersion: resolveCliVersion(),
2065
2112
  cwd,
2066
2113
  env,
2114
+ ...(preview ? {
2115
+ expectedConfigDigest: preview.configDigest,
2116
+ expectedProposedConfigDigest: preview.proposedConfigDigest,
2117
+ expectedImpactDigest: preview.impactDigest,
2118
+ } : {}),
2119
+ requireImpactConfirmation: true,
2120
+ confirmImpact: rawOptions.yes === true,
2067
2121
  });
2068
2122
  if (rawOptions.json)
2069
2123
  writeJsonReceipt(io.stdout, receipt);
@@ -2129,12 +2183,18 @@ export function buildProgram(options = {}) {
2129
2183
  : {}),
2130
2184
  }
2131
2185
  : { autoCheck: rawOptions.autoCheck };
2186
+ const preview = await preflightCatalogSourceMutation({
2187
+ request: { action: 'update', sourceId: id, update }, cwd, env,
2188
+ });
2132
2189
  const receipt = await updateCatalogSourceCommand({
2133
2190
  sourceId: id,
2134
2191
  update,
2135
2192
  cliVersion: resolveCliVersion(),
2136
2193
  cwd,
2137
2194
  env,
2195
+ expectedConfigDigest: preview.configDigest,
2196
+ expectedProposedConfigDigest: preview.proposedConfigDigest,
2197
+ expectedImpactDigest: preview.impactDigest,
2138
2198
  requireIdentityChangeConfirmation: true,
2139
2199
  confirmIdentityChange: rawOptions.yes === true,
2140
2200
  });
@@ -2152,10 +2212,17 @@ export function buildProgram(options = {}) {
2152
2212
  catalogSource
2153
2213
  .command('set-primary')
2154
2214
  .argument('<id>')
2215
+ .option('-y, --yes', 'confirm affected or unknown primary source references', false)
2155
2216
  .option('-j, --json', 'print mutation receipt as JSON', false)
2156
2217
  .action(async (id, rawOptions) => {
2157
2218
  try {
2158
- const receipt = await setPrimaryCatalogSourceCommand({ sourceId: id, cwd, env });
2219
+ const receipt = await setPrimaryCatalogSourceCommand({
2220
+ sourceId: id,
2221
+ cwd,
2222
+ env,
2223
+ requireImpactConfirmation: true,
2224
+ confirmImpact: rawOptions.yes === true,
2225
+ });
2159
2226
  if (rawOptions.json)
2160
2227
  writeJsonReceipt(io.stdout, receipt);
2161
2228
  else
@@ -2209,18 +2276,22 @@ export function buildProgram(options = {}) {
2209
2276
  writeLine(io.stdout, `${entry.storeKey}: ${entry.category}, ${entry.status}, ${entry.reason}, ${bytes}`);
2210
2277
  }
2211
2278
  writeLine(io.stdout, `Reclaimable: ${result.totals.reclaimableEntries} item(s).`);
2279
+ if (result.errors.length > 0) {
2280
+ writeLine(io.stderr, `${result.errors.length} item(s) could not be fully inspected and were retained.`);
2281
+ }
2212
2282
  }
2283
+ commandExitState.exitCode = result.ok ? 0 : 1;
2213
2284
  }
2214
2285
  catch (error) {
2215
2286
  const failure = sanitizeCatalogSourceError(error, env);
2216
2287
  const message = redactString(failure.message);
2217
2288
  if (rawOptions.json)
2218
2289
  writeJsonReceipt(io.stdout, {
2219
- catalogStoreSchemaVersion: 1,
2290
+ catalogStoreSchemaVersion: 2,
2220
2291
  command: 'catalog:store:status',
2221
2292
  ok: false,
2222
2293
  entries: [],
2223
- errors: [{ code: catalogGenerationErrorCode(error), message }],
2294
+ errors: [{ code: catalogStoreErrorCode(error), message }],
2224
2295
  });
2225
2296
  writeLine(io.stderr, message);
2226
2297
  commandExitState.exitCode = 1;
@@ -2246,24 +2317,23 @@ export function buildProgram(options = {}) {
2246
2317
  else if (dryRun) {
2247
2318
  writeLine(io.stdout, `Dry run: ${result.entries.filter((entry) => entry.status === 'reclaimable').length} item(s) are reclaimable.`);
2248
2319
  writeLine(io.stdout, 'Run `aw catalog store prune --yes` to delete them.');
2320
+ if (result.errors.length > 0)
2321
+ writeLine(io.stderr, `${result.errors.length} item(s) could not be fully inspected and were retained.`);
2249
2322
  }
2250
2323
  else {
2251
2324
  writeLine(io.stdout, `Deleted ${result.deleted.length} Catalog store item(s) (${result.deletedBytes} bytes).`);
2252
2325
  if (result.errors.length > 0)
2253
- writeLine(io.stderr, `${result.errors.length} item(s) could not be deleted and were retained.`);
2326
+ writeLine(io.stderr, `${result.errors.length} item(s) could not be fully inspected or deleted and were retained.`);
2254
2327
  }
2255
2328
  commandExitState.exitCode = result.ok ? 0 : 1;
2256
2329
  }
2257
2330
  catch (error) {
2258
2331
  const failure = sanitizeCatalogSourceError(error, env);
2259
2332
  const message = redactString(failure.message);
2260
- const explicitCode = error.code;
2261
- const code = typeof explicitCode === 'string'
2262
- ? explicitCode
2263
- : catalogGenerationErrorCode(error);
2333
+ const code = catalogStoreErrorCode(error);
2264
2334
  if (rawOptions.json)
2265
2335
  writeJsonReceipt(io.stdout, {
2266
- catalogStoreSchemaVersion: 1,
2336
+ catalogStoreSchemaVersion: 2,
2267
2337
  command: 'catalog:store:prune',
2268
2338
  ok: false,
2269
2339
  overallState: 'failed',
@@ -2312,7 +2382,8 @@ export function buildProgram(options = {}) {
2312
2382
  .requiredOption('-p, --platform <platform>', 'codex, claude, or both')
2313
2383
  .option('-a, --all', 'reconcile every desired plugin in the selected scope', false)
2314
2384
  .option('--refresh', 'refresh only Catalog sources required by selected intent roots', false)
2315
- .option('-y, --yes', 'authorize shared native replacement or forced repair', false)
2385
+ .option('--script-timeout <ms>', 'override plugin preApply script timeout in milliseconds')
2386
+ .option('-y, --yes', 'authorize preApply and shared native replacement or forced repair', false)
2316
2387
  .option('--allow-managed-codex-install', 'allow this command to acquire or rebuild the pinned AW-managed Codex runtime', false)
2317
2388
  .option('-j, --json', 'print sync receipt as JSON', false)
2318
2389
  .option('-v, --verbose', 'show command diagnostics', false)
@@ -2324,6 +2395,7 @@ export function buildProgram(options = {}) {
2324
2395
  cwd: context.cwd,
2325
2396
  scope: rawOptions.scope,
2326
2397
  platform: rawOptions.platform,
2398
+ scriptTimeout: rawOptions.scriptTimeout,
2327
2399
  allowManagedCodexInstall: rawOptions.allowManagedCodexInstall,
2328
2400
  }));
2329
2401
  const syncPlatform = normalized.platform;
@@ -2340,6 +2412,7 @@ export function buildProgram(options = {}) {
2340
2412
  interactive: context.interactive && context.isTty && !context.isCi,
2341
2413
  prompt: context.prompt,
2342
2414
  allowManagedCodexInstall: rawOptions.allowManagedCodexInstall,
2415
+ scriptTimeoutMs: normalized.scriptTimeoutMs,
2343
2416
  }, context));
2344
2417
  if (rawOptions.json) {
2345
2418
  writeJsonReceipt(io.stdout, buildRebuildReceiptJson('sync', result));
@@ -2357,9 +2430,9 @@ export function buildProgram(options = {}) {
2357
2430
  .option('-s, --scope <scope>', 'project or user')
2358
2431
  .option('-p, --platform <platform>', 'codex | claude | both')
2359
2432
  .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')
2433
+ .option('--script-timeout <ms>', 'override plugin preApply script timeout in milliseconds')
2361
2434
  .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)
2435
+ .option('-y, --yes', 'authorize preApply and shared Codex native replacement', false)
2363
2436
  .option('-j, --json', 'print receipt as JSON', false)
2364
2437
  .option('-v, --verbose', 'show command diagnostics', false)
2365
2438
  .option('-D, --debug', 'write debug diagnostics to a log file', false)
@@ -2386,7 +2459,6 @@ export function buildProgram(options = {}) {
2386
2459
  .argument('[plugins...]')
2387
2460
  .option('-s, --scope <scope>', 'project or user')
2388
2461
  .option('-p, --platform <platform>', 'codex | claude | both')
2389
- .option('--script-timeout <ms>', 'override plugin postApply script timeout in milliseconds')
2390
2462
  .option('--allow-managed-codex-install', 'allow this command to acquire or rebuild the pinned AW-managed Codex runtime', false)
2391
2463
  .option('-j, --json', 'print receipt as JSON', false)
2392
2464
  .option('-v, --verbose', 'show command diagnostics', false)
@@ -2442,9 +2514,9 @@ export function buildProgram(options = {}) {
2442
2514
  .argument('[plugins...]')
2443
2515
  .option('-s, --scope <scope>', 'project or user')
2444
2516
  .option('-p, --platform <platform>', 'codex | claude | both')
2445
- .option('--script-timeout <ms>', 'override plugin postApply script timeout in milliseconds')
2517
+ .option('--script-timeout <ms>', 'override plugin preApply script timeout in milliseconds')
2446
2518
  .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)
2519
+ .option('-y, --yes', 'authorize preApply and shared Codex native replacement or forced reinstall', false)
2448
2520
  .option('-j, --json', 'print receipt as JSON', false)
2449
2521
  .option('-v, --verbose', 'show command diagnostics', false)
2450
2522
  .option('-D, --debug', 'write debug diagnostics to a log file', false)
@@ -2612,9 +2684,11 @@ export function buildProgram(options = {}) {
2612
2684
  .argument('[field]')
2613
2685
  .option('-s, --scope <scope>', 'project or user')
2614
2686
  .option('--value-json <json>', 'set the field to an exact JSON value')
2687
+ .option('--value-stdin', 'read the exact string value from stdin until EOF', false)
2615
2688
  .option('--preset <id>', 'set the field to the current manifest preset value')
2616
2689
  .option('--apply', 'apply the saved config to visible desired placements', false)
2617
- .option('-y, --yes', 'confirm shared Codex native config apply', false)
2690
+ .option('--script-timeout <ms>', 'override plugin preApply script timeout in milliseconds')
2691
+ .option('-y, --yes', 'confirm preApply and shared Codex native config apply', false)
2618
2692
  .option('-j, --json', 'print receipt as JSON', false)
2619
2693
  .option('-v, --verbose', 'show command diagnostics', false)
2620
2694
  .option('-D, --debug', 'write debug diagnostics to a log file', false)
@@ -2627,8 +2701,16 @@ export function buildProgram(options = {}) {
2627
2701
  try {
2628
2702
  outcome = await runActionWithContext(context, async () => {
2629
2703
  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>.');
2704
+ const scriptTimeoutMs = resolveScriptTimeoutMs(rawOptions);
2705
+ const explicitValueCount = [
2706
+ rawOptions.valueJson !== undefined,
2707
+ rawOptions.valueStdin === true,
2708
+ rawOptions.preset !== undefined,
2709
+ ].filter(Boolean).length;
2710
+ if (explicitValueCount > 1
2711
+ || (explicitValueCount === 0
2712
+ && !(context.interactive && context.isTty && !context.isCi && rawOptions.json !== true))) {
2713
+ throw new Error('Use exactly one of --value-json <json>, --value-stdin, or --preset <id>.');
2632
2714
  }
2633
2715
  return withResolvedConfigMutationPlugin(context, pluginName, async ({ pluginId, source, plugin }, awHomeMutationToken, catalogOperationContext) => {
2634
2716
  if (!plugin.manifest.config?.fields) {
@@ -2638,8 +2720,43 @@ export function buildProgram(options = {}) {
2638
2720
  if (!field) {
2639
2721
  throw new Error(`Unknown config key "${key}".`);
2640
2722
  }
2723
+ const sensitive = field.sensitive === true;
2724
+ if (sensitive && scope !== 'user') {
2725
+ const error = new Error('sensitiveProjectConfigUnsupported: Sensitive config can only be set in user scope.');
2726
+ error.code = 'sensitiveProjectConfigUnsupported';
2727
+ throw error;
2728
+ }
2729
+ if (sensitive && (rawOptions.valueJson !== undefined || rawOptions.preset !== undefined)) {
2730
+ const error = new Error('sensitiveConfigInputUnsupported: Sensitive config cannot use --value-json or --preset.');
2731
+ error.code = 'sensitiveConfigInputUnsupported';
2732
+ throw error;
2733
+ }
2734
+ if (!sensitive && explicitValueCount !== 1) {
2735
+ throw new Error('Use exactly one of --value-json <json>, --value-stdin, or --preset <id>.');
2736
+ }
2641
2737
  let inputValue;
2642
- if (rawOptions.valueJson !== undefined) {
2738
+ if (rawOptions.valueStdin === true) {
2739
+ inputValue = await readUtf8Stdin(context.stdin);
2740
+ }
2741
+ else if (sensitive) {
2742
+ if (!(context.interactive && context.isTty && !context.isCi && rawOptions.json !== true)
2743
+ || !context.prompt.password) {
2744
+ const error = new Error('sensitiveConfigStdinRequired: Use --value-stdin for sensitive config outside an interactive terminal.');
2745
+ error.code = 'sensitiveConfigStdinRequired';
2746
+ throw error;
2747
+ }
2748
+ const response = await context.prompt.password({
2749
+ message: `输入 ${field.title ?? key}`,
2750
+ mask: true,
2751
+ });
2752
+ if (response.cancelled || response.action !== 'select' || response.value === undefined) {
2753
+ const error = new Error('sensitiveConfigInputCancelled: Sensitive config input was cancelled.');
2754
+ error.code = 'sensitiveConfigInputCancelled';
2755
+ throw error;
2756
+ }
2757
+ inputValue = response.value;
2758
+ }
2759
+ else if (rawOptions.valueJson !== undefined) {
2643
2760
  try {
2644
2761
  inputValue = JSON.parse(rawOptions.valueJson);
2645
2762
  }
@@ -2665,6 +2782,7 @@ export function buildProgram(options = {}) {
2665
2782
  awHomeMutationToken,
2666
2783
  catalogOperationContext,
2667
2784
  expectedGenerationSetDigest: catalogOperationContext.generationSetDigest,
2785
+ ...(scriptTimeoutMs === undefined ? {} : { scriptTimeoutMs }),
2668
2786
  },
2669
2787
  awHomeMutationToken,
2670
2788
  request: {
@@ -2713,7 +2831,8 @@ export function buildProgram(options = {}) {
2713
2831
  .argument('[key]')
2714
2832
  .option('-s, --scope <scope>', 'project or user')
2715
2833
  .option('--apply', 'apply the saved config to visible desired placements', false)
2716
- .option('-y, --yes', 'confirm shared Codex native config apply', false)
2834
+ .option('--script-timeout <ms>', 'override plugin preApply script timeout in milliseconds')
2835
+ .option('-y, --yes', 'confirm preApply and shared Codex native config apply', false)
2717
2836
  .option('-j, --json', 'print receipt as JSON', false)
2718
2837
  .option('-v, --verbose', 'show command diagnostics', false)
2719
2838
  .option('-D, --debug', 'write debug diagnostics to a log file', false)
@@ -2724,13 +2843,12 @@ export function buildProgram(options = {}) {
2724
2843
  try {
2725
2844
  outcome = await runActionWithContext(context, async () => {
2726
2845
  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
- }
2846
+ const scriptTimeoutMs = resolveScriptTimeoutMs(rawOptions);
2847
+ const execute = async (selectedPlugin, selectedKey, confirmed) => withResolvedConfigMutationPlugin(context, selectedPlugin, async ({ pluginId, source, plugin }, awHomeMutationToken, catalogOperationContext) => {
2731
2848
  const store = await readPluginConfigStore({
2732
2849
  sourceId: source.sourceId,
2733
2850
  sourceIdentity: source.sourceIdentity,
2851
+ logicalIdentity: source.logicalIdentity,
2734
2852
  pluginName: plugin.manifest.name,
2735
2853
  scope,
2736
2854
  cwd: context.cwd,
@@ -2752,13 +2870,14 @@ export function buildProgram(options = {}) {
2752
2870
  awHomeMutationToken,
2753
2871
  catalogOperationContext,
2754
2872
  expectedGenerationSetDigest: catalogOperationContext.generationSetDigest,
2873
+ ...(scriptTimeoutMs === undefined ? {} : { scriptTimeoutMs }),
2755
2874
  },
2756
2875
  awHomeMutationToken,
2757
2876
  request: {
2758
2877
  removeKeys: [selectedKey],
2759
2878
  },
2760
2879
  apply: rawOptions.apply === true,
2761
- sharedNativeApplyConfirmed: rawOptions.yes === true,
2880
+ sharedNativeApplyConfirmed: confirmed,
2762
2881
  });
2763
2882
  return buildConfigMutationReceipt('config:unset', {
2764
2883
  ok: writeReceipt.overallState === 'succeeded',
@@ -2777,11 +2896,15 @@ export function buildProgram(options = {}) {
2777
2896
  reserved: false,
2778
2897
  action: 'unset',
2779
2898
  scope,
2899
+ ...(!plugin.manifest.config?.fields?.[selectedKey] ? { stale: true } : {}),
2780
2900
  }],
2781
2901
  });
2782
2902
  });
2783
2903
  if (pluginName && key) {
2784
- return { cancelled: false, value: await execute(pluginName, key) };
2904
+ return {
2905
+ cancelled: false,
2906
+ value: await execute(pluginName, key, rawOptions.yes === true),
2907
+ };
2785
2908
  }
2786
2909
  if (!isWizardAvailable(context, rawOptions))
2787
2910
  throw new Error(configCommandUsage('unset'));
@@ -2808,7 +2931,7 @@ export function buildProgram(options = {}) {
2808
2931
  scope: selection.scope ?? 'user',
2809
2932
  })),
2810
2933
  resultState: overallResultState,
2811
- execute: (selection) => execute(selection.plugins[0], selection.key),
2934
+ execute: (selection) => execute(selection.plugins[0], selection.key, true),
2812
2935
  });
2813
2936
  return result.cancelled
2814
2937
  ? { cancelled: true }
@@ -2838,6 +2961,7 @@ export function buildProgram(options = {}) {
2838
2961
  .argument('[plugin]')
2839
2962
  .option('-s, --scope <scope>', 'project or user')
2840
2963
  .option('--apply', 'apply the saved config to visible desired placements', false)
2964
+ .option('--script-timeout <ms>', 'override plugin preApply script timeout in milliseconds')
2841
2965
  .option('-y, --yes', 'confirm destructive reset', false)
2842
2966
  .option('-j, --json', 'print receipt as JSON', false)
2843
2967
  .option('-v, --verbose', 'show command diagnostics', false)
@@ -2849,6 +2973,7 @@ export function buildProgram(options = {}) {
2849
2973
  try {
2850
2974
  outcome = await runActionWithContext(context, async () => {
2851
2975
  const execute = async (selectedPlugin, selectedScope, confirmed) => {
2976
+ const scriptTimeoutMs = resolveScriptTimeoutMs(rawOptions);
2852
2977
  if (!confirmed) {
2853
2978
  throw new Error(`Reset requires confirmation. Re-run \`aw config reset ${selectedPlugin} -s ${selectedScope} --yes\` to delete this store.`);
2854
2979
  }
@@ -2861,6 +2986,7 @@ export function buildProgram(options = {}) {
2861
2986
  const affectedFields = await describeResetAffectedFields({
2862
2987
  sourceId: located.sourceId,
2863
2988
  sourceIdentity: located.sourceIdentity,
2989
+ logicalIdentity: located.logicalIdentity,
2864
2990
  pluginName: located.pluginName,
2865
2991
  plugin,
2866
2992
  pluginError,
@@ -2871,6 +2997,7 @@ export function buildProgram(options = {}) {
2871
2997
  const resetReceipt = await resetPluginConfigWithHelper({
2872
2998
  sourceId: located.sourceId,
2873
2999
  sourceIdentity: located.sourceIdentity,
3000
+ logicalIdentity: located.logicalIdentity,
2874
3001
  pluginName: located.pluginName,
2875
3002
  scope: selectedScope,
2876
3003
  cwd: context.cwd,
@@ -2879,6 +3006,8 @@ export function buildProgram(options = {}) {
2879
3006
  plugin,
2880
3007
  pluginError,
2881
3008
  apply: rawOptions.apply === true,
3009
+ rebuildRuntime: scriptTimeoutMs === undefined ? undefined : { scriptTimeoutMs },
3010
+ sharedNativeApplyConfirmed: confirmed,
2882
3011
  });
2883
3012
  return buildConfigMutationReceipt('config:reset', {
2884
3013
  ok: resetReceipt.overallState === 'succeeded',
@@ -3115,11 +3244,12 @@ export async function runCli(argv, options = {}) {
3115
3244
  const message = 'option --subdir cannot be used with option --no-subdir';
3116
3245
  if (argv.includes('--json') && argv[0] === 'catalog' && argv[1] === 'source' && argv[2] === 'update') {
3117
3246
  writeJsonReceipt(io.stdout, {
3118
- receiptSchemaVersion: 5,
3247
+ receiptSchemaVersion: 6,
3119
3248
  command: 'catalog:source:update',
3120
3249
  ok: false,
3121
3250
  changed: false,
3122
3251
  sourceId: argv[3] ?? '',
3252
+ primaryChange: null,
3123
3253
  references: [],
3124
3254
  errors: [{ code: 'catalogSourceOptionConflict', message }],
3125
3255
  });
@@ -3132,11 +3262,12 @@ export async function runCli(argv, options = {}) {
3132
3262
  const message = 'option --auto-check cannot be used with option --no-auto-check';
3133
3263
  if (argv.includes('--json') || argv.includes('-j')) {
3134
3264
  writeJsonReceipt(io.stdout, {
3135
- receiptSchemaVersion: 5,
3265
+ receiptSchemaVersion: 6,
3136
3266
  command: 'catalog:source:update',
3137
3267
  ok: false,
3138
3268
  changed: false,
3139
3269
  sourceId: argv[3] ?? '',
3270
+ primaryChange: null,
3140
3271
  references: [],
3141
3272
  errors: [{ code: 'catalogSourceOptionConflict', message }],
3142
3273
  });