Skip to content

feat(monorepo): Turborepo build-pipeline foundation — @gt/core (approach 2 of 3)#191

Open
genesiscz wants to merge 2 commits into
masterfrom
feat/monorepo-2
Open

feat(monorepo): Turborepo build-pipeline foundation — @gt/core (approach 2 of 3)#191
genesiscz wants to merge 2 commits into
masterfrom
feat/monorepo-2

Conversation

@genesiscz

@genesiscz genesiscz commented May 31, 2026

Copy link
Copy Markdown
Owner

Monorepo foundation — Approach 2: Build-pipeline (Turborepo + Bun workspaces)

One of three competing monorepo designs (feat/monorepo-1 / -2 / -3). Each was independently designed, implemented, and verified by a separate agent. Pick one; close the other two. This is the build-pipeline / caching option.

What it does

  • Introduces Turborepo (turbo@2.7.3, pinned) over Bun workspaces, with a turbo.json dependsOn graph for build / typecheck / lint / test.
  • Packages use source-first exports maps (conditions bun → types → default): bun/types resolve to source .ts so Bun runs and tsgo typechecks without a build step (no-build invariant intact); default → dist is additive (CI artifact / isolated typecheck / future publish), never on the ./tools run path.
  • Extracts the acyclic leaf spine into @gt/core (packages/core/): array, date, format, json, math, object, paths, paths.client, string, Stopwatch. Each old src/utils/<f>.ts becomes a pure re-export shim.
  • Migrates 6 representative tools (json, npm-package-diff, files-to-prompt, last-changes, timer, usage).

Green bar (independently verified)

  • whole-repo tsgo --noEmit = 0 errors (== master baseline; proven meaningful via an injected-then-reverted type error)
  • turbo run typecheck --filter=@gt/core green, with a full cache hit on rerun (904ms → 62ms)
  • 13 core tests pass; ./tools + migrated tools + the shim path smoke-run; biome clean

