Skip to content

chore: apply ultracite fixes and harden README generation/tests#2

Merged
BurnedChris merged 12 commits intomainfrom
ultracite
Feb 19, 2026
Merged

chore: apply ultracite fixes and harden README generation/tests#2
BurnedChris merged 12 commits intomainfrom
ultracite

Conversation

@BurnedChris
Copy link
Copy Markdown
Contributor

@BurnedChris BurnedChris commented Feb 19, 2026

This PR resolves Ultracite/lint-driven issues and aligns related code quality improvements across CLI, config merging, README generation, and tests.

  • Defers workspace root resolution to command runtime in generate:workspace.
  • Reorders Effect.tryPromise fields for consistency/readability.
  • Improves invocation handling with explicit mode checks and fail-fast behavior.
  • Replaces sync filesystem checks with async pathExists and fixes workspace failure reporting to use full project paths.
  • Improves README template behavior by generating unique TOC slugs and removing unnecessary object copies.
  • Strengthens tests with safer temp-dir cleanup, clearer assertion diagnostics, and added invocation branch coverage.
  • Includes test files in TypeScript typechecking and updates example/config formatting consistency.

… bun.lock

- Introduced .oxfmtrc.jsonc for oxfmt configuration to standardize code formatting.
- Added .oxlintrc.json for oxlint configuration, extending core linting rules.
- Updated package.json to include new scripts for formatting and linting, and added dependencies for oxfmt and oxlint.
- Modified bun.lock to reflect the addition of oxfmt and oxlint packages and their bindings for various platforms.
- Configured lefthook for pre-commit checks to run formatting automatically on specified file types.
- Modified .oxfmtrc.jsonc to include a trailing comma for consistency.
- Simplified .oxlintrc.json by removing unnecessary array brackets.
- Enhanced package.json with additional metadata including keywords, homepage, bugs, license, author, and repository details.
- Ensured proper formatting and structure in various JSON files for improved readability and maintainability.
- Updated bun.lock to use "latest" versions for all dependencies, ensuring compatibility with the latest features and fixes.
- Modified package.json to reflect updated versions for several packages, including @changesets and typescript.
- Enhanced tsconfig.json with new compiler options for better module resolution and stricter type checking.
- Added import paths in package.json and tsconfig.json for improved module management.
- Refactored import statements in source files to utilize the new path aliases, improving code readability and maintainability.
- Updated README and test files to align with the new configuration and ensure proper functionality.
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Feb 19, 2026

Caution

Review failed

The pull request is closed.

📜 Recent review details

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between f44d702 and 28d4b2b.

📒 Files selected for processing (1)
  • src/config/load-config.ts

📝 Walkthrough

Summary by CodeRabbit

  • New Features

    • Table of contents and custom section support in generated READMEs
  • Improvements

    • Smarter placeholder interpolation across global and project configs
    • More robust workspace discovery with optional project filtering
    • Centralized command execution with unified error handling
    • Improved README generation (stable output, fewer unnecessary writes)
  • Chores

    • Added formatting, linting, pre-commit, and test runner configs; updated package metadata and developer scripts

Walkthrough

Refactors CLI control flow into a centralized main, replaces Node fs/path with fs-extra/pathe across CLI, config loader, and README generator, adds formatting/linting/test tooling and configs, restructures config merging/interpolation, updates TS and package metadata, and applies widespread formatting/style changes.

Changes

