Skip to content

fix(root): use agent identifier as scaffolded file name fixes NV-7479#10972

Merged
ChmaraX merged 4 commits intonextfrom
cursor/agent-scaffold-filename-29d0
May 4, 2026
Merged

fix(root): use agent identifier as scaffolded file name fixes NV-7479#10972
ChmaraX merged 4 commits intonextfrom
cursor/agent-scaffold-filename-29d0

Conversation

@ChmaraX
Copy link
Copy Markdown
Contributor

@ChmaraX ChmaraX commented May 4, 2026

What changed

The novu init -t agent --agent-identifier <id> scaffolding command now names the generated agent file after the provided identifier instead of always using support-agent.tsx.

Before: npx novu init -t agent --agent-identifier first-agent → creates app/novu/agents/support-agent.tsx (only the string inside agent(...) was replaced).

After: the same command creates app/novu/agents/first-agent.tsx with all references updated across the scaffolded project.

How

The file rename happens during copy() via the existing rename callback — the same mechanism used for gitignore.gitignore and README-template.mdREADME.md. Then a single glob-based pass replaces supportAgent → camelCase name and support-agent → identifier across all .tsx, .ts, and .md files.

When no --agent-identifier is provided, the default support-agent.tsx template is preserved unchanged.

Changes

File Change
packages/novu/src/commands/init/templates/index.ts Rename via copy() callback + glob-based content replacement

Linear Issue: NV-7479

Open in Web Open in Cursor 

What changed

The scaffolder for novu init -t agent now uses the provided --agent-identifier to name the generated agent file and update references across the scaffolded project. When an identifier is supplied, the template file support-agent.tsx is renamed to {identifier}.tsx during copy, the identifier is validated as a lowercase slug, a camelCased export name is derived, and a glob-based pass replaces supportAgent/support-agent across .tsx, .ts, and .md files so code and filenames stay consistent.

Affected areas

novu (packages/novu): The template installation logic was updated to support conditional rename of the agent template during copy, validate the agent identifier, derive a camelCase export name, and perform a single glob-based content replacement across scaffolded TypeScript and Markdown files.

Key technical decisions

  • Enforce a lowercase slug regex for agent identifiers to ensure safe filenames and imports.
  • Use the existing copy rename callback (used elsewhere for gitignore/README) to rename support-agent.tsx to {identifier}.tsx.
  • Perform a single glob-based replacement pass to update both kebab-case filenames and camelCase export identifiers across multiple file types.

Testing

No automated tests were added; verification is manual by running npx novu init -t agent --agent-identifier <id> and confirming the generated filename and cross-file references are correctly updated.

Previously, the scaffolding command always created the agent file as
support-agent.tsx regardless of the --agent-identifier value. Now the
file, export name, and all references (index.ts, route.ts, page.tsx,
README) are renamed to match the provided agent identifier.

Co-authored-by: Adam Chmara <adam.chmara1@gmail.com>
@linear-code
Copy link
Copy Markdown

linear-code Bot commented May 4, 2026

@netlify
Copy link
Copy Markdown

netlify Bot commented May 4, 2026

Deploy Preview for dashboard-v2-novu-staging canceled.

Name Link
🔨 Latest commit a0e86c1
🔍 Latest deploy log https://app.netlify.com/projects/dashboard-v2-novu-staging/deploys/69f891c466b09600081ce027

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 4, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 9b643df4-dada-4ae8-af8d-056f637fc2b9

📥 Commits

Reviewing files that changed from the base of the PR and between 15893ce and a0e86c1.

📒 Files selected for processing (1)
  • packages/novu/src/commands/init/templates/index.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/novu/src/commands/init/templates/index.ts

📝 Walkthrough

Walkthrough

