Skip to content
This repository was archived by the owner on Sep 4, 2025. It is now read-only.

feat: replace ESLint with Biome and add Lefthook for git hooks#89

Closed
galligan wants to merge 5 commits into
graphite-base/89from
feat_replace_eslint_with_biome_and_add_lefthook_for_git_hooks
Closed

feat: replace ESLint with Biome and add Lefthook for git hooks#89
galligan wants to merge 5 commits into
graphite-base/89from
feat_replace_eslint_with_biome_and_add_lefthook_for_git_hooks

Conversation

@galligan

@galligan galligan commented Sep 1, 2025

Copy link
Copy Markdown
Contributor

feat: replace ESLint with Biome and add Lefthook for git hooks

  • Replace ESLint with Biome/Ultracite for TS/JS linting and formatting
  • Add Lefthook for managing git hooks
  • Configure markdownlint-cli2 for Markdown formatting
  • Update all package.json scripts to use new tooling
  • Update CI workflow to use new linting commands
  • Remove old ESLint configuration files

fix: resolve linting and TypeScript errors after tooling migration

  • Fix TypeScript strict mode type errors
  • Update test files for API changes (runMixdownV0 -> runRulesetsV0)
  • Change parse and lint functions from async to sync
  • Add Frontmatter type definition for better type safety
  • Update tests to match new rulesets frontmatter structure
  • Configure Biome rules to suppress false positives
  • Fix all formatting and linting issues

- Replace ESLint with Biome/Ultracite for TS/JS linting and formatting
- Add Lefthook for managing git hooks
- Configure markdownlint-cli2 for Markdown formatting
- Update all package.json scripts to use new tooling
- Update CI workflow to use new linting commands
- Remove old ESLint configuration files
- Fix TypeScript strict mode type errors
- Update test files for API changes (runMixdownV0 -> runRulesetsV0)
- Change parse and lint functions from async to sync
- Add Frontmatter type definition for better type safety
- Update tests to match new rulesets frontmatter structure
- Configure Biome rules to suppress false positives
- Fix all formatting and linting issues
@coderabbitai

coderabbitai Bot commented Sep 1, 2025

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

📝 Walkthrough

Summary by CodeRabbit

  • New Features

    • Introduced Biome/Ultracite tooling with Bun; Lefthook git hooks for format/lint/test.
    • Added ConsoleLogger and PinoLogger with log‑level control.
    • Destination plugins support configurable output paths and richer metadata; more resilient per‑destination processing.
  • Changes

    • Replaced ESLint; revamped scripts and CI (format, lint, markdown lint).
    • Parser and linter are now synchronous; compile enriched with context.
    • Default output paths moved to .rulesets/; terminology updated (Mixdown → Rulesets).
  • Documentation

    • Updated README and CHANGELOG (v0.1.0), CLI installation, terminology, and structure.
  • Chores

    • Added ignore/config files; removed automated code‑review workflow; formatting cleanups.

Walkthrough

Replaces ESLint with Biome/Ultracite and adds Bun/Ultracite tooling, Lefthook hooks and markdownlint-cli2; converts parse and lint APIs from async to synchronous; introduces a Frontmatter type and rulesets structure; CompiledDoc gains a context field; destination processing refactored with per-destination compile/write and directory creation.

Changes

Cohort / File(s) Summary
Tooling & config
biome.json, \.biomeignore, \.prettierignore, \.prettierrc, \.markdownlint-cli2.yaml, \.markdownlint.json, lefthook.yml, tsconfig.json, tsconfig.base.json, turbo.json, \.changeset/config.json
Adds Biome config + ignore, Prettier/markdownlint configs, Lefthook hooks, root tsconfig (noEmit) and minor EOF newline fixes.
ESLint removed
\.eslintrc.js
Deletes ESLint configuration file.
GitHub action / Bun setup
.github/actions/setup-bun-and-deps/action.yml
Quote style changes, passthrough bun-version, adds Install Dependencies step, changes lint step to check:ci, adds Markdown lint step.
Repo docs
CHANGELOG.md, README.md, AGENTS.md
Terminology and formatting updates, added release block and small text edits.
Root package.json
package.json
Replaces ESLint toolchain with ultracite/biome/markdownlint-cli2/lefthook; adds many scripts (lint/format/check/typecheck/ci), sets packageManager to bun@1.2.21 and adjusts devDependencies.
Core package scripts & deps
packages/core/package.json
Uses rimraf for clean, switches lint to ultracite, adds lint:fix, updates deps (adds pino, rimraf, removes eslint).
Interfaces: types & frontmatter
packages/core/src/interfaces/* (compiled-doc.ts, destination-plugin.ts, frontmatter.ts, logger.ts, index.ts)
Converts several interfaces to type aliases, adds Frontmatter type, adds context to CompiledDoc, reworks DestinationPlugin and logger types, adds PinoLogger and LogLevel.
Parser (sync)
packages/core/src/parser/index.ts, tests
Changes parse from async → sync return; tests updated to synchronous usage and adjusted error messages.
Linter (sync) & rules
packages/core/src/linter/index.ts, tests
lint now synchronous and returns LintResult[]; LinterConfig/LintResult become type aliases; frontmatter.rulesets validation added; tests aligned.
Compiler changes
packages/core/src/compiler/index.ts, tests
Adds LINE_SPLIT_REGEX, removes empty-content warning, merges destination config into compiled context, updates metadata propagation; tests adjusted for quoting.
Destinations & plugins
packages/core/src/destinations/* (cursor-plugin.ts, windsurf-plugin.ts, index.ts, __tests__/*)
Switch to node:fs/node:path; support config.outputPath and legacy config.path; ensure mkdir for output directories; priority logging added; exports reorganised; tests updated.
Core orchestration
packages/core/src/index.ts
Refactors run flow: sync parse/lint, per-destination compile with isolated errors, plugin.write({ compiled, destPath, config, logger }) usage, export reordering.
Build & test config hygiene
packages/core/tsup.config.ts, packages/core/vitest.config.ts, packages/core/tsconfig.json, packages/core/tests/integration/e2e.spec.ts
Quote/EOL/style changes, integration tests renamed to runRulesetsV0 and updated to new frontmatter/output paths and node:fs mocks.
CI workflow removed
.github/workflows/claude-code-review.yml
Removes the Claude code-review workflow.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor CLI as CLI
  participant Core as Core (index.ts)
  participant Parser as Parser
  participant Linter as Linter
  participant Compiler as Compiler
  participant Plugin as Destination Plugin

  CLI->>Core: runRulesetsV0(path, logger)
  Core->>Parser: parse(content)  %% synchronous
  Parser-->>Core: ParsedDoc
  Core->>Linter: lint(ParsedDoc, config)  %% synchronous
  Linter-->>Core: LintResult[]
  Core->>Core: determine destinationIds
  loop per destination
    Core->>Compiler: compile(ParsedDoc, destinationId, projectConfig)
    Compiler-->>Core: CompiledDoc { context: { destinationId, config } }
    Core->>Plugin: plugin.write({ compiled, destPath, config, logger })
    alt directory missing
      Plugin->>Plugin: mkdir -p dir
    end
    Plugin-->>Core: success / throw
  end
  Core-->>CLI: done / errors
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

Possibly related PRs

  • outfitter-dev/rulesets#63 — Overlapping tooling/CI and linting changes (Biome/Ultracite, Bun scripts, action updates).
  • outfitter-dev/rulesets#91 — Related logger changes: pino/pino-pretty deps and new PinoLogger implementation and tests.
  • outfitter-dev/rulesets#47 — Broadly overlaps core API changes (parser, linter, compiler, destinations, interfaces) and ESLint removal.
✨ Finishing Touches
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat_replace_eslint_with_biome_and_add_lefthook_for_git_hooks

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore or @coderabbit ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@claude

claude Bot commented Sep 1, 2025

Copy link
Copy Markdown

Claude encountered an error —— View job


I'll analyze this and get back to you.

galligan commented Sep 1, 2025

Copy link
Copy Markdown
Contributor Author

Warning

This pull request is not mergeable via GitHub because a downstack PR is open. Once all requirements are satisfied, merge this PR as a stack on Graphite.
Learn more

This stack of pull requests is managed by Graphite. Learn more about stacking.

@galligan

galligan commented Sep 1, 2025

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Sep 1, 2025

Copy link
Copy Markdown
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 16

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
packages/core/package.json (1)

20-27: Replace rm -rf with cross‑platform rimraf in build script

rm -rf is not portable on Windows. Use rimraf.

-    "build": "rm -rf dist && tsup && tsc --emitDeclarationOnly",
+    "build": "rimraf dist && tsup && tsc --emitDeclarationOnly",

Add devDependency:

   "devDependencies": {
+    "rimraf": "^6.0.1",
CHANGELOG.md (1)

1-19: Document the toolchain migration and add a release header

The changelog omits the major Biome/Lefthook/markdownlint and CI changes described in the PR. Also add a version/date header for traceability.

Apply something like:

+## [0.1.0] - 2025-09-01
+
 ### Added
 
 - Added `.mix.md` file extension for source rules files to improve discoverability, search capabilities, and IDE support
 
 ### Changed
 
+- Replaced ESLint with Biome/Ultracite for linting/formatting
+- Added Lefthook-managed git hooks
+- Configured markdownlint-cli2 for Markdown formatting
+- Updated package.json scripts and CI workflow to new lint commands
+- Converted parse/lint APIs from async to sync
+- Introduced Frontmatter type and updated frontmatter.rulesets structure
+- Updated tests to use runRulesetsV0 and new destinations model
 - Updated terminology throughout the documentation:
   - "Mix files" → "Source rules"
   - "Target" → "Destination"
   - "Output" → "Compiled rules"
   - "Track" → "Stem"
   - "Option" → "Property"
   - "Snippet" → "Mixin"
   - `property(value)` → `property-*` and `name-("value")`
 - Updated directory structure:
   - `.mixdown/mixes/` → `.mixdown/src/`
   - `.mixdown/mixes/_snippets/` → `.mixdown/src/_mixins/`
   - `.mixdown/output/` → `.mixdown/dist/`
packages/core/src/linter/__tests__/linter.spec.ts (1)

73-93: Update test name and message for non-object rulesets.
The linter expects an object with version; it reports an invalid declaration, not “field type”.

-    it("should error when rulesets field is not a string", () => {
+    it("should error when rulesets field is not an object with version", () => {
...
-      const typeError = results.find((r) => r.message.includes('Invalid "rulesets" field type'));
+      const typeError = results.find((r) =>
+        r.message.includes("Invalid Rulesets version declaration")
+      );
🧹 Nitpick comments (39)
packages/core/tsconfig.json (1)

3-11: Optional: align TS baseline with Bun/Node ESM usage.

  • Consider moduleResolution: "NodeNext" (or "Bundler") in base for cleaner ESM/resolution.
  • If the repo targets modern runtimes, bump target/lib to ES2022 for built-ins typing.
.markdownlint.json (1)

6-6: Avoid dual-config drift with markdownlint-cli2.

If CLI2 is the only runner, drop this file and keep .markdownlint-cli2.yaml as single source of truth.

.biomeignore (1)

1-8: Expand ignores to cover real lockfiles and common artefacts.

Biome may scan/format JSON/YAML; add the actual lockfiles and snapshots.

Apply:

 node_modules/
 dist/
 .turbo/
 coverage/
-*.lock
-bun.lock
+.DS_Store
+# Lockfiles
+*.lock
+package-lock.json
+pnpm-lock.yaml
+yarn.lock
+bun.lockb
+# Misc
 .changeset/
 docs_archive/
+*.snap
tsconfig.base.json (1)

2-16: Modernise moduleResolution and isolate test typings

  • In tsconfig.base.json, update
    "moduleResolution": "node""moduleResolution": "NodeNext" (keep "module": "ESNext").
  • Remove "vitest/globals" from the base "types" and add it only in a new per-package test tsconfig (e.g. tsconfig.test.json extending the base) so global test types don’t leak into non-test builds.
.prettierrc (1)

6-18: Prevent formatter overlap with Biome/markdownlint.
Since Biome now formats TS/JS and markdownlint-cli2 covers Markdown, consider excluding Markdown (and any other Biome-managed types) from Prettier to avoid churn. Verify lefthook/CI don’t run both on the same files.

If desired, update .prettierignore to include:

  • *.md
  • *.mdx
  • docs/**
tsconfig.json (1)

1-8: Consider project references and test typechecking.

  • Optional: add "composite": true and "references" to packages for faster tsc -b and clearer boundaries.
  • Excluding tests here is fine if tests are typechecked elsewhere; confirm there’s a per-package test tsconfig or a CI step that typechecks tests.
.prettierignore (1)

17-19: Ignore Bun’s actual lockfile (bun.lockb), not bun.lock

Bun uses bun.lockb. Keeping bun.lock is a no-op and bun.lockb might still be processed by Prettier.

 *.lock
-bun.lock
+bun.lockb
 .changeset/
packages/core/vitest.config.ts (1)

7-13: Confirm test runner direction (Vitest vs Bun test)

Repo-wide work has been moving to Bun-first. If the intention is to standardise on Bun’s test runner, plan a migration; otherwise ensure CI calls vitest explicitly (not bun test).

packages/core/package.json (1)

24-25: Script naming consistency: prefer format/check over lint:fix

Elsewhere we’ve standardised on format (writes) and check (CI). Consider aligning.

-    "lint": "bunx ultracite lint .",
-    "lint:fix": "bunx ultracite format .",
+    "check": "bunx ultracite lint .",
+    "format": "bunx ultracite format .",

If CI expects a specific name (e.g., check:ci), keep it consistent with the workflow.

biome.json (1)

15-16: Include mjs/cjs/mts/cts in Biome file matches

Covers common JS/TS module variants so lint/format applies uniformly.

-    "includes": ["**/*.{js,ts,jsx,tsx,json,jsonc}"]
+    "includes": ["**/*.{js,ts,jsx,tsx,mjs,cjs,mts,cts,json,jsonc}"]
README.md (1)

154-155: Header punctuation consistency

Minor: other numbered headings use terminal punctuation variably. Either keep the colon or remove consistently across the section.

-### 3. Find your compiled rules at
+### 3. Find your compiled rules at:
.markdownlint-cli2.yaml (3)

3-9: Remove duplicate MD013 disablement

You’re disabling line-length twice (MD013 and line-length). Keep one (prefer MD013) to avoid confusion.

   MD025: false # Multiple top-level headings
-  line-length: false

11-23: Deduplicate ignores and add Bun’s lockfile

Trim duplicate patterns and ignore Bun’s binary lockfile to avoid accidental checks.

 ignores:
-  - node_modules/**
-  - "**/node_modules/**"
-  - dist/**
-  - "**/dist/**"
-  - .turbo/**
-  - "**/.turbo/**"
-  - coverage/**
-  - "**/coverage/**"
-  - "**/*.lock"
-  - "**/bun.lock"
-  - .changeset/**
-  - docs_archive/**
+  - "**/node_modules/**"
+  - "**/dist/**"
+  - "**/.turbo/**"
+  - "**/coverage/**"
+  - "**/*.lock"
+  - "**/bun.lock"
+  - "**/bun.lockb"
+  - ".changeset/**"
+  - "docs_archive/**"

23-23: Add trailing newline

YAMLLint flags missing EOF newline. Add one to satisfy formatters and tools.

.github/actions/setup-bun-and-deps/action.yml (1)

34-41: Use explicit expressions in if: for clarity

The current if: inputs.run-… works, but wrapping in ${{ }} avoids ambiguity and matches GH Actions docs.

-    - name: Check Format
-      if: inputs.run-lint == 'true'
+    - name: Check Format
+      if: ${{ inputs.run-lint == 'true' }}
       run: bun run check:ci
       shell: bash

-    - name: Lint Markdown
-      if: inputs.run-lint == 'true'
+    - name: Lint Markdown
+      if: ${{ inputs.run-lint == 'true' }}
       run: bun run lint:md
       shell: bash

     - name: Test
-      if: inputs.run-test == 'true'
+      if: ${{ inputs.run-test == 'true' }}
       run: bun run test
       shell: bash

     - name: Build
-      if: inputs.run-build == 'true'
+      if: ${{ inputs.run-build == 'true' }}
       run: bun run build
       shell: bash

Also applies to: 45-52

packages/core/src/destinations/index.ts (2)

8-11: Avoid side effects at import-time if constructors touch the FS.
If CursorPlugin/WindsurfPlugin constructors do IO or read config, prefer lazy instantiation to keep module loads cheap and test-friendly.

Apply:

-export const cursorPlugin = new CursorPlugin();
-export const windsurfPlugin = new WindsurfPlugin();
+let _singletons:
+  | { cursor: DestinationPlugin; windsurf: DestinationPlugin }
+  | undefined;
+export const getDestinations = () => {
+  if (!_singletons) {
+    _singletons = {
+      cursor: new CursorPlugin(),
+      windsurf: new WindsurfPlugin(),
+    };
+  }
+  return _singletons;
+};

13-16: Prefer a typed Record over Map for exhaustiveness and simpler consumption.
A Record with a DestinationId union catches missing keys at compile time and is easier to serialise/mock.

-export const destinations: ReadonlyMap<string, DestinationPlugin> = new Map([
-  ["cursor", cursorPlugin],
-  ["windsurf", windsurfPlugin],
-]);
+export type DestinationId = "cursor" | "windsurf";
+export const destinations = {
+  cursor: new CursorPlugin(),
+  windsurf: new WindsurfPlugin(),
+} as const satisfies Record<DestinationId, DestinationPlugin>;

If you keep Map, consider deriving keys from plugin.id to avoid drift.

lefthook.yml (2)

1-12: Prevent formatter races on .md and auto-stage fixes.
Prettier and markdownlint both write to Markdown; running them in parallel can cause non-deterministic results. Also, without stage_fixed: true, fixes may not be re-staged.

-pre-commit:
-  parallel: true
+pre-commit:
+  parallel: false
+  stage_fixed: true
   commands:
     ultracite:
       glob: "**/*.{ts,tsx,js,jsx,json}"
       run: "bunx ultracite format {staged_files}"
-    prettier:
-      glob: "**/*.{md,yml,yaml}"
+    prettier:
+      glob: "**/*.{yml,yaml}"
       run: "bunx prettier --write {staged_files}"
     markdownlint:
       glob: "**/*.md"
       run: "bunx markdownlint-cli2 {staged_files} --fix"

Alternatively, keep Prettier on MD but keep parallel: false to sequence them deterministically.


14-23: Pre-push gate is sensible. LGTM.
Optional: add timeout tags if pushes occasionally hang on CI-heavy repos.

packages/core/src/parser/__tests__/parser.spec.ts (2)

79-92: Unclosed frontmatter assertion mirrors the previous test—looks good pending line-base check.


104-118: Body preservation assertion is robust. LGTM.
Minor: if parse exposes body, asserting exact body equality would remove reliance on substring checks.

packages/core/src/destinations/cursor-plugin.ts (1)

61-64: Optional: write atomically to avoid partial writes

Write to a temp file and rename to reduce risk of readers observing partial content.

-      await fs.writeFile(resolvedPath, compiled.output.content, { encoding: "utf8" });
+      const tmpPath = `${resolvedPath}.tmp`;
+      await fs.writeFile(tmpPath, compiled.output.content, { encoding: "utf8" });
+      await fs.rename(tmpPath, resolvedPath);
packages/core/src/destinations/windsurf-plugin.ts (1)

61-65: Optional: atomic writes for robustness

Mirror the atomic write approach here as well.

-      await fs.writeFile(resolvedPath, compiled.output.content, "utf8");
+      const tmpPath = `${resolvedPath}.tmp`;
+      await fs.writeFile(tmpPath, compiled.output.content, "utf8");
+      await fs.rename(tmpPath, resolvedPath);
packages/core/src/interfaces/frontmatter.ts (1)

7-21: Tighten value types to JSON-safe values

Use a JsonValue alias instead of unknown to prevent functions/symbols leaking into config.

Add:

export type JsonValue =
  | string | number | boolean | null
  | JsonValue[]
  | { [key: string]: JsonValue };

Then update the type:

-  rulesets?: {
-    version: string;
-    [key: string]: unknown;
-  };
+  rulesets?: {
+    version: string;
+    [key: string]: JsonValue;
+  };
@@
-      [key: string]: unknown;
+      [key: string]: JsonValue;
     }
   >;
-  [key: string]: unknown;
+  [key: string]: JsonValue;
packages/core/src/parser/index.ts (3)

9-12: Update JSDoc to reflect synchronous API.

Comment still says it returns a Promise.

- * @returns A promise that resolves to a ParsedDoc
+ * @returns ParsedDoc

17-33: Handle BOM and YAML terminating ellipsis.

Improve robustness for UTF-8 BOMs and YAML ... terminator.

-export function parse(content: string): ParsedDoc {
-  const lines = content.split("\n");
+export function parse(content: string): ParsedDoc {
+  // Normalise potential BOM at start of file
+  const normalised = content.replace(/^\uFEFF/, "");
+  const lines = normalised.split("\n");
@@
-    for (let i = 1; i < lines.length; i++) {
-      if (lines[i].trim() === "---") {
+    for (let i = 1; i < lines.length; i++) {
+      const trimmed = lines[i].trim();
+      if (trimmed === "---" || trimmed === "...") {
         frontmatterEnd = i;
         break;
       }
     }

Also applies to: 35-38


39-70: Surface precise YAML error location.

Use js-yaml’s error.mark to report accurate line/column within frontmatter.

-      } catch (error) {
-        let friendlyMessage = "Invalid YAML syntax in frontmatter. ";
+      } catch (error) {
+        let friendlyMessage = "Invalid YAML syntax in frontmatter. ";
+        const mark = (error as any)?.mark;
@@
-        errors.push({
-          message: friendlyMessage,
-          line: frontmatterStart + 1,
-          column: 1,
-        });
+        errors.push({
+          message: friendlyMessage,
+          // error.mark.{line,column} are 0-based and relative to frontmatter
+          line: typeof mark?.line === "number" ? frontmatterStart + 1 + mark.line : frontmatterStart + 1,
+          column: typeof mark?.column === "number" ? mark.column + 1 : 1,
+        });
package.json (2)

17-18: Add missing path argument to format:check for consistency.

Other Ultracite invocations pass “.”; keep it consistent.

-    "format:check": "bunx ultracite lint",
+    "format:check": "bunx ultracite lint .",

14-19: Deduplicate “lint:fix” aliasing and keep semantics clear.

Have lint:fix call format:fix to avoid two sources of truth.

-    "lint:fix": "bunx ultracite format .",
+    "lint:fix": "bun run format:fix",
packages/core/tests/integration/e2e.spec.ts (1)

3-6: Optional: migrate to Bun’s test API for consistency.

If the repo standardised on Bun tests, switch from Vitest imports to bun:test.

I can provide a mechanical codemod if desired.

packages/core/src/interfaces/destination-plugin.ts (1)

41-47: Make write ctx immutable and future-proof config typing.

Avoid accidental mutations and leave room for narrowed config types later.

-  write(ctx: {
-    compiled: CompiledDoc;
-    destPath: string;
-    config: Record<string, unknown>; // Validated via schema from configSchema()
-    logger: Logger;
-  }): Promise<void>;
+  write(ctx: Readonly<{
+    compiled: CompiledDoc;
+    destPath: string;
+    config: Record<string, unknown>; // Validated via schema from configSchema()
+    logger: Logger;
+  }>): Promise<void>;
packages/core/src/compiler/index.ts (2)

5-13: Fix JSDoc: function is synchronous, not a Promise.
Update the return type in the doc to avoid confusion.

- * @returns A promise that resolves to a CompiledDoc
+ * @returns CompiledDoc

47-51: Preserve body whitespace unless the spec mandates trimming.
Trimming drops intentional leading/trailing blank lines.

-          .join("\n")
-          .trim();
+          .join("\n");

Would you like this normalisation, or should we preserve authoring whitespace?

packages/core/src/linter/index.ts (2)

31-38: Fix JSDoc: function is synchronous.
Update the return description accordingly.

- * @returns A promise that resolves to an array of lint results
+ * @returns LintResult[]

80-87: Validate rulesets.version type as string.
Prevents objects with non-string versions slipping through.

-    } else if (typeof frontmatter.rulesets !== "object" || frontmatter.rulesets === null || !('version' in frontmatter.rulesets)) {
+    } else if (
+      typeof frontmatter.rulesets !== "object" ||
+      frontmatter.rulesets === null ||
+      !("version" in frontmatter.rulesets)
+    ) {
       results.push({
         message: `Invalid ${getFieldName("/rulesets")}. Expected object with version property, got ${typeof frontmatter.rulesets}.`,
         line: 1,
         column: 1,
         severity: "error",
       });
+    } else if (typeof (frontmatter.rulesets as any).version !== "string") {
+      results.push({
+        message: `Invalid ${getFieldName("/rulesets/version")}. Expected string, got ${typeof (frontmatter.rulesets as any).version}.`,
+        line: 1,
+        column: 1,
+        severity: "error",
+      });
packages/core/src/interfaces/compiled-doc.ts (2)

56-64: Prefer readonly arrays for AST collections

These arrays are part of the parsed/compiled model and shouldn’t be mutated downstream. Making them readonly helps prevent accidental writes and improves type safety.

-  ast: {
-    // Abstract Syntax Tree - minimal for v0
-    stems: Stem[];
-    imports: Import[];
-    variables: Variable[];
-    markers: Marker[]; // All markers found - empty for v0 body processing
-  };
+  ast: {
+    // Abstract Syntax Tree - minimal for v0
+    stems: ReadonlyArray<Stem>;
+    imports: ReadonlyArray<Import>;
+    variables: ReadonlyArray<Variable>;
+    markers: ReadonlyArray<Marker>; // All markers found - empty for v0 body processing
+  };
-  ast: {
-    stems: Stem[]; // Array of parsed stems (empty for v0 body)
-    imports: Import[]; // Array of parsed imports (empty for v0 body)
-    variables: Variable[]; // Array of parsed variables (empty for v0 body)
-    markers: Marker[]; // All markers found in the document (empty for v0 body)
-  };
+  ast: {
+    stems: ReadonlyArray<Stem>; // Array of parsed stems (empty for v0 body)
+    imports: ReadonlyArray<Import>; // Array of parsed imports (empty for v0 body)
+    variables: ReadonlyArray<Variable>; // Array of parsed variables (empty for v0 body)
+    markers: ReadonlyArray<Marker>; // All markers found in the document (empty for v0 body)
+  };

Also applies to: 84-89


97-101: Consider making CompiledDoc generic over config

Context config will vary by destination. A generic makes the type more expressive without breaking current usage.

-export type CompiledDoc = {
+export type CompiledDoc<TConfig = Record<string, unknown>> = {
   /** Additional context for the compilation */
   context: {
     destinationId: string; // Current destination being compiled for
-    config: Record<string, unknown>; // Resolved configuration for this compilation (e.g., project config, destination-specific config)
+    config: TConfig; // Resolved configuration for this compilation (e.g., project config, destination-specific config)
   };
 };
packages/core/src/index.ts (2)

94-108: Make the severity switch exhaustive and observable

If the enum widens, the default path is currently silent. Emit a warning and assert exhaustiveness in TS.

       switch (result.severity) {
         case "error":
           logger.error(message);
           hasErrors = true;
           break;
         case "warning":
           logger.warn(message);
           break;
         case "info":
           logger.info(message);
           break;
-        default:
-          // Exhaustive check for LintSeverity type
-          break;
+        default: {
+          // Exhaustive check for LintSeverity type
+          const _exhaustive: never = result.severity as never;
+          logger.warn(`Unknown lint severity: ${String(result.severity)}`);
+          void _exhaustive;
+          break;
+        }
       }

173-186: CJS main-module check is safe
The repository has no "type" field in any package.json (defaults to CommonJS) and tsconfig.json doesn’t specify an ESM module, so require.main === module works as expected. If you plan to support ESM execution in the future, you can optionally adopt the cross-runtime guard pattern suggested earlier.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • 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 12a8ebb and 37b3cb0.

⛔ Files ignored due to path filters (1)
  • bun.lock is excluded by !**/*.lock
📒 Files selected for processing (39)
  • .biomeignore (1 hunks)
  • .changeset/config.json (1 hunks)
  • .eslintrc.js (0 hunks)
  • .github/actions/setup-bun-and-deps/action.yml (3 hunks)
  • .markdownlint-cli2.yaml (1 hunks)
  • .markdownlint.json (1 hunks)
  • .prettierignore (1 hunks)
  • .prettierrc (1 hunks)
  • AGENTS.md (1 hunks)
  • CHANGELOG.md (1 hunks)
  • README.md (3 hunks)
  • biome.json (1 hunks)
  • lefthook.yml (1 hunks)
  • package.json (2 hunks)
  • packages/core/package.json (2 hunks)
  • packages/core/src/compiler/__tests__/compiler.spec.ts (13 hunks)
  • packages/core/src/compiler/index.ts (4 hunks)
  • packages/core/src/destinations/__tests__/cursor-plugin.spec.ts (8 hunks)
  • packages/core/src/destinations/__tests__/windsurf-plugin.spec.ts (9 hunks)
  • packages/core/src/destinations/cursor-plugin.ts (4 hunks)
  • packages/core/src/destinations/index.ts (1 hunks)
  • packages/core/src/destinations/windsurf-plugin.ts (3 hunks)
  • packages/core/src/index.ts (5 hunks)
  • packages/core/src/interfaces/compiled-doc.ts (3 hunks)
  • packages/core/src/interfaces/destination-plugin.ts (2 hunks)
  • packages/core/src/interfaces/frontmatter.ts (1 hunks)
  • packages/core/src/interfaces/index.ts (1 hunks)
  • packages/core/src/interfaces/logger.ts (2 hunks)
  • packages/core/src/linter/__tests__/linter.spec.ts (9 hunks)
  • packages/core/src/linter/index.ts (6 hunks)
  • packages/core/src/parser/__tests__/parser.spec.ts (4 hunks)
  • packages/core/src/parser/index.ts (4 hunks)
  • packages/core/tests/integration/e2e.spec.ts (5 hunks)
  • packages/core/tsconfig.json (1 hunks)
  • packages/core/tsup.config.ts (1 hunks)
  • packages/core/vitest.config.ts (1 hunks)
  • tsconfig.base.json (1 hunks)
  • tsconfig.json (1 hunks)
  • turbo.json (1 hunks)
💤 Files with no reviewable changes (1)
  • .eslintrc.js
🧰 Additional context used
🧠 Learnings (61)
📓 Common learnings
Learnt from: galligan
PR: outfitter-dev/rulesets#0
File: :0-0
Timestamp: 2025-08-15T18:44:08.632Z
Learning: The user (galligan) successfully implemented all PR review feedback after initial discrepancies were identified, including: version marker format standardization from ruleset-v* to mixd-v* throughout PLAN-rulesets-v0.md, cross-platform build scripts using rimraf in packages/compiler/package.json, accurate package description removing CommonMark claims in root package.json, and proper commit tracking with specific hashes (f27e034 + 9ac6df9).
Learnt from: galligan
PR: outfitter-dev/monorepo#0
File: :0-0
Timestamp: 2025-08-23T01:01:27.260Z
Learning: User galligan successfully implemented comprehensive review feedback for PR #93 Bun-native optimization, systematically addressing all critical and important issues including: complete Turborepo reference removal from documentation and codebase, proper build.mjs error logging with array formatting and null coalescing, bunfig.toml security improvements (disabled auto="fallback", fixed watchExclude, moved telemetry to top-level), package.json script optimization (build:all alias, CI enhancement with test:all), and lefthook ultracite command fix (removed invalid --write flag), achieving -422 lines of legacy code removal while adding +18 lines of focused improvements with zero breaking changes and enhanced security, demonstrating gold standard systematic implementation following established patterns from previous PRs.
Learnt from: galligan
PR: outfitter-dev/rulesets#0
File: :0-0
Timestamp: 2025-08-19T17:49:13.493Z
Learning: User galligan provided comprehensive feedback on PR review issues, categorizing them by priority (high/medium/minor) and requesting systematic fixes including cross-platform build compatibility (rimraf instead of rm -rf), test framework alignment (bun:test instead of Jest), documentation-code consistency for directory exclusions, extraction of shared discovery logic to reduce duplication, and proper integration test implementation. Successfully addressed all feedback with complete code solutions.
Learnt from: galligan
PR: outfitter-dev/rulesets#0
File: :0-0
Timestamp: 2025-08-26T04:15:29.029Z
Learning: User galligan reported comprehensive fixes for PR #84 critical CodeRabbit feedback including: turbo dependency addition for CI build failure, codex provider addition to sandbox VALID_PROVIDER_TYPES, DEFAULT_CONFIG parallelCompilation property, RegExp lastIndex hazard fixes using matchAll, parallel compilation test logging enhancements, partial cache improvements storing compiled templates, .rule.md extension support for @-partial resolution, clearPartialCache fixes for hbs.partials registry, and silent LogLevel type addition. Verification confirmed extensive codex provider implementation, sophisticated CI quick fix workflow, robust partial cache system, and parallel compilation test infrastructure. Some specific claims require additional verification due to possible branch visibility issues, consistent with galligan's systematic implementation track record across multiple PRs.
Learnt from: galligan
PR: outfitter-dev/monorepo#0
File: :0-0
Timestamp: 2025-08-22T21:25:13.038Z
Learning: User galligan demonstrated exceptional systematic implementation for commit b93dcf8 in PR #90, comprehensively addressing all review feedback with production-grade fixes including: README documentation alignment using proper ≥ symbol matching package.json engines exactly, package.json script semantic corrections (prepare script using 'bun run config:mdlint', format/check distinction with format writing and check verifying), shell script hardening with defaulted parameter expansions for set -u compatibility (${VAR-} pattern), Biome generator architecture improvements with centralized BIOME_SCHEMA_URL constant and Bun subprocess API with 300s timeouts, enhanced error handling with exit codes and command context, SILENCE_BIOME_WARNINGS environment gate for developer experience, and pragmatic schema version strategy maintaining 2.1.4 for base config compatibility while using 2.2.0 for generated configs, showcasing systematic precision with comprehensive verification and documentation quali...
Learnt from: galligan
PR: outfitter-dev/blz#0
File: :0-0
Timestamp: 2025-08-27T17:01:21.600Z
Learning: User galligan successfully implemented comprehensive fixes for all 4 CodeRabbit review comments in PR #43 commit e7da15d, including: defensive error handling replacing unreachable!() with proper anyhow::bail! error message for NotModified on initial fetch, updating message from "Not modified" to "Up-to-date" in update command, adding etag and last_modified fields to FetchResult::NotModified variant for consistent metadata handling, and implementing atomic metadata writes using temp file pattern (.json.tmp) with fs::rename for data integrity, all within a massive 39K+ line initial codebase commit while maintaining production-quality standards.
<!--
Learnt from: galligan
PR: outfitter-dev/rulesets#0
File: :0-0
Timestamp: 2025-09-01T17:50:46.629Z
Learning: User galligan successfully implemented comprehensive CodeRabbit and Copilot feedback for PR #88 Bun migration CI/CD workflow, including: eliminating code duplication by creating composite action .github/actions/setup-bun-and-deps/action.yml for reusable setup process, pinning actions to specific SHAs for security (actions/checkout08eba0b, oven-sh/setup-bun735343b, changesets/actione0145ed), fixing bun.lockb filename issue by renaming from bun.lock for proper Bun lockfile format, hardening release job with timeout-minutes: 30, explicit permissions (contents: write, pull-requests: write), and BUN_VERSION environment variable for consistency, and achieving perfect YAML formatting by removing trailing spaces and adding final newline. This demonstrates galligan's continued systematic approach to implementing feedback with production-ready GitHub Actions automation following enterprise-grade technical standards.
Learnt from: galligan
PR: outfitter-dev/monorepo#0
File: :0-0
Timestamp: 2025-08-22T21:25:13.038Z
Learning: Branch visibility issue identified in PR #90 review: verification scripts running on branch "coderabbit_90" with no recent commits visible, explaining why galligan's claimed fixes from commit b93dcf8 were not found during verification. Current state shows pre-fix conditions (README/package.json mismatch, invalid prepare script syntax, swapped format/check semantics, direct $VAR usage in shell), suggesting either different branch contains the fixes, commit not merged to review branch, or push timing issue. This technical issue explains discrepancies without affecting galligan's systematic implementation quality track record.
Learnt from: galligan
PR: outfitter-dev/blz#0
File: :0-0
Timestamp: 2025-08-30T20:13:12.910Z
Learning: User galligan successfully completed the v0.1 release train stack consolidation for Issue #86, achieving: linear stack structure (main → #57 → #76 → #77 → #78 → #79 → #80 → #81 → #65 → #66 → #82 → #68 → #61 → #46 → #58 → #60 → #53), removal of closed PR #84, repositioning of PR #61 after PR #68, resolution of PR #66 merge conflicts, addressing all 21+ CodeRabbit review comments on PR #68 with proper Rust async patterns and MCP protocol updates, and CI workflow configuration fixes. Remaining blockers are 7 clippy warnings, segmentation fault in coverage testing, and dependency validation failures - demonstrating systematic project management and technical execution for complex Graphite stack operations.
Learnt from: galligan
PR: outfitter-dev/rulesets#0
File: :0-0
Timestamp: 2025-08-26T04:15:29.029Z
Learning: User galligan successfully implemented comprehensive fixes for all critical CodeRabbit feedback in PR #84 feature consolidation, including: adding missing turbo dependency to fix CI build failure, adding codex provider to sandbox VALID_PROVIDER_TYPES, fixing DEFAULT_CONFIG type annotation with parallelCompilation property, fixing global RegExp lastIndex hazard using matchAll instead of exec, adding missing log statements for parallel compilation tests, fixing partial cache to store compiled templates for better performance, adding .rule.md extension support for @-partial resolution, fixing clearPartialCache to also clear hbs.partials registry, and adding silent to LogLevel type to match runtime usage. All parallel compilation tests now pass and backward compatibility with v0 alias is maintained, demonstrating galligan's continued systematic approach to implementing feedback with enterprise-grade technical standards.
Learnt from: CR
PR: outfitter-dev/monorepo#0
File: packages/fieldguides/CLAUDE.md:0-0
Timestamp: 2025-08-18T18:13:30.555Z
Learning: Applies to packages/fieldguides/**/*.md : Always lint markdown files with markdownlint-cli2 and fix issues before committing
Learnt from: CR
PR: outfitter-dev/rulesets#0
File: CLAUDE.md:0-0
Timestamp: 2025-08-14T03:51:26.625Z
Learning: Applies to **/*.{md,mix.md,mdc} : Markdown files must pass standard markdown-lint without hacks
Learnt from: galligan
PR: outfitter-dev/blz#0
File: :0-0
Timestamp: 2025-08-31T14:18:47.842Z
Learning: User galligan correctly pointed out that after modifying commits, CodeRabbit's memory may become outdated. The files were reorganized from .agents/rules/ directly to .agents/rules/conventions/rust/ subdirectory, and the primary documentation moved from CLAUDE.md to AGENTS.md files. All technical fixes (async-patterns handle.await??, compiler-loop.md jq -sr usage, agent-check.sh permissions and jq usage, storage layout documentation, MCP protocol version 2024-11-05) were properly implemented despite the file structure changes.
📚 Learning: 2025-08-15T16:42:04.468Z
Learnt from: galligan
PR: outfitter-dev/monorepo#0
File: :0-0
Timestamp: 2025-08-15T16:42:04.468Z
Learning: The user (galligan) successfully implemented comprehensive fixes addressing critical configuration issues in biome.json (globals format, files configuration), bunfig.toml (exact setting), and VS Code settings (removing invalid multi-language overrides), while also resolving documentation contradictions and ensuring Ultracite preset compatibility over strict Biome 2.2.0 schema compliance.

Applied to files:

  • biome.json
📚 Learning: 2025-08-18T18:17:52.697Z
Learnt from: CR
PR: outfitter-dev/monorepo#0
File: .cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc:0-0
Timestamp: 2025-08-18T18:17:52.697Z
Learning: Applies to **/*.test.@(ts|tsx|js|jsx) : Write tests using Bun’s test API: `import { test, expect } from "bun:test"`; do not use Jest or Vitest APIs

Applied to files:

  • biome.json
  • packages/core/package.json
  • packages/core/tests/integration/e2e.spec.ts
  • packages/core/vitest.config.ts
📚 Learning: 2025-08-18T18:14:06.160Z
Learnt from: CR
PR: outfitter-dev/monorepo#0
File: shared/configs/changeset/CLAUDE.md:0-0
Timestamp: 2025-08-18T18:14:06.160Z
Learning: Applies to shared/configs/changeset/**/package.json : Ensure package.json includes Changesets scripts: changeset, changeset:version, and changeset:publish

Applied to files:

  • .changeset/config.json
📚 Learning: 2025-08-18T18:12:19.906Z
Learnt from: CR
PR: outfitter-dev/monorepo#0
File: packages/cli/CLAUDE.md:0-0
Timestamp: 2025-08-18T18:12:19.906Z
Learning: Applies to packages/cli/**/tsconfig.json : TypeScript config uses ES modules with target ES2022, module ES2022, and outDir set to ./dist

Applied to files:

  • packages/core/tsconfig.json
  • tsconfig.json
  • packages/core/tsup.config.ts
  • tsconfig.base.json
📚 Learning: 2025-08-18T18:14:06.160Z
Learnt from: CR
PR: outfitter-dev/monorepo#0
File: shared/configs/changeset/CLAUDE.md:0-0
Timestamp: 2025-08-18T18:14:06.160Z
Learning: Applies to shared/configs/changeset/**/{tsup.config.ts,tsup.config.js,package.json} : Use tsup to build both CJS and ESM outputs, include TypeScript declarations, and generate source maps

Applied to files:

  • packages/core/tsconfig.json
  • tsconfig.json
  • packages/core/tsup.config.ts
  • .prettierignore
  • packages/core/package.json
  • tsconfig.base.json
📚 Learning: 2025-08-24T11:27:06.182Z
Learnt from: CR
PR: outfitter-dev/monorepo#0
File: CLAUDE.md:0-0
Timestamp: 2025-08-24T11:27:06.182Z
Learning: Applies to {tsconfig.json,packages/**/tsconfig.json} : Enable TypeScript strict mode

Applied to files:

  • tsconfig.json
📚 Learning: 2025-08-14T03:50:36.782Z
Learnt from: CR
PR: outfitter-dev/rulesets#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-08-14T03:50:36.782Z
Learning: Applies to **/tsconfig*.json : Use strict TypeScript settings

Applied to files:

  • tsconfig.json
  • tsconfig.base.json
📚 Learning: 2025-08-24T11:27:39.408Z
Learnt from: CR
PR: outfitter-dev/monorepo#0
File: AGENT.md:0-0
Timestamp: 2025-08-24T11:27:39.408Z
Learning: Applies to **/tsconfig*.json : Enable TypeScript strict mode in tsconfig

Applied to files:

  • tsconfig.json
📚 Learning: 2025-08-24T11:27:06.182Z
Learnt from: CR
PR: outfitter-dev/monorepo#0
File: CLAUDE.md:0-0
Timestamp: 2025-08-24T11:27:06.182Z
Learning: Applies to tsconfig.json : Root tsconfig.json must define project references for all packages (including packages/typescript-config and packages/contracts/ts)

Applied to files:

  • tsconfig.json
📚 Learning: 2025-08-18T18:10:42.517Z
Learnt from: CR
PR: outfitter-dev/monorepo#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-08-18T18:10:42.517Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : Don't export empty modules that don't change anything

Applied to files:

  • tsconfig.json
📚 Learning: 2025-08-18T18:14:06.160Z
Learnt from: CR
PR: outfitter-dev/monorepo#0
File: shared/configs/changeset/CLAUDE.md:0-0
Timestamp: 2025-08-18T18:14:06.160Z
Learning: Applies to shared/configs/changeset/**/package.json : Ensure package.json includes scripts: build, dev, and typecheck (invoked via pnpm)

Applied to files:

  • tsconfig.json
  • packages/core/package.json
  • package.json
📚 Learning: 2025-08-18T18:10:42.517Z
Learnt from: CR
PR: outfitter-dev/monorepo#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-08-18T18:10:42.517Z
Learning: Applies to **/*.{ts,tsx} : Don't use TypeScript namespaces

Applied to files:

  • tsconfig.json
📚 Learning: 2025-08-18T18:12:55.183Z
Learnt from: CR
PR: outfitter-dev/monorepo#0
File: packages/contracts/ts/CLAUDE.md:0-0
Timestamp: 2025-08-18T18:12:55.183Z
Learning: Applies to packages/contracts/ts/**/__tests__/**/*.test.ts : Place core tests in standard __tests__ directories using .test.ts files.

Applied to files:

  • tsconfig.json
  • packages/core/tests/integration/e2e.spec.ts
  • packages/core/vitest.config.ts
📚 Learning: 2025-08-18T18:10:42.517Z
Learnt from: CR
PR: outfitter-dev/monorepo#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-08-18T18:10:42.517Z
Learning: Applies to **/*.{ts,tsx} : Use either `T[]` or `Array<T>` consistently

Applied to files:

  • packages/core/tsup.config.ts
📚 Learning: 2025-08-18T18:17:07.077Z
Learnt from: CR
PR: outfitter-dev/monorepo#0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-08-18T18:17:07.077Z
Learning: Applies to **/*.{ts,tsx} : Use Array<T> over T[] for array types

Applied to files:

  • packages/core/tsup.config.ts
📚 Learning: 2025-08-24T11:27:39.408Z
Learnt from: CR
PR: outfitter-dev/monorepo#0
File: AGENT.md:0-0
Timestamp: 2025-08-24T11:27:39.408Z
Learning: Applies to **/*.{ts,tsx} : Prefer Array<T> over T[]

Applied to files:

  • packages/core/tsup.config.ts
📚 Learning: 2025-08-14T03:50:36.782Z
Learnt from: CR
PR: outfitter-dev/rulesets#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-08-14T03:50:36.782Z
Learning: Applies to **/*.ts : Mark environment-dependent behavior with mixd-config

Applied to files:

  • packages/core/tsup.config.ts
📚 Learning: 2025-08-18T18:14:06.160Z
Learnt from: CR
PR: outfitter-dev/monorepo#0
File: shared/configs/changeset/CLAUDE.md:0-0
Timestamp: 2025-08-18T18:14:06.160Z
Learning: Applies to shared/configs/changeset/src/index.ts : Keep the main entry point at src/index.ts for this package

Applied to files:

  • packages/core/tsup.config.ts
📚 Learning: 2025-08-24T11:27:06.182Z
Learnt from: CR
PR: outfitter-dev/monorepo#0
File: CLAUDE.md:0-0
Timestamp: 2025-08-24T11:27:06.182Z
Learning: Build both CJS and ESM formats for packages

Applied to files:

  • packages/core/tsup.config.ts
📚 Learning: 2025-08-14T03:50:36.782Z
Learnt from: CR
PR: outfitter-dev/rulesets#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-08-14T03:50:36.782Z
Learning: Before submitting, run pnpm turbo lint && pnpm turbo test && pnpm turbo build

Applied to files:

  • .biomeignore
  • package.json
📚 Learning: 2025-08-18T18:13:30.555Z
Learnt from: CR
PR: outfitter-dev/monorepo#0
File: packages/fieldguides/CLAUDE.md:0-0
Timestamp: 2025-08-18T18:13:30.555Z
Learning: Applies to packages/fieldguides/**/*.md : Always lint markdown files with markdownlint-cli2 and fix issues before committing

Applied to files:

  • .markdownlint-cli2.yaml
  • .markdownlint.json
📚 Learning: 2025-08-14T03:51:26.625Z
Learnt from: CR
PR: outfitter-dev/rulesets#0
File: CLAUDE.md:0-0
Timestamp: 2025-08-14T03:51:26.625Z
Learning: Applies to **/*.{md,mix.md,mdc} : Markdown files must pass standard markdown-lint without hacks

Applied to files:

  • .markdownlint-cli2.yaml
  • .prettierignore
  • .markdownlint.json
📚 Learning: 2025-08-29T20:55:19.549Z
Learnt from: CR
PR: outfitter-dev/blz#0
File: docs/AGENTS.md:0-0
Timestamp: 2025-08-29T20:55:19.549Z
Learning: Applies to docs/**/*.{md,mdx} : When writing docs, follow the ./.agents/rules/STYLEGUIDE.md

Applied to files:

  • .markdownlint-cli2.yaml
  • AGENTS.md
📚 Learning: 2025-08-14T03:50:36.782Z
Learnt from: CR
PR: outfitter-dev/rulesets#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-08-14T03:50:36.782Z
Learning: Applies to **/*.ts : Start each TypeScript file with a TLDR file-purpose comment including the version marker, e.g., // TLDR: File purpose description (mixd-v0)

Applied to files:

  • packages/core/src/interfaces/frontmatter.ts
📚 Learning: 2025-08-18T18:10:42.517Z
Learnt from: CR
PR: outfitter-dev/monorepo#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-08-18T18:10:42.517Z
Learning: Applies to **/*.{test,spec}.{js,jsx,ts,tsx} : Ensure assertion functions (like expect) are placed inside an it() call

Applied to files:

  • packages/core/src/compiler/__tests__/compiler.spec.ts
  • packages/core/src/parser/__tests__/parser.spec.ts
  • packages/core/tests/integration/e2e.spec.ts
  • packages/core/src/linter/__tests__/linter.spec.ts
  • packages/core/src/destinations/__tests__/cursor-plugin.spec.ts
📚 Learning: 2025-08-18T18:17:07.077Z
Learnt from: CR
PR: outfitter-dev/monorepo#0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-08-18T18:17:07.077Z
Learning: Applies to **/*.{test,spec}.{js,jsx,ts,tsx} : Ensure the assertion function (e.g., expect) is inside an it() call

Applied to files:

  • packages/core/src/compiler/__tests__/compiler.spec.ts
  • packages/core/tests/integration/e2e.spec.ts
  • packages/core/src/linter/__tests__/linter.spec.ts
📚 Learning: 2025-08-14T03:51:26.625Z
Learnt from: CR
PR: outfitter-dev/rulesets#0
File: CLAUDE.md:0-0
Timestamp: 2025-08-14T03:51:26.625Z
Learning: Applies to .mixdown/src/**/*.{mix.md,md} : Author source rules in Mixdown Markdown using .mix.md (preferred) or .md extensions

Applied to files:

  • packages/core/src/compiler/__tests__/compiler.spec.ts
  • CHANGELOG.md
  • README.md
  • packages/core/tests/integration/e2e.spec.ts
  • packages/core/src/index.ts
📚 Learning: 2025-08-14T03:51:26.625Z
Learnt from: CR
PR: outfitter-dev/rulesets#0
File: CLAUDE.md:0-0
Timestamp: 2025-08-14T03:51:26.625Z
Learning: Applies to .mixdown/src/**/*.mix.md : Name source rules files in kebab-case with .mix.md extension (e.g., coding-standards.mix.md)

Applied to files:

  • packages/core/src/compiler/__tests__/compiler.spec.ts
  • CHANGELOG.md
  • packages/core/src/index.ts
📚 Learning: 2025-08-14T03:51:26.625Z
Learnt from: CR
PR: outfitter-dev/rulesets#0
File: CLAUDE.md:0-0
Timestamp: 2025-08-14T03:51:26.625Z
Learning: Applies to .mixdown/src/**/*.{mix.md,md} : Write mixes using Markdown ATX-style headers and proper fenced code blocks with language identifiers

Applied to files:

  • packages/core/src/compiler/__tests__/compiler.spec.ts
  • CHANGELOG.md
  • README.md
📚 Learning: 2025-08-14T03:51:26.625Z
Learnt from: CR
PR: outfitter-dev/rulesets#0
File: CLAUDE.md:0-0
Timestamp: 2025-08-14T03:51:26.625Z
Learning: Applies to .mixdown/mixdown.config.json : Place the Mixdown configuration at .mixdown/mixdown.config.json (kebab-case.config.json)

Applied to files:

  • packages/core/src/compiler/__tests__/compiler.spec.ts
📚 Learning: 2025-08-14T03:51:26.625Z
Learnt from: CR
PR: outfitter-dev/rulesets#0
File: CLAUDE.md:0-0
Timestamp: 2025-08-14T03:51:26.625Z
Learning: Use mixd-* markers in code comments for version tracking (e.g., // TLDR: ... (mixd-v0))

Applied to files:

  • packages/core/src/compiler/__tests__/compiler.spec.ts
  • CHANGELOG.md
📚 Learning: 2025-08-18T18:17:52.697Z
Learnt from: CR
PR: outfitter-dev/monorepo#0
File: .cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc:0-0
Timestamp: 2025-08-18T18:17:52.697Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : Do not import or configure `dotenv`; Bun auto-loads .env files

Applied to files:

  • .prettierignore
📚 Learning: 2025-08-18T18:10:42.517Z
Learnt from: CR
PR: outfitter-dev/monorepo#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-08-18T18:10:42.517Z
Learning: Applies to **/*.{ts,tsx} : Don't use the TypeScript directive ts-ignore

Applied to files:

  • .prettierignore
📚 Learning: 2025-08-31T14:18:47.842Z
Learnt from: galligan
PR: outfitter-dev/blz#0
File: :0-0
Timestamp: 2025-08-31T14:18:47.842Z
Learning: User galligan correctly pointed out that after modifying commits, CodeRabbit's memory may become outdated. The files were reorganized from .agents/rules/ directly to .agents/rules/conventions/rust/ subdirectory, and the primary documentation moved from CLAUDE.md to AGENTS.md files. All technical fixes (async-patterns handle.await??, compiler-loop.md jq -sr usage, agent-check.sh permissions and jq usage, storage layout documentation, MCP protocol version 2024-11-05) were properly implemented despite the file structure changes.

Applied to files:

  • AGENTS.md
  • README.md
📚 Learning: 2025-08-29T20:27:03.108Z
Learnt from: CR
PR: outfitter-dev/rulesets#0
File: AGENTS.md:0-0
Timestamp: 2025-08-29T20:27:03.108Z
Learning: Regularly consult docs: docs/project/GREPABLE.md, docs/project/LANGUAGE.md, docs/project/plans/PLAN-mixdown-v0.md, CLAUDE.md, docs/agentic/**

Applied to files:

  • AGENTS.md
📚 Learning: 2025-06-23T12:39:16.491Z
Learnt from: CR
PR: outfitter-dev/monorepo#0
File: packages/fieldguides/docs/CLAUDE.md:0-0
Timestamp: 2025-06-23T12:39:16.491Z
Learning: When writing internal documentation for Agent Outfitter in the docs directory, adopt an enthusiastic and exploratory tone, using adventure metaphors and focusing on equipping agents for their journeys.

Applied to files:

  • AGENTS.md
📚 Learning: 2025-08-18T18:17:52.697Z
Learnt from: CR
PR: outfitter-dev/monorepo#0
File: .cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc:0-0
Timestamp: 2025-08-18T18:17:52.697Z
Learning: Applies to package.json : Use `bun <file>` (or `bun --hot`) for direct script execution instead of `node` or `ts-node` in scripts

Applied to files:

  • packages/core/package.json
  • package.json
📚 Learning: 2025-08-18T18:17:52.697Z
Learnt from: CR
PR: outfitter-dev/monorepo#0
File: .cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc:0-0
Timestamp: 2025-08-18T18:17:52.697Z
Learning: Applies to package.json : Use `bun build <file.html|file.ts|file.css>` for build scripts instead of webpack or esbuild

Applied to files:

  • packages/core/package.json
  • package.json
📚 Learning: 2025-08-18T18:17:52.697Z
Learnt from: CR
PR: outfitter-dev/monorepo#0
File: .cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc:0-0
Timestamp: 2025-08-18T18:17:52.697Z
Learning: Applies to package.json : Use `bun test` to run tests instead of `jest` or `vitest` in scripts

Applied to files:

  • packages/core/package.json
  • package.json
📚 Learning: 2025-08-18T18:17:52.697Z
Learnt from: CR
PR: outfitter-dev/monorepo#0
File: .cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc:0-0
Timestamp: 2025-08-18T18:17:52.697Z
Learning: Applies to package.json : Use `bun run <script>` instead of `npm run`, `yarn run`, or `pnpm run` in package.json scripts

Applied to files:

  • packages/core/package.json
  • .github/actions/setup-bun-and-deps/action.yml
📚 Learning: 2025-08-18T18:17:52.697Z
Learnt from: CR
PR: outfitter-dev/monorepo#0
File: .cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc:0-0
Timestamp: 2025-08-18T18:17:52.697Z
Learning: Applies to package.json : Avoid Vite scripts/dependencies; use Bun’s HTML imports and bundler instead

Applied to files:

  • packages/core/package.json
  • package.json
📚 Learning: 2025-08-18T18:14:06.160Z
Learnt from: CR
PR: outfitter-dev/monorepo#0
File: shared/configs/changeset/CLAUDE.md:0-0
Timestamp: 2025-08-18T18:14:06.160Z
Learning: Applies to shared/configs/changeset/src/index.ts : addChangesetScripts must add the scripts: changeset, changeset:version, and changeset:publish to package.json

Applied to files:

  • packages/core/package.json
📚 Learning: 2025-08-18T18:17:52.697Z
Learnt from: CR
PR: outfitter-dev/monorepo#0
File: .cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc:0-0
Timestamp: 2025-08-18T18:17:52.697Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : Use `Bun.$` for running shell commands instead of `execa`

Applied to files:

  • packages/core/package.json
  • package.json
📚 Learning: 2025-08-18T18:17:52.697Z
Learnt from: CR
PR: outfitter-dev/monorepo#0
File: .cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc:0-0
Timestamp: 2025-08-18T18:17:52.697Z
Learning: Applies to **/esbuild*.@(js|ts|mjs|cjs) : Do not use esbuild; prefer `bun build`

Applied to files:

  • packages/core/package.json
📚 Learning: 2025-08-18T18:17:52.697Z
Learnt from: CR
PR: outfitter-dev/monorepo#0
File: .cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc:0-0
Timestamp: 2025-08-18T18:17:52.697Z
Learning: Applies to **/webpack.config.@(js|ts|mjs|cjs) : Do not use webpack; prefer `bun build`

Applied to files:

  • packages/core/package.json
📚 Learning: 2025-08-14T03:50:36.782Z
Learnt from: CR
PR: outfitter-dev/rulesets#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-08-14T03:50:36.782Z
Learning: Applies to **/*.ts : Mark API changes or deprecations with mixd-api

Applied to files:

  • CHANGELOG.md
  • packages/core/tests/integration/e2e.spec.ts
📚 Learning: 2025-08-29T20:27:03.108Z
Learnt from: CR
PR: outfitter-dev/rulesets#0
File: AGENTS.md:0-0
Timestamp: 2025-08-29T20:27:03.108Z
Learning: Applies to **/*.ts : Use version markers in code: mixd-v{version} (e.g., mixd-v0)

Applied to files:

  • CHANGELOG.md
📚 Learning: 2025-08-22T21:25:13.038Z
Learnt from: galligan
PR: outfitter-dev/monorepo#0
File: :0-0
Timestamp: 2025-08-22T21:25:13.038Z
Learning: Verification revealed discrepancies between galligan's claimed fixes for PR #90 commit b93dcf8 and actual file contents: README still shows "Node.js 20+ LTS" vs package.json ">=20" (not aligned), prepare script still contains invalid "bun config:mdlint" syntax (missing run keyword), format/check script semantics remain swapped with format using lint and check using format, shell parameter expansion safety patterns ${VAR-} not found in setup.sh, and Biome generator enhancements not visible via grep patterns, suggesting either commit not pushed, wrong branch being verified, or fixes not actually implemented despite detailed documentation claiming completion.

Applied to files:

  • package.json
📚 Learning: 2025-08-29T20:27:03.108Z
Learnt from: CR
PR: outfitter-dev/rulesets#0
File: AGENTS.md:0-0
Timestamp: 2025-08-29T20:27:03.108Z
Learning: Run pnpm turbo lint, typecheck, build, and test before submitting; all must pass

Applied to files:

  • package.json
📚 Learning: 2025-06-22T11:43:29.772Z
Learnt from: galligan
PR: outfitter-dev/monorepo#0
File: :0-0
Timestamp: 2025-06-22T11:43:29.772Z
Learning: TypeScript NodeNext module resolution requires explicit re-exports in packages/contracts/typescript/src/index.ts to make internal symbols visible to external consumers, not just wildcard re-exports.

Applied to files:

  • packages/core/src/interfaces/index.ts
📚 Learning: 2025-09-01T17:50:46.629Z
Learnt from: galligan
PR: outfitter-dev/rulesets#0
File: :0-0
Timestamp: 2025-09-01T17:50:46.629Z
Learning: User galligan successfully implemented comprehensive feedback for PR #88 Bun migration CI/CD workflow, creating enterprise-grade GitHub Actions automation including: sophisticated composite action ./.github/actions/setup-bun-and-deps/action.yml with conditional execution (run-lint/test/build inputs), security hardening with SHA-pinned actions (actions/checkout08eba0b, oven-sh/setup-bun735343b, changesets/actione0145ed), proper bun.lockb file management (113KB) replacing old bun.lock, production-ready release job with timeout-minutes: 30, explicit permissions (contents: write, pull-requests: write), consistent BUN_VERSION: 1.2.21 environment variable, and perfect YAML formatting with zero trailing spaces and proper EOF newlines. This demonstrates galligan's continued systematic approach to implementing feedback with gold standard technical excellence and comprehensive verification.

Applied to files:

  • .github/actions/setup-bun-and-deps/action.yml
📚 Learning: 2025-09-01T17:50:46.629Z
Learnt from: galligan
PR: outfitter-dev/rulesets#0
File: :0-0
Timestamp: 2025-09-01T17:50:46.629Z
Learning: User galligan successfully implemented comprehensive CodeRabbit and Copilot feedback for PR #88 Bun migration CI/CD workflow, including: eliminating code duplication by creating composite action .github/actions/setup-bun-and-deps/action.yml for reusable setup process, pinning actions to specific SHAs for security (actions/checkout08eba0b, oven-sh/setup-bun735343b, changesets/actione0145ed), fixing bun.lockb filename issue by renaming from bun.lock for proper Bun lockfile format, hardening release job with timeout-minutes: 30, explicit permissions (contents: write, pull-requests: write), and BUN_VERSION environment variable for consistency, and achieving perfect YAML formatting by removing trailing spaces and adding final newline. This demonstrates galligan's continued systematic approach to implementing feedback with production-ready GitHub Actions automation following enterprise-grade technical standards.

Applied to files:

  • .github/actions/setup-bun-and-deps/action.yml
📚 Learning: 2025-08-24T11:27:06.182Z
Learnt from: CR
PR: outfitter-dev/monorepo#0
File: CLAUDE.md:0-0
Timestamp: 2025-08-24T11:27:06.182Z
Learning: Always use Bun (not npm/yarn/pnpm) for installs, scripts, and updates

Applied to files:

  • .github/actions/setup-bun-and-deps/action.yml
📚 Learning: 2025-08-18T18:17:52.697Z
Learnt from: CR
PR: outfitter-dev/monorepo#0
File: .cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc:0-0
Timestamp: 2025-08-18T18:17:52.697Z
Learning: Default to using Bun instead of Node.js for running, testing, building, and serving applications

Applied to files:

  • .github/actions/setup-bun-and-deps/action.yml
📚 Learning: 2025-08-29T20:27:03.108Z
Learnt from: CR
PR: outfitter-dev/rulesets#0
File: AGENTS.md:0-0
Timestamp: 2025-08-29T20:27:03.108Z
Learning: Applies to **/*.ts : Use API markers: mixd-api for breaking changes or deprecated functionality

Applied to files:

  • packages/core/tests/integration/e2e.spec.ts
📚 Learning: 2025-08-24T11:27:06.182Z
Learnt from: CR
PR: outfitter-dev/monorepo#0
File: CLAUDE.md:0-0
Timestamp: 2025-08-24T11:27:06.182Z
Learning: Applies to packages/**/src/__tests__/**/*.test.{ts,tsx} : Place unit tests under src/__tests__ and name them *.test.ts(x) (Vitest)

Applied to files:

  • packages/core/tests/integration/e2e.spec.ts
  • packages/core/vitest.config.ts
📚 Learning: 2025-08-18T18:12:55.183Z
Learnt from: CR
PR: outfitter-dev/monorepo#0
File: packages/contracts/ts/CLAUDE.md:0-0
Timestamp: 2025-08-18T18:12:55.183Z
Learning: Applies to packages/contracts/ts/**/*.test.ts : Create dedicated test files for sub-path entry points (e.g., zod-specific tests) to isolate dependency-aware logic.

Applied to files:

  • packages/core/tests/integration/e2e.spec.ts
📚 Learning: 2025-08-18T18:10:42.517Z
Learnt from: CR
PR: outfitter-dev/monorepo#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-08-18T18:10:42.517Z
Learning: Applies to **/*.{test,spec}.{js,jsx,ts,tsx} : Don't nest describe() blocks too deeply in test files

Applied to files:

  • packages/core/tests/integration/e2e.spec.ts
  • packages/core/src/destinations/__tests__/cursor-plugin.spec.ts
📚 Learning: 2025-08-18T18:17:07.077Z
Learnt from: CR
PR: outfitter-dev/monorepo#0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-08-18T18:17:07.077Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Don't nest describe() blocks too deeply in test files

Applied to files:

  • packages/core/tests/integration/e2e.spec.ts
  • packages/core/src/destinations/__tests__/cursor-plugin.spec.ts
📚 Learning: 2025-08-18T18:10:42.517Z
Learnt from: CR
PR: outfitter-dev/monorepo#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-08-18T18:10:42.517Z
Learning: Applies to **/*.{test,spec}.{js,jsx,ts,tsx} : Don't have duplicate hooks in describe blocks

Applied to files:

  • packages/core/src/destinations/__tests__/cursor-plugin.spec.ts
🪛 YAMLlint (1.37.1)
lefthook.yml

[error] 23-23: no new line character at the end of file

(new-line-at-end-of-file)

.markdownlint-cli2.yaml

[error] 23-23: no new line character at the end of file

(new-line-at-end-of-file)

Comment thread lefthook.yml
run: "bun run typecheck"
test:
tags: [optional]
run: "bun run test" No newline at end of file

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

Add trailing newline to satisfy linters.
[new-line-at-end-of-file]

-      run: "bun run test"
+      run: "bun run test"
+
📝 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
run: "bun run test"
run: "bun run test"
🧰 Tools
🪛 YAMLlint (1.37.1)

[error] 23-23: no new line character at the end of file

(new-line-at-end-of-file)

🤖 Prompt for AI Agents
In lefthook.yml around line 23, the file is missing a trailing newline which
some linters require; add a single newline character at the end of the file so
the final line (run: "bun run test") is terminated by a newline. Ensure the file
ends with exactly one newline and save the file.

Comment thread package.json Outdated
Comment on lines 21 to 25
"check": "bunx ultracite format .",
"check:ci": "bunx ultracite lint .",
"check:all": "bun run format && bun run lint && bun run lint:md && bun run typecheck",
"ci": "bun run format && bun run lint && bun run lint:md && bun run typecheck && bun test",
"changeset": "changeset",

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Avoid writes in “check” and ensure CI runs workspace tests.

  • “check” currently formats (writes). Checks should be read-only.
  • “ci” uses bun test which will not run workspace tests via Turbo.
-    "check": "bunx ultracite format .",
-    "check:ci": "bunx ultracite lint .",
-    "check:all": "bun run format && bun run lint && bun run lint:md && bun run typecheck",
-    "ci": "bun run format && bun run lint && bun run lint:md && bun run typecheck && bun test",
+    "check": "bun run format:check && bun run lint && bun run lint:md && bun run typecheck",
+    "check:ci": "bunx ultracite lint .",
+    "check:all": "bun run format:check && bun run lint && bun run lint:md && bun run typecheck",
+    "ci": "bun run format && bun run lint && bun run lint:md && bun run typecheck && bun run test",
📝 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
"check": "bunx ultracite format .",
"check:ci": "bunx ultracite lint .",
"check:all": "bun run format && bun run lint && bun run lint:md && bun run typecheck",
"ci": "bun run format && bun run lint && bun run lint:md && bun run typecheck && bun test",
"changeset": "changeset",
"check": "bun run format:check && bun run lint && bun run lint:md && bun run typecheck",
"check:ci": "bunx ultracite lint .",
"check:all": "bun run format:check && bun run lint && bun run lint:md && bun run typecheck",
"ci": "bun run format && bun run lint && bun run lint:md && bun run typecheck && bun run test",
"changeset": "changeset",
🤖 Prompt for AI Agents
package.json lines 21-25: The "check" script runs a formatter that writes files
and should be read-only, and the "ci" script invokes `bun test` which doesn't
execute workspace tests via Turbo; change "check" to run the formatter in check
mode (e.g., add the formatter's --check/--list-different flag) so it only
reports differences, and update "ci" to run workspace tests through Turbo (e.g.,
invoke turbo run test or bunx turbo run test) instead of direct `bun test` so
all workspace packages' tests run in CI.

Comment thread packages/core/src/compiler/index.ts Outdated
Comment thread packages/core/src/destinations/__tests__/cursor-plugin.spec.ts
Comment thread packages/core/src/destinations/__tests__/windsurf-plugin.spec.ts Outdated
Comment thread packages/core/src/linter/__tests__/linter.spec.ts Outdated
Comment thread packages/core/src/linter/__tests__/linter.spec.ts
Comment thread packages/core/src/linter/__tests__/linter.spec.ts Outdated
Comment on lines +20 to 31
const result = parse(content);

expect(result.source.content).toBe(content);
expect(result.source.frontmatter).toEqual({
mixdown: 'v0',
title: 'Test Rule',
mixdown: "v0",
title: "Test Rule",
destinations: {
cursor: {
path: '.cursor/rules/test.mdc',
path: ".cursor/rules/test.mdc",
},
},
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Verify frontmatter key naming matches the new Frontmatter type.
You assert mixdown: "v0". Double-check the canonical field name in Frontmatter (e.g., rulesets vs mixdown) to avoid future drift.

Run:

If the canonical key differs, update the fixture accordingly.


🏁 Script executed:

#!/bin/bash
rg -nP --type=ts -C2 '\b(interface|type)\s+Frontmatter\b' packages/core/src/interfaces
rg -nP -C2 '\bmixdown\b|\brulesets\b' packages/core

Length of output: 19287


Replace mixdown with rulesets.version in frontmatter fixture
Update packages/core/src/parser/__tests__/parser.spec.ts (lines 20–31) to assert

frontmatter: {
  rulesets: { version: "v0" },
  title: "Test Rule",
  destinations: { … }
}

instead of using mixdown: "v0".

🤖 Prompt for AI Agents
In packages/core/src/parser/__tests__/parser.spec.ts around lines 20 to 31, the
test fixture asserts frontmatter using the deprecated key mixdown: "v0"; update
the assertion to replace that key with a nested rulesets.version field. Change
the expected frontmatter object to include rulesets: { version: "v0" } while
keeping title and destinations unchanged, ensuring the test checks
result.source.frontmatter.rulesets.version === "v0" instead of mixdown.

Comment thread packages/core/tests/integration/e2e.spec.ts Outdated
- Update cursor plugin to expect { encoding: 'utf8' } object instead of 'utf-8' string
- Update windsurf plugin to expect 'utf8' string instead of 'utf-8' string
- Update default paths from .mixdown/dist/ to .rulesets/dist/
- Fix node:fs mocking in test files
- Update success log message expectation
@galligan galligan force-pushed the feat_replace_eslint_with_biome_and_add_lefthook_for_git_hooks branch from 37b3cb0 to ac40457 Compare September 1, 2025 19:22
@galligan galligan marked this pull request as ready for review September 1, 2025 22:18
@galligan

galligan commented Sep 1, 2025

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Sep 1, 2025

Copy link
Copy Markdown
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Codex Review: Here are some suggestions.

Reply with @codex fix comments to fix any unresolved comments.

About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you open a pull request for review, mark a draft as ready, or comment "@codex review". If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex fix this CI failure" or "@codex address that feedback".

Comment thread packages/core/src/interfaces/logger.ts Outdated
Comment on lines +109 to +116
private createTransport(): pino.TransportTargetOptions | undefined {
if (process.env.RULESETS_LOG_PRETTY !== "true") {
return;
}

try {
// Check if pino-pretty is available
require.resolve("pino-pretty");

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[P1] Use of require breaks ESM when pretty logging enabled

The new PinoLogger calls require.resolve("pino-pretty") inside createTransport. This runs whenever RULESETS_LOG_PRETTY is set to "true". However, the package ships an ESM build (tsup outputs an .mjs bundle) where require is not defined. In that case new PinoLogger() throws a ReferenceError before logging can start, so enabling pretty logging crashes instead of gracefully falling back. Consider using createRequire(import.meta.url) or a dynamic import() to probe for pino-pretty so the ESM build can run without errors.

Useful? React with 👍 / 👎.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
packages/core/package.json (1)

1-48: Remove lingering ESLint references in documentation

  • Update or remove all ESLint mentions in the docs (e.g. docs/project/** and docs/plugins/**) so they reflect the post-migration tooling.
packages/core/src/linter/index.ts (1)

31-38: Fix JSDoc: function is synchronous (no Promise).

Return type is now sync; update the docs accordingly and align the version note.

 /**
  * Lints a parsed Rulesets document by validating its frontmatter.
- * For v0.1.0, this performs basic schema validation on the frontmatter.
+ * For v0, this performs basic schema validation on the frontmatter.
  *
  * @param parsedDoc - The parsed document to lint
  * @param config - Optional linter configuration
- * @returns A promise that resolves to an array of lint results
+ * @returns An array of lint results
  */
♻️ Duplicate comments (3)
packages/core/tests/integration/e2e.spec.ts (1)

9-15: Nice fix: mock the correct module specifier.

Switching to vi.mock("node:fs", …) resolves the prior issue.

packages/core/src/linter/__tests__/linter.spec.ts (1)

66-72: Past feedback applied: updated assertion string.

Assertion now targets “Missing required Rulesets version declaration”. Looks good.

packages/core/src/compiler/index.ts (1)

38-44: Frontmatter delimiter detection is now CRLF-safe — nice.

This addresses the prior feedback to trim and split with /\r?\n/.

🧹 Nitpick comments (21)
CHANGELOG.md (1)

1-1: Add compare/reference links for Keep a Changelog consistency

Append link refs for [0.1.0] (e.g., compare main...v0.1.0) at file end for easy navigation.

 ## [0.1.0] - 2025-09-01
+
+<!-- Links -->
+[0.1.0]: https://github.com/outfitter-dev/rulesets/compare/prev-tag...v0.1.0
packages/core/package.json (2)

24-25: Minor: unify lint script naming to reduce cognitive load

Both “lint” (checks) and “lint:fix” (formats) are fine, but consider aligning names with root (format vs lint) to avoid overlap.


28-31: Optional: mark package as side‑effect free for better tree‑shaking

Add sideEffects:false if the bundle is pure on import (appears so).

   "files": [
     "dist"
   ],
+  "sideEffects": false,

Also applies to: 36-43

package.json (2)

21-24: Avoid duplicate work in “check” pipeline

“check” and “check:all” re-run lint via format:check (which equals lint) and then lint again. Drop the first call to de-duplicate.

-    "check": "bun run format:check && bun run lint && bun run lint:md && bun run typecheck",
+    "check": "bun run lint && bun run lint:md && bun run typecheck",
-    "check:all": "bun run format:check && bun run lint && bun run lint:md && bun run typecheck",
+    "check:all": "bun run lint && bun run lint:md && bun run typecheck",

24-24: CI should not write files

Running “format” in CI writes; prefer read‑only checks.

-    "ci": "bun run format && bun run lint && bun run lint:md && bun run typecheck && bun run test",
+    "ci": "bun run lint && bun run lint:md && bun run typecheck && bun run test",
packages/core/src/interfaces/logger.ts (2)

110-129: ESM-safe pino-pretty detection

require.resolve can throw ReferenceError in ESM; use createRequire for robust resolution while keeping the graceful fallback.

-import pino from "pino";
+import pino from "pino";
+import { createRequire } from "node:module";
@@
   private createTransport(): pino.TransportTargetOptions | undefined {
     if (process.env.RULESETS_LOG_PRETTY !== "true") {
       return;
     }
 
     try {
-      // Check if pino-pretty is available
-      require.resolve("pino-pretty");
+      // Check if pino-pretty is available (ESM-safe)
+      const req = createRequire(import.meta.url);
+      req.resolve("pino-pretty");
       return {
         target: "pino-pretty",
         options: {
           colorize: true,
           ignore: "pid,hostname",
           translateTime: "SYS:standard",
         },
       };
     } catch {
       // pino-pretty not available, fall back to default transport
       return;
     }
   }

Also applies to: 3-3


5-6: Consider aligning levels with Pino’s full set

If you want environment parity with Pino, include “trace” and “fatal” in LogLevel and ordering.

-export type LogLevel = "debug" | "info" | "warn" | "error";
+export type LogLevel = "trace" | "debug" | "info" | "warn" | "error" | "fatal";
@@
-  const validLevels: LogLevel[] = ["debug", "info", "warn", "error"];
+  const validLevels: LogLevel[] = ["trace", "debug", "info", "warn", "error", "fatal"];
@@
-  const levels: LogLevel[] = ["debug", "info", "warn", "error"];
+  const levels: LogLevel[] = ["trace", "debug", "info", "warn", "error", "fatal"];

Also applies to: 24-27, 31-35

packages/core/src/destinations/cursor-plugin.ts (1)

3-5: Minor: prefer named import for path in TS without esModuleInterop

If tsconfig disables synthetic default imports, switch to import * as path from "node:path".

-import path from "node:path";
+import * as path from "node:path";
packages/core/src/interfaces/__tests__/logger.spec.ts (2)

1-2: Drop hard-coded version in header.

Avoid embedding version (“v0.2.0”) in test comments; it drifts. Keep a single, generic header.

Apply:

-// :M: tldr: Tests for Logger interface implementations
-// :M: v0.2.0: Tests for both ConsoleLogger and PinoLogger implementations
+// Tests for Logger interface implementations (ConsoleLogger + PinoLogger)

13-16: Use spies instead of reassigning global console.

Directly overwriting console methods is brittle; prefer vi.spyOn and drop manual restores.

Apply:

-const originalConsoleDebug = console.debug;
-const originalConsoleInfo = console.info;
-const originalConsoleWarn = console.warn;
-const originalConsoleError = console.error;
+// originals not needed when using spies

 beforeEach(() => {
-  console.debug = mockConsoleDebug;
-  console.info = mockConsoleInfo;
-  console.warn = mockConsoleWarn;
-  console.error = mockConsoleError;
+  vi.spyOn(console, "debug").mockImplementation(mockConsoleDebug);
+  vi.spyOn(console, "info").mockImplementation(mockConsoleInfo);
+  vi.spyOn(console, "warn").mockImplementation(mockConsoleWarn);
+  vi.spyOn(console, "error").mockImplementation(mockConsoleError);
   mockConsoleDebug.mockClear();
   mockConsoleInfo.mockClear();
   mockConsoleWarn.mockClear();
   mockConsoleError.mockClear();
   logger = new ConsoleLogger();
 });

 afterEach(() => {
-  console.debug = originalConsoleDebug;
-  console.info = originalConsoleInfo;
-  console.warn = originalConsoleWarn;
-  console.error = originalConsoleError;
+  vi.restoreAllMocks();

Also applies to: 22-31, 35-38

packages/core/tests/integration/e2e.spec.ts (4)

60-60: Make encoding assertion robust (utf8 vs utf-8).

Avoid brittle exact match; accept both spellings.

Apply:

-expect(fs.readFile).toHaveBeenCalledWith("./test.mix.md", "utf-8");
+expect(fs.readFile).toHaveBeenCalledWith("./test.mix.md", expect.stringMatching(/^utf-?8$/));

87-89: Don’t pin the exact version in success log assertion.

Future version bumps will break this test unnecessarily.

Apply:

-expect(mockLogger.info).toHaveBeenCalledWith(
-  "Rulesets v0.1.0 processing completed successfully!"
-);
+expect(mockLogger.info).toHaveBeenCalledWith(
+  expect.stringContaining("Rulesets v0")
+);

121-133: Add negative I/O assertions on read failure.

Assert no mkdir/writeFile when read fails.

Apply:

   await expect(runRulesetsV0("./nonexistent.mix.md", mockLogger)).rejects.toThrow(
     "File not found"
   );

   expect(mockLogger.error).toHaveBeenCalledWith(
     "Failed to read source file: ./nonexistent.mix.md",
     error
   );
+  expect(fs.mkdir).not.toHaveBeenCalled();
+  expect(fs.writeFile).not.toHaveBeenCalled();

174-174: Rename test to reflect Rulesets terminology.

Avoid lingering “Mixdown” naming.

Apply:

-it("should preserve Mixdown markers in output", async () => {
+it("should preserve Rulesets templating markers in output", async () => {
packages/core/src/linter/index.ts (2)

71-92: Tighten rulesets validation and align example with v0.

Handle arrays explicitly, ensure version is a string, and use v0 in the example for consistency.

-        message: `Missing required ${getFieldName("/rulesets")}. Specify the Rulesets version (e.g., rulesets: { version: "0.1.0" }).`,
+        message: `Missing required ${getFieldName("/rulesets")}. Specify the Rulesets version (e.g., rulesets: { version: "v0" }).`,
...
-    } else if (
-      typeof frontmatter.rulesets !== "object" ||
-      frontmatter.rulesets === null ||
-      !("version" in frontmatter.rulesets)
-    ) {
+    } else if (
+      typeof frontmatter.rulesets !== "object" ||
+      frontmatter.rulesets === null ||
+      Array.isArray(frontmatter.rulesets) ||
+      typeof (frontmatter.rulesets as any).version !== "string"
+    ) {
       results.push({
-        message: `Invalid ${getFieldName("/rulesets")}. Expected object with version property, got ${typeof frontmatter.rulesets}.`,
+        message: `Invalid ${getFieldName("/rulesets")}. Expected object with string "version", got ${Array.isArray(frontmatter.rulesets) ? "array" : typeof frontmatter.rulesets}.`,
         line: 1,
         column: 1,
         severity: "error",
       });

103-113: Micro‑optimise allowed destinations membership check.

Use a Set to avoid repeated linear includes scans for large lists.

-    } else if (config.allowedDestinations && config.allowedDestinations.length > 0) {
-      // Validate allowed destinations if configured
-      for (const destId of Object.keys(frontmatter.destinations)) {
-        if (!config.allowedDestinations.includes(destId)) {
+    } else if (config.allowedDestinations && config.allowedDestinations.length > 0) {
+      // Validate allowed destinations if configured
+      const allowed = new Set(config.allowedDestinations);
+      for (const destId of Object.keys(frontmatter.destinations)) {
+        if (!allowed.has(destId)) {
           results.push({
             message: `Unknown destination "${destId}". Allowed destinations: ${config.allowedDestinations.join(", ")}.`,
             line: 1,
             column: 1,
             severity: "warning",
           });
         }
       }
     }
packages/core/src/linter/__tests__/linter.spec.ts (4)

74-96: Rename test to reflect current validation semantics.

The linter expects an object with a string version; the title still mentions “not a string”.

-    it("should error when rulesets field is not a string", () => {
+    it("should error when rulesets is not an object with a string 'version'", () => {

124-151: Assert exactly one “unknown destination” warning for clarity.

Optional: verify only a single unknown‑destination warning is emitted.

       const destWarning = results.find((r) => r.message.includes("Unknown destination"));
       expect(destWarning).toBeDefined();
       expect(destWarning!.severity).toBe("warning");
+      expect(results.filter((r) => r.message.includes("Unknown destination")).length).toBe(1);

1-1: Update file header wording.

Use current terminology.

-// TLDR: Unit tests for the Rulesets linter module (mixd-v0)
+// TLDR: Unit tests for the Rulesets linter module (v0)

6-6: Optional: reduce fixture duplication with a tiny factory.

Keeps tests tight and focused.

// helper (top-level in this file)
function baseDoc(overrides: Partial<ParsedDoc["source"]> = {}): ParsedDoc {
  return {
    source: {
      content: "",
      ...overrides,
    },
    ast: { stems: [], imports: [], variables: [], markers: [] },
  } as ParsedDoc;
}
packages/core/src/compiler/index.ts (1)

41-44: Optionally support YAML '...' end delimiter.

Frontmatter can also be terminated by '...'. Quick win if you want broader compatibility.

Apply this diff:

-        if (lines[i].trim() === "---") {
+        const t = lines[i].trim();
+        if (t === "---" || t === "...") {
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • 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 37b3cb0 and c82e7bc.

⛔ Files ignored due to path filters (1)
  • bun.lock is excluded by !**/*.lock
📒 Files selected for processing (18)
  • .github/workflows/claude-code-review.yml (0 hunks)
  • CHANGELOG.md (1 hunks)
  • biome.json (1 hunks)
  • package.json (2 hunks)
  • packages/core/package.json (1 hunks)
  • packages/core/src/compiler/index.ts (4 hunks)
  • packages/core/src/destinations/__tests__/cursor-plugin.spec.ts (8 hunks)
  • packages/core/src/destinations/__tests__/windsurf-plugin.spec.ts (9 hunks)
  • packages/core/src/destinations/cursor-plugin.ts (3 hunks)
  • packages/core/src/destinations/windsurf-plugin.ts (3 hunks)
  • packages/core/src/index.ts (6 hunks)
  • packages/core/src/interfaces/__tests__/logger.spec.ts (1 hunks)
  • packages/core/src/interfaces/frontmatter.ts (1 hunks)
  • packages/core/src/interfaces/logger.ts (2 hunks)
  • packages/core/src/linter/__tests__/linter.spec.ts (9 hunks)
  • packages/core/src/linter/index.ts (6 hunks)
  • packages/core/tests/integration/e2e.spec.ts (5 hunks)
  • tsconfig.json (1 hunks)
💤 Files with no reviewable changes (1)
  • .github/workflows/claude-code-review.yml
🚧 Files skipped from review as they are similar to previous changes (7)
  • biome.json
  • packages/core/src/interfaces/frontmatter.ts
  • tsconfig.json
  • packages/core/src/destinations/tests/windsurf-plugin.spec.ts
  • packages/core/src/destinations/tests/cursor-plugin.spec.ts
  • packages/core/src/destinations/windsurf-plugin.ts
  • packages/core/src/index.ts
🧰 Additional context used
🧠 Learnings (42)
📓 Common learnings
Learnt from: galligan
PR: outfitter-dev/rulesets#0
File: :0-0
Timestamp: 2025-08-15T18:44:08.632Z
Learning: The user (galligan) successfully implemented all PR review feedback after initial discrepancies were identified, including: version marker format standardization from ruleset-v* to mixd-v* throughout PLAN-rulesets-v0.md, cross-platform build scripts using rimraf in packages/compiler/package.json, accurate package description removing CommonMark claims in root package.json, and proper commit tracking with specific hashes (f27e034 + 9ac6df9).
Learnt from: galligan
PR: outfitter-dev/monorepo#0
File: :0-0
Timestamp: 2025-08-23T01:01:27.260Z
Learning: User galligan successfully implemented comprehensive review feedback for PR #93 Bun-native optimization, systematically addressing all critical and important issues including: complete Turborepo reference removal from documentation and codebase, proper build.mjs error logging with array formatting and null coalescing, bunfig.toml security improvements (disabled auto="fallback", fixed watchExclude, moved telemetry to top-level), package.json script optimization (build:all alias, CI enhancement with test:all), and lefthook ultracite command fix (removed invalid --write flag), achieving -422 lines of legacy code removal while adding +18 lines of focused improvements with zero breaking changes and enhanced security, demonstrating gold standard systematic implementation following established patterns from previous PRs.
Learnt from: galligan
PR: outfitter-dev/rulesets#0
File: :0-0
Timestamp: 2025-08-19T17:49:13.493Z
Learning: User galligan provided comprehensive feedback on PR review issues, categorizing them by priority (high/medium/minor) and requesting systematic fixes including cross-platform build compatibility (rimraf instead of rm -rf), test framework alignment (bun:test instead of Jest), documentation-code consistency for directory exclusions, extraction of shared discovery logic to reduce duplication, and proper integration test implementation. Successfully addressed all feedback with complete code solutions.
Learnt from: galligan
PR: outfitter-dev/rulesets#0
File: :0-0
Timestamp: 2025-09-01T22:04:41.689Z
Learning: User galligan successfully implemented comprehensive CodeRabbit feedback for PR #91 pino logger implementation, including: moving pino-pretty to optionalDependencies with graceful fallback using require.resolve() try/catch, implementing RULESETS_LOG_PRETTY environment gate for opt-in pretty formatting, adding getValidLogLevel() helper for level validation with fallback to 'info', aligning ConsoleLogger and PinoLogger level filtering with shouldLog() helper, implementing native pino error logging patterns with { err, msg } convention, improving object argument handling with direct merging, adding scoped biome.json overrides for console usage in logger files only, and making error stack test assertions resilient using substring matching. All 77 tests pass with comprehensive coverage for level filtering, environment validation, and graceful fallbacks, demonstrating production-ready dual-logger architecture following established systematic implementation patterns.
Learnt from: galligan
PR: outfitter-dev/rulesets#0
File: :0-0
Timestamp: 2025-08-26T04:15:29.029Z
Learning: User galligan reported comprehensive fixes for PR #84 critical CodeRabbit feedback including: turbo dependency addition for CI build failure, codex provider addition to sandbox VALID_PROVIDER_TYPES, DEFAULT_CONFIG parallelCompilation property, RegExp lastIndex hazard fixes using matchAll, parallel compilation test logging enhancements, partial cache improvements storing compiled templates, .rule.md extension support for @-partial resolution, clearPartialCache fixes for hbs.partials registry, and silent LogLevel type addition. Verification confirmed extensive codex provider implementation, sophisticated CI quick fix workflow, robust partial cache system, and parallel compilation test infrastructure. Some specific claims require additional verification due to possible branch visibility issues, consistent with galligan's systematic implementation track record across multiple PRs.
Learnt from: galligan
PR: outfitter-dev/monorepo#0
File: :0-0
Timestamp: 2025-08-22T21:25:13.038Z
Learning: User galligan demonstrated exceptional systematic implementation for commit b93dcf8 in PR #90, comprehensively addressing all review feedback with production-grade fixes including: README documentation alignment using proper ≥ symbol matching package.json engines exactly, package.json script semantic corrections (prepare script using 'bun run config:mdlint', format/check distinction with format writing and check verifying), shell script hardening with defaulted parameter expansions for set -u compatibility (${VAR-} pattern), Biome generator architecture improvements with centralized BIOME_SCHEMA_URL constant and Bun subprocess API with 300s timeouts, enhanced error handling with exit codes and command context, SILENCE_BIOME_WARNINGS environment gate for developer experience, and pragmatic schema version strategy maintaining 2.1.4 for base config compatibility while using 2.2.0 for generated configs, showcasing systematic precision with comprehensive verification and documentation quali...
Learnt from: galligan
PR: outfitter-dev/rulesets#0
File: :0-0
Timestamp: 2025-09-01T22:04:41.689Z
Learning: User galligan successfully implemented comprehensive CodeRabbit feedback for PR #91 pino logger implementation with exceptional quality, including: correctly moving pino-pretty to optionalDependencies with graceful require.resolve() fallback in createTransport() method, implementing RULESETS_LOG_PRETTY environment gate for opt-in pretty formatting, adding getValidLogLevel() helper with validation against known levels and fallback to 'info', implementing shouldLog() helper for consistent level filtering across ConsoleLogger and PinoLogger, using native pino error logging patterns with { err: errorObj, msg: errorObj.message } convention, improving object argument handling with direct merging for single objects and args array for multiple arguments, adding properly scoped biome.json overrides for console usage in logger.ts and test files only, removing all biome-ignore comments from production code, and implementing comprehensive test coverage with 87 test cases covering level validation,...
Learnt from: galligan
PR: outfitter-dev/rulesets#0
File: :0-0
Timestamp: 2025-09-01T17:50:46.629Z
Learning: User galligan successfully implemented comprehensive CodeRabbit and Copilot feedback for PR #88 Bun migration CI/CD workflow, including: eliminating code duplication by creating composite action .github/actions/setup-bun-and-deps/action.yml for reusable setup process, pinning actions to specific SHAs for security (actions/checkout08eba0b, oven-sh/setup-bun735343b, changesets/actione0145ed), fixing bun.lockb filename issue by renaming from bun.lock for proper Bun lockfile format, hardening release job with timeout-minutes: 30, explicit permissions (contents: write, pull-requests: write), and BUN_VERSION environment variable for consistency, and achieving perfect YAML formatting by removing trailing spaces and adding final newline. This demonstrates galligan's continued systematic approach to implementing feedback with production-ready GitHub Actions automation following enterprise-grade technical standards.
Learnt from: galligan
PR: outfitter-dev/blz#0
File: :0-0
Timestamp: 2025-08-27T17:01:21.600Z
Learning: User galligan successfully implemented comprehensive fixes for all 4 CodeRabbit review comments in PR #43 commit e7da15d, including: defensive error handling replacing unreachable!() with proper anyhow::bail! error message for NotModified on initial fetch, updating message from "Not modified" to "Up-to-date" in update command, adding etag and last_modified fields to FetchResult::NotModified variant for consistent metadata handling, and implementing atomic metadata writes using temp file pattern (.json.tmp) with fs::rename for data integrity, all within a massive 39K+ line initial codebase commit while maintaining production-quality standards.
<!--
Learnt from: galligan
PR: outfitter-dev/monorepo#0
File: :0-0
Timestamp: 2025-08-15T16:42:04.468Z
Learning: The user (galligan) successfully implemented comprehensive fixes addressing critical configuration issues in biome.json (globals format, files configuration), bunfig.toml (exact setting), and VS Code settings (removing invalid multi-language overrides), while also resolving documentation contradictions and ensuring Ultracite preset compatibility over strict Biome 2.2.0 schema compliance.
Learnt from: CR
PR: outfitter-dev/monorepo#0
File: packages/fieldguides/CLAUDE.md:0-0
Timestamp: 2025-08-18T18:13:30.555Z
Learning: Applies to packages/fieldguides/**/*.md : Always lint markdown files with markdownlint-cli2 and fix issues before committing
📚 Learning: 2025-09-01T22:04:41.689Z
Learnt from: galligan
PR: outfitter-dev/rulesets#0
File: :0-0
Timestamp: 2025-09-01T22:04:41.689Z
Learning: User galligan successfully implemented comprehensive CodeRabbit feedback for PR #91 pino logger implementation, including: moving pino-pretty to optionalDependencies with graceful fallback using require.resolve() try/catch, implementing RULESETS_LOG_PRETTY environment gate for opt-in pretty formatting, adding getValidLogLevel() helper for level validation with fallback to 'info', aligning ConsoleLogger and PinoLogger level filtering with shouldLog() helper, implementing native pino error logging patterns with { err, msg } convention, improving object argument handling with direct merging, adding scoped biome.json overrides for console usage in logger files only, and making error stack test assertions resilient using substring matching. All 77 tests pass with comprehensive coverage for level filtering, environment validation, and graceful fallbacks, demonstrating production-ready dual-logger architecture following established systematic implementation patterns.

Applied to files:

  • packages/core/src/interfaces/__tests__/logger.spec.ts
  • packages/core/src/interfaces/logger.ts
📚 Learning: 2025-09-01T22:04:41.689Z
Learnt from: galligan
PR: outfitter-dev/rulesets#0
File: :0-0
Timestamp: 2025-09-01T22:04:41.689Z
Learning: User galligan successfully implemented comprehensive CodeRabbit feedback for PR #91 pino logger implementation with exceptional quality, including: correctly moving pino-pretty to optionalDependencies with graceful require.resolve() fallback in createTransport() method, implementing RULESETS_LOG_PRETTY environment gate for opt-in pretty formatting, adding getValidLogLevel() helper with validation against known levels and fallback to 'info', implementing shouldLog() helper for consistent level filtering across ConsoleLogger and PinoLogger, using native pino error logging patterns with { err: errorObj, msg: errorObj.message } convention, improving object argument handling with direct merging for single objects and args array for multiple arguments, adding properly scoped biome.json overrides for console usage in logger.ts and test files only, removing all biome-ignore comments from production code, and implementing comprehensive test coverage with 87 test cases covering level validation,...

Applied to files:

  • packages/core/src/interfaces/__tests__/logger.spec.ts
  • packages/core/src/interfaces/logger.ts
📚 Learning: 2025-08-31T14:18:47.842Z
Learnt from: galligan
PR: outfitter-dev/blz#0
File: :0-0
Timestamp: 2025-08-31T14:18:47.842Z
Learning: User galligan correctly pointed out that after modifying commits, CodeRabbit's memory may become outdated. The files were reorganized from .agents/rules/ directly to .agents/rules/conventions/rust/ subdirectory, and the primary documentation moved from CLAUDE.md to AGENTS.md files. All technical fixes (async-patterns handle.await??, compiler-loop.md jq -sr usage, agent-check.sh permissions and jq usage, storage layout documentation, MCP protocol version 2024-11-05) were properly implemented despite the file structure changes.

Applied to files:

  • packages/core/src/linter/__tests__/linter.spec.ts
📚 Learning: 2025-08-18T18:10:42.517Z
Learnt from: CR
PR: outfitter-dev/monorepo#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-08-18T18:10:42.517Z
Learning: Applies to **/*.{test,spec}.{js,jsx,ts,tsx} : Ensure assertion functions (like expect) are placed inside an it() call

Applied to files:

  • packages/core/src/linter/__tests__/linter.spec.ts
  • packages/core/tests/integration/e2e.spec.ts
📚 Learning: 2025-08-18T18:17:07.077Z
Learnt from: CR
PR: outfitter-dev/monorepo#0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-08-18T18:17:07.077Z
Learning: Applies to **/*.{test,spec}.{js,jsx,ts,tsx} : Ensure the assertion function (e.g., expect) is inside an it() call

Applied to files:

  • packages/core/src/linter/__tests__/linter.spec.ts
  • packages/core/tests/integration/e2e.spec.ts
📚 Learning: 2025-08-18T18:17:07.077Z
Learnt from: CR
PR: outfitter-dev/monorepo#0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-08-18T18:17:07.077Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Ensure a message is passed when creating a built-in error

Applied to files:

  • packages/core/src/interfaces/logger.ts
📚 Learning: 2025-08-18T18:10:42.517Z
Learnt from: CR
PR: outfitter-dev/monorepo#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-08-18T18:10:42.517Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : Ensure a message is passed when creating a built-in error

Applied to files:

  • packages/core/src/interfaces/logger.ts
📚 Learning: 2025-08-18T18:12:55.183Z
Learnt from: CR
PR: outfitter-dev/monorepo#0
File: packages/contracts/ts/CLAUDE.md:0-0
Timestamp: 2025-08-18T18:12:55.183Z
Learning: Applies to packages/contracts/ts/**/*.ts : Keep error codes and messages consistent across the codebase.

Applied to files:

  • packages/core/src/interfaces/logger.ts
📚 Learning: 2025-08-18T18:12:55.183Z
Learnt from: CR
PR: outfitter-dev/monorepo#0
File: packages/contracts/ts/CLAUDE.md:0-0
Timestamp: 2025-08-18T18:12:55.183Z
Learning: Applies to packages/contracts/ts/**/*.ts : Ensure all failure modes are handled; no missing error handling paths.

Applied to files:

  • packages/core/src/interfaces/logger.ts
📚 Learning: 2025-08-15T18:44:08.632Z
Learnt from: galligan
PR: outfitter-dev/rulesets#0
File: :0-0
Timestamp: 2025-08-15T18:44:08.632Z
Learning: The user (galligan) successfully implemented all PR review feedback after initial discrepancies were identified, including: version marker format standardization from ruleset-v* to mixd-v* throughout PLAN-rulesets-v0.md, cross-platform build scripts using rimraf in packages/compiler/package.json, accurate package description removing CommonMark claims in root package.json, and proper commit tracking with specific hashes (f27e034 + 9ac6df9).

Applied to files:

  • packages/core/tests/integration/e2e.spec.ts
  • CHANGELOG.md
  • packages/core/package.json
📚 Learning: 2025-06-28T02:42:56.229Z
Learnt from: galligan
PR: outfitter-dev/monorepo#0
File: :0-0
Timestamp: 2025-06-28T02:42:56.229Z
Learning: The user properly justified keeping complex promisify mocks in tests because they accurately simulate Node.js util.promisify() behavior, which is essential for testing callback-to-promise conversion that production code relies on.

Applied to files:

  • packages/core/tests/integration/e2e.spec.ts
📚 Learning: 2025-08-18T18:12:55.183Z
Learnt from: CR
PR: outfitter-dev/monorepo#0
File: packages/contracts/ts/CLAUDE.md:0-0
Timestamp: 2025-08-18T18:12:55.183Z
Learning: Applies to packages/contracts/ts/**/*.test.ts : Create dedicated test files for sub-path entry points (e.g., zod-specific tests) to isolate dependency-aware logic.

Applied to files:

  • packages/core/tests/integration/e2e.spec.ts
📚 Learning: 2025-08-18T18:10:42.517Z
Learnt from: CR
PR: outfitter-dev/monorepo#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-08-18T18:10:42.517Z
Learning: Applies to **/*.{test,spec}.{js,jsx,ts,tsx} : Don't use export or module.exports in test files

Applied to files:

  • packages/core/tests/integration/e2e.spec.ts
📚 Learning: 2025-08-18T18:12:19.906Z
Learnt from: CR
PR: outfitter-dev/monorepo#0
File: packages/cli/CLAUDE.md:0-0
Timestamp: 2025-08-18T18:12:19.906Z
Learning: Applies to packages/cli/src/**/*.ts : Use Node.js path.join() for all file path construction to ensure cross-platform compatibility

Applied to files:

  • packages/core/tests/integration/e2e.spec.ts
📚 Learning: 2025-08-18T18:10:42.517Z
Learnt from: CR
PR: outfitter-dev/monorepo#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-08-18T18:10:42.517Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : Use the node: protocol for Node.js builtin modules

Applied to files:

  • packages/core/tests/integration/e2e.spec.ts
📚 Learning: 2025-08-18T18:17:07.077Z
Learnt from: CR
PR: outfitter-dev/monorepo#0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-08-18T18:17:07.077Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Use the node: protocol for Node.js builtin modules

Applied to files:

  • packages/core/tests/integration/e2e.spec.ts
📚 Learning: 2025-08-18T18:17:52.697Z
Learnt from: CR
PR: outfitter-dev/monorepo#0
File: .cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc:0-0
Timestamp: 2025-08-18T18:17:52.697Z
Learning: Applies to **/*.test.@(ts|tsx|js|jsx) : Write tests using Bun’s test API: `import { test, expect } from "bun:test"`; do not use Jest or Vitest APIs

Applied to files:

  • packages/core/tests/integration/e2e.spec.ts
  • package.json
📚 Learning: 2025-08-18T18:10:42.517Z
Learnt from: CR
PR: outfitter-dev/monorepo#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-08-18T18:10:42.517Z
Learning: Applies to **/*.{test,spec}.{js,jsx,ts,tsx} : Don't nest describe() blocks too deeply in test files

Applied to files:

  • packages/core/tests/integration/e2e.spec.ts
📚 Learning: 2025-08-18T18:17:07.077Z
Learnt from: CR
PR: outfitter-dev/monorepo#0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-08-18T18:17:07.077Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Don't nest describe() blocks too deeply in test files

Applied to files:

  • packages/core/tests/integration/e2e.spec.ts
📚 Learning: 2025-08-24T11:27:06.182Z
Learnt from: CR
PR: outfitter-dev/monorepo#0
File: CLAUDE.md:0-0
Timestamp: 2025-08-24T11:27:06.182Z
Learning: Applies to packages/**/src/__tests__/**/*.test.{ts,tsx} : Place unit tests under src/__tests__ and name them *.test.ts(x) (Vitest)

Applied to files:

  • packages/core/tests/integration/e2e.spec.ts
📚 Learning: 2025-08-14T03:51:26.625Z
Learnt from: CR
PR: outfitter-dev/rulesets#0
File: CLAUDE.md:0-0
Timestamp: 2025-08-14T03:51:26.625Z
Learning: Applies to .mixdown/src/**/*.{mix.md,md} : Author source rules in Mixdown Markdown using .mix.md (preferred) or .md extensions

Applied to files:

  • packages/core/tests/integration/e2e.spec.ts
  • CHANGELOG.md
📚 Learning: 2025-08-18T18:14:06.160Z
Learnt from: CR
PR: outfitter-dev/monorepo#0
File: shared/configs/changeset/CLAUDE.md:0-0
Timestamp: 2025-08-18T18:14:06.160Z
Learning: Applies to shared/configs/changeset/**/package.json : Ensure package.json includes scripts: build, dev, and typecheck (invoked via pnpm)

Applied to files:

  • package.json
  • packages/core/package.json
📚 Learning: 2025-08-18T18:17:52.697Z
Learnt from: CR
PR: outfitter-dev/monorepo#0
File: .cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc:0-0
Timestamp: 2025-08-18T18:17:52.697Z
Learning: Applies to package.json : Avoid Vite scripts/dependencies; use Bun’s HTML imports and bundler instead

Applied to files:

  • package.json
  • packages/core/package.json
📚 Learning: 2025-08-22T21:25:13.038Z
Learnt from: galligan
PR: outfitter-dev/monorepo#0
File: :0-0
Timestamp: 2025-08-22T21:25:13.038Z
Learning: Verification revealed discrepancies between galligan's claimed fixes for PR #90 commit b93dcf8 and actual file contents: README still shows "Node.js 20+ LTS" vs package.json ">=20" (not aligned), prepare script still contains invalid "bun config:mdlint" syntax (missing run keyword), format/check script semantics remain swapped with format using lint and check using format, shell parameter expansion safety patterns ${VAR-} not found in setup.sh, and Biome generator enhancements not visible via grep patterns, suggesting either commit not pushed, wrong branch being verified, or fixes not actually implemented despite detailed documentation claiming completion.

Applied to files:

  • package.json
📚 Learning: 2025-08-18T18:17:52.697Z
Learnt from: CR
PR: outfitter-dev/monorepo#0
File: .cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc:0-0
Timestamp: 2025-08-18T18:17:52.697Z
Learning: Applies to package.json : Use `bun <file>` (or `bun --hot`) for direct script execution instead of `node` or `ts-node` in scripts

Applied to files:

  • package.json
  • packages/core/package.json
📚 Learning: 2025-08-18T18:17:52.697Z
Learnt from: CR
PR: outfitter-dev/monorepo#0
File: .cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc:0-0
Timestamp: 2025-08-18T18:17:52.697Z
Learning: Applies to package.json : Use `bun build <file.html|file.ts|file.css>` for build scripts instead of webpack or esbuild

Applied to files:

  • package.json
  • packages/core/package.json
📚 Learning: 2025-08-18T18:17:52.697Z
Learnt from: CR
PR: outfitter-dev/monorepo#0
File: .cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc:0-0
Timestamp: 2025-08-18T18:17:52.697Z
Learning: Applies to package.json : Use `bun test` to run tests instead of `jest` or `vitest` in scripts

Applied to files:

  • package.json
  • packages/core/package.json
📚 Learning: 2025-08-29T20:27:03.108Z
Learnt from: CR
PR: outfitter-dev/rulesets#0
File: AGENTS.md:0-0
Timestamp: 2025-08-29T20:27:03.108Z
Learning: Run pnpm turbo lint, typecheck, build, and test before submitting; all must pass

Applied to files:

  • package.json
📚 Learning: 2025-08-18T18:17:52.697Z
Learnt from: CR
PR: outfitter-dev/monorepo#0
File: .cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc:0-0
Timestamp: 2025-08-18T18:17:52.697Z
Learning: Applies to package.json : Use `bun run <script>` instead of `npm run`, `yarn run`, or `pnpm run` in package.json scripts

Applied to files:

  • package.json
📚 Learning: 2025-08-18T18:17:52.697Z
Learnt from: CR
PR: outfitter-dev/monorepo#0
File: .cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc:0-0
Timestamp: 2025-08-18T18:17:52.697Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : Use `Bun.$` for running shell commands instead of `execa`

Applied to files:

  • package.json
📚 Learning: 2025-08-14T03:50:36.782Z
Learnt from: CR
PR: outfitter-dev/rulesets#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-08-14T03:50:36.782Z
Learning: Before submitting, run pnpm turbo lint && pnpm turbo test && pnpm turbo build

Applied to files:

  • package.json
  • packages/core/package.json
📚 Learning: 2025-08-14T03:51:26.625Z
Learnt from: CR
PR: outfitter-dev/rulesets#0
File: CLAUDE.md:0-0
Timestamp: 2025-08-14T03:51:26.625Z
Learning: Use mixd-* markers in code comments for version tracking (e.g., // TLDR: ... (mixd-v0))

Applied to files:

  • CHANGELOG.md
📚 Learning: 2025-08-14T03:51:26.625Z
Learnt from: CR
PR: outfitter-dev/rulesets#0
File: CLAUDE.md:0-0
Timestamp: 2025-08-14T03:51:26.625Z
Learning: Applies to .mixdown/src/**/*.mix.md : Name source rules files in kebab-case with .mix.md extension (e.g., coding-standards.mix.md)

Applied to files:

  • CHANGELOG.md
📚 Learning: 2025-08-14T03:51:26.625Z
Learnt from: CR
PR: outfitter-dev/rulesets#0
File: CLAUDE.md:0-0
Timestamp: 2025-08-14T03:51:26.625Z
Learning: Applies to .mixdown/src/**/*.{mix.md,md} : Write mixes using Markdown ATX-style headers and proper fenced code blocks with language identifiers

Applied to files:

  • CHANGELOG.md
📚 Learning: 2025-08-23T01:01:27.260Z
Learnt from: galligan
PR: outfitter-dev/monorepo#0
File: :0-0
Timestamp: 2025-08-23T01:01:27.260Z
Learning: User galligan successfully implemented comprehensive review feedback for PR #93 Bun-native optimization, systematically addressing all critical and important issues including: complete Turborepo reference removal from documentation and codebase, proper build.mjs error logging with array formatting and null coalescing, bunfig.toml security improvements (disabled auto="fallback", fixed watchExclude, moved telemetry to top-level), package.json script optimization (build:all alias, CI enhancement with test:all), and lefthook ultracite command fix (removed invalid --write flag), achieving -422 lines of legacy code removal while adding +18 lines of focused improvements with zero breaking changes and enhanced security, demonstrating gold standard systematic implementation following established patterns from previous PRs.

Applied to files:

  • packages/core/package.json
📚 Learning: 2025-08-19T17:49:13.493Z
Learnt from: galligan
PR: outfitter-dev/rulesets#0
File: :0-0
Timestamp: 2025-08-19T17:49:13.493Z
Learning: User galligan provided comprehensive feedback on PR review issues, categorizing them by priority (high/medium/minor) and requesting systematic fixes including cross-platform build compatibility (rimraf instead of rm -rf), test framework alignment (bun:test instead of Jest), documentation-code consistency for directory exclusions, extraction of shared discovery logic to reduce duplication, and proper integration test implementation. Successfully addressed all feedback with complete code solutions.

Applied to files:

  • packages/core/package.json
📚 Learning: 2025-08-22T20:51:01.048Z
Learnt from: galligan
PR: outfitter-dev/monorepo#0
File: :0-0
Timestamp: 2025-08-22T20:51:01.048Z
Learning: User galligan implemented exceptional security and performance fixes for PR #90 setup script with production-grade quality: completely eliminated curl | bash vulnerability using secure temp file handling with mktemp, comprehensive verification (empty check, suspicious pattern detection like rm -rf /), and proper cleanup; added robust input validation with VALID_ENVIRONMENTS readonly array and proper error handling; implemented proper async patterns replacing Bun.sleepSync with Promise-based setTimeout and exponential backoff retry logic; added comprehensive timeout handling (5-minute/300s for builds) with structured error objects containing exitCode and signal properties; fixed type safety with explicit dev: boolean parameter in getAddCommand(); corrected CI flags adding --frozen-lockfile for Bun; cleaned up Ultracite commands removing invalid --write flags; maintained backward compatibility with 'local' as default environment; achieved 16 try-catch blocks for comprehensive error handl...

Applied to files:

  • packages/core/package.json
📚 Learning: 2025-08-22T21:25:13.038Z
Learnt from: galligan
PR: outfitter-dev/monorepo#0
File: :0-0
Timestamp: 2025-08-22T21:25:13.038Z
Learning: User galligan demonstrated exceptional systematic implementation for commit b93dcf8 in PR #90, comprehensively addressing all review feedback with production-grade fixes including: README documentation alignment using proper ≥ symbol matching package.json engines exactly, package.json script semantic corrections (prepare script using 'bun run config:mdlint', format/check distinction with format writing and check verifying), shell script hardening with defaulted parameter expansions for set -u compatibility (${VAR-} pattern), Biome generator architecture improvements with centralized BIOME_SCHEMA_URL constant and Bun subprocess API with 300s timeouts, enhanced error handling with exit codes and command context, SILENCE_BIOME_WARNINGS environment gate for developer experience, and pragmatic schema version strategy maintaining 2.1.4 for base config compatibility while using 2.2.0 for generated configs, showcasing systematic precision with comprehensive verification and documentation quali...

Applied to files:

  • packages/core/package.json
📚 Learning: 2025-08-22T20:51:01.048Z
Learnt from: galligan
PR: outfitter-dev/monorepo#0
File: :0-0
Timestamp: 2025-08-22T20:51:01.048Z
Learning: User galligan successfully implemented comprehensive security and performance fixes for PR #90 setup script, including: secure Bun installation by replacing curl | bash with temp file verification and cleanup, complete type annotation coverage with explicit boolean types for function parameters, proper async/await patterns replacing Bun.sleepSync with Promise-based setTimeout, robust input validation using VALID_ENVIRONMENTS array with exit-on-invalid logic, CI flag corrections adding --frozen-lockfile for Bun, structured timeout handling for build operations (5-minute/300s limits), comprehensive error handling with structured error objects and exit codes, and command accuracy improvements removing invalid Ultracite --write flags while maintaining full backward compatibility and cross-platform support.

Applied to files:

  • packages/core/package.json
📚 Learning: 2025-08-18T18:14:06.160Z
Learnt from: CR
PR: outfitter-dev/monorepo#0
File: shared/configs/changeset/CLAUDE.md:0-0
Timestamp: 2025-08-18T18:14:06.160Z
Learning: Applies to shared/configs/changeset/**/{tsup.config.ts,tsup.config.js,package.json} : Use tsup to build both CJS and ESM outputs, include TypeScript declarations, and generate source maps

Applied to files:

  • packages/core/package.json
📚 Learning: 2025-08-18T18:17:52.697Z
Learnt from: CR
PR: outfitter-dev/monorepo#0
File: .cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc:0-0
Timestamp: 2025-08-18T18:17:52.697Z
Learning: Applies to **/esbuild*.@(js|ts|mjs|cjs) : Do not use esbuild; prefer `bun build`

Applied to files:

  • packages/core/package.json
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Graphite / mergeability_check
🔇 Additional comments (19)
CHANGELOG.md (1)

9-15: Changelog reads well and matches the migration scope

The Added/Changed entries accurately capture the ESLint→Biome swap, Lefthook, sync API, and frontmatter updates. No issues.

packages/core/package.json (2)

20-20: Cross‑platform clean via rimraf is correct

Good swap from rm -rf to rimraf for portability.


29-34: Runtime logging deps look right; pino‑pretty as optional is ideal

Solid split: pino in dependencies, pino-pretty in optionalDependencies.

package.json (2)

13-19: Script naming is clear and consistent

Good separation: lint vs lint:fix; format vs format:fix; md lint with fix flag.


37-47: Keep Prettier dependency
Prettier is invoked in lefthook.yml to format Markdown/YAML files (glob "**/*.{md,yml,yaml}" → bunx prettier --write) and is required for non-TS asset formatting.

Likely an incorrect or invalid review comment.

packages/core/src/interfaces/logger.ts (1)

70-80: Console errors are now surfaced — good fix

Stack preserved for Error instances; level gating is consistent with other methods.

packages/core/src/destinations/cursor-plugin.ts (3)

45-55: Path resolution and logging look solid

Supports both outputPath and path; resolves once and logs the final path.


56-63: Robust directory creation with error logging

Good use of mkdir recursive and propagating failures.


73-77: Priority derivation matches spec

Prefers config.priority and falls back to metadata; mirrors schema.

packages/core/src/interfaces/__tests__/logger.spec.ts (1)

148-157: Logger tests look solid.

Good isolation, interface conformance, and underlying pino instance checks.

Also applies to: 213-220, 278-292

packages/core/src/linter/index.ts (3)

59-69: Early return on missing frontmatter — LGTM.

Prevents cascaded follow‑up errors and keeps messaging clean.


118-135: Helpful suggestions for missing metadata — LGTM.

Clear, actionable info‑level guidance.


43-44: No lingering async calls or Promise typings detected. All downstream callers have been updated to use the synchronous lint API.

packages/core/src/linter/__tests__/linter.spec.ts (2)

6-29: Synchronous lint usage and object‑form rulesets — LGTM.

Matches the new API and schema; assertions are inside it() per our prior guidance.

Also applies to: 31-48


98-122: Destinations structure validation — LGTM.

Correctly exercises the array‑vs‑object check and asserts error severity.

packages/core/src/compiler/index.ts (4)

5-6: CRLF-safe split looks good.

The dedicated LINE_SPLIT_REGEX is a clean improvement.


66-69: AST pass-through — confirm parser guarantees.

If ast fields can ever be undefined from older parser outputs, consider defaulting to empty arrays/objects to avoid crashes.


24-24: Compile is fully synchronous—no async usages detected
No await compile(...), .then(compile), or Promise<CompiledDoc> references found across the codebase.


79-79: Remove nested metadata/config suggestion—Frontmatter.destinations is flat.
The Frontmatter type in packages/core/src/interfaces/frontmatter.ts defines each destinations[destId] entry as a flat object with no nested metadata or config properties, so spreading …destinations[destId]?.metadata or …destinations[destId]?.config won’t compile.

Likely an incorrect or invalid review comment.

Comment on lines +50 to +53
bodyContent = lines
.slice(frontmatterEnd + 1)
.join("\n")
.trim();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Preserve original EOLs and avoid trimming body content.

.join("\n").trim() normalises line endings and strips leading/trailing whitespace, which can be content-significant. Preserve EOL style and keep body as-is.

Apply this diff:

-        bodyContent = lines
-          .slice(frontmatterEnd + 1)
-          .join("\n")
-          .trim();
+        const eol = /\r\n/.test(source.content) ? "\r\n" : "\n";
+        bodyContent = lines
+          .slice(frontmatterEnd + 1)
+          .join(eol);

Also applies to: 72-72

Comment on lines +39 to +40
process.env.RULESETS_LOG_LEVEL = undefined;
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Unset env vars correctly to avoid flaky state.

Assigning process.env.FOO = undefined can coerce to the string "undefined". Use delete to unset.

Apply:

-      process.env.RULESETS_LOG_LEVEL = undefined;
+      delete process.env.RULESETS_LOG_LEVEL;
-      if (originalLogLevel === undefined) {
-        process.env.RULESETS_LOG_LEVEL = undefined;
-      } else {
-        process.env.RULESETS_LOG_LEVEL = originalLogLevel;
-      }
+      if (originalLogLevel === undefined) {
+        delete process.env.RULESETS_LOG_LEVEL;
+      } else {
+        process.env.RULESETS_LOG_LEVEL = originalLogLevel;
+      }
-      if (originalPretty === undefined) {
-        process.env.RULESETS_LOG_PRETTY = undefined;
-      } else {
-        process.env.RULESETS_LOG_PRETTY = originalPretty;
-      }
+      if (originalPretty === undefined) {
+        delete process.env.RULESETS_LOG_PRETTY;
+      } else {
+        process.env.RULESETS_LOG_PRETTY = originalPretty;
+      }
-      if (originalLogLevel === undefined) {
-        process.env.RULESETS_LOG_LEVEL = undefined;
-      } else {
-        process.env.RULESETS_LOG_LEVEL = originalLogLevel;
-      }
+      if (originalLogLevel === undefined) {
+        delete process.env.RULESETS_LOG_LEVEL;
+      } else {
+        process.env.RULESETS_LOG_LEVEL = originalLogLevel;
+      }

Also applies to: 241-246, 255-260, 270-275

🤖 Prompt for AI Agents
In packages/core/src/interfaces/__tests__/logger.spec.ts around lines 39-40 (and
also apply same change at 241-246, 255-260, 270-275), the test unsets
environment variables by assigning process.env.VAR = undefined which results in
the string "undefined"; change these to use delete process.env.VAR to properly
remove the variables from the environment and avoid flaky tests.

@galligan galligan force-pushed the feat_replace_eslint_with_biome_and_add_lefthook_for_git_hooks branch from c82e7bc to ac40457 Compare September 2, 2025 00:01
@galligan galligan changed the base branch from fix_migrate_to_bun_to_resolve_ci_cd_scoped_package_issues to graphite-base/89 September 2, 2025 05:05
@galligan

galligan commented Sep 4, 2025

Copy link
Copy Markdown
Contributor Author

Migration complete and included in PR #97

@galligan galligan closed this Sep 4, 2025
@galligan galligan deleted the feat_replace_eslint_with_biome_and_add_lefthook_for_git_hooks branch September 4, 2025 14:24
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant