/** * package-smoke (CUT A5) — the release-grade pack/install/import smoke as a * finite, structured command (migrated from `scripts/package-smoke.ts`). It fails * when a publishable `@czap/*` scope would ship broken: a tarball that won't pack, * a `workspace:` protocol leaked into a packed manifest, a consumer install that * doesn't materialize the package, an import specifier that won't resolve, or a * `czap` binstub that won't run. * * The engine (per-package `pnpm pack`, `pnpm install` into an isolated consumer * fixture, `tar` extraction, `node` import-smoke) is INJECTED via * `context.runPackageSmoke`, never imported here, so `@czap/command` (and the MCP * server that re-uses it) stays free of the subprocess/child_process edge. Unlike * `plumb`/`check-invariants` (whose scans are pure `node:fs` and are provisioned * in the shared host factory), this gate is a terminal-streaming SUBPROCESS * orchestrator — minutes of `pnpm pack`/`install`/`tar`/`node` mutating a scratch * tree — in the same category as `gauntlet`/`ship`. So like `audit-floor` it is * CLI-only and NOT MCP-exposed: only `@czap/cli` injects `runPackageSmoke`, and * over MCP the command degrades to a structured `capabilityUnavailable` failure. * * @module */ import { Schema } from 'effect'; import { schemaToJsonSchema, wallClock, type CapsuleCommandResult } from '@czap/core'; import { capabilityUnavailable, type CommandCapability, type CommandContext, type HandledCommand, } from '../registry.js'; /** * Structured payload returned by `package-smoke` — ONE Effect Schema is the * source of both {@link PackageSmokePayload} and the descriptor's `outputSchema`. */ export const PackageSmokePayloadSchema = Schema.Struct({ ok: Schema.Boolean, /** Number of `@czap/*` (+ unscoped) scopes packed via `pnpm pack`. */ packagesPacked: Schema.Number, /** Number of module specifiers the import-smoke resolved (0 when it never ran). */ importsSmoked: Schema.Number, /** The bracketed step label of the first failure, or null on success. */ failedStep: Schema.NullOr(Schema.String), /** The failure message of the first failure, or null on success. */ failure: Schema.NullOr(Schema.String), }); /** Structured payload returned by `package-smoke`. */ export type PackageSmokePayload = Schema.Schema.Type; /** `package-smoke` — pack/install/import-smoke every publishable scope; emit a structured pass/fail verdict. */ export const packageSmokeCommand: HandledCommand = { descriptor: { name: 'package-smoke', summary: 'Release gate: pack every publishable @czap/* scope, install into an isolated consumer, and import-smoke every module specifier (+ czap binstub).', requires: ['runPackageSmoke'] satisfies readonly CommandCapability[], inputSchema: schemaToJsonSchema(Schema.Struct({})), outputSchema: schemaToJsonSchema(PackageSmokePayloadSchema), // NOT mcpExposed: the engine is a CLI-injected subprocess orchestrator // (runPackageSmoke spawns pnpm pack/install/tar/node, mutating a scratch tree); // terminal-streaming, like gauntlet/ship, so cli-only by design. annotations: { readOnly: true, cliOnly: true, group: 'castoff' }, }, handler: async (_invocation, context: CommandContext): Promise => { // Direct-invocation guard; the dispatcher already enforces `requires`. if (!context.runPackageSmoke) return capabilityUnavailable('package-smoke', ['runPackageSmoke']); const summary = await context.runPackageSmoke(); return { status: summary.ok ? 'ok' : 'failed', command: 'package-smoke', timestamp: new Date(wallClock.now()).toISOString(), exitCode: summary.ok ? 0 : 1, payload: { ok: summary.ok, packagesPacked: summary.packagesPacked, importsSmoked: summary.importsSmoked, failedStep: summary.failedStep, failure: summary.failure, } satisfies PackageSmokePayload, }; }, };