agentic-workflow-manager 3.0.1 → 3.2.0

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 (103) hide show
  1. package/dist/src/commands/add.js +84 -0
  2. package/dist/src/commands/agent.js +95 -0
  3. package/dist/src/commands/backup.js +46 -0
  4. package/dist/src/commands/doctor.js +80 -4
  5. package/dist/src/commands/export.js +48 -0
  6. package/dist/src/commands/hooks/claude.js +192 -0
  7. package/dist/src/commands/hooks/codex.js +191 -0
  8. package/dist/src/commands/hooks/index.js +23 -8
  9. package/dist/src/commands/hooks/install.js +11 -107
  10. package/dist/src/commands/hooks/resync.js +28 -18
  11. package/dist/src/commands/hooks/shared.js +94 -0
  12. package/dist/src/commands/hooks/status.js +13 -64
  13. package/dist/src/commands/hooks/uninstall.js +11 -47
  14. package/dist/src/commands/init.js +90 -28
  15. package/dist/src/commands/registry/index.js +1 -1
  16. package/dist/src/commands/sync.js +113 -0
  17. package/dist/src/commands/update.js +107 -0
  18. package/dist/src/core/agent-targets.js +50 -0
  19. package/dist/src/core/artifact-state.js +65 -0
  20. package/dist/src/core/atomic-file.js +72 -0
  21. package/dist/src/core/bundle-install.js +60 -38
  22. package/dist/src/core/bundles.js +21 -0
  23. package/dist/src/core/context/managed-block.js +190 -0
  24. package/dist/src/core/context/orchestrator.js +3 -1
  25. package/dist/src/core/context/project-constitution-inject.js +1 -1
  26. package/dist/src/core/context/regenerate.js +3 -3
  27. package/dist/src/core/context/strategies/codex-agents.js +100 -0
  28. package/dist/src/core/diagnostics/checks.js +16 -0
  29. package/dist/src/core/diagnostics/context.js +37 -8
  30. package/dist/src/core/diagnostics/provider-checks.js +219 -0
  31. package/dist/src/core/discovery.js +9 -3
  32. package/dist/src/core/executor.js +30 -9
  33. package/dist/src/core/export/index.js +51 -0
  34. package/dist/src/core/export/pack.js +58 -0
  35. package/dist/src/core/export/resolve.js +77 -0
  36. package/dist/src/core/export/transform.js +57 -0
  37. package/dist/src/core/export/types.js +2 -0
  38. package/dist/src/core/init/mutation-targets.js +139 -0
  39. package/dist/src/core/init/provider-facts.js +164 -0
  40. package/dist/src/core/init/steps.js +65 -9
  41. package/dist/src/core/install-planner.js +206 -0
  42. package/dist/src/core/install-transaction.js +405 -0
  43. package/dist/src/core/profile.js +1 -1
  44. package/dist/src/core/provider-artifacts.js +54 -0
  45. package/dist/src/core/provider-version.js +36 -0
  46. package/dist/src/core/reconciliation.js +61 -0
  47. package/dist/src/core/registries.js +10 -0
  48. package/dist/src/core/renderers/canonical-agent.js +27 -0
  49. package/dist/src/core/renderers/codex-agent.js +60 -0
  50. package/dist/src/core/skill-integrity.js +4 -3
  51. package/dist/src/index.js +99 -289
  52. package/dist/src/providers/index.js +143 -39
  53. package/dist/src/ui/provider-preflight.js +26 -0
  54. package/dist/src/utils/config.js +101 -9
  55. package/dist/tests/commands/agent.test.js +103 -0
  56. package/dist/tests/commands/backup.test.js +109 -0
  57. package/dist/tests/commands/doctor.test.js +65 -4
  58. package/dist/tests/commands/export.test.js +64 -0
  59. package/dist/tests/commands/hooks/codex.test.js +230 -0
  60. package/dist/tests/commands/hooks/install.test.js +20 -1
  61. package/dist/tests/commands/hooks/resync.test.js +53 -6
  62. package/dist/tests/commands/hooks/status.test.js +10 -0
  63. package/dist/tests/commands/hooks/uninstall.test.js +12 -0
  64. package/dist/tests/commands/init.test.js +195 -8
  65. package/dist/tests/commands/multi-agent-targeting.test.js +231 -0
  66. package/dist/tests/core/agent-targets.test.js +45 -0
  67. package/dist/tests/core/artifact-state.test.js +144 -0
  68. package/dist/tests/core/atomic-file.test.js +96 -0
  69. package/dist/tests/core/bundle-install.test.js +208 -17
  70. package/dist/tests/core/bundles.test.js +12 -0
  71. package/dist/tests/core/context/managed-block.test.js +90 -0
  72. package/dist/tests/core/context/orchestrator.test.js +48 -3
  73. package/dist/tests/core/context/regenerate.test.js +1 -1
  74. package/dist/tests/core/context/strategies/codex-agents.test.js +185 -0
  75. package/dist/tests/core/context/strategies/config-instructions.test.js +1 -1
  76. package/dist/tests/core/diagnostics/checks.test.js +19 -0
  77. package/dist/tests/core/diagnostics/context.test.js +74 -0
  78. package/dist/tests/core/diagnostics/provider-checks.test.js +252 -0
  79. package/dist/tests/core/executor.test.js +20 -0
  80. package/dist/tests/core/export/engine.test.js +104 -0
  81. package/dist/tests/core/export/pack.test.js +122 -0
  82. package/dist/tests/core/export/resolve.test.js +78 -0
  83. package/dist/tests/core/export/transform.test.js +74 -0
  84. package/dist/tests/core/init/mutation-targets.test.js +235 -0
  85. package/dist/tests/core/init/orchestrator.test.js +1 -1
  86. package/dist/tests/core/init/provider-facts.test.js +129 -0
  87. package/dist/tests/core/init/steps.test.js +106 -2
  88. package/dist/tests/core/install-planner.test.js +224 -0
  89. package/dist/tests/core/install-transaction.test.js +257 -0
  90. package/dist/tests/core/provider-artifacts.test.js +64 -0
  91. package/dist/tests/core/provider-version.test.js +53 -0
  92. package/dist/tests/core/reconciliation.test.js +165 -0
  93. package/dist/tests/core/registries-sync.test.js +4 -4
  94. package/dist/tests/core/renderers/canonical-agent.test.js +58 -0
  95. package/dist/tests/core/renderers/codex-agent.test.js +128 -0
  96. package/dist/tests/core/versioning.test.js +1 -1
  97. package/dist/tests/integration/codex-provider-isolated.test.js +206 -0
  98. package/dist/tests/providers/hooks-config.test.js +43 -25
  99. package/dist/tests/providers/index.test.js +144 -39
  100. package/dist/tests/structural/codex-agent-escaping-completeness.test.js +77 -0
  101. package/dist/tests/ui/provider-preflight.test.js +25 -0
  102. package/dist/tests/utils/config.test.js +178 -18
  103. package/package.json +1 -1
