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,181 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.renderInitOutcome = renderInitOutcome;
40
+ exports.runInit = runInit;
41
+ exports.makeConfirmExtensions = makeConfirmExtensions;
42
+ exports.registerInitCommand = registerInitCommand;
43
+ // src/commands/init.ts
44
+ const fs_1 = __importDefault(require("fs"));
45
+ const picocolors_1 = __importDefault(require("picocolors"));
46
+ const doctor_1 = require("./doctor");
47
+ const context_1 = require("../core/diagnostics/context");
48
+ const bundles_1 = require("../core/bundles");
49
+ const registries_1 = require("../core/registries");
50
+ const orchestrator_1 = require("../core/init/orchestrator");
51
+ const steps_1 = require("../core/init/steps");
52
+ // ---------------------------------------------------------------------------
53
+ // Rendering
54
+ // ---------------------------------------------------------------------------
55
+ function stepGlyph(action) {
56
+ if (action === 'applied')
57
+ return picocolors_1.default.green('✔');
58
+ if (action === 'pending')
59
+ return picocolors_1.default.yellow('◷');
60
+ if (action === 'failed')
61
+ return picocolors_1.default.red('✖');
62
+ return picocolors_1.default.dim('·');
63
+ }
64
+ function renderInitOutcome(o) {
65
+ const lines = [];
66
+ lines.push(picocolors_1.default.bold('AWM · init'));
67
+ lines.push('');
68
+ // --- Estado inicial ---
69
+ lines.push(picocolors_1.default.bold('Estado inicial'));
70
+ lines.push((0, doctor_1.renderReport)(o.before));
71
+ lines.push('');
72
+ // --- Acciones ---
73
+ lines.push(picocolors_1.default.bold('Acciones'));
74
+ for (const s of o.steps) {
75
+ const det = s.detail ? picocolors_1.default.dim(` ${s.detail}`) : '';
76
+ const err = s.error ? picocolors_1.default.red(` [${s.error}]`) : '';
77
+ lines.push(` ${stepGlyph(s.action)} ${s.id}${det}${err}`);
78
+ }
79
+ lines.push('');
80
+ // --- Estado final ---
81
+ lines.push(picocolors_1.default.bold('Estado final'));
82
+ lines.push((0, doctor_1.renderReport)(o.after));
83
+ lines.push('');
84
+ // --- Summary ---
85
+ const pendingCount = o.pending;
86
+ const estado = o.after.overall === 'healthy' ? picocolors_1.default.green('sano') : picocolors_1.default.red('degradado');
87
+ lines.push(`estado: ${estado} · ${pendingCount} pasos requieren un agente (skills arriba)`);
88
+ return lines.join('\n');
89
+ }
90
+ async function runInit(opts = {}) {
91
+ const cwd = opts.cwd ?? process.cwd();
92
+ const agent = opts.agent ?? 'claude-code';
93
+ let outcome;
94
+ try {
95
+ const mergedActions = {
96
+ ...steps_1.defaultActions,
97
+ ...(opts.actions ?? {}),
98
+ };
99
+ (0, registries_1.seedBaselineRegistry)();
100
+ if ((0, registries_1.listRegistries)().some((r) => !fs_1.default.existsSync(r.contentRoot))) {
101
+ await mergedActions.syncCache();
102
+ }
103
+ const bundles = (0, bundles_1.discoverAllBundles)();
104
+ const ctx = (0, context_1.gatherContext)({ cwd, bundles, agent });
105
+ // In machineOnly mode, null out the project context so project steps are skipped
106
+ const effectiveCtx = opts.machineOnly
107
+ ? { ...ctx, project: null }
108
+ : ctx;
109
+ const confirmExtensions = makeConfirmExtensions(!!opts.yes);
110
+ outcome = await (0, orchestrator_1.runInitSteps)({
111
+ cwd,
112
+ ctx: effectiveCtx,
113
+ bundles,
114
+ agent,
115
+ installMethod: 'symlink',
116
+ registryRoot: (0, registries_1.capabilityRoot)('hooks') ?? '',
117
+ contentDir: (0, registries_1.contentRoots)()[0] ?? '',
118
+ sensorPacksRoot: (0, registries_1.capabilityRoot)('sensor-packs') ?? '',
119
+ confirmExtensions,
120
+ actions: mergedActions,
121
+ });
122
+ }
123
+ catch (err) {
124
+ process.stderr.write(`awm init: error interno: ${err.message}\n`);
125
+ return 2;
126
+ }
127
+ if (opts.json) {
128
+ process.stdout.write(JSON.stringify(outcome, null, 2) + '\n');
129
+ }
130
+ else {
131
+ process.stdout.write(renderInitOutcome(outcome) + '\n');
132
+ }
133
+ return outcome.after.overall === 'healthy' ? 0 : 1;
134
+ }
135
+ // ---------------------------------------------------------------------------
136
+ // Extension confirmation factory
137
+ // ---------------------------------------------------------------------------
138
+ /**
139
+ * Builds the extension-confirmation callback. The non-`--yes` path opens a clack
140
+ * `multiselect`; clack crashes ("Cannot read properties of undefined (reading
141
+ * 'disabled')") when handed an empty options array, so we short-circuit empty
142
+ * `proposed` BEFORE importing/invoking it (#1, greenfield dirs detect no signals).
143
+ */
144
+ function makeConfirmExtensions(yes) {
145
+ if (yes)
146
+ return async (proposed) => proposed;
147
+ return async (proposed, signals) => {
148
+ if (proposed.length === 0)
149
+ return [];
150
+ const { multiselect, isCancel } = await Promise.resolve().then(() => __importStar(require('@clack/prompts')));
151
+ const choice = await multiselect({
152
+ message: `Extensiones detectadas (${signals.join(', ')}) — ¿activar?`,
153
+ options: proposed.map((p) => ({ value: p, label: p })),
154
+ initialValues: proposed,
155
+ required: false,
156
+ });
157
+ if (isCancel(choice))
158
+ return [];
159
+ return choice;
160
+ };
161
+ }
162
+ // ---------------------------------------------------------------------------
163
+ // Commander registration
164
+ // ---------------------------------------------------------------------------
165
+ function registerInitCommand(program) {
166
+ program.command('init')
167
+ .description('Bootstrap the AWM harness on this machine / project (idempotent)')
168
+ .option('-y, --yes', 'Skip confirmation prompts')
169
+ .option('-a, --agent <agent>', 'Target agent (default: claude-code)')
170
+ .option('--machine-only', 'Only run machine-level steps (skip project steps)')
171
+ .option('--json', 'Emit the InitOutcome as JSON')
172
+ .action(async (options) => {
173
+ const code = await runInit({
174
+ yes: options.yes,
175
+ agent: options.agent,
176
+ machineOnly: options.machineOnly,
177
+ json: options.json,
178
+ });
179
+ process.exitCode = code;
180
+ });
181
+ }
@@ -0,0 +1,73 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.registerLedgerCommand = registerLedgerCommand;
4
+ const store_1 = require("../../core/ledger/store");
5
+ function archiveLabel() {
6
+ return new Date().toISOString().replace(/[-:]/g, '').replace(/\.\d+Z$/, '');
7
+ }
8
+ function registerLedgerCommand(program) {
9
+ const ledger = program.command('ledger').description('persistent per-branch findings ledger (working memory for harness-retro)');
10
+ ledger
11
+ .command('add')
12
+ .description('append a finding or win to the current branch ledger')
13
+ .requiredOption('--polarity <polarity>', 'win | finding')
14
+ .requiredOption('--class <class>', 'structural | logica | proceso | seguridad')
15
+ .requiredOption('--signature <slug>', 'dedup key for recurrence grouping')
16
+ .requiredOption('--severity <severity>', 'blocker | important | minor | info')
17
+ .requiredOption('--desc <text>', 'one-line description')
18
+ .option('--ref <ref>', 'file:line or PR/commit reference')
19
+ .option('--phase <phase>', 'lifecycle phase', 'unknown')
20
+ .option('--source-skill <skill>', 'emitting skill', 'unknown')
21
+ .option('--branch <branch>', 'override branch (default: git current branch)')
22
+ .action((opts) => {
23
+ const cwd = process.cwd();
24
+ const branch = opts.branch ?? (0, store_1.detectBranch)(cwd);
25
+ const entry = {
26
+ ts: new Date().toISOString(),
27
+ branch,
28
+ phase: opts.phase ?? 'unknown',
29
+ source_skill: opts.sourceSkill ?? 'unknown',
30
+ polarity: opts.polarity,
31
+ class: opts.class,
32
+ signature: opts.signature,
33
+ severity: opts.severity,
34
+ desc: opts.desc,
35
+ ref: opts.ref,
36
+ };
37
+ (0, store_1.addEntry)(cwd, entry);
38
+ });
39
+ ledger
40
+ .command('list')
41
+ .description('print the current branch ledger as JSON')
42
+ .option('--branch <branch>', 'override branch (default: git current branch)')
43
+ .action((opts) => {
44
+ const cwd = process.cwd();
45
+ const branch = opts.branch ?? (0, store_1.detectBranch)(cwd);
46
+ process.stdout.write(JSON.stringify((0, store_1.listEntries)(cwd, branch), null, 2) + '\n');
47
+ });
48
+ ledger
49
+ .command('recurring')
50
+ .description('print signature clusters with count >= min (recurrence signal)')
51
+ .option('--min <n>', 'minimum occurrences', '2')
52
+ .option('--branch <branch>', 'override branch (default: git current branch)')
53
+ .action((opts) => {
54
+ const cwd = process.cwd();
55
+ const branch = opts.branch ?? (0, store_1.detectBranch)(cwd);
56
+ const parsed = Number.parseInt(opts.min, 10);
57
+ const min = Number.isNaN(parsed) || parsed < 1 ? 2 : parsed;
58
+ process.stdout.write(JSON.stringify((0, store_1.recurring)(cwd, branch, min), null, 2) + '\n');
59
+ });
60
+ ledger
61
+ .command('archive')
62
+ .description('rotate the current branch ledger out of the active flow')
63
+ .option('--branch <branch>', 'override branch (default: git current branch)')
64
+ .action((opts) => {
65
+ const cwd = process.cwd();
66
+ const branch = opts.branch ?? (0, store_1.detectBranch)(cwd);
67
+ const moved = (0, store_1.archiveLedger)(cwd, branch, archiveLabel());
68
+ if (!moved) {
69
+ process.stderr.write(`awm ledger archive: no active ledger found for branch "${branch}" — nothing to archive\n`);
70
+ }
71
+ process.stdout.write(JSON.stringify({ archived: moved, branch }, null, 2) + '\n');
72
+ });
73
+ }
@@ -0,0 +1,75 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.setPin = setPin;
7
+ exports.removePin = removePin;
8
+ exports.registerPinCommands = registerPinCommands;
9
+ const picocolors_1 = __importDefault(require("picocolors"));
10
+ const config_1 = require("../utils/config");
11
+ const registries_1 = require("../core/registries");
12
+ const versioning_1 = require("../core/versioning");
13
+ const VERSION_RE = /^v?\d+\.\d+\.\d+$/;
14
+ function knownRegistryNames() {
15
+ return ['base', ...(0, registries_1.readRegistriesConfig)().map((r) => r.name)];
16
+ }
17
+ function assertKnownRegistry(name) {
18
+ const known = knownRegistryNames();
19
+ if (!known.includes(name)) {
20
+ throw new Error(`Unknown registry "${name}". Valid names: ${known.join(', ')}.`);
21
+ }
22
+ }
23
+ /** Valida y persiste pins[name] = version (normalizada sin prefijo v). */
24
+ function setPin(name, version) {
25
+ assertKnownRegistry(name);
26
+ if (!VERSION_RE.test(version)) {
27
+ throw new Error(`Invalid version "${version}" — expected X.Y.Z (e.g. 1.2.0).`);
28
+ }
29
+ const normalized = (0, versioning_1.normalizePin)(version);
30
+ const prefs = (0, config_1.getPreferences)();
31
+ prefs.pins = { ...(prefs.pins ?? {}), [name]: normalized };
32
+ (0, config_1.savePreferences)(prefs);
33
+ return normalized;
34
+ }
35
+ /** Borra pins[name]; devuelve true si existía. */
36
+ function removePin(name) {
37
+ assertKnownRegistry(name);
38
+ const prefs = (0, config_1.getPreferences)();
39
+ if (!prefs.pins || !(name in prefs.pins))
40
+ return false;
41
+ delete prefs.pins[name];
42
+ (0, config_1.savePreferences)(prefs);
43
+ return true;
44
+ }
45
+ function registerPinCommands(program) {
46
+ program.command('pin <registry> <version>')
47
+ .description("Pin a registry ('base' or an additional registry name) to a version tag, e.g. awm pin base 1.2.0")
48
+ .action((registry, version) => {
49
+ try {
50
+ const normalized = setPin(registry, version);
51
+ console.log(picocolors_1.default.green(`✓ ${registry} pinned to v${normalized}.`) + picocolors_1.default.dim(' Run `awm update` to apply.'));
52
+ }
53
+ catch (e) {
54
+ console.error(picocolors_1.default.red(e instanceof Error ? e.message : String(e)));
55
+ process.exit(1);
56
+ }
57
+ });
58
+ program.command('unpin <registry>')
59
+ .description('Remove the version pin of a registry (it returns to the latest tag on the next update)')
60
+ .action((registry) => {
61
+ try {
62
+ const removed = removePin(registry);
63
+ if (removed) {
64
+ console.log(picocolors_1.default.green(`✓ ${registry} unpinned.`) + picocolors_1.default.dim(' Run `awm update` to move to the latest tag.'));
65
+ }
66
+ else {
67
+ console.log(picocolors_1.default.yellow(`${registry} had no pin — nothing to do.`));
68
+ }
69
+ }
70
+ catch (e) {
71
+ console.error(picocolors_1.default.red(e instanceof Error ? e.message : String(e)));
72
+ process.exit(1);
73
+ }
74
+ });
75
+ }
@@ -0,0 +1,62 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.deriveRegistryName = deriveRegistryName;
7
+ exports.addRegistry = addRegistry;
8
+ // cli/src/commands/registry/add.ts
9
+ // Logic for `awm registry add`, separated from commander wiring (testable without prompts).
10
+ const fs_1 = __importDefault(require("fs"));
11
+ const simple_git_1 = __importDefault(require("simple-git"));
12
+ const registries_1 = require("../../core/registries");
13
+ const discovery_1 = require("../../core/discovery");
14
+ const bundles_1 = require("../../core/bundles");
15
+ function deriveRegistryName(remote) {
16
+ const base = remote.replace(/\/+$/, '').split(/[/:]/).pop() ?? '';
17
+ return base.replace(/\.git$/, '');
18
+ }
19
+ async function addRegistry(remote, nameOverride) {
20
+ const name = nameOverride ?? deriveRegistryName(remote);
21
+ if (!name || name === '.' || /[/\\]/.test(name)) {
22
+ return { ok: false, error: `Invalid registry name "${name}" — use --name <simple-dir-name>` };
23
+ }
24
+ const existing = (0, registries_1.readRegistriesConfig)();
25
+ if (existing.some((r) => r.name === name)) {
26
+ return { ok: false, name, error: `Registry "${name}" already exists — remove it first with 'awm registry remove ${name}'` };
27
+ }
28
+ const dest = (0, registries_1.registryContentRoot)(name);
29
+ if (fs_1.default.existsSync(dest)) {
30
+ return { ok: false, name, error: `Destination already exists on disk: ${dest}` };
31
+ }
32
+ fs_1.default.mkdirSync(registries_1.REGISTRIES_DIR, { recursive: true });
33
+ try {
34
+ await (0, simple_git_1.default)().clone(remote, dest);
35
+ }
36
+ catch (e) {
37
+ fs_1.default.rmSync(dest, { recursive: true, force: true });
38
+ return { ok: false, name, error: `Clone failed: ${e instanceof Error ? e.message : String(e)}` };
39
+ }
40
+ if (!(0, registries_1.validateRegistryLayout)(dest)) {
41
+ fs_1.default.rmSync(dest, { recursive: true, force: true });
42
+ return {
43
+ ok: false,
44
+ name,
45
+ error: `Invalid registry layout: expected at least one of ${registries_1.CONTENT_DIR_NAMES.map((d) => `${d}/`).join(', ')} at the repo root of ${remote}`,
46
+ };
47
+ }
48
+ // Collision check against already-known content — BEFORE writing config.
49
+ try {
50
+ const roots = [...(0, registries_1.contentRoots)(), dest];
51
+ (0, discovery_1.discoverSkills)(roots);
52
+ (0, discovery_1.discoverWorkflows)(roots);
53
+ (0, discovery_1.discoverAgents)(roots);
54
+ (0, bundles_1.discoverAllBundles)(roots);
55
+ }
56
+ catch (e) {
57
+ fs_1.default.rmSync(dest, { recursive: true, force: true });
58
+ return { ok: false, name, error: e instanceof Error ? e.message : String(e) };
59
+ }
60
+ (0, registries_1.writeRegistriesConfig)([...existing, { name, remote }]);
61
+ return { ok: true, name, contentRoot: dest };
62
+ }
@@ -0,0 +1,166 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.registerRegistryCommand = registerRegistryCommand;
7
+ // cli/src/commands/registry/index.ts
8
+ const fs_1 = __importDefault(require("fs"));
9
+ const prompts_1 = require("@clack/prompts");
10
+ const picocolors_1 = __importDefault(require("picocolors"));
11
+ const registries_1 = require("../../core/registries");
12
+ const discovery_1 = require("../../core/discovery");
13
+ const bundles_1 = require("../../core/bundles");
14
+ const skill_integrity_1 = require("../../core/skill-integrity");
15
+ const regenerate_1 = require("../../core/context/regenerate");
16
+ const add_1 = require("./add");
17
+ const remove_1 = require("./remove");
18
+ const status_1 = require("./status");
19
+ const config_1 = require("../../utils/config");
20
+ const profile_1 = require("../../core/profile");
21
+ const providers_1 = require("../../providers");
22
+ const install_bundles_1 = require("./install-bundles");
23
+ function registerRegistryCommand(program) {
24
+ const reg = program.command('registry').description('manage additional content registries (team/personal)');
25
+ reg.command('add <remote>')
26
+ .description('clone an additional registry (git URL or local path) and register it')
27
+ .option('--name <name>', 'registry name (default: repo basename)')
28
+ .option('--install-all', 'install every bundle from the new registry for the default agent')
29
+ .option('--no-install', 'skip the bundle install offer')
30
+ .action(async (remote, options) => {
31
+ (0, prompts_1.intro)(picocolors_1.default.bgCyan(picocolors_1.default.black(' AWM - Add Registry ')));
32
+ const s = (0, prompts_1.spinner)();
33
+ s.start('Cloning and validating registry...');
34
+ const result = await (0, add_1.addRegistry)(remote, options.name);
35
+ if (!result.ok) {
36
+ s.stop('Failed.');
37
+ console.error(picocolors_1.default.red(result.error));
38
+ process.exit(1);
39
+ }
40
+ s.stop(`Registry ${picocolors_1.default.cyan(result.name)} added at ${result.contentRoot}`);
41
+ try {
42
+ (0, regenerate_1.regenerateGlobalContext)();
43
+ }
44
+ catch {
45
+ // context regeneration must not abort a successful add
46
+ }
47
+ // Bundle install offer — failure NEVER reverts the add.
48
+ try {
49
+ const available = (0, install_bundles_1.bundlesInRegistry)(result.contentRoot);
50
+ if (available.length > 0) {
51
+ const prefs = (0, config_1.getPreferences)();
52
+ const projectRoot = (0, profile_1.findProjectRoot)(process.cwd()) ?? process.cwd();
53
+ const interactive = process.stdout.isTTY && process.stdin.isTTY;
54
+ let selection = null;
55
+ let agents = [prefs.defaultAgent];
56
+ if (options.install === false) {
57
+ selection = null;
58
+ }
59
+ else if (options.installAll) {
60
+ selection = 'all';
61
+ }
62
+ else if (interactive) {
63
+ const picked = await (0, prompts_1.multiselect)({
64
+ message: `Install bundles from ${result.name}?`,
65
+ options: available.map((b) => ({ value: b, label: b })),
66
+ required: false,
67
+ });
68
+ if (!(0, prompts_1.isCancel)(picked) && picked.length > 0) {
69
+ selection = picked;
70
+ const agentPick = await (0, prompts_1.select)({
71
+ message: 'Target agent',
72
+ initialValue: prefs.defaultAgent,
73
+ options: Object.keys(providers_1.PROVIDERS).map((a) => ({ value: a, label: a })),
74
+ });
75
+ if (!(0, prompts_1.isCancel)(agentPick))
76
+ agents = [agentPick];
77
+ else
78
+ selection = null;
79
+ }
80
+ }
81
+ if (selection) {
82
+ for (const r of (0, install_bundles_1.installBundlesFromRegistry)(result.contentRoot, selection, agents, projectRoot)) {
83
+ for (const line of r.installed)
84
+ console.log(picocolors_1.default.green(` ✓ ${line}`));
85
+ for (const sk of r.skipped)
86
+ console.log(picocolors_1.default.yellow(` ⚠ Skipped: ${sk}`));
87
+ }
88
+ }
89
+ else if (options.install !== false && !interactive) {
90
+ console.log(picocolors_1.default.dim(` Bundles available: ${available.join(', ')}`));
91
+ console.log(picocolors_1.default.dim(` Install with: awm add <bundle> --agent <agent>`));
92
+ }
93
+ }
94
+ }
95
+ catch (e) {
96
+ console.warn(picocolors_1.default.yellow(` ⚠ Bundle install failed (registry add is intact): ${e instanceof Error ? e.message : String(e)}`));
97
+ }
98
+ (0, prompts_1.outro)(`✅ Run ${picocolors_1.default.cyan('awm list')} to see the new content.`);
99
+ });
100
+ reg.command('list')
101
+ .description('list configured additional registries')
102
+ .action(() => {
103
+ const regs = (0, registries_1.listRegistries)();
104
+ if (regs.length === 0) {
105
+ console.log(picocolors_1.default.dim('No additional registries. Add one with `awm registry add <git-url>`.'));
106
+ return;
107
+ }
108
+ const earlier = [];
109
+ for (const r of regs) {
110
+ if (!fs_1.default.existsSync(r.contentRoot)) {
111
+ console.log(`${picocolors_1.default.cyan(r.name)} ${r.remote} ${picocolors_1.default.yellow("missing on disk — run 'awm update'")}`);
112
+ // Push before continue so overrides declared against this missing registry
113
+ // are correctly shown as "sin efecto" (orphan) rather than "active".
114
+ earlier.push(r.contentRoot);
115
+ continue;
116
+ }
117
+ try {
118
+ const counts = [
119
+ `${(0, discovery_1.discoverSkills)([r.contentRoot]).length} skills`,
120
+ `${(0, bundles_1.discoverAllBundles)([r.contentRoot]).length} bundles`,
121
+ `${(0, discovery_1.discoverWorkflows)([r.contentRoot]).length} workflows`,
122
+ `${(0, discovery_1.discoverAgents)([r.contentRoot]).length} agents`,
123
+ ].join(', ');
124
+ console.log(`${picocolors_1.default.cyan(r.name)} ${r.remote} ${picocolors_1.default.dim(counts)}`);
125
+ for (const o of (0, status_1.overrideStatus)(r.contentRoot, earlier)) {
126
+ console.log(o.active
127
+ ? picocolors_1.default.yellow(` ↑ override activo: ${o.name}`)
128
+ : picocolors_1.default.dim(` ∅ override sin efecto: ${o.name}`));
129
+ }
130
+ }
131
+ catch (e) {
132
+ console.log(`${picocolors_1.default.cyan(r.name)} ${r.remote} ${picocolors_1.default.yellow(`⚠ Error reading registry: ${e instanceof Error ? e.message : String(e)}`)}`);
133
+ }
134
+ earlier.push(r.contentRoot);
135
+ }
136
+ });
137
+ reg.command('remove <name>')
138
+ .description('remove an additional registry (config + clone)')
139
+ .option('-y, --yes', 'skip confirmation')
140
+ .action(async (name, options) => {
141
+ (0, prompts_1.intro)(picocolors_1.default.bgCyan(picocolors_1.default.black(' AWM - Remove Registry ')));
142
+ if (!options.yes) {
143
+ const sure = await (0, prompts_1.confirm)({ message: `Remove registry "${name}" and its local clone?` });
144
+ if ((0, prompts_1.isCancel)(sure) || !sure) {
145
+ (0, prompts_1.outro)('Cancelled.');
146
+ return;
147
+ }
148
+ }
149
+ const result = (0, remove_1.removeRegistry)(name);
150
+ if (!result.ok) {
151
+ console.error(picocolors_1.default.red(result.error));
152
+ process.exit(1);
153
+ }
154
+ try {
155
+ for (const { agent, result: r } of (0, skill_integrity_1.reconcileAllSkillLinks)((0, registries_1.contentRoots)())) {
156
+ if (r.pruned.length > 0) {
157
+ console.log(picocolors_1.default.yellow(` ⚠ Pruned ${r.pruned.length} dead skill link(s) for ${agent}`));
158
+ }
159
+ }
160
+ }
161
+ catch {
162
+ // reconciliation must not abort a successful remove
163
+ }
164
+ (0, prompts_1.outro)(`✅ Registry ${picocolors_1.default.cyan(name)} removed.`);
165
+ });
166
+ }
@@ -0,0 +1,36 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.bundlesInRegistry = bundlesInRegistry;
4
+ exports.installBundlesFromRegistry = installBundlesFromRegistry;
5
+ // cli/src/commands/registry/install-bundles.ts
6
+ // Instalación de bundles de un registry recién agregado (flujo post-add).
7
+ // Separado del wiring de commander para ser testeable sin prompts.
8
+ const bundles_1 = require("../../core/bundles");
9
+ const bundle_install_1 = require("../../core/bundle-install");
10
+ /** Bundles disponibles en un content root concreto (candidatos a instalar tras el add).
11
+ * Uses single-root discovery to avoid surfacing cross-registry collision errors here. */
12
+ function bundlesInRegistry(contentRoot) {
13
+ return (0, bundles_1.discoverBundles)(contentRoot).map((b) => b.name);
14
+ }
15
+ /**
16
+ * Instala bundles del registry `contentRoot` para los agentes dados.
17
+ * `selection` = 'all' instala todos los del registry; una lista instala solo esos.
18
+ * Las dependencias se resuelven contra TODOS los roots (pueden vivir en el base).
19
+ */
20
+ function installBundlesFromRegistry(contentRoot, selection, agents, projectRoot) {
21
+ const allBundles = (0, bundles_1.discoverAllBundles)();
22
+ const candidates = allBundles.filter((b) => b.contentRoot === contentRoot);
23
+ const wanted = selection === 'all' ? candidates : candidates.filter((b) => selection.includes(b.name));
24
+ const results = [];
25
+ for (const b of wanted) {
26
+ const summary = (0, bundle_install_1.addBundle)({
27
+ bundleName: b.name,
28
+ bundles: allBundles,
29
+ agents,
30
+ method: 'symlink',
31
+ projectRoot,
32
+ });
33
+ results.push({ bundle: b.name, installed: summary.installed, skipped: summary.skipped });
34
+ }
35
+ return results;
36
+ }
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.removeRegistry = removeRegistry;
7
+ // cli/src/commands/registry/remove.ts
8
+ const fs_1 = __importDefault(require("fs"));
9
+ const registries_1 = require("../../core/registries");
10
+ function removeRegistry(name) {
11
+ const existing = (0, registries_1.readRegistriesConfig)();
12
+ if (!existing.some((r) => r.name === name)) {
13
+ return { ok: false, error: `Registry "${name}" not found — see 'awm registry list'` };
14
+ }
15
+ (0, registries_1.writeRegistriesConfig)(existing.filter((r) => r.name !== name));
16
+ fs_1.default.rmSync((0, registries_1.registryContentRoot)(name), { recursive: true, force: true });
17
+ return { ok: true };
18
+ }
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.overrideStatus = overrideStatus;
4
+ // Estado de los overrides declarados por un registry: activo (tapa un artifact
5
+ // de un root anterior) o sin efecto (huérfano — el nombre ya no existe upstream).
6
+ const registries_1 = require("../../core/registries");
7
+ const discovery_1 = require("../../core/discovery");
8
+ const bundles_1 = require("../../core/bundles");
9
+ function artifactNamesInRoot(root) {
10
+ const names = new Set();
11
+ for (const s of (0, discovery_1.discoverSkills)([root]))
12
+ names.add(s.name);
13
+ for (const w of (0, discovery_1.discoverWorkflows)([root]))
14
+ names.add(w.name);
15
+ for (const a of (0, discovery_1.discoverAgents)([root]))
16
+ names.add(a.name);
17
+ for (const b of (0, bundles_1.discoverAllBundles)([root]))
18
+ names.add(b.name);
19
+ return names;
20
+ }
21
+ function overrideStatus(contentRoot, earlierRoots) {
22
+ const declared = Array.from((0, registries_1.readRegistryManifest)(contentRoot).overrides);
23
+ if (declared.length === 0)
24
+ return [];
25
+ const earlier = new Set();
26
+ for (const root of earlierRoots) {
27
+ for (const n of artifactNamesInRoot(root))
28
+ earlier.add(n);
29
+ }
30
+ return declared.map((name) => ({ name, active: earlier.has(name) }));
31
+ }