Deferred (documented in MONOREPO-SPEC.md §6 / MONOREPO-PLAN.md)

  • Break the cli ↔ logger ↔ prompts cycle (invert the prompts → @app/doctor leak), then extract @gt/logger + @gt/cli
  • Extract @gt/storage, @gt/ui (666-import @ui/* surface), @gt/ai
  • Cutover (codemod + delete shims); promote hot tool clusters to apps/*; CI wiring + turbo remote cache

Trade-offs vs the other two

Best CI speed, incremental builds, local/remote caching, scales to many packages. More tooling than approach 1 (minimal) and less architectural enforcement than approach 3 (domain-driven boundaries).

Full design on the branch: MONOREPO-SPEC.md + MONOREPO-PLAN.md.

Note: cold bun install hits the same pre-existing puppeteer postinstall failure (environmental, not branch-caused); PUPPETEER_SKIP_DOWNLOAD=1 bun install is clean.

🤖 Generated via a multi-agent design→implement→verify workflow.

Summary by CodeRabbit

  • Chores
    • Established monorepo structure with Turborepo and Bun workspaces for improved code organization.
    • Extracted shared utility functions into a dedicated core package with documented public interfaces.
    • Migrated multiple tools to import from the new shared package structure.
    • Added comprehensive monorepo architecture and migration plan documentation.

@coderabbitai

coderabbitai Bot commented May 31, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

This pull request establishes a monorepo foundation by extracting 10 shared utility modules from src/utils/* into a new @gt/core package, setting up Turborepo and Bun workspaces, creating re-export shims for backward compatibility, and migrating six representative tools to use the new package structure.

Changes

Foundation Monorepo Setup

Layer / File(s) Summary
Architecture plan and specification
MONOREPO-PLAN.md, MONOREPO-SPEC.md
Detailed documentation of the monorepo strategy, baseline verification workflow, foundation milestone scope, representative tool migrations, follow-up phases for extracting additional packages, and trade-offs of the build-pipeline approach using Turborepo and Bun workspaces.
Workspace and build tool configuration
.gitignore, package.json, turbo.json
Adds Turborepo-specific ignore rules, configures Bun as the package manager with workspaces targeting packages/*, pins Turborepo 2.7.3, and defines task dependencies (typecheck, build, lint, test) with cache outputs and CI environment forwarding.
@gt/core package setup and utility modules
packages/core/package.json, packages/core/tsconfig.json, packages/core/src/*
Creates the @gt/core private ES module package with subpath exports pointing to src/* for Bun/types and dist/* for runtime defaults. Extracts 10 utility modules: Stopwatch class (lap/reset timing), date utilities (formatDateTime, parseDate, range/period helpers), format utilities (duration, relative time, byte/cost/token/list formatting), JSON SafeJSON facade, math cosineDistance, object isObject/deepMerge, path utilities (tilde expansion, temp dirs, POSIX normalization), path.client display helpers, and string utilities (slugify, ANSI stripping, shell/HTML escaping, fuzzy matching).
Re-export shims and tool import updates
src/utils/*, src/*/index.ts, src/utils/search/stores/vector-store.ts
Replaces all src/utils/* implementations with single re-export statements (export * from "@gt/core/*"), removing original logic (~2,000 lines), and updates imports in six representative tools (files-to-prompt, json, last-changes, npm-package-diff, timer, usage) plus vector-store to import directly from @gt/core instead of the old shim paths, establishing the import migration pattern.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • genesiscz/GenesisTools#118: Both PRs touch the shared formatDateTime date-utility surface; PR #118 modifies the implementation in src/utils/date.ts while this PR extracts it into @gt/core/date and replaces the old file with re-exports.
  • genesiscz/GenesisTools#137: Retrieved PR adds home-directory collapsing (collapsePath()) to src/utils/paths.ts, directly overlapping with this PR's replacement of that module's entire implementation via re-export from @gt/core/paths.
  • genesiscz/GenesisTools#123: Both PRs modify path and string utilities (including Windows-aware escapeShellArg and separator handling), with PR #123 making compatibility changes to the same implementations this PR extracts and re-exports from @gt/core.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 79.71% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title clearly and accurately describes the main change: implementing a Turborepo-based monorepo foundation with @gt/core extraction (approach 2 of 3).
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/monorepo-2

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

@socket-security

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot 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.

Code Review

This pull request establishes a Turborepo and Bun workspaces monorepo structure by extracting ten leaf utility modules into a new @gt/core package and shimming their original paths. Additionally, six tools were updated to import directly from @gt/core. The review feedback identifies critical pathing and dependency issues: the PROJECT_ROOT resolution in paths.ts must be adjusted to go three levels up, date-locale.ts needs to be relocated to @gt/core to prevent runtime import failures in date.ts, and tsup should be declared in the package's devDependencies to support the build script.

/**
* Absolute path to the GenesisTools project root (where package.json lives).
*/
export const PROJECT_ROOT = resolve(import.meta.dirname, "../..");

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.

high

The PROJECT_ROOT constant is resolved using ../.. relative to import.meta.dirname (which is packages/core/src). This resolves to packages/ instead of the actual monorepo root. Since the file was moved from src/utils/paths.ts to packages/core/src/paths.ts, it is now three levels down from the root and requires ../../.. to resolve correctly.

Suggested change
export const PROJECT_ROOT = resolve(import.meta.dirname, "../..");
export const PROJECT_ROOT = resolve(import.meta.dirname, "../../..");
References
  1. Centralize shared configuration values and directory paths into a single source of truth (e.g., a dedicated paths.ts utility) to eliminate duplication and ensure consistency across multiple modules.

Comment thread packages/core/src/date.ts

if (!_resolveLocale) {
// Lazy require so Vite won't bundle node:child_process into client code.
_resolveLocale = (require("./date-locale") as { getSystemLocale: () => string }).getSystemLocale;

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.

high

The file date-locale.ts was not moved to packages/core/src/, which will cause this require("./date-locale") call to fail with a MODULE_NOT_FOUND error at runtime. Consider moving date-locale.ts to packages/core/src/ to resolve this.

References
  1. The GenesisTools project is designed to be Bun-only; portability to other runtimes is not a design goal.

Comment on lines +23 to +25
"dependencies": {
"comment-json": "^4.6.2"
}

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.

medium

The build script in packages/core uses tsup, but tsup is not declared in the package's devDependencies (or the root package.json). As noted in the migration plan (MONOREPO-PLAN.md), tsup should be added to this package's devDependencies to ensure the build script can run successfully in isolation.

    "dependencies": {
        "comment-json": "^4.6.2"
    },
    "devDependencies": {
        "tsup": "^8.0.2"
    }

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 9

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@MONOREPO-PLAN.md`:
- Around line 91-99: The tool/migration table lists the wrong packages (it
includes collect-files-for-ai and git-last-commits-diff) which conflicts with
the executed list (last-changes and usage); update the table rows so the tools
column matches the executed set by replacing the collect-files-for-ai row with
last-changes and the git-last-commits-diff row with usage, and adjust their
Exercises/Migration cells accordingly (preserve the same migration pattern:
switch `@app/utils/`* imports to `@gt/core/`* where applicable, and keep any barrel
imports unchanged like the npm-package-diff note). Ensure the table now exactly
matches the earlier “executed” list so the plan is consistent and reproducible.

In `@MONOREPO-SPEC.md`:
- Around line 83-100: The fenced dependency-graph block in MONOREPO-SPEC.md is
missing a language tag (MD040); update the opening triple-backtick for the ASCII
diagram to include a tag such as "text" (i.e., change ``` to ```text) so the
diagram (the block containing `@gt/core`, `@gt/logger`, `@gt/storage`, `@gt/ui`, `@gt/ai`,
`@gt/cli` and apps/*) is lint-clean while leaving the ASCII content unchanged.

In `@packages/core/src/date.ts`:
- Around line 22-28: The lazy-load of the locale in resolveLocale() uses
require("./date-locale") which points to a missing file and breaks in Node ESM;
update resolveLocale/_resolveLocale to load the actual module
(src/utils/date-locale.ts) via a Node-ESM-safe mechanism (either use
createRequire(import.meta.url) to require the compiled dist/date-locale or use
dynamic import() to load the source module) and call its getSystemLocale; ensure
the symbol names (_resolveLocale, resolveLocale, formatDateTime,
getSystemLocale) are used to locate the change and also update tsup build inputs
so date-locale is included in the package build.

In `@packages/core/src/math.ts`:
- Around line 9-18: The function cosineDistance currently iterates up to
a.length without validating b, which can produce NaN or incorrect results;
update cosineDistance(a: Float32Array, b: Float32Array) to first verify the
lengths match (e.g., if (a.length !== b.length) throw an Error or return a
defined sentinel) and early-return/throw when they differ, then proceed with the
existing dot/norm calculation using the validated arrays so out-of-bounds
accesses cannot occur.

In `@packages/core/src/object.ts`:
- Around line 16-25: The deepMerge implementation should only iterate own
enumerable keys and only recurse into plain objects: replace the for...in loop
with iteration over Object.keys(source) and ensure the isObject predicate only
returns true for plain objects (e.g., Object.prototype.toString === '[object
Object]' and Object.getPrototypeOf(obj) === Object.prototype or null) so Dates,
Maps, class instances, etc. are treated as non-plain; when either source[key] or
result[key] is not a plain object, assign/overwrite rather than recursing. Also
ensure keys like "__proto__" or other prototype mutators are not able to change
the target prototype by relying on own-key iteration and plain-object checks in
deepMerge and isObject.

In `@packages/core/src/paths.client.ts`:
- Around line 31-67: splitPathSegments currently drops the original path "root
kind" (relative vs POSIX absolute vs Windows drive), and joinPathSegments always
emits POSIX-absolute "/" for non-tilde roots, breaking common-prefix logic (see
splitPathSegments and joinPathSegments and use in shortenPathWithPrefix). Fix by
preserving the root as an explicit first segment or token when splitting: detect
and store a root kind for inputs that start with "/" (use "/" root), that start
with a Windows drive like /^[A-Za-z]:/ (store the "C:"-style root token), and
leave no root token for relative paths; keep "~" handling as-is. Then update
joinPathSegments to reconstruct the path based on that root token: return "~" or
"~/<...>" for tilde, return "/" + joined segments for POSIX root, return
"<Drive>/" + joined segments for Windows drive tokens, and return a plain joined
path (no leading slash) for relative roots. Ensure shortenPathWithPrefix and any
callers still compare prefixes using the preserved root token when
computing/commonizing prefixes.

In `@packages/core/src/string.ts`:
- Around line 122-124: The matchGlob function currently builds a RegExp from the
pattern and replaces '*' with '.*', which is vulnerable to catastrophic
backtracking; replace that with a linear, case-insensitive '*' wildcard matcher
inside matchGlob: treat '*' as "match any string" by splitting the pattern on
'*' into literal segments, lower-case both pattern and value once, handle edge
cases for leading/trailing '*' (must match prefix/suffix when absent), and
iterate using indexOf to find each segment in order (advancing the search index)
to ensure segments appear sequentially; also handle exact-match when pattern
contains no '*' and return true for a pattern consisting only of '*' or empty
segments accordingly.

In `@src/json/index.ts`:
- Line 6: The file imports SafeJSON from the wrong module; change the import so
SafeJSON is imported from the canonical re-export path by replacing the current
import of SafeJSON from "`@gt/core/json`" with an import from "`@app/utils/json`"
(update the import statement in src/json/index.ts that references SafeJSON
accordingly) to comply with the guideline and use the project's shim.

In `@src/npm-package-diff/index.ts`:
- Line 10: Replace the non-canonical import of SafeJSON in
src/npm-package-diff/index.ts: change the import source from "`@gt/core/json`" to
the canonical shim "`@app/utils/json`" so the file imports SafeJSON from the
project re-export (keeping the same imported symbol name SafeJSON); update the
import statement that currently references SafeJSON to use "`@app/utils/json`" to
comply with the coding guideline.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 5dde5796-2dbe-406a-a797-ceae00107704

📥 Commits

Reviewing files that changed from the base of the PR and between 581f71f and f7615dd.

⛔ Files ignored due to path filters (1)
  • bun.lock is excluded by !**/*.lock
📒 Files selected for processing (36)
  • .gitignore
  • MONOREPO-PLAN.md
  • MONOREPO-SPEC.md
  • package.json
  • packages/core/package.json
  • packages/core/src/Stopwatch.ts
  • packages/core/src/array.ts
  • packages/core/src/date.ts
  • packages/core/src/format.ts
  • packages/core/src/json.ts
  • packages/core/src/math.test.ts
  • packages/core/src/math.ts
  • packages/core/src/object.ts
  • packages/core/src/paths.client.test.ts
  • packages/core/src/paths.client.ts
  • packages/core/src/paths.ts
  • packages/core/src/string.ts
  • packages/core/tsconfig.json
  • src/files-to-prompt/index.ts
  • src/json/index.ts
  • src/last-changes/index.ts
  • src/npm-package-diff/index.ts
  • src/timer/index.ts
  • src/usage/index.ts
  • src/utils/Stopwatch.ts
  • src/utils/array.ts
  • src/utils/date.ts
  • src/utils/format.ts
  • src/utils/json.ts
  • src/utils/math.ts
  • src/utils/object.ts
  • src/utils/paths.client.ts
  • src/utils/paths.ts
  • src/utils/search/stores/vector-store.ts
  • src/utils/string.ts
  • turbo.json
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: test (ubuntu-latest, 4)
🧰 Additional context used
📓 Path-based instructions (6)
src/**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

src/**/*.ts: Always import and use SafeJSON from @app/utils/json instead of the global JSON object; use SafeJSON.parse() and SafeJSON.stringify() everywhere
Use logger (from @app/logger) for diagnostics; write to day-stamped file always and to stderr only when log level permits; use out.result() as the only writer to stdout
Log enough context to triage issues from logs alone without re-running the tool; log key decision branches, external-resource access, mode/config resolution, and result counts
Prefer error: err over error: err instanceof Error ? err.message : String(err) when the error field accepts unknown type

Files:

  • src/utils/Stopwatch.ts
  • src/utils/search/stores/vector-store.ts
  • src/usage/index.ts
  • src/files-to-prompt/index.ts
  • src/last-changes/index.ts
  • src/timer/index.ts
  • src/utils/json.ts
  • src/utils/array.ts
  • src/npm-package-diff/index.ts
  • src/utils/math.ts
  • src/utils/string.ts
  • src/utils/object.ts
  • src/utils/paths.client.ts
  • src/utils/format.ts
  • src/utils/date.ts
  • src/json/index.ts
  • src/utils/paths.ts
src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

src/**/*.{ts,tsx}: Do not use as any type assertions; use proper type narrowing, type guards, or explicit interfaces instead
When working with union types, use discriminant checks (e.g. entity.className === "User") instead of type assertions
Never use bare catch {} blocks; at minimum log the caught error with context using logger.debug() or logger.warn()
For functions with 3+ parameters or optional parameters, use an object parameter instead of positional parameters
Do not use one-line if statements, even for early returns; always use block form with braces
Add an empty line before if statements unless the preceding line is a variable declaration used by that if
Add an empty line after closing } unless followed by else, catch, finally, or another }
Always check isInteractive() from @app/utils/cli before showing prompts; provide sensible defaults or error with suggestCommand() in non-interactive mode

Files:

  • src/utils/Stopwatch.ts
  • src/utils/search/stores/vector-store.ts
  • src/usage/index.ts
  • src/files-to-prompt/index.ts
  • src/last-changes/index.ts
  • src/timer/index.ts
  • src/utils/json.ts
  • src/utils/array.ts
  • src/npm-package-diff/index.ts
  • src/utils/math.ts
  • src/utils/string.ts
  • src/utils/object.ts
  • src/utils/paths.client.ts
  • src/utils/format.ts
  • src/utils/date.ts
  • src/json/index.ts
  • src/utils/paths.ts
**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.ts: Never add a file-path comment as the first line of files (e.g., // src/path/to/file.ts)
Do not add comments that restate what the code already says; avoid obvious comments like // Build initial context before buildContext()

Files:

  • src/utils/Stopwatch.ts
  • src/utils/search/stores/vector-store.ts
  • packages/core/src/object.ts
  • src/usage/index.ts
  • src/files-to-prompt/index.ts
  • src/last-changes/index.ts
  • packages/core/src/array.ts
  • src/timer/index.ts
  • packages/core/src/Stopwatch.ts
  • src/utils/json.ts
  • src/utils/array.ts
  • src/npm-package-diff/index.ts
  • packages/core/src/math.ts
  • packages/core/src/json.ts
  • src/utils/math.ts
  • src/utils/string.ts
  • src/utils/object.ts
  • src/utils/paths.client.ts
  • src/utils/format.ts
  • src/utils/date.ts
  • src/json/index.ts
  • packages/core/src/string.ts
  • packages/core/src/paths.client.ts
  • src/utils/paths.ts
  • packages/core/src/paths.ts
  • packages/core/src/format.ts
  • packages/core/src/date.ts
src/utils/

📄 CodeRabbit inference engine (CLAUDE.md)

When creating a new tool, check if helper functions are general-purpose and usable by other tools; if so, place them in src/utils/ instead of inside the tool directory

Files:

  • src/utils/Stopwatch.ts
  • src/utils/search/stores/vector-store.ts
  • src/utils/json.ts
  • src/utils/array.ts
  • src/utils/math.ts
  • src/utils/string.ts
  • src/utils/object.ts
  • src/utils/paths.client.ts
  • src/utils/format.ts
  • src/utils/date.ts
  • src/utils/paths.ts
src/**/index.ts

📄 CodeRabbit inference engine (CLAUDE.md)

src/**/index.ts: Tool entry points must use a TypeScript file with shebang that shows an interactive tool selector when run without arguments, and executes the specified tool via bun run when given arguments
Tool entry points must end with await runTool(program, { tool }) from @app/utils/cli, which owns -v/--readme/help registration and console-level resolution

Files:

  • src/usage/index.ts
  • src/files-to-prompt/index.ts
  • src/last-changes/index.ts
  • src/timer/index.ts
  • src/npm-package-diff/index.ts
  • src/json/index.ts
src/*/index.ts

📄 CodeRabbit inference engine (CLAUDE.md)

Tool directories must contain either index.ts/index.tsx or standalone .ts/.tsx files; tool name is derived from directory name or filename without extension

Files:

  • src/usage/index.ts
  • src/files-to-prompt/index.ts
  • src/last-changes/index.ts
  • src/timer/index.ts
  • src/npm-package-diff/index.ts
  • src/json/index.ts
🧠 Learnings (25)
📚 Learning: 2026-05-17T18:12:35.585Z
Learnt from: genesiscz
Repo: genesiscz/GenesisTools PR: 168
File: src/utils/ai/transcription/TranscriptionManager.ts:138-139
Timestamp: 2026-05-17T18:12:35.585Z
Learning: In genesiscz/GenesisTools, avoid raising a “silent no-op” review finding in src/utils/ai/transcription/TranscriptionManager.ts about TranscriptionOptions.speakers not being forwarded in buildProviderOptions. speakers is intentionally wired for the local diarization path (Transcriber.ts → maybeDiarizeLocal → diarizeLocal({ speakers })) and is not meant to be passed to cloud providers (e.g., Deepgram/AssemblyAI) via TranscriptionManager.buildProviderOptions; downstream usage occurs in Transcriber.ts.

Applied to files:

  • .gitignore
📚 Learning: 2026-05-18T14:01:18.072Z
Learnt from: genesiscz
Repo: genesiscz/GenesisTools PR: 171
File: src/utils/fs/file-tailer.ts:66-73
Timestamp: 2026-05-18T14:01:18.072Z
Learning: In genesiscz/GenesisTools `src/utils/fs/file-tailer.ts` (class `FileTailer`), the code intentionally sets `this.started = true` before calling `writeFileSync(...)` and then calls `writeFileSync(path, "", { flag: "wx" })` inside a bare `catch {}`.

During review, do not flag this as an incorrect “swallowing errors” pattern or as a misordered `started` assignment. This is deliberate create-or-skip bootstrap logic: `fs.watch` requires the file to exist at registration time, and `{ flag: "wx" }` ensures exclusive creation; the only expected failure is `EEXIST` when another writer already created the file, so ignoring that error is correct for this use case.

Applied to files:

  • .gitignore
📚 Learning: 2026-02-24T15:32:37.494Z
Learnt from: genesiscz
Repo: genesiscz/GenesisTools PR: 54
File: src/github/lib/output.ts:109-113
Timestamp: 2026-02-24T15:32:37.494Z
Learning: In TypeScript files under src/, do not require a leading blank line before an if statement that is the first statement inside a function body (immediately after the function signature). The blank line rule should only apply to if statements that come after other statements within the function body. Apply this guideline consistently across TS files in src to reduce unnecessary vertical whitespace and keep concise function bodies.

Applied to files:

  • src/utils/Stopwatch.ts
  • src/utils/search/stores/vector-store.ts
  • src/usage/index.ts
  • src/files-to-prompt/index.ts
  • src/last-changes/index.ts
  • src/timer/index.ts
  • src/utils/json.ts
  • src/utils/array.ts
  • src/npm-package-diff/index.ts
  • src/utils/math.ts
  • src/utils/string.ts
  • src/utils/object.ts
  • src/utils/paths.client.ts
  • src/utils/format.ts
  • src/utils/date.ts
  • src/json/index.ts
  • src/utils/paths.ts
📚 Learning: 2026-03-09T13:13:58.786Z
Learnt from: genesiscz
Repo: genesiscz/GenesisTools PR: 81
File: src/github/commands/get.ts:209-212
Timestamp: 2026-03-09T13:13:58.786Z
Learning: In the GenesisTools repo (genesiscz/GenesisTools), do not treat CI formatter warnings as enforceable formatting rules for TypeScript files under src/. Focus reviews on logical correctness and consistency with existing code patterns. For files under src (e.g., src/github/commands/get.ts), prioritize code structure, readability, naming, correctness, and adherence to project conventions over automated formatting warnings from CI tools.

Applied to files:

  • src/utils/Stopwatch.ts
  • src/utils/search/stores/vector-store.ts
  • src/usage/index.ts
  • src/files-to-prompt/index.ts
  • src/last-changes/index.ts
  • src/timer/index.ts
  • src/utils/json.ts
  • src/utils/array.ts
  • src/npm-package-diff/index.ts
  • src/utils/math.ts
  • src/utils/string.ts
  • src/utils/object.ts
  • src/utils/paths.client.ts
  • src/utils/format.ts
  • src/utils/date.ts
  • src/json/index.ts
  • src/utils/paths.ts
📚 Learning: 2026-03-12T01:26:31.610Z
Learnt from: genesiscz
Repo: genesiscz/GenesisTools PR: 95
File: src/timely/utils/entry-processor.ts:0-0
Timestamp: 2026-03-12T01:26:31.610Z
Learning: In code paths where JSON is consumed, prefer strict RFC 8259 validation by using SafeJSON.parse(text, { strict: true }) instead of the lenient default. Apply this at non-config boundaries (e.g., API responses, JSONL, cache outputs, subprocess outputs). Reserve the lenient comment-json behavior only for user-authored config files that may legitimately contain comments or trailing commas. For src/timely/utils/entry-processor.ts and similar modules, replace or wrap JSON parsing with SafeJSON.parse(text, { strict: true }) unless you are explicitly handling config files that require comments.

Applied to files:

  • src/utils/Stopwatch.ts
  • src/utils/search/stores/vector-store.ts
  • src/usage/index.ts
  • src/files-to-prompt/index.ts
  • src/last-changes/index.ts
  • src/timer/index.ts
  • src/utils/json.ts
  • src/utils/array.ts
  • src/npm-package-diff/index.ts
  • src/utils/math.ts
  • src/utils/string.ts
  • src/utils/object.ts
  • src/utils/paths.client.ts
  • src/utils/format.ts
  • src/utils/date.ts
  • src/json/index.ts
  • src/utils/paths.ts
📚 Learning: 2026-03-12T01:58:27.831Z
Learnt from: genesiscz
Repo: genesiscz/GenesisTools PR: 103
File: src/port/index.ts:137-144
Timestamp: 2026-03-12T01:58:27.831Z
Learning: In GenesisTools, apply a no-obvious-comments rule: do not add inline comments for well-known POSIX patterns or standard idioms (e.g., a process.kill(pid, 0) probe) when surrounding code is self-documenting through descriptive function/variable names. This guidance applies to TypeScript files under src (src/**/*.ts). Only include comments if they add non-obvious rationale, edge-case behavior, or explain complex logic that cannot be inferred from code alone.

Applied to files:

  • src/utils/Stopwatch.ts
  • src/utils/search/stores/vector-store.ts
  • src/usage/index.ts
  • src/files-to-prompt/index.ts
  • src/last-changes/index.ts
  • src/timer/index.ts
  • src/utils/json.ts
  • src/utils/array.ts
  • src/npm-package-diff/index.ts
  • src/utils/math.ts
  • src/utils/string.ts
  • src/utils/object.ts
  • src/utils/paths.client.ts
  • src/utils/format.ts
  • src/utils/date.ts
  • src/json/index.ts
  • src/utils/paths.ts
📚 Learning: 2026-03-22T22:19:44.520Z
Learnt from: genesiscz
Repo: genesiscz/GenesisTools PR: 119
File: src/indexer/commands/graph.ts:34-34
Timestamp: 2026-03-22T22:19:44.520Z
Learning: In genesiscz/GenesisTools, when using `SafeJSON.parse` in `src/**/*.ts`, it is acceptable to omit `{ strict: true }` if (and only if) the JSON being parsed is internal cache/state written by the same codebase (e.g., data saved by one internal writer and later read from a corresponding cached file). Do not require strict mode for these internal, machine-generated cache files. Require `{ strict: true }` at external/untrusted boundaries instead (e.g., API responses, third-party JSONL, subprocess output, or any JSON whose contents may not have been produced by trusted internal code).

Applied to files:

  • src/utils/Stopwatch.ts
  • src/utils/search/stores/vector-store.ts
  • src/usage/index.ts
  • src/files-to-prompt/index.ts
  • src/last-changes/index.ts
  • src/timer/index.ts
  • src/utils/json.ts
  • src/utils/array.ts
  • src/npm-package-diff/index.ts
  • src/utils/math.ts
  • src/utils/string.ts
  • src/utils/object.ts
  • src/utils/paths.client.ts
  • src/utils/format.ts
  • src/utils/date.ts
  • src/json/index.ts
  • src/utils/paths.ts
📚 Learning: 2026-03-25T19:55:27.917Z
Learnt from: genesiscz
Repo: genesiscz/GenesisTools PR: 129
File: src/utils/search/stores/vector-store.ts:19-23
Timestamp: 2026-03-25T19:55:27.917Z
Learning: When reviewing this codebase’s “3+ parameters → object parameter” guideline, only suggest object-parameter refactoring when the function’s parameters are ambiguous or include optional/unclear semantics. Do not flag tightly-defined utility/helper functions where (1) all parameters are required, (2) meanings are semantically clear from parameter names, and (3) the ordering is well-ordered and obvious. For example, functions like bruteForceVectorSearch(memoryIndex, queryVector, limit) should be allowed to keep positional parameters because the intent is clear.

Applied to files:

  • src/utils/Stopwatch.ts
  • src/utils/search/stores/vector-store.ts
  • src/usage/index.ts
  • src/files-to-prompt/index.ts
  • src/last-changes/index.ts
  • src/timer/index.ts
  • src/utils/json.ts
  • src/utils/array.ts
  • src/npm-package-diff/index.ts
  • src/utils/math.ts
  • src/utils/string.ts
  • src/utils/object.ts
  • src/utils/paths.client.ts
  • src/utils/format.ts
  • src/utils/date.ts
  • src/json/index.ts
  • src/utils/paths.ts
📚 Learning: 2026-05-05T03:52:21.057Z
Learnt from: genesiscz
Repo: genesiscz/GenesisTools PR: 163
File: src/debugging-master/core/dashboard-server.ts:115-127
Timestamp: 2026-05-05T03:52:21.057Z
Learning: When reviewing Bun.serve fetch handlers in this repo, don’t treat `req.signal` as possibly `undefined` at runtime. Bun guarantees an `AbortSignal` on every incoming Request, so `req.signal?.addEventListener(...)` is unnecessary for runtime safety and is only a TypeScript narrowing artifact (e.g., the type might be `AbortSignal | null`). Therefore, don’t raise concerns about SSE/subscription cleanup being skipped because `req.signal` could be missing; cleanup decisions should be based on the actual handler lifecycle, not an imagined runtime absence of `req.signal`.

Applied to files:

  • src/utils/Stopwatch.ts
  • src/utils/search/stores/vector-store.ts
  • src/usage/index.ts
  • src/files-to-prompt/index.ts
  • src/last-changes/index.ts
  • src/timer/index.ts
  • src/utils/json.ts
  • src/utils/array.ts
  • src/npm-package-diff/index.ts
  • src/utils/math.ts
  • src/utils/string.ts
  • src/utils/object.ts
  • src/utils/paths.client.ts
  • src/utils/format.ts
  • src/utils/date.ts
  • src/json/index.ts
  • src/utils/paths.ts
📚 Learning: 2026-02-24T15:32:44.925Z
Learnt from: genesiscz
Repo: genesiscz/GenesisTools PR: 54
File: src/github/lib/review-output.ts:18-20
Timestamp: 2026-02-24T15:32:44.925Z
Learning: In TypeScript files, do not require a blank line between the opening brace of a function and the first statement if the first statement is the if statement immediately after the signature. The blank-line rule applies to separating an if from unrelated preceding code within the same block, not to spacing after the function opening brace. Apply this rule to all TS functions across the codebase.

Applied to files:

  • src/utils/Stopwatch.ts
  • src/utils/search/stores/vector-store.ts
  • packages/core/src/object.ts
  • src/usage/index.ts
  • src/files-to-prompt/index.ts
  • src/last-changes/index.ts
  • packages/core/src/array.ts
  • src/timer/index.ts
  • packages/core/src/Stopwatch.ts
  • src/utils/json.ts
  • src/utils/array.ts
  • src/npm-package-diff/index.ts
  • packages/core/src/math.ts
  • packages/core/src/json.ts
  • src/utils/math.ts
  • src/utils/string.ts
  • src/utils/object.ts
  • src/utils/paths.client.ts
  • src/utils/format.ts
  • src/utils/date.ts
  • src/json/index.ts
  • packages/core/src/string.ts
  • packages/core/src/paths.client.ts
  • src/utils/paths.ts
  • packages/core/src/paths.ts
  • packages/core/src/format.ts
  • packages/core/src/date.ts
📚 Learning: 2026-03-12T01:26:03.611Z
Learnt from: genesiscz
Repo: genesiscz/GenesisTools PR: 95
File: src/ask/lib/ChatSessionManager.ts:0-0
Timestamp: 2026-03-12T01:26:03.611Z
Learning: Use SafeJSON.parse(text, { strict: true }) for strict RFC 8259 validation in all non-config boundaries (API responses, JSONL, cache, subprocess output). The 3-arg form SafeJSON.parse(text, null, { strict: true }) is invalid and should not be used. Only lenient default (no options) is appropriate for user-authored config files that may contain comments/trailing commas. Apply this guideline across TypeScript files (src/**/*.ts) wherever SafeJSON.parse is used.

Applied to files:

  • src/utils/Stopwatch.ts
  • src/utils/search/stores/vector-store.ts
  • packages/core/src/object.ts
  • src/usage/index.ts
  • src/files-to-prompt/index.ts
  • src/last-changes/index.ts
  • packages/core/src/array.ts
  • src/timer/index.ts
  • packages/core/src/Stopwatch.ts
  • src/utils/json.ts
  • src/utils/array.ts
  • src/npm-package-diff/index.ts
  • packages/core/src/math.ts
  • packages/core/src/json.ts
  • src/utils/math.ts
  • src/utils/string.ts
  • src/utils/object.ts
  • src/utils/paths.client.ts
  • src/utils/format.ts
  • src/utils/date.ts
  • src/json/index.ts
  • packages/core/src/string.ts
  • packages/core/src/paths.client.ts
  • src/utils/paths.ts
  • packages/core/src/paths.ts
  • packages/core/src/format.ts
  • packages/core/src/date.ts
📚 Learning: 2026-03-12T01:26:18.985Z
Learnt from: genesiscz
Repo: genesiscz/GenesisTools PR: 95
File: src/claude/lib/history/search.ts:0-0
Timestamp: 2026-03-12T01:26:18.985Z
Learning: When using SafeJSON.parse in TypeScript code, prefer the two-argument form SafeJSON.parse(text, { strict: true }) to enable strict RFC 8259 validation via the native JSON.parse. Do NOT use the three-argument form SafeJSON.parse(text, null, { strict: true }). Apply strict parsing at remote/third-party API boundaries, JSONL parsing points, and subprocess output. Fall back to the lenient/default form only for user-authored config files that may legitimately contain comments or trailing commas. This pattern keeps strict validation where appropriate and preserves leniency for internal/config data.

Applied to files:

  • src/utils/Stopwatch.ts
  • src/utils/search/stores/vector-store.ts
  • packages/core/src/object.ts
  • src/usage/index.ts
  • src/files-to-prompt/index.ts
  • src/last-changes/index.ts
  • packages/core/src/array.ts
  • src/timer/index.ts
  • packages/core/src/Stopwatch.ts
  • src/utils/json.ts
  • src/utils/array.ts
  • src/npm-package-diff/index.ts
  • packages/core/src/math.ts
  • packages/core/src/json.ts
  • src/utils/math.ts
  • src/utils/string.ts
  • src/utils/object.ts
  • src/utils/paths.client.ts
  • src/utils/format.ts
  • src/utils/date.ts
  • src/json/index.ts
  • packages/core/src/string.ts
  • packages/core/src/paths.client.ts
  • src/utils/paths.ts
  • packages/core/src/paths.ts
  • packages/core/src/format.ts
  • packages/core/src/date.ts
📚 Learning: 2026-03-12T01:26:27.000Z
Learnt from: genesiscz
Repo: genesiscz/GenesisTools PR: 95
File: src/debugging-master/commands/tail.ts:0-0
Timestamp: 2026-03-12T01:26:27.000Z
Learning: In the genesiscz/GenesisTools repository, prefer using SafeJSON.parse(text, { strict: true }) (2-argument form) at all non-config JSON boundaries such as API responses, JSONL parsers, cache files, and subprocess stdout. Reserve the lenient default (SafeJSON.parse(text) with no options) only for user-authored config files that may legitimately contain comments or trailing commas.

Applied to files:

  • src/utils/Stopwatch.ts
  • src/utils/search/stores/vector-store.ts
  • packages/core/src/object.ts
  • src/usage/index.ts
  • src/files-to-prompt/index.ts
  • src/last-changes/index.ts
  • packages/core/src/array.ts
  • src/timer/index.ts
  • packages/core/src/Stopwatch.ts
  • src/utils/json.ts
  • src/utils/array.ts
  • src/npm-package-diff/index.ts
  • packages/core/src/math.ts
  • packages/core/src/json.ts
  • src/utils/math.ts
  • src/utils/string.ts
  • src/utils/object.ts
  • src/utils/paths.client.ts
  • src/utils/format.ts
  • src/utils/date.ts
  • src/json/index.ts
  • packages/core/src/string.ts
  • packages/core/src/paths.client.ts
  • src/utils/paths.ts
  • packages/core/src/paths.ts
  • packages/core/src/format.ts
  • packages/core/src/date.ts
📚 Learning: 2026-03-12T01:26:24.859Z
Learnt from: genesiscz
Repo: genesiscz/GenesisTools PR: 95
File: src/azure-devops/commands/history-sync.ts:0-0
Timestamp: 2026-03-12T01:26:24.859Z
Learning: In GenesisTools, ensure SafeJSON.parse is called with exactly two arguments. Use SafeJSON.parse(text, { strict: true }) for strict RFC 8259 validation, or pass a reviver function as the second argument. Do not call SafeJSON.parse(text, null, { strict: true }) since the function signature does not support a three-argument form. Apply this guideline to all TypeScript files that use SafeJSON.parse (e.g., src/utils/json.ts) and other related code.

Applied to files:

  • src/utils/Stopwatch.ts
  • src/utils/search/stores/vector-store.ts
  • packages/core/src/object.ts
  • src/usage/index.ts
  • src/files-to-prompt/index.ts
  • src/last-changes/index.ts
  • packages/core/src/array.ts
  • src/timer/index.ts
  • packages/core/src/Stopwatch.ts
  • src/utils/json.ts
  • src/utils/array.ts
  • src/npm-package-diff/index.ts
  • packages/core/src/math.ts
  • packages/core/src/json.ts
  • src/utils/math.ts
  • src/utils/string.ts
  • src/utils/object.ts
  • src/utils/paths.client.ts
  • src/utils/format.ts
  • src/utils/date.ts
  • src/json/index.ts
  • packages/core/src/string.ts
  • packages/core/src/paths.client.ts
  • src/utils/paths.ts
  • packages/core/src/paths.ts
  • packages/core/src/format.ts
  • packages/core/src/date.ts
📚 Learning: 2026-03-17T01:30:56.939Z
Learnt from: genesiscz
Repo: genesiscz/GenesisTools PR: 107
File: src/utils/macos/tts.ts:130-139
Timestamp: 2026-03-17T01:30:56.939Z
Learning: In genesiscz/GenesisTools, do not suggest converting two-argument functions with an optional second parameter (for example setMute(muted: boolean, app?: string)) to an object-parameter form. The project prefers simple positional parameters for short utility functions, even when an optional argument is present. The object-parameter guideline should only apply when a function has 3 or more parameters.

Applied to files:

  • src/utils/Stopwatch.ts
  • src/utils/search/stores/vector-store.ts
  • packages/core/src/object.ts
  • src/usage/index.ts
  • src/files-to-prompt/index.ts
  • src/last-changes/index.ts
  • packages/core/src/array.ts
  • src/timer/index.ts
  • packages/core/src/Stopwatch.ts
  • src/utils/json.ts
  • src/utils/array.ts
  • src/npm-package-diff/index.ts
  • packages/core/src/math.ts
  • packages/core/src/json.ts
  • src/utils/math.ts
  • src/utils/string.ts
  • src/utils/object.ts
  • src/utils/paths.client.ts
  • src/utils/format.ts
  • src/utils/date.ts
  • src/json/index.ts
  • packages/core/src/string.ts
  • packages/core/src/paths.client.ts
  • src/utils/paths.ts
  • packages/core/src/paths.ts
  • packages/core/src/format.ts
  • packages/core/src/date.ts
📚 Learning: 2026-03-22T22:19:49.876Z
Learnt from: genesiscz
Repo: genesiscz/GenesisTools PR: 119
File: src/indexer/index.ts:41-56
Timestamp: 2026-03-22T22:19:49.876Z
Learning: When using Bun projects, treat `import.meta.dir` as an absolute directory path provided by Bun. If you build paths by concatenating with `import.meta.dir` (e.g., `import.meta.dir + "/file.ts"`), do not require `path.resolve()` as it would be redundant. Only apply `path.resolve()` guidance when the base path is relative (not when the base is already an absolute `import.meta.dir`).

Applied to files:

  • src/utils/Stopwatch.ts
  • src/utils/search/stores/vector-store.ts
  • packages/core/src/object.ts
  • src/usage/index.ts
  • src/files-to-prompt/index.ts
  • src/last-changes/index.ts
  • packages/core/src/array.ts
  • src/timer/index.ts
  • packages/core/src/Stopwatch.ts
  • src/utils/json.ts
  • src/utils/array.ts
  • src/npm-package-diff/index.ts
  • packages/core/src/math.ts
  • packages/core/src/json.ts
  • src/utils/math.ts
  • src/utils/string.ts
  • src/utils/object.ts
  • src/utils/paths.client.ts
  • src/utils/format.ts
  • src/utils/date.ts
  • src/json/index.ts
  • packages/core/src/string.ts
  • packages/core/src/paths.client.ts
  • src/utils/paths.ts
  • packages/core/src/paths.ts
  • packages/core/src/format.ts
  • packages/core/src/date.ts
📚 Learning: 2026-03-12T03:48:42.474Z
Learnt from: genesiscz
Repo: genesiscz/GenesisTools PR: 104
File: src/darwinkit/index.ts:146-156
Timestamp: 2026-03-12T03:48:42.474Z
Learning: In TypeScript files that use Commander subcommands and exit after showing help, replace code after Command.help() with the pattern: call sub.outputHelp(); (returns void) followed by process.exit(0) or process.exit(1). This avoids TS7027 unreachable-code because Command.help() returns never. Apply this pattern in all src/**/*.ts files where subcommands need to display help before exiting.

Applied to files:

  • src/utils/Stopwatch.ts
  • src/utils/search/stores/vector-store.ts
  • packages/core/src/object.ts
  • src/usage/index.ts
  • src/files-to-prompt/index.ts
  • src/last-changes/index.ts
  • packages/core/src/array.ts
  • src/timer/index.ts
  • packages/core/src/Stopwatch.ts
  • src/utils/json.ts
  • src/utils/array.ts
  • src/npm-package-diff/index.ts
  • packages/core/src/math.ts
  • packages/core/src/json.ts
  • src/utils/math.ts
  • src/utils/string.ts
  • src/utils/object.ts
  • src/utils/paths.client.ts
  • src/utils/format.ts
  • src/utils/date.ts
  • src/json/index.ts
  • packages/core/src/string.ts
  • packages/core/src/paths.client.ts
  • src/utils/paths.ts
  • packages/core/src/paths.ts
  • packages/core/src/format.ts
  • packages/core/src/date.ts
📚 Learning: 2026-03-25T21:01:55.569Z
Learnt from: genesiscz
Repo: genesiscz/GenesisTools PR: 129
File: src/utils/string.ts:104-111
Timestamp: 2026-03-25T21:01:55.569Z
Learning: For GenesisTools utilities under src/utils/**, Windows path support is required. When reviewing files in src/utils, treat POSIX-only path handling as a CRITICAL issue—e.g., code that searches for only "/" as the path separator or ignores "\\". Ensure path utility functions correctly handle both separators ("/" and "\\"), for example by using regex patterns like /[\\/]/ when parsing or splitting paths.

Applied to files:

  • src/utils/Stopwatch.ts
  • src/utils/search/stores/vector-store.ts
  • src/utils/json.ts
  • src/utils/array.ts
  • src/utils/math.ts
  • src/utils/string.ts
  • src/utils/object.ts
  • src/utils/paths.client.ts
  • src/utils/format.ts
  • src/utils/date.ts
  • src/utils/paths.ts
📚 Learning: 2026-03-26T00:12:19.016Z
Learnt from: genesiscz
Repo: genesiscz/GenesisTools PR: 129
File: src/utils/string.ts:100-103
Timestamp: 2026-03-26T00:12:19.016Z
Learning: In this repo’s utility files (src/utils/**/*.ts), prefer minimal JSDoc for functions like truncatePath(path, maxLength). Do not add “obvious” implementation details (e.g., explicitly listing handled path separators such as / and \\) when the function/parameter names are self-documenting. Only expand JSDoc when there is non-obvious rationale, important design constraints, or edge-case behavior that would otherwise be unclear to reviewers.

Applied to files:

  • src/utils/Stopwatch.ts
  • src/utils/search/stores/vector-store.ts
  • src/utils/json.ts
  • src/utils/array.ts
  • src/utils/math.ts
  • src/utils/string.ts
  • src/utils/object.ts
  • src/utils/paths.client.ts
  • src/utils/format.ts
  • src/utils/date.ts
  • src/utils/paths.ts
📚 Learning: 2026-05-05T11:58:33.420Z
Learnt from: genesiscz
Repo: genesiscz/GenesisTools PR: 163
File: src/indexer/lib/sources/mail-source.dateSent.probe.test.ts:0-0
Timestamp: 2026-05-05T11:58:33.420Z
Learning: This repo uses Biome 2.x. The console lint rule is `noConsole` (located at `lint/suspicious/noConsole`), not `noConsoleLog`. In this codebase, `noConsole` is disabled in `biome.json`, so adding a `// biome-ignore lint/suspicious/noConsole:<...>` suppression comment is a no-op and should be avoided (CI flags it as having no effect). When reviewing, do not suggest adding Biome suppression comments for console usage; if a `console.*` call must remain, leave it without a `biome-ignore` comment.

Applied to files:

  • src/utils/Stopwatch.ts
  • src/utils/search/stores/vector-store.ts
  • packages/core/src/object.ts
  • src/usage/index.ts
  • src/files-to-prompt/index.ts
  • src/last-changes/index.ts
  • packages/core/src/array.ts
  • src/timer/index.ts
  • packages/core/src/Stopwatch.ts
  • src/utils/json.ts
  • src/utils/array.ts
  • src/npm-package-diff/index.ts
  • packages/core/src/math.ts
  • packages/core/src/json.ts
  • src/utils/math.ts
  • src/utils/string.ts
  • src/utils/object.ts
  • src/utils/paths.client.ts
  • src/utils/format.ts
  • src/utils/date.ts
  • src/json/index.ts
  • packages/core/src/string.ts
  • packages/core/src/paths.client.ts
  • src/utils/paths.ts
  • packages/core/src/paths.ts
  • packages/core/src/format.ts
  • packages/core/src/date.ts
📚 Learning: 2026-05-18T14:02:30.445Z
Learnt from: genesiscz
Repo: genesiscz/GenesisTools PR: 171
File: src/utils/ui/layouts/AuthLayout.tsx:34-34
Timestamp: 2026-05-18T14:02:30.445Z
Learning: When reviewing a PR, before leaving any comment on a specific file and hunk, verify that the file (and the relevant lines) actually exist in the PR’s current diff. For example, use `git diff --name-only <base>...<head>` (or the PR’s file list) to confirm the file is part of the diff, since pre-rebase/stale hunk references can lead to incorrect or outdated comments.

Applied to files:

  • src/utils/Stopwatch.ts
  • src/utils/search/stores/vector-store.ts
  • packages/core/src/object.ts
  • src/usage/index.ts
  • src/files-to-prompt/index.ts
  • src/last-changes/index.ts
  • packages/core/src/array.ts
  • src/timer/index.ts
  • packages/core/src/Stopwatch.ts
  • src/utils/json.ts
  • src/utils/array.ts
  • src/npm-package-diff/index.ts
  • packages/core/src/math.ts
  • packages/core/src/json.ts
  • src/utils/math.ts
  • src/utils/string.ts
  • src/utils/object.ts
  • src/utils/paths.client.ts
  • src/utils/format.ts
  • src/utils/date.ts
  • src/json/index.ts
  • packages/core/src/string.ts
  • packages/core/src/paths.client.ts
  • src/utils/paths.ts
  • packages/core/src/paths.ts
  • packages/core/src/format.ts
  • packages/core/src/date.ts
📚 Learning: 2026-05-18T15:39:25.103Z
Learnt from: genesiscz
Repo: genesiscz/GenesisTools PR: 173
File: src/question/commands/log.ts:0-0
Timestamp: 2026-05-18T15:39:25.103Z
Learning: In genesiscz/GenesisTools, when implementing colored terminal/CLI output in TypeScript code under src/, use `picocolors` imported as `pc` (e.g., `import pc from 'picocolors'`). Do not propose `chalk` for CLI coloring. For chained styling (e.g., what chalk would express as `bold` + `blue`), compose picocolors calls by nesting, such as `pc.bold(pc.blue(text))`. Treat any mention of chalk in outdated docs (e.g., CLAUDE.md) as non-authoritative for this guideline.

Applied to files:

  • src/utils/Stopwatch.ts
  • src/utils/search/stores/vector-store.ts
  • src/usage/index.ts
  • src/files-to-prompt/index.ts
  • src/last-changes/index.ts
  • src/timer/index.ts
  • src/utils/json.ts
  • src/utils/array.ts
  • src/npm-package-diff/index.ts
  • src/utils/math.ts
  • src/utils/string.ts
  • src/utils/object.ts
  • src/utils/paths.client.ts
  • src/utils/format.ts
  • src/utils/date.ts
  • src/json/index.ts
  • src/utils/paths.ts
📚 Learning: 2026-05-19T18:33:15.211Z
Learnt from: genesiscz
Repo: genesiscz/GenesisTools PR: 176
File: src/telegram/index.ts:25-28
Timestamp: 2026-05-19T18:33:15.211Z
Learning: When reviewing legacy CLI entrypoint files (e.g., src/**/index.ts) that call `await runTool(program, { tool: "..." })`, allow the `.catch()` handler to keep `console.error(err); process.exit(1)` without requiring a switch to `logger.error` **only** for minimal-touch migrations that were done solely to satisfy the “no-default-import” gate and that add no new feature/behavior code. If the PR introduces any new feature logic or expands the catch-handling beyond that migration, prefer `logger.error` (and follow the repo’s normal logging conventions).

Applied to files:

  • src/usage/index.ts
  • src/files-to-prompt/index.ts
  • src/last-changes/index.ts
  • src/timer/index.ts
  • src/npm-package-diff/index.ts
  • src/json/index.ts
📚 Learning: 2026-02-25T23:00:07.620Z
Learnt from: genesiscz
Repo: genesiscz/GenesisTools PR: 56
File: plugins/genesis-tools/commands/github-pr.md:131-131
Timestamp: 2026-02-25T23:00:07.620Z
Learning: Adopt the style: use lowercase 'markdown' (not 'Markdown') in the GenesisTools documentation. Apply this consistently across all Markdown files in the repository (any .md file), including generated docs and READMEs.

Applied to files:

  • MONOREPO-PLAN.md
  • MONOREPO-SPEC.md
📚 Learning: 2026-05-22T18:53:48.562Z
Learnt from: genesiscz
Repo: genesiscz/GenesisTools PR: 183
File: scripts/benchmarks/clones/microbenches/README.md:4-4
Timestamp: 2026-05-22T18:53:48.562Z
Learning: In GenesisTools markdown docs, do not treat `macos` (lowercase) inside backticks as a capitalization error. When `macos` is used as a literal CLI subcommand token (e.g., `tools macos clones ...`) corresponding to the `src/macos/` command implementation, keep it lowercase and ignore capitalization suggestions such as LanguageTool rule `MAC_OS` (it would document the wrong command). Only capitalize `MacOS`/`macOS` when it is clearly prose about the operating system, not when it’s a code-formatted command token.

Applied to files:

  • MONOREPO-PLAN.md
  • MONOREPO-SPEC.md
🪛 ast-grep (0.42.3)
packages/core/src/string.ts

[warning] 123-123: Regular expression constructed from variable input detected. This can lead to Regular Expression Denial of Service (ReDoS) attacks if the variable contains malicious patterns. Use libraries like 'recheck' to validate regex safety or use static patterns.
Context: new RegExp(^${escaped}$, "i")
Note: [CWE-1333] Inefficient Regular Expression Complexity [REFERENCES]
- https://owasp.org/www-community/attacks/Regular_expression_Denial_of_Service_-_ReDoS
- https://cwe.mitre.org/data/definitions/1333.html

(regexp-from-variable)

🪛 LanguageTool
MONOREPO-PLAN.md

[uncategorized] ~142-~142: The official name of this popular video platform is spelled with a capital “T”.
Context: ...ps/*packages -shops(914 inbound),youtube(292),azure-devops` (176) → their ow...

(YOUTUBE)

MONOREPO-SPEC.md

[uncategorized] ~11-~11: The official name of this popular video platform is spelled with a capital “T”.
Context: ...(@app/shops 914, @app/Internal 323, @app/youtube 292, @app/azure-devops 176, …). Alia...

(YOUTUBE)


[grammar] ~24-~24: Ensure spelling is correct
Context: ...nd a rerun is FULL TURBO cache hit (904ms → 62ms) — the build-pipeline thesis mad...

(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)


[style] ~28-~28: Consider an alternative for the overused word “exactly”.
Context: ...rters, so it got its own shim). This is exactly the kind of leak the per-file tsgo-0 ga...

(EXACTLY_PRECISELY)


[grammar] ~129-~129: Use a hyphen to join words.
Context: ..../toolsortsgo. | new, additive, off run-path | ### Root turbo.json` (targe...

(QB_NEW_EN_HYPHEN)


[uncategorized] ~162-~162: The official name of this popular video platform is spelled with a capital “T”.
Context: ...pps/* packages** (shops914 inbound,youtube, azure-devops`) so they gain isolated...

(YOUTUBE)


[style] ~175-~175: Consider an alternative for the overused word “exactly”.
Context: ... disciplined about acyclicity, which is exactly why foundation here is conservatively s...

(EXACTLY_PRECISELY)

🪛 markdownlint-cli2 (0.22.1)
MONOREPO-PLAN.md

[warning] 40-40: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


[warning] 50-50: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


[warning] 59-59: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


[warning] 61-61: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


[warning] 63-63: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


[warning] 66-66: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


[warning] 77-77: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


[warning] 83-83: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


[warning] 118-118: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


[warning] 125-125: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


[warning] 131-131: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


[warning] 137-137: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


[warning] 141-141: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


[warning] 144-144: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)

MONOREPO-SPEC.md

[warning] 83-83: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🔇 Additional comments (26)
.gitignore (1)

3-5: LGTM!

package.json (1)

6-9: LGTM!

Also applies to: 67-67

turbo.json (1)

1-9: LGTM!

packages/core/package.json (1)

6-26: LGTM!

packages/core/tsconfig.json (1)

1-7: LGTM!

packages/core/src/Stopwatch.ts (1)

14-61: LGTM!

packages/core/src/array.ts (1)

9-14: LGTM!

packages/core/src/format.ts (1)

23-415: LGTM!

src/utils/date.ts (1)

1-1: LGTM!

src/utils/json.ts (1)

1-1: Ensure @app/utils/json keeps back-compat SafeJSON + parseJSON exports
src/utils/json.ts is export * from "@gt/core/json";, and packages/core/src/json.ts exports named SafeJSON and parseJSON, so both symbols remain available to consumers (e.g., src/har-analyzer/commands/show.ts imports parseJSON from @app/utils/json).

packages/core/src/json.ts (2)

1-82: LGTM!


45-45: ⚡ Quick win

Check that options.unbox is the right boolean for comment-json’s 3rd arg (removesComments).

comment-json@4.6.2 typings define parse(json, reviver?, removesComments?: boolean); this code calls parse(text, options.reviver, options.unbox), so options.unbox should be confirmed as the intended “remove comments” flag (and not a differently-scoped option or inverted meaning). [minor]

src/utils/object.ts (1)

1-1: LGTM!

src/utils/paths.client.ts (1)

1-1: LGTM!

src/files-to-prompt/index.ts (1)

8-8: LGTM!

src/last-changes/index.ts (1)

6-7: LGTM!

src/utils/Stopwatch.ts (1)

1-1: LGTM!

src/utils/paths.ts (1)

1-1: LGTM!

src/timer/index.ts (1)

10-10: LGTM!

src/usage/index.ts (1)

7-7: LGTM!

Also applies to: 54-56

src/utils/search/stores/vector-store.ts (1)

1-1: LGTM!

src/utils/string.ts (1)

1-1: LGTM!

packages/core/src/paths.ts (1)

15-201: LGTM!

src/utils/array.ts (1)

1-1: LGTM!

src/utils/format.ts (1)

1-1: LGTM!

src/utils/math.ts (1)

1-1: LGTM!

Comment thread MONOREPO-PLAN.md
Comment on lines +91 to +99
| Tool | Exercises | Migration |
|---|---|---|
| `json` (`src/json/index.ts`) | `SafeJSON` (`@app/utils/json`) | already smoke-verified; switch its `@app/utils/json` → `@gt/core/json` |
| `files-to-prompt` (`src/files-to-prompt/index.ts`) | `formatBytes` (`@app/utils/format`) | `@app/utils/format` → `@gt/core/format` |
| `collect-files-for-ai` (`src/collect-files-for-ai/index.ts`) | paths/format glue | switch the `@app/utils/format`/`paths` imports it uses → `@gt/core/*` |
| `npm-package-diff` (`src/npm-package-diff/index.ts`) | `SafeJSON`, `resolvePathWithTilde` | `@app/utils/json` → `@gt/core/json` (keep `@app/utils` barrel import as-is — barrel not moved) |
| `git-last-commits-diff` (`src/git-last-commits-diff/index.ts`) | date/format/string | switch its `@app/utils/format`/`date`/`string` imports → `@gt/core/*` |
| `timer` (`src/timer*`) or `t3chat-length` | `format`/`Stopwatch`/`string` | switch matching imports → `@gt/core/*` |

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.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Align Step 4 tool list with the “executed” list to avoid drift.

This table conflicts with the already-executed set in Line 28 (it lists collect-files-for-ai / git-last-commits-diff instead of last-changes / usage). Please make these sections consistent so the plan is reproducible without ambiguity.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@MONOREPO-PLAN.md` around lines 91 - 99, The tool/migration table lists the
wrong packages (it includes collect-files-for-ai and git-last-commits-diff)
which conflicts with the executed list (last-changes and usage); update the
table rows so the tools column matches the executed set by replacing the
collect-files-for-ai row with last-changes and the git-last-commits-diff row
with usage, and adjust their Exercises/Migration cells accordingly (preserve the
same migration pattern: switch `@app/utils/`* imports to `@gt/core/`* where
applicable, and keep any barrel imports unchanged like the npm-package-diff
note). Ensure the table now exactly matches the earlier “executed” list so the
plan is consistent and reproducible.

Comment thread MONOREPO-SPEC.md
Comment on lines +83 to +100
```
┌────────────┐
│ @gt/core │ (json,date,format,string,paths,Stopwatch,array,object,math)
└─────┬──────┘
┌──────────────┼───────────────┬───────────────┐
▼ ▼ ▼ ▼
@gt/logger @gt/storage @gt/ui @gt/ai
│ ▲ │ │ │
└──┤ │ │ │
@gt/cli ────────┘ │ │
│ (cli↔logger cycle: one pkg until §6) │
▼ ▼ ▼ ▼
┌─────────────────────────────────────────────────────┐
│ apps/* (the 79 tools) │
│ ask, shops, youtube, azure-devops, task, … │
│ (tool→tool imports e.g. @app/shops kept as-is) │
└─────────────────────────────────────────────────────┘
```

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.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add a language tag to the fenced dependency-graph block.

The code fence here is untyped; markdownlint flags this (MD040). Use an explicit tag (e.g., text) to keep docs lint-clean.

Suggested diff
-```
+```text
                  ┌────────────┐
                  │  `@gt/core`  │  (json,date,format,string,paths,Stopwatch,array,object,math)
                  └─────┬──────┘
 ...
-```
+```
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
```
┌────────────┐
│ @gt/core │ (json,date,format,string,paths,Stopwatch,array,object,math)
└─────┬──────┘
┌──────────────┼───────────────┬───────────────┐
▼ ▼ ▼ ▼
@gt/logger @gt/storage @gt/ui @gt/ai
│ ▲ │ │ │
└──┤ │ │ │
@gt/cli ────────┘ │ │
│ (cli↔logger cycle: one pkg until §6) │
▼ ▼ ▼ ▼
┌─────────────────────────────────────────────────────┐
│ apps/* (the 79 tools) │
│ ask, shops, youtube, azure-devops, task, … │
│ (tool→tool imports e.g. @app/shops kept as-is) │
└─────────────────────────────────────────────────────┘
```
🧰 Tools
🪛 markdownlint-cli2 (0.22.1)

[warning] 83-83: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@MONOREPO-SPEC.md` around lines 83 - 100, The fenced dependency-graph block in
MONOREPO-SPEC.md is missing a language tag (MD040); update the opening
triple-backtick for the ASCII diagram to include a tag such as "text" (i.e.,
change ``` to ```text) so the diagram (the block containing `@gt/core`,
`@gt/logger`, `@gt/storage`, `@gt/ui`, `@gt/ai`, `@gt/cli` and apps/*) is lint-clean while
leaving the ASCII content unchanged.

Comment thread packages/core/src/date.ts
Comment on lines +22 to +28
if (!_resolveLocale) {
// Lazy require so Vite won't bundle node:child_process into client code.
_resolveLocale = (require("./date-locale") as { getSystemLocale: () => string }).getSystemLocale;
}

return _resolveLocale();
}

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.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Confirm date-locale module exists and is built, and check whether any non-bun consumer hits the default/dist path.
fd -t f 'date-locale' packages/core/src
rg -nP "createRequire|import\(.*date-locale" packages/core/src/date.ts
# Look for tsup banner/shim config that might inject a require polyfill
fd -t f 'tsup.config' 
rg -nP "createRequire|banner" -g 'tsup.config*' || true

Repository: genesiscz/GenesisTools

Length of output: 215


🏁 Script executed:

#!/bin/bash
set -euo pipefail
echo "== date.ts =="
ls -la packages/core/src/date.ts || true
sed -n '1,120p' packages/core/src/date.ts || true

echo
echo "== Find date-locale files =="
fd -t f "date-locale" packages/core/src || true
fd -t f "*locale*" packages/core/src || true

echo
echo "== Check for require/createRequire in date.ts =="
rg -n --hidden "require\\(|createRequire\\(|import\\(" packages/core/src/date.ts || true

echo
echo "== Check package.json type for `@gt/core` =="
cat packages/core/package.json || true
# Also search for root workspace package json if monorepo
ls -ლა package.json || true
cat package.json 2>/dev/null | sed -n '1,160p' || true

echo
echo "== tsup config =="
fd -t f "tsup.config.*" packages/core -d 6 || true
fd -t f "tsup.config.*" -d 6 . || true

rg -n --hidden "format\\s*:\\s*['\"]esm['\"]|tsup|banner|inject|createRequire|require\\s*\\(|conditions" -S . -g'tsup.config*' || true

Repository: genesiscz/GenesisTools

Length of output: 13336


🏁 Script executed:

#!/bin/bash
set -euo pipefail
echo "== date.ts =="
ls -la packages/core/src/date.ts || true
sed -n '1,140p' packages/core/src/date.ts || true

echo
echo "== Find date-locale files =="
fd -t f "date-locale" packages/core/src || true
fd -t f "*date-locale*" packages/core/src || true
fd -t f "*locale*" packages/core/src || true

echo
echo "== Check for require/createRequire in date.ts =="
rg -n --hidden "require\\(|createRequire\\(|import\\(" packages/core/src/date.ts || true

echo
echo "== package.json type for packages/core =="
cat packages/core/package.json || true
echo
echo "== root package.json (if any) =="
ls -la package.json || true
sed -n '1,120p' package.json 2>/dev/null || true

echo
echo "== tsup config(s) =="
fd -t f "tsup.config.*" packages/core -d 6 || true
fd -t f "tsup.config.*" -d 6 . || true

echo
echo "== any tsup configs mentioning format/esm or banners/inject =="
rg -n --hidden "format\\s*[:=]\\s*['\"]esm['\"]|banner|inject|shims?|createRequire|require\\s*\\(|conditions|bun" -S . -g'tsup.config*' || true

Repository: genesiscz/GenesisTools

Length of output: 12989


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Locate date-locale source =="
fd -t f "date-locale" packages/core/src || true
fd -t f -e ts "date-locale" packages/core/src || true
fd -t f "date-locale\.ts" packages/core/src || true
fd -t f "locale" packages/core/src | head -n 50 || true

echo
echo "== List packages/core/src filenames (shallow) =="
ls -la packages/core/src || true

echo
echo "== Inspect dist output if present =="
ls -la packages/core/dist || true
fd -t f packages/core/dist/date* || true
fd -t f packages/core/dist/*locale* || true

echo
echo "== Inspect built packages/core/dist/date*.js =="
for f in $(fd -t f "dist/date" packages/core/dist 2>/dev/null || true); do
  echo "---- $f (head) ----"
  sed -n '1,120p' "$f" | sed -n '1,120p' || true
  echo "---- $f (grep require/date-locale) ----"
  rg -n "require\\(\"\\.\\/date-locale\"\\)|date-locale" "$f" || true
done

echo
echo "== Check for tsup config at repo root / packages/core =="
fd -t f "tsup.config.*" -a . || true
fd -t f -i "tsup.config.*" . || true

echo
echo "== Check packages/core build pipeline =="
cat packages/core/package.json | rg -n "build|tsup" || true
ls -la packages/core || true

Repository: genesiscz/GenesisTools

Length of output: 1690


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Repo-wide search for date-locale =="

rg -n --hidden --glob '!*node_modules/*' "date-locale" . || true
fd -t f "date-locale" . || true
fd -t f "*date-locale*" . || true
fd -t f "*locale*" packages/core/src || true

echo
echo "== List packages/core/src for anything locale-related =="

ls -la packages/core/src
rg -n "locale" packages/core/src/date.ts || true

echo
echo "== Inspect packages/core/src/date.ts full resolveLocale block =="

rg -n "let _resolveLocale|function resolveLocale" packages/core/src/date.ts
sed -n '1,80p' packages/core/src/date.ts

Repository: genesiscz/GenesisTools

Length of output: 6842


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Does packages/core/src/date-locale.ts exist? =="
ls -la packages/core/src/date-locale.ts packages/core/src/date-locale.* 2>/dev/null || true
echo

echo "== All getSystemLocale definitions =="
rg -n --hidden --glob '!*node_modules/*' "getSystemLocale" . || true
echo

echo "== Inspect src/utils/date-locale.ts =="
ls -la src/utils/date-locale.ts 2>/dev/null || true
sed -n '1,200p' src/utils/date-locale.ts 2>/dev/null || true
echo

echo "== Where is packages/core/src/date.ts imported/used? (rough) =="
rg -n --hidden --glob '!*node_modules/*' "`@gt/core/date`" . || true
rg -n --hidden --glob '!*node_modules/*' "from ['\"]`@gt/core`['\"]" . || true

Repository: genesiscz/GenesisTools

Length of output: 2639


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Find all date-locale* files across repo (excluding node_modules) =="
fd -t f -i "date-locale" -e ts -e tsx -e js -e mjs -e cjs . || true
fd -t f -i "*date-locale*" . || true
rg -n --hidden --glob '!*node_modules/*' "date-locale" . || true

echo
echo "== Find all require(\"./date-locale\") usages =="
rg -n --hidden --glob '!*node_modules/*' "require\\(\"\\.\\/date-locale\"\\)" . || true
rg -n --hidden --glob '!*node_modules/*' "date-locale\"\\)" . || true

echo
echo "== Inspect packages/core/tsconfig.json =="
cat packages/core/tsconfig.json || true

echo
echo "== Inspect packages/core/package.json exports/build scripts =="
cat packages/core/package.json || true

echo
echo "== List packages/core/src tree =="
ls -la packages/core/src

Repository: genesiscz/GenesisTools

Length of output: 3679


🏁 Script executed:

#!/bin/bash
set -euo pipefail
echo "== Call sites of formatDateTime =="
rg -n --hidden --glob '!*node_modules/*' "formatDateTime\\(" . -g'*.ts' -g'*.tsx' -g'*.js' -g'*.jsx' | head -n 80
echo
echo "== Inspect src/utils/date.ts =="
sed -n '1,120p' src/utils/date.ts 2>/dev/null || true
echo
echo "== Inspect src/usage/index.ts =="
sed -n '1,200p' src/usage/index.ts 2>/dev/null || true

Repository: genesiscz/GenesisTools

Length of output: 13406


🏁 Script executed:

#!/bin/bash
set -euo pipefail
echo "== Inspect src/utils/date.ts =="
sed -n '1,80p' src/utils/date.ts

echo
echo "== Find where `@gt/core/date` is imported =="
rg -n --hidden --glob '!*node_modules/*' "from \"`@gt/core/date`\"" . || true
rg -n --hidden --glob '!*node_modules/*' "from ['\"]`@gt/core/date`['\"]" . || true

echo
echo "== Inspect a couple callsites around those imports (first 20 lines) =="
for f in $(rg -l --hidden --glob '!*node_modules/*' "from ['\"]`@gt/core/date`['\"]" . | head -n 20); do
  echo "---- $f ----"
  sed -n '1,40p' "$f"
done

echo
echo "== Search for any packages/core/src/date.ts build references to date-locale =="
rg -n --hidden --glob '!*node_modules/*' "date-locale" packages/core . || true

Repository: genesiscz/GenesisTools

Length of output: 4124


🏁 Script executed:

#!/bin/bash
set -euo pipefail
echo "== Inspect src/utils/date.ts =="
sed -n '1,80p' src/utils/date.ts

echo
echo "== Find where `@gt/core/date` is imported =="
rg -n --hidden --glob '!*node_modules/*' "from \"`@gt/core/date`\"" . || true
rg -n --hidden --glob '!*node_modules/*' "from ['\"]`@gt/core/date`['\"]" . || true

echo
echo "== Inspect a couple callsites around those imports (first 20 lines) =="
for f in $(rg -l --hidden --glob '!*node_modules/*' "from ['\"]`@gt/core/date`['\"]" . | head -n 20); do
  echo "---- $f ----"
  sed -n '1,50p' "$f"
done

echo
echo "== Search for any packages/core/src/date.ts build references to date-locale =="
rg -n --hidden --glob '!*node_modules/*' "date-locale" packages/core . || true

Repository: genesiscz/GenesisTools

Length of output: 4665


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Root tsconfig.json (compilerOptions.paths) =="
cat tsconfig.json | sed -n '1,200p'
echo
rg -n "paths" tsconfig.json || true

echo
echo "== packages/core tsconfig.json (extends + overrides) =="
cat packages/core/tsconfig.json | sed -n '1,200p'

echo
echo "== Search for tsup version / config in repo =="
rg -n --hidden --glob '!*node_modules/*' "\"tsup\"|tsup " package.json packages/*/package.json || true
rg -n --hidden --glob '!*node_modules/*' "tsup\\.config|defineConfig\\(.*tsup" . || true

echo
echo "== Check for tsup config file existence (any name) =="
fd -t f -i "*tsup*.ts" -i "*tsup*.js" -i "*tsup*.cjs" -i "*tsup*.mjs" . || true

Repository: genesiscz/GenesisTools

Length of output: 2517


Fix locale lazy-load in @gt/core: require("./date-locale") points to a missing module and will break in Node ESM.

  • packages/core/src/date.ts does require("./date-locale"), but there is no packages/core/src/date-locale.ts in the package (the only getSystemLocale is src/utils/date-locale.ts), so resolveLocale() (called by formatDateTime() with no locale override by default) will fail to load.
  • Even if the module existed, @gt/core is "type":"module" and the default export targets dist/date.js, where require is unavailable; use createRequire(import.meta.url) or import() and ensure the locale file is actually part of the tsup src/*.ts build inputs.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/core/src/date.ts` around lines 22 - 28, The lazy-load of the locale
in resolveLocale() uses require("./date-locale") which points to a missing file
and breaks in Node ESM; update resolveLocale/_resolveLocale to load the actual
module (src/utils/date-locale.ts) via a Node-ESM-safe mechanism (either use
createRequire(import.meta.url) to require the compiled dist/date-locale or use
dynamic import() to load the source module) and call its getSystemLocale; ensure
the symbol names (_resolveLocale, resolveLocale, formatDateTime,
getSystemLocale) are used to locate the change and also update tsup build inputs
so date-locale is included in the package build.

Comment thread packages/core/src/math.ts
Comment on lines +9 to +18
export function cosineDistance(a: Float32Array, b: Float32Array): number {
let dot = 0;
let normA = 0;
let normB = 0;

for (let i = 0; i < a.length; i++) {
dot += a[i] * b[i];
normA += a[i] * a[i];
normB += b[i] * b[i];
}

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.

⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Missing length validation for input vectors.

The loop iterates using a.length without verifying that b.length matches. If the arrays differ in length:

  • When b.length < a.length: accessing b[i] beyond its bounds returns undefined, yielding NaN in the dot product and norms.
  • When b.length > a.length: elements in b beyond index a.length are silently ignored, producing an incorrect distance.
🛡️ Proposed fix to add length validation
 export function cosineDistance(a: Float32Array, b: Float32Array): number {
+    if (a.length !== b.length) {
+        throw new Error(`Vector length mismatch: ${a.length} vs ${b.length}`);
+    }
+
     let dot = 0;
     let normA = 0;
     let normB = 0;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/core/src/math.ts` around lines 9 - 18, The function cosineDistance
currently iterates up to a.length without validating b, which can produce NaN or
incorrect results; update cosineDistance(a: Float32Array, b: Float32Array) to
first verify the lengths match (e.g., if (a.length !== b.length) throw an Error
or return a defined sentinel) and early-return/throw when they differ, then
proceed with the existing dot/norm calculation using the validated arrays so
out-of-bounds accesses cannot occur.

Comment on lines +16 to +25
export function deepMerge<T extends Record<string, unknown>>(target: T, source: Partial<T>): T {
const result = { ...target };
for (const key in source) {
if (source[key] && isObject(source[key]) && isObject(result[key])) {
(result as Record<string, unknown>)[key] = deepMerge(
result[key] as Record<string, unknown>,
source[key] as Record<string, unknown>
);
} else if (source[key] !== undefined) {
(result as Record<string, unknown>)[key] = source[key];

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.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Harden deepMerge against prototype keys and non-plain objects.

for...in walks inherited properties, and the current isObject() predicate also treats Date, Map, class instances, etc. as mergeable "plain objects". That lets payloads like {"__proto__": {...}} change the merged object's prototype, and it also turns nested non-plain objects into broken plain-object merges instead of overwriting them.

Proposed fix
 export function isObject(value: unknown): value is Record<string, unknown> {
-    return value !== null && typeof value === "object" && !Array.isArray(value);
+    if (value === null || typeof value !== "object" || Array.isArray(value)) {
+        return false;
+    }
+
+    const prototype = Object.getPrototypeOf(value);
+    return prototype === Object.prototype || prototype === null;
 }
 
 export function deepMerge<T extends Record<string, unknown>>(target: T, source: Partial<T>): T {
     const result = { ...target };
-    for (const key in source) {
-        if (source[key] && isObject(source[key]) && isObject(result[key])) {
+    for (const [key, value] of Object.entries(source)) {
+        if (key === "__proto__" || key === "constructor" || key === "prototype") {
+            continue;
+        }
+
+        if (isObject(value) && isObject(result[key])) {
             (result as Record<string, unknown>)[key] = deepMerge(
                 result[key] as Record<string, unknown>,
-                source[key] as Record<string, unknown>
+                value
             );
-        } else if (source[key] !== undefined) {
-            (result as Record<string, unknown>)[key] = source[key];
+        } else if (value !== undefined) {
+            (result as Record<string, unknown>)[key] = value;
         }
     }
     return result;
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/core/src/object.ts` around lines 16 - 25, The deepMerge
implementation should only iterate own enumerable keys and only recurse into
plain objects: replace the for...in loop with iteration over Object.keys(source)
and ensure the isObject predicate only returns true for plain objects (e.g.,
Object.prototype.toString === '[object Object]' and Object.getPrototypeOf(obj)
=== Object.prototype or null) so Dates, Maps, class instances, etc. are treated
as non-plain; when either source[key] or result[key] is not a plain object,
assign/overwrite rather than recursing. Also ensure keys like "__proto__" or
other prototype mutators are not able to change the target prototype by relying
on own-key iteration and plain-object checks in deepMerge and isObject.

Comment on lines +31 to +67
function splitPathSegments(path: string): string[] {
const normalized = collapsePathForDisplay(toPosixPath(path.trim()));

if (!normalized) {
return [];
}

if (normalized === "~") {
return ["~"];
}

if (normalized.startsWith("~/")) {
return ["~", ...normalized.slice(2).split("/").filter(Boolean)];
}

if (normalized.startsWith("/")) {
return normalized.split("/").filter(Boolean);
}

return normalized.split("/").filter(Boolean);
}

function joinPathSegments(segments: string[]): string {
if (segments.length === 0) {
return "";
}

if (segments[0] === "~") {
if (segments.length === 1) {
return "~";
}

return `~/${segments.slice(1).join("/")}`;
}

return `/${segments.join("/")}`;
}

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.

⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Preserve path root kind when computing the common prefix.

splitPathSegments() drops whether the input was relative, POSIX-absolute, or a Windows drive path, and joinPathSegments() rebuilds every non-~ prefix as /.... That produces prefixes like /src for ["src/a", "src/b"] and /C:/work for ["C:\\work\\a", "C:\\work\\b"], which means shortenPathWithPrefix() never matches and those paths stop shortening at all.

Also applies to: 70-101

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/core/src/paths.client.ts` around lines 31 - 67, splitPathSegments
currently drops the original path "root kind" (relative vs POSIX absolute vs
Windows drive), and joinPathSegments always emits POSIX-absolute "/" for
non-tilde roots, breaking common-prefix logic (see splitPathSegments and
joinPathSegments and use in shortenPathWithPrefix). Fix by preserving the root
as an explicit first segment or token when splitting: detect and store a root
kind for inputs that start with "/" (use "/" root), that start with a Windows
drive like /^[A-Za-z]:/ (store the "C:"-style root token), and leave no root
token for relative paths; keep "~" handling as-is. Then update joinPathSegments
to reconstruct the path based on that root token: return "~" or "~/<...>" for
tilde, return "/" + joined segments for POSIX root, return "<Drive>/" + joined
segments for Windows drive tokens, and return a plain joined path (no leading
slash) for relative roots. Ensure shortenPathWithPrefix and any callers still
compare prefixes using the preserved root token when computing/commonizing
prefixes.

Comment on lines +122 to +124
export function matchGlob(value: string, pattern: string): boolean {
const escaped = pattern.replace(/[.+^${}()|[\]\\?]/g, "\\$&").replace(/\*/g, ".*");
return new RegExp(`^${escaped}$`, "i").test(value);

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.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# 1) Inspect matchGlob implementation and surrounding code
rg -n "function matchGlob|matchGlob\(" packages/core/src/string.ts
echo "----"
sed -n '90,160p' packages/core/src/string.ts

# 2) Find all usages to understand controllability/scope
echo "----"
rg -n "matchGlob\(" -S .

# 3) Check if there are tests covering matchGlob behavior/perf
echo "----"
rg -n "matchGlob" -S packages | head -n 200

Repository: genesiscz/GenesisTools

Length of output: 3796


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Show the relevant call-site code for matchGlob usage
sed -n '1,120p' src/har-analyzer/core/query-engine.ts
echo "----"
sed -n '1,120p' src/macos/lib/clones/filters.ts

# Inspect matchGlob tests
sed -n '180,280p' src/utils/string.test.ts

# Find where filter.domain/filter.url/filter.type are populated (likely from CLI/query params)
rg -n "filter\.domain|filter\.url|filter\.type" -S src/har-analyzer/core
rg -n "domain!|url!|type!" -S src/har-analyzer
rg -n "interface .*Filter|type .*Filter|const .*filter" -S src/har-analyzer | head -n 200

# Look for CLI argument parsing for har-analyzer filters
rg -n "har-analyzer|domain|url|mimeType|filter\.domain|filter\.url|filter\.type" -S src | head -n 200

Repository: genesiscz/GenesisTools

Length of output: 31985


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect EntryFilter type
rg -n "export interface EntryFilter" -S src/har-analyzer/types.ts
sed -n '130,210p' src/har-analyzer/types.ts

# Inspect commands that create EntryFilter from CLI options
for f in \
  src/har-analyzer/commands/list.ts \
  src/har-analyzer/commands/search.ts \
  src/har-analyzer/commands/domains.ts \
  src/har-analyzer/commands/errors.ts \
  src/har-analyzer/commands/export.ts \
  src/har-analyzer/commands/waterfall.ts; do
  echo "---- $f"
  if [ -f "$f" ]; then
    sed -n '1,140p' "$f"
  fi
done

# Inspect MCP server filter population
sed -n '120,220p' src/har-analyzer/mcp/server.ts
sed -n '340,420p' src/har-analyzer/mcp/server.ts

# Inspect macos clone filters usage
sed -n '1,120p' src/macos/lib/clones/filters.ts

Repository: genesiscz/GenesisTools

Length of output: 36222


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect EntryFilter type
rg -n "export interface EntryFilter" -S src/har-analyzer/types.ts
sed -n '130,220p' src/har-analyzer/types.ts

# Inspect commands that create EntryFilter from CLI options
for f in \
  src/har-analyzer/commands/list.ts \
  src/har-analyzer/commands/search.ts \
  src/har-analyzer/commands/domains.ts \
  src/har-analyzer/commands/errors.ts \
  src/har-analyzer/commands/export.ts \
  src/har-analyzer/commands/waterfall.ts; do
  echo "---- $f"
  if [ -f "$f" ]; then
    sed -n '1,180p' "$f"
  fi
done

# Inspect MCP server filter population
sed -n '130,220p' src/har-analyzer/mcp/server.ts
sed -n '340,420p' src/har-analyzer/mcp/server.ts

# Inspect macos clone filters usage
sed -n '1,120p' src/macos/lib/clones/filters.ts

Repository: genesiscz/GenesisTools

Length of output: 36153


Replace matchGlob’s RegExp-based glob matcher with a linear * wildcard matcher

matchGlob() escapes regex metacharacters but still converts every * to .* inside new RegExp(\^${escaped}$`, "i"). Since glob patterns come directly from user inputs (e.g., har-analyzer list/search/waterfalloptions like--domain, --url, --type, and MCP har_listargs), hostile patterns can generate backtracking-heavy regexes like^.*a.*a.*a.*a.*b$` that can lead to slow evaluation/DoS on long candidate strings.

Proposed fix
 export function matchGlob(value: string, pattern: string): boolean {
-    const escaped = pattern.replace(/[.+^${}()|[\]\\?]/g, "\\$&").replace(/\*/g, ".*");
-    return new RegExp(`^${escaped}$`, "i").test(value);
+    const input = value.toLowerCase();
+    const glob = pattern.toLowerCase();
+    let inputIndex = 0;
+    let globIndex = 0;
+    let starIndex = -1;
+    let retryIndex = 0;
+
+    while (inputIndex < input.length) {
+        if (globIndex < glob.length && glob[globIndex] === "*") {
+            starIndex = globIndex++;
+            retryIndex = inputIndex;
+            continue;
+        }
+
+        if (globIndex < glob.length && glob[globIndex] === input[inputIndex]) {
+            globIndex++;
+            inputIndex++;
+            continue;
+        }
+
+        if (starIndex === -1) {
+            return false;
+        }
+
+        globIndex = starIndex + 1;
+        inputIndex = ++retryIndex;
+    }
+
+    while (globIndex < glob.length && glob[globIndex] === "*") {
+        globIndex++;
+    }
+
+    return globIndex === glob.length;
 }
🧰 Tools
🪛 ast-grep (0.42.3)

[warning] 123-123: Regular expression constructed from variable input detected. This can lead to Regular Expression Denial of Service (ReDoS) attacks if the variable contains malicious patterns. Use libraries like 'recheck' to validate regex safety or use static patterns.
Context: new RegExp(^${escaped}$, "i")
Note: [CWE-1333] Inefficient Regular Expression Complexity [REFERENCES]
- https://owasp.org/www-community/attacks/Regular_expression_Denial_of_Service_-_ReDoS
- https://cwe.mitre.org/data/definitions/1333.html

(regexp-from-variable)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/core/src/string.ts` around lines 122 - 124, The matchGlob function
currently builds a RegExp from the pattern and replaces '*' with '.*', which is
vulnerable to catastrophic backtracking; replace that with a linear,
case-insensitive '*' wildcard matcher inside matchGlob: treat '*' as "match any
string" by splitting the pattern on '*' into literal segments, lower-case both
pattern and value once, handle edge cases for leading/trailing '*' (must match
prefix/suffix when absent), and iterate using indexOf to find each segment in
order (advancing the search index) to ensure segments appear sequentially; also
handle exact-match when pattern contains no '*' and return true for a pattern
consisting only of '*' or empty segments accordingly.

Comment thread src/json/index.ts
import { runTool } from "@app/utils/cli";
import { SafeJSON } from "@app/utils/json";
import { handleReadmeFlag } from "@app/utils/readme";
import { SafeJSON } from "@gt/core/json";

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.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Import SafeJSON from the canonical path.

The coding guideline mandates importing SafeJSON from @app/utils/json for all files under src/**/*.ts, but this imports from @gt/core/json directly. Since src/utils/json.ts is now a re-export shim, importing from @app/utils/json will resolve to the same module while maintaining consistency with the established guideline.

📋 Recommended fix to align with coding guidelines
-import { SafeJSON } from "`@gt/core/json`";
+import { SafeJSON } from "`@app/utils/json`";

As per coding guidelines: Always import and use SafeJSON from @app/utils/json instead of the global JSON object.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import { SafeJSON } from "@gt/core/json";
import { SafeJSON } from "`@app/utils/json`";
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/json/index.ts` at line 6, The file imports SafeJSON from the wrong
module; change the import so SafeJSON is imported from the canonical re-export
path by replacing the current import of SafeJSON from "`@gt/core/json`" with an
import from "`@app/utils/json`" (update the import statement in src/json/index.ts
that references SafeJSON accordingly) to comply with the guideline and use the
project's shim.

import { isVerbose, runTool } from "@app/utils/cli";
import { SafeJSON } from "@app/utils/json";
import { handleReadmeFlag } from "@app/utils/readme";
import { SafeJSON } from "@gt/core/json";

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.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Import SafeJSON from the canonical path.

The coding guideline mandates importing SafeJSON from @app/utils/json for all files under src/**/*.ts, but this imports from @gt/core/json directly. Since src/utils/json.ts is now a re-export shim, importing from @app/utils/json will resolve to the same module while maintaining consistency with the established guideline.

📋 Recommended fix to align with coding guidelines
-import { SafeJSON } from "`@gt/core/json`";
+import { SafeJSON } from "`@app/utils/json`";

As per coding guidelines: Always import and use SafeJSON from @app/utils/json instead of the global JSON object.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import { SafeJSON } from "@gt/core/json";
import { SafeJSON } from "`@app/utils/json`";
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/npm-package-diff/index.ts` at line 10, Replace the non-canonical import
of SafeJSON in src/npm-package-diff/index.ts: change the import source from
"`@gt/core/json`" to the canonical shim "`@app/utils/json`" so the file imports
SafeJSON from the project re-export (keeping the same imported symbol name
SafeJSON); update the import statement that currently references SafeJSON to use
"`@app/utils/json`" to comply with the coding guideline.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant