@lesliechan721/aw 0.1.0-beta.54 → 0.1.0-beta.56

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 (109) hide show
  1. package/dist/authoring/scripts/lib/plugin-version-check.mjs +1 -1
  2. package/dist/authoring/scripts/validate-plugin.mjs +208 -31
  3. package/dist/authoring/scripts/validate-plugin.mjs.map +1 -1
  4. package/dist/scripts/bundle-plugins.js +8 -3
  5. package/dist/scripts/bundle-plugins.js.map +1 -1
  6. package/dist/src/adapters/helpers.d.ts +7 -0
  7. package/dist/src/adapters/helpers.js.map +1 -1
  8. package/dist/src/commands/aw-capabilities.d.ts +1 -1
  9. package/dist/src/commands/aw-capabilities.js +2 -0
  10. package/dist/src/commands/aw-capabilities.js.map +1 -1
  11. package/dist/src/commands/managed-commands.d.ts +26 -0
  12. package/dist/src/commands/managed-commands.js +277 -0
  13. package/dist/src/commands/managed-commands.js.map +1 -0
  14. package/dist/src/commands/operation-plan.d.ts +30 -1
  15. package/dist/src/commands/operation-plan.js.map +1 -1
  16. package/dist/src/commands/operation-planner.d.ts +1 -0
  17. package/dist/src/commands/operation-planner.js +1 -0
  18. package/dist/src/commands/operation-planner.js.map +1 -1
  19. package/dist/src/commands/plugin-capabilities.js +29 -1
  20. package/dist/src/commands/plugin-capabilities.js.map +1 -1
  21. package/dist/src/commands/rebuild-command.d.ts +2 -1
  22. package/dist/src/commands/rebuild-command.js +66 -26
  23. package/dist/src/commands/rebuild-command.js.map +1 -1
  24. package/dist/src/commands/rebuild-integration.d.ts +13 -1
  25. package/dist/src/commands/rebuild-integration.js +535 -61
  26. package/dist/src/commands/rebuild-integration.js.map +1 -1
  27. package/dist/src/commands/rebuild-operations.d.ts +3 -1
  28. package/dist/src/commands/rebuild-operations.js +9 -5
  29. package/dist/src/commands/rebuild-operations.js.map +1 -1
  30. package/dist/src/generators/local-plugin.js +16 -0
  31. package/dist/src/generators/local-plugin.js.map +1 -1
  32. package/dist/src/generators/permissions.d.ts +5 -2
  33. package/dist/src/generators/permissions.js +28 -15
  34. package/dist/src/generators/permissions.js.map +1 -1
  35. package/dist/src/index.js +11 -0
  36. package/dist/src/index.js.map +1 -1
  37. package/dist/src/output/command-receipt.d.ts +3 -1
  38. package/dist/src/output/command-receipt.js +30 -9
  39. package/dist/src/output/command-receipt.js.map +1 -1
  40. package/dist/src/output/rebuild-progress.js +14 -0
  41. package/dist/src/output/rebuild-progress.js.map +1 -1
  42. package/dist/src/portable/materializer.js +3 -0
  43. package/dist/src/portable/materializer.js.map +1 -1
  44. package/dist/src/review/skill-materialization.d.ts +14 -1
  45. package/dist/src/review/skill-materialization.js +138 -0
  46. package/dist/src/review/skill-materialization.js.map +1 -1
  47. package/dist/src/tui/console-app-v4.js +19 -7
  48. package/dist/src/tui/console-app-v4.js.map +1 -1
  49. package/dist/src/tui/controller-runtime.js +23 -9
  50. package/dist/src/tui/controller-runtime.js.map +1 -1
  51. package/dist/src/tui/controller.d.ts +5 -1
  52. package/dist/src/tui/controller.js +24 -3
  53. package/dist/src/tui/controller.js.map +1 -1
  54. package/dist/src/tui/diagnostic-projection.js +34 -6
  55. package/dist/src/tui/diagnostic-projection.js.map +1 -1
  56. package/dist/src/tui/operation-review-planner.js +102 -16
  57. package/dist/src/tui/operation-review-planner.js.map +1 -1
  58. package/dist/src/types.d.ts +22 -2
  59. package/dist/src/types.js.map +1 -1
  60. package/dist/src/utils/artifact-plan.d.ts +4 -3
  61. package/dist/src/utils/artifact-plan.js +50 -7
  62. package/dist/src/utils/artifact-plan.js.map +1 -1
  63. package/dist/src/utils/artifact-renderer.d.ts +7 -3
  64. package/dist/src/utils/artifact-renderer.js +19 -6
  65. package/dist/src/utils/artifact-renderer.js.map +1 -1
  66. package/dist/src/utils/artifact-request.d.ts +16 -5
  67. package/dist/src/utils/artifact-request.js +27 -15
  68. package/dist/src/utils/artifact-request.js.map +1 -1
  69. package/dist/src/utils/artifact-sources.d.ts +4 -0
  70. package/dist/src/utils/artifact-sources.js +17 -0
  71. package/dist/src/utils/artifact-sources.js.map +1 -1
  72. package/dist/src/utils/bundle-layout.js +7 -0
  73. package/dist/src/utils/bundle-layout.js.map +1 -1
  74. package/dist/src/utils/claude-skills-root.d.ts +8 -0
  75. package/dist/src/utils/claude-skills-root.js +76 -0
  76. package/dist/src/utils/claude-skills-root.js.map +1 -0
  77. package/dist/src/utils/codex-skills-root.d.ts +4 -0
  78. package/dist/src/utils/codex-skills-root.js +25 -0
  79. package/dist/src/utils/codex-skills-root.js.map +1 -0
  80. package/dist/src/utils/dynamic-skill-tree.d.ts +1 -0
  81. package/dist/src/utils/dynamic-skill-tree.js +25 -6
  82. package/dist/src/utils/dynamic-skill-tree.js.map +1 -1
  83. package/dist/src/utils/local-marketplace.d.ts +9 -0
  84. package/dist/src/utils/local-marketplace.js +170 -90
  85. package/dist/src/utils/local-marketplace.js.map +1 -1
  86. package/dist/src/utils/managed-command-closure.d.ts +3 -0
  87. package/dist/src/utils/managed-command-closure.js +35 -0
  88. package/dist/src/utils/managed-command-closure.js.map +1 -0
  89. package/dist/src/utils/managed-command-evidence.d.ts +7 -0
  90. package/dist/src/utils/managed-command-evidence.js +86 -0
  91. package/dist/src/utils/managed-command-evidence.js.map +1 -0
  92. package/dist/src/utils/managed-command-materialization.d.ts +106 -0
  93. package/dist/src/utils/managed-command-materialization.js +307 -0
  94. package/dist/src/utils/managed-command-materialization.js.map +1 -0
  95. package/dist/src/utils/managed-command-runtime.d.ts +32 -0
  96. package/dist/src/utils/managed-command-runtime.js +110 -0
  97. package/dist/src/utils/managed-command-runtime.js.map +1 -0
  98. package/dist/src/utils/managed-command-store.d.ts +124 -0
  99. package/dist/src/utils/managed-command-store.js +576 -0
  100. package/dist/src/utils/managed-command-store.js.map +1 -0
  101. package/dist/src/utils/ownership.d.ts +2 -0
  102. package/dist/src/utils/plugin-config-impact.d.ts +8 -1
  103. package/dist/src/utils/plugin-config-impact.js +101 -26
  104. package/dist/src/utils/plugin-config-impact.js.map +1 -1
  105. package/dist/src/utils/plugin-config-write.js +142 -60
  106. package/dist/src/utils/plugin-config-write.js.map +1 -1
  107. package/dist/src/utils/rendered-contract.js +18 -1
  108. package/dist/src/utils/rendered-contract.js.map +1 -1
  109. package/package.json +3 -3