@@ -88,10 +88,11 @@ function repairGlobalSkills(skillsDir, registryContentDirs) {
88
88
  * único agente target. Cada provider en su propio path; un dir ausente se omite. */
89
89
  function reconcileAllSkillLinks(registryContentDirs) {
90
90
  const out = [];
91
- for (const agent of Object.keys(providers_1.PROVIDERS)) {
92
- if (!fs_1.default.existsSync(providers_1.PROVIDERS[agent].skill.global))
91
+ for (const agent of providers_1.AGENT_TARGETS) {
92
+ const skillsDir = (0, providers_1.providerFor)(agent).skill.global;
93
+ if (!fs_1.default.existsSync(skillsDir))
93
94
  continue;
94
- out.push({ agent, result: repairGlobalSkills(providers_1.PROVIDERS[agent].skill.global, registryContentDirs) });
95
+ out.push({ agent, result: repairGlobalSkills(skillsDir, registryContentDirs) });
95
96
  }
96
97
  return out;
97
98
  }
package/dist/src/index.js CHANGED
@@ -13,30 +13,33 @@ const tty_1 = require("./ui/tty");
13
13
  const picker_1 = require("./ui/picker");
14
14
  const providers_1 = require("./providers");
15
15
  const executor_1 = require("./core/executor");
16
- const regenerate_1 = require("./core/context/regenerate");
16
+ const provider_artifacts_1 = require("./core/provider-artifacts");
17
+ const provider_preflight_1 = require("./ui/provider-preflight");
17
18
  const discovery_1 = require("./core/discovery");
18
19
  const bundles_1 = require("./core/bundles");
19
- const skill_integrity_1 = require("./core/skill-integrity");
20
20
  const registries_1 = require("./core/registries");
21
- const cli_version_1 = require("./core/cli-version");
22
- const bundle_install_1 = require("./core/bundle-install");
23
- const profile_1 = require("./core/profile");
24
21
  const path_1 = __importDefault(require("path"));
25
22
  const picocolors_1 = __importDefault(require("picocolors"));
26
23
  const fs_1 = __importDefault(require("fs"));
27
24
  const story_map_parser_1 = require("./core/story-map-parser");
28
25
  const miro_1 = require("./core/miro");
29
26
  const hooks_1 = require("./commands/hooks");
30
- const resync_1 = require("./commands/hooks/resync");
31
27
  const sensors_1 = require("./commands/sensors");
32
28
  const ledger_1 = require("./commands/ledger");
33
29
  const doctor_1 = require("./commands/doctor");
30
+ const backup_1 = require("./commands/backup");
34
31
  const init_1 = require("./commands/init");
35
32
  const registry_1 = require("./commands/registry");
36
33
  const pin_1 = require("./commands/pin");
37
- const profile_pins_1 = require("./core/profile-pins");
34
+ const export_1 = require("./commands/export");
35
+ const agent_1 = require("./commands/agent");
36
+ const add_1 = require("./commands/add");
37
+ const sync_1 = require("./commands/sync");
38
+ const update_1 = require("./commands/update");
39
+ const agent_targets_1 = require("./core/agent-targets");
38
40
  const update_check_1 = require("./core/update-check");
39
41
  const paths_1 = require("./core/paths");
42
+ const cli_version_1 = require("./core/cli-version");
40
43
  const program = new commander_1.Command();
41
44
  program.name('awm').description('Agentic Workflow Manager').version((0, cli_version_1.cliVersion)());
42
45
  program.hook('postAction', () => {
@@ -45,6 +48,17 @@ program.hook('postAction', () => {
45
48
  }
46
49
  catch { /* el aviso nunca rompe un comando */ }
47
50
  });
51
+ /** Shared resolve-or-exit for the 3 index.ts call sites that need `--agent` targeting
52
+ * outside an already-testable `run*Core` function (which returns `{ code: 1, ... }`
53
+ * instead — see `core/agent-targets.ts`'s `resolveAgentTargetsOrError`). */
54
+ function resolveTargetsOrExit(prefs, explicit) {
55
+ const resolved = (0, agent_targets_1.resolveAgentTargetsOrError)({ prefs, explicit });
56
+ if (!resolved.ok) {
57
+ console.error(picocolors_1.default.red(resolved.error));
58
+ process.exit(1);
59
+ }
60
+ return resolved.targets;
61
+ }
48
62
  function handleCancel(value) {
49
63
  if ((0, prompts_1.isCancel)(value)) {
50
64
  (0, prompts_1.outro)('Operation cancelled.');
@@ -71,7 +85,7 @@ function resolveSelectedArtifacts(selections) {
71
85
  program.command('add [name]')
72
86
  .description('Add a skill, workflow, or process interactively (or non-interactively with flags)')
73
87
  .option('-t, --type <type>', 'Artifact type: skill, workflow, or process')
74
- .option('-a, --agent <agent>', `Target agent: ${Object.keys(providers_1.PROVIDERS).join(', ')}`)
88
+ .option('-a, --agent <agent>', `Target agent: ${providers_1.AGENT_TARGETS.join(', ')}`)
75
89
  .option('-s, --scope <scope>', 'Scope: local or global')
76
90
  .option('-m, --method <method>', 'Install method: symlink or copy')
77
91
  .option('-y, --yes', 'Skip confirmation prompts')
@@ -90,65 +104,12 @@ program.command('add [name]')
90
104
  // 1b. If `name` matches a bundle, run the bundle-activation flow and exit.
91
105
  if (name) {
92
106
  const allBundles = (0, bundles_1.discoverAllBundles)();
93
- const matchedBundle = allBundles.find((b) => b.name === name);
94
- if (matchedBundle) {
95
- const prefs = (0, config_1.getPreferences)();
96
- let bundleAgents;
97
- if (options.agent) {
98
- const valid = Object.keys(providers_1.PROVIDERS);
99
- const parsed = options.agent.split(',').map((a) => a.trim());
100
- for (const a of parsed) {
101
- if (!valid.includes(a)) {
102
- console.error(picocolors_1.default.red(`Invalid agent "${a}". Use: ${valid.join(', ')}.`));
103
- process.exit(1);
104
- }
105
- }
106
- bundleAgents = parsed;
107
- }
108
- else {
109
- bundleAgents = [prefs.defaultAgent];
110
- }
111
- let scopeOverride;
112
- if (options.scope) {
113
- if (!['local', 'global'].includes(options.scope)) {
114
- console.error(picocolors_1.default.red(`Invalid scope "${options.scope}". Use: local or global.`));
115
- process.exit(1);
116
- }
117
- scopeOverride = options.scope;
118
- }
119
- const effective = scopeOverride ?? (0, bundles_1.defaultScopeForBundle)(matchedBundle.scope);
120
- const projectRoot = (0, profile_1.findProjectRoot)(process.cwd());
121
- if (effective === 'local' && !projectRoot) {
122
- console.error(picocolors_1.default.red('No project root found (need a .git/, package.json, or .awm/profile.json here). Run inside a project, or pass --global.'));
123
- process.exit(1);
124
- }
125
- const result = (0, bundle_install_1.addBundle)({
126
- bundleName: matchedBundle.name,
127
- bundles: allBundles,
128
- agents: bundleAgents,
129
- method: 'symlink',
130
- projectRoot: projectRoot ?? process.cwd(),
131
- scopeOverride,
132
- });
133
- if (result.skipped.length > 0) {
134
- for (const s of result.skipped)
135
- console.log(picocolors_1.default.yellow(` ⚠ Skipped: ${s}`));
136
- }
137
- if (result.installed.length === 0) {
138
- (0, prompts_1.outro)(picocolors_1.default.yellow(`Nothing installed for bundle "${matchedBundle.name}".`));
139
- return;
140
- }
141
- const lines = result.installed.map((n) => picocolors_1.default.green(n)).join('\n ');
142
- const recordNote = result.recordedExtension
143
- ? `\n\n${picocolors_1.default.dim('Recorded as a project extension in .awm/profile.json (commit it; symlinks are gitignored).')}`
144
- : '';
145
- (0, prompts_1.outro)(`✅ Installed bundle ${picocolors_1.default.cyan(matchedBundle.name)}:\n ${lines}${recordNote}`);
146
- return;
147
- }
148
- // name given but no matching bundle found — report clearly regardless of TTY
149
- console.error(picocolors_1.default.red(`Bundle "${name}" not found in registry.`));
150
- console.error(picocolors_1.default.dim('Run `awm list` to see available packages.'));
151
- process.exit(1);
107
+ const prefs = (0, config_1.getPreferences)();
108
+ const outcome = (0, add_1.runAddBundleCore)({ name, agent: options.agent, scope: options.scope }, prefs, allBundles);
109
+ if (outcome.code !== 0)
110
+ process.exit(outcome.code);
111
+ (0, prompts_1.outro)('Done.');
112
+ return;
152
113
  }
153
114
  // 2. Discover artifacts
154
115
  const skills = (0, discovery_1.discoverSkills)();
@@ -161,21 +122,7 @@ program.command('add [name]')
161
122
  const prefs = (0, config_1.getPreferences)();
162
123
  // --all: install everything from every package headlessly
163
124
  if (options.all) {
164
- let targetAgents;
165
- if (options.agent) {
166
- const validAgents = Object.keys(providers_1.PROVIDERS);
167
- const parsed = options.agent.split(',').map((a) => a.trim());
168
- for (const a of parsed) {
169
- if (!validAgents.includes(a)) {
170
- console.error(picocolors_1.default.red(`Invalid agent "${a}". Use: ${validAgents.join(', ')}.`));
171
- process.exit(1);
172
- }
173
- }
174
- targetAgents = parsed;
175
- }
176
- else {
177
- targetAgents = [prefs.defaultAgent];
178
- }
125
+ const targetAgents = resolveTargetsOrExit(prefs, options.agent);
179
126
  let scopeVal;
180
127
  if (options.scope) {
181
128
  if (!['local', 'global'].includes(options.scope)) {
@@ -198,8 +145,8 @@ program.command('add [name]')
198
145
  else {
199
146
  methodVal = scopeVal === 'local' ? 'copy' : 'symlink';
200
147
  }
201
- const includeWorkflows = targetAgents.some((a) => providers_1.PROVIDERS[a].workflow !== null);
202
- const includeAgents = targetAgents.some((a) => providers_1.PROVIDERS[a].agent !== null);
148
+ const includeWorkflows = targetAgents.some((a) => (0, providers_1.providerFor)(a).workflow !== null);
149
+ const includeAgents = targetAgents.some((a) => (0, providers_1.providerFor)(a).agent !== null);
203
150
  const allView = (0, registry_view_1.buildPackageView)(skills, includeWorkflows ? workflows : [], includeAgents ? agents : [], (0, bundles_1.discoverAllBundles)());
204
151
  const allDedup = new Map();
205
152
  for (const pkg of allView) {
@@ -216,6 +163,9 @@ program.command('add [name]')
216
163
  (0, prompts_1.outro)(picocolors_1.default.yellow('No artifacts available.'));
217
164
  return;
218
165
  }
166
+ const preflightOk = (0, provider_preflight_1.preflightLinkArtifactsForCli)(targetAgents.flatMap((agent) => artifactsToInstall.map((artifact) => ({ agent, artifact }))));
167
+ if (!preflightOk)
168
+ return;
219
169
  const installSpinner = (0, prompts_1.spinner)();
220
170
  installSpinner.start('Installing artifacts...');
221
171
  try {
@@ -223,17 +173,24 @@ program.command('add [name]')
223
173
  const skipped = [];
224
174
  for (const currentAgent of targetAgents) {
225
175
  for (const artifact of artifactsToInstall) {
226
- if (providers_1.PROVIDERS[currentAgent][artifact.type] === null) {
176
+ const config = (0, providers_1.assertLinkRenderer)(artifact.type, currentAgent);
177
+ if (config === null) {
227
178
  skipped.push(`${artifact.name} (${currentAgent})`);
228
179
  continue;
229
180
  }
230
- const targetDir = (0, providers_1.getTargetPath)(artifact.type, currentAgent, scopeVal);
181
+ const targetDir = config[scopeVal];
231
182
  const finalDest = path_1.default.join(targetDir, artifact.name);
232
183
  (0, executor_1.installArtifact)(artifact.sourcePath, finalDest, methodVal);
233
184
  installed.push(`${artifact.name} → ${currentAgent} (${scopeVal})`);
234
185
  }
235
186
  }
236
- (0, config_1.savePreferences)({ defaultAgent: targetAgents[0], defaultScope: scopeVal, installMethod: methodVal });
187
+ const updatedPrefs = targetAgents.reduce((current, agent) => (0, config_1.enableAgent)(current, agent), prefs);
188
+ (0, config_1.savePreferences)({
189
+ ...updatedPrefs,
190
+ defaultAgent: targetAgents[0],
191
+ defaultScope: scopeVal,
192
+ installMethod: methodVal,
193
+ });
237
194
  installSpinner.stop('Installation complete!');
238
195
  if (skipped.length > 0) {
239
196
  for (const sk of skipped) {
@@ -259,24 +216,16 @@ program.command('add [name]')
259
216
  // 3. Agent & Scope Prompts (Moved up)
260
217
  let targetAgents;
261
218
  if (options.agent) {
262
- const validAgents = Object.keys(providers_1.PROVIDERS);
263
- const parsed = options.agent.split(',').map(a => a.trim());
264
- for (const a of parsed) {
265
- if (!validAgents.includes(a)) {
266
- console.error(picocolors_1.default.red(`Invalid agent "${a}". Use: ${validAgents.join(', ')}.`));
267
- process.exit(1);
268
- }
269
- }
270
- targetAgents = parsed;
219
+ targetAgents = resolveTargetsOrExit(prefs, options.agent);
271
220
  }
272
221
  else {
273
222
  const agentChoice = await (0, prompts_1.multiselect)({
274
223
  message: 'Which agent(s) do you want to install to?',
275
- options: Object.entries(providers_1.PROVIDERS).map(([key, config]) => ({
224
+ options: providers_1.AGENT_TARGETS.map((key) => ({
276
225
  value: key,
277
- label: config.label
226
+ label: (0, providers_1.providerFor)(key).label
278
227
  })),
279
- initialValues: [prefs.defaultAgent],
228
+ initialValues: [...prefs.enabledAgents],
280
229
  required: true
281
230
  });
282
231
  handleCancel(agentChoice);
@@ -303,8 +252,8 @@ program.command('add [name]')
303
252
  scopeVal = scopeChoice;
304
253
  }
305
254
  // 4. Build the package view, filtered to artifact types the target agent(s) support
306
- const includeWorkflows = targetAgents.some(a => providers_1.PROVIDERS[a].workflow !== null);
307
- const includeAgents = targetAgents.some(a => providers_1.PROVIDERS[a].agent !== null);
255
+ const includeWorkflows = targetAgents.some(a => (0, providers_1.providerFor)(a).workflow !== null);
256
+ const includeAgents = targetAgents.some(a => (0, providers_1.providerFor)(a).agent !== null);
308
257
  const view = (0, registry_view_1.buildPackageView)(skills, includeWorkflows ? workflows : [], includeAgents ? agents : [], (0, bundles_1.discoverAllBundles)());
309
258
  if (view.length === 0) {
310
259
  (0, prompts_1.outro)(picocolors_1.default.yellow('No artifacts available for the selected agent(s).'));
@@ -348,6 +297,9 @@ program.command('add [name]')
348
297
  (0, prompts_1.outro)(picocolors_1.default.yellow('No artifacts selected.'));
349
298
  return;
350
299
  }
300
+ const preflightOk = (0, provider_preflight_1.preflightLinkArtifactsForCli)(targetAgents.flatMap((agent) => artifactsToInstall.map((artifact) => ({ agent, artifact }))));
301
+ if (!preflightOk)
302
+ return;
351
303
  // 6. Installation Method
352
304
  let methodVal;
353
305
  if (options.method) {
@@ -388,17 +340,24 @@ program.command('add [name]')
388
340
  for (const currentAgent of targetAgents) {
389
341
  for (const artifact of artifactsToInstall) {
390
342
  // Skip artifacts not supported by this agent
391
- if (providers_1.PROVIDERS[currentAgent][artifact.type] === null) {
343
+ const config = (0, providers_1.assertLinkRenderer)(artifact.type, currentAgent);
344
+ if (config === null) {
392
345
  skipped.push(`${artifact.name} (${currentAgent})`);
393
346
  continue;
394
347
  }
395
- const targetDir = (0, providers_1.getTargetPath)(artifact.type, currentAgent, scopeVal);
348
+ const targetDir = config[scopeVal];
396
349
  const finalDest = path_1.default.join(targetDir, artifact.name);
397
350
  (0, executor_1.installArtifact)(artifact.sourcePath, finalDest, methodVal);
398
351
  installed.push(`${artifact.name} → ${currentAgent} (${scopeVal})`);
399
352
  }
400
353
  }
401
- (0, config_1.savePreferences)({ defaultAgent: targetAgents[0], defaultScope: scopeVal, installMethod: methodVal });
354
+ const updatedPrefs = targetAgents.reduce((current, agent) => (0, config_1.enableAgent)(current, agent), prefs);
355
+ (0, config_1.savePreferences)({
356
+ ...updatedPrefs,
357
+ defaultAgent: targetAgents[0],
358
+ defaultScope: scopeVal,
359
+ installMethod: methodVal,
360
+ });
402
361
  installSpinner.stop('Installation complete!');
403
362
  if (skipped.length > 0) {
404
363
  for (const s of skipped) {
@@ -415,149 +374,25 @@ program.command('add [name]')
415
374
  }
416
375
  });
417
376
  program.command('update')
418
- .description('Sync all configured registries with their remotes')
419
- .action(async () => {
377
+ .description('Sync all configured registries, reconcile artifacts and re-sync hooks')
378
+ .option('-a, --agent <agent>', `Target agent(s), comma-separated: ${providers_1.AGENT_TARGETS.join(', ')} (defaults to every enabled agent)`)
379
+ .action(async (options) => {
420
380
  (0, prompts_1.intro)(picocolors_1.default.bgCyan(picocolors_1.default.black(' AWM - Update Registries ')));
421
- const s = (0, prompts_1.spinner)();
422
- s.start('Syncing registries...');
423
- const results = await (0, registries_1.syncRegistries)();
424
- s.stop('Registries synced.');
425
- if (results.length === 0) {
426
- console.log(picocolors_1.default.yellow(' No registries configured — run `awm init` (seeds baseline) or `awm registry add <remote>`.'));
427
- }
428
- for (const r of results) {
429
- if (r.action === 'error') {
430
- console.warn(picocolors_1.default.yellow(` ⚠ registry ${r.name}: ${r.error}`));
431
- }
432
- else {
433
- console.log(picocolors_1.default.green(` ✓ Registry ${r.name} ${r.action === 'pulled' ? 'updated' : 're-cloned'} @ ${r.version}`));
434
- }
435
- }
436
- for (const f of (0, registries_1.verifyMinCliVersions)()) {
437
- console.warn(picocolors_1.default.yellow(` ⚠ Registry ${f.name} requires CLI ≥ ${f.min} (you have ${(0, cli_version_1.cliVersion)()}) — run: npm i -g agentic-workflow-manager`));
438
- }
439
- try {
440
- const regen = (0, regenerate_1.regenerateGlobalContext)();
441
- const refreshed = regen.filter((r) => r.action === 'refreshed').map((r) => r.agent);
442
- if (refreshed.length > 0)
443
- console.log(picocolors_1.default.green(` ✓ Regenerated AWM context for: ${refreshed.join(', ')}`));
444
- }
445
- catch { /* no aborta */ }
446
- try {
447
- for (const { agent, result } of (0, skill_integrity_1.reconcileAllSkillLinks)((0, registries_1.contentRoots)())) {
448
- const touched = result.relinked.length + result.pruned.length;
449
- if (touched > 0)
450
- console.log(picocolors_1.default.green(` ✓ Reconciled ${agent} skill links: re-linked ${result.relinked.length}, pruned ${result.pruned.length}`));
451
- }
452
- }
453
- catch { /* no aborta */ }
454
- try {
455
- const hooksRoot = (0, registries_1.capabilityRoot)('hooks');
456
- if (hooksRoot) {
457
- for (const r of (0, resync_1.resyncInstalledHooks)(hooksRoot)) {
458
- if (r.action === 'resynced')
459
- console.log(picocolors_1.default.green(` ✓ Re-synced ${r.agent} hook scripts`));
460
- else if (r.action === 'registry-missing')
461
- console.warn(picocolors_1.default.yellow(` ⚠ ${r.agent} hook installed but registry hooks missing — run 'awm hooks install'`));
462
- }
463
- }
464
- }
465
- catch { /* no aborta */ }
466
- await (0, update_check_1.offerSelfUpdate)(); // capa 2 — Task 13
467
- (0, prompts_1.outro)('✅ Registries, skills and hooks updated.');
381
+ (0, paths_1.warnIfUnsupportedPlatform)((m) => console.warn(picocolors_1.default.yellow(`⚠ ${m}`)));
382
+ const result = await (0, update_1.runUpdateCore)(options);
383
+ (0, prompts_1.outro)(result.code === 0 ? '✅ Registries, skills and hooks updated.' : picocolors_1.default.red('Update failed — see errors above.'));
384
+ process.exitCode = result.code;
468
385
  });
469
386
  program.command('sync')
470
387
  .description('Rebuild local skill symlinks from .awm/profile.json (e.g. after cloning on a new machine)')
471
- .option('-a, --agent <agent>', `Target agent: ${Object.keys(providers_1.PROVIDERS).join(', ')}`)
388
+ .option('-a, --agent <agent>', `Target agent(s), comma-separated: ${providers_1.AGENT_TARGETS.join(', ')} (defaults to every enabled agent)`)
472
389
  .option('-m, --method <method>', 'Install method: symlink or copy', 'symlink')
473
390
  .action(async (options) => {
474
391
  (0, prompts_1.intro)(picocolors_1.default.bgCyan(picocolors_1.default.black(' AWM - Sync Project Profile ')));
475
392
  (0, paths_1.warnIfUnsupportedPlatform)((m) => console.warn(picocolors_1.default.yellow(`⚠ ${m}`)));
476
- const projectRoot = (0, profile_1.findProjectRoot)(process.cwd());
477
- if (!projectRoot) {
478
- console.error(picocolors_1.default.red('No project root found (need a .git/, package.json, or .awm/profile.json here).'));
479
- process.exit(1);
480
- }
481
- let profile;
482
- try {
483
- profile = (0, profile_1.readProfile)(projectRoot);
484
- }
485
- catch (e) {
486
- console.error(picocolors_1.default.red(e.message));
487
- process.exit(1);
488
- }
489
- const s = (0, prompts_1.spinner)();
490
- s.start('Syncing registries...');
491
- const syncResults = await (0, registries_1.syncRegistries)();
492
- s.stop('Registries synced.');
493
- for (const r of syncResults) {
494
- if (r.action === 'error')
495
- console.warn(picocolors_1.default.yellow(` ⚠ registry ${r.name}: ${r.error}`));
496
- }
497
- // Gate minCliVersion (WS-4): un registry puede exigir una versión mínima del CLI.
498
- // Corre ANTES del gate de pins — gates de contrato primero (CONSTITUTION).
499
- const cliFailures = (0, registries_1.verifyMinCliVersions)();
500
- if (cliFailures.length > 0) {
501
- for (const f of cliFailures) {
502
- console.error(picocolors_1.default.red(`Registry ${f.name} requires CLI ≥ ${f.min} (you have ${(0, cli_version_1.cliVersion)()}).`));
503
- console.error(picocolors_1.default.red(' Run: npm i -g agentic-workflow-manager'));
504
- }
505
- process.exit(1);
506
- }
507
- // Gate de versión (WS-3): el pin del profile es el lock del proyecto.
508
- // Runs before the empty-extensions early-exit so pinned projects always fail fast.
509
- const pins = profile.registries ?? {};
510
- if (Object.keys(pins).length > 0) {
511
- const failures = await (0, profile_pins_1.verifyProjectPins)(pins);
512
- if (failures.length > 0) {
513
- for (const f of failures) {
514
- if (f.reason === 'missing-registry') {
515
- const registriesConfig = (0, registries_1.readRegistriesConfig)();
516
- const isConfigured = registriesConfig.some((r) => r.name === f.name);
517
- if (isConfigured) {
518
- console.error(picocolors_1.default.red(`The registry "${f.name}" is configured but not yet synced on this machine. Run: awm update`));
519
- }
520
- else {
521
- console.error(picocolors_1.default.red(`The registry "${f.name}" is not configured on this machine. Run: awm registry add <remote>`));
522
- }
523
- }
524
- else {
525
- console.error(picocolors_1.default.red(`This machine has ${f.name} @ ${f.actual ? `v${f.actual}` : 'HEAD (no tag)'} but the project requires v${f.required}.`));
526
- console.error(picocolors_1.default.red(` Run: awm pin ${f.name} ${f.required} && awm update`));
527
- }
528
- }
529
- process.exit(1);
530
- }
531
- }
532
- if (profile.extensions.length === 0) {
533
- (0, prompts_1.outro)(picocolors_1.default.yellow('No extensions in .awm/profile.json — nothing to sync. Use `awm add <bundle>` first.'));
534
- return;
535
- }
536
- const prefs = (0, config_1.getPreferences)();
537
- let agents;
538
- if (options.agent) {
539
- const valid = Object.keys(providers_1.PROVIDERS);
540
- const parsed = options.agent.split(',').map((a) => a.trim());
541
- for (const a of parsed) {
542
- if (!valid.includes(a)) {
543
- console.error(picocolors_1.default.red(`Invalid agent "${a}". Use: ${valid.join(', ')}.`));
544
- process.exit(1);
545
- }
546
- }
547
- agents = parsed;
548
- }
549
- else {
550
- agents = [prefs.defaultAgent];
551
- }
552
- const method = options.method === 'copy' ? 'copy' : 'symlink';
553
- const result = (0, bundle_install_1.syncProfile)({ projectRoot, bundles: (0, bundles_1.discoverAllBundles)(), agents, method });
554
- if (result.skipped.length > 0) {
555
- for (const sk of result.skipped)
556
- console.log(picocolors_1.default.yellow(` ⚠ Skipped: ${sk}`));
557
- }
558
- const lines = result.installed.map((n) => picocolors_1.default.green(n)).join('\n ');
559
- const installedNote = lines ? `\n ${lines}` : picocolors_1.default.dim(' (all up to date)');
560
- (0, prompts_1.outro)(`✅ Synced extensions [${result.extensions.join(', ')}]:${installedNote}`);
393
+ const { code } = await (0, sync_1.runSyncCore)(options);
394
+ (0, prompts_1.outro)(code === 0 ? 'Done.' : picocolors_1.default.red('Sync failed — see errors above.'));
395
+ process.exitCode = code;
561
396
  });
562
397
  program.command('list [package]')
563
398
  .description('List available artifacts. With no argument shows a package summary; pass a package name or --all for detail.')
@@ -620,21 +455,29 @@ program.command('list [package]')
620
455
  });
621
456
  program.command('remove')
622
457
  .description('Remove an installed skill or workflow')
623
- .action(async () => {
458
+ .option('-a, --agent <agent>', `Target agent(s), comma-separated: ${providers_1.AGENT_TARGETS.join(', ')} (defaults to every enabled agent)`)
459
+ .action(async (options) => {
624
460
  (0, prompts_1.intro)(picocolors_1.default.bgCyan(picocolors_1.default.black(' AWM - Remove Artifact ')));
625
461
  const prefs = (0, config_1.getPreferences)();
626
- // Multi-agent selection (matching the add command flow)
627
- const agentChoice = await (0, prompts_1.multiselect)({
628
- message: 'From which agent(s)?',
629
- options: Object.entries(providers_1.PROVIDERS).map(([key, config]) => ({
630
- value: key,
631
- label: config.label
632
- })),
633
- initialValues: [prefs.defaultAgent],
634
- required: true
635
- });
636
- handleCancel(agentChoice);
637
- const targetAgents = agentChoice;
462
+ // Multi-agent selection (matching the add command flow). --agent skips
463
+ // the interactive prompt and resolves the same way as add/sync/update/doctor (R12/R13).
464
+ let targetAgents;
465
+ if (options.agent) {
466
+ targetAgents = resolveTargetsOrExit(prefs, options.agent);
467
+ }
468
+ else {
469
+ const agentChoice = await (0, prompts_1.multiselect)({
470
+ message: 'From which agent(s)?',
471
+ options: providers_1.AGENT_TARGETS.map((key) => ({
472
+ value: key,
473
+ label: (0, providers_1.providerFor)(key).label
474
+ })),
475
+ initialValues: [...prefs.enabledAgents],
476
+ required: true
477
+ });
478
+ handleCancel(agentChoice);
479
+ targetAgents = agentChoice;
480
+ }
638
481
  const scopeChoice = await (0, prompts_1.select)({
639
482
  message: 'Scope?',
640
483
  options: [
@@ -645,43 +488,7 @@ program.command('remove')
645
488
  });
646
489
  handleCancel(scopeChoice);
647
490
  const scopeVal = scopeChoice;
648
- // Scan installed artifacts across all selected agents, aggregating by name
649
- const artifactMap = new Map();
650
- const scanDir = (dir, type, agent) => {
651
- if (!fs_1.default.existsSync(dir))
652
- return;
653
- const entries = fs_1.default.readdirSync(dir, { withFileTypes: true });
654
- for (const entry of entries) {
655
- const existing = artifactMap.get(entry.name);
656
- if (existing) {
657
- existing.installedIn.push(agent);
658
- existing.fullPaths.push(path_1.default.join(dir, entry.name));
659
- }
660
- else {
661
- artifactMap.set(entry.name, {
662
- name: entry.name,
663
- type,
664
- installedIn: [agent],
665
- fullPaths: [path_1.default.join(dir, entry.name)]
666
- });
667
- }
668
- }
669
- };
670
- for (const targetAgent of targetAgents) {
671
- try {
672
- scanDir((0, providers_1.getTargetPath)('skill', targetAgent, scopeVal), 'skill', targetAgent);
673
- }
674
- catch { /* ok */ }
675
- try {
676
- scanDir((0, providers_1.getTargetPath)('workflow', targetAgent, scopeVal), 'workflow', targetAgent);
677
- }
678
- catch { /* ok */ }
679
- try {
680
- scanDir((0, providers_1.getTargetPath)('agent', targetAgent, scopeVal), 'agent', targetAgent);
681
- }
682
- catch { /* ok */ }
683
- }
684
- const installed = Array.from(artifactMap.values());
491
+ const installed = (0, provider_artifacts_1.scanLegacyArtifacts)(targetAgents, scopeVal);
685
492
  if (installed.length === 0) {
686
493
  (0, prompts_1.outro)(picocolors_1.default.yellow('No installed artifacts found for the selected agents/scope.'));
687
494
  process.exit(0);
@@ -798,7 +605,10 @@ miroCmd.command('sync <storyMapPath>')
798
605
  (0, sensors_1.registerSensorsCommand)(program);
799
606
  (0, ledger_1.registerLedgerCommand)(program);
800
607
  (0, doctor_1.registerDoctorCommand)(program);
608
+ (0, backup_1.registerBackupCommand)(program);
801
609
  (0, init_1.registerInitCommand)(program);
802
610
  (0, registry_1.registerRegistryCommand)(program);
803
611
  (0, pin_1.registerPinCommands)(program);
612
+ (0, export_1.registerExportCommand)(program);
613
+ (0, agent_1.registerAgentCommand)(program);
804
614
  program.parse();