Cohort / File(s) Summary
Tooling & CI
/.oxfmtrc.jsonc, /.oxlintrc.json, /.github/workflows/release.yml, lefthook.yml, vitest.config.ts, .changeset/neat-rabbits-clap.md
Add Oxfmt/Oxlint and Vitest configs, Lefthook pre-commit hook, a changeset entry; tiny quoting tweak in GH release workflow.
Package Manifest
package.json
Rework dependencies/devDependencies, add imports alias #src/*, expand/reorder scripts and metadata.
TypeScript Config
tsconfig.json
Replace with ESNext/bundler-focused config, add #src/* path mapping, enable allowJs and include tests.
CLI Entrypoint & Routing
src/index.ts, src/cli/resolve-invocation.ts, src/cli/help.ts
Centralize invocation handling into main/selectCommandEffect, add modeFromToken routing, unified error handling; minor help formatting.
CLI Commands
src/cli/commands/generate.ts, src/cli/commands/generate-workspace.ts, src/cli/commands/init.ts
Migrate I/O to fs-extra/pathe, convert to named generator handlers, reorder/standardize option definitions and internal wiring.
Config Loading
src/config/load-config.ts, src/config/types.ts, src/config/starter-config.ts
Replace Node fs/path with fs-extra/pathe; add interpolation placeholders, merging helpers for customSections, improved error causes, and refactored schema/setup.
README Generator & Template
src/readme-generator/generator.ts, src/readme-generator/template.ts
Refactor to async/await, add loadMergedConfig/resolveOutputPath/resolvePackageName, modularize template rendering (sections, TOC, slug uniqueness, normalize/append helpers).
Schemas & Examples
schemas/readie.*.json, readie.json, examples/*/readie.json, README.md, examples/*/README.md, examples/*/old.md
Widespread formatting/indentation/quoting-only changes across schemas, examples, and README snippets; no semantic changes.
Tests
test/*.test.ts, test/generator-global-interpolation.test.ts, test/merge-config.test.ts, test/resolve-invocation.test.ts, test/template.test.ts, test/validate-config.test.ts
Switch tests to fs-extra/pathe/tempy, use path-alias imports, consolidate fixtures and update assertions/descriptions.
Project Hooks
lefthook.yml
Add pre-commit hook to run bun x ultracite fix on matched files.

Sequence Diagram(s)

sequenceDiagram
  participant CLI as "CLI (process)"
  participant Resolver as "resolveInvocation"
  participant Router as "selectCommandEffect"
  participant Command as "Command Handler\n(generate/init/workspace)"
  participant Config as "loadMergedConfig / loadReadieConfig"
  participant FS as "fs-extra / pathe"

  CLI->>Resolver: parse argv
  Resolver->>Router: return { mode, args, isHelp }
  Router->>Command: dispatch by mode
  Command->>Config: load and merge configs
  Config->>FS: pathExists / readFile
  FS-->>Config: file content / not found
  Config-->>Command: merged config
  Command->>FS: read existing README / write new README
  FS-->>Command: write result
  Command-->>CLI: exit status / logs
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • Template injection #1: Overlapping changes to README templating, interpolation helpers, and generator/config merge logic.

Poem

🐇 I hopped through paths and swapped the fs,
Aliased imports, made templates less of a mess.
Configs now merge, TOCs find their name,
Tests wake and run — commits feel the same.
Little rabbit cheers — formatting, hip-hip-hurrah!

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: applying ultracite fixes (code formatting/linting) and improving README generation with better tests.
Description check ✅ Passed The description is directly related to the changeset, detailing specific improvements made across CLI, config, README generation, and tests that align with the ultracite formatting changes visible in the diff.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch ultracite

Comment @coderabbitai help to get the list of available commands and usage tips.

- Deleted AGENTS.md, reference.md, SKILL.md, and index files for JSDoc and TSDoc authoring as they are no longer needed.
- This cleanup helps streamline the documentation structure and removes redundant content.
…ency

- Updated .oxfmtrc.jsonc, .oxlintrc.json, and package.json to use consistent indentation and formatting styles.
- Enhanced readability by aligning JSON properties and values.
- Made minor adjustments to other configuration files to maintain uniformity across the project.
- Added missing "license" and "author" fields for better project documentation.
- Reorganized properties to improve clarity, including restoring "type", "main", and "imports" fields.
- Ensured consistent formatting and structure for improved readability.
- Introduced a new type `TocTitleEntry` for better type safety in table of contents title entries.
- Updated the `createTocTitles` function to filter out empty sections and return only visible titles.
- Adjusted the `createTocBlock` function to accept the new type for improved clarity and maintainability.
- Introduced vitest.config.ts to define testing configuration.
- Enabled global test options for improved test management and consistency.
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 16

📜 Review details

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 6c27e4d and e9ca159.

⛔ Files ignored due to path filters (1)
  • bun.lock is excluded by !**/*.lock