@@ -10,7 +10,7 @@ import { fileURLToPath, pathToFileURL } from 'node:url';
10
10
  import { compareStrictSemVer, parseStrictSemVer } from './semver.mjs';
11
11
  import { assertAuthoringPluginPathFence, resolveAuthoringPluginRoot, } from './plugin-root.mjs';
12
12
  const execFileAsync = promisify(execFile);
13
- const EXPECTED_MANIFEST_CONTRACT_VERSION = 16;
13
+ const EXPECTED_MANIFEST_CONTRACT_VERSION = 17;
14
14
  const PLUGIN_NAME_PATTERN = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
15
15
  const GIT_OBJECT_ID_PATTERN = /^(?:[0-9a-f]{40}|[0-9a-f]{64})$/u;
16
16
  const MAX_GIT_BLOB_BYTES = 50 * 1024 * 1024;
@@ -6,7 +6,7 @@ import { createRequire } from 'node:module';
6
6
  import * as os from 'node:os';
7
7
  import * as path from 'node:path';
8
8
  import { fileURLToPath, pathToFileURL } from 'node:url';
9
- import { AW_RUNTIME_CONFIG_READER_PATH, createRuntimeConfigSnapshot, getPluginAuthoringAcceptedValues as getCorePluginAuthoringAcceptedValues, getSkillFrontmatterCapabilityRegistry, normalizePluginConfigDefinition, } from '@lesliechan721/aw-plugin-core/manifest';
9
+ import { AW_RUNTIME_CONFIG_READER_PATH, createRuntimeConfigSnapshot, getPluginAuthoringAcceptedValues as getCorePluginAuthoringAcceptedValues, getSkillFrontmatterCapabilityRegistry, getManagedCommandArtifactTargets, normalizePluginConfigDefinition, parseManagedCommandPlaceholders, replaceManagedCommandPlaceholders, validateCommandEntryFiles, } from '@lesliechan721/aw-plugin-core/manifest';
10
10
  import { checkPluginVersions } from './lib/plugin-version-check.mjs';
