Skip to content

feat(scaffold): generate Cursor adapter from kit content at scaffold time#13

Merged
vancura merged 2 commits into
mainfrom
agents-cursor
Jun 13, 2026
Merged

feat(scaffold): generate Cursor adapter from kit content at scaffold time#13
vancura merged 2 commits into
mainfrom
agents-cursor

Conversation

@vancura

@vancura vancura commented Jun 13, 2026

Copy link
Copy Markdown
Owner

Replace static templates/optional/cursor/ with generateCursorAdapter(), which composes .cursor/rules/, hooks.json, shell hook scripts, and commands/ from kit content/rules, content/skills, and hooks.manifest.json. Add canonical format-on-edit and shell-safety hooks.

This PR replaces the static Cursor adapter template with a dynamic generation system that composes the .cursor directory at scaffold time from kit content sources.

Key Changes

Cursor adapter generation: The scaffolder now invokes a new generateCursorAdapter() function that assembles the .cursor directory from canonical kit sources instead of copying a static template tree. The generator:

  • Translates content/hooks.manifest.json into .cursor/hooks.json with template variable rendering
  • Emits .cursor/rules/*.mdc from content/rules/*.md, preserving YAML frontmatter
  • Copies shell hook scripts from content/hooks/
  • Generates .cursor/commands/*.md from content/skills/*/SKILL.md

Hook manifest: A new hooks.manifest.json defines two Cursor hooks:

  • format-on-edit: Runs a package-manager-based formatter after AI edits
  • block-dangerous-shell: Executes shell-safety.sh before shell execution with failClosed: true

Shell safety hook: A new shell-safety.sh script blocks destructive git operations (git reset --hard, git clean -f, git checkout --) and prompts for force-push operations, while allowing all other commands.

Kit ownership: The .cursor/hooks.json is now classified as kit-owned, ensuring blit agents sync regenerates it when unmodified.

Test updates: Test coverage expanded to validate the new dynamic generation, including:

  • Cursor rule files and frontmatter preservation
  • hooks.json structure and hook entries
  • Template variable rendering in hooks and commands
  • Shell-safety and command markdown generation

The old static template file blit-tech-api-names.mdc is removed as it is now dynamically generated from kit content.

…time

Replace static templates/optional/cursor/ with generateCursorAdapter(),
which composes .cursor/rules/, hooks.json, shell hook scripts, and
commands/ from kit content/rules, content/skills, and
hooks.manifest.json. Add canonical format-on-edit and shell-safety hooks.

Assisted-by: Claude Code <noreply@anthropic.com>
Signed-off-by: Vaclav Vancura <commit@vancura.dev>
@coderabbitai

coderabbitai Bot commented Jun 13, 2026

Copy link
Copy Markdown

Review Change Stack

Important

Review skipped

Auto reviews are limited based on label configuration.

🚫 Excluded labels (none allowed) (1)
  • skip-cr

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.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: b47ba308-d81a-41d9-a0fd-d55c96dedc57

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

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Walkthrough

This PR adds Cursor adapter generation to the scaffolding pipeline, converting the kit's canonical hook manifest and content sources into Cursor-specific .cursor/* outputs during project setup. A shell-safety hook blocks destructive git commands before execution.

Changes

Cursor Adapter Generation

Layer / File(s) Summary
Hook manifest and shell-safety hook
packages/kit/content/hooks.manifest.json, packages/kit/content/hooks/shell-safety.sh
Defines two Cursor hooks: one runs a post-edit formatter, and another executes a shell-safety script that parses JSON from stdin and blocks destructive git operations (git reset --hard, git clean -f, git checkout --) while allowing other commands or requesting confirmation on force push.
Cursor adapter generator and scaffold integration
packages/create-blit-tech/src/scaffold.ts
Adds hook/manifest TypeScript types, implements buildCursorHooks to translate hooks.manifest.json into Cursor's JSON format with template rendering, and generateCursorAdapter to emit rule files (with frontmatter), hooks manifest, hook scripts, and command markdowns from kit sources. Marks .cursor/hooks.json as kit-owned and updates scaffold() to invoke the generator instead of copying the static template.
Cursor adapter generation test coverage
packages/create-blit-tech/test/scaffold.test.mjs
Validates existence of generated Cursor assets (rules, hooks, commands), confirms rule files preserve YAML frontmatter with alwaysApply: true, verifies hooks.json structure (versions, hook arrays, failClosed field), and confirms template variables are fully rendered (no {{ placeholders).

Possibly related PRs

  • vancura/create-blit-tech#4: Updates scaffold.ts and test to conditionally scaffold Cursor agent files with smoke-test assertions, directly overlapping with this PR's Cursor scaffolding and hook generation changes.
  • vancura/create-blit-tech#3: Adds the same Cursor hook/rule scripts and config files that this PR generates from canonical packages/kit/content/* sources.
  • vancura/create-blit-tech#12: Implements analogous Claude adapter generation from kit content/ at scaffold time, following the same pattern as this PR's Cursor implementation.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title 'feat(scaffold): generate Cursor adapter from kit content at scaffold time' directly and accurately summarizes the main change: replacing static templates with dynamic generation of Cursor adapter at scaffold time from kit content sources.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch agents-cursor

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

@vancura

vancura commented Jun 13, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 13, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

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.

@vancura

vancura commented Jun 13, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 13, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

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.

🧹 Nitpick comments (2)
packages/create-blit-tech/test/scaffold.test.mjs (1)

221-227: 💤 Low value

Consider guarding array element access for clearer test failure messages.

Lines 226-227 access beforeShellExecution[0] after only asserting the array exists. If the array were unexpectedly empty, safetyHook would be undefined and safetyHook.failClosed would throw a TypeError rather than a clean assertion failure. Same pattern applies to afterFileEdit[0] on line 230.

Since the implementation should always produce entries, this is unlikely to bite in practice, but a length check yields more actionable failure output:

 assert.ok(
     Array.isArray(hooksJson.hooks.beforeShellExecution),
     'hooks.json should have beforeShellExecution entries',
 );
+assert.ok(hooksJson.hooks.beforeShellExecution.length > 0, 'beforeShellExecution should have at least one entry');
 const safetyHook = hooksJson.hooks.beforeShellExecution[0];
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/create-blit-tech/test/scaffold.test.mjs` around lines 221 - 227, The
test should guard array element access before indexing: after asserting
Array.isArray for hooksJson.hooks.beforeShellExecution and
hooksJson.hooks.afterFileEdit, add explicit non-empty checks (e.g.
assert.ok(hooksJson.hooks.beforeShellExecution.length > 0, 'beforeShellExecution
should contain at least one entry') and same for afterFileEdit) so that
accessing beforeShellExecution[0] and afterFileEdit[0] yields a clear assertion
failure instead of a TypeError when arrays are empty.
packages/kit/content/hooks/shell-safety.sh (1)

9-36: 💤 Low value

Python3 dependency undocumented.

The script silently requires python3 for JSON parsing. If unavailable, the command substitution fails and COMMAND_TEXT becomes empty, causing all commands to be allowed (fail-open). Consider adding a brief comment at the top noting the python3 requirement, or check for its presence before attempting the parse:

+# Requires: python3 (for JSON parsing)
+
 INPUT_JSON="$(cat)"
+
+if ! command -v python3 >/dev/null 2>&1; then
+    printf '{"permission":"deny","user_message":"python3 required for shell safety hook."}\n'
+    exit 0
+fi

Alternatively, keep the fail-open behavior but document it explicitly so future maintainers understand the trade-off.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/kit/content/hooks/shell-safety.sh` around lines 9 - 36, The script
assigns COMMAND_TEXT via a command substitution that invokes python3 to parse
JSON; add an explicit pre-check and/or documentation to avoid silent fail-open:
before the COMMAND_TEXT assignment, detect python3 availability (e.g., test
command -v python3) and if missing either (a) print a clear stderr warning and
exit non-zero so the hook fails closed, or (b) add a top-of-file comment stating
that python3 is required and that the current behavior intentionally falls back
to an empty COMMAND_TEXT; update the script around the python3 invocation (the
COMMAND_TEXT assignment and its python3 -c block) to implement the chosen
behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@packages/create-blit-tech/test/scaffold.test.mjs`:
- Around line 221-227: The test should guard array element access before
indexing: after asserting Array.isArray for hooksJson.hooks.beforeShellExecution
and hooksJson.hooks.afterFileEdit, add explicit non-empty checks (e.g.
assert.ok(hooksJson.hooks.beforeShellExecution.length > 0, 'beforeShellExecution
should contain at least one entry') and same for afterFileEdit) so that
accessing beforeShellExecution[0] and afterFileEdit[0] yields a clear assertion
failure instead of a TypeError when arrays are empty.

In `@packages/kit/content/hooks/shell-safety.sh`:
- Around line 9-36: The script assigns COMMAND_TEXT via a command substitution
that invokes python3 to parse JSON; add an explicit pre-check and/or
documentation to avoid silent fail-open: before the COMMAND_TEXT assignment,
detect python3 availability (e.g., test command -v python3) and if missing
either (a) print a clear stderr warning and exit non-zero so the hook fails
closed, or (b) add a top-of-file comment stating that python3 is required and
that the current behavior intentionally falls back to an empty COMMAND_TEXT;
update the script around the python3 invocation (the COMMAND_TEXT assignment and
its python3 -c block) to implement the chosen behavior.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: c51406d7-17cc-48e4-b3d4-a4ab6b62a12b

📥 Commits

Reviewing files that changed from the base of the PR and between 7926339 and ce85d87.

📒 Files selected for processing (5)
  • packages/create-blit-tech/src/scaffold.ts
  • packages/create-blit-tech/templates/optional/cursor/dot-cursor/rules/blit-tech-api-names.mdc
  • packages/create-blit-tech/test/scaffold.test.mjs
  • packages/kit/content/hooks.manifest.json
  • packages/kit/content/hooks/shell-safety.sh
💤 Files with no reviewable changes (1)
  • packages/create-blit-tech/templates/optional/cursor/dot-cursor/rules/blit-tech-api-names.mdc

Add explicit non-empty length assertions for hooks.json afterFileEdit
and beforeShellExecution arrays before indexing with [0], so an empty
array produces a clear assertion failure instead of a TypeError.

Add a python3 availability pre-check to shell-safety.sh: if python3
is not installed the hook now exits non-zero with a deny response and
a descriptive user/agent message, ensuring fail-closed behaviour
rather than silently allowing commands through via an empty
COMMAND_TEXT.

Assisted-by: Claude Sonnet 4.6
Signed-off-by: Vaclav Vancura <commit@vancura.dev>
@vancura vancura merged commit 71e0714 into main Jun 13, 2026
7 checks passed
@vancura vancura deleted the agents-cursor branch June 13, 2026 11:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant