feat(monorepo): Turborepo build-pipeline foundation — @gt/core (approach 2 of 3)#191
feat(monorepo): Turborepo build-pipeline foundation — @gt/core (approach 2 of 3)#191genesiscz wants to merge 2 commits into
Conversation
📝 WalkthroughWalkthroughThis pull request establishes a monorepo foundation by extracting 10 shared utility modules from ChangesFoundation Monorepo Setup
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
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, "../.."); |
There was a problem hiding this comment.
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.
| export const PROJECT_ROOT = resolve(import.meta.dirname, "../.."); | |
| export const PROJECT_ROOT = resolve(import.meta.dirname, "../../.."); |
References
- Centralize shared configuration values and directory paths into a single source of truth (e.g., a dedicated
paths.tsutility) to eliminate duplication and ensure consistency across multiple modules.
|
|
||
| if (!_resolveLocale) { | ||
| // Lazy require so Vite won't bundle node:child_process into client code. | ||
| _resolveLocale = (require("./date-locale") as { getSystemLocale: () => string }).getSystemLocale; |
There was a problem hiding this comment.
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
- The GenesisTools project is designed to be Bun-only; portability to other runtimes is not a design goal.
| "dependencies": { | ||
| "comment-json": "^4.6.2" | ||
| } |
There was a problem hiding this comment.
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"
}There was a problem hiding this comment.
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
⛔ Files ignored due to path filters (1)
bun.lockis excluded by!**/*.lock
📒 Files selected for processing (36)
.gitignoreMONOREPO-PLAN.mdMONOREPO-SPEC.mdpackage.jsonpackages/core/package.jsonpackages/core/src/Stopwatch.tspackages/core/src/array.tspackages/core/src/date.tspackages/core/src/format.tspackages/core/src/json.tspackages/core/src/math.test.tspackages/core/src/math.tspackages/core/src/object.tspackages/core/src/paths.client.test.tspackages/core/src/paths.client.tspackages/core/src/paths.tspackages/core/src/string.tspackages/core/tsconfig.jsonsrc/files-to-prompt/index.tssrc/json/index.tssrc/last-changes/index.tssrc/npm-package-diff/index.tssrc/timer/index.tssrc/usage/index.tssrc/utils/Stopwatch.tssrc/utils/array.tssrc/utils/date.tssrc/utils/format.tssrc/utils/json.tssrc/utils/math.tssrc/utils/object.tssrc/utils/paths.client.tssrc/utils/paths.tssrc/utils/search/stores/vector-store.tssrc/utils/string.tsturbo.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 useSafeJSONfrom@app/utils/jsoninstead of the globalJSONobject; useSafeJSON.parse()andSafeJSON.stringify()everywhere
Uselogger(from@app/logger) for diagnostics; write to day-stamped file always and to stderr only when log level permits; useout.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
Prefererror: errovererror: err instanceof Error ? err.message : String(err)when the error field accepts unknown type
Files:
src/utils/Stopwatch.tssrc/utils/search/stores/vector-store.tssrc/usage/index.tssrc/files-to-prompt/index.tssrc/last-changes/index.tssrc/timer/index.tssrc/utils/json.tssrc/utils/array.tssrc/npm-package-diff/index.tssrc/utils/math.tssrc/utils/string.tssrc/utils/object.tssrc/utils/paths.client.tssrc/utils/format.tssrc/utils/date.tssrc/json/index.tssrc/utils/paths.ts
src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
src/**/*.{ts,tsx}: Do not useas anytype 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 barecatch {}blocks; at minimum log the caught error with context usinglogger.debug()orlogger.warn()
For functions with 3+ parameters or optional parameters, use an object parameter instead of positional parameters
Do not use one-lineifstatements, even for early returns; always use block form with braces
Add an empty line beforeifstatements unless the preceding line is a variable declaration used by thatif
Add an empty line after closing}unless followed byelse,catch,finally, or another}
Always checkisInteractive()from@app/utils/clibefore showing prompts; provide sensible defaults or error withsuggestCommand()in non-interactive mode
Files:
src/utils/Stopwatch.tssrc/utils/search/stores/vector-store.tssrc/usage/index.tssrc/files-to-prompt/index.tssrc/last-changes/index.tssrc/timer/index.tssrc/utils/json.tssrc/utils/array.tssrc/npm-package-diff/index.tssrc/utils/math.tssrc/utils/string.tssrc/utils/object.tssrc/utils/paths.client.tssrc/utils/format.tssrc/utils/date.tssrc/json/index.tssrc/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 contextbeforebuildContext()
Files:
src/utils/Stopwatch.tssrc/utils/search/stores/vector-store.tspackages/core/src/object.tssrc/usage/index.tssrc/files-to-prompt/index.tssrc/last-changes/index.tspackages/core/src/array.tssrc/timer/index.tspackages/core/src/Stopwatch.tssrc/utils/json.tssrc/utils/array.tssrc/npm-package-diff/index.tspackages/core/src/math.tspackages/core/src/json.tssrc/utils/math.tssrc/utils/string.tssrc/utils/object.tssrc/utils/paths.client.tssrc/utils/format.tssrc/utils/date.tssrc/json/index.tspackages/core/src/string.tspackages/core/src/paths.client.tssrc/utils/paths.tspackages/core/src/paths.tspackages/core/src/format.tspackages/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.tssrc/utils/search/stores/vector-store.tssrc/utils/json.tssrc/utils/array.tssrc/utils/math.tssrc/utils/string.tssrc/utils/object.tssrc/utils/paths.client.tssrc/utils/format.tssrc/utils/date.tssrc/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 viabun runwhen given arguments
Tool entry points must end withawait runTool(program, { tool })from@app/utils/cli, which owns-v/--readme/help registration and console-level resolution
Files:
src/usage/index.tssrc/files-to-prompt/index.tssrc/last-changes/index.tssrc/timer/index.tssrc/npm-package-diff/index.tssrc/json/index.ts
src/*/index.ts
📄 CodeRabbit inference engine (CLAUDE.md)
Tool directories must contain either
index.ts/index.tsxor standalone.ts/.tsxfiles; tool name is derived from directory name or filename without extension
Files:
src/usage/index.tssrc/files-to-prompt/index.tssrc/last-changes/index.tssrc/timer/index.tssrc/npm-package-diff/index.tssrc/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.tssrc/utils/search/stores/vector-store.tssrc/usage/index.tssrc/files-to-prompt/index.tssrc/last-changes/index.tssrc/timer/index.tssrc/utils/json.tssrc/utils/array.tssrc/npm-package-diff/index.tssrc/utils/math.tssrc/utils/string.tssrc/utils/object.tssrc/utils/paths.client.tssrc/utils/format.tssrc/utils/date.tssrc/json/index.tssrc/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.tssrc/utils/search/stores/vector-store.tssrc/usage/index.tssrc/files-to-prompt/index.tssrc/last-changes/index.tssrc/timer/index.tssrc/utils/json.tssrc/utils/array.tssrc/npm-package-diff/index.tssrc/utils/math.tssrc/utils/string.tssrc/utils/object.tssrc/utils/paths.client.tssrc/utils/format.tssrc/utils/date.tssrc/json/index.tssrc/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.tssrc/utils/search/stores/vector-store.tssrc/usage/index.tssrc/files-to-prompt/index.tssrc/last-changes/index.tssrc/timer/index.tssrc/utils/json.tssrc/utils/array.tssrc/npm-package-diff/index.tssrc/utils/math.tssrc/utils/string.tssrc/utils/object.tssrc/utils/paths.client.tssrc/utils/format.tssrc/utils/date.tssrc/json/index.tssrc/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.tssrc/utils/search/stores/vector-store.tssrc/usage/index.tssrc/files-to-prompt/index.tssrc/last-changes/index.tssrc/timer/index.tssrc/utils/json.tssrc/utils/array.tssrc/npm-package-diff/index.tssrc/utils/math.tssrc/utils/string.tssrc/utils/object.tssrc/utils/paths.client.tssrc/utils/format.tssrc/utils/date.tssrc/json/index.tssrc/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.tssrc/utils/search/stores/vector-store.tssrc/usage/index.tssrc/files-to-prompt/index.tssrc/last-changes/index.tssrc/timer/index.tssrc/utils/json.tssrc/utils/array.tssrc/npm-package-diff/index.tssrc/utils/math.tssrc/utils/string.tssrc/utils/object.tssrc/utils/paths.client.tssrc/utils/format.tssrc/utils/date.tssrc/json/index.tssrc/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.tssrc/utils/search/stores/vector-store.tssrc/usage/index.tssrc/files-to-prompt/index.tssrc/last-changes/index.tssrc/timer/index.tssrc/utils/json.tssrc/utils/array.tssrc/npm-package-diff/index.tssrc/utils/math.tssrc/utils/string.tssrc/utils/object.tssrc/utils/paths.client.tssrc/utils/format.tssrc/utils/date.tssrc/json/index.tssrc/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.tssrc/utils/search/stores/vector-store.tssrc/usage/index.tssrc/files-to-prompt/index.tssrc/last-changes/index.tssrc/timer/index.tssrc/utils/json.tssrc/utils/array.tssrc/npm-package-diff/index.tssrc/utils/math.tssrc/utils/string.tssrc/utils/object.tssrc/utils/paths.client.tssrc/utils/format.tssrc/utils/date.tssrc/json/index.tssrc/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.tssrc/utils/search/stores/vector-store.tspackages/core/src/object.tssrc/usage/index.tssrc/files-to-prompt/index.tssrc/last-changes/index.tspackages/core/src/array.tssrc/timer/index.tspackages/core/src/Stopwatch.tssrc/utils/json.tssrc/utils/array.tssrc/npm-package-diff/index.tspackages/core/src/math.tspackages/core/src/json.tssrc/utils/math.tssrc/utils/string.tssrc/utils/object.tssrc/utils/paths.client.tssrc/utils/format.tssrc/utils/date.tssrc/json/index.tspackages/core/src/string.tspackages/core/src/paths.client.tssrc/utils/paths.tspackages/core/src/paths.tspackages/core/src/format.tspackages/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.tssrc/utils/search/stores/vector-store.tspackages/core/src/object.tssrc/usage/index.tssrc/files-to-prompt/index.tssrc/last-changes/index.tspackages/core/src/array.tssrc/timer/index.tspackages/core/src/Stopwatch.tssrc/utils/json.tssrc/utils/array.tssrc/npm-package-diff/index.tspackages/core/src/math.tspackages/core/src/json.tssrc/utils/math.tssrc/utils/string.tssrc/utils/object.tssrc/utils/paths.client.tssrc/utils/format.tssrc/utils/date.tssrc/json/index.tspackages/core/src/string.tspackages/core/src/paths.client.tssrc/utils/paths.tspackages/core/src/paths.tspackages/core/src/format.tspackages/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.tssrc/utils/search/stores/vector-store.tspackages/core/src/object.tssrc/usage/index.tssrc/files-to-prompt/index.tssrc/last-changes/index.tspackages/core/src/array.tssrc/timer/index.tspackages/core/src/Stopwatch.tssrc/utils/json.tssrc/utils/array.tssrc/npm-package-diff/index.tspackages/core/src/math.tspackages/core/src/json.tssrc/utils/math.tssrc/utils/string.tssrc/utils/object.tssrc/utils/paths.client.tssrc/utils/format.tssrc/utils/date.tssrc/json/index.tspackages/core/src/string.tspackages/core/src/paths.client.tssrc/utils/paths.tspackages/core/src/paths.tspackages/core/src/format.tspackages/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.tssrc/utils/search/stores/vector-store.tspackages/core/src/object.tssrc/usage/index.tssrc/files-to-prompt/index.tssrc/last-changes/index.tspackages/core/src/array.tssrc/timer/index.tspackages/core/src/Stopwatch.tssrc/utils/json.tssrc/utils/array.tssrc/npm-package-diff/index.tspackages/core/src/math.tspackages/core/src/json.tssrc/utils/math.tssrc/utils/string.tssrc/utils/object.tssrc/utils/paths.client.tssrc/utils/format.tssrc/utils/date.tssrc/json/index.tspackages/core/src/string.tspackages/core/src/paths.client.tssrc/utils/paths.tspackages/core/src/paths.tspackages/core/src/format.tspackages/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.tssrc/utils/search/stores/vector-store.tspackages/core/src/object.tssrc/usage/index.tssrc/files-to-prompt/index.tssrc/last-changes/index.tspackages/core/src/array.tssrc/timer/index.tspackages/core/src/Stopwatch.tssrc/utils/json.tssrc/utils/array.tssrc/npm-package-diff/index.tspackages/core/src/math.tspackages/core/src/json.tssrc/utils/math.tssrc/utils/string.tssrc/utils/object.tssrc/utils/paths.client.tssrc/utils/format.tssrc/utils/date.tssrc/json/index.tspackages/core/src/string.tspackages/core/src/paths.client.tssrc/utils/paths.tspackages/core/src/paths.tspackages/core/src/format.tspackages/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.tssrc/utils/search/stores/vector-store.tspackages/core/src/object.tssrc/usage/index.tssrc/files-to-prompt/index.tssrc/last-changes/index.tspackages/core/src/array.tssrc/timer/index.tspackages/core/src/Stopwatch.tssrc/utils/json.tssrc/utils/array.tssrc/npm-package-diff/index.tspackages/core/src/math.tspackages/core/src/json.tssrc/utils/math.tssrc/utils/string.tssrc/utils/object.tssrc/utils/paths.client.tssrc/utils/format.tssrc/utils/date.tssrc/json/index.tspackages/core/src/string.tspackages/core/src/paths.client.tssrc/utils/paths.tspackages/core/src/paths.tspackages/core/src/format.tspackages/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.tssrc/utils/search/stores/vector-store.tspackages/core/src/object.tssrc/usage/index.tssrc/files-to-prompt/index.tssrc/last-changes/index.tspackages/core/src/array.tssrc/timer/index.tspackages/core/src/Stopwatch.tssrc/utils/json.tssrc/utils/array.tssrc/npm-package-diff/index.tspackages/core/src/math.tspackages/core/src/json.tssrc/utils/math.tssrc/utils/string.tssrc/utils/object.tssrc/utils/paths.client.tssrc/utils/format.tssrc/utils/date.tssrc/json/index.tspackages/core/src/string.tspackages/core/src/paths.client.tssrc/utils/paths.tspackages/core/src/paths.tspackages/core/src/format.tspackages/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.tssrc/utils/search/stores/vector-store.tspackages/core/src/object.tssrc/usage/index.tssrc/files-to-prompt/index.tssrc/last-changes/index.tspackages/core/src/array.tssrc/timer/index.tspackages/core/src/Stopwatch.tssrc/utils/json.tssrc/utils/array.tssrc/npm-package-diff/index.tspackages/core/src/math.tspackages/core/src/json.tssrc/utils/math.tssrc/utils/string.tssrc/utils/object.tssrc/utils/paths.client.tssrc/utils/format.tssrc/utils/date.tssrc/json/index.tspackages/core/src/string.tspackages/core/src/paths.client.tssrc/utils/paths.tspackages/core/src/paths.tspackages/core/src/format.tspackages/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.tssrc/utils/search/stores/vector-store.tssrc/utils/json.tssrc/utils/array.tssrc/utils/math.tssrc/utils/string.tssrc/utils/object.tssrc/utils/paths.client.tssrc/utils/format.tssrc/utils/date.tssrc/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.tssrc/utils/search/stores/vector-store.tssrc/utils/json.tssrc/utils/array.tssrc/utils/math.tssrc/utils/string.tssrc/utils/object.tssrc/utils/paths.client.tssrc/utils/format.tssrc/utils/date.tssrc/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.tssrc/utils/search/stores/vector-store.tspackages/core/src/object.tssrc/usage/index.tssrc/files-to-prompt/index.tssrc/last-changes/index.tspackages/core/src/array.tssrc/timer/index.tspackages/core/src/Stopwatch.tssrc/utils/json.tssrc/utils/array.tssrc/npm-package-diff/index.tspackages/core/src/math.tspackages/core/src/json.tssrc/utils/math.tssrc/utils/string.tssrc/utils/object.tssrc/utils/paths.client.tssrc/utils/format.tssrc/utils/date.tssrc/json/index.tspackages/core/src/string.tspackages/core/src/paths.client.tssrc/utils/paths.tspackages/core/src/paths.tspackages/core/src/format.tspackages/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.tssrc/utils/search/stores/vector-store.tspackages/core/src/object.tssrc/usage/index.tssrc/files-to-prompt/index.tssrc/last-changes/index.tspackages/core/src/array.tssrc/timer/index.tspackages/core/src/Stopwatch.tssrc/utils/json.tssrc/utils/array.tssrc/npm-package-diff/index.tspackages/core/src/math.tspackages/core/src/json.tssrc/utils/math.tssrc/utils/string.tssrc/utils/object.tssrc/utils/paths.client.tssrc/utils/format.tssrc/utils/date.tssrc/json/index.tspackages/core/src/string.tspackages/core/src/paths.client.tssrc/utils/paths.tspackages/core/src/paths.tspackages/core/src/format.tspackages/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.tssrc/utils/search/stores/vector-store.tssrc/usage/index.tssrc/files-to-prompt/index.tssrc/last-changes/index.tssrc/timer/index.tssrc/utils/json.tssrc/utils/array.tssrc/npm-package-diff/index.tssrc/utils/math.tssrc/utils/string.tssrc/utils/object.tssrc/utils/paths.client.tssrc/utils/format.tssrc/utils/date.tssrc/json/index.tssrc/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.tssrc/files-to-prompt/index.tssrc/last-changes/index.tssrc/timer/index.tssrc/npm-package-diff/index.tssrc/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.mdMONOREPO-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.mdMONOREPO-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/jsonkeeps back-compatSafeJSON+parseJSONexports
src/utils/json.tsisexport * from "@gt/core/json";, andpackages/core/src/json.tsexports namedSafeJSONandparseJSON, so both symbols remain available to consumers (e.g.,src/har-analyzer/commands/show.tsimportsparseJSONfrom@app/utils/json).packages/core/src/json.ts (2)
1-82: LGTM!
45-45: ⚡ Quick winCheck that
options.unboxis the right boolean for comment-json’s 3rd arg (removesComments).
comment-json@4.6.2typings defineparse(json, reviver?, removesComments?: boolean); this code callsparse(text, options.reviver, options.unbox), sooptions.unboxshould 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!
| | 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/*` | | ||
|
|
There was a problem hiding this comment.
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.
| ``` | ||
| ┌────────────┐ | ||
| │ @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) │ | ||
| └─────────────────────────────────────────────────────┘ | ||
| ``` |
There was a problem hiding this comment.
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.
| ``` | |
| ┌────────────┐ | |
| │ @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.
| 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(); | ||
| } |
There was a problem hiding this comment.
🧩 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*' || trueRepository: 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*' || trueRepository: 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*' || trueRepository: 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 || trueRepository: 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.tsRepository: 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`['\"]" . || trueRepository: 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/srcRepository: 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 || trueRepository: 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 . || trueRepository: 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 . || trueRepository: 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" . || trueRepository: 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.tsdoesrequire("./date-locale"), but there is nopackages/core/src/date-locale.tsin the package (the onlygetSystemLocaleissrc/utils/date-locale.ts), soresolveLocale()(called byformatDateTime()with no locale override by default) will fail to load.- Even if the module existed,
@gt/coreis"type":"module"and thedefaultexport targetsdist/date.js, whererequireis unavailable; usecreateRequire(import.meta.url)orimport()and ensure the locale file is actually part of thetsup src/*.tsbuild 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.
| 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]; | ||
| } |
There was a problem hiding this comment.
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: accessingb[i]beyond its bounds returnsundefined, yieldingNaNin the dot product and norms. - When
b.length > a.length: elements inbbeyond indexa.lengthare 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.
| 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]; |
There was a problem hiding this comment.
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.
| 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("/")}`; | ||
| } |
There was a problem hiding this comment.
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.
| export function matchGlob(value: string, pattern: string): boolean { | ||
| const escaped = pattern.replace(/[.+^${}()|[\]\\?]/g, "\\$&").replace(/\*/g, ".*"); | ||
| return new RegExp(`^${escaped}$`, "i").test(value); |
There was a problem hiding this comment.
🧩 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 200Repository: 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 200Repository: 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.tsRepository: 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.tsRepository: 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.
| import { runTool } from "@app/utils/cli"; | ||
| import { SafeJSON } from "@app/utils/json"; | ||
| import { handleReadmeFlag } from "@app/utils/readme"; | ||
| import { SafeJSON } from "@gt/core/json"; |
There was a problem hiding this comment.
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.
| 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"; |
There was a problem hiding this comment.
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.
| 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.
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
turbo@2.7.3, pinned) over Bun workspaces, with aturbo.jsondependsOngraph forbuild/typecheck/lint/test.exportsmaps (conditionsbun → types → default):bun/typesresolve to source.tsso Bun runs andtsgotypechecks without a build step (no-build invariant intact);default → distis additive (CI artifact / isolated typecheck / future publish), never on the./toolsrun path.@gt/core(packages/core/): array, date, format, json, math, object, paths, paths.client, string, Stopwatch. Each oldsrc/utils/<f>.tsbecomes a pure re-export shim.json,npm-package-diff,files-to-prompt,last-changes,timer,usage).Green bar (independently verified)
tsgo --noEmit= 0 errors (== master baseline; proven meaningful via an injected-then-reverted type error)turbo run typecheck --filter=@gt/coregreen, with a full cache hit on rerun (904ms → 62ms)./tools+ migrated tools + the shim path smoke-run; biome cleanDeferred (documented in
MONOREPO-SPEC.md§6 /MONOREPO-PLAN.md)cli ↔ logger ↔ promptscycle (invert theprompts → @app/doctorleak), then extract@gt/logger+@gt/cli@gt/storage,@gt/ui(666-import@ui/*surface),@gt/aiapps/*; CI wiring + turbo remote cacheTrade-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.🤖 Generated via a multi-agent design→implement→verify workflow.
Summary by CodeRabbit