feat: introduce Crisp commands for code simplicity auditing and management: - #247
Conversation
…ement: - Added commands: /crisp, /crisp-review, /crisp-audit, /crisp-debt, and /crisp-gain to manage and evaluate code simplicity. - Implemented functionality to review code against the Crisp simplicity ladder, audit for over-engineering patterns, and assess potential gains from applying Crisp principles. - Enhanced CLI with new configuration options for Crisp modes and integrated prompts for user guidance. - Updated workspace context to include Crisp principles in code reviews.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
Your trial has ended. Reactivate Greptile to resume code reviews.
|
Note Currently processing new changes in this PR. This may take a few minutes, please wait... ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: ⛔ Files ignored due to path filters (3)
📒 Files selected for processing (32)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 13
🧹 Nitpick comments (9)
apps/web/app/(pages)/features/page.tsx (2)
199-199: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winUse
cn()consistently for conditional classes. This preserves Tailwind conflict handling and follows the web-app class composition convention.
apps/web/app/(pages)/features/page.tsx#L199-L199: compose the base classes and optionalclassNamewithcn().apps/web/app/(pages)/features/page.tsx#L460-L462: compose the base icon classes and conditional rotation withcn().As per coding guidelines, use
cn()from@/lib/utilsfor conditional classes.🤖 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 `@apps/web/app/`(pages)/features/page.tsx at line 199, Update the container class composition at apps/web/app/(pages)/features/page.tsx:199 to use cn() for the base classes and optional className, and update the icon class composition at apps/web/app/(pages)/features/page.tsx:460-462 to use cn() for its base classes and conditional rotation; import cn from `@/lib/utils` if needed.Source: Coding guidelines
290-290: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winReplace repeated hardcoded colors with semantic tokens. Theme-aware text utilities should represent the same visual role in both headings.
apps/web/app/(pages)/features/page.tsx#L290-L290: replacetext-[#A1A1AA]with the appropriate semantic text token.apps/web/app/(pages)/features/page.tsx#L493-L493: use that same semantic token for the CTA heading.As per coding guidelines, prefer semantic CSS variables over hardcoded values.
🤖 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 `@apps/web/app/`(pages)/features/page.tsx at line 290, Replace the hardcoded text color in the heading at apps/web/app/(pages)/features/page.tsx lines 290-290 with the appropriate semantic text token, and apply the same token to the CTA heading at lines 493-493. Preserve the existing layout and styling while ensuring both headings use theme-aware semantic utilities.Source: Coding guidelines
apps/supercode-cli/server/src/cli/crisp/config.ts (1)
1-25: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚖️ Poor tradeoffUse Bun filesystem APIs for Crisp configuration.
This new server path reads configuration through Node
fs; migrate the config API and its callers to async Bun filesystem operations instead. As per coding guidelines, “PreferBun.fileover Node.jsnode:fsreadFile/writeFile for file operations.”🤖 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 `@apps/supercode-cli/server/src/cli/crisp/config.ts` around lines 1 - 25, Migrate getCrispModeSync and its callers to an asynchronous configuration API using Bun.file for reading CONFIG_FILE, removing the Node fs dependency. Preserve the existing JSON parsing, CRISP_MODES validation, and fallback behavior while updating every caller to await the new async function.Source: Coding guidelines
apps/web/components/blog/featured-post.tsx (2)
1-74: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winUse PascalCase component filenames.
apps/web/components/blog/featured-post.tsx#L1-L74: rename to a PascalCase component filename, such asFeaturedPost.tsx, and update imports.apps/web/app/(pages)/blog/[slug]/post-client.tsx#L1-L101: rename to a PascalCase component filename, such asPostPage.tsx, and update the route import.🤖 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 `@apps/web/components/blog/featured-post.tsx` around lines 1 - 74, Rename the component file containing FeaturedPost to FeaturedPost.tsx and update every import referencing it. Rename apps/web/app/(pages)/blog/[slug]/post-client.tsx to PostPage.tsx and update the route import accordingly; no direct code changes are required beyond these filename and import updates.Source: Coding guidelines
8-10: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winUse
typefor these closed props contracts.
apps/web/components/blog/featured-post.tsx#L8-L10: replaceinterface FeaturedPostPropswith atype.apps/web/app/(pages)/blog/[slug]/post-client.tsx#L10-L13: replaceinterface PostPagePropswith atype.🤖 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 `@apps/web/components/blog/featured-post.tsx` around lines 8 - 10, Replace the closed props-contract interfaces with type aliases in FeaturedPostProps at apps/web/components/blog/featured-post.tsx lines 8-10 and PostPageProps at apps/web/app/(pages)/blog/[slug]/post-client.tsx lines 10-13, preserving each existing property definition and usage.Source: Coding guidelines
apps/web/components/blog/mdx-components.tsx (1)
149-153: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winReplace the hardcoded code-block background token.
Use an existing semantic color token, or add a dedicated code-surface variable, instead of
bg-[#0a0a0a]so the component follows the site theme contract.🤖 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 `@apps/web/components/blog/mdx-components.tsx` around lines 149 - 153, Update the className in the pre code-block component to remove the hardcoded bg-[`#0a0a0a`] value and use an existing semantic background token, or the established dedicated code-surface variable if one exists. Preserve the remaining styling and className composition unchanged.Source: Coding guidelines
apps/web/lib/blog.ts (1)
1-5: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winSeparate import groups consistently.
apps/web/lib/blog.ts#L1-L5: separate Node built-ins, external packages, and relative imports with blank lines.apps/web/components/blog/featured-post.tsx#L3-L6: separate Next, external, and alias imports with blank lines.apps/web/components/blog/mdx-components.tsx#L1-L2: place the Next import before external imports and separate groups.apps/web/app/(pages)/blog/[slug]/page.tsx#L1-L6: separate Next, external, alias, and relative imports with blank lines.apps/web/app/(pages)/blog/[slug]/post-client.tsx#L3-L8: place Next before external imports and separate import groups.🤖 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 `@apps/web/lib/blog.ts` around lines 1 - 5, Organize imports into consistently separated groups: in apps/web/lib/blog.ts lines 1-5, group Node built-ins, external packages, and relative imports; in apps/web/components/blog/featured-post.tsx lines 3-6, group Next, external, and alias imports; in apps/web/components/blog/mdx-components.tsx lines 1-2, place Next imports before external imports with blank lines; in apps/web/app/(pages)/blog/[slug]/page.tsx lines 1-6, group Next, external, alias, and relative imports; and in apps/web/app/(pages)/blog/[slug]/post-client.tsx lines 3-8, place Next imports before external imports and separate each group.Source: Coding guidelines
apps/web/app/(pages)/blog/blog-client.tsx (2)
1-1: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winRename new component files to PascalCase.
apps/web/app/(pages)/blog/blog-client.tsx#L1-L1: rename the file to a PascalCase component filename such asBlogPage.tsxand update imports.apps/web/components/blog/blog-card.tsx#L1-L1: rename the file toBlogCard.tsxand update imports.As per coding guidelines, TypeScript/TSX component filenames must use PascalCase.
🤖 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 `@apps/web/app/`(pages)/blog/blog-client.tsx at line 1, Rename apps/web/app/(pages)/blog/blog-client.tsx to a PascalCase component filename such as BlogPage.tsx and update all imports; rename apps/web/components/blog/blog-card.tsx to BlogCard.tsx and update all imports referencing it.Source: Coding guidelines
3-9: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winSeparate dependency groups in the new web imports.
The new files omit the required blank lines between external libraries, internal aliases, and relative imports.
apps/web/app/(pages)/blog/blog-client.tsx#L3-L9: separate external library imports from@/...imports.apps/web/app/(pages)/blog/page.tsx#L1-L2: separate@/...imports from the relative./blog-clientimport.apps/web/components/blog/blog-card.tsx#L3-L6: separate external library imports from@/...imports.As per coding guidelines, web imports require React/Next → external libraries → internal aliases → relative imports, with blank lines between groups.
🤖 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 `@apps/web/app/`(pages)/blog/blog-client.tsx around lines 3 - 9, Separate imports into the required groups with blank lines: in apps/web/app/(pages)/blog/blog-client.tsx lines 3-9, place external libraries before internal `@/` aliases; in apps/web/app/(pages)/blog/page.tsx lines 1-2, separate `@/` imports from the relative ./blog-client import; and in apps/web/components/blog/blog-card.tsx lines 3-6, separate external libraries from `@/` imports. Preserve the React/Next → external libraries → internal aliases → relative imports order.Source: Coding guidelines
🤖 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.
Inline comments:
In `@apps/supercode-cli/server/src/cli/commands/slashCommands/crisp-audit.ts`:
- Around line 2-14: Replace execSync in crispAuditCommand with execFileSync,
passing the fd options as fixed argument entries and using process.cwd() through
the cwd option instead of interpolating it into a shell command. Preserve the
existing file extensions, exclusions, depth limit, and UTF-8 output behavior.
In `@apps/supercode-cli/server/src/cli/commands/slashCommands/crisp-debt.ts`:
- Around line 11-18: Update the scan in the command’s marker-counting loop to
include the intended workspace comment file types, including files using # and
-- comments, rather than limiting ripgrep to the current TypeScript and
JavaScript filters. For each matching result line, iterate all occurrences with
matchAll using the global Crisp-marker pattern, and increment tagCounts for
every captured rung instead of only the first match.
In `@apps/supercode-cli/server/src/cli/commands/slashCommands/crisp-help.ts`:
- Around line 38-42: Update the configuration guidance in the Crisp help command
to document the supported ~/.config/supercode/cli-config.json file and its
crispMode field, replacing the unsupported CRISP_DEFAULT_MODE and crisp.json
examples. Do not implement new configuration inputs; keep the help text aligned
with the existing config implementation.
In `@apps/supercode-cli/server/src/cli/commands/slashCommands/crisp-review.ts`:
- Around line 12-14: Update the diff assembly in the crisp-review command so it
includes both staged and unstaged output rather than selecting only the staged
result. Preserve each command’s captured content and combine them in order,
including empty results safely.
In `@apps/supercode-cli/server/src/cli/workspace/context.ts`:
- Around line 219-228: Update pushCrispSection to resolve the Crisp mode through
the shared CrispMode integration or an exported resolver from
src/cli/crisp/index.ts, rather than reading cli-config.json#crispMode directly.
Ensure it honors CRISP_DEFAULT_MODE and ~/.config/supercode/crisp.json, and
replace the current fs.readFileSync usage with the available Bun filesystem API
while preserving the existing valid-mode filtering and prompt behavior.
In `@apps/web/app/`(pages)/blog/blog-client.tsx:
- Around line 18-20: Update BlogPage to use its featured prop and render the
FeaturedPost component for the supplied featured posts. Ensure posts marked
featured from page.tsx are visibly presented while preserving the existing
category filtering and regular post rendering.
In `@apps/web/app/`(pages)/features/page.tsx:
- Line 270: Add the matching top anchor to the page’s main element by setting
id="top" on the <main> returned by the page component. Preserve its existing
classes and structure so Footer’s href="`#top`" link scrolls to the page start.
- Around line 452-466: Add aria-expanded={isOpen} to the FAQ toggle button in
the FAQ rendering block so assistive technology receives the current expansion
state; if the answer content has assigned IDs, also connect the button with a
matching aria-controls value.
- Around line 3-7: Update the imports in the features page to explicitly import
type ReactNode from React, group the React/Next imports together with Link, and
preserve the existing component imports in their appropriate group. Replace any
React.ReactNode usage with the locally imported ReactNode type.
In `@apps/web/components/blog/mdx-components.tsx`:
- Around line 4-6: In the MDX components module, remove the local cn helper and
import the shared cn from `@/lib/utils`. Update existing usages to use that
imported helper, preserving current class composition while enabling clsx and
tailwind-merge behavior.
In `@apps/web/lib/blog.ts`:
- Around line 75-76: Update the BlogPage rendering flow to consume the
collection returned by getFeaturedPosts(), ensuring featured posts render
through the existing FeaturedPost component; alternatively, remove
getFeaturedPosts() and its unused featured contract if featured rendering is not
intended. Keep the behavior consistent with the chosen contract.
- Around line 47-52: Validate the route-derived slug in getPostBySlug before
constructing or reading filePath, rejecting absolute paths and traversal
segments that could escape BLOG_DIR. Ensure the resolved candidate remains
contained within BLOG_DIR, returning null for invalid slugs while preserving
normal valid-slug lookup behavior.
In `@apps/web/lib/utils.ts`:
- Around line 26-31: Update formatDate to specify the UTC timezone in its
toLocaleDateString options, preserving the existing en-US locale and
year/month/day formatting so date-only values render consistently across server
and client time zones.
---
Nitpick comments:
In `@apps/supercode-cli/server/src/cli/crisp/config.ts`:
- Around line 1-25: Migrate getCrispModeSync and its callers to an asynchronous
configuration API using Bun.file for reading CONFIG_FILE, removing the Node fs
dependency. Preserve the existing JSON parsing, CRISP_MODES validation, and
fallback behavior while updating every caller to await the new async function.
In `@apps/web/app/`(pages)/blog/blog-client.tsx:
- Line 1: Rename apps/web/app/(pages)/blog/blog-client.tsx to a PascalCase
component filename such as BlogPage.tsx and update all imports; rename
apps/web/components/blog/blog-card.tsx to BlogCard.tsx and update all imports
referencing it.
- Around line 3-9: Separate imports into the required groups with blank lines:
in apps/web/app/(pages)/blog/blog-client.tsx lines 3-9, place external libraries
before internal `@/` aliases; in apps/web/app/(pages)/blog/page.tsx lines 1-2,
separate `@/` imports from the relative ./blog-client import; and in
apps/web/components/blog/blog-card.tsx lines 3-6, separate external libraries
from `@/` imports. Preserve the React/Next → external libraries → internal aliases
→ relative imports order.
In `@apps/web/app/`(pages)/features/page.tsx:
- Line 199: Update the container class composition at
apps/web/app/(pages)/features/page.tsx:199 to use cn() for the base classes and
optional className, and update the icon class composition at
apps/web/app/(pages)/features/page.tsx:460-462 to use cn() for its base classes
and conditional rotation; import cn from `@/lib/utils` if needed.
- Line 290: Replace the hardcoded text color in the heading at
apps/web/app/(pages)/features/page.tsx lines 290-290 with the appropriate
semantic text token, and apply the same token to the CTA heading at lines
493-493. Preserve the existing layout and styling while ensuring both headings
use theme-aware semantic utilities.
In `@apps/web/components/blog/featured-post.tsx`:
- Around line 1-74: Rename the component file containing FeaturedPost to
FeaturedPost.tsx and update every import referencing it. Rename
apps/web/app/(pages)/blog/[slug]/post-client.tsx to PostPage.tsx and update the
route import accordingly; no direct code changes are required beyond these
filename and import updates.
- Around line 8-10: Replace the closed props-contract interfaces with type
aliases in FeaturedPostProps at apps/web/components/blog/featured-post.tsx lines
8-10 and PostPageProps at apps/web/app/(pages)/blog/[slug]/post-client.tsx lines
10-13, preserving each existing property definition and usage.
In `@apps/web/components/blog/mdx-components.tsx`:
- Around line 149-153: Update the className in the pre code-block component to
remove the hardcoded bg-[`#0a0a0a`] value and use an existing semantic background
token, or the established dedicated code-surface variable if one exists.
Preserve the remaining styling and className composition unchanged.
In `@apps/web/lib/blog.ts`:
- Around line 1-5: Organize imports into consistently separated groups: in
apps/web/lib/blog.ts lines 1-5, group Node built-ins, external packages, and
relative imports; in apps/web/components/blog/featured-post.tsx lines 3-6, group
Next, external, and alias imports; in
apps/web/components/blog/mdx-components.tsx lines 1-2, place Next imports before
external imports with blank lines; in apps/web/app/(pages)/blog/[slug]/page.tsx
lines 1-6, group Next, external, alias, and relative imports; and in
apps/web/app/(pages)/blog/[slug]/post-client.tsx lines 3-8, place Next imports
before external imports and separate each group.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: f4938b11-c600-4814-93af-9dd3777fa3f3
⛔ Files ignored due to path filters (3)
apps/web/components/blog/public/supercode-crisp.pngis excluded by!**/*.pngapps/web/public/supercode-crisp.pngis excluded by!**/*.pngbun.lockis excluded by!**/*.lock
📒 Files selected for processing (32)
apps/supercode-cli/server/src/cli/commands/slashCommands/crisp-audit.tsapps/supercode-cli/server/src/cli/commands/slashCommands/crisp-debt.tsapps/supercode-cli/server/src/cli/commands/slashCommands/crisp-gain.tsapps/supercode-cli/server/src/cli/commands/slashCommands/crisp-help.tsapps/supercode-cli/server/src/cli/commands/slashCommands/crisp-review.tsapps/supercode-cli/server/src/cli/commands/slashCommands/crisp.tsapps/supercode-cli/server/src/cli/commands/slashCommands/index.tsapps/supercode-cli/server/src/cli/crisp/config.tsapps/supercode-cli/server/src/cli/crisp/index.tsapps/supercode-cli/server/src/cli/crisp/prompt.tsapps/supercode-cli/server/src/cli/workspace/context.tsapps/supercode-cli/server/src/lib/cli-config.tsapps/supercode-cli/server/src/tools/definitions/crisp-audit.tsapps/supercode-cli/server/src/tools/definitions/crisp-debt.tsapps/supercode-cli/server/src/tools/definitions/crisp-gain.tsapps/supercode-cli/server/src/tools/definitions/crisp-review.tsapps/supercode-cli/server/src/tools/registry.tsapps/web/app/(pages)/blog/[slug]/page.tsxapps/web/app/(pages)/blog/[slug]/post-client.tsxapps/web/app/(pages)/blog/blog-client.tsxapps/web/app/(pages)/blog/page.tsxapps/web/app/(pages)/features/page.tsxapps/web/components/blog/blog-card.tsxapps/web/components/blog/featured-post.tsxapps/web/components/blog/mdx-components.tsxapps/web/components/homepage/footer.tsxapps/web/components/homepage/navbar.tsxapps/web/content/blog/introducing-supercode-crisp.mdxapps/web/content/blog/why-we-built-supercode.mdxapps/web/lib/blog.tsapps/web/lib/utils.tsapps/web/package.json
| import { execSync } from "node:child_process" | ||
| import { theme, frame } from "src/cli/utils/tui.ts" | ||
| import { getCrispModeSync } from "src/cli/crisp/index.ts" | ||
| import type { SlashCommandResult } from "./index.ts" | ||
|
|
||
| export async function crispAuditCommand(argsStr: string): Promise<SlashCommandResult> { | ||
| const mode = getCrispModeSync() | ||
| const focus = argsStr.trim() || "all" | ||
| const modeLabel = mode === "off" ? "full" : mode | ||
|
|
||
| let fileList = "" | ||
| try { | ||
| fileList = execSync(`fd -e ts -e tsx -e js -e jsx --exclude node_modules --exclude dist --exclude .git --max-depth 6 . ${process.cwd()}`, { encoding: "utf-8" }) |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== locate file =="
git ls-files | grep -F 'apps/supercode-cli/server/src/cli/commands/slashCommands/crisp-audit.ts' || true
echo "== file excerpt =="
if [ -f apps/supercode-cli/server/src/cli/commands/slashCommands/crisp-audit.ts ]; then
wc -l apps/supercode-cli/server/src/cli/commands/slashCommands/crisp-audit.ts
cat -n apps/supercode-cli/server/src/cli/commands/slashCommands/crisp-audit.ts
fi
echo "== child_process imports/usages in server TypeScript =="
rg -n "exec(Sync|File)(Sync)?|child_process" apps/supercode-cli/server -g '*.ts' -g '*.tsx' -g '*.js' || true
echo "== deterministic shell behavior probe =="
node - <<'JS'
const { execSync, execFileSync } = require("node:child_process")
const dir = "/tmp/crisp-audit-probe; printf 'shell injection executed' > /tmp/crisp-audit-probe-payload.txt"
const safeDir = "/tmp/crisp-audit-probe-safe"
try {
execSync(`date +%s > ${dir}/payload.txt`, { stdio: "ignore", encoding: "utf8" })
console.log("execSync: payload exists", require("node:fs").existsSync(`${dir}/payload.txt`))
} catch (e) {
console.log("execSync_error", e.message.trim().split("\n")[0])
}
try {
execFileSync("date", ["+%s"], { cwd: dir, encoding: "utf8" })
console.log("execFileSync: payload_exists=", require("node:fs").existsSync(`${dir}/payload.txt`))
} catch (e) {
console.log("execFileSync_error", e.message.trim().split("\n")[0])
}
require("node:fs").rmSync("/tmp/crisp-audit-probe", { recursive: true, force: true })
require("node:fs").rmSync("/tmp/crisp-audit-probe-safe", { recursive: true, force: true })
JSRepository: yashdev9274/supercli
Length of output: 5729
🌐 Web query:
Node.js child_process execSync shell command execution default shell template string path whitespace documentation
💡 Result:
The Node.js child_process.execSync function executes a command inside a shell [1][2]. Because it operates via a shell, it interprets the provided command string as a set of arguments, where spaces typically act as delimiters [3][4]. Key technical details include: 1. Shell Execution and Whitespace: When you pass a command string containing whitespace to execSync, the underlying shell (e.g., /bin/sh or cmd.exe) parses those spaces as separators between the executable and its arguments [3][4]. To include paths containing whitespace, you must wrap the path in double quotes within the command string to ensure the shell interprets the entire path as a single argument [3][4]. 2. Default Shell: By default, execSync executes commands using '/bin/sh' on Unix-like systems and process.env.ComSpec (usually cmd.exe) on Windows [2][5]. This default behavior can be overridden using the shell option in the options object [2][6]. 3. Security Warning: Because execSync processes the command string directly through a shell, it is vulnerable to shell injection [2][5]. Node.js documentation explicitly warns against passing unsanitized user input to this function, as shell metacharacters (e.g., |, &,;, $) can be used to execute arbitrary commands [2][4]. 4. Recommended Alternatives: For scenarios involving paths with spaces or when user input is involved, it is generally safer and cleaner to use child_process.execFileSync or child_process.spawnSync [7][3]. These methods allow you to pass the executable and its arguments as separate array elements, which avoids shell interpretation entirely and eliminates the need for manual quoting or escaping of paths [7][3].
Citations:
- 1: https://nodejs.org/api/child_process.html
- 2: https://nodejs.org/api/child_process.md
- 3: https://stackoverflow.com/questions/32262071/nodes-exec-not-working-because-of-a-space-in-the-uri-name
- 4: https://r2.nodejs.org/docs/v18.20.2/api/child_process.html
- 5: https://nodejs.org/download/release/v22.14.0/docs/api/child_process.html
- 6: https://beta.docs.nodejs.org/child_process.html
- 7: https://techearl.com/nodejs-child-process-error-handling
Avoid shell interpolation of the workspace path.
execSync runs through a shell, and process.cwd() is interpolated into the command string. A workspace path with spaces breaks the scan, and shell metacharacters in the path can execute commands. Use execFileSync with fixed fd arguments and the cwd option.
🧰 Tools
🪛 OpenGrep (1.26.0)
[ERROR] 14-14: Dynamic command passed to child_process.exec/execSync. Use child_process.execFile or spawn with an argument array instead.
(coderabbit.command-injection.exec-js)
🤖 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 `@apps/supercode-cli/server/src/cli/commands/slashCommands/crisp-audit.ts`
around lines 2 - 14, Replace execSync in crispAuditCommand with execFileSync,
passing the fd options as fixed argument entries and using process.cwd() through
the cwd option instead of interpolating it into a shell command. Preserve the
existing file extensions, exclusions, depth limit, and UTF-8 output behavior.
Source: Linters/SAST tools
| rawMatches = execSync("rg -n '\\[crisp:\\d+\\]' --type ts --type tsx --type js --type jsx -g '!node_modules' -g '!dist'", { encoding: "utf-8" }) | ||
| const matches = rawMatches.split("\n").filter(Boolean) | ||
| for (const m of matches) { | ||
| const tag = m.match(/\[crisp:(\d+)\]/) | ||
| if (tag) { | ||
| const rung = tag[1]! | ||
| tagCounts[rung] = (tagCounts[rung] ?? 0) + 1 | ||
| } |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Scan and count every Crisp marker.
The type filters exclude the # and -- comment styles this command claims to detect, and match() counts only the first [crisp:N] on a line. This can report a false-clean or undercounted workspace ledger. Scan the intended workspace file set and iterate matchAll(/\[crisp:(\d+)\]/g) for each result line.
Also applies to: 24-24
🤖 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 `@apps/supercode-cli/server/src/cli/commands/slashCommands/crisp-debt.ts`
around lines 11 - 18, Update the scan in the command’s marker-counting loop to
include the intended workspace comment file types, including files using # and
-- comments, rather than limiting ripgrep to the current TypeScript and
JavaScript filters. For each matching result line, iterate all occurrences with
matchAll using the global Crisp-marker pattern, and increment tagCounts for
every captured rung instead of only the first match.
| chalk.hex(theme.amber).bold("Configure default"), | ||
| chalk.hex(theme.muted)("Environment variable (highest priority):"), | ||
| ` ${chalk.hex(theme.greenDim)("export CRISP_DEFAULT_MODE=ultra")}`, | ||
| chalk.hex(theme.muted)("Config file (~/.config/supercode/crisp.json):"), | ||
| ` ${chalk.hex(theme.greenDim)('{"defaultMode": "lite"}')}`, |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Document the configuration mechanism that actually exists.
Neither CRISP_DEFAULT_MODE nor ~/.config/supercode/crisp.json is read by the supplied config implementation. Users following this help cannot configure Crisp. Either implement those inputs or document ~/.config/supercode/cli-config.json with its crispMode field.
🤖 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 `@apps/supercode-cli/server/src/cli/commands/slashCommands/crisp-help.ts`
around lines 38 - 42, Update the configuration guidance in the Crisp help
command to document the supported ~/.config/supercode/cli-config.json file and
its crispMode field, replacing the unsupported CRISP_DEFAULT_MODE and crisp.json
examples. Do not implement new configuration inputs; keep the help text aligned
with the existing config implementation.
| const staged = execSync("git diff --cached", { encoding: "utf-8" }) | ||
| const unstaged = execSync("git diff", { encoding: "utf-8" }) | ||
| diff = staged || unstaged |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Include both staged and unstaged changes in the review.
When both diffs exist, staged || unstaged discards the unstaged diff, so /crisp-review misses part of the working tree.
Proposed fix
- diff = staged || unstaged
+ diff = [staged, unstaged].filter(Boolean).join("\n")📝 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.
| const staged = execSync("git diff --cached", { encoding: "utf-8" }) | |
| const unstaged = execSync("git diff", { encoding: "utf-8" }) | |
| diff = staged || unstaged | |
| const staged = execSync("git diff --cached", { encoding: "utf-8" }) | |
| const unstaged = execSync("git diff", { encoding: "utf-8" }) | |
| diff = [staged, unstaged].filter(Boolean).join("\n") |
🤖 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 `@apps/supercode-cli/server/src/cli/commands/slashCommands/crisp-review.ts`
around lines 12 - 14, Update the diff assembly in the crisp-review command so it
includes both staged and unstaged output rather than selecting only the staged
result. Preserve each command’s captured content and combine them in order,
including empty results safely.
| function pushCrispSection(lines: string[]): void { | ||
| const configPath = path.join(os.homedir(), ".config", "supercode", "cli-config.json") | ||
| let mode: string = "off" | ||
| try { | ||
| const data = fs.readFileSync(configPath, "utf-8") | ||
| const config = JSON.parse(data) | ||
| if (["off", "lite", "full", "ultra"].includes(config.crispMode)) { | ||
| mode = config.crispMode | ||
| } | ||
| } catch {} |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "Tracked files around crisp/context:"
git ls-files | rg 'apps/supercode-cli/server/src/cli/(workspace/context.ts|.*crisp.*|.*help.*crisp.*|.*crisp.*help.*)|apps/supercode-cli/server/src' | rg -n 'crisp|context' || true
echo
echo "context.ts outline:"
ast-grep outline apps/supercode-cli/server/src/cli/workspace/context.ts --view compact || true
echo
echo "Relevant context.ts lines:"
sed -n '180,260p' apps/supercode-cli/server/src/cli/workspace/context.ts
echo
echo "Search Crisp config references:"
rg -n "crispMode|CRISP_DEFAULT_MODE|crisp\.json|cli-config\.json|pushCrispSection|Crisp" apps/supercode-cli/server/src -S || trueRepository: yashdev9274/supercli
Length of output: 13836
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "cli-config file:"
sed -n '1,120p' apps/supercode-cli/server/src/lib/cli-config.ts
echo
echo "crisp config/index:"
sed -n '1,120p' apps/supercode-cli/server/src/cli/crisp/config.ts
echo
sed -n '1,20p' apps/supercode-cli/server/src/cli/crisp/index.ts
echo
echo "crisp-help relevant lines:"
sed -n '1,90p' apps/supercode-cli/server/src/cli/commands/slashCommands/crisp-help.ts
echo
echo "context.ts top imports and prompt/ladder call sites:"
sed -n '1,55p' apps/supercode-cli/server/src/cli/workspace/context.ts
rg -n "buildPrompt|function buildPrompt|export function buildPrompt|crispLadderPrompt|pushCrispSection" apps/supercode-cli/server/src/cli/workspace/context.ts -S
sed -n '140,195p' apps/supercode-cli/server/src/cli/workspace/context.ts
sed -n '260,320p' apps/supercode-cli/server/src/cli/workspace/context.ts
echo
echo "Search for CRISP_DEFAULT_MODE outside crisp/help:"
rg -n "CRISP_DEFAULT_MODE|~/.config/supercode/crisp\.json|minimize_ladder|crisp\.json" apps/supercode-cli/server/src -S || trueRepository: yashdev9274/supercli
Length of output: 18507
Use the shared Crisp mode source when injecting the prompt.
crisp-help.ts documents CRISP_DEFAULT_MODE / ~/.config/supercode/crisp.json, but pushCrispSection() reads only cli-config.json#crispMode. A user can set the documented default and still omit Crisp from this system prompt. Reuse src/cli/crisp/index.ts’s CrispMode integration here or export a shared resolver, and use the available Bun filesystem APIs for the file read.
🧰 Tools
🪛 ast-grep (0.45.0)
[warning] 222-222: Filesystem path is not a string literal; a request-/variable-derived path can enable path traversal. Validate and normalize the path before use.
Context: fs.readFileSync(configPath, "utf-8")
Note: [CWE-22] Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal').
(detect-non-literal-fs-filename-typescript)
🤖 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 `@apps/supercode-cli/server/src/cli/workspace/context.ts` around lines 219 -
228, Update pushCrispSection to resolve the Crisp mode through the shared
CrispMode integration or an exported resolver from src/cli/crisp/index.ts,
rather than reading cli-config.json#crispMode directly. Ensure it honors
CRISP_DEFAULT_MODE and ~/.config/supercode/crisp.json, and replace the current
fs.readFileSync usage with the available Bun filesystem API while preserving the
existing valid-mode filtering and prompt behavior.
Source: Coding guidelines
| <button | ||
| onClick={() => setExpandedFaq(isOpen ? null : i)} | ||
| className="w-full flex items-center justify-between gap-4 px-5 py-4 text-left transition-all duration-200 active:scale-[0.99]" | ||
| > | ||
| <span className="text-[14px] font-medium text-foreground font-mono"> | ||
| {item.q} | ||
| </span> | ||
| <span | ||
| className={`text-muted-foreground text-lg transition-transform duration-200 shrink-0 ${ | ||
| isOpen ? "rotate-45" : "" | ||
| }`} | ||
| > | ||
| + | ||
| </span> | ||
| </button> |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Expose FAQ expansion state to assistive technology.
The button toggles content visually but does not provide aria-expanded. Add aria-expanded={isOpen} (and an aria-controls target if assigning answer IDs).
🤖 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 `@apps/web/app/`(pages)/features/page.tsx around lines 452 - 466, Add
aria-expanded={isOpen} to the FAQ toggle button in the FAQ rendering block so
assistive technology receives the current expansion state; if the answer content
has assigned IDs, also connect the button with a matching aria-controls value.
| function cn(...classes: (string | undefined | false)[]) { | ||
| return classes.filter(Boolean).join(" ") | ||
| } |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win
Use the shared cn helper.
The local helper bypasses the required clsx + tailwind-merge behavior, so MDX-provided classes can conflict with base styles. Import cn from @/lib/utils and remove this helper.
🤖 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 `@apps/web/components/blog/mdx-components.tsx` around lines 4 - 6, In the MDX
components module, remove the local cn helper and import the shared cn from
`@/lib/utils`. Update existing usages to use that imported helper, preserving
current class composition while enabling clsx and tailwind-merge behavior.
Source: Coding guidelines
| export function getPostBySlug(slug: string): BlogPost | null { | ||
| ensureBlogDir() | ||
| const filePath = path.join(BLOG_DIR, `${slug}.mdx`) | ||
|
|
||
| if (!fs.existsSync(filePath)) { | ||
| return null |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
Contain slug lookups within the blog directory.
slug is route-derived and is joined into a filesystem path without validation. Traversal segments can resolve to readable .mdx files outside content/blog, which are then compiled and returned by the public post route.
Proposed fix
export function getPostBySlug(slug: string): BlogPost | null {
ensureBlogDir()
- const filePath = path.join(BLOG_DIR, `${slug}.mdx`)
+ const filePath = path.resolve(BLOG_DIR, `${slug}.mdx`)
+ const relativePath = path.relative(BLOG_DIR, filePath)
+
+ if (
+ relativePath.startsWith(`..${path.sep}`) ||
+ path.isAbsolute(relativePath)
+ ) {
+ return null
+ }
if (!fs.existsSync(filePath)) {📝 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.
| export function getPostBySlug(slug: string): BlogPost | null { | |
| ensureBlogDir() | |
| const filePath = path.join(BLOG_DIR, `${slug}.mdx`) | |
| if (!fs.existsSync(filePath)) { | |
| return null | |
| export function getPostBySlug(slug: string): BlogPost | null { | |
| ensureBlogDir() | |
| const filePath = path.resolve(BLOG_DIR, `${slug}.mdx`) | |
| const relativePath = path.relative(BLOG_DIR, filePath) | |
| if ( | |
| relativePath.startsWith(`..${path.sep}`) || | |
| path.isAbsolute(relativePath) | |
| ) { | |
| return null | |
| } | |
| if (!fs.existsSync(filePath)) { | |
| return null |
🤖 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 `@apps/web/lib/blog.ts` around lines 47 - 52, Validate the route-derived slug
in getPostBySlug before constructing or reading filePath, rejecting absolute
paths and traversal segments that could escape BLOG_DIR. Ensure the resolved
candidate remains contained within BLOG_DIR, returning null for invalid slugs
while preserving normal valid-slug lookup behavior.
Source: Linters/SAST tools
| export function getFeaturedPosts(): BlogPostMeta[] { | ||
| return getAllPosts().filter((p) => p.featured) |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Make the featured flag affect the listing.
getFeaturedPosts() is passed into BlogPage, but the supplied BlogPage implementation never reads featured; FeaturedPost is therefore never rendered. Either render the featured collection or remove the unused feature contract.
🤖 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 `@apps/web/lib/blog.ts` around lines 75 - 76, Update the BlogPage rendering
flow to consume the collection returned by getFeaturedPosts(), ensuring featured
posts render through the existing FeaturedPost component; alternatively, remove
getFeaturedPosts() and its unused featured contract if featured rendering is not
intended. Keep the behavior consistent with the chosen contract.
| export function formatDate(dateString: string): string { | ||
| return new Date(dateString).toLocaleDateString("en-US", { | ||
| year: "numeric", | ||
| month: "long", | ||
| day: "numeric", | ||
| }) |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== Locate file =="
git ls-files | grep -F 'apps/web/lib/utils.ts' || true
echo "== Inspect utils excerpt =="
if [ -f apps/web/lib/utils.ts ]; then
sed -n '1,60p' apps/web/lib/utils.ts | cat -n
fi
echo "== Find formatDate usages =="
rg -n "formatDate\(" apps/web || true
echo "== Check environment / next config hints =="
for f in package.json apps/web/package.json next.config.* apps/web/next.config.*; do
if [ -f "$f" ]; then
echo "--- $f ---"
sed -n '1,160p' "$f" | grep -Ei '(date|next|environment|tz|timezone)' || true
fi
done
echo "== Behavioral probe if Node available =="
node - <<'JS'
try {
const TZs = ["America/New_York", "America/Los_Angeles", "UTC"];
for (const tz of TZs) {
process.env.TZ = tz;
const d = new Date("2025-07-29");
const local = d.toLocaleDateString("en-US", {
year: "numeric",
month: "long",
day: "numeric",
});
const utc = d.toLocaleDateString("en-US", {
year: "numeric",
month: "long",
day: "numeric",
timeZone: "UTC",
});
console.log(`${tz}: Date(${JSON.stringify("2025-07-29")}) => local=${JSON.stringify(local)} utc=${JSON.stringify(utc)} iso=${d.toISOString()}`);
}
} catch (e) {
console.error(e && e.stack ? e.stack : e.message);
process.exit(1);
}
JSRepository: yashdev9274/supercli
Length of output: 2500
Format calendar dates in UTC.
Date-only values like "2025-07-29" parse at UTC midnight, so clients in U.S. time zones can render them as July 28. Set the locale timezone to UTC for Server Components/client UI to keep server/client rendering consistent.
🤖 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 `@apps/web/lib/utils.ts` around lines 26 - 31, Update formatDate to specify the
UTC timezone in its toLocaleDateString options, preserving the existing en-US
locale and year/month/day formatting so date-only values render consistently
across server and client time zones.
Description
Type of change
How Has This Been Tested?
Please describe the tests that you ran to verify your changes.
bun testpassesbun run typecheckpassesbun run lintpasses (if applicable)Checklist:
Summary by CodeRabbit