diff --git a/.github/workflows/package-smoke.yml b/.github/workflows/package-smoke.yml new file mode 100644 index 0000000..fb9ecbf --- /dev/null +++ b/.github/workflows/package-smoke.yml @@ -0,0 +1,22 @@ +name: Package install smoke + +on: + pull_request: + push: + branches: [main] + +permissions: + contents: read + +jobs: + package: + runs-on: ubuntu-latest + timeout-minutes: 10 + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: '22' + cache: npm + - run: npm ci + - run: npm run test:package diff --git a/CHANGELOG.md b/CHANGELOG.md index 119d1c0..17d9bb6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,20 @@ All notable changes to pot-cli will be documented in this file. +## [0.8.12] - Unreleased + +### Fixed +- Pin `@pot-sdk2/bridge` to the tested `1.2.0`. Fresh npm installs of + `0.8.11` selected `1.3.0`, which removed `checkAuthorVerifierSeparation` + and caused every CLI command to fail during module loading. +- Read the CLI `--version` from the installed package instead of the + hard-coded `0.5.0`. + +### Added +- `npm run test:package` packs the build, installs it in a clean consumer + without the development lockfile, and checks `--version` and + `ask --dry-run`. Both checks reproduced the `0.8.11` import failure. + ## [0.8.11] - 2026-10-09 Sentinel had been shipping these fixes only as a hand-patched diff --git a/package-lock.json b/package-lock.json index df5bb60..e37f827 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,15 +1,15 @@ { "name": "pot-cli", - "version": "0.8.11", + "version": "0.8.12", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "pot-cli", - "version": "0.8.11", + "version": "0.8.12", "license": "MIT", "dependencies": { - "@pot-sdk2/bridge": "^1.2.0", + "@pot-sdk2/bridge": "1.2.0", "better-sqlite3": "^12.8.0", "chalk": "^5.3.0", "commander": "^12.0.0", diff --git a/package.json b/package.json index 71dca12..9744469 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "pot-cli", - "version": "0.8.11", + "version": "0.8.12", "description": "Multi-model AI verification with adversarial critique. No AI can verify itself — so they verify each other.", "main": "dist/index.js", "bin": { @@ -54,6 +54,7 @@ "prepublishOnly": "npm run build", "test": "node dist/index.js ask 'Test question' --dry-run", "test:rv": "npm run build && node --test tests/rv-pipeline.test.mjs", + "test:package": "npm run build && node --test tests/cli-package.test.mjs", "test:plan": "node --test dist/plan/test-*.js dist/plan/probes/test-*.js", "check:boundaries": "node scripts/check-product-boundaries.mjs", "smoke:v1": "bash scripts/smoke-v1.sh" @@ -82,7 +83,7 @@ "url": "https://github.com/ThoughtProof/pot-cli/issues" }, "dependencies": { - "@pot-sdk2/bridge": "^1.2.0", + "@pot-sdk2/bridge": "1.2.0", "better-sqlite3": "^12.8.0", "chalk": "^5.3.0", "commander": "^12.0.0", diff --git a/src/index.ts b/src/index.ts index e6ae8ba..6c0790a 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,6 +1,7 @@ #!/usr/bin/env node import { Command } from 'commander'; +import { readFileSync } from 'node:fs'; import { askCommand } from './commands/ask.js'; import { deepCommand } from './commands/deep.js'; import { debugCommand } from './commands/debug.js'; @@ -23,11 +24,14 @@ import { runAutoGen } from './commands/plan-auto-gen.js'; import { runLOOCV } from './commands/plan-loocv.js'; const program = new Command(); +const packageVersion = (JSON.parse( + readFileSync(new URL('../package.json', import.meta.url), 'utf8'), +) as { version: string }).version; program .name('pot') .description('ThoughtProof Proof-of-Thought CLI Tool') - .version('0.5.0'); + .version(packageVersion); program .command('ask ') diff --git a/tests/cli-package.test.mjs b/tests/cli-package.test.mjs new file mode 100644 index 0000000..e0b559d --- /dev/null +++ b/tests/cli-package.test.mjs @@ -0,0 +1,57 @@ +import assert from 'node:assert/strict'; +import { execFile } from 'node:child_process'; +import { mkdtempSync, mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import { dirname, join } from 'node:path'; +import { after, before, test } from 'node:test'; +import { fileURLToPath } from 'node:url'; +import { promisify } from 'node:util'; + +const run = promisify(execFile); +const root = dirname(dirname(fileURLToPath(import.meta.url))); +const version = JSON.parse(readFileSync(join(root, 'package.json'), 'utf8')).version; +const workspace = mkdtempSync(join(tmpdir(), 'pot-cli-package-')); +const consumer = join(workspace, 'consumer'); +const cli = join(consumer, 'node_modules', 'pot-cli', 'dist', 'index.js'); + +before(async () => { + mkdirSync(consumer); + writeFileSync(join(consumer, 'package.json'), '{"private":true}\n'); + // npm ci in this repository keeps the development lockfile. A consumer + // installs only the packed package and resolves its declared dependencies. + const packed = await run('npm', ['pack', '--ignore-scripts', '--json', '--pack-destination', workspace], { + cwd: root, + timeout: 120_000, + maxBuffer: 8 * 1024 * 1024, + }); + const [{ filename }] = JSON.parse(packed.stdout); + await run('npm', ['install', '--no-audit', '--no-fund', '--package-lock=false', join(workspace, filename)], { + cwd: consumer, + timeout: 120_000, + maxBuffer: 8 * 1024 * 1024, + }); + const provider = (model) => ({ name: model, model, apiKey: 'unused-dry-run', baseUrl: 'http://127.0.0.1:1' }); + writeFileSync(join(consumer, '.potrc.json'), JSON.stringify({ + generators: [provider('mock-author')], + critic: provider('mock-critic'), + synthesizer: provider('mock-synthesizer'), + blockStoragePath: './blocks', + language: 'en', + })); +}); + +after(() => rmSync(workspace, { recursive: true, force: true })); + +test('freshly installed CLI reports the packed package version', async () => { + const { stdout } = await run(process.execPath, [cli, '--version'], { cwd: consumer }); + assert.equal(stdout.trim(), version); +}); + +test('freshly installed CLI runs ask --dry-run without API credentials', async () => { + const { stdout } = await run(process.execPath, [cli, 'ask', 'Test question', '--dry-run'], { + cwd: consumer, + timeout: 30_000, + }); + assert.match(stdout, /\[DRY-RUN\] Simulated synthesis/); + assert.match(stdout, /Saved as PoT-001/); +});