Closes DOCS-AUDIT §2.3.
The cube contract says each schema field is `.describe()`d and that the
description is the prompt label. Whether it was depended on the order the
manifest happened to chain in: zod 4 keys a description to the schema
*instance* and `.default()` returns a new `ZodDefault` around the described
type rather than mutating it, so the wrapper carries no description of its own
and the prompt, reading the outer node, fell back to the bare key.
z.boolean().describe('Update package cache').default(false) -> 'UPDATE'
z.boolean().default(false).describe('Update package cache') -> the sentence
15 of the 22 core cubes are written the first way, so most prompts showed a key.
`promptLabel()` walks down through `default` / `optional` / `nullable` looking
for a description, which makes the two orders equivalent — the answer that
cannot regress, where re-ordering every manifest and hoping the next one written
gets it right can. It discriminates on `zodKind`, not `instanceof`, for the
reason recorded on that helper: a manifest built by a different zod copy fails
every `instanceof` in the module.
The mocked test asserts all four shapes, including a doubly-wrapped
`describe().optional().default()` and a field with no description at all. The
pty test is the one that carries the weight: its probe schema is written in the
losing order, and it now waits for `First value` on a real enquirer render, so
removing the unwrapping fails a test that talks to an actual terminal rather
than to a mocked `Form`.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DCzYTAm9QUhvLNr2EpdagJ
ansiblings
Infrastructure tooling monorepo: two published CLIs plus the pyinfra "cubes" they deploy.
| Path | Package | Binary | What it is |
|---|---|---|---|
packages/nopy |
@bitsquare/nopy |
nopy |
interactive pyinfra script management and execution |
packages/keyman |
@bitsquare/keyman |
keyman |
SSH key management with age encryption |
packages/nopy-cubes |
@bitsquare/nopy-cubes |
— | the authoring surface a cube's manifest.mjs imports |
packages/nopy-cubes-core |
@bitsquare/nopy-cubes-core |
— | the core bundle of deployment units nopy runs |
npm install -g @bitsquare/nopy @bitsquare/keyman
See each package's README for usage, and README.PUBLISH.md for how they get published.
Development
Requires Node ≥ 22 (the repo pins 24 in .nvmrc) and pnpm — the version is
pinned by packageManager, so corepack enable is enough.
pnpm install
| Command | Does |
|---|---|
pnpm run build |
compiles both packages with tsc |
pnpm run typecheck |
tsc --build across the workspace (see below) |
pnpm run lint |
Biome check |
pnpm run lint:fix |
Biome check with fixes applied |
pnpm test |
vitest, both packages |
pnpm run test:coverage |
vitest with the coverage gate |
pnpm run coverage:summary |
renders the last coverage run as a Markdown table |
typescript is on the 7.x native compiler, so tsc is the fast one — there is
no separate tsgo binary to keep in sync. typecheck is plain tsc --build,
not --noEmit: once a project has references, TypeScript rejects --noEmit
outright (TS6310), because a composite project has to emit the declarations its
dependents read. So the typecheck writes dist as a side effect — gitignored,
and it means the gate also proves the build works. Each package also has a dev-run script
(pnpm --filter @bitsquare/nopy run nopy) that executes the TypeScript sources
directly through tsx.
Git hooks
Installed by simple-git-hooks on pnpm install, configured in the root
package.json:
- pre-commit — Biome check with fixes, on staged files only, re-staging what it fixed. Fast; blocks only on problems it cannot fix itself.
- pre-push —
lint:ci→typecheck→test:coverage. This is the same gate CI runs, so a push that survives it will not surprise you on the runner.
Set SKIP_SIMPLE_GIT_HOOKS=1 to bypass either one; re-install them after
changing the config with pnpm exec simple-git-hooks.
Coverage
Both packages hold a hard 85 % branch floor, enforced by
coverage.thresholds in their vitest.config.ts rather than by a CI-only flag —
pnpm run test:coverage fails the same way locally, in the pre-push hook, and
on the runner. Barrel files and CLI argv wiring are excluded; everything with
behaviour in it is not.