Apply code review fixes: security, deduplication, CLI UX, and bug fixes#11
Merged
teallarson merged 13 commits intomainfrom Mar 5, 2026
Merged
Apply code review fixes: security, deduplication, CLI UX, and bug fixes#11teallarson merged 13 commits intomainfrom
teallarson merged 13 commits intomainfrom
Conversation
Phase 1 – CLI source:
- Add --help and --version flags to the CLI
- Extract validateProjectName() with shell metachar + hyphen rejection
- Auto-generate BETTER_AUTH_SECRET and APP_SECRET_KEY on scaffold
- Pre-check bun is installed before running bun install steps
- Gracefully warn (not exit) on install failures so project is still usable
- Capture stdout in runAsync alongside stderr
Phase 2 – Template/config:
- Fill in template.json hint fields for interactive selector UX
- Sync lucide-react, radix-ui, tailwind-merge, tw-animate-css versions (mastra→ai-sdk)
- Fix langchain README hardcoded localhost:8000 → localhost:{{port}}
- Add maxDuration = 60 to mastra chat route
- Fix cookie_secure to derive from app_url scheme instead of hardcoded False
- Scope ESLint global rules block to src/**/*.ts to avoid overriding template warns
- Update .gitignore to cover .arcade-auth/, .venv/, bun.lock, .serena/, .context/, test-proj*/
Phase 3 – Open redirect:
- Validate next_uri is same-origin before redirecting in Next.js verify route
- Validate next_uri netloc in langchain verify route with urlparse
Phase 4 – Deduplication:
- Extract arcade OAuth provider into arcade-oauth-provider.hbs partial
- Replace ai-sdk and mastra arcade.ts with .hbs stubs referencing the partial
- Extract mapToolToSource() and extractAuthUrlFromToolOutput() into shared partials
- Remove inline duplicates from plan-route-body.hbs and sources-route-body.hbs
- Unify mapToolToSource regex (split on [._]) across both partials
Phase 5 – Security hardening:
- Set mode 0o700 on .arcade-auth/ dir and 0o600 on all written token files (TS + Python)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Instead of hard-failing when bun is missing, detect the available package manager and remap install/migrate/devCommand to use npm/npx. This lets users run `npx @arcadeai/create-agent` without needing bun pre-installed for the TypeScript templates. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The "url" field on todo items was getting populated with URLs found inside message content (links to docs, Jira, etc.) instead of permalinks to the actual Slack message. Add explicit URL RULES to both the TypeScript (Handlebars) and Python (LangChain) plan prompts telling the model to always link to the item itself in its source app. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- installDeps returns boolean; runMigrations gated on success - validateProjectName blocks colon (Windows reserved path char) - eslint.config.mjs: explicit no-console:off for templates/** - verify/route.ts: cache new URL(base) instead of constructing twice - arcade-oauth-provider.hbs: break long setPendingAuthUrl line - arcade_oauth.py: comment explaining mkdir+chmod pattern Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- useState(true) so first-time visitors land on "Create account" - Replace the small bottom text link with a pill tab switcher (Create account / Sign in) so the current mode is always obvious Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Previously, any failure in verifyExistingConnection() (including network glitches or a briefly-down gateway) caused the code to fall through to initiateOAuth(), which would call redirectToAuthorization() and return a new auth URL — forcing users to re-authorize even though their tokens were valid. Fix: verifyExistingConnection() now returns "ok" | "needs_reauth" | "unreachable" instead of boolean. Only a genuine 401/403 response falls through to OAuth. Any other failure surfaces a "check your gateway URL and retry" error instead of triggering a spurious re-auth prompt. Same logic applied to both TypeScript templates and the Python template. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The strict "OMIT url if no deep link" rule was causing most items to render without links. The new rules still prefer direct deep links (Slack permalink, Linear issue URL, Gmail thread URL, etc.) but fall back to any URL found in the tool response rather than omitting the field entirely. Only omit url if no URL exists anywhere in the response. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
… to register Replace red accent colors with neutral gray/dark palette matching the Next.js design. Add a pill tab switcher (Create account / Sign in) replacing the old bottom toggle link, and default to the register mode on first load. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The Next.js template doesn't show this widget; drop it from the Python template too so the dashboards stay consistent. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Replace all red accents (spinner, buttons, gate icons) with neutral gray/dark - Remove emoji from source badges; match Next.js badge color tokens exactly - Fix P2/FYI priority badge colors to match Next.js (gray/outline) - Add dark mode to task and stats cards (bg-white dark:bg-gray-900, dark border) - Align task card layout: badges in one row with effort ml-auto; next step as italic right-aligned text instead of a boxed "Next:" label - Stats cards: text-3xl font-bold, label/value stacked to match StatsBar.tsx Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
CLAUDE.md now points to AGENTS.md, which contains all project guidance including CLI mechanics, package managers, template system, UI components, linting details, CI jobs, E2E testing, and release process. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Implements all findings from the code review audit across 5 phases (stacked naturally on #10, which is now merged):
--help/--versionflags; name validation (rejects hyphen-prefixed names, shell metacharacters, path separators); bun pre-check before install; graceful install failure (warn + continue instead ofprocess.exit(1)); stdout capture inrunAsyncBETTER_AUTH_SECRETandAPP_SECRET_KEYare now filled withrandomBytes(32).toString("hex")when.envis created from.env.example— no more placeholder secrets in scaffolded projectslucide-react/radix-ui/tailwind-merge/tw-animate-cssversions (mastra→ai-sdk); fixed hardcodedlocalhost:8000in langchain README tolocalhost:{{port}}; addedexport const maxDuration = 60to mastra chat route;cookie_securenow derives fromapp_urlscheme; scoped ESLint global rules tosrc/**/*.tsto avoid overriding template-level warns; expanded.gitignorenext_urivalidated same-origin before redirecting in both Next.js and Python verify routesarcade.ts(~150 lines × 2) collapsed into onearcade-oauth-provider.hbspartial with a Handlebars conditional for the mastra-specificMCPClientexport;mapToolToSource()andextractAuthUrlFromToolOutput()extracted into shared partials, removing inline duplicates fromplan-route-body.hbsandsources-route-body.hbs; unifiedmapToolToSourceregex uses[._]split across all templates.arcade-auth/created with mode0o700; all written token/client/verifier files use0o600(both TypeScript and Python)Test plan
npm run build && npm run typecheck && npm run lint && npm run format:check— all passruff check templates/langchain/— all passnode dist/index.js --help— prints usagenode dist/index.js --version— prints0.1.0node dist/index.js "../bad" --template ai-sdk— rejects with path separator error.envhas non-emptyBETTER_AUTH_SECRET.envhas non-emptyBETTER_AUTH_SECRET.envhas non-emptyAPP_SECRET_KEY🤖 Generated with Claude Code