📒 Files selected for processing (31)
  • .github/workflows/release.yml
  • .oxfmtrc.jsonc
  • .oxlintrc.json
  • README.md
  • examples/basic/README.md
  • examples/basic/readie.json
  • examples/c15t/README.md
  • examples/c15t/old.md
  • lefthook.yml
  • package.json
  • readie.json
  • schemas/readie.global.schema.json
  • schemas/readie.schema.json
  • src/cli/commands/generate-workspace.ts
  • src/cli/commands/generate.ts
  • src/cli/commands/init.ts
  • src/cli/help.ts
  • src/cli/resolve-invocation.ts
  • src/config/load-config.ts
  • src/config/starter-config.ts
  • src/config/types.ts
  • src/index.ts
  • src/readme-generator/generator.ts
  • src/readme-generator/template.ts
  • test/generator-global-interpolation.test.ts
  • test/merge-config.test.ts
  • test/resolve-invocation.test.ts
  • test/template.test.ts
  • test/validate-config.test.ts
  • tsconfig.json
  • vitest.config.ts
🧰 Additional context used
🧬 Code graph analysis (13)
test/validate-config.test.ts (1)
src/config/load-config.ts (1)
  • loadReadieConfig (114-129)
src/index.ts (5)
src/cli/commands/generate.ts (1)
  • generateCommand (20-65)
src/cli/commands/generate-workspace.ts (1)
  • generateWorkspaceCommand (19-90)
src/cli/commands/init.ts (1)
  • initCommand (13-55)
src/cli/resolve-invocation.ts (1)
  • resolveInvocation (34-43)
src/cli/help.ts (1)
  • printRootHelp (1-23)
test/generator-global-interpolation.test.ts (1)
src/readme-generator/generator.ts (1)
  • generateReadmeFromConfig (86-118)
src/config/starter-config.ts (1)
src/config/types.ts (1)
  • ReadieConfig (24-49)
test/template.test.ts (1)
src/readme-generator/template.ts (1)
  • baseReadmeTemplate (246-281)
src/readme-generator/generator.ts (3)
src/config/load-config.ts (3)
  • loadReadieConfig (114-129)
  • loadGlobalConfig (148-165)
  • mergeConfigs (293-355)
src/config/types.ts (4)
  • GenerateSingleOptions (53-58)
  • GenerateSingleResult (60-63)
  • GenerateWorkspaceResult (73-78)
  • GenerateWorkspaceOptions (65-71)
src/readme-generator/template.ts (1)
  • baseReadmeTemplate (246-281)
test/merge-config.test.ts (2)
src/config/types.ts (2)
  • ReadieConfig (24-49)
  • ReadieGlobalConfig (51-51)
src/config/load-config.ts (1)
  • mergeConfigs (293-355)
src/cli/commands/init.ts (1)
src/config/starter-config.ts (1)
  • starterConfigText (18-18)
test/resolve-invocation.test.ts (1)
src/cli/resolve-invocation.ts (1)
  • resolveInvocation (34-43)
src/cli/commands/generate.ts (1)
src/readme-generator/generator.ts (1)
  • generateReadmeFromConfig (86-118)
src/config/load-config.ts (1)
src/config/types.ts (2)
  • ReadieConfig (24-49)
  • ReadieGlobalConfig (51-51)
src/cli/commands/generate-workspace.ts (1)
src/readme-generator/generator.ts (2)
  • generateWorkspaceReadmes (198-235)
  • parsePackageList (25-36)
src/readme-generator/template.ts (1)
src/config/types.ts (3)
  • ReadieBadge (11-15)
  • ReadieConfig (24-49)
  • ReadieLicenseObject (17-20)
🔇 Additional comments (24)
.oxlintrc.json (1)

1-4: LGTM!

The Oxlint configuration properly extends the Ultracite core configuration with a valid local schema reference.

.github/workflows/release.yml (1)

34-34: LGTM!

Quote style change aligns with the project's formatting standardization.

examples/basic/readie.json (1)

1-21: LGTM!

Indentation adjustments align with the project's new formatting configuration.

src/cli/help.ts (1)

1-23: LGTM!

Indentation adjustment aligns with the project's formatting standardization.

README.md (1)

68-73: LGTM!

Indentation adjustments in the JSON code sample align with the project's formatting standardization.

examples/c15t/old.md (1)

76-86: LGTM!

Code sample formatting updated to use double quotes, semicolons, and consistent tab indentation, aligning with the project's new formatting standards.

vitest.config.ts (1)

1-7: Configuration is correct and properly configured.

The Vitest configuration correctly enables global test APIs. Version 4.0.18 is the current stable release as of February 2026, so no version concerns apply.

examples/c15t/README.md (1)

77-85: Formatting-only snippet update looks good.

lefthook.yml (1)

1-12: No review comments on this hook config.

readie.json (1)

2-65: Formatting-only update looks consistent.

