Skip to content

Beta - #109

Merged
LCSOGthb merged 3 commits into
mainfrom
beta
Sep 1, 2026
Merged

Beta#109
LCSOGthb merged 3 commits into
mainfrom
beta

Conversation

@LCSOGthb

@LCSOGthb LCSOGthb commented Aug 30, 2026

Copy link
Copy Markdown
Owner

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

  • Adds a tool registry with lazy-loaded components, per-category grouping, search, and a command palette (Ctrl/Cmd+K).
  • Introduces dedicated pages for the catalog, console, and individual tools, with recent-tool tracking.
  • Updates meta tags and replaces the 404 page with one that matches the new design.

Written for commit b369abe. Summary will update on new commits.

Review in cubic


CodeAnt-AI Description

Expand the website into an in-browser toolbox with command-based utilities

What Changed

  • Added a searchable catalog of browser-based tools for text, coding, crypto, images, social media, Linux, colors, encoding, and more
  • Added a command console for calculations, conversions, password generation, QR codes, timestamps, hashing, Base64, DNS lookups, and speed tests
  • Added text utilities for formatting, analysis, generation, encoding, case and font changes, regex work, and content cleanup
  • Added image and social tools with live previews, filtering, metadata generation, thumbnail lookup, mockups, and downloadable PNG/SVG results
  • Added developer utilities for JSON, XML, CSS, UUIDs, cryptography, UTF-8, permissions, cron expressions, paths, colors, barcodes, and test data
  • Added command suggestions, recent history, pinned shortcuts, copy/download actions, and locally stored preferences

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:

@codeant-ai ask: Your question here

This lets you have a chat with CodeAnt AI about your pull request, making it easier to understand and improve your code.

Example

@codeant-ai ask: Can you suggest a safer alternative to storing this secret?

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:

@codeant-ai: Your feedback here

This helps CodeAnt AI learn and adapt to your team's coding style and standards.

Example

@codeant-ai: Do not flag unused imports.

Retrigger review

Ask CodeAnt AI to review the PR again, by typing:

@codeant-ai: review

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.

Signed-off-by: LCSOGthb <185141600+LCSOGthb@users.noreply.github.com>
Signed-off-by: LCSOGthb <185141600+LCSOGthb@users.noreply.github.com>
@codesherlock-ai

Copy link
Copy Markdown

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

@cr-gpt

cr-gpt Bot commented Aug 30, 2026

Copy link
Copy Markdown

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

@semanticdiff-com

semanticdiff-com Bot commented Aug 30, 2026

Copy link
Copy Markdown

Review changes with  SemanticDiff

