Skip to content

refactor(config): lean config load + setup/scaffold path - #366

Merged
YosefHayim merged 1 commit into
mainfrom
refactor/config/config-setup
Aug 7, 2026
Merged

refactor(config): lean config load + setup/scaffold path#366
YosefHayim merged 1 commit into
mainfrom
refactor/config/config-setup

Conversation

@YosefHayim

@YosefHayim YosefHayim commented Aug 6, 2026

Copy link
Copy Markdown
Owner

User description

Summary

Lean remediations for config load + setup/scaffold (path-only deslop for #341).

  • config.ts: shared pathExists / static app.json read+write; DEFAULT_* for fallback config; rename private toDescriptor/resolveConfig stems; explicit iOS field guards; readonly FoundConfig/LoadedConfig shapes
  • setup.ts: DRY Apple/Play store-app readiness probe; delete one-use rehearse wrapper; simplify toolchain consent (mayInstallToolchain + assumeYes: yes); export pure readinessMark / formatPendingTodoLine / mayInstallToolchain
  • configScaffold.ts: explicit null/empty checks; prose names in detectAppRoot
  • Colocated pure-helper tests; regenerate docs test-count badges

Behavior preserved. No live ASC/Play/AWS.

Gate

pnpm typecheck && pnpm lint && pnpm lint:style && pnpm docs:check && pnpm test && pnpm build — all green (2091 tests).

Fixes #341


CodeAnt-AI Description

Streamline configuration discovery and setup readiness checks

What Changed

  • Setup now installs missing tools only when the terminal is interactive or --yes is provided, avoiding unattended installation prompts.
  • Setup readiness checks consistently report missing Apple and Google Play store records with actionable next steps.
  • Configuration loading and app discovery handle missing or invalid files safely while preserving dynamic-versus-static config behavior.
  • Static app versions and entitlements continue to update safely without modifying dynamic configuration files.
  • Added coverage for setup output, tool-install permissions, readiness checks, and configuration edge cases.

Impact

✅ Safer non-interactive setup
✅ Clearer store setup steps
✅ Safer static app config updates

💡 Usage Guide

Checking Your Pull Request

Every time you make a pull request, our system automatically looks through it. We check for security issues, mistakes in how you're setting up your infrastructure, and common code problems. We do this to make sure your changes are solid and won't cause any trouble later.

Talking to CodeAnt AI

Got a question or need a hand with something in your pull request? You can easily get in touch with CodeAnt AI right here. Just type the following in a comment on your pull request, and replace "Your question here" with whatever you want to ask:

@codeant-ai ask: Your question here

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

Example

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

Preserve Org Learnings with CodeAnt

You can record team preferences so CodeAnt AI applies them in future reviews. Reply directly to the specific CodeAnt AI suggestion (in the same thread) and replace "Your feedback here" with your input:

@codeant-ai: Your feedback here

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

Example

@codeant-ai: Do not flag unused imports.

Retrigger review

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

@codeant-ai: review

Check Your Repository Health

To analyze the health of your code repository, visit our dashboard at https://app.codeant.ai. This tool helps you identify potential issues and areas for improvement in your codebase, ensuring your repository maintains high standards of code health.


Summary by cubic

Refactors config loading and setup/scaffold paths for leaner, predictable behavior (fixes #341). Deduplicates static app.json I/O, unifies App Store/Play readiness checks, and exports small setup helpers while keeping behavior the same.

  • Refactors
    • Config: fallback LaunchConfig uses DEFAULT_*; shared pathExists; new loadAppConfigDocument; static JSON helpers readStaticAppJson/writeStaticAppJson; renamed appDescriptorFromConfig; stricter iOS/Android guards; readonly FoundConfig/LoadedConfig.
    • Setup: single store-app probe for Apple/Play; export readinessMark, formatPendingTodoLine, mayInstallToolchain; installs gated by TTY/--yes via ensureToolchain({ assumeYes: yes }); inline runBuild rehearsal; simpler pendingTodos.
    • Scaffold: safer detectAppRoot (readonly input) and deterministic template handling with optional artifactDir.
    • Tests: added business tests for exported helpers; minor naming cleanups.

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

Review in cubic

@YosefHayim YosefHayim added the domain:config launch.config schema and project setup label Aug 6, 2026
@changeset-bot

changeset-bot Bot commented Aug 6, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: ce14d11

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

Click here to learn what changesets are, and how to add one.

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

@codeant-ai

codeant-ai Bot commented Aug 6, 2026

Copy link
Copy Markdown

🤖 CodeAnt AI — Review Status

Status Commit Started (UTC) Finished (UTC)
✅ Reviewed your PR b055e31 Aug 06, 2026 · 23:42 23:45

@codeant-ai

codeant-ai Bot commented Aug 6, 2026

Copy link
Copy Markdown

Thanks for using CodeAnt! 🎉

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

Share on X ·
Reddit ·
LinkedIn

@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@YosefHayim, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 54 minutes

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 5cb8601d-52e9-432c-8b57-f5103a7d74db

📥 Commits

Reviewing files that changed from the base of the PR and between 35037c7 and ce14d11.

📒 Files selected for processing (5)
  • src/core/config/config.test.ts
  • src/core/config/config.ts
  • src/core/config/configScaffold.ts
  • src/core/config/setup.test.ts
  • src/core/config/setup.ts

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.

@codeant-ai codeant-ai Bot added the size:L This PR changes 100-499 lines, ignoring generated files label Aug 6, 2026
@qodo-code-review

Copy link
Copy Markdown

PR Summary by Qodo

Refactor config loading and setup scaffolding helpers

✨ Enhancement 🧪 Tests 📝 Documentation 🕐 40+ Minutes

Grey Divider

AI Description

• Deduplicate config existence + static app.json read/write with shared helpers.
• DRY store-app readiness probes and simplify setup toolchain consent logic.
• Add pure-helper unit tests and update docs test-count badges.
Diagram

graph TD
  CLI["launch setup"] --> Setup["setup.ts runSetup"] --> LoadCfg["config.ts loadConfig"] --> Apps[("Expo app configs")]
  Setup --> Scaffold["configScaffold.ts"] --> LaunchCfg["launch.config.ts"]
  Setup --> StoreProbe["store probes"] --> StoreSvc["SetupStoreReadiness"]
  Setup --> ToolConsent["mayInstallToolchain"] --> Toolchain["ensureToolchain"]
Loading
High-Level Assessment

The PR’s approach (extracting small pure helpers, deduplicating Effect-safe filesystem probes, and consolidating store readiness probing) is appropriate for a behavior-preserving refactor and improves readability/testability without changing external side effects.

Files changed (16) +288 / -224

Refactor (3) +226 / -196
config.tsCentralize filesystem probes and static app.json read/write +99/-97

Centralize filesystem probes and static app.json read/write

• Adds a shared Effect-safe path existence helper and factors static app.json read/write into dedicated helpers used by version/entitlements writers. Renames private config-selection helpers for clearer intent, tightens iOS/Android field guards, and uses DEFAULT_* constants for fallback Launch config defaults.

src/core/config/config.ts

configScaffold.tsHarden app root detection and template injection guards +20/-12

Harden app root detection and template injection guards

• Makes detectAppRoot operate on readonly app lists and clarifies variable naming and early-return semantics. Adds explicit null/empty checks when emitting optional sections in the generated config template.

src/core/config/configScaffold.ts

setup.tsDRY store readiness probes and simplify toolchain consent +107/-87

DRY store readiness probes and simplify toolchain consent

• Extracts a shared helper to append Apple/Play store-app readiness rows, reducing duplicated probe logic. Exports pure helpers (readinessMark, formatPendingTodoLine, mayInstallToolchain), tightens readiness types to readonly, simplifies todo collection, and inlines the rehearsal build call while keeping behavior the same.

src/core/config/setup.ts

Tests (2) +51 / -17
config.test.tsMinor test helper refactor for entitlements tests +2/-2

Minor test helper refactor for entitlements tests

• Converts a local helper to an arrow function for consistency with surrounding test style; no behavior change.

src/core/config/config.test.ts

setup.test.tsAdd unit coverage for exported setup pure helpers +49/-15

Add unit coverage for exported setup pure helpers

• Adds targeted tests for readinessMark, formatPendingTodoLine, and mayInstallToolchain, and improves naming clarity in existing toolchain/setup board tests.

src/core/config/setup.test.ts

Documentation (11) +11 / -11
README.de.mdUpdate tests badge count +1/-1

Update tests badge count

• Bumps the displayed passing test count in the stats badges section to reflect the new total.

README.de.md

README.es.mdUpdate tests badge count +1/-1

Update tests badge count

• Bumps the displayed passing test count in the stats badges section to reflect the new total.

README.es.md

README.fr.mdUpdate tests badge count +1/-1

Update tests badge count

• Bumps the displayed passing test count in the stats badges section to reflect the new total.

README.fr.md

README.ja.mdUpdate tests badge count +1/-1

Update tests badge count

• Bumps the displayed passing test count in the stats badges section to reflect the new total.

README.ja.md

README.ko.mdUpdate tests badge count +1/-1

Update tests badge count

• Bumps the displayed passing test count in the stats badges section to reflect the new total.

README.ko.md

README.mdUpdate tests badge count +1/-1

Update tests badge count

• Bumps the displayed passing test count in the stats badges section to reflect the new total.

README.md

README.pt-BR.mdUpdate tests badge count +1/-1

Update tests badge count

• Bumps the displayed passing test count in the stats badges section to reflect the new total.

README.pt-BR.md

README.ru.mdUpdate tests badge count +1/-1

Update tests badge count

• Bumps the displayed passing test count in the stats badges section to reflect the new total.

README.ru.md

README.zh-CN.mdUpdate tests badge count +1/-1

Update tests badge count

• Bumps the displayed passing test count in the stats badges section to reflect the new total.

README.zh-CN.md

commands.mdRefresh command reference test count +1/-1

Refresh command reference test count

• Updates the generated command reference header line to reflect the current total test count.

docs/commands.md

llms.txtRefresh test count in LLM index +1/-1

Refresh test count in LLM index

• Updates the summary line for commands/coverage to reflect the current total test count.

llms.txt

Comment thread src/core/config/config.ts
Comment on lines +35 to +39
const pathExists = (
fileSystem: FileSystem.FileSystem,
candidatePath: string,
): Effect.Effect<boolean> =>
fileSystem.exists(candidatePath).pipe(Effect.orElseSucceed(() => false));

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Suggestion: pathExists turns every filesystem failure into false, not only a genuine missing-path result. A permission error or transient filesystem failure therefore makes findLaunchConfig silently return null, causing callers to treat an inaccessible existing configuration as absent instead of surfacing the load/access failure. Only suppress a confirmed not-found condition and preserve other errors. [api mismatch]

Severity Level: Major ⚠️
- ❌ Inaccessible launch configs appear to be missing.
- ⚠️ App discovery silently skips filesystem failures.
- ⚠️ Users receive misleading initialization guidance.

Fix in Cursor Fix in VSCode Claude

(Use Cmd/Ctrl + Click for best experience)

Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** src/core/config/config.ts
**Line:** 35:39
**Comment:**
	*Api Mismatch: `pathExists` turns every filesystem failure into `false`, not only a genuine missing-path result. A permission error or transient filesystem failure therefore makes `findLaunchConfig` silently return `null`, causing callers to treat an inaccessible existing configuration as absent instead of surfacing the load/access failure. Only suppress a confirmed not-found condition and preserve other errors.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix
👍 | 👎

Comment on lines +10 to +15
const relativeAppPath = pathService.relative(workingDirectory, app.dir);
// An app at the repo root means scan the root - no shared monorepo subdir.
if (relativeAppPath === '') return null;
const [firstSegment] = relativeAppPath.split(/[/\\]/);
if (firstSegment !== undefined && firstSegment.length > 0) {
topLevelSegments.add(firstSegment);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Suggestion: When an app directory is outside workingDirectory, relativeAppPath begins with .., so this code emits appRoots: ["./.."]. Loading that scaffold then resolves the root to the parent directory and recursively discovers unrelated sibling projects instead of limiting discovery to the intended repository. Reject outside-root apps or return null rather than converting .. into an app root. [possible bug]

Severity Level: Major ⚠️
- ❌ Generated appRoots can include the repository parent.
- ⚠️ Discovery may include unrelated sibling projects.
- ⚠️ Build and app selection can operate on extra apps.

Fix in Cursor Fix in VSCode Claude

(Use Cmd/Ctrl + Click for best experience)

Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** src/core/config/configScaffold.ts
**Line:** 10:15
**Comment:**
	*Possible Bug: When an app directory is outside `workingDirectory`, `relativeAppPath` begins with `..`, so this code emits `appRoots: ["./.."]`. Loading that scaffold then resolves the root to the parent directory and recursively discovers unrelated sibling projects instead of limiting discovery to the intended repository. Reject outside-root apps or return `null` rather than converting `..` into an app root.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix
👍 | 👎

Comment thread src/core/config/setup.ts
Comment on lines +197 to +203
const appCheck = yield* storeAppProbe.checkStoreApp(appId).pipe(Effect.either);
if (appCheck._tag === 'Left') {
storeAppProbe.readinessEntries.push(
makeReadinessRow(storeAppProbe.okLabel(appId), 'todo', storeAppProbe.missingDetail),
);
return;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Suggestion: The helper converts every failed store probe into a missing-app todo. checkAppleApp and checkPlayApp can fail because of authentication, authorization, rate limiting, or transport errors, in which case telling the user to create the app is incorrect and hides the actual readiness failure. Preserve the underlying error classification or report an indeterminate probe separately from a confirmed missing app. [api mismatch]

Severity Level: Major ⚠️
- ❌ Store readiness reports API failures as missing apps.
- ⚠️ Users receive incorrect creation instructions.
- ⚠️ Authentication and transport failures lose diagnostics.

Fix in Cursor Fix in VSCode Claude

(Use Cmd/Ctrl + Click for best experience)

Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** src/core/config/setup.ts
**Line:** 197:203
**Comment:**
	*Api Mismatch: The helper converts every failed store probe into a missing-app todo. `checkAppleApp` and `checkPlayApp` can fail because of authentication, authorization, rate limiting, or transport errors, in which case telling the user to create the app is incorrect and hides the actual readiness failure. Preserve the underlying error classification or report an indeterminate probe separately from a confirmed missing app.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix
👍 | 👎

@qodo-code-review

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (1) 📘 Rule violations (0) 📜 Skill insights (0)

Grey Divider


Remediation recommended

1. Sidecar probe hides FS errors 🐞 Bug ☼ Reliability
Description
resolveSidecarConfig now uses pathExists(), which converts any FileSystem.exists() failure into
false and returns undefined instead of failing. This can silently skip a present-but-unreadable
sidecar (e.g., permission/IO error) and make planners treat the surface as “nothing declared”.
Code

src/core/config/config.ts[R96-99]

    const fileSystem = yield* FileSystem.FileSystem;
-    if (yield* fileSystem.exists(params.configPath)) return yield* params.load(params.configPath);
+    const sidecarExists = yield* pathExists(fileSystem, sidecarRequest.configPath);
+    if (sidecarExists) return yield* sidecarRequest.load(sidecarRequest.configPath);
    return undefined;
Evidence
pathExists() is explicitly implemented to never fail, converting any exists() error into
false. resolveSidecarConfig() relies on this check in the implicit-sidecar branch, so an
exists() failure becomes indistinguishable from “file doesn’t exist”. Planners use
resolveSidecarConfig() to load sidecar JSON when there is no typed config, so returning
undefined here changes downstream behavior from “error” to “no config”.

src/core/config/config.ts[34-39]
src/core/config/config.ts[83-100]
src/core/plan/planners/accessibility.ts[14-23]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`resolveSidecarConfig()` uses `pathExists()` for the implicit sidecar path check. `pathExists()` swallows *all* `FileSystem.exists()` failures and returns `false`, which changes behavior from “surface discovery fails with the underlying FS error” to “surface treated as absent / undefined”. This can hide permission/IO issues and lead to incorrect “nothing declared” outcomes.

### Issue Context
This only affects the implicit fallback sidecar lookup (when `explicitPath` is false and `typed` is undefined). It is used by multiple planners during `launch plan` / `launch drift` to locate default sidecars.

### Fix Focus Areas
- src/core/config/config.ts[34-39]
- src/core/config/config.ts[83-100]

### Suggested fix
- In `resolveSidecarConfig`, prefer `yield* fileSystem.exists(sidecarRequest.configPath)` (no blanket suppression) so unexpected FS errors propagate.
- If you still want best-effort behavior elsewhere, keep `pathExists()` for directory scanning and other non-critical probes, but avoid it for configuration discovery where errors should be surfaced.
- Add a unit test that simulates `FileSystem.exists()` failing and asserts `resolveSidecarConfig` fails (rather than returning `undefined`).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Context used
✅ Compliance rules (platform): 47 rules

To customize comments, go to the Qodo configuration screen, or learn more in the docs.

Qodo Logo

Comment thread src/core/config/config.ts
Comment on lines 96 to 99
const fileSystem = yield* FileSystem.FileSystem;
if (yield* fileSystem.exists(params.configPath)) return yield* params.load(params.configPath);
const sidecarExists = yield* pathExists(fileSystem, sidecarRequest.configPath);
if (sidecarExists) return yield* sidecarRequest.load(sidecarRequest.configPath);
return undefined;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Remediation recommended

1. Sidecar probe hides fs errors 🐞 Bug ☼ Reliability

resolveSidecarConfig now uses pathExists(), which converts any FileSystem.exists() failure into
false and returns undefined instead of failing. This can silently skip a present-but-unreadable
sidecar (e.g., permission/IO error) and make planners treat the surface as “nothing declared”.
Agent Prompt
### Issue description
`resolveSidecarConfig()` uses `pathExists()` for the implicit sidecar path check. `pathExists()` swallows *all* `FileSystem.exists()` failures and returns `false`, which changes behavior from “surface discovery fails with the underlying FS error” to “surface treated as absent / undefined”. This can hide permission/IO issues and lead to incorrect “nothing declared” outcomes.

### Issue Context
This only affects the implicit fallback sidecar lookup (when `explicitPath` is false and `typed` is undefined). It is used by multiple planners during `launch plan` / `launch drift` to locate default sidecars.

### Fix Focus Areas
- src/core/config/config.ts[34-39]
- src/core/config/config.ts[83-100]

### Suggested fix
- In `resolveSidecarConfig`, prefer `yield* fileSystem.exists(sidecarRequest.configPath)` (no blanket suppression) so unexpected FS errors propagate.
- If you still want best-effort behavior elsewhere, keep `pathExists()` for directory scanning and other non-critical probes, but avoid it for configuration discovery where errors should be surfaced.
- Add a unit test that simulates `FileSystem.exists()` failing and asserts `resolveSidecarConfig` fails (rather than returning `undefined`).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

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

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

2 issues found across 16 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="src/core/config/configScaffold.ts">

<violation number="1" location="src/core/config/configScaffold.ts:53">
P2: An empty `appRoot` now produces `appRoots: [""]` instead of the root-scan starter, changing the prior truthiness behavior and generating an ambiguous config. Retaining a non-empty check preserves the documented fallback for an empty path.</violation>
</file>

<file name="src/core/config/config.ts">

<violation number="1" location="src/core/config/config.ts:97">
P2: Unreadable sidecars can silently disappear from `launch plan`/`drift`, yielding an incomplete plan; the new best-effort existence wrapper masks filesystem errors in `resolveSidecarConfig`. Preserving the resolver's previous error propagation here would distinguish a missing sidecar from one that cannot be inspected.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

): string => {
let appRootsLine = ` // appRoots: ["./apps"], // uncomment if your apps live in a subfolder`;
if (appRoot) appRootsLine = ` appRoots: ["${appRoot}"], // every app.json lives under here`;
if (appRoot !== null) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2: An empty appRoot now produces appRoots: [""] instead of the root-scan starter, changing the prior truthiness behavior and generating an ambiguous config. Retaining a non-empty check preserves the documented fallback for an empty path.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/core/config/configScaffold.ts, line 53:

<comment>An empty `appRoot` now produces `appRoots: [""]` instead of the root-scan starter, changing the prior truthiness behavior and generating an ambiguous config. Retaining a non-empty check preserves the documented fallback for an empty path.</comment>

<file context>
@@ -46,13 +50,17 @@ export const configTemplate = (
 ): string => {
   let appRootsLine = `  // appRoots: ["./apps"], // uncomment if your apps live in a subfolder`;
-  if (appRoot) appRootsLine = `  appRoots: ["${appRoot}"], // every app.json lives under here`;
+  if (appRoot !== null) {
+    appRootsLine = `  appRoots: ["${appRoot}"], // every app.json lives under here`;
+  }
</file context>
Suggested change
if (appRoot !== null) {
if (appRoot !== null && appRoot.length > 0) {

Comment thread src/core/config/config.ts
Comment on lines +97 to +98
const sidecarExists = yield* pathExists(fileSystem, sidecarRequest.configPath);
if (sidecarExists) return yield* sidecarRequest.load(sidecarRequest.configPath);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2: Unreadable sidecars can silently disappear from launch plan/drift, yielding an incomplete plan; the new best-effort existence wrapper masks filesystem errors in resolveSidecarConfig. Preserving the resolver's previous error propagation here would distinguish a missing sidecar from one that cannot be inspected.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/core/config/config.ts, line 97:

<comment>Unreadable sidecars can silently disappear from `launch plan`/`drift`, yielding an incomplete plan; the new best-effort existence wrapper masks filesystem errors in `resolveSidecarConfig`. Preserving the resolver's previous error propagation here would distinguish a missing sidecar from one that cannot be inspected.</comment>

<file context>
@@ -74,41 +80,47 @@ export const defineConfig = (input: LaunchConfigInput): LaunchConfig => {
+    if (sidecarRequest.typed !== undefined) return sidecarRequest.typed;
     const fileSystem = yield* FileSystem.FileSystem;
-    if (yield* fileSystem.exists(params.configPath)) return yield* params.load(params.configPath);
+    const sidecarExists = yield* pathExists(fileSystem, sidecarRequest.configPath);
+    if (sidecarExists) return yield* sidecarRequest.load(sidecarRequest.configPath);
     return undefined;
</file context>
Suggested change
const sidecarExists = yield* pathExists(fileSystem, sidecarRequest.configPath);
if (sidecarExists) return yield* sidecarRequest.load(sidecarRequest.configPath);
if (yield* fileSystem.exists(sidecarRequest.configPath))
return yield* sidecarRequest.load(sidecarRequest.configPath);

@YosefHayim
YosefHayim force-pushed the refactor/config/config-setup branch from b055e31 to 3680a28 Compare August 7, 2026 10:45
Deduplicate static app.json read/write and store-app readiness probes,
wire DEFAULT_* into the fallback Launch config, rename private bad-stem
helpers, simplify toolchain consent, and export pure setup helpers with
business tests. Behavior preserved. Fixes #341.
@YosefHayim
YosefHayim force-pushed the refactor/config/config-setup branch from 3680a28 to ce14d11 Compare August 7, 2026 10:48
@YosefHayim
YosefHayim merged commit 8c1e951 into main Aug 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

domain:config launch.config schema and project setup size:L This PR changes 100-499 lines, ignoring generated files

Projects

None yet

Development

Successfully merging this pull request may close these issues.

refactor(config): lean config load + setup modules

1 participant