diff --git a/package-lock.json b/package-lock.json index b8c9de9..fb0c95b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@treeseed/cli", - "version": "0.13.0-rc.39", + "version": "0.13.0-rc.40", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@treeseed/cli", - "version": "0.13.0-rc.39", + "version": "0.13.0-rc.40", "bundleDependencies": [ "ink", "react", @@ -15,7 +15,7 @@ ], "license": "Apache-2.0", "dependencies": { - "@treeseed/sdk": "0.13.0-rc.61", + "@treeseed/sdk": "0.13.0-rc.63", "ink": "^7.1.1", "react": "^19.2.8", "string-width": "^8.2.2", @@ -492,9 +492,9 @@ } }, "node_modules/@treeseed/sdk": { - "version": "0.13.0-rc.61", - "resolved": "https://registry.npmjs.org/@treeseed/sdk/-/sdk-0.13.0-rc.61.tgz", - "integrity": "sha512-Op9t955kwz750YzSG7F458ZEBvGMgMITgj64k8WSAbys1r0XT37OVv98wzTaKRLgvbEOTDrgRUdBiKsLJsbtKw==", + "version": "0.13.0-rc.63", + "resolved": "https://registry.npmjs.org/@treeseed/sdk/-/sdk-0.13.0-rc.63.tgz", + "integrity": "sha512-YfZVOb2Q1+8hvyzBYd/swi32vGIwY5PjlYK8J8i93LsJEgqKdxmGbOT/gFEf0XPJoQAffiN2vEVONAUX/YEjNw==", "dependencies": { "@treeseed/treedx": "0.3.0-rc.4", "esbuild": "^0.28.0", diff --git a/package.json b/package.json index 6bce6e6..bb60560 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@treeseed/cli", - "version": "0.13.0-rc.39", + "version": "0.13.0-rc.40", "description": "Operator-facing Treeseed CLI package.", "license": "Apache-2.0", "repository": { @@ -50,7 +50,7 @@ "release:custody": "node --import tsx ./scripts/packages/release-custody.ts" }, "dependencies": { - "@treeseed/sdk": "0.13.0-rc.61", + "@treeseed/sdk": "0.13.0-rc.63", "ink": "^7.1.1", "react": "^19.2.8", "string-width": "^8.2.2", @@ -74,5 +74,11 @@ }, "bin": { "trsd": "./dist/cli/main.js" - } + }, + "bundleDependencies": [ + "ink", + "react", + "string-width", + "yaml" + ] } diff --git a/src/cli/commands/platform/index.ts b/src/cli/commands/platform/index.ts index 4959d30..9610d5d 100644 --- a/src/cli/commands/platform/index.ts +++ b/src/cli/commands/platform/index.ts @@ -14,7 +14,11 @@ function verify(invocation: ParsedInvocation, context: CommandContext) { const profiles = loadPlatformProfiles(root); const selected = values(invocation.options.profile); if (selected.length) resolveProfileProjects(profiles, selected); - return { ...verifyPlatformRepository(root), profiles: selected }; + const result = { ...verifyPlatformRepository(root), profiles: selected }; + if (!result.ok) throw Object.assign(new Error('Platform repository verification failed.'), { + category: 'policy_blocked', code: 'platform_verification_failed', partialResult: result, + }); + return result; } function workset(invocation: ParsedInvocation, context: CommandContext) { diff --git a/src/cli/runtime.ts b/src/cli/runtime.ts index e0efa8e..e910fa3 100644 --- a/src/cli/runtime.ts +++ b/src/cli/runtime.ts @@ -106,8 +106,9 @@ export async function runCommandLine(argv: string[], overrides: Partial path.startsWith('scripts/')), false); assert.equal(pkg.dependencies['@treeseed/agent'], undefined); - assert.deepEqual(pkg.dependencies, { '@treeseed/sdk': '0.13.0-rc.61', ink: '^7.1.1', react: '^19.2.8', 'string-width': '^8.2.2', yaml: '2.9.0' }); + assert.deepEqual(pkg.dependencies, { '@treeseed/sdk': '0.13.0-rc.63', ink: '^7.1.1', react: '^19.2.8', 'string-width': '^8.2.2', yaml: '2.9.0' }); }); test('built package contains executable runtime only', () => { diff --git a/tests/unit/command-boundary/platform/workset.test.ts b/tests/unit/command-boundary/platform/workset.test.ts index dc34136..3acbec3 100644 --- a/tests/unit/command-boundary/platform/workset.test.ts +++ b/tests/unit/command-boundary/platform/workset.test.ts @@ -12,17 +12,34 @@ test('platform verify works from a clean declarative clone without packages or a const root = mkdtempSync(resolve(tmpdir(), 'platform-cli-')); try { execFileSync('git', ['init'], { cwd: root, stdio: 'ignore' }); + mkdirSync(resolve(root, 'seeds')); writeFileSync(resolve(root, 'README.md'), '# Portable Platform\n'); writeFileSync(resolve(root, 'treeseed.site.yaml'), 'development:\n local:\n inventory: { source: seed, path: seeds/inventory.yaml }\n'); + writeFileSync(resolve(root, 'seeds/inventory.yaml'), 'schemaVersion: treeseed.seed-bundle/v3\nresources:\n projects: []\n repositories: []\n'); execFileSync('git', ['add', '.'], { cwd: root, stdio: 'ignore' }); const target = capture(); - assert.equal(await runCommandLine(['platform', 'verify', '--json'], { cwd: root, interactiveUi: false, write: target.write }), 0); + assert.equal(await runCommandLine(['platform', 'verify', '--json'], { cwd: root, interactiveUi: false, write: target.write }), 0, target.output.join('\n')); const envelope = JSON.parse(target.output[0]!); assert.equal(envelope.result.ok, true); assert.equal(envelope.result.profiles.length, 0); } finally { rmSync(root, { recursive: true, force: true }); } }); +test('platform verify preserves local policy diagnostics instead of masking them as a control-plane rejection', async () => { + const root = mkdtempSync(resolve(tmpdir(), 'platform-cli-')); + try { + execFileSync('git', ['init'], { cwd: root, stdio: 'ignore' }); + writeFileSync(resolve(root, 'package.json'), '{}\n'); + execFileSync('git', ['add', '.'], { cwd: root, stdio: 'ignore' }); + const target = capture(); + assert.equal(await runCommandLine(['platform', 'verify', '--json'], { cwd: root, interactiveUi: false, write: target.write }), 1); + const envelope = JSON.parse(target.output[0]!); + assert.equal(envelope.error.code, 'platform_verification_failed'); + assert.equal(envelope.result.diagnostics[0].code, 'content_root_forbidden'); + assert.notEqual(envelope.error.code, 'control_plane_rejected'); + } finally { rmSync(root, { recursive: true, force: true }); } +}); + test('platform workset plans and applies an exact local staging checkout', async () => { const root = mkdtempSync(resolve(tmpdir(), 'platform-cli-')); const source = mkdtempSync(resolve(tmpdir(), 'platform-source-'));