Changed Files
File Status
  artifacts/personal-tool-console/index.html  73% smaller
  artifacts/personal-tool-console/src/pages/not-found.tsx  19% smaller
  artifacts/personal-tool-console/src/App.tsx  7% smaller
  pnpm-lock.yaml  1% smaller
  artifacts/personal-tool-console/src/components/layout/app-shell.tsx  0% smaller
  artifacts/personal-tool-console/src/components/layout/command-palette.tsx  0% smaller
  artifacts/personal-tool-console/src/components/layout/site-footer.tsx  0% smaller
  artifacts/personal-tool-console/src/components/layout/site-header.tsx  0% smaller
  artifacts/personal-tool-console/src/components/layout/tool-page-layout.tsx  0% smaller
  artifacts/personal-tool-console/src/components/tools/base64.tsx  0% smaller
  artifacts/personal-tool-console/src/components/tools/bitmap/bitmap-tools.tsx  0% smaller
  artifacts/personal-tool-console/src/components/tools/calculator.tsx  0% smaller
  artifacts/personal-tool-console/src/components/tools/code-to-image.tsx  0% smaller
  artifacts/personal-tool-console/src/components/tools/coding-tools.tsx  0% smaller
  artifacts/personal-tool-console/src/components/tools/color/color-tools.tsx  0% smaller
  artifacts/personal-tool-console/src/components/tools/crypto/crypto-tools.tsx  0% smaller
  artifacts/personal-tool-console/src/components/tools/css/css-generators.tsx  0% smaller
  artifacts/personal-tool-console/src/components/tools/currency-converter.tsx  0% smaller
  artifacts/personal-tool-console/src/components/tools/dns-lookup.tsx  0% smaller
  artifacts/personal-tool-console/src/components/tools/hash.tsx  0% smaller
  artifacts/personal-tool-console/src/components/tools/image/image-tools.tsx  0% smaller
  artifacts/personal-tool-console/src/components/tools/json-formatter.tsx  0% smaller
  artifacts/personal-tool-console/src/components/tools/json-tree-viewer.tsx  0% smaller
  artifacts/personal-tool-console/src/components/tools/linux/linux-tools.tsx  0% smaller
  artifacts/personal-tool-console/src/components/tools/misc/misc-tools.tsx  0% smaller
  artifacts/personal-tool-console/src/components/tools/password-generator.tsx  0% smaller
  artifacts/personal-tool-console/src/components/tools/qr-generator.tsx  0% smaller
  artifacts/personal-tool-console/src/components/tools/rn-shadow.tsx  0% smaller
  artifacts/personal-tool-console/src/components/tools/set/set-tools.tsx  0% smaller
  artifacts/personal-tool-console/src/components/tools/shared/coming-soon.tsx  0% smaller
  artifacts/personal-tool-console/src/components/tools/shared/fields.tsx  0% smaller
  artifacts/personal-tool-console/src/components/tools/social/social-tools.tsx  0% smaller
  artifacts/personal-tool-console/src/components/tools/speed-test.tsx  0% smaller
  artifacts/personal-tool-console/src/components/tools/text/text-tool-page.tsx  0% smaller
  artifacts/personal-tool-console/src/components/tools/timestamp.tsx  0% smaller
  artifacts/personal-tool-console/src/components/tools/unit-converter.tsx  0% smaller
  artifacts/personal-tool-console/src/components/tools/url-encoder.tsx  0% smaller
  artifacts/personal-tool-console/src/components/tools/utf8/utf8-tools.tsx  0% smaller
  artifacts/personal-tool-console/src/components/tools/uuid-generator.tsx  0% smaller
  artifacts/personal-tool-console/src/components/tools/xml/xml-tools.tsx  0% smaller
  artifacts/personal-tool-console/src/hooks/use-page-title.ts  0% smaller
  artifacts/personal-tool-console/src/lib/copy.ts  0% smaller
  artifacts/personal-tool-console/src/lib/format.ts  0% smaller
  artifacts/personal-tool-console/src/lib/registry/core-tools.ts  0% smaller
  artifacts/personal-tool-console/src/lib/registry/css-tools.ts  0% smaller
  artifacts/personal-tool-console/src/lib/registry/dev-tools.ts  0% smaller
  artifacts/personal-tool-console/src/lib/registry/lazy.ts  0% smaller
  artifacts/personal-tool-console/src/lib/registry/media-tools.ts  0% smaller
  artifacts/personal-tool-console/src/lib/registry/text.ts  0% smaller
  artifacts/personal-tool-console/src/lib/storage.ts  0% smaller
  artifacts/personal-tool-console/src/lib/tool-registry.ts  0% smaller
  artifacts/personal-tool-console/src/lib/tools/base64.ts  0% smaller
  artifacts/personal-tool-console/src/lib/tools/bitmap/index.ts  0% smaller
  artifacts/personal-tool-console/src/lib/tools/calculator.ts  0% smaller
  artifacts/personal-tool-console/src/lib/tools/coding.ts  0% smaller
  artifacts/personal-tool-console/src/lib/tools/color.ts  0% smaller
  artifacts/personal-tool-console/src/lib/tools/crypto.ts  0% smaller
  artifacts/personal-tool-console/src/lib/tools/css-gen.ts  0% smaller
  artifacts/personal-tool-console/src/lib/tools/currency-converter.ts  0% smaller
  artifacts/personal-tool-console/src/lib/tools/dns.ts  0% smaller
  artifacts/personal-tool-console/src/lib/tools/hash.ts  0% smaller
  artifacts/personal-tool-console/src/lib/tools/linux.ts  0% smaller
  artifacts/personal-tool-console/src/lib/tools/misc.ts  0% smaller
  artifacts/personal-tool-console/src/lib/tools/password.ts  0% smaller
  artifacts/personal-tool-console/src/lib/tools/set/index.ts  0% smaller
  artifacts/personal-tool-console/src/lib/tools/speed-test.ts  0% smaller
  artifacts/personal-tool-console/src/lib/tools/text/existing.ts  0% smaller
  artifacts/personal-tool-console/src/lib/tools/text/helpers.ts  0% smaller
  artifacts/personal-tool-console/src/lib/tools/text/index.ts  0% smaller
  artifacts/personal-tool-console/src/lib/tools/text/part1.ts  0% smaller
  artifacts/personal-tool-console/src/lib/tools/text/part2.ts  0% smaller
  artifacts/personal-tool-console/src/lib/tools/text/types.ts  0% smaller
  artifacts/personal-tool-console/src/lib/tools/timestamp.ts  0% smaller
  artifacts/personal-tool-console/src/lib/tools/unit-converter.ts  0% smaller
  artifacts/personal-tool-console/src/lib/tools/utf8.ts  0% smaller
  artifacts/personal-tool-console/src/lib/tools/xml.ts  0% smaller
  artifacts/personal-tool-console/src/pages/catalog.tsx  0% smaller
  artifacts/personal-tool-console/src/pages/console.tsx  0% smaller
  artifacts/personal-tool-console/src/pages/tool-page.tsx  0% smaller

Comment thread artifacts/personal-tool-console/src/lib/tools/coding.ts Fixed
name: "Extract Text from HTML",
description: "Strip HTML tags and decode common entities with regex only.",
run: (input) => {
let out = input.replace(/<[^>]*>/g, "");
Comment on lines +895 to +896
out = out
.replace(/&amp;/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");
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Aug 30, 2026

Copy link
Copy Markdown
Contributor

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Updated (UTC)
❌ Deployment failed
View logs
tools b369abe Aug 30 2026, 07:20 PM

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Sorry @LCSOGthb, your pull request is larger than the review limit of 150,000 diff characters

@codereviewbot-ai

codereviewbot-ai Bot commented Aug 30, 2026

Copy link
Copy Markdown

Summary of Changes & PR Review

Overall, 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:

  1. CSS Generator Preview Scoping (css-generators.tsx): The scope class generated by useRef is applied to <style> selectors but missing from the preview wrapper element <div>, causing all generator previews to render without styles.
  2. Side Effect Hook Misuse (hash.tsx): useMemo is used to trigger asynchronous hash calculation and returns a cleanup function; this should be useEffect.
  3. Double Base Routing in Command Palette (command-palette.tsx): navigate(base + url) manually prepends BASE_URL even though wouter's root <WouterRouter base="..."> already prefixes base paths.

🤖 Reviewed by codereviewbot.ai - Catch bugs before your team does.

@vercel

vercel Bot commented Aug 30, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
tools Ready Ready Preview Aug 30, 2026 7:20pm

@codeant-ai

codeant-ai Bot commented Aug 30, 2026

Copy link
Copy Markdown

🤖 CodeAnt AI — Review Status

Status Commit Started (UTC) Finished (UTC)
✅ Reviewed your PR e3bac34 Aug 30, 2026 · 19:18 19:22

@codeant-ai

codeant-ai Bot commented Aug 30, 2026

Copy link
Copy Markdown

Thanks for using CodeAnt! 🎉

We're free for open-source projects. if you're enjoying it, help us grow by sharing.

Share on X ·
Reddit ·
LinkedIn

@coderabbitai

coderabbitai Bot commented Aug 30, 2026

Copy link
Copy Markdown

Review Change Stack

Important

Approval pending

CodeRabbit 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.

  • 🔍 Trigger review
✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch beta
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch 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.

❤️ Share

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

@github-actions

Copy link
Copy Markdown

Dependency Review

✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.

Scanned Files

None

@github-advanced-security github-advanced-security AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

devskim found more than 20 potential problems in the proposed changes. Check the Files changed tab for more details.

@difflens

difflens Bot commented Aug 30, 2026

Copy link
Copy Markdown

View changes in DiffLens

@guardrails

guardrails Bot commented Aug 30, 2026

Copy link
Copy Markdown

⚠️ We detected 4 security issues in this pull request:

Hard-Coded Secrets (1)
Severity Details Docs
Medium Title: Secret Keyword
📚

More info on how to fix Hard-Coded Secrets in General.


Insecure Processing of Data (3)
Severity Details Docs
Medium Title: Unescaped user input in React dangerouslySetInnerHTML
📚
Medium Title: Unescaped user input in React dangerouslySetInnerHTML
📚
Medium Title: Unescaped user input in React dangerouslySetInnerHTML
<div dangerouslySetInnerHTML={{ __html: result.svg }} />
📚

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.

@github-advanced-security github-advanced-security AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

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 = "";

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'pending' is never reassigned. Use 'const' instead.

Suggested change
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")}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Spaces are hard to count. Use {2}.

Suggested change
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) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'raw' is never reassigned. Use 'const' instead.

Suggested change
for (let raw of tokens) {
for (const raw of tokens) {

@codeant-ai codeant-ai Bot added the size:XXL This PR changes 1000+ lines, ignoring generated files label Aug 30, 2026
@difflens

difflens Bot commented Aug 30, 2026

Copy link
Copy Markdown

View changes in DiffLens

@qltysh

qltysh Bot commented Aug 30, 2026

Copy link
Copy Markdown

100 new issues

Tool Category Rule Count
qlty Structure Function with high complexity (count = 19): CalculatorPage 43
qlty Duplication Found 15 lines of similar code in 2 locations (mass = 89) 26
qlty Structure Function with many returns (count = 12): CodingTools 16
qlty Structure High total complexity (count = 94) 12
qlty Structure Deeply nested control flow (level = 5) 2
qlty Duplication Found 42 lines of identical code in 2 locations (mass = 127) 1

</GhostButton>
</div>
</div>
);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Function with high complexity (count = 19): CalculatorPage [qlty:function-complexity]

case "md5-hash": return <Md5Hash />;
default: return <div className="text-sm text-muted-foreground">Unknown tool</div>;
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

High total complexity (count = 94) [qlty:file-complexity]

i++;
}

return out.join("");

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Function with high complexity (count = 77): formatJsCode [qlty:function-complexity]

Comment thread artifacts/personal-tool-console/src/components/tools/coding-tools.tsx Outdated
case "js-minifier": return <JsMinifier />;
case "md5-hash": return <Md5Hash />;
default: return <div className="text-sm text-muted-foreground">Unknown tool</div>;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Function with many returns (count = 12): CodingTools [qlty:return-statements]

i++;
}
out = result.join("").replace(/[ \t]+/g, " ").replace(/\n\s*\n+/g, "\n").trim();
return out;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Function with high complexity (count = 39): minifyJs [qlty:function-complexity]

