Skip to content

feat: CLI should respect tsconfig.json for path resolution and general configuration#1013

Merged
yamcodes merged 4 commits into
mainfrom
908-cli-should-respect-tsconfigjson-for-path-resolution-and-general-configuration-1
May 16, 2026
Merged

feat: CLI should respect tsconfig.json for path resolution and general configuration#1013
yamcodes merged 4 commits into
mainfrom
908-cli-should-respect-tsconfigjson-for-path-resolution-and-general-configuration-1

Conversation

@yamcodes

@yamcodes yamcodes commented May 16, 2026

Copy link
Copy Markdown
Owner

Fixes #908

The Arkenv CLI now dynamically resolves configuration paths and scans project files by respecting tsconfig.json settings (rootDir, paths, baseUrl).

Key improvements include:

  • Robust tsconfig Parser: Added support for parsing tsconfig.json files with comments (jsonc-parser), handling extends, rootDir, baseUrl, and paths alias resolution.
  • Dynamic Scaffolding Defaults: Updated init scaffolding logic to suggest project-appropriate default paths based on compilerOptions.rootDir rather than hardcoding ./src/env.ts.
  • Advanced Environment Scanning: Enhanced getEnvExampleKeys to scan project source files for process.env and import.meta.env usages, correctly resolving aliased imports (e.g. @/env).
  • Framework & Package Manager Detection: Leverages parsed tsconfig.json context to accurately identify project frameworks and package managers.

Summary by CodeRabbit

  • New Features

    • CLI now respects tsconfig.json for path resolution and scaffolding, including rootDir, baseUrl, and path aliases
    • Enhanced environment scanning to detect process.env and import.meta.env usages with alias import resolution
    • Improved framework and package-manager detection leveraging tsconfig.json configuration
  • Tests

    • Added comprehensive test coverage for new scanning and path resolution functionality
  • Chores

    • Internal code optimizations and cleanup

Review Change Stack

@yamcodes yamcodes added bug Something isn't working enhancement New feature or improvement @arkenv/cli Issues or Pull Requests involving the ArkEnv CLI labels May 16, 2026
@changeset-bot

changeset-bot Bot commented May 16, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: a2da92d

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@arkenv/cli Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@coderabbitai

coderabbitai Bot commented May 16, 2026

Copy link
Copy Markdown
Contributor

Warning

Rate limit exceeded

@yamcodes has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 37 minutes and 39 seconds before requesting another review.

You’ve run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: f9b4f5c2-2f68-41a8-ae77-0bf90ce5fe9e

📥 Commits

Reviewing files that changed from the base of the PR and between 1720d05 and a2da92d.

📒 Files selected for processing (24)
  • .changeset/respect-tsconfig-cli.md
  • packages/cli/src/adapters/index.ts
  • packages/cli/src/adapters/node-project-scanner/index.ts
  • packages/cli/src/adapters/node-project-scanner/node-project-scanner.adapter.test.ts
  • packages/cli/src/adapters/node-project-scanner/node-project-scanner.adapter.ts
  • packages/cli/src/adapters/node-workspace/node-workspace.test.ts
  • packages/cli/src/adapters/node-workspace/node-workspace.ts
  • packages/cli/src/adapters/prompt.adapter.ts
  • packages/cli/src/cli/commands/init.ts
  • packages/cli/src/cli/composition.ts
  • packages/cli/src/cli/ui/prompts.test.ts
  • packages/cli/src/cli/ui/prompts/steps.ts
  • packages/cli/src/cli/ui/prompts/wizard.ts
  • packages/cli/src/features/scaffold/env-parser.test.ts
  • packages/cli/src/features/scaffold/env-parser.ts
  • packages/cli/src/features/scaffold/index.ts
  • packages/cli/src/features/scaffold/scaffold.test.ts
  • packages/cli/src/features/scaffold/scaffold.ts
  • packages/cli/src/shared/ports/index.ts
  • packages/cli/src/shared/ports/project-scanner.port.ts
  • packages/cli/src/shared/ports/prompt.port.ts
  • packages/fumadocs-ui/src/components/ai-actions.tsx
  • skills/skill-creator/assets/eval-review.html
  • skills/skill-creator/eval-viewer/viewer.html
📝 Walkthrough

Walkthrough

This PR adds comprehensive TypeScript configuration (tsconfig.json) support to the ArkEnv CLI, enabling dynamic scaffolding defaults based on project structure. Unrelated code cleanup improves style and import hygiene across tests and HTML rendering.

Changes

tsconfig-Aware CLI Feature

Layer / File(s) Summary
TypeScript Configuration Parser
packages/cli/src/features/scaffold/tsconfig-parser.ts, packages/cli/src/features/scaffold/index.ts
New tsconfig-parser module exports findTsConfig, loadTsConfig, and resolveImportPath to locate, parse (with JSONC comment support), recursively resolve extends, and resolve path aliases and baseUrl-relative imports.
Scaffold Feature Integration
packages/cli/src/features/scaffold/scaffold.ts, packages/cli/src/features/scaffold/scaffold.test.ts
checkTsConfig now returns parsed config, detectFramework and detectPackageManager accept optional tsConfig for early-return type detection, and new suggestDefaultEnvPath derives env.ts location from compilerOptions.rootDir with fallback to ./src/ or ./env.ts.
Project Environment Variable Scanning
packages/cli/src/features/scaffold/env-parser.ts, packages/cli/src/features/scaffold/env-parser.test.ts
New scanProjectEnvKeys recursively finds process.env.*, import.meta.env.*, and alias-resolved env usage; getEnvExampleKeys now returns { keys, source } and falls back to project scanning when .env.example is unavailable.
CLI Init Command Orchestration
packages/cli/src/cli/commands/init.ts
Loads and parses tsconfig, computes defaultEnvPath, and passes both through the wizard pipeline alongside the detected framework for context-aware scaffolding.
Prompt Adapter & Wizard Refactoring
packages/cli/src/adapters/prompt.adapter.ts, packages/cli/src/shared/ports/prompt.port.ts, packages/cli/src/cli/ui/prompts/steps.ts, packages/cli/src/cli/ui/prompts/wizard.ts
Prompt steps and wizard accept configurable defaultEnvPath and tsConfig, parameterizing prompt factories instead of using hardcoded ./src/env.ts, and wiring env-example detection through the prompts.

Code Cleanup & Refactoring

Layer / File(s) Summary
Import & Parameter Cleanup
apps/www/hooks/use-copy-command.test.ts, packages/arkenv/src/standard-mode.test.ts
Removes unused waitFor import and renames unused parameter to _value convention.
Console Logging & Styling
packages/fumadocs-ui/src/components/ai-actions.tsx, packages/fumadocs-ui/src/components/header.tsx
Removes console error logging from clipboard copy error, refactors string concatenation to template literal for mobile menu path matching.
Eval Review & Viewer HTML Refactoring
skills/skill-creator/assets/eval-review.html, skills/skill-creator/eval-viewer/viewer.html
Converts HTML string concatenation to template literals with safe escaping; renames global UI functions to underscore-prefixed form (updateQuery_updateQuery, toggleGrades_toggleGrades, etc.); adds optional chaining for previous data lookups.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • yamcodes/arkenv#998: Also refactors the init command orchestration layer; this PR updates how tsconfig and defaultEnvPath are threaded through the command, while that PR restructures command state collection and executor delegation.

Suggested labels

refactor

Poem

🐰 Twitching whiskers at typescript configs so fine,
rootDir guides the way, no more ./src hardcoded line,
Env vars scatter across the project tree,
Scaffolding flows with tsconfig in harmony,
Plus template strings and proper names so clean!

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning Several unrelated changes are included: unused import removals in test files, underscore-prefix renaming of global functions in HTML files, template literal conversions, and unused parameter renames that fall outside tsconfig functionality scope. Separate unrelated cleanup tasks (unused imports, refactoring HTML functions, template literal conversions) into dedicated PRs to keep this PR focused on tsconfig.json integration.
Docstring Coverage ⚠️ Warning Docstring coverage is 75.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: CLI now respects tsconfig.json for path resolution and general configuration.
Linked Issues check ✅ Passed The PR implements all core requirements from issue #908: tsconfig.json parsing with extends support, rootDir-based path suggestions, flexible fallback, path alias resolution, and improved framework/package-manager detection.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch 908-cli-should-respect-tsconfigjson-for-path-resolution-and-general-configuration-1

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@github-actions github-actions Bot added docs Adds or changes documentation, or acts as documentation in and of itself arkenv Changes to the `arkenv` npm package. www Improvements or additions to arkenv.js.org tests This issue or PR is about adding, removing or changing tests @arkenv/fumadocs-ui Issues or Pull Requests involving the ArkEnv Fumadocs UI theme labels May 16, 2026
@arkenv-bot