schemas/readie.schema.json (1)

2-156: Schema formatting update looks consistent.

schemas/readie.global.schema.json (1)

2-140: Schema formatting update looks consistent.

src/config/types.ts (1)

1-78: Type declarations unchanged; formatting-only update looks good.

src/config/starter-config.ts (1)

1-16: Starter config formatting update looks good.

.oxfmtrc.jsonc (1)

1-23: No review comments on this formatter config.

src/config/load-config.ts (2)

196-209: LGTM!

The interpolateCustomSections function correctly handles the undefined case with an early return and properly iterates over entries to apply placeholder interpolation.


148-165: LGTM!

The directory traversal logic for finding the global config is correct - it walks up the directory tree using dirname and properly terminates when reaching the root (when parent === current).

test/merge-config.test.ts (1)

1-60: LGTM!

The test file provides good coverage for the mergeConfigs function:

  • Tests global placeholder interpolation including customSections
  • Verifies project-over-global precedence
  • Validates fallback behavior when packageName is unavailable

The use of a factory helper (createProjectConfig) keeps tests DRY and readable.

package.json (1)

37-39: LGTM! Subpath imports configuration.

The #src/* import mapping enables cleaner internal imports throughout the codebase, aligning with the module alias usage observed in other files.

src/cli/resolve-invocation.ts (1)

1-43: LGTM! Clean invocation resolution logic.

The refactored modeFromToken helper centralizes mode detection with clear precedence: empty token defaults to generate, help flags/commands return help, known commands are mapped, and everything else falls back to unknown. The preservation of full args for unknown mode enables better error messaging downstream.

src/index.ts (1)

56-73: LGTM! Well-structured main orchestration.

The main() function cleanly separates concerns: resolve invocation, handle help/unknown modes with appropriate exit codes, then execute the selected command with proper error handling via try/catch.

src/cli/commands/generate.ts (1)

1-65: LGTM! Clean command implementation.

The refactored generateCommand is well-structured with:

  • Clear separation of concerns via the resultStatus helper
  • Proper error normalization in Effect.tryPromise
  • Well-documented CLI options with sensible defaults
src/readme-generator/generator.ts (1)

1-9: LGTM! Clean imports with fs-extra and pathe.

The migration to fs-extra and pathe provides consistent cross-platform path handling and a cleaner async file API. The use of #src/* aliases maintains import consistency with the rest of the codebase.

src/cli/commands/generate-workspace.ts (1)

48-90: LGTM! Well-structured workspace command.

The command implementation properly:

  • Parses repeated --package options into a filter set
  • Provides comprehensive summary output
  • Respects --strict mode for CI/automation use cases
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@examples/basic/README.md`:
- Around line 31-33: The README and source config disagree on JS/TS formatting:
README shows import { createClient } from "acme-toolkit"; and const client =
createClient(); while examples/basic/readie.json contains a fenced code string
using single quotes and no semicolons; update the source config entry in
examples/basic/readie.json so the embedded code block matches the generated
README (use double quotes and trailing semicolons for import and const
statements), or if the README was edited manually, revert the README to match
the canonical readie.json content and then re-run generation; locate the fenced
code string that contains "import { createClient }" in readie.json and make the
formatting consistent.

In `@package.json`:
- Line 73: The package.json dependency list pins "ultracite" to an exact version
("7.2.3") while other dependencies use caret ranges; update the "ultracite"
entry to use a caret range (e.g., "^7.2.3") to match the project's versioning
convention so it behaves like the other dependencies and accepts compatible
minor/patch updates.

In `@src/cli/commands/generate-workspace.ts`:
- Around line 39-43: The default value for the "root" option is being computed
at module load via resolve("./packages"); change this so resolution is deferred
to command execution: remove the static resolve call from Options.withDefault in
the Options.directory(...) declaration (root) and instead, inside the command
handler for generate-workspace, check if the root option is falsy and then
compute the default by calling resolve("./packages") at runtime and assign it to
the variable used downstream; update any references that expect the option value
(e.g., reads of root in the handler or functions it calls) to use this
runtime-resolved value.

In `@src/cli/commands/init.ts`:
- Around line 39-45: The Effect.tryPromise call has its catch property before
try, hurting readability; update the object passed to Effect.tryPromise (the
call using Effect.tryPromise with try: () => writeFile(configPath,
starterConfigText, "utf8")) so that the try property comes first and the catch
property follows (preserving the existing catch logic that maps unknown to
Error), i.e., reorder properties in the Effect.tryPromise argument while keeping
writeFile, configPath, starterConfigText, and the error-mapping behavior
unchanged.

In `@src/config/load-config.ts`:
- Around line 282-285: The null/undefined check on projectCustomSections is
redundant; simplify the guard after calling readProjectCustomSections by
replacing the `projectCustomSections === null || !projectCustomSections`
condition with a single nullish check such as `projectCustomSections == null`
(or `projectCustomSections === undefined` if you prefer explicitness) and return
early; reference: variable projectCustomSections and function
readProjectCustomSections.

In `@src/index.ts`:
- Line 13: The version constant const version = "0.1.0"; in src/index.ts doesn't
match package.json ("version": "0.0.1"); update the version declaration to match
package.json or, better, remove the hardcoded const version and import the
version from package.json (e.g., require('./package.json').version or using
import) so the exported CLI/version value is always consistent with
package.json; ensure the symbol name remains version and adjust any consumers if
necessary.
- Around line 33-43: selectCommandEffect currently falls through to runInit for
any unhandled mode which can hide bugs when new InvocationMode values are added;
update selectCommandEffect to perform an exhaustive check on resolved.mode (the
return of resolveInvocation) and explicitly handle unknown values by throwing an
error or using a default-failure branch instead of implicitly calling runInit.
Locate the selectCommandEffect function and replace the final unconditional
return runInit(...) with an explicit case for "init" and an else branch that
throws a descriptive Error (including resolved.mode) so new modes fail fast;
ensure calls to runGenerate, runGenerateWorkspace, and runInit remain unchanged
for their respective modes.

In `@src/readme-generator/generator.ts`:
- Around line 206-207: Replace the synchronous existsSync check with the async
pathExists call: await pathExists(absoluteRootDir) and throw the same Error if
it returns false; update the surrounding function to be async if needed and
import pathExists from fs-extra (or the project's util) so the validation uses
the same async pattern as other calls (existsSync -> pathExists, absoluteRootDir
remains the checked variable).
- Around line 192-194: The catch block pushes a failure using the wrong value:
it sets result.failed.push({ error, projectDir: projectName }) even though a
full directory path is expected; change the pushed object to use the actual
projectDir variable (not projectName) so the failed entry stores the directory
path consistently (update the catch in the function handling README generation
where result.failed is populated to use projectDir instead of projectName).

In `@src/readme-generator/template.ts`:
- Around line 193-198: The slugifyHeading function can produce duplicate anchors
for different headings (e.g., "Setup!" and "Setup?")—update slug generation to
ensure uniqueness by tracking generated slugs and appending a numeric suffix
when collisions occur; modify slugifyHeading (or introduce a wrapper that calls
it) to maintain a Set/Map of seen slugs and return slug, slug-1, slug-2, etc. on
collisions so each heading yields a unique anchor while preserving the existing
normalization logic.
- Around line 246-248: Remove the unnecessary shallow copy in
baseReadmeTemplate: stop creating a new config variable from rawConfig (the
`config` constant) since it is never mutated, and pass `rawConfig` directly to
`createReadmeSections`; update references inside `baseReadmeTemplate` (e.g.,
remove `config: ReadieConfig = { ...rawConfig }` and use `rawConfig` in the call
to `createReadmeSections`) to simplify the function.

In `@test/generator-global-interpolation.test.ts`:
- Around line 35-51: The test "generateReadmeFromConfig with global
interpolation" leaks the temporary directory if an assertion throws because
cleanup (await remove(rootDir)) is only at the end of the test; update the test
to guarantee removal by moving cleanup into a test-level teardown (use afterEach
or afterAll) or wrap the test body with try/finally so remove(rootDir) always
runs; reference the setupFixture() call that returns rootDir and the
remove(rootDir) call so the teardown can access and delete the created directory
even when the test fails.

In `@test/resolve-invocation.test.ts`:
- Around line 1-25: Add tests to cover the remaining `help` and `unknown`
branches of resolveInvocation: call resolveInvocation with ["--help"] and with
["help"] and assert resolved.mode === "help" and resolved.commandArgs is an
empty array, and call resolveInvocation with an unrecognized token like
["invalid-command","--flag"] and assert resolved.mode === "unknown" and
resolved.commandArgs equals the original args; place these cases alongside the
existing tests in resolve-invocation.test.ts referencing the resolveInvocation
function.

In `@test/template.test.ts`:
- Around line 15-23: The test currently checks
requiredHeadings.every(...).toBeTruthy() which hides which heading is missing;
update the assertion to provide diagnostic info by either iterating
requiredHeadings and asserting each one individually (e.g.,
requiredHeadings.forEach(h => expect(markdown).toContain(h))) or compute
missingHeadings = requiredHeadings.filter(h => !markdown.includes(h)) and assert
expect(missingHeadings).toEqual([]) so the failure shows which headings are
absent; refer to the requiredHeadings array and the markdown variable in
template.test.ts when making the change.

In `@test/validate-config.test.ts`:
- Around line 7-12: The createTempFile helper currently creates a temp dir via
temporaryDirectory() but never exposes it for cleanup; modify createTempFile to
return both the created file path and the temp directory path (e.g., return {
filePath, dir }), update tests that call createTempFile to capture the dir, and
add an afterEach hook in the test suite to remove the directory (using the same
cleanup utility used in generator-global-interpolation.test.ts or fs.rm/rimraf)
so temporary directories are deleted after each test; refer to the
createTempFile helper, temporaryDirectory() call, and test-level afterEach for
where to implement this change.

In `@tsconfig.json`:
- Around line 28-33: The tsconfig.json include only covers "src/**/*.ts" so test
files (which use the "#src/*" path alias and "vitest/globals" types) are omitted
from the tsc typecheck; fix by either adding "test/**/*.ts" to the "include"
array in tsconfig.json so tests are type-checked with the same paths/types, or
create a separate tsconfig (e.g., tsconfig.test.json) that "extends":
"./tsconfig.json", adds "test/**/*.ts" to its include and (if needed) adjusts
"types" to include "vitest/globals", and point the typecheck script to that new
tsconfig.

Comment on lines +39 to +45
yield* Effect.tryPromise({
catch: (error: unknown) =>
error instanceof Error
? error
: new Error(`Failed to write config: ${String(error)}`),
try: () => writeFile(configPath, starterConfigText, "utf8"),
});
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Verify property order for Effect.tryPromise.

The catch property is placed before try in the Effect.tryPromise call. While this may work due to JavaScript object property ordering being non-deterministic for execution, the conventional order is try first, then catch for readability.

♻️ Suggested reorder for readability
 			yield* Effect.tryPromise({
-				catch: (error: unknown) =>
-					error instanceof Error
-						? error
-						: new Error(`Failed to write config: ${String(error)}`),
 				try: () => writeFile(configPath, starterConfigText, "utf8"),
+				catch: (error: unknown) =>
+					error instanceof Error
+						? error
+						: new Error(`Failed to write config: ${String(error)}`),
 			});
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
yield* Effect.tryPromise({
catch: (error: unknown) =>
error instanceof Error
? error
: new Error(`Failed to write config: ${String(error)}`),
try: () => writeFile(configPath, starterConfigText, "utf8"),
});
yield* Effect.tryPromise({
try: () => writeFile(configPath, starterConfigText, "utf8"),
catch: (error: unknown) =>
error instanceof Error
? error
: new Error(`Failed to write config: ${String(error)}`),
});
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/cli/commands/init.ts` around lines 39 - 45, The Effect.tryPromise call
has its catch property before try, hurting readability; update the object passed
to Effect.tryPromise (the call using Effect.tryPromise with try: () =>
writeFile(configPath, starterConfigText, "utf8")) so that the try property comes
first and the catch property follows (preserving the existing catch logic that
maps unknown to Error), i.e., reorder properties in the Effect.tryPromise
argument while keeping writeFile, configPath, starterConfigText, and the
error-mapping behavior unchanged.