When initializing the APP_AGENT template with an agentIdentifier, the installer validates the identifier, conditionally renames support-agent.tsx to ${agentIdentifier}.tsx during copy, and performs global replacements: supportAgent → camelCase(agentIdentifier) and support-agent → agentIdentifier across copied **/*.{tsx,ts,md} files.

Changes

APP_AGENT Template Installation

Layer / File(s) Summary
Input Validation
packages/novu/src/commands/init/templates/index.ts
Adds lowercase-slug regex validation for agentIdentifier and sets renameAgent when valid.
Template Copy / Rename
packages/novu/src/commands/init/templates/index.ts
Enhances copy(..., { rename(name) { ... } }) to rename support-agent.tsx${agentIdentifier}.tsx when renameAgent is set.
Content Substitutions
packages/novu/src/commands/init/templates/index.ts, .../**/*.{tsx,ts,md}
After copy, computes camelCase name from agentIdentifier, globs copied **/*.{tsx,ts,md} and replaces supportAgent → camelCase(id) and support-agent → id; writes files only when changed.
Removed legacy edit
packages/novu/src/commands/init/templates/index.ts
Removes previous per-file edit that revalidated the id and patched app/novu/agents/support-agent.tsx directly.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Possibly related PRs

Suggested reviewers

  • scopsy
🚥 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 title follows the Conventional Commits format with a valid type (fix), valid scope (root), lowercase description in imperative mood, and includes the Linear ticket reference (NV-7479) at the end as required.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
Review rate limit: 7/8 reviews remaining, refill in 7 minutes and 30 seconds.

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

Co-authored-by: Adam Chmara <adam.chmara1@gmail.com>
Co-authored-by: Adam Chmara <adam.chmara1@gmail.com>
@ChmaraX ChmaraX marked this pull request as ready for review May 4, 2026 11:52
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Caution

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

⚠️ Outside diff range comments (1)
packages/novu/src/commands/init/templates/index.ts (1)

93-99: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Digit-leading identifiers pass validation but produce invalid JS variable names in the generated code.

The existing slug regex /^[a-z0-9]+(?:[-_][a-z0-9]+)*$/ (line 93) allows identifiers like 1agent or 0-foo. When such a value reaches line 99, camelName inherits the leading digit (e.g., 1agent, 0Foo). A JavaScript identifier must start with a letter, underscore, or dollar sign — it can't start with a digit. The scaffolded .tsx file would emit export const 1agent = ..., which is a hard syntax error in the generated project.

Fix: tighten the slug regex to require a leading letter:

🐛 Proposed fix
-    if (!/^[a-z0-9]+(?:[-_][a-z0-9]+)*$/.test(agentIdentifier)) {
+    if (!/^[a-z][a-z0-9]*(?:[-_][a-z0-9]+)*$/.test(agentIdentifier)) {
       throw new Error(
         `Invalid agent identifier: "${agentIdentifier}". Must be a lowercase slug (a-z, 0-9, hyphens, underscores).`
       );

The error message should also be updated to reflect that the identifier must start with a letter (a-z).

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

In `@packages/novu/src/commands/init/templates/index.ts` around lines 93 - 99, The
agentIdentifier validation allows leading digits which later produce invalid JS
variable names when used to build camelName; change the regex used in the agent
identifier check (the `/^[a-z0-9]+(?:[-_][a-z0-9]+)*$/` test around
agentIdentifier) to require a leading letter (e.g. start with [a-z] rather than
[a-z0-9]) and update the thrown Error message to state the identifier must start
with a letter (a-z) and only contain lowercase letters, digits, hyphens, and
underscores so generated variable names (camelName) won't begin with a digit.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@packages/novu/src/commands/init/templates/index.ts`:
- Around line 93-99: The agentIdentifier validation allows leading digits which
later produce invalid JS variable names when used to build camelName; change the
regex used in the agent identifier check (the `/^[a-z0-9]+(?:[-_][a-z0-9]+)*$/`
test around agentIdentifier) to require a leading letter (e.g. start with [a-z]
rather than [a-z0-9]) and update the thrown Error message to state the
identifier must start with a letter (a-z) and only contain lowercase letters,
digits, hyphens, and underscores so generated variable names (camelName) won't
begin with a digit.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: d363f54e-247a-4b92-8925-cf127a0d15a0

📥 Commits

Reviewing files that changed from the base of the PR and between b5365d7 and 4ff392f.

📒 Files selected for processing (1)
  • packages/novu/src/commands/init/templates/index.ts

Copy link
Copy Markdown
Contributor

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

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

Security review completed: 1 net-new finding on the current PR head.

Open in Web View Automation 

Sent by Cursor Security Review Agent: Security Reviewer

(await fs.readFile(agentFile, 'utf8')).replace("agent('support-agent',", `agent('${agentIdentifier}',`)
if (renameAgent) {
const camelName = agentIdentifier.replace(/[-_]([a-z0-9])/g, (_, c) => c.toUpperCase());
const files = await glob('**/*.{tsx,ts,md}', { cwd: root, absolute: true });
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔒 Agentic Security Review
Severity: HIGH
Description: The recursive glob used during agent rename (glob('**/*.{tsx,ts,md}', { cwd: root, absolute: true })) can follow symlinks under the target root and then rewrite matched files. This allows writes outside the intended scaffold directory when a symlink points externally.
Impact: An attacker with control over workspace contents can trigger out-of-root file modification during scaffold execution, potentially overwriting arbitrary files accessible to the current user.

@ChmaraX
Copy link
Copy Markdown
Contributor Author

ChmaraX commented May 4, 2026

@cursoragent check if PR comments are relevant and address

@cursor
Copy link
Copy Markdown
Contributor

cursor Bot commented May 4, 2026

The security finding was valid and has been addressed. The glob('**/*.{tsx,ts,md}', ...) call with absolute: true could follow symlinks and rewrite files outside the scaffold directory. Fixed by adding followSymbolicLinks: false to the glob options, which prevents traversal beyond the intended root.

The other PR comments (Linear linkback, Netlify deploy preview, CodeRabbit summary) are informational and don't require action.

Open in Web Open in Cursor 

Co-authored-by: Adam Chmara <adam.chmara1@gmail.com>
@ChmaraX ChmaraX merged commit 2d61362 into next May 4, 2026
34 checks passed
@ChmaraX ChmaraX deleted the cursor/agent-scaffold-filename-29d0 branch May 4, 2026 13:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants