plans/typescript-migration.md
Remove the legacy Build-mode “Auto-fix problems” feature and its user setting, move all remaining on-disk type checks to the app’s local TypeScript CLI, and let Code Explorer fall back to a Dyad-packaged TypeScript 6 compiler API when an installed local TypeScript does not expose the legacy API (notably TypeScript 7).
The Problems panel remains available through its explicit Run checks and Fix selected actions, and Local Agent keeps run_type_checks. Dyad will not automatically type-check after a file save, proposal approval, or Build-mode response. Projects without an installed typescript package remain unsupported by both type checking and Code Explorer.
enableAutoFixProblems setting end-to-end: defaults and active schema, Settings UI/switch, Settings search entry and ID, all locale strings, help/debug-report fields, test setup options, and settings snapshots. Retain it only as a deprecated stored-settings field so older files parse, then strip it during migration; it disappears on a later settings write.chat_stream_handlers.ts, including speculative type checks, <dyad-problem-report> generation, retry prompts, and the virtual codebase assembled from pending write/rename/delete tags. Preserve parsing/rendering and transcript cleanup for <dyad-problem-report> so historical chats continue to display and replay safely.useCheckProblems manual-only (enabled: false) while retaining its refetch API for the Problems panel. Local Agent continues updating the Problems cache through agent-tool:problems-update after run_type_checks.createProblemFixPrompt.Replace generateProblemReport({ fullResponse, appPath }) with an on-disk API such as runTypeScriptCheck({ appPath }); update the Problems IPC handler, Local Agent tool, hybrid mocks, and tests. No virtual changes remain in this contract.
Delete the now-unused synchronous/asynchronous virtual filesystem implementation and virtual-change protocol together with the TSC worker that still consumes it at the start of this phase. Simplify extractCodebase and its helpers to read the real filesystem only, removing their optional virtual-filesystem parameters. Remove the obsolete TSC worker entry, worker config/directory, Forge build entry, and worker-only shared types.
Establish eligibility by resolving typescript/package.json from appPath. Preserve the existing guidance split:
tsconfig.app.json or tsconfig.json: return the existing tsconfig precondition guidance.Resolve the local executable from appPath/node_modules/.bin/tsc (tsc.cmd on Windows), never through npx, a global compiler, or a package-defined typecheck script. Prepend the app’s .bin directory to getPackageManagerCommandEnv() so the selected system/custom/managed Node runtime launches the project-local shim. Treat a missing shim after the package resolved as an incomplete-install precondition. Resolve and cache the actual CLI version with that same shim’s --version output (keyed by shim realpath/mtime), rather than assuming it matches typescript/package.json; this preserves the official side-by-side layout where typescript can expose the TS6 API while another local alias owns the TS7 tsc shim.
Preserve config selection order: tsconfig.app.json, then tsconfig.json. Run the local CLI from appPath with fixed arguments equivalent to:
tsc --pretty false --noEmit --incremental --tsBuildInfoFile <dyad-cache-file> --project <config>
Store build info under Dyad’s TypeScript cache, keyed by app path, config path, and local TypeScript version, so checks never write generated files into the user project and caches are not shared across compiler versions.
Continue running checks inside typescriptUtilityProcessScheduler.runExclusive("tsc", ...). The external CLI process does not register as a resident utility process, but the scheduler must stop a resident Code Explorer before launching it and must hold the slot until the CLI child has fully exited. This preserves the existing protection against simultaneous memory-heavy TypeScript workloads and keeps performance activity labeled as tsc.
Reuse the bounded process runner and existing five-minute type-check timeout. Execute the command/arguments without an interpolated shell command; extend the runner options only as needed to support a larger explicit diagnostic-output cap. Terminate the entire process tree on timeout.
path(line,column): error TS####: message, attach indented/continuation lines to the preceding diagnostic, normalize paths to app-relative forward-slash paths, and preserve numeric code, 1-based line/column, and multiline message text.snippet after parsing by asynchronously reading the reported source file. Do not read outside the app root; external diagnostics may be reported with an empty snippet.0 returns { problems: [] }. A normal non-zero diagnostic exit returns a ProblemReport when all meaningful output was parsed as file diagnostics. Config/global diagnostics, spawn failures, signals, timeouts, unrecognized output, or output truncation must fail clearly instead of returning a misleading partial or empty report.ProblemReport, Problems IPC output, Problems-panel rendering, and agent-tool:problems-update wire shapes unchanged. Rename worker-specific error types to type-checker terminology while preserving the existing typescript-not-found and tsconfig-not-found precondition behavior.@typescript/typescript6 compatibility package as an exact runtime dependency (initially the current 6.0.x release) and lock its transitive compiler dependency. Package one external copy rather than inlining the compiler into the worker bundle: externalize it in the Code Explorer Vite config and allow both @typescript/typescript6 and its @typescript/old dependency through Forge’s package filter.typescript/package.json from the app. If it is absent, keep the existing typescript_not_installed precondition and do not use the fallback.typescript module.@typescript/typescript6 module and log the local version/reason and fallback version.getCodeExplorerAvailability based on an installed local TypeScript package plus a discoverable tsconfig. A TS7 app therefore remains eligible and uses the fallback; an app with a tsconfig but no TypeScript installation remains ineligible.{ module, source: "local" | "bundled-ts6", version } so logs and failures identify the active engine. Clear this cache with existing worker test-cache cleanup.enableAutoFixProblems from UserSettings, debug settings, help output, translations, and renderer behavior.appPath; callers and IPC response shapes remain otherwise unchanged.WorkerInput/WorkerOutput, virtual-change types, and the TSC worker build artifact.explore_code tool input/output remains unchanged.tsc shim, config selection, local .bin precedence over global PATH, fixed argument construction, version-keyed build-info paths, successful exit, diagnostic exit, spawn failure, timeout/signal cleanup, and truncated output.@typescript/typescript6/@typescript/old runtime files are present and loadable from ASAR on the target platform.run_type_checks against a normal TS5/6 fixture;npm run fmt, npm run lint, npm run ts, npm test, npm run build, and the focused Problems/Code Explorer E2E tests.tsc, including native TypeScript 7, and never fall back to Dyad TS6.explore_code IPC/tool result shapes remain compatible, and historical problem-report chat messages continue rendering.tsc is intentional: framework-specific wrappers (vue-tsc, Angular compilers), arbitrary package scripts, TypeScript 7’s unstable API, and automatic support for projects without TypeScript are out of scope.None. Resolved decisions: