agentic-workflow-manager 9.7.1 → 9.9.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/README.md +5 -1
- package/dist/src/commands/job/exec-wrapper.js +53 -3
- package/dist/src/commands/job/gate.js +18 -0
- package/dist/src/commands/job/index.js +61 -0
- package/dist/src/commands/model-policy/index.js +73 -0
- package/dist/src/commands/plan/index.js +182 -7
- package/dist/src/commands/sensors/bootstrap.js +36 -5
- package/dist/src/commands/sensors/compatibility/contract.js +19 -4
- package/dist/src/commands/sensors/compatibility/discovery.js +23 -3
- package/dist/src/commands/sensors/compatibility/live.js +18 -1
- package/dist/src/commands/sensors/compatibility/probe.js +8 -2
- package/dist/src/commands/sensors/compatibility/resolve.js +5 -2
- package/dist/src/commands/sensors/coverage/evidence.js +19 -10
- package/dist/src/commands/sensors/coverage/index.js +11 -2
- package/dist/src/commands/sensors/coverage/resolve.js +10 -0
- package/dist/src/commands/sensors/exec.js +16 -1
- package/dist/src/commands/sensors/migrate.js +62 -2
- package/dist/src/commands/sensors/prepare.js +2 -0
- package/dist/src/commands/sensors/result.js +2 -0
- package/dist/src/commands/sensors/run.js +64 -1
- package/dist/src/commands/sensors/status.js +6 -4
- package/dist/src/commands/watch/apply.js +32 -0
- package/dist/src/commands/watch/archive-unused.js +138 -0
- package/dist/src/commands/watch/generations.js +32 -9
- package/dist/src/commands/watch/index.js +108 -2
- package/dist/src/commands/watch/init.js +149 -18
- package/dist/src/commands/watch/supervisor.js +167 -13
- package/dist/src/commands/watch/teardown-driver.js +13 -13
- package/dist/src/commands/watch/track-state.js +59 -0
- package/dist/src/commands/watch/tracks.js +38 -102
- package/dist/src/core/admission/index.js +231 -0
- package/dist/src/core/admission/registry-contracts.js +290 -0
- package/dist/src/core/journal/fingerprint.js +35 -1
- package/dist/src/core/journal/paths.js +11 -0
- package/dist/src/core/journal/requests.js +1 -1
- package/dist/src/core/journal/store.js +146 -4
- package/dist/src/core/journal/types.js +57 -2
- package/dist/src/core/migration/historical-provenance.js +18 -0
- package/dist/src/core/migration/index.js +322 -0
- package/dist/src/core/model-policy/canonical.js +18 -0
- package/dist/src/core/model-policy/capabilities.js +197 -0
- package/dist/src/core/model-policy/capability-types.js +2 -0
- package/dist/src/core/model-policy/journal.js +124 -0
- package/dist/src/core/model-policy/paths.js +12 -0
- package/dist/src/core/model-policy/resolve.js +116 -0
- package/dist/src/core/model-policy/store.js +182 -0
- package/dist/src/core/model-policy/types.js +2 -0
- package/dist/src/core/model-policy/validate.js +112 -0
- package/dist/src/core/plan/identity.js +77 -0
- package/dist/src/core/plan/validate.js +191 -78
- package/dist/src/index.js +2 -0
- package/dist/tests/commands/job/exec-wrapper.test.js +16 -0
- package/dist/tests/commands/job/gate-reconcile.test.js +40 -10
- package/dist/tests/commands/job/gate.test.js +9 -0
- package/dist/tests/commands/job/routing-report-cli.test.js +46 -0
- package/dist/tests/commands/job/routing.test.js +11 -0
- package/dist/tests/commands/model-policy/index.test.js +57 -0
- package/dist/tests/commands/pin.test.js +23 -23
- package/dist/tests/commands/plan/index.test.js +682 -14
- package/dist/tests/commands/sensors/bootstrap.test.js +57 -4
- package/dist/tests/commands/sensors/compatibility/contract.test.js +21 -0
- package/dist/tests/commands/sensors/compatibility/discovery.test.js +19 -0
- package/dist/tests/commands/sensors/compatibility/probe.test.js +14 -1
- package/dist/tests/commands/sensors/compatibility/resolve.test.js +17 -0
- package/dist/tests/commands/sensors/coverage/evidence.test.js +51 -27
- package/dist/tests/commands/sensors/coverage/resolve.test.js +51 -0
- package/dist/tests/commands/sensors/exec.test.js +112 -0
- package/dist/tests/commands/sensors/run-changed.test.js +11 -0
- package/dist/tests/commands/sensors/run.test.js +15 -2
- package/dist/tests/commands/sensors/status.test.js +3 -3
- package/dist/tests/commands/watch/apply.test.js +12 -0
- package/dist/tests/commands/watch/e2e-crash.test.js +126 -11
- package/dist/tests/commands/watch/generations.test.js +113 -4
- package/dist/tests/commands/watch/plan-lifecycle.test.js +263 -0
- package/dist/tests/commands/watch/supervisor-loop.test.js +247 -49
- package/dist/tests/commands/watch/track-finalize.test.js +20 -3
- package/dist/tests/commands/watch/track-freeze.test.js +43 -30
- package/dist/tests/commands/watch/track-state-dependency.test.js +15 -0
- package/dist/tests/commands/watch/watch-init.test.js +244 -0
- package/dist/tests/core/admission/index.test.js +140 -0
- package/dist/tests/core/journal/fingerprint.test.js +22 -0
- package/dist/tests/core/journal/store.test.js +53 -0
- package/dist/tests/core/journal/types.test.js +7 -0
- package/dist/tests/core/migration/facts.test.js +289 -0
- package/dist/tests/core/migration/historical-provenance.test.js +25 -0
- package/dist/tests/core/model-policy/capabilities.test.js +365 -0
- package/dist/tests/core/model-policy/journal.test.js +46 -0
- package/dist/tests/core/model-policy/policy.test.js +47 -0
- package/dist/tests/core/model-policy/resolve.test.js +111 -0
- package/dist/tests/core/model-policy/store.test.js +177 -0
- package/dist/tests/core/plan/validate.test.js +360 -8
- package/dist/tests/core/secure-fs/native-bridge.test.js +81 -4
- package/dist/tests/integration/pack-e2e.test.js +4 -1
- package/dist/tests/integration/preflight-json-pipe.e2e.test.js +7 -3
- package/dist/tests/integration/sensor-bootstrap.e2e.test.js +37 -0
- package/dist/tests/integration/sensor-structured-run.e2e.test.js +12 -10
- package/dist/tests/providers/injection-config.test.js +14 -6
- package/dist/tests/structural/directory-fsync-is-single-source.test.js +97 -0
- package/dist/tests/structural/jest-environment-is-isolated.test.js +29 -24
- package/dist/tests/structural/native-release-artifacts.test.js +30 -0
- package/package.json +4 -3
- 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
|
@@ -13,6 +13,8 @@ const reconcile_1 = require("../../../src/commands/job/reconcile");
|
|
|
13
13
|
const reap_1 = require("../../../src/commands/job/reap");
|
|
14
14
|
const job_1 = require("../../../src/commands/job");
|
|
15
15
|
const watch_1 = require("../../../src/commands/watch");
|
|
16
|
+
const init_1 = require("../../../src/commands/watch/init");
|
|
17
|
+
const validate_1 = require("../../../src/core/plan/validate");
|
|
16
18
|
const types_1 = require("../../../src/core/journal/types");
|
|
17
19
|
const store_1 = require("../../../src/core/journal/store");
|
|
18
20
|
const descriptor_1 = require("../../../src/core/tracks/descriptor");
|
|
@@ -53,6 +55,22 @@ function passingState() {
|
|
|
53
55
|
return s;
|
|
54
56
|
}
|
|
55
57
|
describe('gate', () => {
|
|
58
|
+
test('un verdict routed exige intento observado, identidad y fingerprint coincidentes', () => {
|
|
59
|
+
const s = passingState();
|
|
60
|
+
s.verdicts[0] = { ...s.verdicts[0], routingAttemptId: 'route-1' };
|
|
61
|
+
let gate = (0, gate_1.computeGate)(s, false, fpCurrent);
|
|
62
|
+
expect(gate.reasons.some((reason) => reason.category === 'routing-evidence')).toBe(true);
|
|
63
|
+
s.routingAttempts = [{
|
|
64
|
+
schema: 'routing-attempt/v1', id: 'route-1', obligationId: 'o-spec', lineageId: 'lineage-1', attempt: 1,
|
|
65
|
+
envelope: { schema: 'routing-envelope/v1', runtime: { target: 'codex', kind: 'native', version: '1', accountScopeDigest: '0'.repeat(64) }, role: 'specification-reviewer', requestedProfile: 'full', effectiveProfile: 'full', resolved: { selector: { kind: 'model', id: 'm' }, effort: { kind: 'explicit', value: 'high' } }, outcome: 'native', unavailableEvidence: [], policyDigest: 'a'.repeat(64), capabilityDigest: 'b'.repeat(64), planDigest: 'c'.repeat(64), executionDigest: 'd'.repeat(64) },
|
|
66
|
+
envelopeDigest: 'a'.repeat(64), fingerprint: 'fp', state: 'active', nativeAgentId: 'native-1', observed: { selector: { kind: 'model', id: 'm' }, effort: { kind: 'explicit', value: 'high' } },
|
|
67
|
+
}];
|
|
68
|
+
s.planBinding = { path: 'plan.md', digest: 'c'.repeat(64), executionDigest: 'd'.repeat(64), executionIdentitySchema: 'awm-plan-execution/v1', schema: 'compact-slices/v2', executionMode: 'desatendido', boundAt: 'now' };
|
|
69
|
+
expect((0, gate_1.computeGate)(s, false, fpCurrent).pass).toBe(true);
|
|
70
|
+
s.routingAttempts[0].fingerprint = 'different';
|
|
71
|
+
gate = (0, gate_1.computeGate)(s, false, fpCurrent);
|
|
72
|
+
expect(gate.reasons.some((reason) => reason.category === 'routing-evidence')).toBe(true);
|
|
73
|
+
});
|
|
56
74
|
test('el estado de referencia pasa; la corrupcion bloquea (R3.2)', () => {
|
|
57
75
|
expect((0, gate_1.computeGate)(passingState(), false, fpCurrent).pass).toBe(true);
|
|
58
76
|
const g = (0, gate_1.computeGate)(null, true, fpCurrent);
|
|
@@ -501,6 +519,16 @@ function trackRefFixture(overrides, worktreePath) {
|
|
|
501
519
|
function descriptorFixture(overrides, planRoot) {
|
|
502
520
|
return { schema: 1, planRoot, planBranch: 'main', trackId: 'cli', planJournalId: 'j-1', fencingToken: 'f'.repeat(32), ...overrides };
|
|
503
521
|
}
|
|
522
|
+
function initCompactJournal(repo, branch) {
|
|
523
|
+
const planPath = path_1.default.join(repo, 'plans', 'fixture.md');
|
|
524
|
+
fs_1.default.mkdirSync(path_1.default.dirname(planPath), { recursive: true });
|
|
525
|
+
fs_1.default.writeFileSync(planPath, fs_1.default.readFileSync(path_1.default.join(__dirname, '../../core/plan/fixtures/compact-slices-v1/valid.md'), 'utf8'));
|
|
526
|
+
fs_1.default.writeFileSync(path_1.default.join(repo, 'source.md'), '## Canonical source\nfixture source\n');
|
|
527
|
+
const report = (0, validate_1.validatePlanFile)('plans/fixture.md', repo);
|
|
528
|
+
if (report.state !== 'valid')
|
|
529
|
+
throw new Error(`compact fixture must validate: ${JSON.stringify(report)}`);
|
|
530
|
+
(0, init_1.initWatch)(repo, branch, { path: 'plans/fixture.md', report });
|
|
531
|
+
}
|
|
504
532
|
async function runCommand(register, argv, cwd) {
|
|
505
533
|
const prog = new commander_1.Command();
|
|
506
534
|
prog.exitOverride();
|
|
@@ -543,12 +571,12 @@ describe('guard de contexto en awm job / awm watch (R9.4)', () => {
|
|
|
543
571
|
gitInitAt(planRoot, 'main');
|
|
544
572
|
gitInitAt(trackRoot, 'track/cli');
|
|
545
573
|
gitInitAt(otherRoot, 'track/cli');
|
|
546
|
-
(
|
|
574
|
+
initCompactJournal(planRoot, 'main');
|
|
547
575
|
const planState = (0, store_1.readJournal)(planRoot, 'main').state;
|
|
548
576
|
planState.journalId = 'j-1';
|
|
549
577
|
planState.tracks = [trackRefFixture({ fencingToken: 'f'.repeat(32) }, trackRoot)];
|
|
550
578
|
(0, store_1.writeJournal)(planRoot, 'main', planState);
|
|
551
|
-
(
|
|
579
|
+
initCompactJournal(trackRoot, 'track/cli');
|
|
552
580
|
const trackState = (0, store_1.readJournal)(trackRoot, 'track/cli').state;
|
|
553
581
|
trackState.trackContext = { trackId: 'cli', taskIds: [], planDigest: 'x', baseSha: 'y', planJournalId: 'j-1' };
|
|
554
582
|
(0, store_1.writeJournal)(trackRoot, 'track/cli', trackState);
|
|
@@ -556,7 +584,7 @@ describe('guard de contexto en awm job / awm watch (R9.4)', () => {
|
|
|
556
584
|
// otherRoot: mismo descriptor (mismo plan/trackId/fencing) pero NO es
|
|
557
585
|
// el worktree que el TrackRef del plan declara — su realpath jamas
|
|
558
586
|
// puede autenticar (R9.4), aunque el resto del descriptor "calce".
|
|
559
|
-
(
|
|
587
|
+
initCompactJournal(otherRoot, 'track/cli');
|
|
560
588
|
const otherState = (0, store_1.readJournal)(otherRoot, 'track/cli').state;
|
|
561
589
|
otherState.trackContext = { trackId: 'cli', taskIds: [], planDigest: 'x', baseSha: 'y', planJournalId: 'j-1' };
|
|
562
590
|
(0, store_1.writeJournal)(otherRoot, 'track/cli', otherState);
|
|
@@ -580,24 +608,26 @@ describe('guard de contexto en awm job / awm watch (R9.4)', () => {
|
|
|
580
608
|
expect(exitCode).toBe(1);
|
|
581
609
|
expect(JSON.parse(out).pass).toBe(false);
|
|
582
610
|
});
|
|
583
|
-
test('`watch --init` desde un cwd SIN descriptor
|
|
611
|
+
test('`watch --init --plan` desde un cwd SIN descriptor crea un binding compacto', async () => {
|
|
584
612
|
const plainRepo = fs_1.default.mkdtempSync(path_1.default.join(os_1.default.tmpdir(), 'awm-guard-plain-'));
|
|
585
613
|
try {
|
|
586
614
|
gitInitAt(plainRepo, 'main');
|
|
587
|
-
const
|
|
615
|
+
const planPath = path_1.default.join(plainRepo, 'plans', 'fixture.md');
|
|
616
|
+
fs_1.default.mkdirSync(path_1.default.dirname(planPath), { recursive: true });
|
|
617
|
+
fs_1.default.writeFileSync(planPath, fs_1.default.readFileSync(path_1.default.join(__dirname, '../../core/plan/fixtures/compact-slices-v1/valid.md'), 'utf8'));
|
|
618
|
+
fs_1.default.writeFileSync(path_1.default.join(plainRepo, 'source.md'), '## Canonical source\nfixture source\n');
|
|
619
|
+
const { out, err, exitCode } = await runWatch(['--init', '--plan', 'plans/fixture.md'], plainRepo);
|
|
588
620
|
expect(exitCode).toBeNull();
|
|
589
621
|
expect(err).toBe('');
|
|
590
622
|
expect(out).toContain('journal inicializado');
|
|
623
|
+
expect((0, store_1.readJournal)(plainRepo, 'main').state).toMatchObject({ schema: 2, planBinding: { path: 'plans/fixture.md', executionMode: 'desatendido' } });
|
|
591
624
|
}
|
|
592
625
|
finally {
|
|
593
626
|
fs_1.default.rmSync(plainRepo, { recursive: true, force: true });
|
|
594
627
|
}
|
|
595
628
|
});
|
|
596
|
-
test('`watch --init` desde el cwd autenticado
|
|
597
|
-
|
|
598
|
-
expect(err).not.toContain('cwd no autenticado');
|
|
599
|
-
expect(exitCode).toBeNull();
|
|
600
|
-
expect(out).toContain('journal inicializado');
|
|
629
|
+
test('`watch --init --plan` desde el cwd autenticado alcanza la guarda de lifecycle y rechaza sobrescribir el binding', async () => {
|
|
630
|
+
await expect(runWatch(['--init', '--plan', 'plans/fixture.md'], trackRoot)).rejects.toThrow(/overwrite|sobrescribir/i);
|
|
601
631
|
});
|
|
602
632
|
test('`watch --init` desde un cwd cuyo descriptor no autentica rechaza con "cwd no autenticado"', async () => {
|
|
603
633
|
const { err, exitCode } = await runWatch(['--init'], otherRoot);
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const gate_1 = require("../../../src/commands/job/gate");
|
|
4
|
+
const types_1 = require("../../../src/core/journal/types");
|
|
5
|
+
test('routed evidence cannot certify against a legacy journal without its attempt', () => {
|
|
6
|
+
const state = (0, types_1.emptyState)('main');
|
|
7
|
+
state.verdicts.push({ id: 'v1', obligationId: 'o1', result: 'pass', detail: '', receivedAt: 'now', fingerprint: 'fp', argv: [], paths: [], cwd: '.', routingAttemptId: 'missing' });
|
|
8
|
+
expect((0, gate_1.computeGate)(state, false, () => 'fp').reasons).toContainEqual(expect.objectContaining({ category: 'routing-evidence' }));
|
|
9
|
+
});
|
|
@@ -0,0 +1,46 @@
|
|
|
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
|
+
const fs_1 = __importDefault(require("fs"));
|
|
7
|
+
const os_1 = __importDefault(require("os"));
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
const child_process_1 = require("child_process");
|
|
10
|
+
const commander_1 = require("commander");
|
|
11
|
+
const job_1 = require("../../../src/commands/job");
|
|
12
|
+
const store_1 = require("../../../src/core/journal/store");
|
|
13
|
+
const journal_1 = require("../../../src/core/model-policy/journal");
|
|
14
|
+
const envelope = { schema: 'routing-envelope/v1', runtime: { target: 'codex', kind: 'native', version: '1', accountScopeDigest: '0'.repeat(64) }, role: 'implementer', sliceId: 'S1', requestedProfile: 'mechanical', effectiveProfile: 'mechanical', resolved: { selector: { kind: 'model', id: 'model-private' }, effort: { kind: 'explicit', value: 'medium' } }, outcome: 'native', unavailableEvidence: [], policyDigest: 'a'.repeat(64), capabilityDigest: 'b'.repeat(64), planDigest: 'c'.repeat(64), executionDigest: 'd'.repeat(64) };
|
|
15
|
+
function gitInit(repo) {
|
|
16
|
+
(0, child_process_1.execFileSync)('git', ['-c', 'user.email=t@t.t', '-c', 'user.name=t', 'init', '-q', '-b', 'main'], { cwd: repo });
|
|
17
|
+
fs_1.default.writeFileSync(path_1.default.join(repo, 'fixture'), 'x');
|
|
18
|
+
(0, child_process_1.execFileSync)('git', ['add', '.'], { cwd: repo });
|
|
19
|
+
(0, child_process_1.execFileSync)('git', ['-c', 'user.email=t@t.t', '-c', 'user.name=t', 'commit', '-qm', 'fixture'], { cwd: repo });
|
|
20
|
+
}
|
|
21
|
+
test('`job routing-report --json` emits only aggregate routing evidence', async () => {
|
|
22
|
+
const repo = fs_1.default.mkdtempSync(path_1.default.join(os_1.default.tmpdir(), 'awm-routing-report-'));
|
|
23
|
+
try {
|
|
24
|
+
gitInit(repo);
|
|
25
|
+
(0, store_1.initJournal)(repo, 'main');
|
|
26
|
+
const state = (0, store_1.readJournal)(repo, 'main').state;
|
|
27
|
+
const reserved = (0, journal_1.reserveRoutingAttempt)(state, { obligationId: 'obligation', lineageId: 'lineage', envelope, fingerprint: 'e'.repeat(64) }, '2026-09-17T00:00:00.000Z');
|
|
28
|
+
(0, store_1.writeJournal)(repo, 'main', (0, journal_1.observeRoutingAttempt)(reserved.state, { attemptId: reserved.attemptId, nativeAgentId: 'native-private' }, '2026-09-17T00:01:00.000Z'));
|
|
29
|
+
const program = new commander_1.Command();
|
|
30
|
+
program.exitOverride();
|
|
31
|
+
(0, job_1.registerJobCommand)(program);
|
|
32
|
+
const out = jest.spyOn(process.stdout, 'write').mockImplementation(() => true);
|
|
33
|
+
const cwd = jest.spyOn(process, 'cwd').mockReturnValue(repo);
|
|
34
|
+
await program.parseAsync(['node', 'awm', 'job', 'routing-report', '--json']);
|
|
35
|
+
const rendered = String(out.mock.calls[0][0]);
|
|
36
|
+
const report = JSON.parse(rendered);
|
|
37
|
+
expect(report).toMatchObject({ schema: 'routing-report/v1', attempts: 1, plannedByRole: { implementer: 1 }, actualByRole: { implementer: 1 }, byState: { active: 1 } });
|
|
38
|
+
expect(rendered).not.toContain('native-private');
|
|
39
|
+
expect(rendered).not.toContain('model-private');
|
|
40
|
+
cwd.mockRestore();
|
|
41
|
+
out.mockRestore();
|
|
42
|
+
}
|
|
43
|
+
finally {
|
|
44
|
+
fs_1.default.rmSync(repo, { recursive: true, force: true });
|
|
45
|
+
}
|
|
46
|
+
});
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const types_1 = require("../../../src/core/journal/types");
|
|
4
|
+
const journal_1 = require("../../../src/core/model-policy/journal");
|
|
5
|
+
const envelope = { schema: 'routing-envelope/v1', runtime: { target: 'codex', kind: 'native', version: '1', accountScopeDigest: '0'.repeat(64) }, role: 'implementer', sliceId: 'S1', requestedProfile: 'mechanical', effectiveProfile: 'mechanical', resolved: { selector: { kind: 'model', id: 'm' }, effort: { kind: 'explicit', value: 'medium' } }, outcome: 'native', unavailableEvidence: [], policyDigest: 'a'.repeat(64), capabilityDigest: 'b'.repeat(64), planDigest: 'c'.repeat(64), executionDigest: 'd'.repeat(64) };
|
|
6
|
+
test('routing report remains read-only across an observed attempt', () => {
|
|
7
|
+
const reserved = (0, journal_1.reserveRoutingAttempt)((0, types_1.emptyState)('main'), { obligationId: 'o1', lineageId: 'l1', envelope, fingerprint: 'e'.repeat(64) }, '2026-09-17T00:00:00.000Z');
|
|
8
|
+
const observed = (0, journal_1.observeRoutingAttempt)(reserved.state, { attemptId: reserved.attemptId, nativeAgentId: 'native-id' }, '2026-09-17T00:01:00.000Z');
|
|
9
|
+
expect((0, journal_1.routingReport)(observed)).toMatchObject({ attempts: 1, byState: { active: 1 } });
|
|
10
|
+
expect(observed.routingAttempts[0].nativeAgentId).toBe('native-id');
|
|
11
|
+
});
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const commander_1 = require("commander");
|
|
4
|
+
const model_policy_1 = require("../../../src/commands/model-policy");
|
|
5
|
+
const out = jest.spyOn(process.stdout, 'write').mockImplementation(() => true);
|
|
6
|
+
describe('model-policy command', () => {
|
|
7
|
+
beforeEach(() => { jest.clearAllMocks(); process.exitCode = undefined; });
|
|
8
|
+
afterAll(() => out.mockRestore());
|
|
9
|
+
it('emits a read-only protocol contract as JSON', async () => {
|
|
10
|
+
const program = new commander_1.Command();
|
|
11
|
+
program.exitOverride();
|
|
12
|
+
program.configureOutput({ writeErr: () => undefined });
|
|
13
|
+
(0, model_policy_1.registerModelPolicyCommand)(program);
|
|
14
|
+
await program.parseAsync(['node', 'awm', 'model-policy', 'contract', '--json']);
|
|
15
|
+
expect(JSON.parse(String(out.mock.calls[0][0]))).toMatchObject({
|
|
16
|
+
schema: 'routing-protocol/v1',
|
|
17
|
+
supportedPlanSchemas: ['compact-slices/v1', 'compact-slices/v2'],
|
|
18
|
+
implementerProfiles: ['mechanical', 'integration', 'judgment'],
|
|
19
|
+
limits: { maxFileBytes: 262144 },
|
|
20
|
+
});
|
|
21
|
+
});
|
|
22
|
+
it('rejects missing values instead of silently accepting an incomplete approval', async () => {
|
|
23
|
+
const program = new commander_1.Command();
|
|
24
|
+
program.exitOverride();
|
|
25
|
+
program.configureOutput({ writeErr: () => undefined });
|
|
26
|
+
(0, model_policy_1.registerModelPolicyCommand)(program);
|
|
27
|
+
await expect(program.parseAsync(['node', 'awm', 'model-policy', 'approve', '--file', '--scope', 'user', '--expected-digest', 'a'.repeat(64)])).rejects.toThrow();
|
|
28
|
+
});
|
|
29
|
+
it('accepts and validates --cwd on contract, and resolves status through it', async () => {
|
|
30
|
+
const readEffectivePolicy = jest.fn(() => ({ state: 'absent' }));
|
|
31
|
+
const program = new commander_1.Command();
|
|
32
|
+
program.exitOverride();
|
|
33
|
+
program.configureOutput({ writeErr: () => undefined });
|
|
34
|
+
(0, model_policy_1.registerModelPolicyCommand)(program, { readEffectivePolicy });
|
|
35
|
+
await program.parseAsync(['node', 'awm', 'model-policy', 'contract', '--cwd', 'fixture-root', '--json']);
|
|
36
|
+
await program.parseAsync(['node', 'awm', 'model-policy', 'status', '--provider', 'codex', '--runtime-kind', 'native', '--runtime-version', '1.0.0', '--account-scope-digest', 'a'.repeat(64), '--cwd', 'fixture-root', '--json']);
|
|
37
|
+
expect(readEffectivePolicy).toHaveBeenCalledWith('fixture-root');
|
|
38
|
+
await expect(program.parseAsync(['node', 'awm', 'model-policy', 'contract', '--cwd', '--json'])).rejects.toThrow();
|
|
39
|
+
});
|
|
40
|
+
it('reports receipt provenance in status and rejects stale receipt state', async () => {
|
|
41
|
+
const readCapabilities = jest.fn(() => ({ state: 'stale', reason: 'expired' }));
|
|
42
|
+
const program = new commander_1.Command();
|
|
43
|
+
program.exitOverride();
|
|
44
|
+
program.configureOutput({ writeErr: () => undefined });
|
|
45
|
+
(0, model_policy_1.registerModelPolicyCommand)(program, { readEffectivePolicy: () => ({ state: 'absent' }), readCapabilities });
|
|
46
|
+
await program.parseAsync(['node', 'awm', 'model-policy', 'status', '--provider', 'codex', '--runtime-kind', 'native', '--runtime-version', '1.0.0', '--account-scope-digest', 'a'.repeat(64), '--json']);
|
|
47
|
+
expect(JSON.parse(String(out.mock.calls[0][0]))).toMatchObject({ policy: { state: 'absent' }, capability: { state: 'stale' } });
|
|
48
|
+
expect(process.exitCode).toBe(2);
|
|
49
|
+
});
|
|
50
|
+
it('rejects an empty replacement digest for capability approval at the command boundary', async () => {
|
|
51
|
+
const program = new commander_1.Command();
|
|
52
|
+
program.exitOverride();
|
|
53
|
+
program.configureOutput({ writeErr: () => undefined });
|
|
54
|
+
(0, model_policy_1.registerModelPolicyCommand)(program, { approveCapabilities: jest.fn() });
|
|
55
|
+
await expect(program.parseAsync(['node', 'awm', 'model-policy', 'capabilities', 'approve', '--file', 'receipt.json', '--expected-digest', 'a'.repeat(64), '--replace-digest', ''])).rejects.toThrow(/requires a non-empty value/);
|
|
56
|
+
});
|
|
57
|
+
});
|
|
@@ -7,30 +7,30 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
7
7
|
const fs_1 = __importDefault(require("fs"));
|
|
8
8
|
const path_1 = __importDefault(require("path"));
|
|
9
9
|
const os_1 = __importDefault(require("os"));
|
|
10
|
+
let tmpHome;
|
|
11
|
+
let originalHome;
|
|
12
|
+
let originalAwmHome;
|
|
13
|
+
beforeEach(() => {
|
|
14
|
+
tmpHome = fs_1.default.mkdtempSync(path_1.default.join(os_1.default.tmpdir(), 'awm-pin-home-'));
|
|
15
|
+
originalHome = process.env.HOME;
|
|
16
|
+
originalAwmHome = process.env.AWM_HOME;
|
|
17
|
+
process.env.HOME = tmpHome;
|
|
18
|
+
process.env.AWM_HOME = path_1.default.join(tmpHome, '.awm');
|
|
19
|
+
jest.resetModules();
|
|
20
|
+
});
|
|
21
|
+
afterEach(() => {
|
|
22
|
+
fs_1.default.rmSync(tmpHome, { recursive: true, force: true });
|
|
23
|
+
if (originalHome === undefined)
|
|
24
|
+
delete process.env.HOME;
|
|
25
|
+
else
|
|
26
|
+
process.env.HOME = originalHome;
|
|
27
|
+
if (originalAwmHome === undefined)
|
|
28
|
+
delete process.env.AWM_HOME;
|
|
29
|
+
else
|
|
30
|
+
process.env.AWM_HOME = originalAwmHome;
|
|
31
|
+
});
|
|
32
|
+
const readPrefs = () => JSON.parse(fs_1.default.readFileSync(path_1.default.join(tmpHome, '.awm/preferences.json'), 'utf-8'));
|
|
10
33
|
describe('pin/unpin (editores de preferences)', () => {
|
|
11
|
-
let tmpHome;
|
|
12
|
-
let originalHome;
|
|
13
|
-
let originalAwmHome;
|
|
14
|
-
beforeEach(() => {
|
|
15
|
-
tmpHome = fs_1.default.mkdtempSync(path_1.default.join(os_1.default.tmpdir(), 'awm-pin-home-'));
|
|
16
|
-
originalHome = process.env.HOME;
|
|
17
|
-
originalAwmHome = process.env.AWM_HOME;
|
|
18
|
-
process.env.HOME = tmpHome;
|
|
19
|
-
process.env.AWM_HOME = path_1.default.join(tmpHome, '.awm');
|
|
20
|
-
jest.resetModules();
|
|
21
|
-
});
|
|
22
|
-
afterEach(() => {
|
|
23
|
-
fs_1.default.rmSync(tmpHome, { recursive: true, force: true });
|
|
24
|
-
if (originalHome === undefined)
|
|
25
|
-
delete process.env.HOME;
|
|
26
|
-
else
|
|
27
|
-
process.env.HOME = originalHome;
|
|
28
|
-
if (originalAwmHome === undefined)
|
|
29
|
-
delete process.env.AWM_HOME;
|
|
30
|
-
else
|
|
31
|
-
process.env.AWM_HOME = originalAwmHome;
|
|
32
|
-
});
|
|
33
|
-
const readPrefs = () => JSON.parse(fs_1.default.readFileSync(path_1.default.join(tmpHome, '.awm/preferences.json'), 'utf-8'));
|
|
34
34
|
it('setPin escribe pins.base normalizado (acepta prefijo v)', () => {
|
|
35
35
|
const { setPin } = require('../../src/commands/pin');
|
|
36
36
|
setPin('base', 'v1.2.0');
|