arkenv-bot Bot commented May 16, 2026

Copy link
Copy Markdown
Contributor

🤖 Hi @yamcodes, I've received your request, and I'm working on it now! You can track my progress in the logs for more details.

@pkg-pr-new

pkg-pr-new Bot commented May 16, 2026

Copy link
Copy Markdown

Open in StackBlitz

arkenv

npm i https://pkg.pr.new/arkenv@1013

@arkenv/bun-plugin

npm i https://pkg.pr.new/@arkenv/bun-plugin@1013

@arkenv/cli

npm i https://pkg.pr.new/@arkenv/cli@1013

@arkenv/fumadocs-ui

npm i https://pkg.pr.new/@arkenv/fumadocs-ui@1013

@arkenv/vite-plugin

npm i https://pkg.pr.new/@arkenv/vite-plugin@1013

commit: a2da92d

@arkenv-bot

arkenv-bot Bot commented May 16, 2026

Copy link
Copy Markdown
Contributor

📦 Bundle Size Report

Package Size Limit Diff Status
arkenv 1.73 kB 1.95 kB 0.0%
arkenv/standard 1.01 kB 1.07 kB 0.0%
arkenv/core 441 B 500 B 0.0%

All size limits passed!

@arkenv-bot

arkenv-bot Bot commented May 16, 2026

Copy link
Copy Markdown
Contributor

🤖 I'm sorry @yamcodes, but I was unable to process your request. Please see the logs for more details.

@yamcodes

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented May 16, 2026

Copy link
Copy Markdown
Contributor
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@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: 10

🧹 Nitpick comments (1)
packages/fumadocs-ui/src/components/ai-actions.tsx (1)

55-55: ⚖️ Poor tradeoff

Consider adding user-facing error feedback.

The empty catch block silently swallows clipboard errors. While the button won't show a checkmark on failure (providing basic visual feedback), users may not understand why the copy operation failed. Clipboard API failures can occur due to browser permissions, HTTPS requirements, or network issues when fetching the markdown content.

💡 Potential improvement

Consider adding simple error feedback, such as:

+const [error, setError] = useState<string | null>(null);
+
 const [checked, onClick] = useCopyButton(async () => {
+  setError(null);
   const cached = cache.get(markdownUrl);
   if (cached) return navigator.clipboard.writeText(cached);
 
   setLoading(true);
 
   try {
     await navigator.clipboard.write([
       // ...
     ]);
-  } catch (_err) {
+  } catch (err) {
+    setError("Failed to copy. Please check permissions and try again.");
   } finally {
     setLoading(false);
   }
 });

Then display the error message near the button when present.

