Conversation
Signed-off-by: LCSOGthb <185141600+LCSOGthb@users.noreply.github.com>
Signed-off-by: LCSOGthb <185141600+LCSOGthb@users.noreply.github.com>
|
Your 14-day trial has expired! You have already exhausted your 14th day trial period. Please upgrade your subscription to continue new analysis. Upgrade by visiting: View Dashboard |
|
Seems you are using me but didn't get OPENAI_API_KEY seted in Variables/Secrets for this repo. you could follow readme for more information |
| name: "Extract Text from HTML", | ||
| description: "Strip HTML tags and decode common entities with regex only.", | ||
| run: (input) => { | ||
| let out = input.replace(/<[^>]*>/g, ""); |
| out = out | ||
| .replace(/&/g, "&") |
| name: "Extract Text from XML", | ||
| description: "Strip XML tags and collapse whitespace per line.", | ||
| run: (input) => | ||
| toLines(input.replace(/<[^>]*>/g, "")) |
| // XML utilities — uses DOMParser/XMLSerializer available in the browser. | ||
|
|
||
| export function parseXml(xml: string): Document { | ||
| const doc = new DOMParser().parseFromString(xml, "application/xml"); |
Deploying with
|
| Status | Name | Latest Commit | Updated (UTC) |
|---|---|---|---|
| ❌ Deployment failed View logs |
tools | b369abe | Aug 30 2026, 07:20 PM |
There was a problem hiding this comment.
Sorry @LCSOGthb, your pull request is larger than the review limit of 150,000 diff characters
Summary of Changes & PR ReviewOverall, the PR adds a comprehensive suite of client-side developer and utility tools. A few functional bugs and React anti-patterns were identified and commented inline:
🤖 Reviewed by codereviewbot.ai - Catch bugs before your team does. |
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
🤖 CodeAnt AI — Review Status
|
Thanks for using CodeAnt! 🎉We're free for open-source projects. if you're enjoying it, help us grow by sharing. Share on X · |
|
Important Approval pendingCodeRabbit has no unresolved comments, but it has not reviewed the latest commit. Use the checkbox below to review the latest commit. CodeRabbit will approve the changes if it finds no blocking issues.
✨ Finishing Touches 💡 1🛠️ Fix failing CI checks 💡
📝 Generate docstrings
🧪 Generate unit tests (beta)
✨ Simplify code
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 |
Dependency Review✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.Scanned FilesNone |
There was a problem hiding this comment.
devskim found more than 20 potential problems in the proposed changes. Check the Files changed tab for more details.
|
View changes in DiffLens |
Hard-Coded Secrets (1)
More info on how to fix Hard-Coded Secrets in General. Insecure Processing of Data (3)
More info on how to fix Insecure Processing of Data in JavaScript. 👉 Go to the dashboard for detailed results. 📥 Happy? Share your feedback with us. |
There was a problem hiding this comment.
Bearer found more than 20 potential problems in the proposed changes. Check the Files changed tab for more details.
| const out: string[] = []; | ||
| let i = 0; | ||
| let lineStart = true; | ||
| let pending = ""; |
There was a problem hiding this comment.
'pending' is never reassigned. Use 'const' instead.
| let pending = ""; | |
| const pending = ""; |
| chip="" | ||
| label="HTML input" | ||
| placeholder="<div><p>Hello</p></div>" | ||
| transform={(s) => formatHtml(s).split("\n").map((l) => (indent === "4" ? l.replace(/^( )/g, " ") : l)).join("\n")} |
There was a problem hiding this comment.
Spaces are hard to count. Use {2}.
| transform={(s) => formatHtml(s).split("\n").map((l) => (indent === "4" ? l.replace(/^( )/g, " ") : l)).join("\n")} | |
| transform={(s) => formatHtml(s).split("\n").map((l) => (indent === "4" ? l.replace(/^( {2})/g, " ") : l)).join("\n")} |
| const tokens = noComments.replace(/([{};])/g, "$1\n").split("\n"); | ||
| let indent = 0; | ||
| const lines: string[] = []; | ||
| for (let raw of tokens) { |
There was a problem hiding this comment.
'raw' is never reassigned. Use 'const' instead.
| for (let raw of tokens) { | |
| for (const raw of tokens) { |
|
View changes in DiffLens |
100 new issues
|
| </GhostButton> | ||
| </div> | ||
| </div> | ||
| ); |
| case "md5-hash": return <Md5Hash />; | ||
| default: return <div className="text-sm text-muted-foreground">Unknown tool</div>; | ||
| } | ||
| } |
| i++; | ||
| } | ||
|
|
||
| return out.join(""); |
| case "js-minifier": return <JsMinifier />; | ||
| case "md5-hash": return <Md5Hash />; | ||
| default: return <div className="text-sm text-muted-foreground">Unknown tool</div>; | ||
| } |
| i++; | ||
| } | ||
| out = result.join("").replace(/[ \t]+/g, " ").replace(/\n\s*\n+/g, "\n").trim(); | ||
| return out; |
| result = (result & ~clear) | masked; | ||
| } | ||
| } | ||
| return result.toString(8).padStart(3, "0"); |
|
View changes in DiffLens |
Not up to standards ⛔🔴 Issues
|
| Category | Results |
|---|---|
| BestPractice | 1 medium 1 high |
| CodeStyle | 31 minor |
| Complexity | 26 minor 16 critical 25 medium |
🟢 Metrics 226 duplication
Metric Results Duplication 226
NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.
|
Seems you are using me but didn't get OPENAI_API_KEY seted in Variables/Secrets for this repo. you could follow readme for more information |
|
View changes in DiffLens |
| transform={(s) => | ||
| formatHtml(s) | ||
| .split("\n") | ||
| .map((l) => (indent === "4" ? l.replace(/^( )/g, " ") : l)) |
There was a problem hiding this comment.
Spaces are hard to count. Use {2}.
| .map((l) => (indent === "4" ? l.replace(/^( )/g, " ") : l)) | |
| .map((l) => (indent === "4" ? l.replace(/^( {2})/g, " ") : l)) |
| const r = await hmacHash(`${parts[0]}.${parts[1]}`, secret, "SHA-256"); | ||
| const expected = r.base64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, ""); |
There was a problem hiding this comment.
Suggestion: Verification always computes HMAC-SHA256 without checking the JWT alg, so a token labeled RS256 or another algorithm can be reported as valid. [security]
Assessment: 🟠 Major · 🔁 Occurrence: Sometimes
Prompt for AI Agent 🤖
This is a comment left during a code review.
**Path:** artifacts/personal-tool-console/src/components/tools/crypto/crypto-tools.tsx
**Line:** 208:209
**Comment:**
*Security: Verification always computes HMAC-SHA256 without checking the JWT `alg`, so a token labeled RS256 or another algorithm can be reported as valid.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix| const res = await dnsLookup(host); | ||
| const out: Row[] = []; | ||
| for (const t of selected) { | ||
| const q = `https://cloudflare-dns.com/dns-query?name=${encodeURIComponent(host)}&type=${t}`; |
There was a problem hiding this comment.
Suggestion: Each lookup first performs A and AAAA queries through dnsLookup, then repeats them in the selected-type loop, causing duplicate requests and mismatched displayed latency. [performance]
Assessment: 🟠 Major · 🔁 Occurrence: Often
Prompt for AI Agent 🤖
This is a comment left during a code review.
**Path:** artifacts/personal-tool-console/src/components/tools/dns-lookup.tsx
**Line:** 46:49
**Comment:**
*Performance: Each lookup first performs A and AAAA queries through `dnsLookup`, then repeats them in the selected-type loop, causing duplicate requests and mismatched displayed latency.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix| const result = useMemo(() => { | ||
| if (!spec) return ""; | ||
| try { | ||
| return spec.run(input, opts); | ||
| } catch (e) { | ||
| return `Error: ${(e as Error).message}`; | ||
| } | ||
| }, [spec, input, opts]); |
There was a problem hiding this comment.
Suggestion: The result is recomputed on every input and option change, and nonempty input displays it before Run, contradicting the run-only behavior shown by the page. [logic error]
Assessment: 🟠 Major · 🔁 Occurrence: Often
Prompt for AI Agent 🤖
This is a comment left during a code review.
**Path:** artifacts/personal-tool-console/src/components/tools/text/text-tool-page.tsx
**Line:** 22:29
**Comment:**
*Logic Error: The result is recomputed on every input and option change, and nonempty input displays it before `Run`, contradicting the run-only behavior shown by the page.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix| let bytes = new TextEncoder().encode(raw); | ||
| const len = mode === "AES-GCM" ? 12 : 16; | ||
| if (bytes.length >= len) bytes = bytes.slice(0, len); | ||
| const out = new Uint8Array(len); | ||
| out.fill(0); | ||
| out.set(bytes); | ||
| return out; |
There was a problem hiding this comment.
Suggestion: The UI supplies a base64 IV, but this encodes that text as UTF-8, truncating or padding it instead of using the generated IV bytes. [api mismatch]
Assessment: 🟠 Major · 🔁 Occurrence: Often
Prompt for AI Agent 🤖
This is a comment left during a code review.
**Path:** artifacts/personal-tool-console/src/lib/tools/crypto.ts
**Line:** 38:44
**Comment:**
*Api Mismatch: The UI supplies a base64 IV, but this encodes that text as UTF-8, truncating or padding it instead of using the generated IV bytes.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix| const secondsToExpiry = exp ? Math.floor((exp - Date.now()) / 1000) : undefined; | ||
| return { | ||
| header, | ||
| payload, | ||
| signature: parts[2], | ||
| expiry: exp ? new Date(exp).toLocaleString() : undefined, |
There was a problem hiding this comment.
Suggestion: An expiration timestamp of zero is treated as missing, so JWTs with exp: 0 are not marked expired or displayed with an expiry time. [falsy zero check]
Assessment: 🟠 Major · 🔁 Occurrence: Sometimes
Prompt for AI Agent 🤖
This is a comment left during a code review.
**Path:** artifacts/personal-tool-console/src/lib/tools/crypto.ts
**Line:** 125:130
**Comment:**
*Falsy Zero Check: An expiration timestamp of zero is treated as missing, so JWTs with `exp: 0` are not marked expired or displayed with an expiry time.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix| const targetSet = targets === "" ? ["u", "g", "o"] : targets.split(""); | ||
| const value = perms.split("").reduce((acc, p) => acc + (p === "r" ? 4 : p === "w" ? 2 : 1), 0); |
There was a problem hiding this comment.
Suggestion: The symbolic target a is treated as owner only, so modes such as a+r fail to apply permissions to group and others. [logic error]
Assessment: 🟠 Major · 🔁 Occurrence: Sometimes
Prompt for AI Agent 🤖
This is a comment left during a code review.
**Path:** artifacts/personal-tool-console/src/lib/tools/linux.ts
**Line:** 36:37
**Comment:**
*Logic Error: The symbolic target `a` is treated as owner only, so modes such as `a+r` fail to apply permissions to group and others.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix| const idx = names.findIndex((n) => n === lower || n.startsWith(lower)); | ||
| if (idx >= 0) return idx; | ||
| } | ||
| return Number(v); |
There was a problem hiding this comment.
Suggestion: Named months are zero-based, but valid months start at one, so jan is discarded and every other month is shifted down. [off-by-one]
Assessment: 🟠 Major · 🔁 Occurrence: Sometimes
Prompt for AI Agent 🤖
This is a comment left during a code review.
**Path:** artifacts/personal-tool-console/src/lib/tools/linux.ts
**Line:** 132:135
**Comment:**
*Off By One: Named months are zero-based, but valid months start at one, so `jan` is discarded and every other month is shifted down.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix| const minuteField = useSeconds ? parts[2] : parts[0]; | ||
| const hourField = useSeconds ? parts[3] : parts[1]; | ||
| const dayField = useSeconds ? parts[4] : parts[2]; | ||
| const monthField = useSeconds ? parts[5] : parts[3]; | ||
| const weekdayField = useSeconds ? parts[5] : parts[4]; |
There was a problem hiding this comment.
Suggestion: Six-field cron expressions use the month field for both month and weekday, so weekday values are parsed incorrectly. [incorrect variable usage]
Assessment: 🟠 Major · 🔁 Occurrence: Rarely
Prompt for AI Agent 🤖
This is a comment left during a code review.
**Path:** artifacts/personal-tool-console/src/lib/tools/linux.ts
**Line:** 174:178
**Comment:**
*Incorrect Variable Usage: Six-field cron expressions use the month field for both `month` and `weekday`, so weekday values are parsed incorrectly.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix| s.pop(); | ||
| return s.join("/"); | ||
| } | ||
| return acc ? `${acc}/${part}` : part; |
There was a problem hiding this comment.
Suggestion: posixJoin("/a", "b", "c") returns a/b/c because the leading slash is discarded, producing a relative path instead of an absolute one. [api mismatch]
Assessment: 🟠 Major · 🔁 Occurrence: Often
Prompt for AI Agent 🤖
This is a comment left during a code review.
**Path:** artifacts/personal-tool-console/src/lib/tools/linux.ts
**Line:** 239:239
**Comment:**
*Api Mismatch: `posixJoin("/a", "b", "c")` returns `a/b/c` because the leading slash is discarded, producing a relative path instead of an absolute one.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix|
|
||
| export function posixBasename(p: string, ext?: string): string { | ||
| const idx = p.lastIndexOf("/"); | ||
| const base = idx === -1 ? p : p.slice(idx + 1); |
There was a problem hiding this comment.
Suggestion: A path ending in / produces an empty basename, so posixBasename("/var/log/") does not return the final directory name. [possible bug]
Assessment: 🟠 Major · 🔁 Occurrence: Sometimes
Prompt for AI Agent 🤖
This is a comment left during a code review.
**Path:** artifacts/personal-tool-console/src/lib/tools/linux.ts
**Line:** 252:252
**Comment:**
*Possible Bug: A path ending in `/` produces an empty basename, so `posixBasename("/var/log/")` does not return the final directory name.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix| } | ||
|
|
||
| function Md5Hash() { | ||
| return <TextTransformer chip="md5-hash" label="Input text" placeholder="hello" transform={md5} />; |
There was a problem hiding this comment.
Suggestion: The MD5 helper encodes JavaScript UTF-16 code units instead of UTF-8 bytes, so this tool returns nonstandard hashes for any non-ASCII input. [data type]
Assessment: 🟠 Major · 🔁 Occurrence: Often
Prompt for AI Agent 🤖
This is a comment left during a code review.
**Path:** artifacts/personal-tool-console/src/components/tools/coding-tools.tsx
**Line:** 256:256
**Comment:**
*Data Type: The MD5 helper encodes JavaScript UTF-16 code units instead of UTF-8 bytes, so this tool returns nonstandard hashes for any non-ASCII input.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix| const scopeRef = useRef(`pv-${Math.random().toString(36).slice(2, 8)}`); | ||
| const scoped = useMemo(() => scopeCss(css, scopeRef.current), [css]); | ||
| return ( | ||
| <div className={className}> | ||
| <style>{scoped}</style> |
There was a problem hiding this comment.
Suggestion: scopeCss prefixes selectors with pv-*, but this wrapper never receives that class, so every live preview's generated CSS is inactive. [logic error]
Assessment: 🟠 Major · 🔁 Occurrence: Often
Prompt for AI Agent 🤖
This is a comment left during a code review.
**Path:** artifacts/personal-tool-console/src/components/tools/css/css-generators.tsx
**Line:** 31:35
**Comment:**
*Logic Error: `scopeCss` prefixes selectors with `pv-*`, but this wrapper never receives that class, so every live preview's generated CSS is inactive.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix| const [border, setBorder] = useState("1"); | ||
| const [radius, setRadius] = useState(16); | ||
| const [color, setColor] = useState("rgba(255,255,255,0.25)"); | ||
| const result = useMemo(() => cssGlassmorphism(blur, opacity, border, radius, color), [blur, opacity, border, radius, color]); |
There was a problem hiding this comment.
Suggestion: The glassmorphism helper formats opacity as 0.${...}, so opacity 1 produces 0.10 and the generated CSS never represents full opacity. [logic error]
Assessment: 🟠 Major · 🔁 Occurrence: Often
Prompt for AI Agent 🤖
This is a comment left during a code review.
**Path:** artifacts/personal-tool-console/src/components/tools/css/css-generators.tsx
**Line:** 95:95
**Comment:**
*Logic Error: The glassmorphism helper formats opacity as `0.${...}`, so opacity `1` produces `0.10` and the generated CSS never represents full opacity.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix| <Field label="Gap (px)"><NumInput min={0} max={64} value={gap} onChange={(e) => setGap(e.target.value)} /></Field> | ||
| <Field label="Fixed width (px, optional)"><NumInput min={0} max={300} value={fixedPx} onChange={(e) => setFixedPx(e.target.value)} /></Field> | ||
| <Field label="Grid template areas (free text)" className="sm:col-span-2"> | ||
| <TextInput value={areas} onChange={(e) => setAreas(e.target.value)} placeholder={'header header header\ncontent content aside'} /> |
There was a problem hiding this comment.
Suggestion: TextInput cannot accept newline characters, so users cannot enter the multiline grid-template-areas value shown by this generator. [api mismatch]
Assessment: 🟠 Major · 🔁 Occurrence: Sometimes
Prompt for AI Agent 🤖
This is a comment left during a code review.
**Path:** artifacts/personal-tool-console/src/components/tools/css/css-generators.tsx
**Line:** 428:428
**Comment:**
*Api Mismatch: `TextInput` cannot accept newline characters, so users cannot enter the multiline grid-template-areas value shown by this generator.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix| const schedule = parseCronExpression(use); | ||
| return { | ||
| schedule, | ||
| next: cronNextTimes(use, 5), |
There was a problem hiding this comment.
Suggestion: Valid sparse cron schedules can have their next run more than 100,000 minutes away, causing the helper to return no results despite a future match. [possible bug]
Assessment: 🟠 Major · 🔁 Occurrence: Rarely
Prompt for AI Agent 🤖
This is a comment left during a code review.
**Path:** artifacts/personal-tool-console/src/components/tools/linux/linux-tools.tsx
**Line:** 220:220
**Comment:**
*Possible Bug: Valid sparse cron schedules can have their next run more than 100,000 minutes away, causing the helper to return no results despite a future match.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix| if (!r.valid) { setError(r.error ?? "Invalid input"); return; } | ||
| setResult({ svg: r.svg, width: r.width }); | ||
| } else { | ||
| const r = ean13(text); |
There was a problem hiding this comment.
Suggestion: ean13 builds the barcode with the check digit as the first pattern and omits guard bars, so generated EAN-13 SVGs are not valid EAN-13 barcodes. [api mismatch]
Assessment: 🟠 Major · 🔁 Occurrence: Often
Prompt for AI Agent 🤖
This is a comment left during a code review.
**Path:** artifacts/personal-tool-console/src/components/tools/misc/misc-tools.tsx
**Line:** 127:127
**Comment:**
*Api Mismatch: `ean13` builds the barcode with the check digit as the first pattern and omits guard bars, so generated EAN-13 SVGs are not valid EAN-13 barcodes.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix| drops[i]++; | ||
| } | ||
| } | ||
| if (playingRef.current) raf = requestAnimationFrame(frame); |
There was a problem hiding this comment.
Suggestion: When this animation is paused, the current frame schedules no next frame; changing playing only updates a ref, so pressing Play cannot resume it. [logic error]
Assessment: 🟠 Major · 🔁 Occurrence: Often
Prompt for AI Agent 🤖
This is a comment left during a code review.
**Path:** artifacts/personal-tool-console/src/components/tools/misc/misc-tools.tsx
**Line:** 223:223
**Comment:**
*Logic Error: When this animation is paused, the current frame schedules no next frame; changing `playing` only updates a ref, so pressing Play cannot resume it.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix|
View changes in DiffLens |
|
|
Overall Grade |
Security Reliability Complexity Hygiene |
Code Review Summary
| Analyzer | Status | Updated (UTC) | Details |
|---|---|---|---|
| Scala | Aug 30, 2026 7:20p.m. | Review ↗ | |
| Swift | Aug 30, 2026 7:20p.m. | Review ↗ | |
| JavaScript | Aug 30, 2026 7:20p.m. | Review ↗ | |
| Ruby | Aug 30, 2026 7:20p.m. | Review ↗ | |
| C & C++ | Aug 30, 2026 7:20p.m. | Review ↗ | |
| C# | Aug 30, 2026 7:20p.m. | Review ↗ | |
| Rust | Aug 30, 2026 7:20p.m. | Review ↗ | |
| Shell | Aug 30, 2026 7:20p.m. | Review ↗ | |
| Terraform | Aug 30, 2026 7:20p.m. | Review ↗ | |
| Code coverage | Aug 30, 2026 7:50p.m. | Review ↗ | |
| SQL | Aug 30, 2026 7:20p.m. | Review ↗ | |
| Secrets | Aug 30, 2026 7:20p.m. | Review ↗ | |
| Ansible | Aug 30, 2026 7:20p.m. | Review ↗ |
Important
AI Review is run only on demand for your team. We're only showing results of static analysis review right now. To trigger AI Review, comment @deepsourcebot review on this thread.
| const base = import.meta.env.BASE_URL.replace(/\/$/, ""); | ||
| navigate(base + url); |
There was a problem hiding this comment.
Suggestion: WouterRouter already applies BASE_URL, so prefixing it again sends navigation to a doubled base path on subpath deployments. [api mismatch]
Assessment: 🟠 Major · 🔁 Occurrence: Sometimes
Prompt for AI Agent 🤖
This is a comment left during a code review.
**Path:** artifacts/personal-tool-console/src/components/layout/command-palette.tsx
**Line:** 39:40
**Comment:**
*Api Mismatch: `WouterRouter` already applies `BASE_URL`, so prefixing it again sends navigation to a doubled base path on subpath deployments.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix| <span className="text-muted-foreground/60"> | ||
| Tools run locally in your browser — nothing is uploaded. | ||
| </span> |
There was a problem hiding this comment.
Suggestion: The privacy statement is false: the speed test posts payloads to /api/upload-test, and other tools send entered domains and URLs to external services. [docstring mismatch]
Assessment: 🟠 Major · 🔁 Occurrence: Sometimes
Prompt for AI Agent 🤖
This is a comment left during a code review.
**Path:** artifacts/personal-tool-console/src/components/layout/site-footer.tsx
**Line:** 23:25
**Comment:**
*Docstring Mismatch: The privacy statement is false: the speed test posts payloads to `/api/upload-test`, and other tools send entered domains and URLs to external services.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix| useMemo(() => { | ||
| if (!text) { | ||
| setHashes({ "SHA-1": "", "SHA-256": "", "SHA-384": "", "SHA-512": "" }); | ||
| return; | ||
| } |
There was a problem hiding this comment.
Suggestion: Empty input is a valid hash input, but this branch clears every digest, so users cannot hash or verify an empty string. [logic error]
Assessment: 🟠 Major · 🔁 Occurrence: Sometimes
Prompt for AI Agent 🤖
This is a comment left during a code review.
**Path:** artifacts/personal-tool-console/src/components/tools/hash.tsx
**Line:** 14:18
**Comment:**
*Logic Error: Empty input is a valid hash input, but this branch clears every digest, so users cannot hash or verify an empty string.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix| let cancelled = false; | ||
| (async () => { | ||
| const [sha1, sha256, sha384, sha512] = await Promise.all([ | ||
| hashWithAlgo(text, "SHA-1"), | ||
| hashWithAlgo(text, "SHA-256"), | ||
| hashWithAlgo(text, "SHA-384"), | ||
| hashWithAlgo(text, "SHA-512"), | ||
| ]); | ||
| if (!cancelled) setHashes({ "SHA-1": sha1, "SHA-256": sha256, "SHA-384": sha384, "SHA-512": sha512 }); | ||
| })(); | ||
| return () => { | ||
| cancelled = true; | ||
| }; |
There was a problem hiding this comment.
Suggestion: React ignores the cleanup returned by useMemo, so an older asynchronous digest can overwrite hashes for newer input. [race condition]
Assessment: 🟠 Major · 🔁 Occurrence: Sometimes
Prompt for AI Agent 🤖
This is a comment left during a code review.
**Path:** artifacts/personal-tool-console/src/components/tools/hash.tsx
**Line:** 19:31
**Comment:**
*Race Condition: React ignores the cleanup returned by `useMemo`, so an older asynchronous digest can overwrite hashes for newer input.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix| {error ? ( | ||
| <p className="text-red-400 text-sm">{error}</p> | ||
| ) : ( | ||
| transform() !== "" && <OutBox value={transform()} mono filename={mode === "Encode" ? "encoded.txt" : "decoded.txt"} /> | ||
| )} |
There was a problem hiding this comment.
Suggestion: After a malformed decode sets error, correcting the input never calls transform, so the stale error remains and valid output is hidden. [stale reference]
Assessment: 🟠 Major · 🔁 Occurrence: Sometimes
Prompt for AI Agent 🤖
This is a comment left during a code review.
**Path:** artifacts/personal-tool-console/src/components/tools/url-encoder.tsx
**Line:** 40:44
**Comment:**
*Stale Reference: After a malformed decode sets `error`, correcting the input never calls `transform`, so the stale error remains and valid output is hidden.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix| /> | ||
| {preview ? ( | ||
| <img | ||
| src={preview} |
| <div className="grid gap-4 lg:grid-cols-2"> | ||
| <div className="rounded-2xl border border-border bg-card/60 p-4"> | ||
| <img | ||
| src={previewUrl ?? ""} |
| <div className="max-w-sm overflow-hidden rounded-2xl border border-border bg-black/40"> | ||
| {image && ( | ||
| <img | ||
| src={image} |
| <div className="overflow-hidden rounded-2xl border border-border bg-black/40"> | ||
| {image && card === "summary_large_image" && ( | ||
| <img | ||
| src={image} |
| <div className="flex items-start gap-3 p-3"> | ||
| {image && card === "summary" && ( | ||
| <img | ||
| src={image} |
| </div> | ||
| <div className="flex gap-1"> | ||
| <a | ||
| href={u} |
| <div className="max-w-md overflow-hidden rounded-2xl border border-border bg-black/40"> | ||
| {image && ( | ||
| <img | ||
| src={image} |
| <div className="mx-auto mt-1 max-w-[240px] rounded-[2rem] border-4 border-border bg-black/60 p-3"> | ||
| <div className="mb-2 h-2 w-16 rounded-full bg-border/60 mx-auto" /> | ||
| {image && ( | ||
| <img src={image} alt="link" className="w-full object-cover" /> |
| // --- HTML / CSS / JS --- | ||
|
|
||
| export function minifyHtml(html: string): string { | ||
| const noComments = html.replace(/<!--[\s\S]*?-->/g, ""); |
|
|
|
||
| const handleFile = (f: File) => { | ||
| if (preview) URL.revokeObjectURL(preview); | ||
| setPreview(URL.createObjectURL(f)); |
There was a problem hiding this comment.
Suggestion: Each selected file creates an object URL, but the latest URL is never revoked when this component unmounts, leaking blob resources after repeated use. [resource leak]
Assessment: 🟠 Major · 🔁 Occurrence: Sometimes
Prompt for AI Agent 🤖
This is a comment left during a code review.
**Path:** artifacts/personal-tool-console/src/components/tools/image/image-tools.tsx
**Line:** 35:35
**Comment:**
*Resource Leak: Each selected file creates an object URL, but the latest URL is never revoked when this component unmounts, leaking blob resources after repeated use.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix| const i = await readImageFile(f); | ||
| setFile(f); | ||
| setImg(i); |
There was a problem hiding this comment.
Suggestion: If files are selected quickly, an older asynchronous load can finish later and overwrite the newer image, dimensions, and output state. [race condition]
Assessment: 🟠 Major · 🔁 Occurrence: Sometimes
Prompt for AI Agent 🤖
This is a comment left during a code review.
**Path:** artifacts/personal-tool-console/src/components/tools/image/image-tools.tsx
**Line:** 82:84
**Comment:**
*Race Condition: If files are selected quickly, an older asynchronous load can finish later and overwrite the newer image, dimensions, and output state.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix| if (title) lines.push(`<meta property="og:title" content="${title}" />`); | ||
| if (description) lines.push(`<meta property="og:description" content="${description}" />`); |
There was a problem hiding this comment.
Suggestion: Metadata values are inserted directly into HTML attributes, so quotes in a title or description produce malformed generated tags and can inject attributes into the output. [security]
Assessment: 🟠 Major · 🔁 Occurrence: Sometimes
Prompt for AI Agent 🤖
This is a comment left during a code review.
**Path:** artifacts/personal-tool-console/src/components/tools/social/social-tools.tsx
**Line:** 49:50
**Comment:**
*Security: Metadata values are inserted directly into HTML attributes, so quotes in a title or description produce malformed generated tags and can inject attributes into the output.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix| <Field label="Quote text"><TextArea value={text} onChange={(e) => setText(e.target.value)} /></Field> | ||
| <Field label="Author"><TextInput value={author} onChange={(e) => setAuthor(e.target.value)} /></Field> | ||
| <div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-3"> | ||
| <Field label="Style"><SelectInput value={style} onChange={(e) => setStyle(e.target.value)} options={["minimal", "quote-mark", "gradient", "retro frame"]} /></Field> |
There was a problem hiding this comment.
Suggestion: The select offers retro frame, but drawing checks for retro, so choosing that option never renders the retro frame style. [incorrect condition logic]
Assessment: 🟠 Major · 🔁 Occurrence: Sometimes
Prompt for AI Agent 🤖
This is a comment left during a code review.
**Path:** artifacts/personal-tool-console/src/components/tools/social/social-tools.tsx
**Line:** 479:479
**Comment:**
*Incorrect Condition Logic: The select offers `retro frame`, but drawing checks for `retro`, so choosing that option never renders the retro frame style.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix| if (!title) setTitle(c.title); if (!description) setDescription(c.description); if (!image) setImage(c.image); if (!siteName) setSiteName(c.siteName); | ||
| setLoading(false); return; | ||
| } | ||
| const res = await fetch("https://api.microlink.io/?url=" + encodeURIComponent(norm)); |
There was a problem hiding this comment.
Suggestion: The user-controlled URL is sent to Microlink, a server-side fetch proxy, allowing requests to private or internal addresses through that service. [ssrf]
Assessment: 🔴 Critical · 🔁 Occurrence: Sometimes
Prompt for AI Agent 🤖
This is a comment left during a code review.
**Path:** artifacts/personal-tool-console/src/components/tools/social/social-tools.tsx
**Line:** 681:681
**Comment:**
*Ssrf: The user-controlled URL is sent to Microlink, a server-side fetch proxy, allowing requests to private or internal addresses through that service.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix| let query = raw; | ||
| try { query = decodeURIComponent(raw); } catch { query = raw; } |
There was a problem hiding this comment.
Suggestion: URLSearchParams.get already decodes query values, so this second decode changes literal percent sequences in QR, hash, or base64 input. [logic error]
Assessment: 🟠 Major · 🔁 Occurrence: Sometimes
Prompt for AI Agent 🤖
This is a comment left during a code review.
**Path:** artifacts/personal-tool-console/src/pages/console.tsx
**Line:** 308:309
**Comment:**
*Logic Error: `URLSearchParams.get` already decodes query values, so this second decode changes literal percent sequences in QR, hash, or base64 input.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix| actions = ['configure speed endpoint']; | ||
| } else { | ||
| const parsedPw = parsePasswordCommand(normalized, prefs); | ||
| const parsedQr = !parsedPw ? parseQrCommand(normalized) : null; |
There was a problem hiding this comment.
Suggestion: Case-sensitive payloads are parsed from normalized, which lowercases them; QR URLs, hashes, and base64 encoding therefore produce different data than the user entered. [incorrect variable usage]
Assessment: 🟠 Major · 🔁 Occurrence: Often
Prompt for AI Agent 🤖
This is a comment left during a code review.
**Path:** artifacts/personal-tool-console/src/pages/console.tsx
**Line:** 349:349
**Comment:**
*Incorrect Variable Usage: Case-sensitive payloads are parsed from `normalized`, which lowercases them; QR URLs, hashes, and base64 encoding therefore produce different data than the user entered.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix| if (parsedPw) { | ||
| type = 'password'; | ||
| const pw = randomPassword(parsedPw.length, parsedPw.mode); | ||
| output = { password: pw, score: strengthScore(pw), mode: parsedPw.mode, length: parsedPw.length }; |
There was a problem hiding this comment.
Suggestion: Generated passwords are placed in history records, which are persisted to local storage, leaving plaintext credentials available to any same-origin script and retained after use. [security]
Assessment: 🔴 Critical · 🔁 Occurrence: Often
Prompt for AI Agent 🤖
This is a comment left during a code review.
**Path:** artifacts/personal-tool-console/src/pages/console.tsx
**Line:** 355:355
**Comment:**
*Security: Generated passwords are placed in history records, which are persisted to local storage, leaving plaintext credentials available to any same-origin script and retained after use.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix| setResult(record); | ||
| addHistory(record); | ||
| setStatus(`${domain} → ${ipv4[0] ?? ipv6[0] ?? 'NXDOMAIN'} (${responseMs} ms)`); |
There was a problem hiding this comment.
Suggestion: Overlapping DNS requests can complete out of order, allowing an older lookup to replace the newer result and display the wrong domain. [race condition]
Assessment: 🟠 Major · 🔁 Occurrence: Sometimes
Prompt for AI Agent 🤖
This is a comment left during a code review.
**Path:** artifacts/personal-tool-console/src/pages/console.tsx
**Line:** 629:631
**Comment:**
*Race Condition: Overlapping DNS requests can complete out of order, allowing an older lookup to replace the newer result and display the wrong domain.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix| if (e.key === 'Escape') { e.preventDefault(); setIsPaletteOpen(false); return; } | ||
| if (e.key === 'Enter') { | ||
| e.preventDefault(); | ||
| const n = normalize(input); | ||
| const dnsDomain = parseDnsCommand(n); | ||
| const hashText = parseHashCommand(n); | ||
| if (n === 'speed test' || n === 'speed') runSpeedTest(); | ||
| else if (dnsDomain) runDnsLookup(dnsDomain, input); | ||
| else if (hashText) runHash(hashText, input); | ||
| else executeCommand(input); | ||
| setIsPaletteOpen(false); |
There was a problem hiding this comment.
Suggestion: The input handler and window handler both process Enter, so one keypress executes commands twice, duplicating history and starting concurrent tests or lookups. [logic error]
Assessment: 🟠 Major · 🔁 Occurrence: Often
Prompt for AI Agent 🤖
This is a comment left during a code review.
**Path:** artifacts/personal-tool-console/src/pages/console.tsx
**Line:** 730:740
**Comment:**
*Logic Error: The input handler and window handler both process Enter, so one keypress executes commands twice, duplicating history and starting concurrent tests or lookups.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix
CodeAnt Nitpicks3 code suggestions1. The four-space formatter replaces only the first two-space prefix on each line, so nested HTML remains incorrectly indented at deeper levels.Logic error · 2. Palette schemes can repeat colors, making
|
There was a problem hiding this comment.
1 issue found across 78 files (changes from recent commits).
Confidence score: 3/5
- In
artifacts/personal-tool-console/src/components/tools/dns-lookup.tsx, each lookup fetches A and AAAA records throughdnsLookup(host)and then requests them again in the loop, adding unnecessary latency and request load; reuse the existing results or remove the duplicate requests.
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="artifacts/personal-tool-console/src/components/tools/dns-lookup.tsx">
<violation number="1" location="artifacts/personal-tool-console/src/components/tools/dns-lookup.tsx:68">
P2: Custom agent: **Flag AI Slop and Fabricated Changes**
Each lookup performs duplicate Cloudflare requests for A and AAAA: `dnsLookup(host)` already fetches those types, then this loop fetches them again while reimplementing response parsing. Consolidate the query and parsing logic in one helper that returns the selected record types and metadata.</violation>
</file>
Shadow auto-approve: would not auto-approve because issues were found.
Re-trigger cubic
| const out: Row[] = []; | ||
| for (const t of selected) { | ||
| const q = `https://cloudflare-dns.com/dns-query?name=${encodeURIComponent(host)}&type=${t}`; | ||
| const r = await fetch(q, { |
There was a problem hiding this comment.
P2: Custom agent: Flag AI Slop and Fabricated Changes
Each lookup performs duplicate Cloudflare requests for A and AAAA: dnsLookup(host) already fetches those types, then this loop fetches them again while reimplementing response parsing. Consolidate the query and parsing logic in one helper that returns the selected record types and metadata.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At artifacts/personal-tool-console/src/components/tools/dns-lookup.tsx, line 68:
<comment>Each lookup performs duplicate Cloudflare requests for A and AAAA: `dnsLookup(host)` already fetches those types, then this loop fetches them again while reimplementing response parsing. Consolidate the query and parsing logic in one helper that returns the selected record types and metadata.</comment>
<file context>
@@ -47,10 +65,21 @@ export default function DnsLookupPage({ tool }: ToolPageProps) {
const q = `https://cloudflare-dns.com/dns-query?name=${encodeURIComponent(host)}&type=${t}`;
- const r = await fetch(q, { headers: { Accept: "application/dns-json" } });
- const data = (await r.json()) as { Status: number; Answer?: { name: string; TTL: number; data: string; type: number }[] };
+ const r = await fetch(q, {
+ headers: { Accept: "application/dns-json" },
+ });
</file context>
| const base = import.meta.env.BASE_URL.replace(/\/$/, ""); | ||
| navigate(base + url); |
There was a problem hiding this comment.
wouter's <WouterRouter base="..."> in App.tsx already manages the base path for navigate(). Prepending base manually will cause double-prefixing (e.g. /subpath/subpath/tools/...) when the app is hosted on a base URL subpath.
| const base = import.meta.env.BASE_URL.replace(/\/$/, ""); | |
| navigate(base + url); | |
| navigate(url); |
| const scopeRef = useRef(`pv-${Math.random().toString(36).slice(2, 8)}`); | ||
| const scoped = useMemo(() => scopeCss(css, scopeRef.current), [css]); | ||
| return ( | ||
| <div className={className}> |
There was a problem hiding this comment.
scopeCss scopes all selectors to .${scopeRef.current}, but the generated scope class name is never added to the preview wrapper <div className={className}>. As a result, none of the generated CSS rules match any preview elements and all CSS previews render unstyled.
| <div className={className}> | |
| <div className={`${scopeRef.current} ${className ?? ""}`}> |
| useMemo(() => { | ||
| if (!text) { | ||
| setHashes({ "SHA-1": "", "SHA-256": "", "SHA-384": "", "SHA-512": "" }); | ||
| return; | ||
| } | ||
| let cancelled = false; | ||
| (async () => { | ||
| const [sha1, sha256, sha384, sha512] = await Promise.all([ | ||
| hashWithAlgo(text, "SHA-1"), | ||
| hashWithAlgo(text, "SHA-256"), | ||
| hashWithAlgo(text, "SHA-384"), | ||
| hashWithAlgo(text, "SHA-512"), | ||
| ]); | ||
| if (!cancelled) setHashes({ "SHA-1": sha1, "SHA-256": sha256, "SHA-384": sha384, "SHA-512": sha512 }); | ||
| })(); | ||
| return () => { | ||
| cancelled = true; | ||
| }; | ||
| }, [text]); |
There was a problem hiding this comment.
useMemo is intended for pure computations and does not execute cleanup functions. Using it for asynchronous side-effects (calling setHashes and returning a cleanup function) can cause state updates during render and potential race conditions. Use useEffect instead.
| useMemo(() => { | |
| if (!text) { | |
| setHashes({ "SHA-1": "", "SHA-256": "", "SHA-384": "", "SHA-512": "" }); | |
| return; | |
| } | |
| let cancelled = false; | |
| (async () => { | |
| const [sha1, sha256, sha384, sha512] = await Promise.all([ | |
| hashWithAlgo(text, "SHA-1"), | |
| hashWithAlgo(text, "SHA-256"), | |
| hashWithAlgo(text, "SHA-384"), | |
| hashWithAlgo(text, "SHA-512"), | |
| ]); | |
| if (!cancelled) setHashes({ "SHA-1": sha1, "SHA-256": sha256, "SHA-384": sha384, "SHA-512": sha512 }); | |
| })(); | |
| return () => { | |
| cancelled = true; | |
| }; | |
| }, [text]); | |
| useEffect(() => { | |
| if (!text) { | |
| setHashes({ "SHA-1": "", "SHA-256": "", "SHA-384": "", "SHA-512": "" }); | |
| return; | |
| } | |
| let cancelled = false; | |
| (async () => { | |
| const [sha1, sha256, sha384, sha512] = await Promise.all([ | |
| hashWithAlgo(text, "SHA-1"), | |
| hashWithAlgo(text, "SHA-256"), | |
| hashWithAlgo(text, "SHA-384"), | |
| hashWithAlgo(text, "SHA-512"), | |
| ]); | |
| if (!cancelled) setHashes({ "SHA-1": sha1, "SHA-256": sha256, "SHA-384": sha384, "SHA-512": sha512 }); | |
| })(); | |
| return () => { | |
| cancelled = true; | |
| }; | |
| }, [text]); |
Pull Request Review SummaryOverall, this PR introduces a comprehensive suite of client-side utility tools and routing components. Several actionable issues were identified and commented on inline:
🤖 Reviewed by codereviewbot.ai - Catch bugs before your team does. |
There was a problem hiding this comment.
5 issues found and verified against the latest diff
Confidence score: 2/5
artifacts/personal-tool-console/src/lib/tools/crypto.tsencodes the displayed base64 IV as literal text, causing AES output to use a different IV and preventing interoperability with standard AES; decode the base64 IV before encryption or decryption.- The XML-to-JSON conversion in
artifacts/personal-tool-console/src/lib/tools/xml.tscan lose repeated empty elements and CDATA content, causing silent data corruption; detect existing properties by ownership and preserve CDATA as text. artifacts/personal-tool-console/src/lib/tools/xml.tstreats any valid element namedparsererroras a parse failure, rejecting otherwise valid XML; identify parser-generated error documents or namespaces instead.- XML minification in
artifacts/personal-tool-console/src/lib/tools/xml.tscan alter mixed-content text by removing meaningful whitespace; remove only formatting-only nodes or preserve whitespace in mixed-content elements.
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="artifacts/personal-tool-console/src/lib/tools/crypto.ts">
<violation number="1" location="artifacts/personal-tool-console/src/lib/tools/crypto.ts:43">
P1: When the UI-generated base64 IV is passed here, `TextEncoder` encodes the base64 characters instead of decoding them, so AES uses a different IV than the displayed 12/16 bytes and cannot interoperate with standard AES implementations. Decode the base64 input and reject values whose decoded length is not the mode’s required IV length.</violation>
</file>
<file name="artifacts/personal-tool-console/src/lib/tools/xml.ts">
<violation number="1" location="artifacts/personal-tool-console/src/lib/tools/xml.ts:5">
P2: Valid XML containing an element named `parsererror` is reported as invalid. Detect the parser's error document or namespace rather than any matching element.</violation>
<violation number="2" location="artifacts/personal-tool-console/src/lib/tools/xml.ts:59">
P2: Minifying mixed-content XML currently changes its text content. Remove only whitespace-only nodes known to be formatting, or preserve whitespace in mixed-content elements.</violation>
<violation number="3" location="artifacts/personal-tool-console/src/lib/tools/xml.ts:99">
P2: XML-to-JSON conversion drops CDATA text. Treat CDATA sections as text when collecting element content.</violation>
<violation number="4" location="artifacts/personal-tool-console/src/lib/tools/xml.ts:117">
P1: Repeated empty elements are lost during XML-to-JSON conversion because duplicate detection uses value truthiness. Test whether the object owns `child.tag` before deciding whether to create an array.</violation>
</file>
Shadow auto-approve: would not auto-approve because issues were found.
Re-trigger cubic
| let bytes = new TextEncoder().encode(raw); | ||
| const len = mode === "AES-GCM" ? 12 : 16; | ||
| if (bytes.length >= len) bytes = bytes.slice(0, len); | ||
| const out = new Uint8Array(len); | ||
| out.fill(0); | ||
| out.set(bytes); | ||
| return out; | ||
| } |
There was a problem hiding this comment.
P1: When the UI-generated base64 IV is passed here, TextEncoder encodes the base64 characters instead of decoding them, so AES uses a different IV than the displayed 12/16 bytes and cannot interoperate with standard AES implementations. Decode the base64 input and reject values whose decoded length is not the mode’s required IV length.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At artifacts/personal-tool-console/src/lib/tools/crypto.ts, line 38:
<comment>When the UI-generated base64 IV is passed here, `TextEncoder` encodes the base64 characters instead of decoding them, so AES uses a different IV than the displayed 12/16 bytes and cannot interoperate with standard AES implementations. Decode the base64 input and reject values whose decoded length is not the mode’s required IV length.</comment>
<file context>
@@ -0,0 +1,143 @@
+
+function deriveIv(mode: AesMode, ivInput: string): Uint8Array<ArrayBuffer> {
+ const raw = ivInput || "";
+ let bytes = new TextEncoder().encode(raw);
+ const len = mode === "AES-GCM" ? 12 : 16;
+ if (bytes.length >= len) bytes = bytes.slice(0, len);
</file context>
| let bytes = new TextEncoder().encode(raw); | |
| const len = mode === "AES-GCM" ? 12 : 16; | |
| if (bytes.length >= len) bytes = bytes.slice(0, len); | |
| const out = new Uint8Array(len); | |
| out.fill(0); | |
| out.set(bytes); | |
| return out; | |
| } | |
| const len = mode === "AES-GCM" ? 12 : 16; | |
| const bytes = toBuf(base64ToBytes(raw)); | |
| if (bytes.length !== len) throw new Error(`IV must be exactly ${len} bytes`); | |
| return bytes; |
| if (Object.keys(n.attributes).length > 0) Object.assign(obj, makeAttrs(n)); | ||
| for (const child of n.children) { | ||
| const value = serialize(child); | ||
| if (obj[child.tag]) { |
There was a problem hiding this comment.
P1: Repeated empty elements are lost during XML-to-JSON conversion because duplicate detection uses value truthiness. Test whether the object owns child.tag before deciding whether to create an array.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At artifacts/personal-tool-console/src/lib/tools/xml.ts, line 112:
<comment>Repeated empty elements are lost during XML-to-JSON conversion because duplicate detection uses value truthiness. Test whether the object owns `child.tag` before deciding whether to create an array.</comment>
<file context>
@@ -0,0 +1,158 @@
+ if (Object.keys(n.attributes).length > 0) Object.assign(obj, makeAttrs(n));
+ for (const child of n.children) {
+ const value = serialize(child);
+ if (obj[child.tag]) {
+ obj[child.tag] = Array.isArray(obj[child.tag]) ? [...(obj[child.tag] as unknown[]), value] : [obj[child.tag], value];
+ } else {
</file context>
| if (obj[child.tag]) { | |
| if (Object.prototype.hasOwnProperty.call(obj, child.tag)) { |
|
|
||
| export function parseXml(xml: string): Document { | ||
| const doc = new DOMParser().parseFromString(xml, "application/xml"); | ||
| const parseError = doc.querySelector("parsererror"); |
There was a problem hiding this comment.
P2: Valid XML containing an element named parsererror is reported as invalid. Detect the parser's error document or namespace rather than any matching element.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At artifacts/personal-tool-console/src/lib/tools/xml.ts, line 5:
<comment>Valid XML containing an element named `parsererror` is reported as invalid. Detect the parser's error document or namespace rather than any matching element.</comment>
<file context>
@@ -0,0 +1,158 @@
+
+export function parseXml(xml: string): Document {
+ const doc = new DOMParser().parseFromString(xml, "application/xml");
+ const parseError = doc.querySelector("parsererror");
+ if (parseError) {
+ const message = parseError.textContent ?? "Invalid XML";
</file context>
| for (const n of Array.from(el.childNodes)) { | ||
| if (n.nodeType === Node.ELEMENT_NODE) | ||
| children.push(elementToObject(n as Element)); | ||
| else if (n.nodeType === Node.TEXT_NODE) text += n.textContent ?? ""; |
There was a problem hiding this comment.
P2: XML-to-JSON conversion drops CDATA text. Treat CDATA sections as text when collecting element content.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At artifacts/personal-tool-console/src/lib/tools/xml.ts, line 94:
<comment>XML-to-JSON conversion drops CDATA text. Treat CDATA sections as text when collecting element content.</comment>
<file context>
@@ -0,0 +1,158 @@
+ let text = "";
+ for (const n of Array.from(el.childNodes)) {
+ if (n.nodeType === Node.ELEMENT_NODE) children.push(elementToObject(n as Element));
+ else if (n.nodeType === Node.TEXT_NODE) text += n.textContent ?? "";
+ }
+ return { tag: el.tagName, attributes, children, text: text.trim() };
</file context>
| else if (n.nodeType === Node.TEXT_NODE) text += n.textContent ?? ""; | |
| else if (n.nodeType === Node.TEXT_NODE || n.nodeType === Node.CDATA_SECTION_NODE) text += n.textContent ?? ""; |
| }); | ||
| } | ||
| const serializer = new XMLSerializer(); | ||
| return serializer.serializeToString(doc).replace(/>\s+</g, "><").trim(); |
There was a problem hiding this comment.
P2: Minifying mixed-content XML currently changes its text content. Remove only whitespace-only nodes known to be formatting, or preserve whitespace in mixed-content elements.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At artifacts/personal-tool-console/src/lib/tools/xml.ts, line 56:
<comment>Minifying mixed-content XML currently changes its text content. Remove only whitespace-only nodes known to be formatting, or preserve whitespace in mixed-content elements.</comment>
<file context>
@@ -0,0 +1,158 @@
+ });
+ }
+ const serializer = new XMLSerializer();
+ return serializer.serializeToString(doc).replace(/>\s+</g, "><").trim();
+}
+
</file context>
| useMemo(() => { | ||
| if (!text) { | ||
| setHashes({ "SHA-1": "", "SHA-256": "", "SHA-384": "", "SHA-512": "" }); | ||
| return; | ||
| } | ||
| let cancelled = false; | ||
| (async () => { | ||
| const [sha1, sha256, sha384, sha512] = await Promise.all([ | ||
| hashWithAlgo(text, "SHA-1"), | ||
| hashWithAlgo(text, "SHA-256"), | ||
| hashWithAlgo(text, "SHA-384"), | ||
| hashWithAlgo(text, "SHA-512"), | ||
| ]); | ||
| if (!cancelled) | ||
| setHashes({ | ||
| "SHA-1": sha1, | ||
| "SHA-256": sha256, | ||
| "SHA-384": sha384, | ||
| "SHA-512": sha512, | ||
| }); | ||
| })(); | ||
| return () => { | ||
| cancelled = true; | ||
| }; | ||
| }, [text]); |
There was a problem hiding this comment.
useMemo must be pure and should not trigger side effects or return cleanup functions (which React ignores for useMemo). Because the async hash computation and cancellation cleanup are side effects, this should be a useEffect.
| useMemo(() => { | |
| if (!text) { | |
| setHashes({ "SHA-1": "", "SHA-256": "", "SHA-384": "", "SHA-512": "" }); | |
| return; | |
| } | |
| let cancelled = false; | |
| (async () => { | |
| const [sha1, sha256, sha384, sha512] = await Promise.all([ | |
| hashWithAlgo(text, "SHA-1"), | |
| hashWithAlgo(text, "SHA-256"), | |
| hashWithAlgo(text, "SHA-384"), | |
| hashWithAlgo(text, "SHA-512"), | |
| ]); | |
| if (!cancelled) | |
| setHashes({ | |
| "SHA-1": sha1, | |
| "SHA-256": sha256, | |
| "SHA-384": sha384, | |
| "SHA-512": sha512, | |
| }); | |
| })(); | |
| return () => { | |
| cancelled = true; | |
| }; | |
| }, [text]); | |
| useEffect(() => { | |
| if (!text) { | |
| setHashes({ "SHA-1": "", "SHA-256": "", "SHA-384": "", "SHA-512": "" }); | |
| return; | |
| } | |
| let cancelled = false; | |
| (async () => { | |
| const [sha1, sha256, sha384, sha512] = await Promise.all([ | |
| hashWithAlgo(text, "SHA-1"), | |
| hashWithAlgo(text, "SHA-256"), | |
| hashWithAlgo(text, "SHA-384"), | |
| hashWithAlgo(text, "SHA-512"), | |
| ]); | |
| if (!cancelled) | |
| setHashes({ | |
| "SHA-1": sha1, | |
| "SHA-256": sha256, | |
| "SHA-384": sha384, | |
| "SHA-512": sha512, | |
| }); | |
| })(); | |
| return () => { | |
| cancelled = true; | |
| }; | |
| }, [text]); |
| return ( | ||
| <div className={className}> | ||
| <style>{scoped}</style> | ||
| {children} | ||
| </div> | ||
| ); |
There was a problem hiding this comment.
scopeCss transforms selector rules to match under .${scope} (e.g. .${scopeRef.current} .gradient), but scopeRef.current is not included in the wrapper div's className. Because the scoping class is missing from the container, none of the generated CSS rules match and the live preview elements will not receive their styles.
| return ( | |
| <div className={className}> | |
| <style>{scoped}</style> | |
| {children} | |
| </div> | |
| ); | |
| return ( | |
| <div className={className ? `${className} ${scopeRef.current}` : scopeRef.current}> | |
| <style>{scoped}</style> | |
| {children} | |
| </div> | |
| ); |
| let d = `M ${pts[0].x.toFixed(2)} ${pts[0].y.toFixed(2)}`; | ||
| for (let i = 0; i < points; i++) { | ||
| const cur = pts[i]; | ||
| const next = pts[(i + 1) % points]; | ||
| const mid = { x: (cur.x + next.x) / 2, y: (cur.y + next.y) / 2 }; | ||
| d += ` Q ${cur.x.toFixed(2)} ${cur.y.toFixed(2)} ${mid.x.toFixed(2)} ${mid.y.toFixed(2)}`; | ||
| } | ||
| d += " Z"; | ||
| return d; |
There was a problem hiding this comment.
Starting the SVG path at pts[0] causes the first segment (Q pts[0] ...) to collapse into a straight line and leaves a sharp discontinuity when closing the path with Z. To create a continuous, smooth blob, the path should start at the midpoint between the last point and the first point:
| let d = `M ${pts[0].x.toFixed(2)} ${pts[0].y.toFixed(2)}`; | |
| for (let i = 0; i < points; i++) { | |
| const cur = pts[i]; | |
| const next = pts[(i + 1) % points]; | |
| const mid = { x: (cur.x + next.x) / 2, y: (cur.y + next.y) / 2 }; | |
| d += ` Q ${cur.x.toFixed(2)} ${cur.y.toFixed(2)} ${mid.x.toFixed(2)} ${mid.y.toFixed(2)}`; | |
| } | |
| d += " Z"; | |
| return d; | |
| const firstMid = { | |
| x: (pts[points - 1].x + pts[0].x) / 2, | |
| y: (pts[points - 1].y + pts[0].y) / 2, | |
| }; | |
| let d = `M ${firstMid.x.toFixed(2)} ${firstMid.y.toFixed(2)}`; | |
| for (let i = 0; i < points; i++) { | |
| const cur = pts[i]; | |
| const next = pts[(i + 1) % points]; | |
| const mid = { x: (cur.x + next.x) / 2, y: (cur.y + next.y) / 2 }; | |
| d += ` Q ${cur.x.toFixed(2)} ${cur.y.toFixed(2)} ${mid.x.toFixed(2)} ${mid.y.toFixed(2)}`; | |
| } | |
| d += " Z"; | |
| return d; |
| const res = await dnsLookup(host); | ||
| const out: Row[] = []; | ||
| for (const t of selected) { | ||
| const q = `https://cloudflare-dns.com/dns-query?name=${encodeURIComponent(host)}&type=${t}`; | ||
| const r = await fetch(q, { | ||
| headers: { Accept: "application/dns-json" }, | ||
| }); | ||
| const data = (await r.json()) as { | ||
| Status: number; | ||
| Answer?: { name: string; TTL: number; data: string; type: number }[]; | ||
| }; | ||
| for (const rec of data.Answer ?? []) { | ||
| if (rec.type === TYPE_IDS[t]) | ||
| out.push({ | ||
| type: t, | ||
| name: rec.name, | ||
| ttl: rec.TTL, | ||
| value: rec.data, | ||
| }); | ||
| } | ||
| } | ||
| setRows(out); | ||
| setMeta({ status: res.status, responseMs: res.responseMs }); |
There was a problem hiding this comment.
dnsLookup(host) already executes DNS queries for A and AAAA records, yet its results are discarded here and replaced by a sequential for (const t of selected) loop that refetches each type one by one. This causes redundant network calls and high latency. Consider running the fetches in parallel using Promise.all across selected directly:
| const res = await dnsLookup(host); | |
| const out: Row[] = []; | |
| for (const t of selected) { | |
| const q = `https://cloudflare-dns.com/dns-query?name=${encodeURIComponent(host)}&type=${t}`; | |
| const r = await fetch(q, { | |
| headers: { Accept: "application/dns-json" }, | |
| }); | |
| const data = (await r.json()) as { | |
| Status: number; | |
| Answer?: { name: string; TTL: number; data: string; type: number }[]; | |
| }; | |
| for (const rec of data.Answer ?? []) { | |
| if (rec.type === TYPE_IDS[t]) | |
| out.push({ | |
| type: t, | |
| name: rec.name, | |
| ttl: rec.TTL, | |
| value: rec.data, | |
| }); | |
| } | |
| } | |
| setRows(out); | |
| setMeta({ status: res.status, responseMs: res.responseMs }); | |
| const t0 = performance.now(); | |
| const responses = await Promise.all( | |
| selected.map(async (t) => { | |
| const q = `https://cloudflare-dns.com/dns-query?name=${encodeURIComponent(host)}&type=${t}`; | |
| const r = await fetch(q, { | |
| headers: { Accept: "application/dns-json" }, | |
| }); | |
| const data = (await r.json()) as { | |
| Status: number; | |
| Answer?: { name: string; TTL: number; data: string; type: number }[]; | |
| }; | |
| return { type: t, data }; | |
| }), | |
| ); | |
| const responseMs = Math.round(performance.now() - t0); | |
| const out: Row[] = []; | |
| let allOk = true; | |
| for (const { type, data } of responses) { | |
| if (data.Status !== 0) allOk = false; | |
| for (const rec of data.Answer ?? []) { | |
| if (rec.type === TYPE_IDS[type]) { | |
| out.push({ | |
| type, | |
| name: rec.name, | |
| ttl: rec.TTL, | |
| value: rec.data, | |
| }); | |
| } | |
| } | |
| } | |
| setRows(out); | |
| setMeta({ | |
| status: allOk ? "resolved" : "partial / error", | |
| responseMs, | |
| }); |




User description
Summary by cubic
Replaces the placeholder Personal Tool Console with Toolbox, a catalog of 300+ browser-based utilities that run entirely client-side — no sign-up or uploads.
New Features
Ctrl/Cmd+K).Written for commit b369abe. Summary will update on new commits.
CodeAnt-AI Description
Expand the website into an in-browser toolbox with command-based utilities
What Changed
Impact
✅ One place for everyday developer and content tools✅ Faster text, image, encoding, and conversion tasks✅ Downloadable results without leaving the browser💡 Usage Guide
Checking Your Pull Request
Every time you make a pull request, our system automatically looks through it. We check for security issues, mistakes in how you're setting up your infrastructure, and common code problems. We do this to make sure your changes are solid and won't cause any trouble later.
Talking to CodeAnt AI
Got a question or need a hand with something in your pull request? You can easily get in touch with CodeAnt AI right here. Just type the following in a comment on your pull request, and replace "Your question here" with whatever you want to ask:
This lets you have a chat with CodeAnt AI about your pull request, making it easier to understand and improve your code.
Example
Preserve Org Learnings with CodeAnt
You can record team preferences so CodeAnt AI applies them in future reviews. Reply directly to the specific CodeAnt AI suggestion (in the same thread) and replace "Your feedback here" with your input:
This helps CodeAnt AI learn and adapt to your team's coding style and standards.
Example
Retrigger review
Ask CodeAnt AI to review the PR again, by typing:
Check Your Repository Health
To analyze the health of your code repository, visit our dashboard at https://app.codeant.ai. This tool helps you identify potential issues and areas for improvement in your codebase, ensuring your repository maintains high standards of code health.