agentic-workflow-manager 2.0.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 (145) hide show
  1. package/README.md +62 -0
  2. package/dist/src/commands/doctor.js +77 -0
  3. package/dist/src/commands/hooks/index.js +118 -0
  4. package/dist/src/commands/hooks/install.js +113 -0
  5. package/dist/src/commands/hooks/resync.js +50 -0
  6. package/dist/src/commands/hooks/status.js +74 -0
  7. package/dist/src/commands/hooks/uninstall.js +59 -0
  8. package/dist/src/commands/init.js +181 -0
  9. package/dist/src/commands/ledger/index.js +73 -0
  10. package/dist/src/commands/pin.js +75 -0
  11. package/dist/src/commands/registry/add.js +62 -0
  12. package/dist/src/commands/registry/index.js +166 -0
  13. package/dist/src/commands/registry/install-bundles.js +36 -0
  14. package/dist/src/commands/registry/remove.js +18 -0
  15. package/dist/src/commands/registry/status.js +31 -0
  16. package/dist/src/commands/sensors/baseline.js +93 -0
  17. package/dist/src/commands/sensors/formatters/eslint.js +29 -0
  18. package/dist/src/commands/sensors/formatters/generic.js +8 -0
  19. package/dist/src/commands/sensors/formatters/semgrep.js +18 -0
  20. package/dist/src/commands/sensors/formatters/test.js +12 -0
  21. package/dist/src/commands/sensors/formatters/tsc.js +23 -0
  22. package/dist/src/commands/sensors/index.js +94 -0
  23. package/dist/src/commands/sensors/init.js +112 -0
  24. package/dist/src/commands/sensors/install.js +78 -0
  25. package/dist/src/commands/sensors/run.js +217 -0
  26. package/dist/src/commands/sensors/status.js +85 -0
  27. package/dist/src/commands/sensors/types.js +2 -0
  28. package/dist/src/core/bundle-install.js +116 -0
  29. package/dist/src/core/bundles.js +122 -0
  30. package/dist/src/core/cli-version.js +30 -0
  31. package/dist/src/core/context/materializer.js +30 -0
  32. package/dist/src/core/context/orchestrator.js +75 -0
  33. package/dist/src/core/context/project-constitution-inject.js +47 -0
  34. package/dist/src/core/context/provider.js +29 -0
  35. package/dist/src/core/context/regenerate.js +61 -0
  36. package/dist/src/core/context/strategies/config-instructions.js +73 -0
  37. package/dist/src/core/context/strategies/hook-merge.js +23 -0
  38. package/dist/src/core/context/strategies/strategy.js +2 -0
  39. package/dist/src/core/context/types.js +2 -0
  40. package/dist/src/core/diagnostics/checks.js +141 -0
  41. package/dist/src/core/diagnostics/context.js +181 -0
  42. package/dist/src/core/diagnostics/types.js +2 -0
  43. package/dist/src/core/discovery.js +135 -0
  44. package/dist/src/core/executor.js +41 -0
  45. package/dist/src/core/init/detector.js +67 -0
  46. package/dist/src/core/init/orchestrator.js +54 -0
  47. package/dist/src/core/init/steps.js +279 -0
  48. package/dist/src/core/init/types.js +2 -0
  49. package/dist/src/core/ledger/store.js +73 -0
  50. package/dist/src/core/ledger/types.js +2 -0
  51. package/dist/src/core/miro.js +314 -0
  52. package/dist/src/core/profile-pins.js +36 -0
  53. package/dist/src/core/profile.js +146 -0
  54. package/dist/src/core/registries.js +205 -0
  55. package/dist/src/core/registry.js +28 -0
  56. package/dist/src/core/skill-integrity.js +97 -0
  57. package/dist/src/core/story-map-parser.js +83 -0
  58. package/dist/src/core/update-check-worker.js +10 -0
  59. package/dist/src/core/update-check.js +106 -0
  60. package/dist/src/core/versioning.js +112 -0
  61. package/dist/src/index.js +689 -0
  62. package/dist/src/providers/index.js +63 -0
  63. package/dist/src/utils/config.js +35 -0
  64. package/dist/src/utils/grouping.js +51 -0
  65. package/dist/src/utils/registry-view.js +154 -0
  66. package/dist/tests/commands/doctor.test.js +98 -0
  67. package/dist/tests/commands/hooks/install.test.js +149 -0
  68. package/dist/tests/commands/hooks/resync.test.js +135 -0
  69. package/dist/tests/commands/hooks/router.test.js +26 -0
  70. package/dist/tests/commands/hooks/status.test.js +88 -0
  71. package/dist/tests/commands/hooks/uninstall.test.js +104 -0
  72. package/dist/tests/commands/init.test.js +87 -0
  73. package/dist/tests/commands/ledger/index.test.js +64 -0
  74. package/dist/tests/commands/pin.test.js +72 -0
  75. package/dist/tests/commands/registry/add.test.js +223 -0
  76. package/dist/tests/commands/registry/install-bundles.test.js +87 -0
  77. package/dist/tests/commands/registry/remove.test.js +49 -0
  78. package/dist/tests/commands/registry/status.test.js +43 -0
  79. package/dist/tests/commands/sensors/baseline.test.js +106 -0
  80. package/dist/tests/commands/sensors/formatters/eslint.test.js +32 -0
  81. package/dist/tests/commands/sensors/formatters/semgrep.test.js +38 -0
  82. package/dist/tests/commands/sensors/formatters/tsc.test.js +25 -0
  83. package/dist/tests/commands/sensors/index.test.js +18 -0
  84. package/dist/tests/commands/sensors/init.test.js +137 -0
  85. package/dist/tests/commands/sensors/install.test.js +60 -0
  86. package/dist/tests/commands/sensors/router.test.js +23 -0
  87. package/dist/tests/commands/sensors/run.test.js +353 -0
  88. package/dist/tests/commands/sensors/status.test.js +98 -0
  89. package/dist/tests/core/base-remote.test.js +70 -0
  90. package/dist/tests/core/bundle-install.test.js +198 -0
  91. package/dist/tests/core/bundles-multiroot.test.js +68 -0
  92. package/dist/tests/core/bundles-overrides.test.js +49 -0
  93. package/dist/tests/core/bundles.test.js +96 -0
  94. package/dist/tests/core/cli-version.test.js +17 -0
  95. package/dist/tests/core/context/materializer.test.js +46 -0
  96. package/dist/tests/core/context/orchestrator.test.js +127 -0
  97. package/dist/tests/core/context/project-constitution-inject.test.js +82 -0
  98. package/dist/tests/core/context/provider.test.js +45 -0
  99. package/dist/tests/core/context/regenerate.test.js +106 -0
  100. package/dist/tests/core/context/strategies/config-instructions.test.js +88 -0
  101. package/dist/tests/core/context/strategies/hook-merge.test.js +71 -0
  102. package/dist/tests/core/context/types.test.js +15 -0
  103. package/dist/tests/core/diagnostics/checks.test.js +208 -0
  104. package/dist/tests/core/diagnostics/context.test.js +170 -0
  105. package/dist/tests/core/discovery-multiroot.test.js +63 -0
  106. package/dist/tests/core/discovery-overrides.test.js +105 -0
  107. package/dist/tests/core/discovery.test.js +113 -0
  108. package/dist/tests/core/executor.test.js +44 -0
  109. package/dist/tests/core/init/detector.test.js +56 -0
  110. package/dist/tests/core/init/orchestrator.test.js +122 -0
  111. package/dist/tests/core/init/steps.test.js +363 -0
  112. package/dist/tests/core/ledger/gitignore.test.js +13 -0
  113. package/dist/tests/core/ledger/store.test.js +122 -0
  114. package/dist/tests/core/miro-layout.test.js +150 -0
  115. package/dist/tests/core/profile-pins.test.js +131 -0
  116. package/dist/tests/core/profile-registries.test.js +59 -0
  117. package/dist/tests/core/profile.test.js +110 -0
  118. package/dist/tests/core/registries-capability.test.js +52 -0
  119. package/dist/tests/core/registries-seed.test.js +66 -0
  120. package/dist/tests/core/registries-sync.test.js +205 -0
  121. package/dist/tests/core/registries.test.js +91 -0
  122. package/dist/tests/core/registry-manifest.test.js +95 -0
  123. package/dist/tests/core/registry-versioned-sync.test.js +113 -0
  124. package/dist/tests/core/registry.test.js +51 -0
  125. package/dist/tests/core/skill-integrity.test.js +126 -0
  126. package/dist/tests/core/story-map-parser.test.js +136 -0
  127. package/dist/tests/core/sync-gates.test.js +97 -0
  128. package/dist/tests/core/update-check.test.js +106 -0
  129. package/dist/tests/core/versioning.test.js +169 -0
  130. package/dist/tests/integration/pack-e2e.test.js +50 -0
  131. package/dist/tests/providers/hooks-config.test.js +45 -0
  132. package/dist/tests/providers/index.test.js +58 -0
  133. package/dist/tests/providers/injection-config.test.js +25 -0
  134. package/dist/tests/registry/b3-ledger-wiring.test.js +74 -0
  135. package/dist/tests/registry/catalog-consistency.test.js +47 -0
  136. package/dist/tests/registry/design-skills.test.js +146 -0
  137. package/dist/tests/registry/prose-agnostic.test.js +18 -0
  138. package/dist/tests/registry/sensor-packs.test.js +45 -0
  139. package/dist/tests/registry/skill-versions.test.js +26 -0
  140. package/dist/tests/registry/using-awm.test.js +39 -0
  141. package/dist/tests/utils/config.test.js +31 -0
  142. package/dist/tests/utils/grouping.test.js +43 -0
  143. package/dist/tests/utils/registry-view-overrides.test.js +41 -0
  144. package/dist/tests/utils/registry-view.test.js +156 -0
  145. package/package.json +49 -0
@@ -0,0 +1,689 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __importDefault = (this && this.__importDefault) || function (mod) {
4
+ return (mod && mod.__esModule) ? mod : { "default": mod };
5
+ };
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ const prompts_1 = require("@clack/prompts");
8
+ const commander_1 = require("commander");
9
+ const config_1 = require("./utils/config");
10
+ const grouping_1 = require("./utils/grouping");
11
+ const registry_view_1 = require("./utils/registry-view");
12
+ const providers_1 = require("./providers");
13
+ const executor_1 = require("./core/executor");
14
+ const regenerate_1 = require("./core/context/regenerate");
15
+ const discovery_1 = require("./core/discovery");
16
+ const bundles_1 = require("./core/bundles");
17
+ const skill_integrity_1 = require("./core/skill-integrity");
18
+ const registries_1 = require("./core/registries");
19
+ const cli_version_1 = require("./core/cli-version");
20
+ const bundle_install_1 = require("./core/bundle-install");
21
+ const profile_1 = require("./core/profile");
22
+ const path_1 = __importDefault(require("path"));
23
+ const picocolors_1 = __importDefault(require("picocolors"));
24
+ const fs_1 = __importDefault(require("fs"));
25
+ const story_map_parser_1 = require("./core/story-map-parser");
26
+ const miro_1 = require("./core/miro");
27
+ const hooks_1 = require("./commands/hooks");
28
+ const resync_1 = require("./commands/hooks/resync");
29
+ const sensors_1 = require("./commands/sensors");
30
+ const ledger_1 = require("./commands/ledger");
31
+ const doctor_1 = require("./commands/doctor");
32
+ const init_1 = require("./commands/init");
33
+ const registry_1 = require("./commands/registry");
34
+ const pin_1 = require("./commands/pin");
35
+ const profile_pins_1 = require("./core/profile-pins");
36
+ const update_check_1 = require("./core/update-check");
37
+ const program = new commander_1.Command();
38
+ program.name('awm').description('Agentic Workflow Manager').version((0, cli_version_1.cliVersion)());
39
+ program.hook('postAction', () => {
40
+ try {
41
+ (0, update_check_1.maybeNotifyUpdate)();
42
+ }
43
+ catch { /* el aviso nunca rompe un comando */ }
44
+ });
45
+ function handleCancel(value) {
46
+ if ((0, prompts_1.isCancel)(value)) {
47
+ (0, prompts_1.outro)('Operation cancelled.');
48
+ process.exit(0);
49
+ }
50
+ }
51
+ function resolveSelectedArtifacts(selections) {
52
+ const result = new Map();
53
+ for (const sel of selections) {
54
+ if (sel._group) {
55
+ for (const c of sel.children) {
56
+ for (const a of c.artifacts)
57
+ result.set(a.name, a);
58
+ }
59
+ }
60
+ else if (sel._child) {
61
+ for (const a of sel.combined.artifacts) {
62
+ result.set(a.name, a);
63
+ }
64
+ }
65
+ }
66
+ return Array.from(result.values());
67
+ }
68
+ program.command('add [name]')
69
+ .description('Add a skill, workflow, or process interactively (or non-interactively with flags)')
70
+ .option('-t, --type <type>', 'Artifact type: skill, workflow, or process')
71
+ .option('-a, --agent <agent>', `Target agent: ${Object.keys(providers_1.PROVIDERS).join(', ')}`)
72
+ .option('-s, --scope <scope>', 'Scope: local or global')
73
+ .option('-m, --method <method>', 'Install method: symlink or copy')
74
+ .option('-y, --yes', 'Skip confirmation prompts')
75
+ .action(async (name, options) => {
76
+ (0, prompts_1.intro)(picocolors_1.default.bgCyan(picocolors_1.default.black(' AWM - Agentic Workflow Manager ')));
77
+ // 1. Sync the registry
78
+ const s = (0, prompts_1.spinner)();
79
+ s.start('Syncing registries...');
80
+ const results = await (0, registries_1.syncRegistries)();
81
+ s.stop('Registries synced.');
82
+ for (const r of results) {
83
+ if (r.action === 'error')
84
+ console.warn(picocolors_1.default.yellow(` ⚠ registry ${r.name}: ${r.error}`));
85
+ }
86
+ // 1b. If `name` matches a bundle, run the bundle-activation flow and exit.
87
+ if (name) {
88
+ const allBundles = (0, bundles_1.discoverAllBundles)();
89
+ const matchedBundle = allBundles.find((b) => b.name === name);
90
+ if (matchedBundle) {
91
+ const prefs = (0, config_1.getPreferences)();
92
+ let bundleAgents;
93
+ if (options.agent) {
94
+ const valid = Object.keys(providers_1.PROVIDERS);
95
+ const parsed = options.agent.split(',').map((a) => a.trim());
96
+ for (const a of parsed) {
97
+ if (!valid.includes(a)) {
98
+ console.error(picocolors_1.default.red(`Invalid agent "${a}". Use: ${valid.join(', ')}.`));
99
+ process.exit(1);
100
+ }
101
+ }
102
+ bundleAgents = parsed;
103
+ }
104
+ else {
105
+ bundleAgents = [prefs.defaultAgent];
106
+ }
107
+ let scopeOverride;
108
+ if (options.scope) {
109
+ if (!['local', 'global'].includes(options.scope)) {
110
+ console.error(picocolors_1.default.red(`Invalid scope "${options.scope}". Use: local or global.`));
111
+ process.exit(1);
112
+ }
113
+ scopeOverride = options.scope;
114
+ }
115
+ const effective = scopeOverride ?? (0, bundles_1.defaultScopeForBundle)(matchedBundle.scope);
116
+ const projectRoot = (0, profile_1.findProjectRoot)(process.cwd());
117
+ if (effective === 'local' && !projectRoot) {
118
+ 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.'));
119
+ process.exit(1);
120
+ }
121
+ const result = (0, bundle_install_1.addBundle)({
122
+ bundleName: matchedBundle.name,
123
+ bundles: allBundles,
124
+ agents: bundleAgents,
125
+ method: 'symlink',
126
+ projectRoot: projectRoot ?? process.cwd(),
127
+ scopeOverride,
128
+ });
129
+ if (result.skipped.length > 0) {
130
+ for (const s of result.skipped)
131
+ console.log(picocolors_1.default.yellow(` ⚠ Skipped: ${s}`));
132
+ }
133
+ if (result.installed.length === 0) {
134
+ (0, prompts_1.outro)(picocolors_1.default.yellow(`Nothing installed for bundle "${matchedBundle.name}".`));
135
+ return;
136
+ }
137
+ const lines = result.installed.map((n) => picocolors_1.default.green(n)).join('\n ');
138
+ const recordNote = result.recordedExtension
139
+ ? `\n\n${picocolors_1.default.dim('Recorded as a project extension in .awm/profile.json (commit it; symlinks are gitignored).')}`
140
+ : '';
141
+ (0, prompts_1.outro)(`✅ Installed bundle ${picocolors_1.default.cyan(matchedBundle.name)}:\n ${lines}${recordNote}`);
142
+ return;
143
+ }
144
+ }
145
+ // 2. Discover artifacts
146
+ const skills = (0, discovery_1.discoverSkills)();
147
+ const workflows = (0, discovery_1.discoverWorkflows)();
148
+ const agents = (0, discovery_1.discoverAgents)();
149
+ if (skills.length === 0 && workflows.length === 0 && agents.length === 0) {
150
+ (0, prompts_1.outro)(picocolors_1.default.yellow('No artifacts found in the registry. Please check your registry content.'));
151
+ process.exit(0);
152
+ }
153
+ const prefs = (0, config_1.getPreferences)();
154
+ // 3. Agent & Scope Prompts (Moved up)
155
+ let targetAgents;
156
+ if (options.agent) {
157
+ const validAgents = Object.keys(providers_1.PROVIDERS);
158
+ const parsed = options.agent.split(',').map(a => a.trim());
159
+ for (const a of parsed) {
160
+ if (!validAgents.includes(a)) {
161
+ console.error(picocolors_1.default.red(`Invalid agent "${a}". Use: ${validAgents.join(', ')}.`));
162
+ process.exit(1);
163
+ }
164
+ }
165
+ targetAgents = parsed;
166
+ }
167
+ else {
168
+ const agentChoice = await (0, prompts_1.multiselect)({
169
+ message: 'Which agent(s) do you want to install to?',
170
+ options: Object.entries(providers_1.PROVIDERS).map(([key, config]) => ({
171
+ value: key,
172
+ label: config.label
173
+ })),
174
+ initialValues: [prefs.defaultAgent],
175
+ required: true
176
+ });
177
+ handleCancel(agentChoice);
178
+ targetAgents = agentChoice;
179
+ }
180
+ let scopeVal;
181
+ if (options.scope) {
182
+ if (!['local', 'global'].includes(options.scope)) {
183
+ console.error(picocolors_1.default.red(`Invalid scope "${options.scope}". Use: local or global.`));
184
+ process.exit(1);
185
+ }
186
+ scopeVal = options.scope;
187
+ }
188
+ else {
189
+ const scopeChoice = await (0, prompts_1.select)({
190
+ message: 'Installation scope',
191
+ options: [
192
+ { value: 'local', label: 'Project (Local)' },
193
+ { value: 'global', label: 'Global' }
194
+ ],
195
+ initialValue: prefs.defaultScope
196
+ });
197
+ handleCancel(scopeChoice);
198
+ scopeVal = scopeChoice;
199
+ }
200
+ // 4. Build the package view, filtered to artifact types the target agent(s) support
201
+ const includeWorkflows = targetAgents.some(a => providers_1.PROVIDERS[a].workflow !== null);
202
+ const includeAgents = targetAgents.some(a => providers_1.PROVIDERS[a].agent !== null);
203
+ const view = (0, registry_view_1.buildPackageView)(skills, includeWorkflows ? workflows : [], includeAgents ? agents : [], (0, bundles_1.discoverAllBundles)());
204
+ if (view.length === 0) {
205
+ (0, prompts_1.outro)(picocolors_1.default.yellow('No artifacts available for the selected agent(s).'));
206
+ process.exit(0);
207
+ }
208
+ // 5. Level 1 — pick package(s)
209
+ const pkgChoice = await (0, prompts_1.multiselect)({
210
+ message: 'Select package(s)',
211
+ options: (0, registry_view_1.buildLevel1Options)(view),
212
+ required: true
213
+ });
214
+ handleCancel(pkgChoice);
215
+ const selectedPackages = pkgChoice
216
+ .map(name => view.find(p => p.name === name))
217
+ .filter(Boolean);
218
+ // 5b. Level 2 — pick skills within each package, in sequence
219
+ const dedup = new Map();
220
+ for (let i = 0; i < selectedPackages.length; i++) {
221
+ const pkg = selectedPackages[i];
222
+ const skillChoice = await (0, prompts_1.multiselect)({
223
+ message: `[${i + 1}/${selectedPackages.length}] ${pkg.name} — select artifacts`,
224
+ options: (0, registry_view_1.buildLevel2Options)(pkg),
225
+ initialValues: [registry_view_1.ALL_SENTINEL],
226
+ required: true
227
+ });
228
+ handleCancel(skillChoice);
229
+ for (const a of (0, registry_view_1.resolveLevel2Selection)(pkg, skillChoice)) {
230
+ dedup.set((0, registry_view_1.artifactValue)(a), a);
231
+ }
232
+ }
233
+ const artifactsToInstall = Array.from(dedup.values()).map(a => ({ name: a.installName, sourcePath: a.sourcePath, type: a.type }));
234
+ if (artifactsToInstall.length === 0) {
235
+ (0, prompts_1.outro)(picocolors_1.default.yellow('No artifacts selected.'));
236
+ return;
237
+ }
238
+ // 6. Installation Method
239
+ let methodVal;
240
+ if (options.method) {
241
+ if (!['symlink', 'copy'].includes(options.method)) {
242
+ console.error(picocolors_1.default.red(`Invalid method "${options.method}". Use: symlink or copy.`));
243
+ process.exit(1);
244
+ }
245
+ methodVal = options.method;
246
+ }
247
+ else {
248
+ const recommendedMethod = scopeVal === 'local' ? 'copy' : 'symlink';
249
+ const methodChoice = await (0, prompts_1.select)({
250
+ message: 'Installation method',
251
+ options: [
252
+ { value: 'symlink', label: `Symlink (Updates instantly)${recommendedMethod === 'symlink' ? ' - Recommended' : ''}` },
253
+ { value: 'copy', label: `Copy to agent${recommendedMethod === 'copy' ? ' - Recommended for Git repos' : ''}` }
254
+ ],
255
+ initialValue: recommendedMethod
256
+ });
257
+ handleCancel(methodChoice);
258
+ methodVal = methodChoice;
259
+ }
260
+ // 7. Confirm (skip with --yes)
261
+ if (!options.yes) {
262
+ const agentLabels = targetAgents.join(', ');
263
+ const shouldProceed = await (0, prompts_1.confirm)({ message: `Install ${artifactsToInstall.length} artifact(s) to ${targetAgents.length} agent(s) (${agentLabels})?` });
264
+ handleCancel(shouldProceed);
265
+ if (!shouldProceed) {
266
+ (0, prompts_1.outro)('Installation cancelled.');
267
+ return;
268
+ }
269
+ }
270
+ const installSpinner = (0, prompts_1.spinner)();
271
+ installSpinner.start('Installing artifacts...');
272
+ try {
273
+ const installed = [];
274
+ const skipped = [];
275
+ for (const currentAgent of targetAgents) {
276
+ for (const artifact of artifactsToInstall) {
277
+ // Skip artifacts not supported by this agent
278
+ if (providers_1.PROVIDERS[currentAgent][artifact.type] === null) {
279
+ skipped.push(`${artifact.name} (${currentAgent})`);
280
+ continue;
281
+ }
282
+ const targetDir = (0, providers_1.getTargetPath)(artifact.type, currentAgent, scopeVal);
283
+ const finalDest = path_1.default.join(targetDir, artifact.name);
284
+ (0, executor_1.installArtifact)(artifact.sourcePath, finalDest, methodVal);
285
+ installed.push(`${artifact.name} → ${currentAgent} (${scopeVal})`);
286
+ }
287
+ }
288
+ (0, config_1.savePreferences)({ defaultAgent: targetAgents[0], defaultScope: scopeVal, installMethod: methodVal });
289
+ installSpinner.stop('Installation complete!');
290
+ if (skipped.length > 0) {
291
+ for (const s of skipped) {
292
+ console.log(picocolors_1.default.yellow(` ⚠️ Skipped: ${s} (not supported by target agent)`));
293
+ }
294
+ }
295
+ const names = installed.map(n => picocolors_1.default.green(n)).join('\n ');
296
+ (0, prompts_1.outro)(`✅ Installed:\n ${names}`);
297
+ }
298
+ catch (e) {
299
+ installSpinner.stop('Installation failed.');
300
+ console.error(picocolors_1.default.red(e.message));
301
+ process.exit(1);
302
+ }
303
+ });
304
+ program.command('update')
305
+ .description('Sync all configured registries with their remotes')
306
+ .action(async () => {
307
+ (0, prompts_1.intro)(picocolors_1.default.bgCyan(picocolors_1.default.black(' AWM - Update Registries ')));
308
+ const s = (0, prompts_1.spinner)();
309
+ s.start('Syncing registries...');
310
+ const results = await (0, registries_1.syncRegistries)();
311
+ s.stop('Registries synced.');
312
+ if (results.length === 0) {
313
+ console.log(picocolors_1.default.yellow(' No registries configured — run `awm init` (seeds baseline) or `awm registry add <remote>`.'));
314
+ }
315
+ for (const r of results) {
316
+ if (r.action === 'error') {
317
+ console.warn(picocolors_1.default.yellow(` ⚠ registry ${r.name}: ${r.error}`));
318
+ }
319
+ else {
320
+ console.log(picocolors_1.default.green(` ✓ Registry ${r.name} ${r.action === 'pulled' ? 'updated' : 're-cloned'} @ ${r.version}`));
321
+ }
322
+ }
323
+ for (const f of (0, registries_1.verifyMinCliVersions)()) {
324
+ console.warn(picocolors_1.default.yellow(` ⚠ El registry ${f.name} requiere CLI ≥ ${f.min} (tenés ${(0, cli_version_1.cliVersion)()}) — corré: npm i -g agentic-workflow-manager`));
325
+ }
326
+ try {
327
+ const regen = (0, regenerate_1.regenerateGlobalContext)();
328
+ const refreshed = regen.filter((r) => r.action === 'refreshed').map((r) => r.agent);
329
+ if (refreshed.length > 0)
330
+ console.log(picocolors_1.default.green(` ✓ Regenerated AWM context for: ${refreshed.join(', ')}`));
331
+ }
332
+ catch { /* no aborta */ }
333
+ try {
334
+ for (const { agent, result } of (0, skill_integrity_1.reconcileAllSkillLinks)((0, registries_1.contentRoots)())) {
335
+ const touched = result.relinked.length + result.pruned.length;
336
+ if (touched > 0)
337
+ console.log(picocolors_1.default.green(` ✓ Reconciled ${agent} skill links: re-linked ${result.relinked.length}, pruned ${result.pruned.length}`));
338
+ }
339
+ }
340
+ catch { /* no aborta */ }
341
+ try {
342
+ const hooksRoot = (0, registries_1.capabilityRoot)('hooks');
343
+ if (hooksRoot) {
344
+ for (const r of (0, resync_1.resyncInstalledHooks)(hooksRoot)) {
345
+ if (r.action === 'resynced')
346
+ console.log(picocolors_1.default.green(` ✓ Re-synced ${r.agent} hook scripts`));
347
+ else if (r.action === 'registry-missing')
348
+ console.warn(picocolors_1.default.yellow(` ⚠ ${r.agent} hook installed but registry hooks missing — run 'awm hooks install'`));
349
+ }
350
+ }
351
+ }
352
+ catch { /* no aborta */ }
353
+ await (0, update_check_1.offerSelfUpdate)(); // capa 2 — Task 13
354
+ (0, prompts_1.outro)('✅ Registries, skills y hooks actualizados.');
355
+ });
356
+ program.command('sync')
357
+ .description('Rebuild local skill symlinks from .awm/profile.json (e.g. after cloning on a new machine)')
358
+ .option('-a, --agent <agent>', `Target agent: ${Object.keys(providers_1.PROVIDERS).join(', ')}`)
359
+ .option('-m, --method <method>', 'Install method: symlink or copy', 'symlink')
360
+ .action(async (options) => {
361
+ (0, prompts_1.intro)(picocolors_1.default.bgCyan(picocolors_1.default.black(' AWM - Sync Project Profile ')));
362
+ const projectRoot = (0, profile_1.findProjectRoot)(process.cwd());
363
+ if (!projectRoot) {
364
+ console.error(picocolors_1.default.red('No project root found (need a .git/, package.json, or .awm/profile.json here).'));
365
+ process.exit(1);
366
+ }
367
+ let profile;
368
+ try {
369
+ profile = (0, profile_1.readProfile)(projectRoot);
370
+ }
371
+ catch (e) {
372
+ console.error(picocolors_1.default.red(e.message));
373
+ process.exit(1);
374
+ }
375
+ const s = (0, prompts_1.spinner)();
376
+ s.start('Syncing registries...');
377
+ const syncResults = await (0, registries_1.syncRegistries)();
378
+ s.stop('Registries synced.');
379
+ for (const r of syncResults) {
380
+ if (r.action === 'error')
381
+ console.warn(picocolors_1.default.yellow(` ⚠ registry ${r.name}: ${r.error}`));
382
+ }
383
+ // Gate minCliVersion (WS-4): un registry puede exigir una versión mínima del CLI.
384
+ // Corre ANTES del gate de pins — gates de contrato primero (CONSTITUTION).
385
+ const cliFailures = (0, registries_1.verifyMinCliVersions)();
386
+ if (cliFailures.length > 0) {
387
+ for (const f of cliFailures) {
388
+ console.error(picocolors_1.default.red(`El registry ${f.name} requiere CLI ≥ ${f.min} (tenés ${(0, cli_version_1.cliVersion)()}).`));
389
+ console.error(picocolors_1.default.red(' Corré: npm i -g agentic-workflow-manager'));
390
+ }
391
+ process.exit(1);
392
+ }
393
+ // Gate de versión (WS-3): el pin del profile es el lock del proyecto.
394
+ // Runs before the empty-extensions early-exit so pinned projects always fail fast.
395
+ const pins = profile.registries ?? {};
396
+ if (Object.keys(pins).length > 0) {
397
+ const failures = await (0, profile_pins_1.verifyProjectPins)(pins);
398
+ if (failures.length > 0) {
399
+ for (const f of failures) {
400
+ if (f.reason === 'missing-registry') {
401
+ const registriesConfig = (0, registries_1.readRegistriesConfig)();
402
+ const isConfigured = registriesConfig.some((r) => r.name === f.name);
403
+ if (isConfigured) {
404
+ console.error(picocolors_1.default.red(`The registry "${f.name}" is configured but not yet synced on this machine. Run: awm update`));
405
+ }
406
+ else {
407
+ console.error(picocolors_1.default.red(`The registry "${f.name}" is not configured on this machine. Run: awm registry add <remote>`));
408
+ }
409
+ }
410
+ else {
411
+ console.error(picocolors_1.default.red(`La máquina tiene ${f.name} @ ${f.actual ? `v${f.actual}` : 'HEAD (sin tag)'} pero el proyecto requiere v${f.required}.`));
412
+ console.error(picocolors_1.default.red(` Corré: awm pin ${f.name} ${f.required} && awm update`));
413
+ }
414
+ }
415
+ process.exit(1);
416
+ }
417
+ }
418
+ if (profile.extensions.length === 0) {
419
+ (0, prompts_1.outro)(picocolors_1.default.yellow('No extensions in .awm/profile.json — nothing to sync. Use `awm add <bundle>` first.'));
420
+ return;
421
+ }
422
+ const prefs = (0, config_1.getPreferences)();
423
+ let agents;
424
+ if (options.agent) {
425
+ const valid = Object.keys(providers_1.PROVIDERS);
426
+ const parsed = options.agent.split(',').map((a) => a.trim());
427
+ for (const a of parsed) {
428
+ if (!valid.includes(a)) {
429
+ console.error(picocolors_1.default.red(`Invalid agent "${a}". Use: ${valid.join(', ')}.`));
430
+ process.exit(1);
431
+ }
432
+ }
433
+ agents = parsed;
434
+ }
435
+ else {
436
+ agents = [prefs.defaultAgent];
437
+ }
438
+ const method = options.method === 'copy' ? 'copy' : 'symlink';
439
+ const result = (0, bundle_install_1.syncProfile)({ projectRoot, bundles: (0, bundles_1.discoverAllBundles)(), agents, method });
440
+ if (result.skipped.length > 0) {
441
+ for (const sk of result.skipped)
442
+ console.log(picocolors_1.default.yellow(` ⚠ Skipped: ${sk}`));
443
+ }
444
+ const lines = result.installed.map((n) => picocolors_1.default.green(n)).join('\n ');
445
+ const installedNote = lines ? `\n ${lines}` : picocolors_1.default.dim(' (all up to date)');
446
+ (0, prompts_1.outro)(`✅ Synced extensions [${result.extensions.join(', ')}]:${installedNote}`);
447
+ });
448
+ program.command('list [package]')
449
+ .description('List available artifacts. With no argument shows a package summary; pass a package name or --all for detail.')
450
+ .option('-a, --all', 'Expand every package')
451
+ .action(async (packageName, options) => {
452
+ (0, prompts_1.intro)(picocolors_1.default.bgCyan(picocolors_1.default.black(' AWM - Registry Listing ')));
453
+ const s = (0, prompts_1.spinner)();
454
+ s.start('Syncing registries...');
455
+ const listSyncResults = await (0, registries_1.syncRegistries)();
456
+ s.stop('Registries synced.');
457
+ for (const r of listSyncResults) {
458
+ if (r.action === 'error')
459
+ console.warn(picocolors_1.default.yellow(` ⚠ registry ${r.name}: ${r.error}`));
460
+ }
461
+ const fullView = (0, registry_view_1.buildPackageView)((0, discovery_1.discoverSkills)(), (0, discovery_1.discoverWorkflows)(), (0, discovery_1.discoverAgents)(), (0, bundles_1.discoverAllBundles)());
462
+ const view = options.all ? fullView : fullView.filter((p) => p.visibility !== 'private');
463
+ if (view.length === 0) {
464
+ (0, prompts_1.outro)(picocolors_1.default.yellow('No artifacts found in the registry. Run `awm update` or check your registry content.'));
465
+ return;
466
+ }
467
+ if (packageName && options.all) {
468
+ console.log(picocolors_1.default.dim('(Ignoring --all when a package name is provided.)'));
469
+ }
470
+ // Detail for a single package.
471
+ if (packageName) {
472
+ const { match, suggestion } = (0, registry_view_1.findPackage)(fullView, packageName);
473
+ if (!match) {
474
+ const hint = suggestion
475
+ ? picocolors_1.default.dim(` Did you mean "${suggestion}"?`)
476
+ : picocolors_1.default.dim(' Run `awm list` to see available packages.');
477
+ console.error(picocolors_1.default.red(`No package named "${packageName}".`) + hint);
478
+ process.exit(1);
479
+ }
480
+ console.log();
481
+ for (const line of (0, registry_view_1.packageDetailLines)(match))
482
+ console.log(line);
483
+ console.log();
484
+ (0, prompts_1.outro)(`Run ${picocolors_1.default.green(`awm add`)} to install artifacts from ${picocolors_1.default.cyan(match.name)}.`);
485
+ return;
486
+ }
487
+ // Expand everything.
488
+ if (options.all) {
489
+ for (const pkg of view) {
490
+ console.log();
491
+ for (const line of (0, registry_view_1.packageDetailLines)(pkg))
492
+ console.log(line);
493
+ }
494
+ console.log();
495
+ (0, prompts_1.outro)(`Run ${picocolors_1.default.green('awm add')} to install any of these artifacts.`);
496
+ return;
497
+ }
498
+ // Default: compact summary.
499
+ console.log();
500
+ for (const line of (0, registry_view_1.packageSummaryLines)(view))
501
+ console.log(line);
502
+ console.log();
503
+ console.log(picocolors_1.default.dim(` awm list <pkg> · awm list --all`));
504
+ (0, prompts_1.outro)(`Run ${picocolors_1.default.green('awm add')} to install artifacts.`);
505
+ });
506
+ program.command('remove')
507
+ .description('Remove an installed skill or workflow')
508
+ .action(async () => {
509
+ (0, prompts_1.intro)(picocolors_1.default.bgCyan(picocolors_1.default.black(' AWM - Remove Artifact ')));
510
+ const prefs = (0, config_1.getPreferences)();
511
+ // Multi-agent selection (matching the add command flow)
512
+ const agentChoice = await (0, prompts_1.multiselect)({
513
+ message: 'From which agent(s)?',
514
+ options: Object.entries(providers_1.PROVIDERS).map(([key, config]) => ({
515
+ value: key,
516
+ label: config.label
517
+ })),
518
+ initialValues: [prefs.defaultAgent],
519
+ required: true
520
+ });
521
+ handleCancel(agentChoice);
522
+ const targetAgents = agentChoice;
523
+ const scopeChoice = await (0, prompts_1.select)({
524
+ message: 'Scope?',
525
+ options: [
526
+ { value: 'local', label: 'Project (Local)' },
527
+ { value: 'global', label: 'Global' }
528
+ ],
529
+ initialValue: prefs.defaultScope
530
+ });
531
+ handleCancel(scopeChoice);
532
+ const scopeVal = scopeChoice;
533
+ // Scan installed artifacts across all selected agents, aggregating by name
534
+ const artifactMap = new Map();
535
+ const scanDir = (dir, type, agent) => {
536
+ if (!fs_1.default.existsSync(dir))
537
+ return;
538
+ const entries = fs_1.default.readdirSync(dir, { withFileTypes: true });
539
+ for (const entry of entries) {
540
+ const existing = artifactMap.get(entry.name);
541
+ if (existing) {
542
+ existing.installedIn.push(agent);
543
+ existing.fullPaths.push(path_1.default.join(dir, entry.name));
544
+ }
545
+ else {
546
+ artifactMap.set(entry.name, {
547
+ name: entry.name,
548
+ type,
549
+ installedIn: [agent],
550
+ fullPaths: [path_1.default.join(dir, entry.name)]
551
+ });
552
+ }
553
+ }
554
+ };
555
+ for (const targetAgent of targetAgents) {
556
+ try {
557
+ scanDir((0, providers_1.getTargetPath)('skill', targetAgent, scopeVal), 'skill', targetAgent);
558
+ }
559
+ catch { /* ok */ }
560
+ try {
561
+ scanDir((0, providers_1.getTargetPath)('workflow', targetAgent, scopeVal), 'workflow', targetAgent);
562
+ }
563
+ catch { /* ok */ }
564
+ try {
565
+ scanDir((0, providers_1.getTargetPath)('agent', targetAgent, scopeVal), 'agent', targetAgent);
566
+ }
567
+ catch { /* ok */ }
568
+ }
569
+ const installed = Array.from(artifactMap.values());
570
+ if (installed.length === 0) {
571
+ (0, prompts_1.outro)(picocolors_1.default.yellow('No installed artifacts found for the selected agents/scope.'));
572
+ process.exit(0);
573
+ }
574
+ const groupedOpts = (0, grouping_1.buildGroupedOptions)(installed, (0, bundles_1.discoverAllBundles)(), (c) => {
575
+ const hasSkill = c.artifacts.some(a => a.type === 'skill');
576
+ const hasWf = c.artifacts.some(a => a.type === 'workflow');
577
+ const hasAgent = c.artifacts.some(a => a.type === 'agent');
578
+ const icons = [hasSkill ? '🧠' : '', hasWf ? '⚡' : '', hasAgent ? '🤖' : ''].filter(Boolean).join(' ');
579
+ const locations = new Set();
580
+ for (const a of c.artifacts) {
581
+ for (const loc of a.installedIn)
582
+ locations.add(loc);
583
+ }
584
+ return `${icons} ${c.baseName} ${picocolors_1.default.dim(`(in: ${Array.from(locations).join(', ')})`)}`;
585
+ });
586
+ const toRemove = await (0, prompts_1.multiselect)({
587
+ message: 'Select artifact(s) to remove',
588
+ options: groupedOpts,
589
+ required: true
590
+ });
591
+ handleCancel(toRemove);
592
+ const resolved = resolveSelectedArtifacts(toRemove);
593
+ const names = resolved.map(a => picocolors_1.default.red(a.name)).join(', ');
594
+ const confirmRemove = await (0, prompts_1.confirm)({ message: `Remove ${names}?` });
595
+ handleCancel(confirmRemove);
596
+ if (confirmRemove) {
597
+ try {
598
+ for (const artifact of resolved) {
599
+ for (const p of artifact.fullPaths) {
600
+ (0, executor_1.removeArtifact)(p);
601
+ }
602
+ }
603
+ (0, prompts_1.outro)(`✅ Removed ${resolved.map(a => picocolors_1.default.red(a.name)).join(', ')} (${scopeVal})`);
604
+ }
605
+ catch (e) {
606
+ console.error(picocolors_1.default.red(e.message));
607
+ process.exit(1);
608
+ }
609
+ }
610
+ else {
611
+ (0, prompts_1.outro)('Removal cancelled.');
612
+ }
613
+ });
614
+ function loadEnvFile(cwd) {
615
+ const envPath = path_1.default.join(cwd, '.env');
616
+ if (!fs_1.default.existsSync(envPath))
617
+ return {};
618
+ const env = {};
619
+ for (const line of fs_1.default.readFileSync(envPath, 'utf-8').split('\n')) {
620
+ const trimmed = line.trim();
621
+ if (!trimmed || trimmed.startsWith('#'))
622
+ continue;
623
+ const eqIdx = trimmed.indexOf('=');
624
+ if (eqIdx === -1)
625
+ continue;
626
+ const key = trimmed.slice(0, eqIdx).trim();
627
+ const value = trimmed.slice(eqIdx + 1).trim().replace(/^["']|["']$/g, '');
628
+ if (key)
629
+ env[key] = value;
630
+ }
631
+ return env;
632
+ }
633
+ const miroCmd = program.command('miro').description('Miro board integration');
634
+ miroCmd.command('sync <storyMapPath>')
635
+ .description('Sync a story-map.md file to a Miro board frame')
636
+ .action(async (storyMapPath) => {
637
+ (0, prompts_1.intro)(picocolors_1.default.bgCyan(picocolors_1.default.black(' AWM - Miro Sync ')));
638
+ // 1. Load config from .env in cwd
639
+ const env = loadEnvFile(process.cwd());
640
+ const token = env['MIRO_TOKEN'];
641
+ const boardId = env['MIRO_BOARD_ID'];
642
+ if (!token || !boardId) {
643
+ console.error(picocolors_1.default.red('✗ Missing config. Add to .env in project root:'));
644
+ console.error(picocolors_1.default.dim(' MIRO_TOKEN=your_token_here'));
645
+ console.error(picocolors_1.default.dim(' MIRO_BOARD_ID=your_board_id_here'));
646
+ process.exit(1);
647
+ }
648
+ // 2. Read and parse story map
649
+ const resolvedPath = path_1.default.resolve(process.cwd(), storyMapPath);
650
+ if (!fs_1.default.existsSync(resolvedPath)) {
651
+ console.error(picocolors_1.default.red(`✗ File not found: ${resolvedPath}`));
652
+ process.exit(1);
653
+ }
654
+ const content = fs_1.default.readFileSync(resolvedPath, 'utf-8');
655
+ const storyMap = (0, story_map_parser_1.parseStoryMap)(content);
656
+ if (storyMap.activities.length === 0) {
657
+ console.error(picocolors_1.default.red('✗ No activities found in Backbone section. Check markdown format.'));
658
+ process.exit(1);
659
+ }
660
+ // 3. Sync to Miro
661
+ const s = (0, prompts_1.spinner)();
662
+ const isFirstSync = !storyMap.miro_frame_id;
663
+ s.start(isFirstSync ? 'Creating Miro frame...' : 'Updating Miro frame...');
664
+ try {
665
+ const result = await (0, miro_1.syncToMiro)({ token, boardId }, storyMap, storyMap.miro_frame_id);
666
+ // 4. Persist frame ID back to frontmatter on first sync
667
+ if (isFirstSync) {
668
+ const updated = (0, story_map_parser_1.updateMiroFrameId)(content, result.frameId);
669
+ fs_1.default.writeFileSync(resolvedPath, updated, 'utf-8');
670
+ }
671
+ s.stop('Sync complete!');
672
+ console.log(picocolors_1.default.green(` ✓ Frame: ${result.frameId}`));
673
+ console.log(picocolors_1.default.green(` ✓ Created: ${result.created} | Updated: ${result.updated} | Deleted: ${result.deleted}`));
674
+ (0, prompts_1.outro)('Story map synced to Miro. Open your board to view the frame.');
675
+ }
676
+ catch (e) {
677
+ s.stop('Sync failed.');
678
+ console.error(picocolors_1.default.red(`✗ ${e.message}`));
679
+ process.exit(1);
680
+ }
681
+ });
682
+ (0, hooks_1.registerHooksCommand)(program);
683
+ (0, sensors_1.registerSensorsCommand)(program);
684
+ (0, ledger_1.registerLedgerCommand)(program);
685
+ (0, doctor_1.registerDoctorCommand)(program);
686
+ (0, init_1.registerInitCommand)(program);
687
+ (0, registry_1.registerRegistryCommand)(program);
688
+ (0, pin_1.registerPinCommands)(program);
689
+ program.parse();