agentic-workflow-manager 3.13.7 → 4.0.1

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.
@@ -11,6 +11,8 @@ const picocolors_1 = __importDefault(require("picocolors"));
11
11
  const context_1 = require("../core/diagnostics/context");
12
12
  const checks_1 = require("../core/diagnostics/checks");
13
13
  const paths_1 = require("../core/paths");
14
+ // `readPreferences`, no `getPreferences`: este comando esta documentado como
15
+ // read-only y el segundo auto-vivifica el archivo. Ver la nota en config.ts.
14
16
  const config_1 = require("../utils/config");
15
17
  const agent_targets_1 = require("../core/agent-targets");
16
18
  function glyph(status) {
@@ -128,7 +130,7 @@ function runDoctor(opts = {}) {
128
130
  // internal-error catch further down.
129
131
  let targets;
130
132
  try {
131
- const prefs = (0, config_1.getPreferences)();
133
+ const prefs = (0, config_1.readPreferences)();
132
134
  targets = resolveTargets({ prefs, explicit: opts.agent });
133
135
  }
134
136
  catch (err) {
package/dist/src/index.js CHANGED
@@ -88,9 +88,19 @@ function resolveSelectedArtifacts(selections) {
88
88
  }
89
89
  return Array.from(result.values());
90
90
  }
91
+ // AWM instala BUNDLES, no artefactos sueltos. Es una decision de producto, no una
92
+ // limitacion pendiente: las skills de AWM se apoyan unas en otras (el spine de
93
+ // development-process invoca brainstorming, writing-plans, los gates de QA...), asi que
94
+ // una skill instalada sola casi nunca hace lo que el usuario espera. Ver
95
+ // docs/decisions.md, D-001.
96
+ //
97
+ // El flag `-t, --type` existia y `add.ts` NUNCA lo leia: se aceptaba y se descartaba en
98
+ // silencio. Peor, la doc y los playbooks de aceptacion documentaban `awm add <skill>
99
+ // --type skill` como el camino scripteado — una invocacion que siempre fallo con
100
+ // «Bundle "<skill>" not found». Los playbooks se escribieron contra la documentacion, no
101
+ // contra el comportamiento. Un flag que no se lee es peor que uno ausente: promete.
91
102
  program.command('add [name]')
92
- .description('Add a skill, workflow, or process interactively (or non-interactively with flags)')
93
- .option('-t, --type <type>', 'Artifact type: skill, workflow, or process')
103
+ .description('Add a bundle (package of skills) interactively, or non-interactively with flags')
94
104
  .option('-a, --agent <agent>', `Target agent: ${providers_1.AGENT_TARGETS.join(', ')}`)
95
105
  .option('-s, --scope <scope>', 'Scope: local or global')
96
106
  .option('-m, --method <method>', 'Install method: symlink or copy')
@@ -4,6 +4,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.preferencesExist = preferencesExist;
7
+ exports.readPreferences = readPreferences;
7
8
  exports.getPreferences = getPreferences;
8
9
  exports.loadPreferences = loadPreferences;
9
10
  exports.savePreferences = savePreferences;
@@ -84,6 +85,28 @@ function normalizePreferences(value, allowEnabledAgentsMigration = true) {
84
85
  JSON.stringify(source) !== JSON.stringify(enabledAgents),
85
86
  };
86
87
  }
88
+ /**
89
+ * Las preferencias TAL COMO ESTAN, sin escribir nada. Devuelve los defaults en memoria
90
+ * cuando el archivo no existe todavia.
91
+ *
92
+ * `getPreferences` auto-vivifica: si no hay archivo, lo crea con los defaults. Eso esta
93
+ * bien para un comando que va a configurar la maquina, y esta mal para uno que solo
94
+ * mira. `awm doctor` —documentado como «Read-only dashboard. Changes nothing.»— lo
95
+ * llamaba, asi que en una maquina limpia el comando de inspeccion dejaba un
96
+ * `preferences.json` con `claude-code` como agente por defecto, que despues se lee como
97
+ * «el usuario configuro esto» cuando no lo hizo. Lo encontro el playbook de aceptacion,
98
+ * no la suite: ningun test preguntaba si un comando de lectura escribia.
99
+ *
100
+ * Se midieron los otros siete comandos de inspeccion (`list`, `preflight`, `sensors
101
+ * status`, `context-budget`, `backup list`, `ledger list`, `registry status`): todos
102
+ * limpios. `doctor` era el unico.
103
+ */
104
+ function readPreferences() {
105
+ const loaded = loadPreferences();
106
+ return loaded.exists
107
+ ? loaded.prefs
108
+ : { ...DEFAULT_PREFS, enabledAgents: [...DEFAULT_PREFS.enabledAgents] };
109
+ }
87
110
  function getPreferences() {
88
111
  const loaded = loadPreferences();
89
112
  if (!loaded.exists) {
@@ -0,0 +1,97 @@
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
+ // `awm doctor` está documentado como «Read-only dashboard of machine + project harness
7
+ // state. **Changes nothing.**» — y escribía.
8
+ //
9
+ // `getPreferences()` auto-vivifica `preferences.json` con los defaults cuando el archivo
10
+ // no existe (`config.ts`: `if (!loaded.exists) savePreferences(DEFAULT_PREFS)`). Un
11
+ // getter con efecto de escritura escondido adentro. `doctor` lo llamaba para resolver a
12
+ // qué agentes mirar, así que en una máquina limpia el comando de inspección dejaba un
13
+ // `preferences.json` con `claude-code` como agente por defecto — que después se lee como
14
+ // «el usuario configuró esto» cuando no lo hizo.
15
+ //
16
+ // Lo encontró el playbook de aceptación en su segundo check, no la suite: ningún test
17
+ // preguntaba si un comando de lectura escribía. Se midieron los otros siete comandos de
18
+ // inspección (`list`, `preflight`, `sensors status`, `context-budget`, `backup list`,
19
+ // `ledger list`, `registry status`) y todos estaban limpios — así que acá el sitio ES la
20
+ // clase, con medición en vez de suposición.
21
+ const fs_1 = __importDefault(require("fs"));
22
+ const os_1 = __importDefault(require("os"));
23
+ const path_1 = __importDefault(require("path"));
24
+ describe('awm doctor no escribe nada', () => {
25
+ let home;
26
+ let projectRoot;
27
+ let saved;
28
+ let writeSpy;
29
+ beforeEach(() => {
30
+ home = fs_1.default.realpathSync(fs_1.default.mkdtempSync(path_1.default.join(os_1.default.tmpdir(), 'awm-doctor-ro-')));
31
+ saved = { HOME: process.env.HOME, AWM_HOME: process.env.AWM_HOME };
32
+ process.env.HOME = home;
33
+ process.env.AWM_HOME = path_1.default.join(home, '.awm');
34
+ projectRoot = path_1.default.join(home, 'proj');
35
+ fs_1.default.mkdirSync(path_1.default.join(projectRoot, '.git'), { recursive: true });
36
+ jest.resetModules();
37
+ writeSpy = jest.spyOn(process.stdout, 'write').mockImplementation(() => true);
38
+ });
39
+ afterEach(() => {
40
+ writeSpy.mockRestore();
41
+ if (saved.HOME === undefined)
42
+ delete process.env.HOME;
43
+ else
44
+ process.env.HOME = saved.HOME;
45
+ if (saved.AWM_HOME === undefined)
46
+ delete process.env.AWM_HOME;
47
+ else
48
+ process.env.AWM_HOME = saved.AWM_HOME;
49
+ fs_1.default.rmSync(home, { recursive: true, force: true });
50
+ });
51
+ /** Todo lo que exista bajo `home`, para comparar el antes y el después. */
52
+ const treeOf = (dir) => {
53
+ const out = [];
54
+ const walk = (sub) => {
55
+ for (const e of fs_1.default.readdirSync(path_1.default.join(dir, sub), { withFileTypes: true })) {
56
+ const rel = path_1.default.join(sub, e.name);
57
+ out.push(rel);
58
+ if (e.isDirectory())
59
+ walk(rel);
60
+ }
61
+ };
62
+ walk('.');
63
+ return out.sort();
64
+ };
65
+ it('no crea AWM_HOME ni preferences.json en una máquina limpia', () => {
66
+ const { runDoctor } = require('../../src/commands/doctor');
67
+ const before = treeOf(home);
68
+ runDoctor({ cwd: projectRoot, json: true });
69
+ expect(fs_1.default.existsSync(path_1.default.join(home, '.awm', 'preferences.json'))).toBe(false);
70
+ expect(treeOf(home)).toEqual(before);
71
+ });
72
+ it('tampoco escribe cuando ya hay preferencias', () => {
73
+ // El otro camino de `getPreferences`: el archivo existe. `migrationRequired`
74
+ // podía reescribirlo — sigue siendo una escritura desde un comando de lectura.
75
+ fs_1.default.mkdirSync(path_1.default.join(home, '.awm'), { recursive: true });
76
+ const prefsPath = path_1.default.join(home, '.awm', 'preferences.json');
77
+ fs_1.default.writeFileSync(prefsPath, JSON.stringify({
78
+ enabledAgents: ['claude-code'], defaultAgent: 'claude-code',
79
+ installMethod: 'symlink', defaultScope: 'global',
80
+ }));
81
+ const before = fs_1.default.readFileSync(prefsPath, 'utf-8');
82
+ const beforeTree = treeOf(home);
83
+ const { runDoctor } = require('../../src/commands/doctor');
84
+ runDoctor({ cwd: projectRoot, json: true });
85
+ expect(fs_1.default.readFileSync(prefsPath, 'utf-8')).toBe(before);
86
+ expect(treeOf(home)).toEqual(beforeTree);
87
+ });
88
+ it('sigue reportando sobre el agente por defecto sin archivo de preferencias', () => {
89
+ // No alcanza con no escribir: tiene que seguir funcionando. Sin preferencias,
90
+ // los defaults en memoria son la respuesta correcta.
91
+ const { runDoctor } = require('../../src/commands/doctor');
92
+ const code = runDoctor({ cwd: projectRoot, json: true });
93
+ expect([0, 1]).toContain(code); // 0 sano / 1 degradado, nunca 2 (error)
94
+ const emitted = writeSpy.mock.calls.map((c) => String(c[0])).join('');
95
+ expect(JSON.parse(emitted).providers.map((p) => p.id)).toEqual(['claude-code']);
96
+ });
97
+ });
@@ -11,7 +11,8 @@ const exec_wrapper_1 = require("../../../src/commands/job/exec-wrapper");
11
11
  const store_1 = require("../../../src/core/journal/store");
12
12
  const paths_1 = require("../../../src/core/journal/paths");
13
13
  const process_1 = require("../../../src/core/journal/process");
14
- // Presupuesto explicito, como sus tres hermanos de `tests/commands/watch/`
14
+ // Presupuesto explicito POR ENCIMA del global (30s en jest.config.js), como sus tres
15
+ // hermanos de `tests/commands/watch/`
15
16
  // (integration 30s, supervisor-loop 60s, e2e-crash 180s). Este archivo era el unico de
16
17
  // la familia sin uno, y hace el mismo trabajo que ellos: cada `collectAndReconcile`
17
18
  // consulta si el proceso sigue vivo, y en Windows eso spawnea `tasklist` — cientos de ms
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentic-workflow-manager",
3
- "version": "3.13.7",
3
+ "version": "4.0.1",
4
4
  "main": "dist/src/index.js",
5
5
  "bin": {
6
6
  "awm": "./dist/src/index.js"