Skip to content

feat: programmatic entry point for generate, check and build - #154

Merged
PhilDL merged 3 commits into
mainfrom
feat/library-entry-point
Aug 30, 2026
Merged

PhilDL merged 3 commits into
mainfrom
feat/library-entry-point

Conversation

@PhilDL

@PhilDL PhilDL commented Aug 29, 2026

Copy link
Copy Markdown
Contributor

Closes #153.

import { generate, check, build } from "balade" runs the three commands from a script or a CI job without a terminal.

What changed

  • src/library.ts — a second root beside cli.ts: generate, check, build as promises, with Effect variants (generateWalkthrough, checkWalkthrough, buildWalkthrough) and one exported liveLayer (Node services, process executor, Pi author adapter, context resolver — no terminal, browser or presence). The layer is provided per call, so a finished call leaves no handle open and a script exits on its own.
  • No prompts. resolveAgentModel (agent/model.ts) matches an explicit { providerId, modelId } or the saved preference and fails typed — AgentModelUnresolved listing the available models, or NoProviderAuthenticated — never logging in or rewriting the preference. An existing same-head walkthrough fails ExistingWalkthroughUndecided naming the files; force: true replaces it, keeping the .superseded copy. PullTargetInvalid and PresetUnknown cover the other two pre-flight refusals. Local checks fail before the pull-request head is fetched.
  • headInstructions defaults to "omit-changed"; "trust-changed" is the explicit opt-in (threat model updated).
  • onProgress receives the pipeline's GenerationProgress events unfiltered; the test replays them through the CLI's terminal renderer.
  • Rejections are the tagged errors themselves (_tag, fields, instanceof) with the CLI's sentence attached as message at the library boundary. The result is the CLI's GenerationResult plus the pull-request notices the command prints as warnings.
  • Packagingpackage.json gains an exports map; the build emits declarations. One explicit return type in pi/inspection.ts keeps Pi's typebox parameter types out of the .d.ts.
  • Teststest/library.test.ts runs the library through Pi's faux author on a real fixture clone (default policy → refused replacement → forced replacement, model resolution, promise rejection, check and build). The Pi harness moves to test/support/pi.ts, shared with generate.test.ts. The architecture test learns the second root and asserts nothing imports either entry. The npm smoke test type-checks and runs a consumer against the packed tarball, including that the process exits.
  • CLI generate/check/build are untouched apart from reading the default output directory from a shared constant; existing CLI tests pass without edits.

Why the CLI is not a literal wrapper over generate()

Its replace prompt and model picker sit between the pre-flight and the paid turn, and the library refuses prompts. Both compose the same functions (parsePrTarget, resolvePullHead, inspectExistingWalkthroughs, planSupersession, runGeneration); the CLI's interactive glue stays in commands/generate/index.ts. Recorded in DECISIONS.md, along with the pkg.pr.new --previewVersion trigger this creates (workflow left alone).

Verified at the real seam

Against this repository with the built dist/library.js: a wrong model id rejects AgentModelUnresolved in ~1s listing the authenticated models, check returns the report for an existing walkthrough, and the process exits without process.exit.

Not exercised here: a paid generate() end to end — the faux author covers the pipeline; the model call itself is the same code path the CLI runs.

https://claude.ai/code/session_01QiAQotDRMwQigFYV9NXv5i

`import { generate, check, build } from "balade"` runs the three commands
from a script or a CI job without a terminal. `src/library.ts` is a second
root beside `cli.ts`: the same pipelines (`runGeneration`, `checkOne`,
`runBuild`) over one `liveLayer` — Node services, the process executor, the
Pi author adapter and the context resolver — provided per call so a finished
call leaves nothing keeping the process alive.

The pre-flight answers the command's two questions with typed errors instead
of prompts: `resolveAgentModel` (agent/model.ts) matches an explicit
`{ providerId, modelId }` or the saved preference and fails
`AgentModelUnresolved` listing what is available or `NoProviderAuthenticated`,
never logging in or rewriting the preference; an existing same-head
walkthrough fails `ExistingWalkthroughUndecided` naming the files unless
`force: true`. `headInstructions` defaults to `omit-changed`. `onProgress`
receives the pipeline's events unfiltered — the terminal renderer is one
consumer of them. Rejections are the tagged errors themselves with the CLI's
sentence attached as `message`.

The build now emits declarations and package.json gains an `exports` map;
one explicit return type in pi/inspection.ts keeps Pi's typebox parameter
types out of the `.d.ts`. The npm smoke test type-checks and runs a consumer
against the packed tarball; the architecture test learns the second root and
asserts nothing imports either entry. The Pi faux harness moves to
test/support/pi.ts so the library test shares it.

Closes #153

Claude-Session: https://claude.ai/code/session_01QiAQotDRMwQigFYV9NXv5i
@pkg-pr-new

pkg-pr-new Bot commented Aug 29, 2026

Copy link
Copy Markdown
npx https://pkg.pr.new/basaltbytes/balade@154

commit: d9e13b9

PhilDL added 2 commits August 29, 2026 12:44
…elling

Windows resolves the fixture's temp directory to an 8.3 short name
(RUNNER~1) through realpathSync while git reports the long one; the
assertion now checks the file lands under the clone's requested directory.

Claude-Session: https://claude.ai/code/session_01QiAQotDRMwQigFYV9NXv5i
… their errors

Review pass on the library entry. `notices` now rides in the pipeline's
GenerationSummary, so `generate` returns GenerationResult unchanged instead of
an intersection type over the union. The agent-model message functions move
from agent/terminal.ts to agent/model.ts, beside the errors they describe:
the library no longer imports the interactive adapter for three sentences.
The Pi test harness takes an options object instead of positional flags.

Claude-Session: https://claude.ai/code/session_01QiAQotDRMwQigFYV9NXv5i
@PhilDL
PhilDL merged commit 1275a0b into main Aug 30, 2026
8 checks passed
@PhilDL
PhilDL deleted the feat/library-entry-point branch August 30, 2026 10:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Programmatic entry point for generate, check and build

1 participant