🤖 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/fumadocs-ui/src/components/ai-actions.tsx` at line 55, The catch
block in packages/fumadocs-ui/src/components/ai-actions.tsx that swallows
clipboard errors should surface a user-facing error message: capture the caught
error (use _err or err), log it (console.error or a logger), set a local React
state (e.g. copyError via useState) with err.message or a friendly string, and
display that state near the copy button (small inline text or tooltip) so users
see why the clipboard action failed; ensure you clear the error on a successful
copy or after a timeout.
🤖 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 @.changeset/respect-tsconfig-cli.md:
- Around line 10-13: Change the inconsistent present tense in the release notes
by updating the fourth bullet "Framework & Package Manager Detection: Leverages
parsed `tsconfig.json` context..." to past tense (e.g., "Leveraged parsed
`tsconfig.json` context...") and scan the other bullets to ensure they all use
past tense (e.g., "Added", "Updated", "Enhanced", "Leveraged") so the four
bullets are stylistically consistent.

In `@packages/cli/src/cli/ui/prompts/steps.ts`:
- Around line 72-77: The prompt handler currently returns the raw text() answer
verbatim, allowing whitespace-only input; update the block that awaits text(...)
(the answer variable) so you trim the string and, if the trimmed result is
empty, fall back to defaultEnvPath before returning — still return null when
isCancel(answer) is true; reference the text(...) call, the answer variable,
isCancel(answer) check, and defaultEnvPath when making the change.

In `@packages/cli/src/features/scaffold/scaffold.ts`:
- Around line 200-205: The code returns a relative env path that can escape the
workspace when currentTsConfig.compilerOptions.rootDir is outside cwd; update
the logic around the rootDir handling (the block using currentTsConfig, rootDir,
rel and path.relative) to detect when rootDir is outside cwd (e.g., rel is
empty? or rel === "." is fine, but if rel startsWith("..") or
path.isAbsolute(rootDir) resolving outside cwd) and in that case fall back to
"./env.ts" instead of returning a "../..." path; otherwise continue returning
`./${rel}/env.ts` as before. Ensure you reference the existing symbols
currentTsConfig, compilerOptions.rootDir, path.relative, cwd and the rootDir/rel
variables when making the change.

In `@packages/cli/src/features/scaffold/tsconfig-parser.ts`:
- Around line 64-81: Detected potential infinite recursion when following
parsed.extends chains; add cycle protection by tracking visited config file
paths (use a Set of resolved absolute paths) and checking before recursing.
Concretely, update loadTsConfig to accept an optional visited:Set<string> (or
create one at entry), resolve each ext to an absolute path (extPath) as you
already do, then if visited.has(extPath) skip or throw a clear error instead of
calling await loadTsConfig(extPath); otherwise add extPath to visited before
recursing and pass visited down to the recursive loadTsConfig call. Ensure the
initial call seeds the visited set with the top-level configPath.
- Around line 144-153: The current alias matching uses startsWith(cleanPattern)
and returns the first target, which allows unintended prefix matches and picks a
non-specific alias; update the resolve logic in tsconfig-parser.ts to (1)
distinguish patterns that end with '*' from exact patterns: only allow prefix
matches when the original pattern had a trailing '*' and require full equality
when it did not, and (2) prefer the most specific alias by selecting the longest
cleanPattern match instead of returning the first match—e.g., compute
cleanPattern and a boolean hadStar from pattern, collect matching entries, sort
or pick the one with the largest cleanPattern.length, then map that match's
targets to cleanTarget/targetRel and resolve with path.resolve(baseUrl,
targetRel).
- Around line 73-77: The code uses require.resolve(...) to compute extPath (the
variable assigned on line with require.resolve) which fails in ESM; replace that
call with an ESM-compatible resolver: use import.meta.resolve(ext, { paths:
[path.dirname(configPath)] }) (await the promise) and convert the returned URL
to a filesystem path if necessary (e.g., with fileURLToPath) before assigning to
extPath; keep the existing fallback that sets extPath =
path.resolve(path.dirname(configPath), "node_modules", ext) inside the catch
path. Alternatively, if you must support older Node versions, create a require
via createRequire(import.meta.url) from "module" and call requireResolve =
createRequire(...).resolve(ext, { paths: [...] }) in place of require.resolve.
Ensure you update the surrounding function (where extPath is used) to be async
if using import.meta.resolve and handle errors consistently.

In `@packages/cli/src/shared/ports/prompt.port.ts`:
- Around line 11-12: Change the tsConfig parameter type from any to the concrete
ParsedTsConfig | null across the init → adapter → wizard pipeline: update the
port's tsConfig declaration (the interface exposing tsConfig), change the
adapter function signature that passes tsConfig to getEnvExampleKeys(), and
update the wizard prompt parameter types to accept ParsedTsConfig | null; add
import type { ParsedTsConfig } from "`@/features/scaffold/tsconfig-parser`" in
each affected file and ensure calls to getEnvExampleKeys(tsConfig) match the new
type.

In `@skills/skill-creator/assets/eval-review.html`:
- Around line 111-113: The HTML still calls the old global names (addRow,
exportEvalSet, updateQuery, updateTrigger, deleteRow) while your JS renamed them
(_updateQuery, _updateTrigger, etc.), causing ReferenceError; restore
compatibility by adding thin global wrapper functions that map the old names to
the new ones (for example implement global functions addRow(...) that call the
new addRow implementation or exportEvalSet(...) that calls the renamed function,
and implement updateQuery(idx,val){ return _updateQuery(idx,val); },
updateTrigger(idx,val){ return _updateTrigger(idx,val); }, deleteRow(idx){
return _deleteRow(idx); }) so the inline HTML handlers keep working without
changing markup.

In `@skills/skill-creator/eval-viewer/viewer.html`:
- Around line 1132-1134: The concatenation that builds the html string (variable
html) inserts unescaped metadata fields (metadata.timestamp, metadata.evals_run
items, metadata.runs_per_configuration and other similar interpolations)
directly into innerHTML, exposing an XSS risk; fix by escaping these values
before concatenation (add/use a helper like escapeHtml(value) and apply it to
metadata.timestamp, each entry in metadata.evals_run,
metadata.runs_per_configuration, etc.), or construct the DOM with
createElement/textContent instead of assigning raw innerHTML, and update the
code paths that build the html string (the blocks referencing html and metadata)
to use the sanitizer helper or text nodes.
- Line 907: Inline onclick handlers are failing because function declarations
like _toggleGrades were renamed or moved out of the global scope; restore the
original public handler names (e.g., _toggleGrades) or update the inline onclick
attributes to call the new names, and ensure these handlers are globally
accessible (attach them to window, e.g., window._toggleGrades = _toggleGrades)
if the functions live inside a closure; apply the same fix to the other renamed
handlers referenced around the other affected spots (lines near 986, 1026, 1063,
1106-1110).

---

Nitpick comments:
In `@packages/fumadocs-ui/src/components/ai-actions.tsx`:
- Line 55: The catch block in packages/fumadocs-ui/src/components/ai-actions.tsx
that swallows clipboard errors should surface a user-facing error message:
capture the caught error (use _err or err), log it (console.error or a logger),
set a local React state (e.g. copyError via useState) with err.message or a
friendly string, and display that state near the copy button (small inline text
or tooltip) so users see why the clipboard action failed; ensure you clear the
error on a successful copy or after a timeout.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 89f158ef-6005-4b36-b465-5975c9d1060b

📥 Commits

Reviewing files that changed from the base of the PR and between cdb1f3b and 1720d05.

📒 Files selected for processing (18)
  • .changeset/respect-tsconfig-cli.md
  • apps/www/hooks/use-copy-command.test.ts
  • packages/arkenv/src/standard-mode.test.ts
  • packages/cli/src/adapters/prompt.adapter.ts
  • packages/cli/src/cli/commands/init.ts
  • packages/cli/src/cli/ui/prompts/steps.ts
  • packages/cli/src/cli/ui/prompts/wizard.ts
  • packages/cli/src/features/scaffold/env-parser.test.ts
  • packages/cli/src/features/scaffold/env-parser.ts
  • packages/cli/src/features/scaffold/index.ts
  • packages/cli/src/features/scaffold/scaffold.test.ts
  • packages/cli/src/features/scaffold/scaffold.ts
  • packages/cli/src/features/scaffold/tsconfig-parser.ts
  • packages/cli/src/shared/ports/prompt.port.ts
  • packages/fumadocs-ui/src/components/ai-actions.tsx
  • packages/fumadocs-ui/src/components/header.tsx
  • skills/skill-creator/assets/eval-review.html
  • skills/skill-creator/eval-viewer/viewer.html

Comment thread .changeset/respect-tsconfig-cli.md Outdated
Comment thread packages/cli/src/cli/ui/prompts/steps.ts Outdated
Comment on lines +200 to +205
if (currentTsConfig?.compilerOptions?.rootDir) {
const rootDir = currentTsConfig.compilerOptions.rootDir;
const rel = path.relative(cwd, rootDir);
if (!rel || rel === ".") return "./env.ts";
return `./${rel}/env.ts`;
}

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

Prevent defaults that escape the current workspace.

When rootDir is outside cwd, this returns paths like ./../.../env.ts, which can steer scaffolding writes outside the project.

Suggested fix
 	if (currentTsConfig?.compilerOptions?.rootDir) {
 		const rootDir = currentTsConfig.compilerOptions.rootDir;
 		const rel = path.relative(cwd, rootDir);
+		if (rel.startsWith("..") || path.isAbsolute(rel)) {
+			return "./env.ts";
+		}
 		if (!rel || rel === ".") return "./env.ts";
 		return `./${rel}/env.ts`;
 	}
📝 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
if (currentTsConfig?.compilerOptions?.rootDir) {
const rootDir = currentTsConfig.compilerOptions.rootDir;
const rel = path.relative(cwd, rootDir);
if (!rel || rel === ".") return "./env.ts";
return `./${rel}/env.ts`;
}
if (currentTsConfig?.compilerOptions?.rootDir) {
const rootDir = currentTsConfig.compilerOptions.rootDir;
const rel = path.relative(cwd, rootDir);
if (rel.startsWith("..") || path.isAbsolute(rel)) {
return "./env.ts";
}
if (!rel || rel === ".") return "./env.ts";
return `./${rel}/env.ts`;
}
🤖 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/cli/src/features/scaffold/scaffold.ts` around lines 200 - 205, The
code returns a relative env path that can escape the workspace when
currentTsConfig.compilerOptions.rootDir is outside cwd; update the logic around
the rootDir handling (the block using currentTsConfig, rootDir, rel and
path.relative) to detect when rootDir is outside cwd (e.g., rel is empty? or rel
=== "." is fine, but if rel startsWith("..") or path.isAbsolute(rootDir)
resolving outside cwd) and in that case fall back to "./env.ts" instead of
returning a "../..." path; otherwise continue returning `./${rel}/env.ts` as
before. Ensure you reference the existing symbols currentTsConfig,
compilerOptions.rootDir, path.relative, cwd and the rootDir/rel variables when
making the change.

