Repository navigation
refactor: the 2.0 pre-release fixes — one home per concept, one portal gate, one project layout - #374
Merged
Merged
Conversation
The first of the three pre-release fix batches in .ai/plans/release-2.0-fixes.md. Behavior-preserving consolidations: - The apimatic.json `languages` block gets one module, types/apimatic-config/languages-block.ts: its types, the entry builder, the merge, `isPublished`, and a lenient reader for the portal whose keys are checked against the typed shape, so a rename fails tsc instead of reading nothing. - TIMING_DEFAULTS and GenerationTimings live once, in the generation poller. - FileService.readFile and its only caller, the unused hasContent, are gone. - `_shell.html`, `404.html` and `portal.zip` are each named once, in portal-context. - code-samples uses the shared languageLabel. - The registry package-name fields are typed against the package configurations. - Prompts name apimatic.json and nav.json by their constants, the artifacts reader uses FileName, and DirectoryPath.fromUserInput replaces three copies of trim-and-unquote. - Riders: prompt.md says log.warn, and PortalSourceContext's doc comment uses the glossary's "source directory". Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…onfig.json, and a tested save The second pre-release fix batch in .ai/plans/release-2.0-fixes.md: - The runtime and authorization checks move into PreparePortalProjectAction, which both portal generate and portal serve run; the copies and their prompt wrappers go. Serve probes its port once the project is prepared, beside the server that uses it, so no fallback-port message precedes an authorization refusal. - portal.config.json is typed on both sides (PortalBuildPaths in the CLI, BuildPaths in the template, which renames its PortalConfig) and held to one shape by the same Equal<> test that guards the identity file. portal.server.ts casts once. - validation-service: the strip failure is a real ServiceError, so its message prints instead of `undefined`; validateViaFile closes its read stream in a finally. - The dev server strips colour codes with node:util's stripVTControlCharacters. - PortalContext.save, the staged replace of the portal directory, gets its first tests: staging failure keeps the previous portal, a failed swap keeps the staged copy. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The third pre-release fix batch in .ai/plans/release-2.0-fixes.md, and the redo of PR #372's intent on current dev: - ProjectContext absorbs BuildContext, which is deleted. ProjectContext.at(input) and ProjectContext.in(directory) are the only ways in; commands and actions take the project, and no caller joins `src`, `sdk`, `portal` or `plugin` onto anything. - A versioned build narrows the project to one version instead of threading a { version, buildContext } pair, or an ActionResult, out of a closure: versionToBuild() answers the project to build from or a problem the prompts name, and the three getters that shared one preamble are one walk. - The layout's names live once, in types/project-layout.ts. GENERATED, the .gitignore entries, derives from the output names; PortalSourceContext and the prompts read the source directory's children from there. - The portal fixtures are real projects, their contents under src/. - ProjectContext gets the unit tests BuildContext never had: the layout, the versioned walk, the destination overrides. - context.md records the narrowed exception for a layout context; command.md and action.md scaffold with ProjectContext. No behavior changes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…art stopped Quickstart on main stripped a spec's unallowed features through ValidationService.stripUnallowedFeatures; #363 removed that call, and decided in review, the pruning does not come back. So the method goes, with parseErrorResponse and FeaturesToRemove, and so does what only fed it: validateViaFile no longer decodes the x-unallowed-features header, UnallowedFeaturesResponse, RemovableFeature and the ValidateApiResponse wrapper go, and ValidateAction returns a plain ActionResult, whose value nothing read. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The batches added multi-line doc blocks that restated the code or narrated its design, against the one-line-of-why rule. Those go; what stays is a constraint the code cannot show, such as the server's 25-minute limit behind the 30-minute timeout, or why /plugin/ must stay untracked. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…rojectContext PR #372's review asked for Project and BuildContext to be deleted in favour of ProjectContext alone. Quickstart's Project record still carried a raw project directory beside a ProjectContext, so the wizard now runs as its two flows, adopting a downloaded project or starting one, which finish the same way. The checks that a destination is not the source move into ProjectContext as isSourceDirectory() and isSourceWithin(), so sourceDirectory() serves only prompts and services, and context.md's exception says that. Also from the review: the version problems reach one prompt keyed by problem, which drops the non-Error throw SonarCloud flagged, along with its two smaller findings; and validateViaFile opens its stream inside the try again. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
This was referenced Sep 25, 2026
|
🎉 This PR is included in version 2.0.0-beta.1 🎉 The release is available on: Your semantic-release bot 📦🚀 |
This was referenced Sep 29, 2026
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.