…structure and functionality

- Changed ultracite version in package.json to use caret notation for better compatibility.
- Expanded tsconfig.json to include test files for comprehensive type checking.
- Updated README example code for consistent formatting and clarity.
- Refactored command handling in index.ts to improve error handling and maintainability.
- Adjusted default root directory in generate-workspace command for better usability.
- Enhanced error handling in init command to ensure proper configuration writing.
- Improved null checks in load-config.ts for robustness.
- Modified README generator to utilize unique slugs for table of contents entries.
- Updated tests to ensure proper cleanup and improved assertions for generated content.
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between e9ca159 and 80e6f26.

📒 Files selected for processing (12)
  • examples/basic/readie.json
  • package.json
  • src/cli/commands/generate-workspace.ts
  • src/config/load-config.ts
  • src/index.ts
  • src/readme-generator/generator.ts
  • src/readme-generator/template.ts
  • test/generator-global-interpolation.test.ts
  • test/resolve-invocation.test.ts
  • test/template.test.ts
  • test/validate-config.test.ts
  • tsconfig.json
🧰 Additional context used
🧬 Code graph analysis (9)
test/resolve-invocation.test.ts (1)
src/cli/resolve-invocation.ts (1)
  • resolveInvocation (34-43)
test/template.test.ts (1)
src/readme-generator/template.ts (1)
  • baseReadmeTemplate (254-288)
