agentic-workflow-manager 6.2.0 → 6.2.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.
@@ -124,20 +124,24 @@ function skillsGlobalCheck(dir, owners, integrity, renderer, artifacts) {
124
124
  // generados NO: quedan con el contenido de la version anterior hasta que alguien
125
125
  // corra `awm sync`, y hasta ahora nada lo decia.
126
126
  const stale = staleRendered(dir, artifacts);
127
+ const names = stale.map((r) => path_1.default.basename(r.targetPath));
127
128
  return {
128
129
  id: 'skills.global',
129
130
  state: stale.length > 0 ? 'stale' : 'supported',
130
131
  target: dir,
131
132
  owners: owners.length > 1 ? owners : undefined,
132
133
  detail: stale.length > 0
133
- ? `${stale.length} rendered file(s) no longer match the installed registry (${stale.slice(0, 3).join(', ')})`
134
+ ? `${stale.length} rendered file(s) no longer match the installed registry (${names.slice(0, 3).join(', ')})`
135
+ : undefined,
136
+ // El remedio depende del ALCANCE, y se midio cual funciona en cada uno:
137
+ // `awm update` reconcilia los artefactos de maquina, `awm sync` los que el
138
+ // profile del proyecto declara. Ofrecer el equivocado seria mandar al usuario
139
+ // a un comando que corre limpio sin cambiar nada — el defecto que ya tuvo
140
+ // `open-hooks-trust` (D-010), y que la primera version de ESTE chequeo
141
+ // repitio: ofrecia `reinstall-bundle` porque dos mediciones mias estaban mal.
142
+ remediationCode: stale.length > 0
143
+ ? (stale.some((r) => r.scope === 'local') ? 'awm-sync' : 'awm-update')
134
144
  : undefined,
135
- // `reinstall-bundle`, y NO `awm-sync` ni `awm-init`: se midio cual de los
136
- // cuatro comandos refresca de verdad un renderizado viejo, y solo `awm add`
137
- // lo hace. `init` y `sync` son idempotentes por presencia —ven el archivo y
138
- // no lo tocan— y `update` refresca el registry, no lo derivado de el. Ofrecer
139
- // un remedio que corre limpio sin cambiar nada es peor que no ofrecer ninguno.
140
- remediationCode: stale.length > 0 ? 'reinstall-bundle' : undefined,
141
145
  };
142
146
  }
143
147
  const shared = owners.length > 1;
@@ -213,8 +217,7 @@ function staleRendered(dir, records) {
213
217
  // corresponden. Aca "no puedo comparar" no se convierte en "esta viejo".
214
218
  return false;
215
219
  }
216
- })
217
- .map((r) => path_1.default.basename(r.targetPath));
220
+ });
218
221
  }