Comment on lines +64 to +81
if (parsed.extends) {
const extendsArr = Array.isArray(parsed.extends)
? parsed.extends
: [parsed.extends];
for (const ext of extendsArr) {
let extPath: string;
if (ext.startsWith(".") || path.isAbsolute(ext)) {
extPath = path.resolve(path.dirname(configPath), ext);
} else {
try {
extPath = require.resolve(ext, { paths: [path.dirname(configPath)] });
} catch {
extPath = path.resolve(path.dirname(configPath), "node_modules", ext);
}
}

const baseConfig = await loadTsConfig(extPath);
const baseOptions = { ...baseConfig.compilerOptions };

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

Add cycle protection for recursive extends loading.

A cyclic extends chain can recurse forever and eventually crash the CLI. Guard visited config paths before recursing.

Suggested fix
-export async function loadTsConfig(
-	configPath: string,
-): Promise<ParsedTsConfig> {
+export async function loadTsConfig(
+	configPath: string,
+	visited = new Set<string>(),
+): Promise<ParsedTsConfig> {
+	const normalizedConfigPath = path.resolve(configPath);
+	if (visited.has(normalizedConfigPath)) {
+		return { path: normalizedConfigPath, compilerOptions: {} };
+	}
+	visited.add(normalizedConfigPath);
+
 	let content = "";
 	try {
-		content = await fsp.readFile(configPath, "utf-8");
+		content = await fsp.readFile(normalizedConfigPath, "utf-8");
 	} catch {
-		return { path: configPath, compilerOptions: {} };
+		return { path: normalizedConfigPath, compilerOptions: {} };
 	}
@@
-			const baseConfig = await loadTsConfig(extPath);
+			const baseConfig = await loadTsConfig(extPath, visited);
🤖 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/cli/src/features/scaffold/tsconfig-parser.ts` around lines 64 - 81,
Detected potential infinite recursion when following parsed.extends chains; add
cycle protection by tracking visited config file paths (use a Set of resolved
absolute paths) and checking before recursing. Concretely, update loadTsConfig
to accept an optional visited:Set<string> (or create one at entry), resolve each
ext to an absolute path (extPath) as you already do, then if
visited.has(extPath) skip or throw a clear error instead of calling await
loadTsConfig(extPath); otherwise add extPath to visited before recursing and
pass visited down to the recursive loadTsConfig call. Ensure the initial call
seeds the visited set with the top-level configPath.

Comment thread packages/cli/src/features/scaffold/tsconfig-parser.ts Outdated
Comment on lines +144 to +153
for (const [pattern, targets] of Object.entries(paths)) {
const cleanPattern = pattern.replace(/\*$/, "");
if (importSpecifier.startsWith(cleanPattern)) {
const subpath = importSpecifier.slice(cleanPattern.length);
for (const target of targets) {
const cleanTarget = target.replace(/\*$/, "");
const targetRel = `${cleanTarget}${subpath}`;
return path.resolve(baseUrl, targetRel);
}
}

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

Alias matching is too permissive and can resolve wrong imports.

startsWith(cleanPattern) can match unintended specifiers (for example, a pattern ending with / can still prefix-match unrelated inputs). Also, returning the first match can pick a less specific alias.

Suggested fix
-	for (const [pattern, targets] of Object.entries(paths)) {
-		const cleanPattern = pattern.replace(/\*$/, "");
-		if (importSpecifier.startsWith(cleanPattern)) {
+	const entries = Object.entries(paths).sort(
+		([a], [b]) => b.replace(/\*$/, "").length - a.replace(/\*$/, "").length,
+	);
+	for (const [pattern, targets] of entries) {
+		const hasWildcard = pattern.endsWith("*");
+		const cleanPattern = pattern.replace(/\*$/, "");
+		const matched = hasWildcard
+			? importSpecifier.startsWith(cleanPattern)
+			: importSpecifier === cleanPattern;
+		if (matched) {
 			const subpath = importSpecifier.slice(cleanPattern.length);
 			for (const target of targets) {
📝 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
for (const [pattern, targets] of Object.entries(paths)) {
const cleanPattern = pattern.replace(/\*$/, "");
if (importSpecifier.startsWith(cleanPattern)) {
const subpath = importSpecifier.slice(cleanPattern.length);
for (const target of targets) {
const cleanTarget = target.replace(/\*$/, "");
const targetRel = `${cleanTarget}${subpath}`;
return path.resolve(baseUrl, targetRel);
}
}
const entries = Object.entries(paths).sort(
([a], [b]) => b.replace(/\*$/, "").length - a.replace(/\*$/, "").length,
);
for (const [pattern, targets] of entries) {
const hasWildcard = pattern.endsWith("*");
const cleanPattern = pattern.replace(/\*$/, "");
const matched = hasWildcard
? importSpecifier.startsWith(cleanPattern)
: importSpecifier === cleanPattern;
if (matched) {
const subpath = importSpecifier.slice(cleanPattern.length);
for (const target of targets) {
const cleanTarget = target.replace(/\*$/, "");
const targetRel = `${cleanTarget}${subpath}`;
return path.resolve(baseUrl, targetRel);
}
}
🤖 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/cli/src/features/scaffold/tsconfig-parser.ts` around lines 144 -
153, The current alias matching uses startsWith(cleanPattern) and returns the
first target, which allows unintended prefix matches and picks a non-specific
alias; update the resolve logic in tsconfig-parser.ts to (1) distinguish
patterns that end with '*' from exact patterns: only allow prefix matches when
the original pattern had a trailing '*' and require full equality when it did
not, and (2) prefer the most specific alias by selecting the longest
cleanPattern match instead of returning the first match—e.g., compute
cleanPattern and a boolean hadStar from pattern, collect matching entries, sort
or pick the one with the largest cleanPattern.length, then map that match's
targets to cleanTarget/targetRel and resolve with path.resolve(baseUrl,
targetRel).

Comment thread packages/cli/src/shared/ports/prompt.port.ts Outdated
Comment thread skills/skill-creator/assets/eval-review.html
Comment thread skills/skill-creator/eval-viewer/viewer.html
Comment thread skills/skill-creator/eval-viewer/viewer.html Outdated
@arkenv-bot

arkenv-bot Bot commented May 16, 2026

Copy link
Copy Markdown
Contributor

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

Warning

Deployment cooldown active

@yamcodes has triggered deployments too frequently. Please wait 12 minutes and 51 seconds before the next automated deployment.

⌛ How to resolve this issue?

After the wait time has elapsed, a deployment can be triggered by pushing new commits to this PR or by re-running the workflow.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

We enforce rate limits to ensure stability and fair usage of resources for all contributors.

…nents, and expose internal handlers for eval tools
@yamcodes

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented May 16, 2026

Copy link
Copy Markdown
Contributor
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@yamcodes
yamcodes merged commit 0a18edd into main May 16, 2026
18 checks passed
@yamcodes
yamcodes deleted the 908-cli-should-respect-tsconfigjson-for-path-resolution-and-general-configuration-1 branch May 16, 2026 14:29
@arkenv-bot arkenv-bot Bot mentioned this pull request May 16, 2026
yamcodes pushed a commit that referenced this pull request May 18, 2026
This PR was opened by the [Changesets
release](https://github.com/changesets/action) GitHub action. When
you're ready to do a release, you can merge this and the packages will
be published to npm automatically. If you're not ready to do a release
yet, that's fine, whenever you add more changesets to main, this PR will
be updated.


# Releases
## @arkenv/cli@0.0.9

### Patch Changes

- #### Refined setup experience in `arkenv init`
_[`#1016`](#1016)
[`d536ed7`](d536ed7)
[@yamcodes](https://github.com/yamcodes)_

- **Clearer Framework Options**: Updated terminology to better
distinguish between server-side runtime validation and client-side
bundling integrations.
- **Architecture Detection**: Improved detection logic recommends the
most efficient configuration based on your project's features.
- **Better In-File Guidance**: Generated templates now include comments
clarifying validation behavior for your specific environment.

- #### Add keyboard navigation hints
_[`ac3adcc`](ac3adcc)
[@yamcodes](https://github.com/yamcodes)_

- #### Improve Ctrl+C handling and implement graceful shutdown
_[`#1019`](#1019)
[`102ce4a`](102ce4a)
[@yamcodes](https://github.com/yamcodes)_

- Implemented graceful shutdown for `SIGINT` (Ctrl+C) to flush logs and
JSON data, with a 2-second safety timeout and support for immediate exit
on a second Ctrl+C.
    -   Corrected exit code (130) for `SIGINT` terminations.
- Fixed a bug where the `init` wizard would continue after a prompt was
cancelled.

- #### Respect `tsconfig.json` for path resolution and scaffolding
_[`#1013`](#1013)
[`0a18edd`](0a18edd)
[@yamcodes](https://github.com/yamcodes)_

The Arkenv CLI now dynamically resolves configuration paths and scans
project files by respecting `tsconfig.json` settings (`rootDir`,
`paths`, `baseUrl`).

    Key improvements include:

- **Robust `tsconfig` Parser**: Added support for parsing
`tsconfig.json` files with comments (`jsonc-parser`), handling
`extends`, `rootDir`, `baseUrl`, and `paths` alias resolution.
- **Dynamic Scaffolding Defaults**: Updated `init` scaffolding logic to
suggest project-appropriate default paths based on
`compilerOptions.rootDir` rather than hardcoding `./src/env.ts`.
- **Advanced Environment Scanning**: Enhanced `getEnvExampleKeys` to
scan project source files for `process.env` and `import.meta.env`
usages, correctly resolving aliased imports (e.g. `@/env`).
- **Framework & Package Manager Detection**: Leveraged parsed
`tsconfig.json` context to accurately identify project frameworks and
package managers.

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

@arkenv/cli Issues or Pull Requests involving the ArkEnv CLI @arkenv/fumadocs-ui Issues or Pull Requests involving the ArkEnv Fumadocs UI theme arkenv Changes to the `arkenv` npm package. bug Something isn't working docs Adds or changes documentation, or acts as documentation in and of itself enhancement New feature or improvement tests This issue or PR is about adding, removing or changing tests www Improvements or additions to arkenv.js.org

Projects

None yet

Development

Successfully merging this pull request may close these issues.

CLI should respect tsconfig.json for path resolution and general configuration

1 participant