src/index.ts (5)
src/cli/commands/generate.ts (1)
  • generateCommand (20-65)
src/cli/commands/generate-workspace.ts (1)
  • generateWorkspaceCommand (19-91)
src/cli/commands/init.ts (1)
  • initCommand (13-55)
src/cli/resolve-invocation.ts (1)
  • resolveInvocation (34-43)
src/cli/help.ts (1)
  • printRootHelp (1-23)
test/validate-config.test.ts (1)
src/config/load-config.ts (1)
  • loadReadieConfig (114-129)
test/generator-global-interpolation.test.ts (1)
src/readme-generator/generator.ts (1)
  • generateReadmeFromConfig (79-111)
src/config/load-config.ts (1)
src/config/types.ts (2)
  • ReadieConfig (24-49)
  • ReadieGlobalConfig (51-51)
src/cli/commands/generate-workspace.ts (1)
src/readme-generator/generator.ts (2)
  • generateWorkspaceReadmes (191-228)
  • parsePackageList (18-29)
src/readme-generator/template.ts (1)
src/config/types.ts (3)
  • ReadieBadge (11-15)
  • ReadieConfig (24-49)
  • ReadieLicenseObject (17-20)
src/readme-generator/generator.ts (3)
src/config/load-config.ts (3)
  • loadReadieConfig (114-129)
  • loadGlobalConfig (148-165)
  • mergeConfigs (293-355)
src/config/types.ts (4)
  • GenerateSingleOptions (53-58)
  • GenerateSingleResult (60-63)
  • GenerateWorkspaceResult (73-78)
  • GenerateWorkspaceOptions (65-71)
src/readme-generator/template.ts (1)
  • baseReadmeTemplate (254-288)
🔇 Additional comments (14)
examples/basic/readie.json (1)

2-20: Formatting-only change looks fine.
No functional impact observed in the example config.

tsconfig.json (1)

2-33: No review notes for this segment.

test/validate-config.test.ts (1)

7-42: Cleanup logic looks good.
The temp directory is reliably removed even when assertions fail.

package.json (1)

2-75: No review notes for this segment.

src/readme-generator/generator.ts (1)

79-111: Readme generation flow looks consistent.

test/template.test.ts (1)

15-25: Assertion improvement looks good.

src/readme-generator/template.ts (1)

177-179: The quickStart type is already properly aligned. The type is defined as string in ReadieConfig (src/config/types.ts:40), the schema validates it as a string (src/config/load-config.ts:54), and it is correctly used as a string in renderHeadingBlock() (src/readme-generator/template.ts:178). There is no type mismatch to fix.

Likely an incorrect or invalid review comment.

test/generator-global-interpolation.test.ts (2)

7-33: Fixture setup is clear and deterministic.

Helper cleanly builds the temp workspace and writes configs for the test scenario.


35-53: Robust cleanup via try/finally.

Ensures temp directory removal even when assertions fail.

test/resolve-invocation.test.ts (1)

1-43: Expanded routing coverage looks solid.

The added help/unknown cases round out the mode matrix nicely.

src/cli/commands/generate-workspace.ts (2)

19-71: Command wiring and runtime resolution are consistent.

The options map and handler invocation flow look correct.


73-85: Summary reporting remains clear and actionable.

Exit code handling for strict mode is preserved.

src/index.ts (2)

13-46: Dispatch logic is now explicit and safe.

Unsupported modes correctly fail fast instead of falling through.


48-76: Centralized error handling and main flow are solid.