Summary
These are the pre-release fixes from the 2.0 release review, planned in
.ai/plans/release-2.0-fixes.md(added here). The review found no must-fix defects, but it did find concepts living in more than one place, a duplicated gate, an unguarded contract, and one recovery path with no tests. There are six commits: one per batch, one for a decision made in review, and two that answer a review of this PR. Each builds and passes the suite on its own. The plan's §3.8, §4.6 and §5.6 record where each commit departed from the plan.1. One home per concept (
fec7109d)languagesblock ofapimatic.jsonnow has one module,types/apimatic-config/languages-block.ts. It holds the types, the entry builder, the merge,isPublished, and the portal's lenient reader. That reader names every key against its type, so a rename failstscinstead of making the portal read nothing without any error.language-entry.tsis gone, andrecord-published-sdk.tsis back to just the action class.TIMING_DEFAULTS/GenerationTimingsare defined once, in the generation poller, instead of once per service.FileService.readFileis gone. It duplicatedgetContents, and its only caller,hasContent, was itself unused._shell.html,404.htmlandportal.zipare each named once, inportal-context.ts.languageLabel:code-samples.tsuses the shared function.apimatic.jsonandnav.jsonby their constants.DirectoryPath.fromUserInput()replaces three hand-rolled trim-and-unquote copies.2. Portal flow polish (
c1f95a9d)PreparePortalProjectAction, which both commands run, and the copies go. Serve now probes its port once the project is prepared, so no fallback-port message appears before an authorization refusal.portal.config.jsonis typed on both sides:PortalBuildPathsin the CLI, andBuildPathsin the template, which renames itsPortalConfig. The sameEqual<>test that guards the identity file now holds the two to one shape.validation-service:validateViaFilecloses its stream in afinally.node:util'sstripVTControlCharacters.PortalContext.savegets its first tests (10 cases). A staging failure keeps the previous portal; a failed swap keeps the staged copy and says where it is.3. One place that knows a project's layout (
c5c55c36)This redoes the intent of #372 on current
dev.ProjectContextabsorbsBuildContext, which is deleted.ProjectContext.at(input)andProjectContext.in(directory)are the only ways to get one. Commands and actions take the project, and no caller joinssrc,sdk,portalorpluginonto a path anymore.versionToBuild()returns either the project to build from or a problem for the prompts to name. It replaces the closure that returned{ version, buildContext }or anActionResult, and the three getters that shared one preamble are now a single walk.types/project-layout.ts.GENERATED, the list of.gitignoreentries, is derived from the output names.src/.ProjectContexthas the unit testsBuildContextnever had, covering the layout, the versioned walk and the destination overrides.No behavior changes.
4. Drop the spec pruning nothing calls (
7b7b7d82)On
main, quickstart usedValidationService.stripUnallowedFeaturesto strip spec features the subscription doesn't allow. #363 removed that call, and review decided the pruning does not come back. This commit deletes the method, along withparseErrorResponseandFeaturesToRemove, which existed only for it. It also removes what only fed the pruning:validateViaFileno longer decodes thex-unallowed-featuresheader;UnallowedFeaturesResponse,RemovableFeatureand theValidateApiResponsewrapper go;ValidateActionreturns a plainActionResult, since nothing read its value.5. Only the comments the code cannot say (
ba90b550)The batches added multi-line doc blocks that restated the code or narrated its design, against the one-line-of-why rule. They are cut to one line or removed. What stays is a constraint the code cannot show, such as the server's 25-minute limit behind the 30-minute timeout, or why
/plugin/must stay untracked.6. Delete quickstart's
Project, and keep the source checks inProjectContext(f22c2fc3)Projectrecord is gone. This finishes refactor: one place that knows a project's layout #372's "Project and BuildContext need to be deleted". The wizard runs as its two flows, adopting a downloaded project or starting a new one, which finish the same way. Each flow makes itsProjectContextonce.ProjectContext.isSourceDirectory()andisSourceWithin()replace six hand-written comparisons.sourceDirectory()now serves only prompts and services, andcontext.md's exception says so.Errorthrow. The two smaller findings are fixed too.validateViaFileopens its stream inside thetryagain. A path Node refuses outright, such as one containing a NUL byte, is reported instead of thrown.No other behavior changes. Prompt text and order are the same, and a new test pins both version messages.
Decided in review
--destinationgap is deferred to its own ticket (plan §5.2, step 9).plugin generate --destinationcan write to a directory.gitignoredoesn't list, and thegit initthatplugin publishthen prints would nest one repository inside another. It isn't a regression, sincemainhas no.gitignorehandling at all, and the fix changes behavior, so it needs its own design.main:SdkPublishActionzipsoutputDirectory/<language>, re-derivingSdkContext's layout, while a versioned project writes its SDK one level deeper.Test plan
pnpm buildpnpm lintpnpm test: 1389 passing, 0 failing (38 pending, unchanged)APIMATIC_E2E=1portal build: 37 passing, two real Vite builds on the moved fixturesplugin publish --input <fixture>andsdk generate --input … --destination <src>resolve the project as before🤖 Generated with Claude Code