@@ -12,6 +12,7 @@ import { copilotBridge } from '../bridges/copilot.js';
1212import type { Bridge , DirectoryBridge , ProjectConfig , PulledEntry , AssetEntry , Rule } from '../bridges/types.js' ;
1313import { getBridgeOutputPaths , isDirectoryBridge } from '../bridges/types.js' ;
1414import { fileExists } from '../utils/fs.js' ;
15+ import { resolveContext } from '../core/resolve-context.js' ;
1516import { isValidScope } from '../core/schema.js' ;
1617import { buildCanonicalOutputs } from '../core/canonical.js' ;
1718import { detectLegacyFiles } from '../core/cleanup.js' ;
@@ -479,44 +480,64 @@ export async function runDoctor(): Promise<void> {
479480 const results : CheckResult [ ] = [ ] ;
480481 let hasFailed = false ;
481482
483+ // Resolve context: local project or global ~/.dwf
484+ const resolved = await resolveContext ( cwd ) ;
485+
486+ if ( ! resolved ) {
487+ ui . error ( 'No devw configuration found.' , 'Run "devw init" to set up a project or global configuration.' ) ;
488+ process . exitCode = 1 ;
489+ return ;
490+ }
491+
492+ const effectiveCwd = resolved . configRoot ;
493+
494+ if ( resolved . globalMode ) {
495+ ui . info ( 'Running in global mode (~/.dwf)' ) ;
496+ ui . newline ( ) ;
497+ }
498+
482499 // Check 1: .dwf/config.yml exists
483- const configExistsResult = await checkConfigExists ( cwd ) ;
500+ const configExistsResult = await checkConfigExists ( effectiveCwd ) ;
484501 results . push ( configExistsResult ) ;
485502
486503 if ( ! configExistsResult . passed ) {
487504 for ( const r of results ) {
488505 ui . check ( r . passed , r . message , r . skipped ) ;
489- if ( ! r . passed ) hasFailed = true ;
506+ if ( ! r . passed ) {
507+ hasFailed = true ;
508+ }
490509 }
491510 printSummary ( results , startTime ) ;
492511 process . exitCode = 1 ;
493512 return ;
494513 }
495514
496515 // Check 2: config.yml is valid
497- const configValidResult = await checkConfigValid ( cwd ) ;
516+ const configValidResult = await checkConfigValid ( effectiveCwd ) ;
498517 results . push ( configValidResult ) ;
499518
500519 // Check 3: Rule files are valid YAML
501- const rulesValidResult = await checkRulesValid ( cwd ) ;
520+ const rulesValidResult = await checkRulesValid ( effectiveCwd ) ;
502521 results . push ( rulesValidResult ) ;
503522
504523 if ( ! configValidResult . passed ) {
505524 for ( const r of results ) {
506525 ui . check ( r . passed , r . message , r . skipped ) ;
507- if ( ! r . passed ) hasFailed = true ;
526+ if ( ! r . passed ) {
527+ hasFailed = true ;
528+ }
508529 }
509530 printSummary ( results , startTime ) ;
510531 process . exitCode = 1 ;
511532 return ;
512533 }
513534
514- const config = await readConfig ( cwd ) ;
535+ const config = await readConfig ( effectiveCwd ) ;
515536
516537 // Load rules for remaining checks
517538 let rules : Rule [ ] = [ ] ;
518539 try {
519- rules = await readRules ( cwd ) ;
540+ rules = await readRules ( effectiveCwd ) ;
520541 } catch {
521542 // readRules may fail if rules dir is missing; that's ok
522543 }
@@ -534,43 +555,45 @@ export async function runDoctor(): Promise<void> {
534555 results . push ( bridgeResult ) ;
535556
536557 // Check 7: Symlinks valid (conditional on mode)
537- const symlinkResult = await checkSymlinks ( cwd , config ) ;
558+ const symlinkResult = await checkSymlinks ( effectiveCwd , config ) ;
538559 results . push ( symlinkResult ) ;
539560
540561 // Check 8: Pulled files exist
541- const pulledResult = await checkPulledFilesExist ( cwd , config . pulled ) ;
562+ const pulledResult = await checkPulledFilesExist ( effectiveCwd , config . pulled ) ;
542563 results . push ( pulledResult ) ;
543564
544565 // Check 9: Asset files exist
545- const assetResult = await checkAssetFilesExist ( cwd , config . assets ) ;
566+ const assetResult = await checkAssetFilesExist ( effectiveCwd , config . assets ) ;
546567 results . push ( assetResult ) ;
547568
548569 // Check 10: Hash sync (conditional on compiled files existing)
549- const hashResult = await checkHashSync ( cwd , rules ) ;
570+ const hashResult = await checkHashSync ( effectiveCwd , rules ) ;
550571 results . push ( hashResult ) ;
551572
552573 // Check 11: Canonical output exists (skip if no rules)
553574 if ( rules . length > 0 ) {
554- const canonicalExistsResult = await checkCanonicalExists ( cwd ) ;
575+ const canonicalExistsResult = await checkCanonicalExists ( effectiveCwd ) ;
555576 results . push ( canonicalExistsResult ) ;
556577
557578 // Check 12: Canonical and native outputs are synchronized
558- const canonicalSyncResult = await checkCanonicalSync ( cwd , rules , config ) ;
579+ const canonicalSyncResult = await checkCanonicalSync ( effectiveCwd , rules , config ) ;
559580 results . push ( canonicalSyncResult ) ;
560581 }
561582
562583 // Check 13: Legacy migration has no pending files
563- const legacyResult = await checkLegacyMigration ( cwd ) ;
584+ const legacyResult = await checkLegacyMigration ( effectiveCwd ) ;
564585 results . push ( legacyResult ) ;
565586
566587 // Check 14: Native files have valid frontmatter for their editor
567- const frontmatterResult = await checkNativeFrontmatter ( cwd , config ) ;
588+ const frontmatterResult = await checkNativeFrontmatter ( effectiveCwd , config ) ;
568589 results . push ( frontmatterResult ) ;
569590
570591 // Output
571592 for ( const r of results ) {
572593 ui . check ( r . passed , r . message , r . skipped ) ;
573- if ( ! r . passed ) hasFailed = true ;
594+ if ( ! r . passed ) {
595+ hasFailed = true ;
596+ }
574597 }
575598
576599 printSummary ( results , startTime ) ;
0 commit comments