Help/unknown handling and error exit codes are clear.

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/config/load-config.ts`:
- Around line 270-290: In resolveMergedCustomSections, avoid spreading undefined
globalCustomSections (and projectCustomSections) by guarding or defaulting them
to empty objects before merging: when building the return value in
resolveMergedCustomSections, use a safe coalesce for globalCustomSections and
projectCustomSections (e.g., treat undefined/null as {}) so the spread operation
never receives undefined; keep the existing early-return when
projectCustomSections is null/undefined if that behavior is intended, otherwise
return the merged object using (globalCustomSections ?? {}) and
(projectCustomSections ?? {}) to produce a stable plain-object result.

@BurnedChris BurnedChris changed the title Ultracite chore: apply ultracite fixes and harden README generation/tests Feb 19, 2026
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

📜 Review details

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 80e6f26 and f44d702.

📒 Files selected for processing (1)
  • .changeset/neat-rabbits-clap.md
🧰 Additional context used
🪛 LanguageTool
.changeset/neat-rabbits-clap.md

[grammar] ~5-~5: Ensure spelling is correct
Context: --- "readie": patch --- Added ultracte to readie

(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)

🪛 markdownlint-cli2 (0.21.0)
.changeset/neat-rabbits-clap.md

[warning] 5-5: First line in a file should be a top-level heading

(MD041, first-line-heading, first-line-h1)

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.changeset/neat-rabbits-clap.md:
- Line 5: In the changeset entry in .changeset/neat-rabbits-clap.md replace the
misspelled token "ultracte" with the correct spelling "ultracite" so the
sentence reads "Added ultracite to readie"; update only that word in the
changeset content.
- Around line 1-5: This changeset file has only YAML frontmatter and no H1,
triggering markdownlint rule MD041; open .changeset/neat-rabbits-clap.md and add
a top‑level heading line (e.g., "# Changes" or "# neat-rabbits-clap")
immediately after the frontmatter closing --- so the file contains frontmatter
followed by an H1 and then the existing body ("Added ultracte to readie").

Comment on lines +1 to +5
---
"readie": patch
---

Added ultracte to readie
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Add a top‑level heading to satisfy MD041.

markdownlint requires a first‑line H1; this file starts with frontmatter only. Add an H1 after the frontmatter if the rule is enforced.

📝 Proposed fix
---
 "readie": patch
---
 
-Added ultracite to readie
+# Changes
+
+Added ultracite to readie
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
---
"readie": patch
---
Added ultracte to readie
---
"readie": patch
---
# Changes
Added ultracite to readie
🧰 Tools
🪛 LanguageTool

[grammar] ~5-~5: Ensure spelling is correct
Context: --- "readie": patch --- Added ultracte to readie

(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)

🪛 markdownlint-cli2 (0.21.0)

[warning] 5-5: First line in a file should be a top-level heading

(MD041, first-line-heading, first-line-h1)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.changeset/neat-rabbits-clap.md around lines 1 - 5, This changeset file has
only YAML frontmatter and no H1, triggering markdownlint rule MD041; open
.changeset/neat-rabbits-clap.md and add a top‑level heading line (e.g., "#
Changes" or "# neat-rabbits-clap") immediately after the frontmatter closing ---
so the file contains frontmatter followed by an H1 and then the existing body
("Added ultracte to readie").

"readie": patch
---

Added ultracte to readie
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Fix spelling: “ultracte” → “ultracite”.

Spelling error flagged by LanguageTool; please correct the word in the changeset entry.

✍️ Proposed fix
-Added ultracte to readie
+Added ultracite to readie
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
Added ultracte to readie
Added ultracite to readie
🧰 Tools
🪛 LanguageTool

[grammar] ~5-~5: Ensure spelling is correct
Context: --- "readie": patch --- Added ultracte to readie

(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)

🪛 markdownlint-cli2 (0.21.0)

[warning] 5-5: First line in a file should be a top-level heading

(MD041, first-line-heading, first-line-h1)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.changeset/neat-rabbits-clap.md at line 5, In the changeset entry in
.changeset/neat-rabbits-clap.md replace the misspelled token "ultracte" with the
correct spelling "ultracite" so the sentence reads "Added ultracite to readie";
update only that word in the changeset content.

…tions

- Updated the resolveMergedCustomSections function to return projectCustomSections when globalCustomSections is not defined, enhancing robustness and clarity in configuration merging.
@BurnedChris BurnedChris merged commit c888a8c into main Feb 19, 2026
1 of 2 checks passed
@BurnedChris BurnedChris deleted the ultracite branch February 19, 2026 22:15
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.

1 participant