Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions packages/agents-audit/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# Changelog

## [Unreleased]

### Patch Changes

- `generate --check --dry-run` now fires the drift gate (exit 1, "manual evidence is untouched") instead of the dry-run branch silently winning and exiting 0; the JSON projection is still printed under `--dry-run`. Deferred from 0.4.4 (META-157) because it changes exit-code semantics; landed here as its own reviewed change with regression tests watched red against the pre-change CLI.
- `generate` now surfaces `invalidFileMoved` (result data that has existed since 0.4.3 but was never displayed): when a previous `.agents/workspace.json` was invalid and moved aside, the CLI prints where it was relocated to and that its manual evidence could not be recovered.

## [0.4.4] - Unreleased

### Patch Changes
Expand Down
44 changes: 44 additions & 0 deletions packages/agents-audit/src/cli.integration.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,50 @@ describe('CLI integration', () => {
logSpy.mockRestore();
});

it('still fails the drift gate when --check is combined with --dry-run', async () => {
const errorSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
const logSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
mocks.generateWorkspaceJson.mockResolvedValueOnce({
path: '/repo/.agents/workspace.json',
written: false,
skipped: false,
drift: true,
preservedManual: true,
content: { staged: true },
});

const exitCode = await runCli(['node', 'agents-audit', 'generate', '/repo', '--check', '--dry-run']);

expect(exitCode).toBe(1);
const errorCalls = (errorSpy as unknown as { mock: { calls: unknown[][] } }).mock.calls;
expect(errorCalls.flat().join(' ')).toContain('manual evidence is untouched');
expect(logSpy).toHaveBeenCalledWith(JSON.stringify({ staged: true }, null, 2));
errorSpy.mockRestore();
logSpy.mockRestore();
});

it('surfaces the relocated invalid file when --force recovers a fresh generate', async () => {
const logSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
mocks.generateWorkspaceJson.mockResolvedValueOnce({
path: '/repo/.agents/workspace.json',
written: true,
skipped: false,
drift: true,
preservedManual: false,
invalidFileMoved: '/repo/.agents/workspace.json.invalid.2026-01-01T00-00-00-000Z',
content: {},
});

const exitCode = await runCli(['node', 'agents-audit', 'generate', '/repo', '--force']);

expect(exitCode).toBe(0);
const logCalls = (logSpy as unknown as { mock: { calls: unknown[][] } }).mock.calls;
const logs = logCalls.flat().join(' ');
expect(logs).toContain('Generated /repo/.agents/workspace.json');
expect(logs).toContain('/repo/.agents/workspace.json.invalid.2026-01-01T00-00-00-000Z');
logSpy.mockRestore();
});

it('treats --dir as an invalid option', async () => {
const exitCode = await runCli(['node', 'agents-audit', 'scan', '--dir', '/tmp/example']);

Expand Down
13 changes: 10 additions & 3 deletions packages/agents-audit/src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,17 +110,24 @@ export async function runCli(argv: string[] = process.argv): Promise<number> {
});
spinner.stop();

if (options.dryRun) {
console.log(JSON.stringify(result.content, null, 2));
} else if (options.check) {
if (options.check) {
if (result.drift) {
console.error(`Generated sections are stale at ${result.path}; manual evidence is untouched. Run: agents-audit generate ${path}`);
exitCode = 1;
} else {
console.log(`Generated sections are current at ${result.path}`);
}
if (options.dryRun) {
console.log(JSON.stringify(result.content, null, 2));
}
} else if (options.dryRun) {
console.log(JSON.stringify(result.content, null, 2));
} else if (result.skipped) {
console.log(`Generated sections already current at ${result.path}; manual evidence preserved`);
} else if (result.invalidFileMoved) {
console.log(`Generated ${result.path}`);
console.log(pc.yellow(` Previous file was invalid and has been moved aside: ${result.invalidFileMoved}`));
console.log(pc.yellow(' Manual evidence from the previous file was not recovered (it could not be parsed/validated).'));
} else {
console.log(`Generated ${result.path}`);
}
Expand Down
Loading