Skip to content

feat: add chatbot template support#27

Open
tonychang04 wants to merge 9 commits intomainfrom
feat/github-templates
Open

feat: add chatbot template support#27
tonychang04 wants to merge 9 commits intomainfrom
feat/github-templates

Conversation

@tonychang04
Copy link
Contributor

@tonychang04 tonychang04 commented Mar 19, 2026

Summary

  • Adds generic downloadGitHubTemplate() function that clones from InsForge/insforge-templates repo
  • New "AI Chatbot with Next.js" option in insforge create template selector
  • Auto-writes .env.local with InsForge credentials
  • Auto-runs migrations/db_int.sql if present in the template
  • Extensible: future templates just need a new selector option + subdirectory in the templates repo

Test plan

  • Run insforge create, select "AI Chatbot with Next.js"
  • Verify chatbot files are copied to project dir
  • Verify .env.local is written with correct credentials
  • Verify db_int.sql migration runs against the database
  • Verify npm install and npm run dev work
  • Test --template chatbot flag in non-interactive mode

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • A new "chatbot" project template is available when creating projects.
    • Chatbot template auto-generates environment settings from your project config, can optionally apply bundled database migrations, and shows clearer progress and warnings on migration or download issues.
    • The CLI now automatically loads local environment variables and includes them when starting a deploy.
  • Chores

    • CLI package version updated to 0.1.24.

Adds downloadGitHubTemplate() that clones InsForge/insforge-templates repo,
copies the selected template to the project dir, writes .env.local with
credentials, and runs migrations/db_int.sql if present.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@coderabbitai
Copy link

coderabbitai bot commented Mar 19, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Adds a new chatbot template flow to the create command: shallow-clones an external templates repo, copies the chosen template into the project, generates .env.local from .env.example (rewriting INSFORGE* values), optionally applies SQL migrations via the OSS API, and cleans up temp files.

Changes

Cohort / File(s) Summary
Create command & templates
src/commands/create.ts
Added chatbot to --template and interactive picker. New downloadGitHubTemplate(templateName, projectConfig, json) shallow-clones https://github.com/InsForge/insforge-templates.git into a timestamped temp dir, copies templateName subdir to cwd, rewrites .env.example.env.local (map INSFORGEURL → projectConfig.oss_host, INSFORGEANON_KEY → fetched anonKey), posts migrations/db_int.sql to /api/database/advance/rawsql/unrestricted via ossFetch with spinner/warnings, always removes temp dir, and logs manual-clone hint on failure. Also updated deploy start to read env vars and pass startBody.envVars.
Env utility
src/lib/env.ts
Added readEnvFile(cwd: string) that finds .env.local/.env.production/.env, parses key=value lines, and returns an array of { key, value }. Exported for use when starting deploy.
Package manifest
package.json
Bumped package version from 0.1.210.1.24.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • 0.1.21 #26 — another PR that updated the package version (related version-bump changes).

Suggested reviewers

  • Fermionic-Lyu
  • jwfing

Poem

🐰 I dug a bright template, fetched by moonlight,
Cloned a small grove and made configs right.
Keys tucked in soil, migrations set to run,
A chatbot grows where the new project begun. 🌱✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title 'feat: add chatbot template support' directly and accurately reflects the main change: introducing chatbot template functionality to the create command.

✏️ 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 feat/github-templates
📝 Coding Plan
  • Generate coding plan for human review comments

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

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (2)
src/commands/create.ts (2)

311-314: Consider handling missing git more gracefully.

The shallow clone requires git to be installed. If it's not available, the error message from execAsync may not clearly indicate the root cause. A pre-check or clearer error would improve UX.

💡 Suggested enhancement
     await fs.mkdir(tempDir, { recursive: true });

     // Shallow clone the templates repo
-    await execAsync(
-      'git clone --depth 1 https://github.com/InsForge/insforge-templates.git .',
-      { cwd: tempDir, maxBuffer: 10 * 1024 * 1024, timeout: 60_000 },
-    );
+    try {
+      await execAsync(
+        'git clone --depth 1 https://github.com/InsForge/insforge-templates.git .',
+        { cwd: tempDir, maxBuffer: 10 * 1024 * 1024, timeout: 60_000 },
+      );
+    } catch (err) {
+      const msg = (err as Error).message;
+      if (msg.includes('ENOENT') || msg.includes('not found') || msg.includes('not recognized')) {
+        throw new Error('Git is not installed or not in PATH. Please install git and try again.');
+      }
+      throw err;
+    }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/commands/create.ts` around lines 311 - 314, The git shallow-clone call
using execAsync('git clone ...', { cwd: tempDir, ... }) can fail if git is not
installed; add a pre-check before the execAsync call to detect git availability
(e.g., run 'git --version' or check for ENOENT) and throw or log a user-friendly
error that clearly states "git is required" including detected error details;
alternatively wrap the execAsync call in a try/catch that inspects the thrown
error (ENOENT or message including 'git') and replaces it with a clearer
message. Update the logic around execAsync and tempDir in src/commands/create.ts
so failures explicitly surface missing git vs other clone errors.

338-358: Database migration runs after spinner stops, which may confuse timing.

The main spinner stops at line 336 ("template downloaded"), but database migration has its own spinner. This is acceptable, but note that if getAnonKey() (line 328) fails, the error is caught at line 359 and the template download is reported as failed, even though files were already copied to cwd. Consider moving the anonKey fetch earlier or clarifying partial success state.

Also, the migration endpoint /api/database/advance/rawsql/unrestricted executes arbitrary SQL from the template repository. This is by design for trusted templates, but ensure the insforge-templates repository has appropriate access controls.

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

In `@src/commands/create.ts` around lines 338 - 358, The code reports the template
download as failed if getAnonKey() (function getAnonKey) fails after files are
copied and the template spinner is stopped, and the DB migration spinner timing
is confusing; to fix, move the getAnonKey() call to before starting/copying the
template (so failures occur before the "template downloaded" spinner stop) or,
alternatively, change the catch that logs the template failure (the catch around
the template download/copy) to report a partial success/partial failure (mention
files were copied) instead of a full download failure; also ensure the database
migration spinner lifecycle (dbSpinner created in the migration block and its
start/stop around ossFetch to /api/database/advance/rawsql/unrestricted) is
independent of the template spinner so timing is clear, and add a code comment
near the migration call to confirm that templates in insforge-templates are
trusted/controlled before executing arbitrary SQL.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/commands/create.ts`:
- Line 62: Add explicit validation for the --template option value where it's
parsed (the option declared as .option('--template <template>', 'Template to
use: react, nextjs, chatbot, or empty') and any code that assigns to the
framework variable), ensuring only the allowed values
['react','nextjs','chatbot','empty'] are accepted; if the provided value is
invalid, print a clear error and exit (or throw) instead of silently falling
back to react (the current fallback logic using framework === 'nextjs' ?
'nextjs' : 'react'). Implement this once as a small helper/validator used in all
parsing locations (references: the option declaration and the framework variable
usage) so the same validation is applied at the other spots noted in the review
(around the areas where template parsing occurs).
- Around line 327-334: The current write that uses fs.writeFile(path.join(cwd,
'.env.local'), envContent) will silently overwrite an existing .env.local;
change create logic to detect and merge instead: check for file existence using
fs.existsSync or fs.stat, read and parse existing .env.local into key/value
pairs, update or add only the NEXT_PUBLIC_INSFORGE_URL and
NEXT_PUBLIC_INSFORGE_ANON_KEY entries (leave all other keys untouched), then
write the merged content back (or warn and abort if merge fails). Update the
section around getAnonKey(), projectConfig, and the fs.writeFile call to perform
this read-merge-write flow so existing env vars are preserved.

---

Nitpick comments:
In `@src/commands/create.ts`:
- Around line 311-314: The git shallow-clone call using execAsync('git clone
...', { cwd: tempDir, ... }) can fail if git is not installed; add a pre-check
before the execAsync call to detect git availability (e.g., run 'git --version'
or check for ENOENT) and throw or log a user-friendly error that clearly states
"git is required" including detected error details; alternatively wrap the
execAsync call in a try/catch that inspects the thrown error (ENOENT or message
including 'git') and replaces it with a clearer message. Update the logic around
execAsync and tempDir in src/commands/create.ts so failures explicitly surface
missing git vs other clone errors.
- Around line 338-358: The code reports the template download as failed if
getAnonKey() (function getAnonKey) fails after files are copied and the template
spinner is stopped, and the DB migration spinner timing is confusing; to fix,
move the getAnonKey() call to before starting/copying the template (so failures
occur before the "template downloaded" spinner stop) or, alternatively, change
the catch that logs the template failure (the catch around the template
download/copy) to report a partial success/partial failure (mention files were
copied) instead of a full download failure; also ensure the database migration
spinner lifecycle (dbSpinner created in the migration block and its start/stop
around ossFetch to /api/database/advance/rawsql/unrestricted) is independent of
the template spinner so timing is clear, and add a code comment near the
migration call to confirm that templates in insforge-templates are
trusted/controlled before executing arbitrary SQL.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: f5b99976-6b0d-42ab-96b8-bd6c730a5e1a

📥 Commits

Reviewing files that changed from the base of the PR and between 9a5d540 and d2676fe.

📒 Files selected for processing (1)
  • src/commands/create.ts

tonychang04 and others added 2 commits March 19, 2026 10:18
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ates

Instead of writing hardcoded NEXT_PUBLIC_ vars to .env.local, the CLI
now reads the template's .env.example, pattern-matches INSFORGE URL and
ANON_KEY vars (regardless of prefix), and fills in the real values.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

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

Inline comments:
In `@src/commands/create.ts`:
- Around line 333-341: The regex in the envExample.replace call (used to build
envContent) only matches letters and underscores and therefore skips env var
names containing digits; update the pattern used in envExample.replace from
/^([A-Z_]+=)(.*)$/gm to include digits in the character class (e.g., use
[A-Z0-9_]+) so variable names like API_KEY_V2 or REGION_1 are matched, keep the
same two capture groups and replacement logic in the envContent computation
(referencing envExample.replace and envContent).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: eb0d2ad6-2f3f-4d91-b533-ca2dd45f8245

📥 Commits

Reviewing files that changed from the base of the PR and between 56c603b and 63a66f1.

📒 Files selected for processing (1)
  • src/commands/create.ts

tonychang04 and others added 3 commits March 19, 2026 13:41
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
During `insforge create`, the CLI now reads .env.local / .env.production
/ .env and passes the variables to the deployment API so the deployed
app has the correct InsForge credentials.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@tonychang04 tonychang04 requested a review from jwfing March 19, 2026 21:48
@tonychang04 tonychang04 enabled auto-merge March 19, 2026 21:48
@tonychang04
Copy link
Contributor Author

tested my running cli to crate project

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (1)
src/commands/create.ts (1)

156-160: Make template routing data-driven.

Hard-coding chatbot as the only GitHub-backed template means the next external template still needs branching changes here. A small registry mapping template → source/handler would keep template additions declarative.

♻️ Example direction
+const templateSources: Record<string, 'github' | 'builtin'> = {
+  chatbot: 'github',
+  react: 'builtin',
+  nextjs: 'builtin',
+};
+
 const hasTemplate = template !== 'empty';
-if (template === 'chatbot') {
-  await downloadGitHubTemplate('chatbot', projectConfig, json);
-} else if (hasTemplate) {
-  await downloadTemplate(template as Framework, projectConfig, projectName, json, apiUrl);
+if (hasTemplate) {
+  const selectedTemplate = template as string;
+  if (templateSources[selectedTemplate] === 'github') {
+    await downloadGitHubTemplate(selectedTemplate, projectConfig, json);
+  } else {
+    await downloadTemplate(selectedTemplate as Framework, projectConfig, projectName, json, apiUrl);
+  }
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/commands/create.ts` around lines 156 - 160, The template routing is
hard-coded around the template variable and
downloadGitHubTemplate/downloadTemplate calls; replace this branching with a
small registry mapping template names to handler functions or source descriptors
and dispatch to the appropriate handler instead of using if (template ===
'chatbot') {...} else if (hasTemplate) {...}. Create a TemplateRegistry (map
from template string to a handler function or an object describing {type,
handler}) and in the create flow use templateRegistry.get(template) to invoke
the correct handler (passing projectConfig, projectName, json, apiUrl as needed)
with a sensible default/fallback to the existing downloadTemplate behavior for
non-GitHub or unknown templates; update places that reference template,
hasTemplate, downloadGitHubTemplate, and downloadTemplate to use the registry
dispatch.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/commands/create.ts`:
- Around line 369-382: The migration and outer template-download catch blocks
currently only log warnings (in the catch handling around dbSpinner and s in
src/commands/create.ts) which allows execution to continue; change both catch
handlers to rethrow the caught error after logging (i.e., after
dbSpinner?.stop(...)/s?.stop(...) and clack.log.warn/info calls) so the error
bubbles up to registerCreateCommand and stops further steps (npm install /
deploy prompt) instead of proceeding with a partial project.
- Around line 320-323: Summary: The code currently clones the templates repo's
default branch via execAsync and immediately runs migrations (e.g.,
migrations/db_int.sql), which allows upstream changes to execute arbitrary SQL;
fix by pinning the template source or requiring explicit user confirmation.
Change the git clone in create.ts (the execAsync call referencing tempDir) to
clone a specific commit or tag supplied by a new
--template-version/--template-commit option (or default to a reviewed,
hard-coded tag), verify the ref was checked out successfully, and refuse to
proceed if no pinned ref is provided; alternatively, if dynamic checkouts are
allowed, require an explicit interactive confirmation before reading/posting
migrations/db_int.sql to the SQL endpoint and log the template ref being used.
Apply the same protection (pin-or-confirm) to the duplicate logic referenced
around the other migration execution (the code block at lines 363-367) so both
clone-and-migrate flows are gated.

In `@src/lib/env.ts`:
- Around line 8-28: readEnvFile currently returns after finding the first env
file and also preserves surrounding quotes verbatim; change it to read all
candidate files ('.env', '.env.production', '.env.local' order or similar where
later files override earlier) and merge entries so missing defaults are retained
while later files overwrite keys, and update the parsing logic inside
readEnvFile to strip surrounding single/double quotes from values and unescape
common escape sequences so deployed values match the intended contents; ensure
you update references to candidates, filePath checks, and the vars accumulation
logic so you accumulate across files and apply overrides by key rather than
returning early.

---

Nitpick comments:
In `@src/commands/create.ts`:
- Around line 156-160: The template routing is hard-coded around the template
variable and downloadGitHubTemplate/downloadTemplate calls; replace this
branching with a small registry mapping template names to handler functions or
source descriptors and dispatch to the appropriate handler instead of using if
(template === 'chatbot') {...} else if (hasTemplate) {...}. Create a
TemplateRegistry (map from template string to a handler function or an object
describing {type, handler}) and in the create flow use
templateRegistry.get(template) to invoke the correct handler (passing
projectConfig, projectName, json, apiUrl as needed) with a sensible
default/fallback to the existing downloadTemplate behavior for non-GitHub or
unknown templates; update places that reference template, hasTemplate,
downloadGitHubTemplate, and downloadTemplate to use the registry dispatch.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 1f3f4d9e-c89a-4833-98e0-847cc712d8a1

📥 Commits

Reviewing files that changed from the base of the PR and between 53cd4e8 and cc36a42.

📒 Files selected for processing (3)
  • package.json
  • src/commands/create.ts
  • src/lib/env.ts
✅ Files skipped from review due to trivial changes (1)
  • package.json

Comment on lines +369 to +382
} catch (err) {
dbSpinner?.stop('Database migration failed');
if (!json) {
clack.log.warn(`Migration failed: ${(err as Error).message}`);
clack.log.info('You can run the migration manually: insforge db query --unrestricted "$(cat migrations/db_int.sql)"');
}
}
}
} catch (err) {
s?.stop(`${templateName} template download failed`);
if (!json) {
clack.log.warn(`Failed to download ${templateName} template: ${(err as Error).message}`);
clack.log.info('You can manually clone from: https://github.com/InsForge/insforge-templates');
}
Copy link

@coderabbitai coderabbitai bot Mar 19, 2026

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Bubble template bootstrap failures back to create.

Both the migration block and the outer template-setup catch only warn, so the command keeps going into npm install and the deploy prompt with a partial project. Return a failure here so registerCreateCommand can stop before presenting the setup as successful.

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

In `@src/commands/create.ts` around lines 369 - 382, The migration and outer
template-download catch blocks currently only log warnings (in the catch
handling around dbSpinner and s in src/commands/create.ts) which allows
execution to continue; change both catch handlers to rethrow the caught error
after logging (i.e., after dbSpinner?.stop(...)/s?.stop(...) and
clack.log.warn/info calls) so the error bubbles up to registerCreateCommand and
stops further steps (npm install / deploy prompt) instead of proceeding with a
partial project.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Intentional design — migration failure is non-fatal because the project, env file, and template files are already set up successfully. Rethrowing would kill the entire create flow over a migration hiccup. The user gets a warning with a manual command to retry.

Copy link

Choose a reason for hiding this comment

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

@tonychang04, that's a fair point — since the scaffolding (project, env, and template files) is already complete at that stage, treating the migration as a non-fatal step with a manual retry path is a reasonable UX choice. Acknowledged!


✏️ Learnings added
Learnt from: tonychang04
Repo: InsForge/CLI PR: 27
File: src/commands/create.ts:0-0
Timestamp: 2026-03-19T22:19:06.362Z
Learning: In `src/commands/create.ts` (InsForge CLI), migration failures inside `downloadGitHubTemplate` are intentionally non-fatal. The project creation, env file generation, and template file copy are all complete before migrations run, so a migration hiccup should only warn the user (with a manual retry command) rather than abort the entire `create` flow.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

@tonychang04 tonychang04 disabled auto-merge March 19, 2026 21:50
tonychang04 and others added 3 commits March 19, 2026 14:51
- Reject invalid --template values with a clear error
- Env var regex now matches names containing digits (e.g. API_KEY_V2)
- Strip surrounding quotes from env file values before deploying

0.1.25

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
0.1.26

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Prompt user for confirmation before executing SQL from downloaded
templates, addressing CodeRabbit review feedback.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

if (!clack.isCancel(runMigration) && runMigration) {
const dbSpinner = clack.spinner();
dbSpinner.start('Running database migrations...');
Copy link
Member

Choose a reason for hiding this comment

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

Why not call insforge db query {sql} instead of REST API?

// Run database migrations if db_int.sql exists
const migrationPath = path.join(cwd, 'migrations', 'db_int.sql');
const migrationExists = await fs.stat(migrationPath).catch(() => null);
if (migrationExists && !json) {
Copy link
Member

Choose a reason for hiding this comment

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

With insforge create --json --template chatbot, the scaffold still includes migrations/db_int.sql, but this block skips it entirely because it is gated on !json. That means the non-interactive/automation path reports success while leaving the chatbot template with an uninitialized schema, so the generated app is broken until the caller notices and runs the SQL manually.

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