Comment thread artifacts/personal-tool-console/src/lib/tools/color.ts
Comment thread artifacts/personal-tool-console/src/lib/tools/linux.ts
result = (result & ~clear) | masked;
}
}
return result.toString(8).padStart(3, "0");

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Function with high complexity (count = 34): chmodSymbolicToOctal [qlty:function-complexity]

Comment thread artifacts/personal-tool-console/src/lib/tools/linux.ts Outdated
@difflens

difflens Bot commented Aug 30, 2026

Copy link
Copy Markdown

View changes in DiffLens

@codacy-production

codacy-production Bot commented Aug 30, 2026

Copy link
Copy Markdown

Not up to standards ⛔

🔴 Issues 16 critical · 1 high · 26 medium · 57 minor

Alerts:
⚠ 100 issues (≤ 0 issues of at least minor severity)

Results:
100 new issues

Category Results
BestPractice 1 medium
1 high
CodeStyle 31 minor
Complexity 26 minor
16 critical
25 medium

View in Codacy

🟢 Metrics 226 duplication

Metric Results
Duplication 226

View in Codacy

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.

…, Rustfmt, Scalafmt, StandardJS, StandardRB and swift-format

This commit fixes the style issues introduced in e3bac34 according to the output
from ClangFormat, dotnet-format, Prettier, RuboCop, Rustfmt, Scalafmt,
StandardJS, StandardRB and swift-format.

Details: #109
@cr-gpt

cr-gpt Bot commented Aug 30, 2026

Copy link
Copy Markdown

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

codescene-delta-analysis[bot]

This comment was marked as outdated.

@difflens

difflens Bot commented Aug 30, 2026

Copy link
Copy Markdown

View changes in DiffLens

transform={(s) =>
formatHtml(s)
.split("\n")
.map((l) => (indent === "4" ? l.replace(/^( )/g, " ") : l))

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Spaces are hard to count. Use {2}.

Suggested change
.map((l) => (indent === "4" ? l.replace(/^( )/g, " ") : l))
.map((l) => (indent === "4" ? l.replace(/^( {2})/g, " ") : l))

Comment on lines +208 to +209
const r = await hmacHash(`${parts[0]}.${parts[1]}`, secret, "SHA-256");
const expected = r.base64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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

Use CodeAnt Skill Fix in Cursor Fix in VSCode Claude

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
👍 | 👎

Comment on lines +46 to +49
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}`;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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

Use CodeAnt Skill Fix in Cursor Fix in VSCode Claude

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
👍 | 👎

Comment on lines +22 to +29
const result = useMemo(() => {
if (!spec) return "";
try {
return spec.run(input, opts);
} catch (e) {
return `Error: ${(e as Error).message}`;
}
}, [spec, input, opts]);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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

Use CodeAnt Skill Fix in Cursor Fix in VSCode Claude

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
👍 | 👎

Comment on lines +38 to +44
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;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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

Use CodeAnt Skill Fix in Cursor Fix in VSCode Claude

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
👍 | 👎

Comment on lines +125 to +130
const secondsToExpiry = exp ? Math.floor((exp - Date.now()) / 1000) : undefined;
return {
header,
payload,
signature: parts[2],
expiry: exp ? new Date(exp).toLocaleString() : undefined,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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

Use CodeAnt Skill Fix in Cursor Fix in VSCode Claude

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
👍 | 👎

Comment on lines +36 to +37
const targetSet = targets === "" ? ["u", "g", "o"] : targets.split("");
const value = perms.split("").reduce((acc, p) => acc + (p === "r" ? 4 : p === "w" ? 2 : 1), 0);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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

Use CodeAnt Skill Fix in Cursor Fix in VSCode Claude

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
👍 | 👎

Comment on lines +132 to +135
const idx = names.findIndex((n) => n === lower || n.startsWith(lower));
if (idx >= 0) return idx;
}
return Number(v);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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

Use CodeAnt Skill Fix in Cursor Fix in VSCode Claude

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
👍 | 👎

Comment on lines +174 to +178
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];

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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

Use CodeAnt Skill Fix in Cursor Fix in VSCode Claude

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;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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

Use CodeAnt Skill Fix in Cursor Fix in VSCode Claude

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);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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

Use CodeAnt Skill Fix in Cursor Fix in VSCode Claude

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} />;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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

Use CodeAnt Skill Fix in Cursor Fix in VSCode Claude

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
👍 | 👎

Comment on lines +31 to +35
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>

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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

Use CodeAnt Skill Fix in Cursor Fix in VSCode Claude

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]);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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

Use CodeAnt Skill Fix in Cursor Fix in VSCode Claude

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'} />

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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

Use CodeAnt Skill Fix in Cursor Fix in VSCode Claude

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),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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

Use CodeAnt Skill Fix in Cursor Fix in VSCode Claude

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);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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

Use CodeAnt Skill Fix in Cursor Fix in VSCode Claude

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);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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

Use CodeAnt Skill Fix in Cursor Fix in VSCode Claude

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
👍 | 👎

@difflens

difflens Bot commented Aug 30, 2026

Copy link
Copy Markdown

View changes in DiffLens

@deepsource-io

deepsource-io Bot commented Aug 30, 2026

Copy link
Copy Markdown
Contributor

DeepSource Code Review

We reviewed changes in 28cad60...b369abe on this pull request. Below is the summary for the review, and you can see the individual issues we found as inline review comments.

See full review on DeepSource ↗

PR Report Card

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.

Comment on lines +39 to +40
const base = import.meta.env.BASE_URL.replace(/\/$/, "");
navigate(base + url);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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

Use CodeAnt Skill Fix in Cursor Fix in VSCode Claude

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
👍 | 👎

Comment on lines +23 to +25
<span className="text-muted-foreground/60">
Tools run locally in your browser — nothing is uploaded.
</span>

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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

Use CodeAnt Skill Fix in Cursor Fix in VSCode Claude

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
👍 | 👎

Comment on lines +14 to +18
useMemo(() => {
if (!text) {
setHashes({ "SHA-1": "", "SHA-256": "", "SHA-384": "", "SHA-512": "" });
return;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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

Use CodeAnt Skill Fix in Cursor Fix in VSCode Claude

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
👍 | 👎

Comment on lines +19 to +31
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;
};

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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

Use CodeAnt Skill Fix in Cursor Fix in VSCode Claude

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
👍 | 👎

Comment on lines +40 to +44
{error ? (
<p className="text-red-400 text-sm">{error}</p>
) : (
transform() !== "" && <OutBox value={transform()} mono filename={mode === "Encode" ? "encoded.txt" : "decoded.txt"} />
)}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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

Use CodeAnt Skill Fix in Cursor Fix in VSCode Claude

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, "");
@sonarqubecloud

Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
0.0% Coverage on New Code (required ≥ 80%)
7.6% Duplication on New Code (required ≤ 3%)
D Security Rating on New Code (required ≥ A)
D Reliability Rating on New Code (required ≥ A)

See analysis details on SonarQube Cloud

Catch issues before they fail your Quality Gate with our IDE extension SonarQube for IDE


const handleFile = (f: File) => {
if (preview) URL.revokeObjectURL(preview);
setPreview(URL.createObjectURL(f));

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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

Use CodeAnt Skill Fix in Cursor Fix in VSCode Claude

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
👍 | 👎

Comment on lines +82 to +84
const i = await readImageFile(f);
setFile(f);
setImg(i);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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

Use CodeAnt Skill Fix in Cursor Fix in VSCode Claude

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
👍 | 👎

Comment on lines +49 to +50
if (title) lines.push(`<meta property="og:title" content="${title}" />`);
if (description) lines.push(`<meta property="og:description" content="${description}" />`);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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

Use CodeAnt Skill Fix in Cursor Fix in VSCode Claude

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>

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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

Use CodeAnt Skill Fix in Cursor Fix in VSCode Claude

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));

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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

Use CodeAnt Skill Fix in Cursor Fix in VSCode Claude

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
👍 | 👎

Comment on lines +308 to +309
let query = raw;
try { query = decodeURIComponent(raw); } catch { query = raw; }

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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

Use CodeAnt Skill Fix in Cursor Fix in VSCode Claude

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;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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

Use CodeAnt Skill Fix in Cursor Fix in VSCode Claude

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 };

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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

Use CodeAnt Skill Fix in Cursor Fix in VSCode Claude

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
👍 | 👎

Comment on lines +629 to +631
setResult(record);
addHistory(record);
setStatus(`${domain} → ${ipv4[0] ?? ipv6[0] ?? 'NXDOMAIN'} (${responseMs} ms)`);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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

Use CodeAnt Skill Fix in Cursor Fix in VSCode Claude

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
👍 | 👎

Comment on lines +730 to +740
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);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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

Use CodeAnt Skill Fix in Cursor Fix in VSCode Claude

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-ai

codeant-ai Bot commented Aug 30, 2026

Copy link
Copy Markdown

CodeAnt Nitpicks

3 code suggestions

1. 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 · artifacts/personal-tool-console/src/components/tools/coding-tools.tsx:226


2. Palette schemes can repeat colors, making key={c} duplicate keys and causing React to reuse or mis-render palette entries.

Missing react key · artifacts/personal-tool-console/src/components/tools/color/color-tools.tsx:89


3. colorB starts as transparent, which is invalid for an HTML color input, so the controlled picker cannot represent its initial state correctly.

Api mismatch · artifacts/personal-tool-console/src/components/tools/image/image-tools.tsx:534

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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 through dnsLookup(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, {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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>

Comment on lines +39 to +40
const base = import.meta.env.BASE_URL.replace(/\/$/, "");
navigate(base + url);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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.

Suggested change
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}>

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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.

Suggested change
<div className={className}>
<div className={`${scopeRef.current} ${className ?? ""}`}>

Comment on lines +14 to +32
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]);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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.

Suggested change
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]);

@codereviewbot-ai

codereviewbot-ai Bot commented Aug 30, 2026

Copy link
Copy Markdown

Pull Request Review Summary

Overall, this PR introduces a comprehensive suite of client-side utility tools and routing components. Several actionable issues were identified and commented on inline:

  1. hash.tsx: useMemo was used to perform asynchronous hashing and return a cancellation cleanup callback. useMemo does not run cleanup functions and should not contain side effects; this should be changed to useEffect.
  2. css-generators.tsx: Scoped styles prefix CSS rules with a dynamic class generated in scopeRef.current, but the class name was omitted from the preview container div, causing styles not to apply to live preview elements.
  3. image-tools.tsx: In SvgBlobGenerator (buildBlobPath), starting the path at pts[0] created a straight tangent segment and a sharp seam upon closing the path with Z. Starting from the midpoint between the last and first points ensures a smooth closed curve.
  4. dns-lookup.tsx: Redundant A/AAAA requests were fired before iterating sequentially through record types; parallelizing queries via Promise.all avoids duplicate fetches and reduces lookup latency.

🤖 Reviewed by codereviewbot.ai - Catch bugs before your team does.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

5 issues found and verified against the latest diff

Confidence score: 2/5

  • artifacts/personal-tool-console/src/lib/tools/crypto.ts encodes 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.ts can 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.ts treats any valid element named parsererror as 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.ts can 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

Comment on lines +43 to +50
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;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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>
Suggested change
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]) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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>
Suggested change
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");

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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 ?? "";

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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>
Suggested change
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();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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>

Comment on lines +24 to +48
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]);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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.

Suggested change
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]);

Comment on lines +66 to +71
return (
<div className={className}>
<style>{scoped}</style>
{children}
</div>
);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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.

Suggested change
return (
<div className={className}>
<style>{scoped}</style>
{children}
</div>
);
return (
<div className={className ? `${className} ${scopeRef.current}` : scopeRef.current}>
<style>{scoped}</style>
{children}
</div>
);

Comment on lines +686 to +694
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;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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:

Suggested change
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;

Comment on lines +64 to +86
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 });

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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:

Suggested change
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,
});

@LCSOGthb
LCSOGthb merged commit 110a8a2 into main Sep 1, 2026
78 of 151 checks passed
@LCSOGthb
LCSOGthb deleted the beta branch September 1, 2026 11:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/XXL size:XXL This PR changes 1000+ lines, ignoring generated files

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants