agentic-workflow-manager 9.4.1 → 9.6.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.
- package/dist/src/commands/preflight/checks.js +58 -27
- package/dist/src/commands/sensors/bootstrap.js +171 -0
- package/dist/src/commands/sensors/compatibility/contract.js +18 -15
- package/dist/src/commands/sensors/compatibility/manifest.js +75 -2
- package/dist/src/commands/sensors/compatibility/materialize.js +256 -54
- package/dist/src/commands/sensors/compatibility/pack-source.js +61 -17
- package/dist/src/commands/sensors/compatibility/safe-file.js +286 -0
- package/dist/src/commands/sensors/compatibility/source.js +75 -0
- package/dist/src/commands/sensors/coverage/index.js +2 -2
- package/dist/src/commands/sensors/coverage/resolve.js +35 -29
- package/dist/src/commands/sensors/detection.js +31 -0
- package/dist/src/commands/sensors/exec.js +116 -11
- package/dist/src/commands/sensors/index.js +51 -10
- package/dist/src/commands/sensors/init.js +17 -168
- package/dist/src/commands/sensors/migrate.js +209 -0
- package/dist/src/commands/sensors/project.js +107 -0
- package/dist/src/commands/sensors/run.js +66 -47
- package/dist/src/commands/sensors/status.js +97 -56
- package/dist/src/core/init/steps.js +24 -11
- package/dist/src/core/secure-fs/native-bridge.js +209 -0
- package/dist/tests/commands/preflight/preflight.test.js +31 -0
- package/dist/tests/commands/sensors/bootstrap-observational.test.js +24 -0
- package/dist/tests/commands/sensors/bootstrap.test.js +175 -0
- package/dist/tests/commands/sensors/compatibility/contract.test.js +38 -0
- package/dist/tests/commands/sensors/compatibility/manifest.test.js +90 -0
- package/dist/tests/commands/sensors/compatibility/materialize.test.js +410 -0
- package/dist/tests/commands/sensors/compatibility/pack-source.test.js +249 -0
- package/dist/tests/commands/sensors/compatibility/safe-file.test.js +52 -0
- package/dist/tests/commands/sensors/compatibility/source.test.js +121 -0
- package/dist/tests/commands/sensors/coverage/index.test.js +20 -0
- package/dist/tests/commands/sensors/coverage/resolve.test.js +36 -34
- package/dist/tests/commands/sensors/exec.test.js +86 -0
- package/dist/tests/commands/sensors/index.test.js +54 -0
- package/dist/tests/commands/sensors/init-pack-unavailable.test.js +21 -84
- package/dist/tests/commands/sensors/init.test.js +56 -490
- package/dist/tests/commands/sensors/migrate.test.js +513 -0
- package/dist/tests/commands/sensors/project.test.js +102 -0
- package/dist/tests/commands/sensors/run.test.js +107 -4
- package/dist/tests/commands/sensors/status.test.js +106 -2
- package/dist/tests/core/init/orchestrator.test.js +3 -1
- package/dist/tests/core/secure-fs/native-bridge.test.js +733 -0
- package/dist/tests/integration/preflight-json-pipe.e2e.test.js +5 -0
- package/dist/tests/integration/sensor-bootstrap.e2e.test.js +165 -0
- package/dist/tests/integration/sensor-compatibility.e2e.test.js +14 -23
- package/dist/tests/integration/sensor-coverage.e2e.test.js +15 -24
- package/dist/tests/integration/sensor-structured-run.e2e.test.js +3 -1
- package/dist/tests/structural/native-release-artifacts.test.js +22 -0
- package/dist/tests/structural/release-flags-are-reachable-from-ci.test.js +10 -0
- package/dist/tests/structural/release-registry-provenance.test.js +4 -0
- package/dist/tests/structural/sensor-portability-contract.test.js +44 -0
- package/package.json +6 -2
- package/prebuilds/darwin-arm64/secure_fs.node +0 -0
- package/prebuilds/darwin-x64/secure_fs.node +0 -0
- package/prebuilds/linux-arm64/secure_fs.node +0 -0
- package/prebuilds/linux-x64/secure_fs.node +0 -0
- package/prebuilds/win32-arm64/secure_fs.node +0 -0
- package/prebuilds/win32-x64/secure_fs.node +0 -0
|
@@ -7,6 +7,7 @@ const fs_1 = __importDefault(require("fs"));
|
|
|
7
7
|
const os_1 = __importDefault(require("os"));
|
|
8
8
|
const path_1 = __importDefault(require("path"));
|
|
9
9
|
const run_1 = require("../../../src/commands/sensors/run");
|
|
10
|
+
const status_1 = require("../../../src/commands/sensors/status");
|
|
10
11
|
const verdict_1 = require("../../../src/commands/sensors/verdict");
|
|
11
12
|
function mkTmp() {
|
|
12
13
|
return fs_1.default.mkdtempSync(path_1.default.join(os_1.default.tmpdir(), 'awm-sensors-'));
|
|
@@ -14,10 +15,18 @@ function mkTmp() {
|
|
|
14
15
|
// Define stable mock before jest.mock hoisting
|
|
15
16
|
const mockRunCommand = jest.fn();
|
|
16
17
|
const mockRunStructuredCommand = jest.fn();
|
|
18
|
+
const mockResolveSensorProject = jest.fn((startCwd) => {
|
|
19
|
+
const actual = jest.requireActual('../../../src/commands/sensors/project');
|
|
20
|
+
return actual.resolveSensorProject(startCwd);
|
|
21
|
+
});
|
|
17
22
|
jest.mock('../../../src/commands/sensors/exec', () => ({
|
|
18
23
|
runCommand: (...args) => mockRunCommand(...args),
|
|
19
24
|
runStructuredCommand: (...args) => mockRunStructuredCommand(...args),
|
|
20
25
|
}));
|
|
26
|
+
jest.mock('../../../src/commands/sensors/project', () => {
|
|
27
|
+
const actual = jest.requireActual('../../../src/commands/sensors/project');
|
|
28
|
+
return { ...actual, resolveSensorProject: (startCwd) => mockResolveSensorProject(startCwd) };
|
|
29
|
+
});
|
|
21
30
|
const { ok, exited, timedOut } = require('./exec-fixtures');
|
|
22
31
|
const MANIFEST = {
|
|
23
32
|
pack: 'js-ts',
|
|
@@ -39,6 +48,7 @@ describe('runSensors', () => {
|
|
|
39
48
|
fs_1.default.writeFileSync(path.join(tmpDir, '.awm', 'sensors.json'), JSON.stringify(MANIFEST));
|
|
40
49
|
mockRunCommand.mockReset();
|
|
41
50
|
mockRunStructuredCommand.mockReset();
|
|
51
|
+
mockResolveSensorProject.mockClear();
|
|
42
52
|
});
|
|
43
53
|
afterEach(() => { fs_1.default.rmSync(tmpDir, { recursive: true }); });
|
|
44
54
|
const load = () => require('../../../src/commands/sensors/run');
|
|
@@ -282,6 +292,22 @@ describe('runSensors v2 lifecycle contract', () => {
|
|
|
282
292
|
expect(result).toEqual(expect.objectContaining({ overall: 'pass' }));
|
|
283
293
|
expect(mockRunStructuredCommand).toHaveBeenCalledWith(expect.objectContaining({ executable: 'live-eslint' }), expect.any(Object));
|
|
284
294
|
});
|
|
295
|
+
it('rebinds a missing v2 registryRoot through the unique configured source without mutation', async () => {
|
|
296
|
+
const manifestPath = path_1.default.join(project, '.awm', 'sensors.json');
|
|
297
|
+
const manifest = JSON.parse(fs_1.default.readFileSync(manifestPath, 'utf8'));
|
|
298
|
+
delete manifest.registryRoot;
|
|
299
|
+
fs_1.default.writeFileSync(manifestPath, JSON.stringify(manifest));
|
|
300
|
+
const before = fs_1.default.readFileSync(manifestPath, 'utf8');
|
|
301
|
+
const inventoryPath = path_1.default.join(home, 'registries.json');
|
|
302
|
+
const inventoryBefore = fs_1.default.readFileSync(inventoryPath, 'utf8');
|
|
303
|
+
const { runSensors } = require('../../../src/commands/sensors/run');
|
|
304
|
+
const result = await runSensors({ cwd: project, fast: true });
|
|
305
|
+
expect(result).toMatchObject({ overall: 'pass', mode: 'project-sensors', reason: 'legacy-rebound' });
|
|
306
|
+
expect(result.source).toMatchObject({ kind: 'legacy-rebound', registry: 'baseline' });
|
|
307
|
+
expect(mockRunStructuredCommand).toHaveBeenCalledWith(expect.objectContaining({ executable: 'live-eslint' }), expect.any(Object));
|
|
308
|
+
expect(fs_1.default.readFileSync(manifestPath, 'utf8')).toBe(before);
|
|
309
|
+
expect(fs_1.default.readFileSync(inventoryPath, 'utf8')).toBe(inventoryBefore);
|
|
310
|
+
});
|
|
285
311
|
it('scopes applicability detection and execution to packageRoot for a monorepo manifest', async () => {
|
|
286
312
|
// Move the fixture project into a subdirectory ("cli") and point the
|
|
287
313
|
// manifest at it via packageRoot — mirrors a monorepo where the
|
|
@@ -388,15 +414,92 @@ describe('runSensors — not_certified + auto-discovery', () => {
|
|
|
388
414
|
expect(out.overall).toBe('not_certified');
|
|
389
415
|
expect(out.sensors).toEqual([]);
|
|
390
416
|
});
|
|
391
|
-
it('
|
|
417
|
+
it('uses the same stable schema-unsupported reason as status', async () => {
|
|
418
|
+
tmpDir = mkTmp();
|
|
419
|
+
fs_1.default.mkdirSync(path_1.default.join(tmpDir, '.git'));
|
|
420
|
+
fs_1.default.mkdirSync(path_1.default.join(tmpDir, '.awm'));
|
|
421
|
+
fs_1.default.writeFileSync(path_1.default.join(tmpDir, '.awm', 'sensors.json'), JSON.stringify({ schemaVersion: 99 }));
|
|
422
|
+
const status = await (0, status_1.computeSensorStatus)(tmpDir);
|
|
423
|
+
const run = await (0, run_1.runSensors)({ cwd: tmpDir });
|
|
424
|
+
expect(status).toMatchObject({ mode: 'invalid', reason: 'schema-unsupported' });
|
|
425
|
+
expect(run).toMatchObject({ mode: 'invalid', reason: 'schema-unsupported' });
|
|
426
|
+
});
|
|
427
|
+
it('resolves the same legacy project and execution cwd from root and nested CWD', async () => {
|
|
392
428
|
tmpDir = mkTmp();
|
|
429
|
+
fs_1.default.mkdirSync(path_1.default.join(tmpDir, '.git'));
|
|
393
430
|
fs_1.default.mkdirSync(path_1.default.join(tmpDir, '.awm'));
|
|
394
431
|
fs_1.default.writeFileSync(path_1.default.join(tmpDir, '.awm', 'sensors.json'), JSON.stringify({ pack: 'test', sensors: { noop: { cmd: 'echo ok', fast: true } } }));
|
|
395
432
|
const nested = path_1.default.join(tmpDir, 'a', 'b');
|
|
396
433
|
fs_1.default.mkdirSync(nested, { recursive: true });
|
|
397
|
-
const
|
|
398
|
-
|
|
399
|
-
expect(
|
|
434
|
+
const rootRun = await (0, run_1.runSensors)({ cwd: tmpDir });
|
|
435
|
+
const nestedRun = await (0, run_1.runSensors)({ cwd: nested });
|
|
436
|
+
expect(nestedRun).toEqual(rootRun);
|
|
437
|
+
expect(rootRun.overall).toBe('not_certified');
|
|
438
|
+
expect(rootRun.sensors).toHaveLength(1);
|
|
439
|
+
expect(mockResolveSensorProject).toHaveBeenCalledWith(tmpDir);
|
|
440
|
+
expect(mockResolveSensorProject).toHaveBeenCalledWith(nested);
|
|
441
|
+
expect(mockRunCommand).toHaveBeenNthCalledWith(1, 'echo ok', expect.objectContaining({ cwd: tmpDir }));
|
|
442
|
+
expect(mockRunCommand).toHaveBeenNthCalledWith(2, 'echo ok', expect.objectContaining({ cwd: tmpDir }));
|
|
443
|
+
});
|
|
444
|
+
it.each([
|
|
445
|
+
['native-gate', 'Release-blocking CI is authoritative.'],
|
|
446
|
+
['opt-out', 'This repository intentionally has no local gate.'],
|
|
447
|
+
])('does not dispatch v3 %s declarations', async (mode, declarationReason) => {
|
|
448
|
+
tmpDir = mkTmp();
|
|
449
|
+
fs_1.default.mkdirSync(path_1.default.join(tmpDir, '.git'));
|
|
450
|
+
fs_1.default.mkdirSync(path_1.default.join(tmpDir, '.awm'), { recursive: true });
|
|
451
|
+
fs_1.default.writeFileSync(path_1.default.join(tmpDir, '.awm', 'sensors.json'), JSON.stringify({ schemaVersion: 3, mode, reason: declarationReason }));
|
|
452
|
+
const out = await (0, run_1.runSensors)({ cwd: tmpDir, all: true });
|
|
453
|
+
expect(out).toMatchObject({
|
|
454
|
+
overall: 'not_certified', mode, reason: `${mode}-declared`,
|
|
455
|
+
declarationReason,
|
|
456
|
+
projectRoot: tmpDir, manifestPath: path_1.default.join(tmpDir, '.awm', 'sensors.json'),
|
|
457
|
+
});
|
|
458
|
+
expect(out.sensors).toEqual([]);
|
|
459
|
+
expect(mockRunCommand).not.toHaveBeenCalled();
|
|
460
|
+
expect(mockRunStructuredCommand).not.toHaveBeenCalled();
|
|
461
|
+
});
|
|
462
|
+
it('reports bounded candidates and a remedy when v2 source resolution is ambiguous', async () => {
|
|
463
|
+
const previousHome = process.env.AWM_HOME;
|
|
464
|
+
const home = mkTmp();
|
|
465
|
+
try {
|
|
466
|
+
process.env.AWM_HOME = home;
|
|
467
|
+
const pack = {
|
|
468
|
+
schemaVersion: 2, name: 'js-ts', description: 'fixture', detects: ['package.json'],
|
|
469
|
+
coverage: { schemaVersion: 1, classes: { lint: { description: 'lint', detectors: [{ sensor: 'lint' }], remedy: { summary: 'fix', command: 'awm sensors init' } } } },
|
|
470
|
+
sensors: { lint: { applicability: { allFiles: ['package.json'] }, variants: [{
|
|
471
|
+
id: 'eslint-10', priority: 1, certifiedRange: '>=10 <11',
|
|
472
|
+
requirements: { tool: 'eslint', toolRange: '>=10 <11', runtime: 'node', runtimeRange: '>=0' },
|
|
473
|
+
assets: [], formatter: 'generic', probe: { kind: 'package-script-present' },
|
|
474
|
+
command: { executable: 'eslint', resolution: 'node-modules-bin', args: ['.'] },
|
|
475
|
+
}] } },
|
|
476
|
+
};
|
|
477
|
+
const registries = ['alpha', 'beta'];
|
|
478
|
+
fs_1.default.writeFileSync(path_1.default.join(home, 'registries.json'), JSON.stringify(registries.map(name => ({ name, remote: `https://example.test/${name}.git` }))));
|
|
479
|
+
for (const name of registries) {
|
|
480
|
+
const packDir = path_1.default.join(home, 'registries', name, 'sensor-packs', 'js-ts');
|
|
481
|
+
fs_1.default.mkdirSync(packDir, { recursive: true });
|
|
482
|
+
fs_1.default.writeFileSync(path_1.default.join(packDir, 'pack.json'), JSON.stringify(pack));
|
|
483
|
+
}
|
|
484
|
+
tmpDir = mkTmp();
|
|
485
|
+
fs_1.default.mkdirSync(path_1.default.join(tmpDir, '.git'));
|
|
486
|
+
fs_1.default.mkdirSync(path_1.default.join(tmpDir, '.awm'), { recursive: true });
|
|
487
|
+
fs_1.default.writeFileSync(path_1.default.join(tmpDir, '.awm', 'sensors.json'), JSON.stringify({ schemaVersion: 2, pack: 'js-ts', sensors: {} }));
|
|
488
|
+
const out = await (0, run_1.runSensors)({ cwd: tmpDir });
|
|
489
|
+
expect(out).toMatchObject({
|
|
490
|
+
overall: 'not_certified', mode: 'source-ambiguous', reason: 'multiple-compatible-registries',
|
|
491
|
+
remedy: 'configure-one-logical-registry',
|
|
492
|
+
source: { kind: 'source-ambiguous', candidates: ['alpha', 'beta'] },
|
|
493
|
+
});
|
|
494
|
+
expect(out.source.candidates).toHaveLength(2);
|
|
495
|
+
}
|
|
496
|
+
finally {
|
|
497
|
+
if (previousHome === undefined)
|
|
498
|
+
delete process.env.AWM_HOME;
|
|
499
|
+
else
|
|
500
|
+
process.env.AWM_HOME = previousHome;
|
|
501
|
+
fs_1.default.rmSync(home, { recursive: true, force: true });
|
|
502
|
+
}
|
|
400
503
|
});
|
|
401
504
|
});
|
|
402
505
|
describe('detectPackDrift', () => {
|
|
@@ -46,6 +46,26 @@ describe('computeSensorStatus', () => {
|
|
|
46
46
|
expect(result.overall).toBe('NOT_CONFIGURED');
|
|
47
47
|
expect(result.pack).toBeNull();
|
|
48
48
|
});
|
|
49
|
+
it('resolves the Git-bounded project manifest from a nested CWD', async () => {
|
|
50
|
+
fs_1.default.mkdirSync(path_1.default.join(tmpDir, '.git'));
|
|
51
|
+
fs_1.default.mkdirSync(path_1.default.join(tmpDir, '.awm'), { recursive: true });
|
|
52
|
+
fs_1.default.mkdirSync(path_1.default.join(tmpDir, 'node_modules', '.bin'), { recursive: true });
|
|
53
|
+
fs_1.default.writeFileSync(path_1.default.join(tmpDir, 'node_modules', '.bin', 'tsc'), '');
|
|
54
|
+
fs_1.default.writeFileSync(path_1.default.join(tmpDir, '.awm', 'sensors.json'), JSON.stringify({
|
|
55
|
+
pack: 'js-ts', sensors: { typecheck: { cmd: 'npx tsc --noEmit', fast: true } },
|
|
56
|
+
}));
|
|
57
|
+
const nestedCwd = path_1.default.join(tmpDir, 'packages', 'app');
|
|
58
|
+
fs_1.default.mkdirSync(nestedCwd, { recursive: true });
|
|
59
|
+
await expect((0, status_1.computeSensorStatus)(nestedCwd)).resolves.toMatchObject({
|
|
60
|
+
overall: 'READY',
|
|
61
|
+
pack: 'js-ts',
|
|
62
|
+
mode: 'project-sensors',
|
|
63
|
+
reason: 'legacy-v1',
|
|
64
|
+
projectRoot: tmpDir,
|
|
65
|
+
manifestPath: path_1.default.join(tmpDir, '.awm', 'sensors.json'),
|
|
66
|
+
checks: { typecheck: { ok: true } },
|
|
67
|
+
});
|
|
68
|
+
});
|
|
49
69
|
it.each([
|
|
50
70
|
['valid manifest', 'READY', () => {
|
|
51
71
|
installLocalBin('eslint');
|
|
@@ -218,17 +238,24 @@ describe('computeSensorStatus', () => {
|
|
|
218
238
|
fs_1.default.writeFileSync(path_1.default.join(packageDir, 'node_modules', '.bin', 'eslint'), '');
|
|
219
239
|
fs_1.default.writeFileSync(path_1.default.join(packageDir, 'eslint.config.awm.mjs'), 'export default []');
|
|
220
240
|
fs_1.default.mkdirSync(path_1.default.join(tmpDir, '.awm'), { recursive: true });
|
|
221
|
-
|
|
222
|
-
|
|
241
|
+
const manifestPath = path_1.default.join(tmpDir, '.awm', 'sensors.json');
|
|
242
|
+
fs_1.default.writeFileSync(manifestPath, JSON.stringify({
|
|
243
|
+
schemaVersion: 2, pack: 'js-ts', packageRoot: 'cli',
|
|
223
244
|
sensors: { lint: {
|
|
224
245
|
enabled: true, variantId: 'eslint-10', command: { executable: 'eslint', resolution: 'node-modules-bin', args: ['.', '--config', 'eslint.config.awm.mjs'] },
|
|
225
246
|
assets: ['eslint.config.awm.mjs'],
|
|
226
247
|
initializedCompatibility: { state: 'certified', reason: 'range-and-probe', variantId: 'eslint-10', toolVersion: '10.4.1', runtimeVersion: process.versions.node, certifiedRange: '>=10.0.0 <11.0.0', evidence: [] },
|
|
227
248
|
} },
|
|
228
249
|
}));
|
|
250
|
+
const manifestBefore = fs_1.default.readFileSync(manifestPath);
|
|
251
|
+
const inventoryPath = path_1.default.join(home, 'registries.json');
|
|
252
|
+
const inventoryBefore = fs_1.default.readFileSync(inventoryPath);
|
|
229
253
|
const result = await (0, status_1.computeSensorStatus)(tmpDir);
|
|
230
254
|
expect(result.checks.lint).toMatchObject({ ok: true });
|
|
231
255
|
expect(result.overall).toBe('READY');
|
|
256
|
+
expect(result.source).toMatchObject({ kind: 'legacy-rebound', registry: 'baseline' });
|
|
257
|
+
expect(fs_1.default.readFileSync(manifestPath)).toEqual(manifestBefore);
|
|
258
|
+
expect(fs_1.default.readFileSync(inventoryPath)).toEqual(inventoryBefore);
|
|
232
259
|
expect(runCommand).not.toHaveBeenCalled();
|
|
233
260
|
expect(runStructuredCommand).not.toHaveBeenCalled();
|
|
234
261
|
}
|
|
@@ -304,4 +331,81 @@ describe('computeSensorStatus', () => {
|
|
|
304
331
|
fs_1.default.rmSync(home, { recursive: true, force: true });
|
|
305
332
|
}
|
|
306
333
|
});
|
|
334
|
+
it.each([
|
|
335
|
+
['native-gate', 'Release-blocking CI is authoritative.', 'native-gate-declared'],
|
|
336
|
+
['opt-out', 'This repository intentionally has no local gate.', 'opt-out-declared'],
|
|
337
|
+
])('reports v3 %s without dispatching sensors', async (mode, declarationReason, diagnosticReason) => {
|
|
338
|
+
fs_1.default.mkdirSync(path_1.default.join(tmpDir, '.git'));
|
|
339
|
+
fs_1.default.mkdirSync(path_1.default.join(tmpDir, '.awm'), { recursive: true });
|
|
340
|
+
fs_1.default.writeFileSync(path_1.default.join(tmpDir, '.awm', 'sensors.json'), JSON.stringify({ schemaVersion: 3, mode, reason: declarationReason }));
|
|
341
|
+
await expect((0, status_1.computeSensorStatus)(tmpDir)).resolves.toMatchObject({
|
|
342
|
+
overall: 'NOT_CONFIGURED', mode, reason: diagnosticReason,
|
|
343
|
+
declarationReason,
|
|
344
|
+
projectRoot: tmpDir, manifestPath: path_1.default.join(tmpDir, '.awm', 'sensors.json'),
|
|
345
|
+
});
|
|
346
|
+
expect(runCommand).not.toHaveBeenCalled();
|
|
347
|
+
expect(runStructuredCommand).not.toHaveBeenCalled();
|
|
348
|
+
});
|
|
349
|
+
it('reports a v2 source-unavailable state instead of accepting a missing pack', async () => {
|
|
350
|
+
const previousHome = process.env.AWM_HOME;
|
|
351
|
+
const home = fs_1.default.mkdtempSync(path_1.default.join(os_1.default.tmpdir(), 'awm-status-missing-source-home-'));
|
|
352
|
+
try {
|
|
353
|
+
process.env.AWM_HOME = home;
|
|
354
|
+
fs_1.default.writeFileSync(path_1.default.join(home, 'registries.json'), JSON.stringify([]));
|
|
355
|
+
fs_1.default.mkdirSync(path_1.default.join(tmpDir, '.awm'), { recursive: true });
|
|
356
|
+
fs_1.default.writeFileSync(path_1.default.join(tmpDir, '.awm', 'sensors.json'), JSON.stringify({
|
|
357
|
+
schemaVersion: 2, pack: 'js-ts', registryRoot: path_1.default.join(home, 'gone'), sensors: {},
|
|
358
|
+
}));
|
|
359
|
+
await expect((0, status_1.computeSensorStatus)(tmpDir)).resolves.toMatchObject({
|
|
360
|
+
overall: 'DEGRADED', pack: 'js-ts', mode: 'source-unavailable',
|
|
361
|
+
reason: 'no-compatible-registry', remedy: 'install-registry-or-run-awm-update',
|
|
362
|
+
projectRoot: tmpDir, manifestPath: path_1.default.join(tmpDir, '.awm', 'sensors.json'),
|
|
363
|
+
});
|
|
364
|
+
}
|
|
365
|
+
finally {
|
|
366
|
+
if (previousHome === undefined)
|
|
367
|
+
delete process.env.AWM_HOME;
|
|
368
|
+
else
|
|
369
|
+
process.env.AWM_HOME = previousHome;
|
|
370
|
+
fs_1.default.rmSync(home, { recursive: true, force: true });
|
|
371
|
+
}
|
|
372
|
+
});
|
|
373
|
+
it('reports bounded candidates and a remedy when v2 source resolution is ambiguous', async () => {
|
|
374
|
+
const previousHome = process.env.AWM_HOME;
|
|
375
|
+
const home = fs_1.default.mkdtempSync(path_1.default.join(os_1.default.tmpdir(), 'awm-status-ambiguous-home-'));
|
|
376
|
+
try {
|
|
377
|
+
process.env.AWM_HOME = home;
|
|
378
|
+
const pack = {
|
|
379
|
+
schemaVersion: 2, name: 'js-ts', description: 'fixture', detects: ['package.json'],
|
|
380
|
+
coverage: { schemaVersion: 1, classes: { lint: { description: 'lint', detectors: [{ sensor: 'lint' }], remedy: { summary: 'fix', command: 'awm sensors init' } } } },
|
|
381
|
+
sensors: { lint: { applicability: { allFiles: ['package.json'] }, variants: [{
|
|
382
|
+
id: 'eslint-10', priority: 1, certifiedRange: '>=10 <11',
|
|
383
|
+
requirements: { tool: 'eslint', toolRange: '>=10 <11', runtime: 'node', runtimeRange: '>=0' },
|
|
384
|
+
assets: [], formatter: 'generic', probe: { kind: 'package-script-present' },
|
|
385
|
+
command: { executable: 'eslint', resolution: 'node-modules-bin', args: ['.'] },
|
|
386
|
+
}] } },
|
|
387
|
+
};
|
|
388
|
+
const registries = ['alpha', 'beta'];
|
|
389
|
+
fs_1.default.writeFileSync(path_1.default.join(home, 'registries.json'), JSON.stringify(registries.map(name => ({ name, remote: `https://example.test/${name}.git` }))));
|
|
390
|
+
for (const name of registries) {
|
|
391
|
+
const packDir = path_1.default.join(home, 'registries', name, 'sensor-packs', 'js-ts');
|
|
392
|
+
fs_1.default.mkdirSync(packDir, { recursive: true });
|
|
393
|
+
fs_1.default.writeFileSync(path_1.default.join(packDir, 'pack.json'), JSON.stringify(pack));
|
|
394
|
+
}
|
|
395
|
+
fs_1.default.mkdirSync(path_1.default.join(tmpDir, '.git'));
|
|
396
|
+
fs_1.default.mkdirSync(path_1.default.join(tmpDir, '.awm'), { recursive: true });
|
|
397
|
+
fs_1.default.writeFileSync(path_1.default.join(tmpDir, '.awm', 'sensors.json'), JSON.stringify({ schemaVersion: 2, pack: 'js-ts', sensors: {} }));
|
|
398
|
+
await expect((0, status_1.computeSensorStatus)(tmpDir)).resolves.toMatchObject({
|
|
399
|
+
overall: 'DEGRADED', mode: 'source-ambiguous', reason: 'multiple-compatible-registries',
|
|
400
|
+
remedy: 'configure-one-logical-registry', candidates: ['alpha', 'beta'],
|
|
401
|
+
});
|
|
402
|
+
}
|
|
403
|
+
finally {
|
|
404
|
+
if (previousHome === undefined)
|
|
405
|
+
delete process.env.AWM_HOME;
|
|
406
|
+
else
|
|
407
|
+
process.env.AWM_HOME = previousHome;
|
|
408
|
+
fs_1.default.rmSync(home, { recursive: true, force: true });
|
|
409
|
+
}
|
|
410
|
+
});
|
|
307
411
|
});
|
|
@@ -135,7 +135,9 @@ describe('runInitSteps — orchestrator', () => {
|
|
|
135
135
|
const deps = buildDeps(root);
|
|
136
136
|
const { runInitSteps } = require('../../../src/core/init/orchestrator');
|
|
137
137
|
const out = await runInitSteps(deps);
|
|
138
|
-
|
|
138
|
+
// The sensor step is always represented; whether this fixture's pack is
|
|
139
|
+
// portable is orthogonal to activation/constitution orchestration.
|
|
140
|
+
expect(out.steps.some((s) => s.id === 'project.sensors')).toBe(true);
|
|
139
141
|
expect(out.steps.find((s) => s.id === 'project.constitution').action).toBe('pending');
|
|
140
142
|
expect(out.steps.find((s) => s.id === 'project.context').action).toBe('pending');
|
|
141
143
|
});
|