219
222
  function corruptRendered(dir, files, renderer) {
220
223
  const marker = (0, registry_1.rendererIntegrityMarker)(renderer);
@@ -154,5 +154,19 @@ function ensureSkillsGitignored(root, agents) {
154
154
  * project extensions and stay out of `.awm/profile.json`.
155
155
  */
156
156
  function shouldRecordExtension(bundleScope, effective) {
157
- return bundleScope === 'project' && effective === 'local';
157
+ // El criterio es el ALCANCE EFECTIVO, no el del bundle.
158
+ //
159
+ // Antes exigia ademas `bundleScope === 'project'`, asi que un bundle baseline
160
+ // instalado explicitamente con `--scope local` no quedaba registrado en ningun lado:
161
+ // `awm sync` reconcilia lo que declara el profile, y esos artefactos no estaban ahi.
162
+ // Resultado: nadie los refrescaba nunca. `update` cubre lo global y `sync` lo del
163
+ // profile; eso caia en el medio.
164
+ //
165
+ // Y no es un caso raro: `awm add dev --scope local` es exactamente lo que el playbook
166
+ // de aceptacion (AG-03) le pide correr a cualquiera que verifique un proveedor.
167
+ //
168
+ // Si alguien pidio artefactos de proyecto, el profile lo dice — que es lo que hace
169
+ // que un companero que clona el repo y corre `awm sync` obtenga lo mismo.
170
+ void bundleScope;
171
+ return effective === 'local';
158
172
  }
@@ -83,7 +83,11 @@ function maybeNotifyUpdate(opts) {
83
83
  const spawnWorker = opts?.spawnWorker ?? spawnRefreshWorker;
84
84
  const cache = readUpdateCache();
85
85
  if (cache?.latest && isNewer(cache.latest, (0, cli_version_1.cliVersion)())) {
86
- console.log(picocolors_1.default.dim(`\n⬆ awm v${cache.latest} available npm i -g ${cli_version_1.CLI_PACKAGE_NAME}`));
86
+ // stderr, NO stdout. Este aviso se imprime al final de CUALQUIER comando, asi
87
+ // que en stdout se mezclaba con la salida de `--json` y rompia a cualquiera que
88
+ // parsee: `awm doctor --json | jq` fallaba con un SyntaxError que no menciona la
89
+ // causa. stdout es la interfaz de maquina; los avisos al humano van por stderr.
90
+ process.stderr.write(picocolors_1.default.dim(`\n⬆ awm v${cache.latest} available → npm i -g ${cli_version_1.CLI_PACKAGE_NAME}\n`));
87
91
  }
88
92
  if (!cache || now - cache.lastCheck > TTL_MS)
89
93
  spawnWorker();
@@ -277,9 +277,9 @@ describe('skillsGlobalCheck — renderer-aware (Task 4.4 / deferred Task 4.3 fin
277
277
  .checks.find((c) => c.id === 'skills.global');
278
278
  expect(stale?.state).toBe('stale');
279
279
  expect(stale?.detail).toContain('using-awm.mdc');
280
- // Medido, no supuesto: de `init`/`update`/`sync`/`add`, solo `add` refresca un
281
- // renderizado viejo. Los otros tres corren limpios y no cambian nada.
282
- expect(stale?.remediationCode).toBe('reinstall-bundle');
280
+ // El remedio depende del alcance, y se midio: `awm update` reconcilia los
281
+ // artefactos de maquina; `awm sync`, los que declara el profile del proyecto.
282
+ expect(stale?.remediationCode).toBe('awm-update');
283
283
  fs_1.default.rmSync(source, { recursive: true, force: true });
284
284
  });
285
285
  it('non-link renderer with an empty/missing dir reports absent, not a false healthy', () => {
@@ -100,11 +100,18 @@ describe('ensureSkillsGitignored', () => {
100
100
  });
101
101
  });
102
102
  describe('shouldRecordExtension', () => {
103
- it('records only project-scope bundles installed locally', () => {
103
+ it('no registra nada instalado a nivel maquina, sea cual sea el bundle', () => {
104
104
  expect((0, profile_1.shouldRecordExtension)('project', 'local')).toBe(true);
105
105
  expect((0, profile_1.shouldRecordExtension)('project', 'global')).toBe(false);
106
106
  expect((0, profile_1.shouldRecordExtension)('baseline', 'global')).toBe(false);
107
- expect((0, profile_1.shouldRecordExtension)('baseline', 'local')).toBe(false);
108
107
  expect((0, profile_1.shouldRecordExtension)('ambient', 'global')).toBe(false);
109
108
  });
109
+ it('records a BASELINE bundle too when it was installed with --scope local', () => {
110
+ // Antes devolvia false, y esos artefactos quedaban fuera del profile: `awm sync`
111
+ // reconcilia lo que el profile declara, asi que nadie los refrescaba nunca —
112
+ // `update` cubre lo global y esto caia en el medio. No es un caso raro:
113
+ // `awm add dev --scope local` es lo que el playbook AG-03 pide correr.
114
+ expect((0, profile_1.shouldRecordExtension)('baseline', 'local')).toBe(true);
115
+ expect((0, profile_1.shouldRecordExtension)('ambient', 'local')).toBe(true);
116
+ });
110
117
  });
@@ -59,12 +59,14 @@ describe('update-check', () => {
59
59
  it('maybeNotifyUpdate avisa si el cache trae versión más nueva y NO refresca cache fresco', () => {
60
60
  const m = require('../../src/core/update-check');
61
61
  m.writeUpdateCache({ lastCheck: 1_000_000, latest: '99.0.0' });
62
- const log = jest.spyOn(console, 'log').mockImplementation(() => { });
62
+ // stderr, no stdout: el aviso sale al final de cualquier comando y en stdout
63
+ // rompia la salida de `--json`.
64
+ const err = jest.spyOn(process.stderr, 'write').mockImplementation(() => true);
63
65
  const spawnWorker = jest.fn();
64
66
  m.maybeNotifyUpdate({ now: 1_000_000 + 1000, spawnWorker });
65
- expect(log.mock.calls.flat().join('\n')).toContain('99.0.0');
67
+ expect(err.mock.calls.flat().join('\n')).toContain('99.0.0');
66
68
  expect(spawnWorker).not.toHaveBeenCalled();
67
- log.mockRestore();
69
+ err.mockRestore();
68
70
  });
69
71
  it('cache viejo (>24h) dispara refresh en background', () => {
70
72
  const m = require('../../src/core/update-check');
@@ -104,3 +106,32 @@ describe('update-check', () => {
104
106
  expect(cache.lastCheck).toBeGreaterThan(0);
105
107
  });
106
108
  });
109
+ // El aviso de version nueva va por stderr, no por stdout.
110
+ //
111
+ // Se imprime al final de CUALQUIER comando, asi que en stdout se mezclaba con la salida
112
+ // de `--json` y rompia a cualquiera que parsee. Encontrado tropezando con el:
113
+ // `awm doctor --json | node -e 'JSON.parse(...)'` fallaba con un SyntaxError que no
114
+ // menciona la causa. stdout es la interfaz de maquina.
115
+ describe('the update banner never contaminates stdout', () => {
116
+ it('writes to stderr so `--json` output stays parseable', () => {
117
+ const stdout = jest.spyOn(process.stdout, 'write').mockImplementation(() => true);
118
+ const stderr = jest.spyOn(process.stderr, 'write').mockImplementation(() => true);
119
+ const log = jest.spyOn(console, 'log').mockImplementation(() => { });
120
+ try {
121
+ const { maybeNotifyUpdate } = require('../../src/core/update-check');
122
+ maybeNotifyUpdate({ spawnWorker: () => { } });
123
+ const onStdout = stdout.mock.calls.map((c) => String(c[0])).join('')
124
+ + log.mock.calls.map((c) => String(c[0])).join('');
125
+ expect(onStdout).not.toContain('available');
126
+ // Y si habia aviso, salio por stderr — no se perdio, se movio.
127
+ const emitted = stderr.mock.calls.map((c) => String(c[0])).join('');
128
+ if (emitted.length > 0)
129
+ expect(emitted).toContain('available');
130
+ }
131
+ finally {
132
+ stdout.mockRestore();
133
+ stderr.mockRestore();
134
+ log.mockRestore();
135
+ }
136
+ });
137
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentic-workflow-manager",
3
- "version": "6.2.0",
3
+ "version": "6.2.1",
4
4
  "main": "dist/src/index.js",
5
5
  "bin": {
6
6
  "awm": "./dist/src/index.js"