11
11
  import { scanJavaScriptImportSpecifiers } from './lib/javascript-import-scanner.mjs';
12
12
  import { assertAuthoringPluginPathFence, assertCanonicalAuthoringPluginRoot, } from './lib/plugin-root.mjs';
@@ -18,7 +18,7 @@ const CLI_PACKAGE_ROOT = path.basename(authoringRuntimeRoot) === 'dist'
18
18
  : authoringRuntimeRoot;
19
19
  const errors = [];
20
20
  const warnings = [];
21
- const SOURCE_PLUGIN_MANIFEST_CONTRACT_VERSION = 16;
21
+ const SOURCE_PLUGIN_MANIFEST_CONTRACT_VERSION = 17;
22
22
  let capabilityDiagnostic = null;
23
23
  const MAX_SKILL_NAME_LEN = 64;
24
24
  const MAX_SKILL_DESCRIPTION_LEN = 1024;
@@ -315,18 +315,25 @@ async function tryLoadCliManifestTools() {
315
315
  const manifestModulePath = path.join(CLI_PACKAGE_ROOT, 'dist', 'src', 'utils', 'manifest.js');
316
316
  const runtimeProjectionModulePath = path.join(CLI_PACKAGE_ROOT, 'dist', 'src', 'utils', 'catalog-runtime-projection.js');
317
317
  const capabilityModulePath = path.join(CLI_PACKAGE_ROOT, 'dist', 'src', 'commands', 'aw-capabilities.js');
318
+ const artifactPlanPath = path.join(CLI_PACKAGE_ROOT, 'dist', 'src', 'utils', 'artifact-plan.js');
319
+ const artifactRequestPath = path.join(CLI_PACKAGE_ROOT, 'dist', 'src', 'utils', 'artifact-request.js');
320
+ const commandMaterializationPath = path.join(CLI_PACKAGE_ROOT, 'dist', 'src', 'utils', 'managed-command-materialization.js');
318
321
  if (!fs.existsSync(manifestModulePath)
319
322
  || !fs.existsSync(runtimeProjectionModulePath)
320
323
  || !fs.existsSync(capabilityModulePath))
321
324
  return null;
322
325
  try {
323
- const [manifestModule, runtimeProjectionModule, capabilityModule] = await Promise.all([
326
+ const [manifestModule, runtimeProjectionModule, capabilityModule, artifactPlanModule, artifactRequestModule, commandModule] = await Promise.all([
324
327
  import(pathToFileURL(manifestModulePath).href),
325
328
  import(pathToFileURL(runtimeProjectionModulePath).href),
326
329
  import(pathToFileURL(capabilityModulePath).href),
330
+ import(pathToFileURL(artifactPlanPath).href),
331
+ import(pathToFileURL(artifactRequestPath).href),
332
+ import(pathToFileURL(commandMaterializationPath).href),
327
333
  ]);
328
334
  if (manifestModule.SOURCE_PLUGIN_MANIFEST_CONTRACT_VERSION
329
- !== SOURCE_PLUGIN_MANIFEST_CONTRACT_VERSION) {
335
+ !== SOURCE_PLUGIN_MANIFEST_CONTRACT_VERSION
336
+ || typeof artifactRequestModule.requiresNonSensitiveArtifactInput !== 'function') {
330
337
  return null;
331
338
  }
332
339
  return {
@@ -337,6 +344,11 @@ async function tryLoadCliManifestTools() {
337
344
  resolvePluginRequirements: manifestModule.resolvePluginRequirements ?? null,
338
345
  implementedCapabilities: capabilityModule.IMPLEMENTED_AW_CAPABILITIES ?? null,
339
346
  createRuntimeResolver: runtimeProjectionModule.createCatalogRuntimeImportResolver ?? null,
347
+ validateArtifactPlan: artifactPlanModule.validateArtifactPlan,
348
+ requiresNonSensitiveArtifactInput: artifactRequestModule.requiresNonSensitiveArtifactInput,
349
+ prepareManagedCommandPackageFiles: commandModule.prepareManagedCommandPackageFiles,
350
+ managedCommandProducerIdentity: commandModule.managedCommandProducerIdentity,
351
+ createManagedCommandReferenceResolver: commandModule.createManagedCommandReferenceResolver,
340
352
  };
341
353
  }
342
354
  catch {
@@ -505,6 +517,7 @@ function validateManifestLightweight(manifest) {
505
517
  'scripts',
506
518
  'config',
507
519
  'artifacts',
520
+ 'managedCommands',
508
521
  ]);
509
522
  if (manifest.dependencies !== undefined) {
510
523
  if (!Array.isArray(manifest.dependencies)) {
@@ -2366,7 +2379,25 @@ function validateRenderedSkillTree(options) {
2366
2379
  }
2367
2380
  for (const [relativePath, content] of files) {
2368
2381
  const text = content.toString('utf8');
2369
- if (/\{\{[^{}]+\}\}/u.test(text)) {
2382
+ let remaining = text;
2383
+ if (relativePath.endsWith('.md')) {
2384
+ try {
2385
+ const placeholders = parseManagedCommandPlaceholders(text);
2386
+ if (placeholders.length > 0 && !(manifest.requires?.aw?.capabilities ?? []).includes('aw.managed-commands.v1')) {
2387
+ error(`${fieldName} managed command references require aw.managed-commands.v1`);
2388
+ }
2389
+ if (declaration.target === 'agent-skills.skill' && placeholders.length > 0) {
2390
+ error(`${fieldName} managedCommandPortableUnsupported: Portable Skills cannot contain managed command references`);
2391
+ }
2392
+ else if (options.managedTrees) {
2393
+ remaining = replaceManagedCommandPlaceholders(text, () => `cmdp_${'0'.repeat(16)}`);
2394
+ }
2395
+ }
2396
+ catch (cause) {
2397
+ error(`${fieldName} ${cause.message}`);
2398
+ }
2399
+ }
2400
+ if (/\{\{[^{}]+\}\}/u.test(remaining)) {
2370
2401
  error(`${fieldName} final file tree contains an unresolved template in "${relativePath}"`);
2371
2402
  }
2372
2403
  }
@@ -2385,6 +2416,7 @@ function validateRenderedSkillTree(options) {
2385
2416
  if (declaration.target === 'codex.skill' && files.has('agents/openai.yaml')) {
2386
2417
  validateOpenAiYaml(path.join(materializedRoot, 'agents', 'openai.yaml'), declaration.skillKey, true, manifest, materializedRoot, skillValidationTools);
2387
2418
  }
2419
+ options.managedTrees?.push({ declaration, files, scope: options.managedScope });
2388
2420
  }
2389
2421
  function validateStaticPortableFinalTrees(pluginDir, manifest, runtimeImports, skillValidationTools) {
2390
2422
  const portableRoot = manifest.distributions?.agentSkills?.skills;
@@ -2444,6 +2476,12 @@ function validateRenderedArtifactPlan(plan, declarations, scopeLabel, options) {
2444
2476
  const entry = expectRecord(artifact, fieldName);
2445
2477
  if (!entry)
2446
2478
  return;
2479
+ if (entry.target === 'aw.command-set' || entry.target === 'aw.command-package') {
2480
+ const declaration = byKey.get(`${entry.id}:${entry.target}`);
2481
+ if (declaration)
2482
+ returned.add(`${entry.id}:${entry.target}`);
2483
+ return; // Shared ArtifactPlan validation owns command response fields.
2484
+ }
2447
2485
  validateAllowedKeys(entry, fieldName, [
2448
2486
  'id',
2449
2487
  'platform',
@@ -2550,6 +2588,8 @@ function validateRenderedArtifactPlan(plan, declarations, scopeLabel, options) {
2550
2588
  runtimeImports: options.runtimeImports,
2551
2589
  materializedRoot: path.join(options.tempRoot, `${declaration.platform ?? declaration.distribution}-${scopeLabel.split('/')[1]}-${index}`),
2552
2590
  skillValidationTools: options.skillValidationTools,
2591
+ managedTrees: options.managedTrees,
2592
+ managedScope: scopeLabel.split('/')[1],
2553
2593
  });
2554
2594
  }
2555
2595
  }
@@ -2564,7 +2604,7 @@ function validateRenderedArtifactPlan(plan, declarations, scopeLabel, options) {
2564
2604
  }
2565
2605
  }
2566
2606
  }
2567
- function resolveArtifactRendererFixtureRequests(declarations, manifest) {
2607
+ function resolveArtifactRendererFixtureRequests(declarations, manifest, requiresNonSensitiveArtifactInput) {
2568
2608
  const awOwned = new Map();
2569
2609
  const codexNative = new Map();
2570
2610
  for (const declaration of declarations) {
@@ -2581,7 +2621,9 @@ function resolveArtifactRendererFixtureRequests(declarations, manifest) {
2581
2621
  codexNative.set(scope, request);
2582
2622
  continue;
2583
2623
  }
2584
- const surface = declaration.platform ?? declaration.distribution;
2624
+ const surface = declaration.surface?.kind === 'aw'
2625
+ ? declaration.surface.name
2626
+ : declaration.platform ?? declaration.distribution;
2585
2627
  if (!surface)
2586
2628
  continue;
2587
2629
  for (const scope of declaration.scopes) {
@@ -2598,37 +2640,33 @@ function resolveArtifactRendererFixtureRequests(declarations, manifest) {
2598
2640
  }
2599
2641
  }
2600
2642
  const partitionedAwOwned = [...awOwned.values()].flatMap((request) => {
2601
- const hasSkill = request.declarations.some((declaration) => declaration.target === 'codex.skill'
2602
- || declaration.target === 'claude.skill'
2603
- || declaration.target === 'agent-skills.skill');
2604
- const hasSensitiveNonSkill = request.declarations.some((declaration) => declaration.target !== 'codex.skill'
2605
- && declaration.target !== 'claude.skill'
2606
- && declaration.target !== 'agent-skills.skill'
2643
+ const hasNonSensitiveTarget = request.declarations.some(requiresNonSensitiveArtifactInput);
2644
+ const hasSensitiveOtherTarget = request.declarations.some((declaration) => !requiresNonSensitiveArtifactInput(declaration)
2607
2645
  && declaration.refreshKeys.some((key) => configFieldContainsSensitiveValue(manifest.config?.fields?.[key])));
2608
- if (!hasSkill || !hasSensitiveNonSkill)
2646
+ if (!hasNonSensitiveTarget || !hasSensitiveOtherTarget)
2609
2647
  return [request];
2610
- const skillDeclarations = request.declarations.filter((declaration) => declaration.target === 'codex.skill'
2611
- || declaration.target === 'claude.skill'
2612
- || declaration.target === 'agent-skills.skill');
2613
- const nonSkillDeclarations = request.declarations.filter((declaration) => !skillDeclarations.includes(declaration));
2648
+ const nonSensitiveDeclarations = request.declarations.filter(requiresNonSensitiveArtifactInput);
2649
+ const otherDeclarations = request.declarations.filter((declaration) => !requiresNonSensitiveArtifactInput(declaration));
2614
2650
  return [
2615
- { ...request, declarations: skillDeclarations },
2616
- { ...request, declarations: nonSkillDeclarations },
2651
+ { ...request, declarations: nonSensitiveDeclarations },
2652
+ { ...request, declarations: otherDeclarations },
2617
2653
  ];
2618
2654
  });
2619
2655
  return [...partitionedAwOwned, ...codexNative.values()];
2620
2656
  }
2621
- function runArtifactRendererFixture(pluginDir, manifest, renderEntry, declarations, resolvedRuntimeImports, skillValidationTools) {
2657
+ async function runArtifactRendererFixture(pluginDir, manifest, renderEntry, declarations, resolvedRuntimeImports, skillValidationTools, managedContext, requiresNonSensitiveArtifactInput) {
2622
2658
  if (!renderEntry || declarations.length === 0)
2623
- return;
2624
- const requests = resolveArtifactRendererFixtureRequests(declarations, manifest);
2659
+ return [];
2660
+ const requests = resolveArtifactRendererFixtureRequests(declarations, manifest, requiresNonSensitiveArtifactInput);
2625
2661
  const values = defaultConfigValues(manifest);
2626
2662
  const tempRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'aw-artifact-render-'));
2663
+ const returnedArtifacts = [];
2627
2664
  try {
2628
2665
  for (const [requestIndex, request] of requests.entries()) {
2629
2666
  const { kind, surface, scope, configScope, declarations: scopedDeclarations, } = request;
2630
2667
  const distribution = surface === 'agent-skills' ? surface : undefined;
2631
- const platform = distribution ? undefined : surface;
2668
+ const awSurface = surface === 'managed-commands';
2669
+ const platform = distribution || awSurface ? undefined : surface;
2632
2670
  const event = distribution ? 'materialize' : 'install';
2633
2671
  const requestRoot = path.join(tempRoot, `${requestIndex}-${kind}-${surface}-${scope}`);
2634
2672
  const rendererAwHome = path.join(requestRoot, 'aw-home');
@@ -2636,7 +2674,7 @@ function runArtifactRendererFixture(pluginDir, manifest, renderEntry, declaratio
2636
2674
  const rendererClaudeHome = path.join(requestRoot, 'claude-home');
2637
2675
  fs.mkdirSync(requestRoot, { recursive: true });
2638
2676
  const contextPath = path.join(requestRoot, 'context.json');
2639
- const runtimeImports = scopedDeclarations.flatMap((target) => target.runtimeImports.map((runtimeImport, importIndex) => {
2677
+ const runtimeImports = scopedDeclarations.flatMap((target) => (target.runtimeImports ?? []).map((runtimeImport, importIndex) => {
2640
2678
  const resolved = resolvedRuntimeImports?.artifactImports.get(authorRuntimeImportKey(target.id, importIndex));
2641
2679
  if (!resolved)
2642
2680
  return null;
@@ -2684,7 +2722,7 @@ function runArtifactRendererFixture(pluginDir, manifest, renderEntry, declaratio
2684
2722
  }
2685
2723
  fs.writeFileSync(contextPath, JSON.stringify({
2686
2724
  event,
2687
- surface: distribution
2725
+ surface: awSurface ? { kind: 'aw', name: 'managed-commands' } : distribution
2688
2726
  ? { kind: 'distribution', name: distribution }
2689
2727
  : { kind: 'platform', name: platform },
2690
2728
  ...(platform ? { platform } : {}),
@@ -2713,6 +2751,9 @@ function runArtifactRendererFixture(pluginDir, manifest, renderEntry, declaratio
2713
2751
  target: target.target,
2714
2752
  sourceDirs: target.sourceDirs.map((sourceDir) => path.join(pluginDir, normalizeRelativePath(sourceDir))),
2715
2753
  })),
2754
+ commandSources: (managedContext?.manifest.managedCommands?.packages ?? [])
2755
+ .filter((entry) => scopedDeclarations.some((target) => target.packageKey === entry.key))
2756
+ .map((entry) => ({ packageKey: entry.key, sourceDir: path.join(pluginDir, normalizeRelativePath(entry.sourceDir)) })),
2716
2757
  runtimeImports,
2717
2758
  paths: {
2718
2759
  awHome: rendererAwHome,
@@ -2747,6 +2788,7 @@ function runArtifactRendererFixture(pluginDir, manifest, renderEntry, declaratio
2747
2788
  AW_PLUGIN_EVENT: event,
2748
2789
  ...(platform ? { AW_PLUGIN_PLATFORM: platform } : {}),
2749
2790
  ...(distribution ? { AW_PLUGIN_DISTRIBUTION: distribution } : {}),
2791
+ ...(awSurface ? { AW_PLUGIN_SURFACE: 'managed-commands' } : {}),
2750
2792
  AW_PLUGIN_SCOPE: scope,
2751
2793
  };
2752
2794
  if (process.platform === 'win32') {
@@ -2793,24 +2835,153 @@ function runArtifactRendererFixture(pluginDir, manifest, renderEntry, declaratio
2793
2835
  runtimeImports: resolvedRuntimeImports,
2794
2836
  tempRoot,
2795
2837
  skillValidationTools,
2838
+ managedTrees: managedContext?.trees,
2796
2839
  });
2840
+ if (managedContext) {
2841
+ try {
2842
+ const validated = managedContext.tools.validateArtifactPlan({
2843
+ manifest: managedContext.manifest,
2844
+ plan,
2845
+ platform: surface,
2846
+ scope,
2847
+ requestedArtifactIds: scopedDeclarations.map((target) => target.id),
2848
+ renderConfig: { values: scopedValues, sources: Object.fromEntries(Object.keys(scopedValues).map((key) => [key, 'default'])), issues: [] },
2849
+ });
2850
+ returnedArtifacts.push(...validated.artifacts.map((artifact) => ({ artifact, scope, surface })));
2851
+ }
2852
+ catch (cause) {
2853
+ error(`${fieldName}: ${cause.message}`);
2854
+ }
2855
+ }
2797
2856
  }
2798
2857
  }
2799
2858
  finally {
2800
2859
  fs.rmSync(tempRoot, { recursive: true, force: true });
2801
2860
  }
2861
+ return returnedArtifacts;
2802
2862
  }
2803
- function validateDynamicArtifactsLightweight(pluginDir, manifest, renderEntry, runtimeImports, skillValidationTools) {
2863
+ async function validateDynamicArtifactsLightweight(pluginDir, manifest, renderEntry, runtimeImports, skillValidationTools, managedContext, requiresNonSensitiveArtifactInput) {
2804
2864
  const declarations = validateArtifactsConfigLightweight(pluginDir, manifest);
2865
+ if (managedContext)
2866
+ declarations.push(...getManagedCommandArtifactTargets(managedContext.manifest));
2805
2867
  const hasTargets = declarations.length > 0;
2806
2868
  const hasRenderer = Boolean(manifest.scripts?.artifacts?.render);
2807
2869
  if (hasTargets && !hasRenderer) {
2808
2870
  error('artifacts.targets requires scripts.artifacts.render');
2809
2871
  }
2810
2872
  if (hasRenderer && !hasTargets) {
2811
- error('scripts.artifacts.render requires artifacts.targets');
2873
+ error('scripts.artifacts.render requires artifacts.targets or dynamic managedCommands targets');
2874
+ }
2875
+ return runArtifactRendererFixture(pluginDir, manifest, renderEntry, declarations, runtimeImports, skillValidationTools, managedContext, requiresNonSensitiveArtifactInput);
2876
+ }
2877
+ async function validateAuthorManagedCommands(pluginDir, manifest, rendered, context) {
2878
+ const { tools, trees } = context;
2879
+ const tempRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'aw-author-commands-'));
2880
+ const env = { AW_HOME: path.join(tempRoot, 'aw-home'), AW_CODEX_HOME: path.join(tempRoot, 'codex-home'), AW_CLAUDE_HOME: path.join(tempRoot, 'claude-home') };
2881
+ const plugin = { manifest, rootDir: pluginDir, sourceId: 'authoring', sourceIdentity: `sha256:${'0'.repeat(64)}` };
2882
+ const candidates = [];
2883
+ const cleanups = [];
2884
+ try {
2885
+ const root = manifest.skills && path.join(pluginDir, normalizeRelativePath(manifest.skills));
2886
+ if (root && fs.existsSync(root)) {
2887
+ for (const entry of fs.readdirSync(root, { withFileTypes: true })) {
2888
+ if (!entry.isDirectory())
2889
+ continue;
2890
+ for (const platform of targetedPlatforms(manifest)) {
2891
+ if ((manifest.artifacts?.targets ?? []).some((target) => target.platform === platform && target.kind === 'skill' && target.skillKey === entry.name))
2892
+ continue;
2893
+ const files = new Map();
2894
+ collectArtifactSourceFiles(path.join(root, entry.name), `static Skill ${entry.name}`, files);
2895
+ for (const [relative, bytes] of files) {
2896
+ if (isTemplateTextFile(relative))
2897
+ files.set(relative, Buffer.from(renderTemplateForPlatform(manifest, `${normalizeRelativePath(manifest.skills)}/${entry.name}/${relative}`, bytes.toString('utf8'), platform)));
2898
+ }
2899
+ const producer = await tools.managedCommandProducerIdentity({
2900
+ plugin,
2901
+ producer: { kind: 'static-skill', platform, skillKey: entry.name },
2902
+ scope: 'user',
2903
+ cwd: pluginDir,
2904
+ });
2905
+ trees.push({ declaration: { target: `${platform}.skill`, platform, skillKey: entry.name, staticSkill: true }, files, scope: producer.scope });
2906
+ }
2907
+ }
2908
+ }
2909
+ const setOutputs = (set, platform, scope) => {
2910
+ if (set.mode === 'static')
2911
+ return { set: set.set, state: 'present', entries: set.entries };
2912
+ const output = rendered.find((entry) => entry.artifact.id === `command-set.${set.set}` && entry.scope === scope && entry.surface === platform)?.artifact;
2913
+ if (!output)
2914
+ throw new Error(`commandReferenceInvalid: dynamic command set ${set.set} was not returned`);
2915
+ return { set: set.set, state: output.state, entries: output.entries };
2916
+ };
2917
+ for (const commandPackage of manifest.managedCommands?.packages ?? []) {
2918
+ const sets = (manifest.managedCommands?.sets ?? [])
2919
+ .filter((set) => set.producer.kind === 'package' && set.producer.packageKey === commandPackage.key)
2920
+ .map((set) => setOutputs(set, 'managed-commands', commandPackage.scope));
2921
+ const files = rendered.find((entry) => entry.artifact.id === `command-package.${commandPackage.key}`)?.artifact.files ?? {};
2922
+ const prepared = await tools.prepareManagedCommandPackageFiles({ sourceRoot: path.join(pluginDir, normalizeRelativePath(commandPackage.sourceDir)), files, entries: sets.flatMap((set) => set.entries) });
2923
+ cleanups.push(prepared.cleanup);
2924
+ candidates.push({ producer: await tools.managedCommandProducerIdentity({ plugin, producer: { kind: 'package', packageKey: commandPackage.key }, scope: commandPackage.scope, cwd: pluginDir }), sets });
2925
+ }
2926
+ for (const [index, tree] of trees.entries()) {
2927
+ const { declaration } = tree;
2928
+ const scope = declaration.delivery?.mode === 'codex-native' ? 'user' : tree.scope;
2929
+ if (!declaration.platform)
2930
+ continue;
2931
+ const producer = declaration.staticSkill
2932
+ ? { kind: 'static-skill', platform: declaration.platform, skillKey: declaration.skillKey }
2933
+ : { kind: 'artifact', artifactId: declaration.id };
2934
+ const sets = (manifest.managedCommands?.sets ?? []).filter((set) => JSON.stringify(set.producer) === JSON.stringify(producer))
2935
+ .map((set) => setOutputs(set, declaration.platform, scope));
2936
+ const resourceRoot = path.join(tempRoot, `skill-${index}`);
2937
+ for (const [relative, bytes] of tree.files) {
2938
+ const target = path.join(resourceRoot, ...relative.split('/'));
2939
+ fs.mkdirSync(path.dirname(target), { recursive: true });
2940
+ fs.writeFileSync(target, bytes);
2941
+ }
2942
+ await validateCommandEntryFiles(resourceRoot, sets.flatMap((set) => set.entries));
2943
+ candidates.push({ producer: await tools.managedCommandProducerIdentity({ plugin, producer, scope, cwd: pluginDir }), sets });
2944
+ }
2945
+ for (const tree of trees) {
2946
+ if (!tree.declaration.platform)
2947
+ continue;
2948
+ const scope = tree.declaration.delivery?.mode === 'codex-native' ? 'user' : tree.scope;
2949
+ const resolve = await tools.createManagedCommandReferenceResolver({ plugin, platform: tree.declaration.platform, scope, cwd: pluginDir, env, candidates });
2950
+ for (const [relative, bytes] of tree.files) {
2951
+ if (!relative.endsWith('.md'))
2952
+ continue;
2953
+ const text = bytes.toString('utf8');
2954
+ if (parseManagedCommandPlaceholders(text).length > 0 && !(manifest.requires?.aw?.capabilities ?? []).includes('aw.managed-commands.v1'))
2955
+ throw new Error('managed command references require aw.managed-commands.v1');
2956
+ replaceManagedCommandPlaceholders(text, resolve);
2957
+ }
2958
+ }
2959
+ for (const permission of manifest.extensions?.permissions ?? []) {
2960
+ for (const platform of targetedPlatforms(manifest)) {
2961
+ for (const scope of platform === 'codex' ? ['user'] : ['user', 'project']) {
2962
+ const resolve = await tools.createManagedCommandReferenceResolver({ plugin, platform, scope, cwd: pluginDir, env, candidates });
2963
+ const override = permission.agentOverrides?.[platform];
2964
+ if (override === null)
2965
+ continue;
2966
+ for (const decision of ['allow', 'ask', 'deny'])
2967
+ for (const rule of override?.[decision] ?? permission[decision] ?? [])
2968
+ if (typeof rule !== 'string')
2969
+ resolve(rule.command);
2970
+ if (platform === 'claude')
2971
+ for (const rule of override?.sandbox?.excludedCommands ?? [])
2972
+ resolve(rule.command);
2973
+ }
2974
+ }
2975
+ }
2976
+ }
2977
+ catch (cause) {
2978
+ error(`managed command authoring candidate: ${cause.message}`);
2979
+ }
2980
+ finally {
2981
+ for (const cleanup of cleanups)
2982
+ await cleanup();
2983
+ fs.rmSync(tempRoot, { recursive: true, force: true });
2812
2984
  }
2813
- runArtifactRendererFixture(pluginDir, manifest, renderEntry, declarations, runtimeImports, skillValidationTools);
2814
2985
  }
2815
2986
  function validateScriptsLightweight(pluginDir, manifest) {
2816
2987
  validateConfigSchemaLightweight(manifest.config);
@@ -3404,8 +3575,9 @@ async function validatePluginDir(pluginDir, options) {
3404
3575
  }
3405
3576
  }
3406
3577
  const skillValidationTools = await tryLoadCliSkillValidationTools();
3578
+ let normalizedManifest;
3407
3579
  try {
3408
- const normalizedManifest = await cliManifestTools.validateSourcePluginManifest(pluginDir, manifest);
3580
+ normalizedManifest = await cliManifestTools.validateSourcePluginManifest(pluginDir, manifest);
3409
3581
  // Renderer fixtures consume the same compiled config as installed runtime consumers.
3410
3582
  if (normalizedManifest.config)
3411
3583
  manifest.config = normalizedManifest.config;
@@ -3448,7 +3620,12 @@ async function validatePluginDir(pluginDir, options) {
3448
3620
  cliManifestTools,
3449
3621
  });
3450
3622
  validateStaticPortableFinalTrees(pluginDir, manifest, runtimeImports, skillValidationTools);
3451
- validateDynamicArtifactsLightweight(pluginDir, manifest, artifactRenderEntry, runtimeImports, skillValidationTools);
3623
+ const managedContext = normalizedManifest
3624
+ ? { manifest: normalizedManifest, tools: cliManifestTools, trees: [] }
3625
+ : undefined;
3626
+ const rendered = await validateDynamicArtifactsLightweight(pluginDir, manifest, artifactRenderEntry, runtimeImports, skillValidationTools, managedContext, cliManifestTools.requiresNonSensitiveArtifactInput);
3627
+ if (managedContext)
3628
+ await validateAuthorManagedCommands(pluginDir, normalizedManifest, rendered ?? [], managedContext);
3452
3629
  validateMcpContent(pluginDir, manifest);
3453
3630
  validateAppsContent(pluginDir, manifest);
3454
3631
  warnCodexProjectScopeLimitations(manifest);