From 9e4019cb029e7d8fd247dc594d969b92bd526a3b Mon Sep 17 00:00:00 2001 From: Adrian Webb Date: Sat, 12 Sep 2026 04:06:49 -0400 Subject: [PATCH] fix(dev): preserve clean JSON output --- src/cli/commands/development-support/host-runtime.ts | 11 ++++++----- .../commands/development-support/runtime-loader.ts | 2 +- src/cli/commands/development.ts | 2 +- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/cli/commands/development-support/host-runtime.ts b/src/cli/commands/development-support/host-runtime.ts index f37085f..2760638 100644 --- a/src/cli/commands/development-support/host-runtime.ts +++ b/src/cli/commands/development-support/host-runtime.ts @@ -74,6 +74,7 @@ async function awaitActivation(context: CommandContext, generationId: string) { } export async function runHostDevelopment(invocation: ParsedInvocation, context: CommandContext) { + const json = invocation.options.json === true; if (invocation.command.name === 'dev host status') return invoke(context, 'local.dev.host.status', {}); if (invocation.command.name === 'dev host deactivate') return invocation.options.plan === true ? { action: 'deactivate', mutation: false } : invoke(context, 'local.dev.host.deactivate', {}); if (invocation.command.name === 'dev host guest image import') { @@ -85,8 +86,8 @@ export async function runHostDevelopment(invocation: ParsedInvocation, context: const directory = resolve(stateBase, 'treeseed', 'development', 'images'), archivePath = resolve(directory, `sandbox-${randomUUID()}.tar`); mkdirSync(directory, { recursive: true, mode: 0o700 }); try { - context.write(`Exporting ${image} for the local Kata runtime…`, 'stdout'); - execFileSync('docker', ['image', 'save', '--output', archivePath, image], { cwd: context.cwd, env: context.env, stdio: 'inherit' }); + if (!json) context.write(`Exporting ${image} for the local Kata runtime…`, 'stdout'); + execFileSync('docker', ['image', 'save', '--output', archivePath, image], { cwd: context.cwd, env: context.env, stdio: json ? 'pipe' : 'inherit' }); const result = await invoke(context, 'local.dev.host.guest-image.import', { archivePath, image }) as { digest?: unknown; architecture?: unknown }; if (typeof result.digest !== 'string' || !/^sha256:[a-f0-9]{64}$/u.test(result.digest)) throw new Error('Host guest-image import omitted its immutable digest.'); const receipt = resolve(stateBase, 'treeseed', 'development', 'sandbox-guest.json'), temporary = `${receipt}.${process.pid}.tmp`; @@ -100,13 +101,13 @@ export async function runHostDevelopment(invocation: ParsedInvocation, context: const packagePath = resolve(worktree, 'package.json'); if (invocation.options.plan === true) return { action: 'activate', worktree, guestImageDigest: invocation.options.guestImage ?? null, mutation: false }; if (!existsSync(packagePath) || basename(worktree) !== 'deployment') throw new Error('Host development activation requires the Deployment package worktree.'); - context.write('Building the local host runtime…', 'stdout'); - execFileSync('npm', ['run', 'build'], { cwd: worktree, env: context.env, stdio: 'inherit' }); + if (!json) context.write('Building the local host runtime…', 'stdout'); + execFileSync('npm', ['run', 'build'], { cwd: worktree, env: context.env, stdio: json ? 'pipe' : 'inherit' }); const manifest = hostDevelopmentRuntimeManifest(worktree); if (!manifest.some((entry) => entry.path === 'dist/src/bin/supervisor.js') || !manifest.some((entry) => entry.path === 'dist/src/bin/api.js') || !manifest.some((entry) => entry.path === 'dist/src/bin/sandbox-broker.js')) throw new Error('Host development build is missing a required runtime entrypoint.'); const source = readFileSync(packagePath); const generationId = `dev-${Date.now()}-${randomUUID().slice(0, 8)}`; - context.write(`Activating ${generationId} and checking host services…`, 'stdout'); + if (!json) context.write(`Activating ${generationId} and checking host services…`, 'stdout'); await invoke(context, 'local.dev.host.activate', { generationId, worktree, packageSha256: sha256(source), files: manifest, ...(typeof invocation.options.guestImage === 'string' ? { guestImageDigest: invocation.options.guestImage } : {}) }); return awaitActivation(context, generationId); } diff --git a/src/cli/commands/development-support/runtime-loader.ts b/src/cli/commands/development-support/runtime-loader.ts index 15ef5a5..41a802b 100644 --- a/src/cli/commands/development-support/runtime-loader.ts +++ b/src/cli/commands/development-support/runtime-loader.ts @@ -31,7 +31,7 @@ async function sourceSchema(selections: ProjectSelection[], prepare: boolean) { const packageDocument = JSON.parse(readFileSync(packagePath, 'utf8')) as { name?: unknown; scripts?: { ['build:dist']?: unknown } }; if (packageDocument.name !== '@treeseed/sdk' || typeof packageDocument.scripts?.['build:dist'] !== 'string') throw new Error('The selected SDK source is not a buildable @treeseed/sdk worktree.'); if (prepare) { - const result = spawnSync('npm', ['run', 'build:dist'], { cwd: worktree, env: process.env, stdio: 'inherit', timeout: 900_000 }); + const result = spawnSync('npm', ['run', 'build:dist'], { cwd: worktree, env: process.env, stdio: 'pipe', timeout: 900_000 }); if (result.status !== 0) throw new Error('The selected SDK source contract could not be built.'); } const entrypoint = resolve(worktree, 'dist/development/index.js'); diff --git a/src/cli/commands/development.ts b/src/cli/commands/development.ts index de12250..58f4320 100644 --- a/src/cli/commands/development.ts +++ b/src/cli/commands/development.ts @@ -114,7 +114,7 @@ export function developmentOperationEnvironment(state: Pick, worktree: string, mode: string, env: NodeJS.ProcessEnv, resolvedEnvironment: NodeJS.ProcessEnv = {}) { const root = operation.cwd ? resolve(worktree, operation.cwd) : worktree; - const result = spawnSync(operation.command, operation.args, { cwd: root, env: developmentOperationEnvironment(state, worktree, mode, env, resolvedEnvironment, operation.environment), stdio: 'inherit', timeout: operation.timeoutSeconds * 1_000 }); + const result = spawnSync(operation.command, operation.args, { cwd: root, env: developmentOperationEnvironment(state, worktree, mode, env, resolvedEnvironment, operation.environment), stdio: 'pipe', timeout: operation.timeoutSeconds * 1_000 }); if (result.status !== 0) throw new Error(`Development operation failed: ${operation.command} ${operation.args.join(' ')}.`); }