feat: programmatic entry point for generate, check and build - #154
Merged
Merged
Conversation
`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
commit: |
…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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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 besidecli.ts:generate,check,buildas promises, with Effect variants (generateWalkthrough,checkWalkthrough,buildWalkthrough) and one exportedliveLayer(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.resolveAgentModel(agent/model.ts) matches an explicit{ providerId, modelId }or the saved preference and fails typed —AgentModelUnresolvedlisting the available models, orNoProviderAuthenticated— never logging in or rewriting the preference. An existing same-head walkthrough failsExistingWalkthroughUndecidednaming the files;force: truereplaces it, keeping the.supersededcopy.PullTargetInvalidandPresetUnknowncover the other two pre-flight refusals. Local checks fail before the pull-request head is fetched.headInstructionsdefaults to"omit-changed";"trust-changed"is the explicit opt-in (threat model updated).onProgressreceives the pipeline'sGenerationProgressevents unfiltered; the test replays them through the CLI's terminal renderer._tag, fields,instanceof) with the CLI's sentence attached asmessageat the library boundary. The result is the CLI'sGenerationResultplus the pull-requestnoticesthe command prints as warnings.package.jsongains anexportsmap; the build emits declarations. One explicit return type inpi/inspection.tskeeps Pi's typebox parameter types out of the.d.ts.test/library.test.tsruns 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 totest/support/pi.ts, shared withgenerate.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.generate/check/buildare 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 incommands/generate/index.ts. Recorded in DECISIONS.md, along with the pkg.pr.new--previewVersiontrigger this creates (workflow left alone).Verified at the real seam
Against this repository with the built
dist/library.js: a wrong model id rejectsAgentModelUnresolvedin ~1s listing the authenticated models,checkreturns the report for an existing walkthrough, and the process exits withoutprocess.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