rapidkit 0.27.2 → 0.27.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -53,7 +53,23 @@ Or run directly with `npx`:
53
53
  npx rapidkit --help
54
54
  ```
55
55
 
56
- All three commands above render the same root help output.
56
+ The commands above provide install/help entry points for the same CLI.
57
+
58
+ ## 60-Second Quickstart
59
+
60
+ ```bash
61
+ npx rapidkit my-workspace
62
+ cd my-workspace
63
+ npx rapidkit create project
64
+ cd <project-name>
65
+ npx rapidkit init && npx rapidkit dev
66
+ ```
67
+
68
+ If you prefer explicit commands instead of shortcut mode:
69
+
70
+ ```bash
71
+ npx rapidkit create workspace my-workspace --yes --profile polyglot
72
+ ```
57
73
 
58
74
  ## Quick Start (Recommended)
59
75
 
@@ -64,6 +80,14 @@ npx rapidkit create workspace my-workspace --yes --profile polyglot
64
80
  cd my-workspace
65
81
  ```
66
82
 
83
+ Shortcut form (equivalent workspace creation flow):
84
+
85
+ ```bash
86
+ npx rapidkit my-workspace
87
+ ```
88
+
89
+ This shortcut launches the same interactive workspace wizard (author, profile, Python version, environment strategy).
90
+
67
91
  ### 2) Bootstrap and setup runtimes
68
92
 
69
93
  ```bash
@@ -77,6 +101,7 @@ npx rapidkit setup go --warm-deps
77
101
  ### 3) Create projects
78
102
 
79
103
  ```bash
104
+ npx rapidkit create project # Interactive kit picker
80
105
  npx rapidkit create project fastapi.standard my-api --yes --skip-install
81
106
  npx rapidkit create project fastapi.ddd my-api --yes --skip-install
82
107
  npx rapidkit create project nestjs.standard my-nest --yes --skip-install
@@ -98,8 +123,11 @@ npx rapidkit workspace policy show
98
123
  npx rapidkit workspace policy set <key> <value>
99
124
  npx rapidkit doctor
100
125
  npx rapidkit doctor workspace [--fix]
126
+ npx rapidkit doctor project [--fix]
101
127
  npx rapidkit workspace list # Display all workspaces created on this system
102
128
  npx rapidkit workspace share [--output <file>] [--include-paths] [--no-doctor]
129
+ npx rapidkit workspace init # Full-init alias (same behavior as root init/workspace run init at workspace root)
130
+ npx rapidkit workspace run <init|test|build|start> [--affected] [--blast-radius] [--since <ref>] [--parallel] [--max-workers <n>] [--strict] [--json]
103
131
  ```
104
132
 
105
133
  ### Workspace collaboration bundle
@@ -132,13 +160,15 @@ RapidKit keeps the wrapper boundary explicit so users know which layer owns each
132
160
  | Command family | Owner | Notes |
133
161
  |---|---|---|
134
162
  | `create workspace`, `workspace`, `cache`, `mirror` | RapidKit wrapper | Platform-level orchestration |
135
- | `init` | Wrapper orchestrated | Chooses the right runtime flow for the current project |
163
+ | `init` | Wrapper orchestrated | Project init in project dirs; full-init alias at workspace root |
136
164
  | `dev`, `test`, `build`, `start` | Runtime aware | Delegates to the active project/runtime when available |
137
165
  | `readiness` | Wrapper release gate | Generates release-readiness evidence (`--json` for CI, `--strict` for fail-fast) |
138
166
  | `doctor` | Wrapper system check | Checks host prerequisites by default |
139
167
  | `doctor workspace` | Workspace health | Full workspace scan with project-level details and fixes |
168
+ | `doctor project` | Project health | Current project (or nearest parent) diagnostics with project evidence and scoped fixes |
169
+ | `workspace run` | Workspace orchestrator | Stage execution across discovered projects with optional affected-only, blast-radius expansion, and policy-gated pre-checks |
140
170
 
141
- Use `npx rapidkit doctor` for a quick host pre-flight and `npx rapidkit doctor workspace` inside a workspace for the full health picture.
171
+ Use `npx rapidkit doctor` for a quick host pre-flight, `npx rapidkit doctor project` for a service-level check, and `npx rapidkit doctor workspace` for the full workspace picture.
142
172
  Use `npx rapidkit readiness` when you need machine-readable release evidence or strict CI gating.
143
173
 
144
174
  ### Doctor workspace fix behavior
@@ -160,6 +190,25 @@ Use `npx rapidkit readiness` when you need machine-readable release evidence or
160
190
  - `supportTier`
161
191
  - `frameworkConfidence`
162
192
 
193
+ ### Doctor project behavior
194
+
195
+ - `npx rapidkit doctor project` resolves the current project or the nearest parent project when run from nested directories.
196
+ - Project mode supports RapidKit and non-RapidKit backend projects (generic runtime diagnostics still run when `.rapidkit` is missing).
197
+ - JSON evidence is written to `.rapidkit/reports/doctor-project-last-run.json` (workspace-level when available).
198
+ - `--fix` in project mode applies only project-scoped actionable fixes, with the same safe/guarded handling used by doctor fix flows.
199
+ - Project diagnostics include built-in probes (configuration surface, migration surface, runtime health surface) and optional custom probe/adapter contracts.
200
+
201
+ ### Doctor project JSON fields (AI/automation)
202
+
203
+ `npx rapidkit doctor project --json` includes project-scoped evidence fields for extension and automation consumers:
204
+
205
+ - `scope` (`project`)
206
+ - `contract` (doctor evidence contract + scoring policy version)
207
+ - `project` (framework/runtime metadata, issues, fix commands, probes)
208
+ - `summary.scopeProvenance`
209
+ - `driftDelta`
210
+ - `scoreBreakdown`
211
+
163
212
  ### Project lifecycle
164
213
 
165
214
  ```bash
@@ -288,6 +337,107 @@ Primary docs live under `docs/`:
288
337
  - Security: [docs/SECURITY.md](docs/SECURITY.md)
289
338
  - Development: [docs/DEVELOPMENT.md](docs/DEVELOPMENT.md)
290
339
 
340
+ ## Workspace Run — Polyglot Fleet Orchestration
341
+
342
+ `workspace run` is an enterprise-grade orchestrator for executing CI-safe stages (init, test, build, start) across polyglot monorepos. It supports 20+ frameworks across 9 runtimes with professional-grade features.
343
+
344
+ ### Quick Start
345
+
346
+ ```bash
347
+ # Test all discovered projects in parallel
348
+ npx rapidkit workspace run test --parallel
349
+
350
+ # Test only affected projects since last commit
351
+ npx rapidkit workspace run test --affected --since HEAD~1
352
+
353
+ # Test affected + their dependents (requires dependency graph)
354
+ npx rapidkit workspace run test --affected --blast-radius
355
+
356
+ # Build specific projects with custom stages (if defined in .rapidkit/context.json)
357
+ npx rapidkit workspace run build --json --max-workers 8
358
+ ```
359
+
360
+ ### Supported Runtimes & Frameworks
361
+
362
+ | Runtime | Frameworks | Status |
363
+ |---------|-----------|--------|
364
+ | **Node** | NestJS, Express, Next.js, Nuxt | Built-in |
365
+ | **Go** | Fiber, Gin, Echo, Chi | Built-in |
366
+ | **Java** | Spring Boot, Quarkus, Gradle | Built-in |
367
+ | **Python** | FastAPI, Django, Flask, Poetry | Built-in |
368
+ | **PHP** | Laravel, Symfony, Slim | Stable |
369
+ | **Rust** | Actix, Axum, Rocket, Tokio | Stable |
370
+ | **.NET** | ASP.NET Core, Entity Framework | Stable |
371
+ | **Elixir** | Phoenix, Umbrella Projects | Stable |
372
+ | **Ruby** | Rails, Sinatra, RSpec | Stable |
373
+
374
+ ### Enterprise Features
375
+
376
+ 1. **Command Overrides** — Customize stage commands per project via `.rapidkit/context.json`
377
+ 2. **Multi-Framework Projects** — Support full-stack apps (e.g., Laravel + Vue in same directory)
378
+ 3. **Error Diagnostics** — Categorize errors (setup vs test failure vs runtime) for better CI feedback
379
+ 4. **Preflight Validation** — Validate command availability before execution
380
+ 5. **Health Checks** — Verify services are ready (port listening, HTTP health, log grep)
381
+ 6. **Custom Stages** — Define project-specific stages (lint, docs, bench, etc.)
382
+ 7. **Stage Dependencies** — Define execution order and prerequisites
383
+ 8. **Environment Variants** — dev/staging/prod command variants
384
+ 9. **Caching** — Skip re-runs of completed stages
385
+ 10. **Composite Steps** — Multi-step build logic
386
+
387
+ For deeper enterprise deployment and governance details, see:
388
+ - [docs/README.md](docs/README.md)
389
+ - [docs/DEVELOPMENT.md](docs/DEVELOPMENT.md)
390
+ - [docs/SECURITY.md](docs/SECURITY.md)
391
+
392
+ ### Configuration Example
393
+
394
+ ```json
395
+ {
396
+ ".rapidkit/context.json": {
397
+ "runtime": "php",
398
+ "framework": "Laravel",
399
+ "commands": {
400
+ "test": "php artisan test --parallel=4",
401
+ "build": "php artisan config:cache && php artisan route:cache",
402
+ "lint": "php bin/phpstan analyse --level=8"
403
+ },
404
+ "environment": "dev"
405
+ }
406
+ }
407
+ ```
408
+
409
+ ### Output & Reporting
410
+
411
+ ```bash
412
+ # JSON report for CI integration
413
+ npx rapidkit workspace run test --json > test-results.json
414
+
415
+ cat test-results.json | jq '.projects[] | {path, status, errorCategory}'
416
+ # Output:
417
+ # {
418
+ # "path": "services/api",
419
+ # "status": "failed",
420
+ # "errorCategory": "setup" # setup | test-failure | runtime | dependency | timeout
421
+ # }
422
+ ```
423
+
424
+ ## Command Semantics
425
+
426
+ RapidKit has two workspace-level execution surfaces, and three equivalent full-init aliases at workspace root:
427
+
428
+ | Command | Intent | Scope |
429
+ |---|---|---|
430
+ | `init` (at workspace root), `workspace init`, `workspace run init` | Mirrored full-init orchestration (workspace-profile deps + selected project init) | Workspace root + discovered project fleet |
431
+ | `workspace run <test\|build\|start>` | Fleet stage execution — run a CI-safe stage across discovered projects | Selected project fleet |
432
+ | `init`, `test`, `build`, `start`, `dev` (inside project directory) | Project primitive — run one stage in the current project only | Single project |
433
+
434
+ **Key design rule:** at workspace root, these are equivalent aliases: `npx rapidkit init`, `npx rapidkit workspace init`, `npx rapidkit workspace run init`.
435
+ Inside a project directory, `npx rapidkit init` remains a project-scoped primitive.
436
+
437
+ `dev` is intentionally excluded from `workspace run` — it is a long-running local process, not a CI batch stage.
438
+
439
+ Detailed enterprise semantic specs and governance evidence contracts are intentionally excluded from OSS docs.
440
+
291
441
  ## Development
292
442
 
293
443
  ```bash
@@ -307,6 +457,16 @@ npx rapidkit --version
307
457
 
308
458
  ## Troubleshooting
309
459
 
460
+ ### Quick fixes matrix
461
+
462
+ | Problem | Quick check | Fix |
463
+ |---|---|---|
464
+ | `python3` not found | `python3 --version` | Install Python 3.10+ and re-run `npx rapidkit create workspace ...` |
465
+ | `setup --warm-deps` skipped | Check for `package.json` / `go.mod` in current dir | Run from the target project directory |
466
+ | strict policy blocks command | Review `.rapidkit/policies.yml` | Set policy intentionally via `npx rapidkit workspace policy set ...` |
467
+ | doctor output seems stale | Check report timestamp in `.rapidkit/reports/` | Re-run `npx rapidkit doctor workspace` or `npx rapidkit doctor project` |
468
+ | affected run scope seems wrong | Verify git ref | Use `--since <ref>` explicitly |
469
+
310
470
  - If setup output looks stale, run `npx rapidkit setup <runtime>` again to refresh `.rapidkit/toolchain.lock`.
311
471
  - If dependency warm-up is skipped, verify you are inside the corresponding project directory (`package.json` for Node, `go.mod` for Go).
312
472
  - For strict-mode blocks, inspect `.rapidkit/policies.yml` and workspace profile in `.rapidkit/workspace.json`.
@@ -0,0 +1,48 @@
1
+ import {b,f,d,a as a$1,k,g,i as i$1}from'./chunk-Z5LKRG57.js';import {a}from'./chunk-VM2TOHNX.js';import l from'chalk';import {execa}from'execa';import i from'fs-extra';import o from'path';import Oe from'inquirer';function Le(e){return [...new Set(e.filter(s=>s&&s.trim().length>0))]}function Ve(){let e=k().map(t=>o.join(t,a$1()?"poetry.exe":"poetry")),s=a$1()?[o.join(process.env.APPDATA||"","Python","Scripts","poetry.exe"),o.join(process.env.USERPROFILE||"","AppData","Roaming","Python","Scripts","poetry.exe")]:[],a=a$1()?[]:["/usr/local/bin/poetry","/usr/bin/poetry"];return Le([...e,...s,...a])}function Je(e){let s=k().map(u=>({location:"Global (user-local)",path:o.join(u,a$1()?"rapidkit.exe":"rapidkit")})),a=[{location:"Global (pipx)",path:o.join(e,".local","bin","rapidkit")},{location:"Global (pipx)",path:o.join(e,"AppData","Roaming","Python","Scripts","rapidkit.exe")},{location:"Global (pyenv)",path:o.join(e,".pyenv","shims","rapidkit")},{location:"Global (system)",path:"/usr/local/bin/rapidkit"},{location:"Global (system)",path:"/usr/bin/rapidkit"}],t=g(o.join(process.cwd(),".venv")),r=i$1(process.cwd()),n=[{location:"Workspace (.venv)",path:t},...r.map(u=>({location:"Workspace (launcher)",path:u}))],c=[...s,...a,...n],d=new Set;return c.filter(u=>d.has(u.path)?false:(d.add(u.path),true))}function qe(e){let s=new Map([["Workspace (.venv)",0],["Global (user-local)",1],["Global (pipx)",2],["Global (pyenv)",3],["Global (system)",4]]);return [...e].sort((a,t)=>{let r=s.get(a.location)??Number.MAX_SAFE_INTEGER,n=s.get(t.location)??Number.MAX_SAFE_INTEGER;return r!==n?r-n:a.path.localeCompare(t.path)})}function Q(e){let s=0,a=e.issues.some(t=>t.toLowerCase().includes("environment file missing"));return e.hasEnvFile===false&&!a&&(s+=1),typeof e.vulnerabilities=="number"&&e.vulnerabilities>0&&(s+=1),s}function pe(e){return e.filter(s=>Q(s)>0).length}function fe(e){return e.reduce((s,a)=>s+Q(a),0)}var Ue="doctor-project-scan-v2",ze=Object.freeze({version:"doctor-evidence-v1",scoringPolicyVersion:"doctor-score-policy-v1",generatedBy:"rapidkit-npm",deterministicScoreBreakdown:true,scopeModel:"workspace-aggregate-or-project-scoped"});function oe(){return {...ze}}function ie(e){return !e||e.total<=0?null:Math.round(e.passed/e.total*100)}function Pe(e){return typeof e=="number"?e:Array.isArray(e)?e.length:0}async function Se(e){try{if(!await i.pathExists(e))return null;let s=await i.readJSON(e);return !s||typeof s!="object"?null:s}catch{return null}}function $e(e,s){if(!e?.system)return [];let a=[{id:"python",current:s.python},{id:"poetry",current:s.poetry},{id:"pipx",current:s.pipx},{id:"go",current:s.go},{id:"rapidkitCore",current:s.rapidkitCore}],t=[];for(let r of a){let n=e.system?.[r.id]?.status;!n||n===r.current.status||t.push({id:r.id,from:n,to:r.current.status});}return t}function Qe(e,s){let a=new Map;for(let f of s.projects)a.set(f.path||f.name,f.issues.length);if(!e)return {baselineAvailable:false,newIssueCount:0,resolvedIssueCount:0,netIssueDelta:0,scoreDeltaPercent:null,systemStatusChanges:[],regressedProjects:[],improvedProjects:[]};let t=Array.isArray(e.projects)?e.projects:[],r=new Map;for(let f of t){let k=f.path||f.name;k&&r.set(k,Pe(f.issues));}let n=0,c=0,d=new Set,u=new Set,m=new Set([...Array.from(r.keys()),...Array.from(a.keys())]);for(let f of m){let k=r.get(f)??0,w=a.get(f)??0;w>k?(n+=w-k,d.add(f)):w<k&&(c+=k-w,u.add(f));}let p=ie(e.healthScore),h=ie(s.healthScore);return {baselineAvailable:true,previousGeneratedAt:e.generatedAt,newIssueCount:n,resolvedIssueCount:c,netIssueDelta:n-c,scoreDeltaPercent:p===null||h===null?null:h-p,systemStatusChanges:$e(e,{python:s.python,poetry:s.poetry,pipx:s.pipx,go:s.go,rapidkitCore:s.rapidkitCore}),regressedProjects:Array.from(d).sort(),improvedProjects:Array.from(u).sort()}}function Xe(e,s){if(!e)return {baselineAvailable:false,newIssueCount:0,resolvedIssueCount:0,netIssueDelta:0,scoreDeltaPercent:null,systemStatusChanges:[],regressedProjects:[],improvedProjects:[]};let a=Pe(e.project?.issues),t=s.project.issues.length,r=Math.max(t-a,0),n=Math.max(a-t,0),c=ie(e.healthScore),d=ie(s.healthScore),u=s.project.path||s.project.name;return {baselineAvailable:true,previousGeneratedAt:e.generatedAt,newIssueCount:r,resolvedIssueCount:n,netIssueDelta:r-n,scoreDeltaPercent:c===null||d===null?null:d-c,systemStatusChanges:$e(e,{python:s.python,poetry:s.poetry,pipx:s.pipx,go:s.go,rapidkitCore:s.rapidkitCore}),regressedProjects:r>0?[u]:[],improvedProjects:n>0?[u]:[]}}function Re(e){let s=e??[],a=0,t=0;for(let c of s){if(c.scope==="project-scoped"){a+=1;continue}(c.scope==="workspace-aggregate"||c.scope==="host-system")&&(t+=1);}let r=a>0&&t>0?1:0,n=r>0?"mixed":a>0?"scoped":t>0?"aggregated":"unknown";return {scopedCount:a,aggregatedCount:t,mixedCount:r,dominantScope:n}}function S(e,s){return a$1()?`cd "${e}"; ${s}`:`cd ${e} && ${s}`}function O(e){return a$1()?S(e,"Copy-Item .env.example .env"):S(e,"cp .env.example .env")}function Ye(e){return e==="FastAPI"||e==="NestJS"||e==="Go/Fiber"||e==="Go/Gin"||e==="Spring Boot"||e==="Rust"||e==="Phoenix"?"first-class":e==="Django"||e==="Flask"||e==="Express"||e==="Fastify"||e==="Koa"||e==="Elixir"||e==="Clojure"||e==="Scala"||e==="Kotlin"||e==="Deno"||e==="Bun"||e==="PHP"||e==="Laravel"||e==="Ruby"||e==="Ruby on Rails"||e==="ASP.NET"?"extended":"observed"}function Ze(e){return e==="Next.js"||e==="Nuxt"||e==="React"||e==="Vue"||e==="Angular"||e==="SvelteKit"?"frontend":e==="Unknown"||e==="Node.js"||e==="Python"?"generic":"backend"}function et(e){return e==="NestJS"||e==="Next.js"||e==="Nuxt"||e==="React"||e==="Vue"||e==="Angular"||e==="SvelteKit"||e==="Bun"||e==="Express"||e==="Fastify"||e==="Koa"||e==="Node.js"?"node":e==="FastAPI"||e==="Django"||e==="Flask"||e==="Python"?"python":e==="Go/Fiber"||e==="Go/Gin"?"go":e==="Spring Boot"?"java":e==="Rust"?"rust":e==="Elixir"||e==="Phoenix"?"elixir":e==="Clojure"?"clojure":e==="Deno"?"deno":e==="Laravel"||e==="PHP"?"php":e==="Ruby on Rails"||e==="Ruby"?"ruby":e==="ASP.NET"?"dotnet":"unknown"}function F(e,s,a){e.framework=s,e.frameworkConfidence=a,e.supportTier=Ye(s),e.projectKind=Ze(s),e.runtimeFamily=et(s);}function tt(e){let s=e.dependencies,a=e.scripts??{},t=(e.kitName??"").toLowerCase(),r=c=>!!s[c],n=Object.values(a).filter(c=>typeof c=="string").join(" ").toLowerCase();return r("next")||n.includes("next ")?{framework:"Next.js",confidence:"high"}:r("nuxt")||n.includes("nuxt ")?{framework:"Nuxt",confidence:"high"}:r("@nestjs/core")||t.startsWith("nestjs.")?{framework:"NestJS",confidence:"high"}:r("express")?{framework:"Express",confidence:"high"}:r("fastify")?{framework:"Fastify",confidence:"high"}:r("koa")?{framework:"Koa",confidence:"high"}:r("@angular/core")?{framework:"Angular",confidence:"high"}:r("@sveltejs/kit")||n.includes("svelte-kit")?{framework:"SvelteKit",confidence:"high"}:r("vue")?{framework:"Vue",confidence:"medium"}:r("react")&&r("react-dom")?{framework:"React",confidence:"medium"}:{framework:"Node.js",confidence:"low"}}async function st(e){let s=[o.join(e,"pyproject.toml"),o.join(e,"requirements.txt")],a=[];for(let r of s)if(await i.pathExists(r))try{a.push((await i.readFile(r,"utf8")).toLowerCase());}catch{continue}let t=a.join(`
2
+ `);return t.includes("fastapi")?{framework:"FastAPI",confidence:"high"}:t.includes("django")?{framework:"Django",confidence:"high"}:t.includes("flask")?{framework:"Flask",confidence:"high"}:{framework:"Python",confidence:a.length>0?"medium":"low"}}async function ve(e){try{let s=await i.stat(e);return `${o.basename(e)}:${s.isDirectory()?"d":"f"}:${s.size}:${s.mtimeMs}`}catch{return `${o.basename(e)}:missing`}}async function nt(e){try{let s=new Set([".git",".venv","node_modules",".rapidkit","dist","build","coverage","__pycache__"]),a=new Set;await ae(e)&&a.add(e);let t=async(r,n)=>{if(n<0)return;let c=await Fe(r);for(let d of c){if(De(d,s))continue;let u=o.join(r,d);if(await ae(u)){a.add(u);continue}n>0&&await t(u,n-1);}};return await t(e,1),a.size===0&&(await gt(e,3,s)).forEach(n=>a.add(n)),Array.from(a).sort((r,n)=>r.localeCompare(n))}catch{return []}}async function ot(e,s){let a=[o.join(e,".rapidkit-workspace"),o.join(e,".rapidkit","workspace.json"),o.join(e,".rapidkit","policies.yml"),o.join(e,".rapidkit","toolchain.lock"),o.join(e,".rapidkit","cache-config.yml")],t=[".rapidkit/project.json",".rapidkit/context.json",".rapidkit/file-hashes.json","package.json","pyproject.toml","composer.json","Gemfile","Gemfile.lock","go.mod","go.sum","pom.xml","requirements.txt","Dockerfile","Makefile",".env",".env.example","src","modules","tests","test",".venv","node_modules"],r=await Promise.all(a.map(ve)),n=await Promise.all(s.map(async c=>{let d=await Promise.all(t.map(u=>ve(o.join(c,u))));return `${c}::${d.join("|")}`}));return [Ue,...r,...n].join("||")}async function it(e,s){try{if(!await i.pathExists(e))return null;let a=await i.readJSON(e);return !a||a.signature!==s||!Array.isArray(a.projects)?null:a}catch{return null}}async function at(e,s){try{await i.ensureDir(o.dirname(e)),await i.writeJSON(e,s,{spaces:2});}catch{}}async function rt(e,s,a){let t=o.join(e,".rapidkit","reports","doctor-last-run.json");try{return await i.ensureDir(o.dirname(t)),await i.writeJSON(t,{generatedAt:new Date().toISOString(),contract:oe(),workspacePath:e,workspaceName:s.workspaceName,projectScanCached:s.projectScanCached??false,projectScanSignature:s.projectScanSignature,cachePath:a,healthScore:s.healthScore,system:{python:s.python,poetry:s.poetry,pipx:s.pipx,go:s.go,rapidkitCore:s.rapidkitCore,versions:{core:s.coreVersion,npm:s.npmVersion}},projects:s.projects,summary:{totalProjects:s.projects.length,totalIssues:s.projects.reduce((r,n)=>r+n.issues.length,0),projectAdvisoryWarningProjects:pe(s.projects),projectAdvisoryWarnings:fe(s.projects),hasSystemErrors:[s.python,s.rapidkitCore].some(r=>r.status==="error"),scopeProvenance:s.scopeProvenance},driftDelta:s.driftDelta,scoreBreakdown:s.scoreBreakdown??[]},{spaces:2}),t}catch{return}}async function ge(){let[e,s,a,t,r]=await Promise.all([ct(),lt(),dt(),ut(),pt()]);return {python:e,poetry:s,pipx:a,go:t,rapidkitCore:r}}async function ct(){let e=d();for(let s of e)try{let{stdout:a}=await execa(s,["--version"],{timeout:3e3}),t=a.match(/Python (\d+\.\d+\.\d+)/);if(t){let r=t[1],[n,c]=r.split(".").map(Number);return n<3||n===3&&c<10?{status:"warn",message:`Python ${r} (requires 3.10+)`,details:`${s} found but version is below minimum requirement`}:{status:"ok",message:`Python ${r}`,details:`Using ${s}`}}}catch{continue}return {status:"error",message:"Python not found",details:"Install Python 3.10+ and ensure it's in PATH"}}async function lt(){try{let{stdout:e}=await execa("poetry",["--version"],{timeout:3e3}),s=e.match(/Poetry .*version ([\d.]+)/);return s?{status:"ok",message:`Poetry ${s[1]}`,details:"Available for dependency management"}:{status:"warn",message:"Poetry version unknown"}}catch{let e=d().map(s=>({cmd:s,args:s==="py"?["-3","-m","poetry","--version"]:["-m","poetry","--version"]}));for(let s of e)try{let{stdout:a}=await execa(s.cmd,s.args,{timeout:3e3,shell:b()}),t=a.match(/Poetry .*version ([\d.]+)/)||a.match(/([\d.]+)/);return {status:"ok",message:t?.[1]?`Poetry ${t[1]}`:"Poetry detected",details:`Available via ${s.cmd} ${s.args.join(" ")}`}}catch{continue}for(let s of Ve())try{if(!await i.pathExists(s))continue;let{stdout:a}=await execa(s,["--version"],{timeout:3e3,shell:b()}),t=a.match(/Poetry .*version ([\d.]+)/)||a.match(/([\d.]+)/);return {status:"ok",message:t?.[1]?`Poetry ${t[1]}`:"Poetry detected",details:`Available at ${s}`}}catch{continue}return {status:"warn",message:"Poetry not installed",details:"Optional: Install for better dependency management"}}}async function dt(){try{let{stdout:e}=await execa("pipx",["--version"],{timeout:3e3});return {status:"ok",message:`pipx ${e.trim()}`,details:"Available for global tool installation"}}catch{let e=d();for(let s of e)try{let a=s==="py"?["-3","-m","pipx","--version"]:["-m","pipx","--version"],{stdout:t}=await execa(s,a,{timeout:3e3,shell:b()});return {status:"ok",message:`pipx ${t.trim()}`,details:`Available via ${s} ${a.join(" ")}`}}catch{continue}return {status:"warn",message:"pipx not installed",details:"Optional: Install for isolated Python tools"}}}async function ut(){try{let{stdout:e}=await execa("go",["version"],{timeout:3e3}),s=e.match(/go version go(\d+\.\d+(?:\.\d+)?)/);return s?{status:"ok",message:`Go ${s[1]}`,details:"Available for Go/Fiber and Go/Gin projects"}:{status:"ok",message:"Go (version unknown)",details:"go found in PATH"}}catch{return {status:"warn",message:"Go not installed",details:"Optional: Required only for gofiber.standard / gogin.standard projects \u2014 https://go.dev/dl/"}}}async function pt(){let e=process.env.HOME||process.env.USERPROFILE||"",s=[],a=Je(e);for(let{location:r,path:n}of a)try{if(await i.pathExists(n)){let{stdout:c,exitCode:d}=await execa(n,["--version"],{timeout:3e3,reject:false});if(d===0&&(c.includes("RapidKit Version")||c.includes("RapidKit"))){let u=c.match(/v?([\d.]+(?:rc\d+)?(?:a\d+)?(?:b\d+)?)/);u&&s.push({location:r,path:n,version:u[1]});}}}catch{continue}if(s.length>0){let r=s.filter(c=>c.location!=="Workspace (launcher)");if(r.length>0){let c=qe(r);return {status:"ok",message:`RapidKit Core ${c[0].version}`,paths:c.map(u=>({location:u.location,path:u.path,version:u.version}))}}return {status:"ok",message:`RapidKit Core ${s[0].version}`,details:"Detected via workspace launcher"}}try{let{stdout:r,exitCode:n}=await execa("rapidkit",["--version"],{timeout:3e3,reject:false});if(n===0&&(r.includes("RapidKit Version")||r.includes("RapidKit"))){let c=r.match(/v?([\d.]+(?:rc\d+)?(?:a\d+)?(?:b\d+)?)/);if(c)return {status:"ok",message:`RapidKit Core ${c[1]}`,details:"Available via PATH"}}}catch{}try{let{stdout:r,exitCode:n}=await execa("poetry",["run","rapidkit","--version"],{timeout:3e3,reject:false});if(n===0&&(r.includes("RapidKit Version")||r.includes("RapidKit"))){let c=r.match(/v?([\d.]+(?:rc\d+)?(?:a\d+)?(?:b\d+)?)/);if(c)return {status:"ok",message:`RapidKit Core ${c[1]}`,details:"Available via Poetry"}}}catch{}let t=d();for(let r of t)try{let{stdout:n,exitCode:c}=await execa(r,["-c","import rapidkit_core; print(rapidkit_core.__version__)"],{timeout:3e3,reject:false});if(c===0&&n&&!n.includes("Traceback")&&!n.includes("ModuleNotFoundError")){let d=n.trim();if(d)return {status:"ok",message:`RapidKit Core ${d}`,details:`Available in ${r} environment`}}}catch{continue}return {status:"error",message:"RapidKit Core not installed",details:"Install with: pipx install rapidkit-core"}}async function H(e,s){let a=o.join(e,"Dockerfile");s.hasDocker=await i.pathExists(a);let t=o.join(e,"tests"),r=o.join(e,"test"),n=o.join(e,"src","test"),c=await i.pathExists(t)||await i.pathExists(r)||await i.pathExists(n),d=false;if(s.framework==="Go/Fiber"||s.framework==="Go/Gin")try{let u=[{dir:e,depth:0}],m=4,p=new Set([".git",".venv","node_modules","dist","build","vendor"]);for(;u.length>0&&!d;){let h=u.shift();if(!h)break;let f=[];try{f=await i.readdir(h.dir);}catch{continue}for(let k of f){let w=o.join(h.dir,k),v;try{v=await i.stat(w);}catch{continue}if(v.isFile()&&k.endsWith("_test.go")){d=true;break}v.isDirectory()&&h.depth<m&&!p.has(k)&&!k.startsWith(".")&&u.push({dir:w,depth:h.depth+1});}}}catch{}if(s.hasTests=c||d,s.runtimeFamily==="node"){let u=o.join(e,".eslintrc.js"),m=o.join(e,".eslintrc.json");s.hasCodeQuality=await i.pathExists(u)||await i.pathExists(m);}else if(s.framework==="Go/Fiber"||s.framework==="Go/Gin"){let u=o.join(e,".golangci.yml"),m=o.join(e,".golangci.yaml"),p=o.join(e,"Makefile"),h=await i.pathExists(p)&&(await i.readFile(p,"utf8")).includes("golangci-lint");s.hasCodeQuality=await i.pathExists(u)||await i.pathExists(m)||h;}else if(s.runtimeFamily==="python"){let u=o.join(e,"ruff.toml"),m=o.join(e,"pyproject.toml");if(await i.pathExists(m))try{let p=await i.readFile(m,"utf8");s.hasCodeQuality=p.includes("[tool.ruff]")||await i.pathExists(u);}catch{s.hasCodeQuality=await i.pathExists(u);}}else if(s.framework==="Spring Boot"){let u=o.join(e,"pom.xml");if(await i.pathExists(u))try{let m=await i.readFile(u,"utf8");s.hasCodeQuality=m.includes("spotless")||m.includes("checkstyle")||m.includes("pmd")||m.includes("maven-enforcer-plugin");}catch{s.hasCodeQuality=false;}}try{if(s.runtimeFamily==="node"){let{stdout:u}=await execa("npm",["audit","--json"],{cwd:e,reject:false});if(u)try{let p=JSON.parse(u).metadata?.vulnerabilities;p&&(s.vulnerabilities=(p.high||0)+(p.critical||0)+(p.moderate||0));}catch{}}else if(s.runtimeFamily==="python"){let u=o.join(e,".venv"),m=f(u);if(await i.pathExists(m))try{let{stdout:p}=await execa(m,["-m","pip","list","--format=json"],{timeout:5e3,reject:false});if(p){JSON.parse(p);s.vulnerabilities=0;}}catch{}}}catch{}}function N(e,s){e.probes||(e.probes=[]),e.probes.push(s);}async function mt(e,s){let a=s.runtimeFamily||"unknown";if(s.projectKind==="backend"||s.projectKind==="generic"){if(a==="node"){let r=await i.pathExists(o.join(e,"package-lock.json"))||await i.pathExists(o.join(e,"pnpm-lock.yaml"))||await i.pathExists(o.join(e,"yarn.lock"));N(s,{id:"adapter-node-lockfile-integrity",label:"Node adapter lockfile integrity",status:r?"pass":"warn",severity:"warn",scope:"project-scoped",reason:r?"Node lockfile detected for deterministic dependency restore.":"No Node lockfile detected (package-lock/yarn.lock/pnpm-lock.yaml).",recommendation:r?void 0:"Commit a lockfile for deterministic installs and CI parity."});let n=await i.pathExists(o.join(e,"src/main.ts"))||await i.pathExists(o.join(e,"src/main.js"))||await i.pathExists(o.join(e,"src/server.ts"))||await i.pathExists(o.join(e,"src/server.js"));N(s,{id:"adapter-node-boot-entrypoint",label:"Node adapter boot entrypoint",status:n?"pass":"warn",severity:"warn",scope:"project-scoped",reason:n?"Boot entrypoint markers detected for service startup path.":"No canonical Node boot entrypoint markers detected.",recommendation:n?void 0:"Define and document service bootstrap entrypoint (main/server)."});return}if(a==="python"){let r=await i.pathExists(o.join(e,"poetry.lock"))||await i.pathExists(o.join(e,"requirements.txt"))||await i.pathExists(o.join(e,"uv.lock"));N(s,{id:"adapter-python-lockfile-integrity",label:"Python adapter dependency integrity",status:r?"pass":"warn",severity:"warn",scope:"project-scoped",reason:r?"Python dependency contract file detected.":"No Python dependency contract file detected (poetry.lock/requirements/uv.lock).",recommendation:r?void 0:"Pin dependency contract for deterministic setup and reproducible CI."});let n=await i.pathExists(o.join(e,"app/main.py"))||await i.pathExists(o.join(e,"main.py"))||await i.pathExists(o.join(e,"manage.py"));N(s,{id:"adapter-python-boot-entrypoint",label:"Python adapter boot entrypoint",status:n?"pass":"warn",severity:"warn",scope:"project-scoped",reason:n?"Python application entrypoint markers detected.":"No Python application entrypoint markers detected.",recommendation:n?void 0:"Expose explicit app/main entrypoint for deterministic boot probes."});return}if(a==="java"){let r=await i.pathExists(o.join(e,"mvnw"))||await i.pathExists(o.join(e,"gradlew"));N(s,{id:"adapter-java-build-wrapper",label:"Java adapter build wrapper",status:r?"pass":"warn",severity:"warn",scope:"project-scoped",reason:r?"Build wrapper detected (mvnw/gradlew).":"No Java build wrapper detected.",recommendation:r?void 0:"Commit mvnw or gradlew for reproducible enterprise pipelines."});return}if(a==="go"){let r=await i.pathExists(o.join(e,"go.sum"));N(s,{id:"adapter-go-module-integrity",label:"Go adapter module integrity",status:r?"pass":"warn",severity:"warn",scope:"project-scoped",reason:r?"go.sum detected for deterministic module verification.":"go.sum missing; module integrity baseline is incomplete.",recommendation:r?void 0:"Generate and commit go.sum in the repository baseline."});}}}async function ft(e,s){let a=[o.join(e,".rapidkit","doctor.adapters.json"),o.join(e,"doctor.adapters.json")];for(let t of a)if(await i.pathExists(t))try{let r=await i.readJSON(t),n=Array.isArray(r?.checks)?r.checks:[];for(let c=0;c<n.length;c+=1){let d=n[c]||{},u=Array.isArray(d.runtimes)?d.runtimes:[];if(u.length>0&&!u.includes(s.runtimeFamily||"unknown"))continue;let m=typeof d.id=="string"&&d.id.trim().length>0?d.id.trim():`adapter-check-${c+1}`,p=typeof d.label=="string"&&d.label.trim().length>0?d.label.trim():m,h=d.severity||"warn",f=Array.isArray(d.anyOfPaths)?d.anyOfPaths.filter(Boolean):[],k=Array.isArray(d.allOfPaths)?d.allOfPaths.filter(Boolean):[],w=f.length===0;for(let D of f)if(await i.pathExists(o.join(e,D))){w=true;break}let v=true;for(let D of k)if(!await i.pathExists(o.join(e,D))){v=false;break}let $=w&&v;N(s,{id:m,label:p,status:$?"pass":h==="error"?"fail":"warn",severity:h,scope:"project-scoped",reason:$?d.passReason||"Custom adapter contract satisfied.":d.failReason||`Custom adapter check failed from ${o.basename(t)}.`,recommendation:d.recommendation});}}catch{N(s,{id:"custom-adapter-config",label:"Custom doctor adapter configuration",status:"warn",severity:"warn",scope:"project-scoped",reason:`Failed to parse ${o.basename(t)}.`,recommendation:"Fix JSON syntax in doctor.adapters.json to re-enable adapter checks."});}}async function W(e,s){if(!(s.projectKind==="backend"||s.projectKind==="generic"))return;let t=o.join(e,".env"),r=o.join(e,".env.example"),n=await i.pathExists(t)||await i.pathExists(r)||await i.pathExists(o.join(e,"config"));N(s,{id:"config-surface",label:"Configuration contract surface",status:n?"pass":"warn",severity:"warn",scope:"project-scoped",reason:n?"Configuration artifacts detected (.env/.env.example/config).":"No explicit configuration contract artifacts detected.",recommendation:n?void 0:"Add .env.example or explicit config contract documentation for deterministic setup."});let c={python:["alembic.ini","migrations","versions"],node:["prisma/schema.prisma","migrations","typeorm.config.ts","typeorm.config.js"],go:["migrations","db/migrations"],java:["src/main/resources/db/migration","src/main/resources/liquibase"],rust:["migrations","sqlx-data.json"],elixir:["priv/repo/migrations"],clojure:["resources/migrations","migrations"],deno:["migrations"],php:["database/migrations","migrations"],ruby:["db/migrate"],dotnet:["Migrations","Data/Migrations"],unknown:["migrations"]},d=s.runtimeFamily||"unknown",u=c[d]||c.unknown,m=false;for(let f of u)if(await i.pathExists(o.join(e,f))){m=true;break}N(s,{id:"migration-surface",label:"Migration/readiness surface",status:m?"pass":"warn",severity:"warn",scope:"project-scoped",reason:m?"Migration or schema evolution markers detected.":"No migration markers detected for this backend runtime.",recommendation:m?void 0:"Add migration tooling baseline (migrations dir or runtime-native migration config)."});let p=["src/health","src/healthcheck","src/main/resources/application.yml","src/main/resources/application.properties","app/health.py","routes/health.ts","routes/health.js"],h=false;for(let f of p)if(await i.pathExists(o.join(e,f))){h=true;break}N(s,{id:"runtime-health-surface",label:"Runtime health probe surface",status:h?"pass":"warn",severity:"warn",scope:"project-scoped",reason:h?"Health endpoint/config markers detected.":"No explicit runtime health endpoint markers detected.",recommendation:h?void 0:"Expose a deterministic health endpoint and keep it covered in verify pack."}),await mt(e,s);}async function _(e,s){let a=[o.join(e,".rapidkit","doctor.probes.json"),o.join(e,"doctor.probes.json")];for(let t of a)if(await i.pathExists(t))try{let r=await i.readJSON(t),n=Array.isArray(r?.probes)?r.probes:[];for(let c=0;c<n.length;c+=1){let d=n[c]||{},u=typeof d.id=="string"&&d.id.trim().length>0?d.id.trim():`custom-probe-${c+1}`,m=typeof d.label=="string"&&d.label.trim().length>0?d.label.trim():u,p=d.severity||"warn",h=Array.isArray(d.anyOfPaths)?d.anyOfPaths.filter(Boolean):[],f=Array.isArray(d.allOfPaths)?d.allOfPaths.filter(Boolean):[],k=h.length===0;for(let $ of h)if(await i.pathExists(o.join(e,$))){k=true;break}let w=true;for(let $ of f)if(!await i.pathExists(o.join(e,$))){w=false;break}let v=k&&w;N(s,{id:u,label:m,status:v?"pass":p==="error"?"fail":"warn",severity:p,scope:"project-scoped",reason:v?"Custom probe contract satisfied.":`Custom probe failed from ${o.basename(t)}.`,recommendation:d.recommendation});}}catch{N(s,{id:"custom-probe-config",label:"Custom doctor probe configuration",status:"warn",severity:"warn",scope:"project-scoped",reason:`Failed to parse ${o.basename(t)}.`,recommendation:"Fix JSON syntax in doctor.probes.json to re-enable custom probes."});}await ft(e,s);}async function he(e,s={}){let t={name:o.basename(e),path:e,venvActive:false,depsInstalled:false,coreInstalled:false,issues:[],fixCommands:[]},r=s.allowNonRapidkit===true,n=o.join(e,".rapidkit");if(!await i.pathExists(n)){if(!r)return t.issues.push("Not a valid RapidKit project (missing .rapidkit directory)"),t;t.issues.push("Not a RapidKit-managed project (running generic backend diagnostics)");}try{let y=o.join(e,"registry.json");if(await i.pathExists(y)){let g=await i.readJson(y);g.installed_modules&&(t.stats={modules:g.installed_modules.length});}}catch{}let c=null;try{let y=o.join(n,"project.json");if(await i.pathExists(y)){c=await i.readJson(y);let g=c?.kit_name||c?.kit;g&&(t.kit=g);}}catch{}try{let y=o.join(e,".git");if(await i.pathExists(y)){let{stdout:g}=await execa("git",["log","-1","--format=%cr"],{cwd:e,reject:false});g&&(t.lastModified=g.trim());}else {let g=await i.stat(e),E=Date.now()-g.mtime.getTime(),b=Math.floor(E/(1e3*60*60*24));t.lastModified=b===0?"today":`${b} day${b>1?"s":""} ago`;}}catch{}let d=o.join(e,"package.json"),u=o.join(e,"pyproject.toml"),m=o.join(e,"requirements.txt"),p=o.join(e,"go.mod"),h=o.join(e,"pom.xml"),f$1=o.join(e,"build.sbt"),k=o.join(e,"Cargo.toml"),w=o.join(e,"mix.exs"),v=o.join(e,"deps.edn"),$=o.join(e,"project.clj"),D=o.join(e,"deno.json"),L=o.join(e,"deno.jsonc"),V=o.join(e,"bun.lockb"),B=o.join(e,"bun.lock"),Y=o.join(e,"composer.json"),J=o.join(e,"Gemfile"),M=await i.pathExists(d),A=await i.pathExists(u)||await i.pathExists(m),Z=await i.pathExists(Y),ee=await i.pathExists(J),Me=await i.pathExists(k),Ge=await i.pathExists(w),We=await i.pathExists(v)||await i.pathExists($),_e=await i.pathExists(f$1),Be=await i.pathExists(D)||await i.pathExists(L),re=false;try{re=(await i.readdir(e)).some(g=>g.endsWith(".csproj")||g.endsWith(".sln"));}catch{re=false;}let Ke=await i.pathExists(p)||c?.runtime==="go"||typeof c?.kit_name=="string"&&(c.kit_name.startsWith("gofiber")||c.kit_name.startsWith("gogin")),ye=M&&(await i.pathExists(V)||await i.pathExists(B)||typeof c?.packageManager=="string"&&(c?.packageManager).toLowerCase().startsWith("bun@"));if(Ke){let y=c?.kit_name??"";F(t,y.startsWith("gogin")?"Go/Gin":"Go/Fiber","high"),t.isGoProject=true,t.venvActive=true,t.coreInstalled=false;try{await execa("go",["version"],{timeout:3e3});}catch{t.issues.push("Go toolchain not found \u2014 install from https://go.dev/dl/"),t.fixCommands?.push("https://go.dev/dl/");}let g=o.join(e,"go.sum");return await i.pathExists(g)?t.depsInstalled=true:(t.depsInstalled=false,t.issues.push("Go dependencies not downloaded (go.sum missing)"),t.fixCommands?.push(S(e,"go mod tidy"))),await H(e,t),await W(e,t),await _(e,t),t}if(await i.pathExists(h)||c?.runtime==="java"||typeof c?.kit_name=="string"&&c.kit_name.startsWith("springboot")){F(t,"Spring Boot","high"),t.venvActive=true,t.coreInstalled=false;let y=await i.pathExists(h),g=await i.pathExists(o.join(e,"build.gradle"))||await i.pathExists(o.join(e,"build.gradle.kts")),C=await i.pathExists(o.join(e,"mvnw"))||await i.pathExists(o.join(e,"mvnw.cmd")),E=await i.pathExists(o.join(e,"gradlew"))||await i.pathExists(o.join(e,"gradlew.bat"));try{await execa("java",["-version"],{timeout:3e3,reject:false});}catch{t.issues.push("Java runtime not found \u2014 install JDK 21+ and ensure java is on PATH"),t.fixCommands?.push("https://adoptium.net/");}if(y){if(!C)try{await execa("mvn",["-version"],{timeout:3e3,reject:false});}catch{t.issues.push("Maven not found \u2014 install Maven 3.9+ or add Maven Wrapper"),t.fixCommands?.push("https://maven.apache.org/install.html");}}else if(g&&!E)try{await execa("gradle",["--version"],{timeout:3e3,reject:false});}catch{t.issues.push("Gradle not found \u2014 install Gradle 8+ or add Gradle Wrapper"),t.fixCommands?.push("https://gradle.org/install/");}let b=o.join(e,"target"),j=o.join(e,"build","libs"),I=o.join(e,".rapidkit","cache","java","m2"),R=o.join(e,".rapidkit","cache","java","gradle");t.depsInstalled=await i.pathExists(b)||await i.pathExists(j)||await i.pathExists(I)||await i.pathExists(R),t.depsInstalled||(t.issues.push("Java dependencies are not warmed or built yet"),t.fixCommands?.push(S(e,"rapidkit init")));let G=o.join(e,".env");if(t.hasEnvFile=await i.pathExists(G),!t.hasEnvFile){let q=o.join(e,".env.example");await i.pathExists(q)&&(t.issues.push("Environment file missing (found .env.example)"),t.fixCommands?.push(O(e)));}let K=o.join(e,"src","main","resources","application.yml");if(await i.pathExists(K))try{let q=await i.readFile(K,"utf-8");/include:\s*[^\n]*health/i.test(q)||/management:\s*[\s\S]*endpoint:\s*[\s\S]*health:/i.test(q)||(t.issues.push("Actuator health endpoint exposure is not clearly configured in application.yml"),t.fixCommands?.push(S(e,"Ensure management.endpoints.web.exposure.include contains health in src/main/resources/application.yml")));}catch{t.issues.push("Unable to read application.yml for Spring Actuator health checks");}return await H(e,t),await W(e,t),await _(e,t),t}if(Me){F(t,"Rust","high"),t.venvActive=true,t.coreInstalled=false;let y=o.join(e,"Cargo.lock"),g=o.join(e,"target");t.depsInstalled=await i.pathExists(y)||await i.pathExists(g),t.depsInstalled||(t.issues.push("Rust dependencies are not resolved yet (Cargo.lock/target missing)"),t.fixCommands?.push(S(e,"cargo fetch")));let C=o.join(e,".env");if(t.hasEnvFile=await i.pathExists(C),!t.hasEnvFile){let E=o.join(e,".env.example");await i.pathExists(E)&&(t.issues.push("Environment file missing (found .env.example)"),t.fixCommands?.push(O(e)));}return await H(e,t),await W(e,t),await _(e,t),t}if(Ge){let y="Elixir",g="medium";try{(await i.readFile(w,"utf8")).toLowerCase().includes("phoenix")&&(y="Phoenix",g="high");}catch{g="low";}F(t,y,g),t.venvActive=true,t.coreInstalled=false;let C=o.join(e,"mix.lock"),E=o.join(e,"deps");t.depsInstalled=await i.pathExists(C)||await i.pathExists(E),t.depsInstalled||(t.issues.push("Elixir dependencies not installed (mix.lock/deps missing)"),t.fixCommands?.push(S(e,"mix deps.get")));let b=o.join(e,".env");if(t.hasEnvFile=await i.pathExists(b),!t.hasEnvFile){let j=o.join(e,".env.example");await i.pathExists(j)&&(t.issues.push("Environment file missing (found .env.example)"),t.fixCommands?.push(O(e)));}return await H(e,t),await W(e,t),await _(e,t),t}if(We){F(t,"Clojure","medium"),t.venvActive=true,t.coreInstalled=false;let y=o.join(e,".cpcache"),g=o.join(e,"target"),C=await i.pathExists(v)||await i.pathExists($);return t.depsInstalled=await i.pathExists(y)||await i.pathExists(g)||C,t.depsInstalled||(t.issues.push("Clojure dependency cache not initialized"),t.fixCommands?.push(S(e,"clojure -P"))),await H(e,t),await W(e,t),await _(e,t),t}if(_e){F(t,"Scala","high"),t.venvActive=true,t.coreInstalled=false;let y=o.join(e,"target");t.depsInstalled=await i.pathExists(y),t.depsInstalled||(t.issues.push("Scala build artifacts missing (run dependency/build warmup)"),t.fixCommands?.push(S(e,"sbt compile")));let g=o.join(e,".env");if(t.hasEnvFile=await i.pathExists(g),!t.hasEnvFile){let C=o.join(e,".env.example");await i.pathExists(C)&&(t.issues.push("Environment file missing (found .env.example)"),t.fixCommands?.push(O(e)));}return await H(e,t),await W(e,t),await _(e,t),t}if(Be){F(t,"Deno","high"),t.venvActive=true,t.coreInstalled=false,t.depsInstalled=true;let y=o.join(e,".env");if(t.hasEnvFile=await i.pathExists(y),!t.hasEnvFile){let g=o.join(e,".env.example");await i.pathExists(g)&&(t.issues.push("Environment file missing (found .env.example)"),t.fixCommands?.push(O(e)));}return await H(e,t),await W(e,t),await _(e,t),t}if(M){let y=null;try{y=await i.readJson(d);}catch{y=null;}let g={...y?.dependencies??{},...y?.devDependencies??{}},C=y?.scripts??{},E=typeof c?.kit_name=="string"?c.kit_name.toLowerCase():typeof c?.kit=="string"?c.kit.toLowerCase():"",b=tt({dependencies:g,scripts:C,kitName:E});ye?F(t,"Bun","high"):F(t,b.framework,b.confidence),t.venvActive=true;let j=o.join(e,"node_modules");if(await i.pathExists(j))try{let G=(await i.readdir(j)).filter(K=>!K.startsWith(".")&&!K.startsWith("_"));t.depsInstalled=G.length>0;}catch{t.depsInstalled=false;}if(t.depsInstalled||(t.issues.push("Dependencies not installed (node_modules empty or missing)"),t.fixCommands?.push(S(e,ye?"bun install":"rapidkit init"))),t.coreInstalled=false,t.projectKind==="frontend"){let R=[".env",".env.local",".env.development",".env.development.local",".env.production",".env.production.local"];if((await Promise.all(R.map(K=>i.pathExists(o.join(e,K))))).some(Boolean))t.hasEnvFile=true;else {let K=o.join(e,".env.example");await i.pathExists(K)&&(t.hasEnvFile=false,t.issues.push("Environment file missing (found .env.example)"),t.fixCommands?.push(O(e)));}}else {let R=o.join(e,".env");if(t.hasEnvFile=await i.pathExists(R),!t.hasEnvFile){let G=o.join(e,".env.example");await i.pathExists(G)&&(t.issues.push("Environment file missing (found .env.example)"),t.fixCommands?.push(O(e)));}}let I=o.join(e,"src");if(t.modulesHealthy=true,t.missingModules=[],await i.pathExists(I))try{let R=await i.readdir(I);t.modulesHealthy=R.length>0;}catch{t.modulesHealthy=false;}return await H(e,t),await W(e,t),await _(e,t),t}if(A){let y=await st(e);F(t,y.framework,y.confidence);let g=o.join(e,".venv");if(await i.pathExists(g)){t.venvActive=true;let j=f(g);if(await i.pathExists(j)){try{let{stdout:G}=await execa(j,["-c","import rapidkit_core; print(rapidkit_core.__version__)"],{timeout:2e3});t.coreInstalled=true,t.coreVersion=G.trim();}catch{t.coreInstalled=false;}let I="fastapi";t.framework==="Django"?I="django":t.framework==="Flask"?I="flask":t.framework==="Python"&&(I="");let R=true;if(I)try{await execa(j,["-c",`import ${I}`],{timeout:2e3}),t.depsInstalled=true,R=false;}catch{R=true;}if(R)try{let G=o.join(g,"lib");if(await i.pathExists(G)){let q=(await i.readdir(G)).find(te=>te.startsWith("python"));if(q){let te=o.join(G,q,"site-packages");if(await i.pathExists(te)){let Te=(await i.readdir(te)).filter(ce=>!ce.startsWith("_")&&!ce.includes("dist-info")&&!["pip","setuptools","wheel","pkg_resources"].includes(ce));t.depsInstalled=Te.length>0;}}}t.depsInstalled||(t.issues.push("Dependencies not installed"),t.fixCommands?.push(S(e,"rapidkit init")));}catch{t.issues.push("Could not verify dependency installation");}}else t.issues.push("Virtual environment exists but Python executable not found");}else t.issues.push("Virtual environment not created"),t.fixCommands?.push(S(e,"rapidkit init"));let C=o.join(e,".env");if(t.hasEnvFile=await i.pathExists(C),!t.hasEnvFile){let j=o.join(e,".env.example");await i.pathExists(j)&&(t.issues.push("Environment file missing (found .env.example)"),t.fixCommands?.push(O(e)));}let E=o.join(e,"src"),b=o.join(e,"modules");if(t.modulesHealthy=true,t.missingModules=[],await i.pathExists(E)){let j=o.join(E,"__init__.py");await i.pathExists(j)||(t.modulesHealthy=false,t.missingModules.push("src/__init__.py"));}if(await i.pathExists(b))try{let j=await Fe(b);for(let I of j){let R=o.join(b,I,"__init__.py");await i.pathExists(R)||(t.modulesHealthy=false,t.missingModules.push(`modules/${I}/__init__.py`));}}catch{}return !t.modulesHealthy&&t.missingModules.length>0&&t.issues.push(`Missing module init files: ${t.missingModules.join(", ")}`),await H(e,t),await W(e,t),await _(e,t),t}if(Z){let y="PHP",g="medium";try{let b=await i.readJson(Y);({...b?.require??{},...b?.["require-dev"]??{}})["laravel/framework"]?(y="Laravel",g="high"):(y="PHP",g="medium");}catch{y="PHP",g="low";}F(t,y,g),t.venvActive=true,t.coreInstalled=false;let C=o.join(e,"vendor");t.depsInstalled=await i.pathExists(C),t.depsInstalled||(t.issues.push("PHP dependencies not installed (vendor missing)"),t.fixCommands?.push(S(e,"composer install")));let E=o.join(e,".env");if(t.hasEnvFile=await i.pathExists(E),!t.hasEnvFile){let b=o.join(e,".env.example");await i.pathExists(b)&&(t.issues.push("Environment file missing (found .env.example)"),t.fixCommands?.push(O(e)));}return await H(e,t),await W(e,t),await _(e,t),t}if(ee){let y="Ruby",g="low";try{let j=(await i.readFile(J,"utf8")).toLowerCase();j.includes("gem 'rails'")||j.includes('gem "rails"')?(y="Ruby on Rails",g="high"):(y="Ruby",g="medium");}catch{g="low";}F(t,y,g),t.venvActive=true,t.coreInstalled=false;let C=await i.pathExists(o.join(e,"Gemfile.lock")),E=await i.pathExists(o.join(e,"vendor","bundle"));t.depsInstalled=C||E,t.depsInstalled||(t.issues.push("Ruby dependencies not installed (Gemfile.lock/vendor missing)"),t.fixCommands?.push(S(e,"bundle install")));let b=o.join(e,".env");return t.hasEnvFile=await i.pathExists(b),await H(e,t),await W(e,t),await _(e,t),t}if(re){F(t,"ASP.NET","medium"),t.venvActive=true,t.coreInstalled=false;let y=o.join(e,"obj"),g=o.join(e,"packages.lock.json");t.depsInstalled=await i.pathExists(y)||await i.pathExists(g),t.depsInstalled||(t.issues.push(".NET restore/build artifacts not found"),t.fixCommands?.push(S(e,"dotnet restore")));let C=o.join(e,".env");return t.hasEnvFile=await i.pathExists(C),await H(e,t),t}return F(t,"Unknown","low"),t.issues.push("Unknown project type (no recognized runtime marker files)"),await H(e,t),await W(e,t),await _(e,t),t}async function Fe(e){try{return (await i.readdir(e,{withFileTypes:true})).filter(a=>a.isDirectory()).map(a=>a.name)}catch{try{let s=await i.readdir(e),a=[];for(let t of s)try{(await i.stat(o.join(e,t))).isDirectory()&&a.push(t);}catch{continue}return a}catch{return []}}}async function ae(e){let s=o.join(e,".rapidkit");if(!await i.pathExists(s))return false;let a=["project.json","context.json","file-hashes.json"];for(let t of a)if(await i.pathExists(o.join(s,t)))return true;return false}function De(e,s){if(s.has(e))return true;let a=e.toLowerCase();return !!(a==="dist"||a.startsWith("dist-")||a.startsWith("dist_")||a==="build"||a.startsWith("build-")||a.startsWith("build_"))}async function gt(e,s,a){let t=new Set,r=[{dir:e,depth:0}];for(;r.length>0;){let n=r.shift();if(!n)break;try{let c=await i.readdir(n.dir);for(let d of c){if(De(d,a))continue;let u=o.join(n.dir,d),m;try{m=await i.stat(u);}catch{continue}if(m.isDirectory()){if(await ae(u)){t.add(u);continue}n.depth<s&&r.push({dir:u,depth:n.depth+1});}}}catch{continue}}return Array.from(t)}async function me(e){let s=e,a=o.parse(s).root;for(;s!==a;){let t=[o.join(s,".rapidkit-workspace"),o.join(s,".rapidkit","workspace-marker.json"),o.join(s,".rapidkit","config.json")];for(let r of t)if(await i.pathExists(r))return s;s=o.dirname(s);}return null}async function ht(e){let s=e,a=o.parse(s).root;for(;;){if(await ae(s)||await yt(s))return s;if(s===a)break;s=o.dirname(s);}return null}function xe(e){let s=o.resolve(e);return process.platform==="darwin"?s.replace(/^\/private(?=\/var\/)/,""):s}async function yt(e){let s=["package.json","pyproject.toml","requirements.txt","go.mod","pom.xml","build.sbt","Cargo.toml","mix.exs","deps.edn","project.clj","deno.json","deno.jsonc","composer.json","Gemfile"];for(let a of s)if(await i.pathExists(o.join(e,a)))return true;return false}function Ae(e,s){let a=0,t=0,r=0;return e.forEach(c=>{c.status==="ok"?a++:c.status==="warn"?t++:c.status==="error"&&r++;}),s.forEach(c=>{let d=Q(c),u=c.isGoProject?c.issues.length===0&&c.depsInstalled:c.issues.length===0&&c.venvActive&&c.depsInstalled;if(c.issues.length>0||d>0||!u){t++;return}a++;}),{total:a+t+r,passed:a,warnings:t,errors:r}}function Ie(e,s,a={}){let t=[];for(let n of e)t.push({id:n.id,label:n.label,status:n.result.status,scope:"host-system",policyRuleId:"system-status-derived",reason:n.result.details||n.result.message});let r=[...s].sort((n,c)=>{let d=`${n.path||""}|${n.name||""}`.toLowerCase(),u=`${c.path||""}|${c.name||""}`.toLowerCase();return d.localeCompare(u)});for(let n of r){let c=n.issues.length>0,d=Q(n),u=c||d>0?"warn":"ok",m=c?`${n.issues.length} blocking issue(s)`:d>0?`${d} advisory warning(s)`:"Project checks passed";t.push({id:`project:${n.name}`,label:`Project ${n.name}`,status:u,scope:"project-scoped",policyRuleId:c?"project-blocking-issues":d>0?"project-advisory-warnings":"project-checks-passed",reason:m});}if(a.includeWorkspaceAggregateRules){let n=s.reduce((u,m)=>u+m.issues.length,0),c=fe(s),d=e.filter(u=>u.result.status==="error").length;t.push({id:"workspace:projects-discovered",label:"Workspace projects discovered",status:s.length>0?"ok":"warn",scope:"workspace-aggregate",policyRuleId:"workspace-project-discovery",reason:s.length>0?`${s.length} project(s) discovered for workspace analysis.`:"No projects discovered for workspace analysis."}),t.push({id:"workspace:system-error-gate",label:"Workspace system error gate",status:d>0?"error":"ok",scope:"workspace-aggregate",policyRuleId:"workspace-system-error-gate",reason:d>0?`${d} system requirement gate(s) failed.`:"All system requirement gates passed."}),t.push({id:"workspace:blocking-issues-gate",label:"Workspace blocking issues gate",status:n>0?"warn":"ok",scope:"workspace-aggregate",policyRuleId:"workspace-blocking-issues-gate",reason:n>0?`${n} blocking project issue(s) detected.`:"No blocking project issues detected."}),t.push({id:"workspace:advisory-warnings-gate",label:"Workspace advisory warnings gate",status:c>0?"warn":"ok",scope:"workspace-aggregate",policyRuleId:"workspace-advisory-warning-gate",reason:c>0?`${c} advisory warning(s) detected.`:"No advisory warnings detected."});}return t}async function be(e,s=true){let a$1=o.basename(e);try{let f=o.join(e,".rapidkit-workspace");await i.pathExists(f)&&(a$1=(await i.readJSON(f)).name||a$1);}catch{try{let f=o.join(e,".rapidkit","config.json");a$1=(await i.readJSON(f)).workspace_name||a$1;}catch{}}let[t,r]=await Promise.all([ge(),nt(e)]),n={workspacePath:e,workspaceName:a$1,python:t.python,poetry:t.poetry,pipx:t.pipx,go:t.go,rapidkitCore:t.rapidkitCore,projects:[]};a.debug(`Workspace scan found ${r.length} project(s)`);let c=await ot(e,r),d=o.join(e,".rapidkit","reports","doctor-workspace-cache.json"),u=s?await it(d,c):null;if(u)n.projects=u.projects,n.projectScanCached=true,a.debug(`Workspace project health cache hit: ${d}`);else try{let f=await Promise.all(r.map(k=>he(k)));n.projects=f,n.projectScanCached=false,await at(d,{signature:c,generatedAt:new Date().toISOString(),projects:f}),a.debug(`Workspace project health cache refreshed: ${d}`);}catch(f){a.debug(`Failed to scan workspace projects: ${f}`);}n.projectScanSignature=c,n.projectScanCachePath=d;let m=[n.python,n.poetry,n.pipx,n.go,n.rapidkitCore];if(n.healthScore=Ae(m,n.projects),n.scoreBreakdown=Ie([{id:"system-python",label:"Python",result:n.python},{id:"system-poetry",label:"Poetry",result:n.poetry},{id:"system-pipx",label:"pipx",result:n.pipx},{id:"system-go",label:"Go",result:n.go},{id:"system-rapidkit-core",label:"RapidKit Core",result:n.rapidkitCore}],n.projects,{includeWorkspaceAggregateRules:true}),n.scopeProvenance=Re(n.scoreBreakdown),n.rapidkitCore.status==="ok"){let f=n.rapidkitCore.message.match(/([\d.]+(?:rc\d+)?(?:a\d+)?(?:b\d+)?)/);f&&(n.coreVersion=f[1]);}let p=o.join(e,".rapidkit","reports","doctor-last-run.json"),h=await Se(p);return n.driftDelta=Qe(h,n),n.evidencePath=await rt(e,n,u?d:null),n}async function wt(e,s){let a=e||s.projectPath,t=o.join(a,".rapidkit","reports","doctor-project-last-run.json");try{return await i.ensureDir(o.dirname(t)),await i.writeJSON(t,{generatedAt:new Date().toISOString(),contract:oe(),workspacePath:e||null,projectPath:s.projectPath,projectName:s.projectName,healthScore:s.healthScore,system:{python:s.python,poetry:s.poetry,pipx:s.pipx,go:s.go,rapidkitCore:s.rapidkitCore},project:s.project,driftDelta:s.driftDelta,summary:{scopeProvenance:s.scopeProvenance},scoreBreakdown:s.scoreBreakdown??[]},{spaces:2}),t}catch{return}}async function kt(e){let s=await me(e),a=await ge(),t=await he(e,{allowNonRapidkit:true}),r=Ae([a.python,a.poetry,a.pipx,a.go,a.rapidkitCore],[t]),n={workspacePath:s||void 0,projectPath:e,projectName:o.basename(e),python:a.python,poetry:a.poetry,pipx:a.pipx,go:a.go,rapidkitCore:a.rapidkitCore,project:t,healthScore:r};n.scoreBreakdown=Ie([{id:"system-python",label:"Python",result:n.python},{id:"system-poetry",label:"Poetry",result:n.poetry},{id:"system-pipx",label:"pipx",result:n.pipx},{id:"system-go",label:"Go",result:n.go},{id:"system-rapidkit-core",label:"RapidKit Core",result:n.rapidkitCore}],[n.project]),n.scopeProvenance=Re(n.scoreBreakdown);let c=s||e,d=o.join(c,".rapidkit","reports","doctor-project-last-run.json"),u=await Se(d);return n.driftDelta=Xe(u,n),n.evidencePath=await wt(s||void 0,n),n}function P(e,s){let a=e.status==="ok"?"\u2705":e.status==="warn"?"\u26A0\uFE0F":"\u274C",t=e.status==="ok"?l.green:e.status==="warn"?l.yellow:l.red;console.log(`${a} ${l.bold(s)}: ${t(e.message)}`),e.paths&&e.paths.length>0?e.paths.forEach(r=>{let n=r.version?l.cyan(` -> ${r.version}`):"";console.log(` ${l.cyan("\u2022")} ${l.gray(r.location)}: ${l.dim(r.path)}${n}`);}):e.details&&console.log(` ${l.gray(e.details)}`);}function je(e){let s=e.issues.length>0,a=s?"\u26A0\uFE0F":"\u2705",t=s?l.yellow:l.green;if(console.log(`
3
+ ${a} ${l.bold("Project")}: ${t(e.name)}`),e.framework){let c=e.framework==="FastAPI"||e.framework==="Django"||e.framework==="Flask"?"\u{1F40D}":e.framework==="NestJS"?"\u{1F985}":e.framework==="Next.js"||e.framework==="Nuxt"?"\u25B2":e.framework==="React"?"\u269B\uFE0F":e.framework==="Vue"?"\u{1F7E2}":e.framework==="Angular"?"\u{1F170}\uFE0F":e.framework==="SvelteKit"?"\u{1F9E1}":e.framework==="Spring Boot"?"\u2615":e.framework==="Rust"?"\u{1F980}":e.framework==="Elixir"||e.framework==="Phoenix"?"\u{1F9EA}":e.framework==="Clojure"?"\u2699\uFE0F":e.framework==="Scala"?"\u{1F53A}":e.framework==="Kotlin"?"\u{1F7E3}":e.framework==="Deno"?"\u{1F995}":e.framework==="Bun"?"\u{1F956}":e.framework==="Go/Fiber"||e.framework==="Go/Gin"?"\u{1F439}":e.framework==="Laravel"||e.framework==="PHP"?"\u{1F418}":e.framework==="Ruby on Rails"||e.framework==="Ruby"?"\u{1F48E}":e.framework==="ASP.NET"?"\u{1F537}":"\u{1F4E6}";console.log(` ${c} Framework: ${l.cyan(e.framework)}${e.kit?l.gray(` (${e.kit})`):""}`);let d=[];e.runtimeFamily&&d.push(`runtime: ${e.runtimeFamily}`),e.projectKind&&d.push(`kind: ${e.projectKind}`),e.supportTier&&d.push(`support: ${e.supportTier}`),e.frameworkConfidence&&d.push(`confidence: ${e.frameworkConfidence}`),d.length>0&&console.log(` ${l.dim("\u21B3")} ${l.gray(d.join(" \u2022 "))}`);}if(console.log(` ${l.gray(`Path: ${e.path}`)}`),e.runtimeFamily==="python"&&(e.venvActive?console.log(` \u2705 Virtual environment: ${l.green("Active")}`):console.log(` \u274C Virtual environment: ${l.red("Not found")}`),e.coreInstalled?console.log(` ${l.dim("\u2139")} RapidKit Core: ${l.gray(e.coreVersion||"In venv")} ${l.dim("(optional)")}`):console.log(` ${l.dim("\u2139")} RapidKit Core: ${l.gray("Using global installation")} ${l.dim("(recommended)")}`)),e.depsInstalled?console.log(` \u2705 Dependencies: ${l.green("Installed")}`):console.log(` \u26A0\uFE0F Dependencies: ${l.yellow("Not installed")}`),e.hasEnvFile!==void 0&&(e.hasEnvFile?console.log(` \u2705 Environment: ${l.green(".env configured")}`):console.log(` \u26A0\uFE0F Environment: ${l.yellow(".env missing")}`)),e.modulesHealthy!==void 0&&(e.modulesHealthy?console.log(` \u2705 Modules: ${l.green("Healthy")}`):e.missingModules&&e.missingModules.length>0&&console.log(` \u26A0\uFE0F Modules: ${l.yellow(`Missing ${e.missingModules.length} init file(s)`)}`)),e.stats){let c=[];e.stats.modules!==void 0&&c.push(`${e.stats.modules} module${e.stats.modules!==1?"s":""}`),c.length>0&&console.log(` \u{1F4CA} Stats: ${l.cyan(c.join(" \u2022 "))}`);}e.lastModified&&console.log(` \u{1F552} Last Modified: ${l.gray(e.lastModified)}`);let n=[];if(e.hasTests!==void 0&&n.push(e.hasTests?"\u2705 Tests":l.dim("\u2298 No tests")),e.hasDocker!==void 0&&n.push(e.hasDocker?"\u2705 Docker":l.dim("\u2298 No Docker")),e.hasCodeQuality!==void 0){let c=e.runtimeFamily==="node"?"ESLint":e.runtimeFamily==="rust"?"clippy":e.runtimeFamily==="elixir"?"Credo":e.runtimeFamily==="clojure"?"clj-kondo":e.runtimeFamily==="deno"?"deno lint":e.framework==="Spring Boot"?"Static analysis":e.framework==="Go/Fiber"||e.framework==="Go/Gin"?"golangci-lint":e.runtimeFamily==="python"?"Ruff":"Lint";n.push(e.hasCodeQuality?`\u2705 ${c}`:l.dim(`\u2298 No ${c}`));}if(n.length>0&&console.log(` ${n.join(" \u2022 ")}`),e.vulnerabilities!==void 0&&e.vulnerabilities>0&&console.log(` \u26A0\uFE0F Security: ${l.yellow(`${e.vulnerabilities} vulnerability(ies) found`)}`),e.issues.length>0&&(console.log(` ${l.bold("Issues:")}`),e.issues.forEach(c=>{console.log(` \u2022 ${l.yellow(c)}`);}),e.fixCommands&&e.fixCommands.length>0&&(console.log(`
4
+ ${l.bold.cyan("\u{1F527} Quick Fix:")}`),e.fixCommands.forEach(c=>{console.log(` ${l.cyan("$")} ${l.white(c)}`);}))),e.probes&&e.probes.length>0){console.log(` ${l.bold("Probe checks:")}`);for(let c of e.probes){let d=c.status==="pass"?"\u2705":c.status==="warn"?"\u26A0\uFE0F":"\u274C";console.log(` ${d} ${c.label}: ${l.gray(c.reason)}`),c.recommendation&&console.log(` ${l.dim("\u21B3")} ${l.gray(c.recommendation)}`);}}}async function Ce(){try{return (await execa("go",["version"],{timeout:3e3,reject:false})).exitCode===0}catch{return false}}function X(e,s){let a=[new RegExp(`^cd\\s+"([^"]+)"\\s*(?:&&|;)\\s*${s}\\s*$`,"i"),new RegExp(`^cd\\s+'([^']+)'\\s*(?:&&|;)\\s*${s}\\s*$`,"i"),new RegExp(`^cd\\s+(.+?)\\s*(?:&&|;)\\s*${s}\\s*$`,"i")];for(let t of a){let r=e.match(t);if(r?.[1])return {projectPath:r[1].trim()}}return null}function He(e){return X(e,"cp\\s+\\.env\\.example\\s+\\.env")||X(e,"copy-item\\s+\\.env\\.example\\s+\\.env")}function Ne(e){let s=[{pattern:"npm\\s+install",command:"npm",args:["install"]},{pattern:"npm\\s+ci",command:"npm",args:["ci"]},{pattern:"pnpm\\s+install",command:"pnpm",args:["install"]},{pattern:"yarn\\s+install",command:"yarn",args:["install"]},{pattern:"poetry\\s+install",command:"poetry",args:["install"]},{pattern:"pip\\s+install\\s+-r\\s+requirements\\.txt",command:"pip",args:["install","-r","requirements.txt"]},{pattern:"composer\\s+install",command:"composer",args:["install"]},{pattern:"bundle\\s+install",command:"bundle",args:["install"]},{pattern:"dotnet\\s+restore",command:"dotnet",args:["restore"]},{pattern:"cargo\\s+fetch",command:"cargo",args:["fetch"]},{pattern:"mix\\s+deps\\.get",command:"mix",args:["deps.get"]},{pattern:"clojure\\s+-P",command:"clojure",args:["-P"]},{pattern:"sbt\\s+compile",command:"sbt",args:["compile"]}];for(let a of s){let t=X(e,a.pattern);if(t)return {projectPath:t.projectPath,command:a.command,args:a.args}}return null}function ue(e,s){return /^https?:\/\//i.test(s.trim())?{projectName:e.name,projectPath:e.path,originalCommand:s,kind:"manual-url",risk:"safe",executable:false,reason:"Manual guidance URL"}:He(s)?{projectName:e.name,projectPath:e.path,originalCommand:s,kind:"env-copy",risk:"safe",executable:true,reason:"Environment seed copy"}:X(s,"rapidkit\\s+init")?{projectName:e.name,projectPath:e.path,originalCommand:s,kind:"rapidkit-init",risk:"guarded",executable:true,reason:"RapidKit initializer may mutate dependencies and configs"}:X(s,"go\\s+mod\\s+tidy")?{projectName:e.name,projectPath:e.path,originalCommand:s,kind:"go-mod-tidy",risk:"guarded",executable:true,reason:"Go module graph reconciliation"}:Ne(s)?{projectName:e.name,projectPath:e.path,originalCommand:s,kind:"dependency-sync",risk:"guarded",executable:true,reason:"Dependency synchronization command"}:{projectName:e.name,projectPath:e.path,originalCommand:s,kind:"shell",risk:"invasive",executable:true,reason:"Generic shell command"}}function Ee(e){let s=e instanceof Error?e.message:String(e),a=["ETIMEDOUT","ECONNRESET","ECONNREFUSED","EAI_AGAIN","ENOTFOUND","network","503","504"],t=s.toLowerCase();return a.some(r=>t.includes(r.toLowerCase()))}async function vt(e,s){let a=e.get(s);if(a)return a;let t=`${Date.now()}-${Math.random().toString(36).slice(2,8)}`,r=o.basename(s).replace(/[^a-zA-Z0-9._-]/g,"_"),n=o.join(s,".rapidkit","reports","fix-snapshots",`${r}-${t}`);await i.ensureDir(n);let c=[".env","package-lock.json","pnpm-lock.yaml","yarn.lock","poetry.lock","requirements.txt","go.mod","go.sum","Cargo.lock","composer.lock","Gemfile.lock","pom.xml","build.gradle","build.gradle.kts","gradle.lockfile"],d=new Map;for(let m of c){let p=o.join(s,m);if(!await i.pathExists(p))continue;let h=o.join(n,m);await i.ensureDir(o.dirname(h)),await i.copy(p,h,{overwrite:true}),d.set(p,h);}let u={snapshotRoot:n,files:d};return e.set(s,u),u}async function xt(e){for(let[s,a]of e.files.entries())await i.pathExists(a)&&(await i.ensureDir(o.dirname(s)),await i.copy(a,s,{overwrite:true}));}async function bt(e){let s=await he(e,{allowNonRapidkit:true});return {issues:s.issues.length,healthy:s.issues.length===0}}async function ne(e,s=false){let a=e.filter(f=>f.fixCommands&&f.fixCommands.length>0),t=null,r=new Map;if(a.length===0){console.log(l.green(`
5
+ \u2705 No fixes needed - all projects are healthy!`));return}let n=a.flatMap(f=>(f.fixCommands??[]).map(k=>ue(f,k)));console.log(l.bold.cyan(`
6
+ \u{1F527} Available Fixes:
7
+ `));for(let f of a){let k=f.fixCommands??[];console.log(l.bold(`Project: ${l.yellow(f.name)}`)),k.forEach((w,v)=>{console.log(` ${v+1}. ${l.cyan(w)}`);}),console.log();}let c=0,d=0,u=0,m=0;for(let f of n)f.executable&&(f.kind==="go-mod-tidy"&&(t===null&&(t=await Ce()),!t)||(c+=1,f.risk==="safe"&&(d+=1),f.risk==="guarded"&&(u+=1),f.risk==="invasive"&&(m+=1)));if(c===0){console.log(l.gray("\u{1F4A1} No automatic fixes can be applied right now.")),t===false&&console.log(l.gray(" Install Go to enable go mod tidy fixes, then rerun `rapidkit doctor workspace --fix`."));return}if(!s){console.log(l.gray('\u{1F4A1} Run "npx rapidkit doctor workspace --fix" to apply fixes automatically'));return}console.log(l.gray(`Risk policy: safe=${d}, guarded=${u}, invasive=${m}. Guarded/invasive fixes use snapshot + rollback.`));let{confirm:p}=await Oe.prompt([{type:"confirm",name:"confirm",message:`Apply ${a.reduce((f,k)=>f+(k.fixCommands?.length??0),0)} fix(es)?`,default:false}]);if(!p){console.log(l.yellow(`
8
+ \u26A0\uFE0F Fixes cancelled by user`));return}console.log(l.bold.cyan(`
9
+ \u{1F680} Applying fixes...
10
+ `));let h=new Set;for(let f of a){let k=f.fixCommands??[];console.log(l.bold(`Fixing ${l.cyan(f.name)}...`));for(let w of k){let v=ue(f,w),$=`${f.path}::${w}`;if(!h.has($)){h.add($);try{if(console.log(l.gray(` $ ${w}`)),v.kind==="manual-url"){console.log(l.yellow(` \u2139 Manual action required: open ${w}`)),console.log(l.green(` \u2705 Recorded as guidance
11
+ `));continue}if(!v.executable){console.log(l.yellow(" \u26A0 Step is non-executable by policy")),console.log(l.green(` \u2705 Recorded as guidance
12
+ `));continue}v.risk!=="safe"&&await vt(r,v.projectPath);let D=He(w);if(D){let M=o.join(D.projectPath,".env.example"),A=o.join(D.projectPath,".env");if(!await i.pathExists(M))throw new Error(`.env.example not found at ${M}`);if(await i.pathExists(A)){console.log(l.green(` \u2705 .env already exists
13
+ `));continue}await i.copy(M,A,{overwrite:false,errorOnExist:false}),console.log(l.green(` \u2705 Success
14
+ `));continue}let L=X(w,"rapidkit\\s+init");if(L){await execa("rapidkit",["init"],{cwd:L.projectPath,shell:b(),stdio:"inherit"}),console.log(l.green(` \u2705 Success
15
+ `));continue}let V=X(w,"go\\s+mod\\s+tidy");if(V){if(t===null&&(t=await Ce()),!t){console.log(l.yellow(" \u26A0 Go toolchain is not installed \u2014 skipping go mod tidy; install Go to apply this fix.")),console.log(l.green(` \u2705 Recorded as guidance
16
+ `));continue}await execa("go",["mod","tidy"],{cwd:V.projectPath,shell:b(),stdio:"inherit"}),console.log(l.green(` \u2705 Success
17
+ `));continue}let B=Ne(w);if(B){let A;for(let Z=1;Z<=2;Z+=1)try{await execa(B.command,B.args,{cwd:B.projectPath,shell:b(),stdio:"inherit"}),A=null;break}catch(ee){if(A=ee,Z<2&&Ee(ee)){console.log(l.yellow(` \u26A0 Retrying dependency sync (${Z}/1)...`));continue}throw ee}if(A)throw A;console.log(l.green(` \u2705 Success
18
+ `));continue}let Y=v.kind==="shell"?2:1,J;for(let M=1;M<=Y;M+=1)try{await execa(w,{shell:true,stdio:"inherit"}),J=null;break}catch(A){if(J=A,M<Y&&Ee(A)){console.log(l.yellow(` \u26A0 Retrying command (${M}/${Y-1})...`));continue}throw A}if(J)throw J;console.log(l.green(` \u2705 Success
19
+ `));}catch(D){let L=ue(f,w);if(L.risk!=="safe"){let V=r.get(L.projectPath);if(V)try{await xt(V),console.log(l.yellow(" \u21A9 Rolled back snapshot after failed fix"));}catch(B){console.log(l.red(` \u274C Rollback failed: ${B instanceof Error?B.message:String(B)}`));}}console.log(l.red(` \u274C Failed: ${D instanceof Error?D.message:String(D)}
20
+ `));}}}try{let w=await bt(f.path);console.log(w.healthy?l.green(` \u2705 Post-fix verification passed for ${f.name}`):l.yellow(` \u26A0 Post-fix verification: ${w.issues} issue(s) remain for ${f.name}`));}catch(w){console.log(l.yellow(` \u26A0 Post-fix verification skipped: ${w instanceof Error?w.message:String(w)}`));}}console.log(l.bold.green(`
21
+ \u2705 Fix process completed!`));}async function Ht(e={}){let s=!e.workspace&&!e.project&&e.fix?await me(process.cwd()):null,a$1=e.workspace||!!s,t=!!e.project&&!a$1;if(e.json||console.log(l.bold.cyan(`
22
+ \u{1FA7A} RapidKit Health Check
23
+ `)),a$1){let r=s??await me(process.cwd());r||(a.error("No RapidKit workspace found in current directory or parents"),a.info('Run this command from within a workspace, or use "rapidkit doctor" for system check'),process.exit(1)),e.json||(s&&console.log(l.gray("\u2139\uFE0F Detected workspace context; enabling workspace checks for --fix")),console.log(l.bold(`Workspace: ${l.cyan(o.basename(r))}`)),console.log(l.gray(`Path: ${r}`)));let n=await be(r);if(e.json||(n.projectScanCached&&console.log(l.gray(`\u2139\uFE0F Reused cached project scan${n.projectScanCachePath?` (${o.basename(n.projectScanCachePath)})`:""}`)),n.evidencePath&&console.log(l.gray(`\u2139\uFE0F Evidence saved: ${n.evidencePath}`))),e.json){let m={contract:oe(),workspace:{name:o.basename(r),path:r},cache:{projectScan:n.projectScanCached??false,projectScanPath:n.projectScanCachePath,evidencePath:n.evidencePath},healthScore:n.healthScore,system:{python:n.python,poetry:n.poetry,pipx:n.pipx,rapidkitCore:n.rapidkitCore,versions:{core:n.coreVersion,npm:n.npmVersion}},projects:n.projects.map(p=>({name:p.name,path:p.path,framework:p.framework,runtimeFamily:p.runtimeFamily,projectKind:p.projectKind,supportTier:p.supportTier,frameworkConfidence:p.frameworkConfidence,venvActive:p.venvActive,depsInstalled:p.depsInstalled,hasEnvFile:p.hasEnvFile,vulnerabilities:p.vulnerabilities,coreInstalled:p.coreInstalled,coreVersion:p.coreVersion,issues:p.issues,fixCommands:p.fixCommands,probes:p.probes})),summary:{totalProjects:n.projects.length,totalIssues:n.projects.reduce((p,h)=>p+h.issues.length,0),projectAdvisoryWarningProjects:pe(n.projects),projectAdvisoryWarnings:fe(n.projects),hasSystemErrors:[n.python,n.rapidkitCore].some(p=>p.status==="error"),scopeProvenance:n.scopeProvenance},driftDelta:n.driftDelta,scoreBreakdown:n.scoreBreakdown??[]};console.log(JSON.stringify(m,null,2));return}if(n.healthScore){let m=n.healthScore,p=Math.round(m.passed/m.total*100),h=p>=80?l.green:p>=50?l.yellow:l.red,f="\u2588".repeat(Math.floor(p/5))+"\u2591".repeat(20-Math.floor(p/5));console.log(l.bold(`
24
+ \u{1F4CA} Health Score:`)),console.log(` ${h(`${p}%`)} ${l.gray(f)}`),console.log(` ${l.green(`\u2705 ${m.passed} passed`)} ${l.gray("|")} ${l.yellow(`\u26A0\uFE0F ${m.warnings} warnings`)} ${l.gray("|")} ${l.red(`\u274C ${m.errors} errors`)}`);}if(console.log(l.bold(`
25
+
26
+ System Tools:
27
+ `)),P(n.python,"Python"),P(n.poetry,"Poetry"),P(n.pipx,"pipx"),P(n.go,"Go"),P(n.rapidkitCore,"RapidKit Core"),n.coreVersion&&n.npmVersion){let m=n.coreVersion.split(".")[1],p=n.npmVersion.split(".")[1];m!==p&&(console.log(l.yellow(`
28
+ \u26A0\uFE0F Version mismatch: Core ${n.coreVersion} / CLI ${n.npmVersion}`)),console.log(l.gray(" Consider updating to matching versions for best compatibility")));}n.projects.length>0?(console.log(l.bold(`
29
+ \u{1F4E6} Projects (${n.projects.length}):`)),n.projects.forEach(m=>je(m))):(console.log(l.bold(`
30
+ \u{1F4E6} Projects:`)),console.log(l.gray(" No RapidKit projects found in workspace")));let c=n.projects.reduce((m,p)=>m+p.issues.length,0),d=pe(n.projects),u=[n.python,n.rapidkitCore].some(m=>m.status==="error");if(u||c>0||d>0){let m=d>0?` and ${d} advisory warning project(s)`:"";if(console.log(l.bold.yellow(`
31
+ \u26A0\uFE0F Found ${c} project issue(s)${m}`)),u&&console.log(l.bold.red("\u274C System requirements not met")),e.fix){if(await ne(n.projects,true),!e.json){let p=await be(r,false),h=p.projects.reduce((k,w)=>k+w.issues.length,0),f=[p.python,p.rapidkitCore].some(k=>k.status==="error");f||h>0?(console.log(l.bold.yellow(`
32
+ \u26A0\uFE0F Post-fix verification found ${h} remaining issue(s)`)),f&&console.log(l.bold.red("\u274C System requirements still not met"))):console.log(l.bold.green(`
33
+ \u2705 Post-fix verification passed. Workspace is healthy.`)),p.projectScanCached&&console.log(l.gray(`\u2139\uFE0F Reused cached project scan${p.projectScanCachePath?` (${o.basename(p.projectScanCachePath)})`:""}`)),p.evidencePath&&console.log(l.gray(`\u2139\uFE0F Evidence refreshed: ${p.evidencePath}`));}}else c>0&&await ne(n.projects,false);}else console.log(l.bold.green(`
34
+ \u2705 All checks passed! Workspace is healthy.`));}else if(t){let r=await ht(process.cwd());r||(a.error("No RapidKit project found in current directory or parents"),a.info('Run this command from within a project, or use "rapidkit doctor workspace" for workspace checks'),process.exit(1));let n=await kt(r),c=n.workspacePath?xe(n.workspacePath):null,d=xe(n.project.path);if(e.json){let v={contract:oe(),scope:"project",workspace:c?{name:o.basename(c),path:c}:null,project:{name:n.project.name,path:d,framework:n.project.framework,runtimeFamily:n.project.runtimeFamily,projectKind:n.project.projectKind,supportTier:n.project.supportTier,frameworkConfidence:n.project.frameworkConfidence,venvActive:n.project.venvActive,depsInstalled:n.project.depsInstalled,hasEnvFile:n.project.hasEnvFile,vulnerabilities:n.project.vulnerabilities,coreInstalled:n.project.coreInstalled,coreVersion:n.project.coreVersion,issues:n.project.issues,fixCommands:n.project.fixCommands,probes:n.project.probes},evidencePath:n.evidencePath,healthScore:n.healthScore,system:{python:n.python,poetry:n.poetry,pipx:n.pipx,go:n.go,rapidkitCore:n.rapidkitCore},summary:{totalProjects:1,totalIssues:n.project.issues.length,projectAdvisoryWarningProjects:Q(n.project)>0?1:0,projectAdvisoryWarnings:Q(n.project),hasSystemErrors:[n.python,n.rapidkitCore].some($=>$.status==="error"),scopeProvenance:n.scopeProvenance},driftDelta:n.driftDelta,scoreBreakdown:n.scoreBreakdown??[]};console.log(JSON.stringify(v,null,2));return}console.log(l.bold(`Project: ${l.cyan(o.basename(r))}`)),console.log(l.gray(`Path: ${r}`)),n.workspacePath&&console.log(l.gray(`Workspace: ${o.basename(n.workspacePath)}`)),n.evidencePath&&console.log(l.gray(`\u2139\uFE0F Evidence saved: ${n.evidencePath}`));let u=n.healthScore,m=u.total>0?Math.round(u.passed/u.total*100):0,p=m>=80?l.green:m>=50?l.yellow:l.red,h="\u2588".repeat(Math.floor(m/5))+"\u2591".repeat(20-Math.floor(m/5));console.log(l.bold(`
35
+ \u{1F4CA} Health Score:`)),console.log(` ${p(`${m}%`)} ${l.gray(h)}`),console.log(` ${l.green(`\u2705 ${u.passed} passed`)} ${l.gray("|")} ${l.yellow(`\u26A0\uFE0F ${u.warnings} warnings`)} ${l.gray("|")} ${l.red(`\u274C ${u.errors} errors`)}`),console.log(l.bold(`
36
+
37
+ System Tools:
38
+ `)),P(n.python,"Python"),P(n.poetry,"Poetry"),P(n.pipx,"pipx"),P(n.go,"Go"),P(n.rapidkitCore,"RapidKit Core"),console.log(l.bold(`
39
+ \u{1F4E6} Project (1):`)),je(n.project);let f=[n.python,n.rapidkitCore].some(v=>v.status==="error"),k=n.project.issues.length,w=Q(n.project);if(f||k>0||w>0){let v=w>0?` and ${w} advisory warning(s)`:"";console.log(l.bold.yellow(`
40
+ \u26A0\uFE0F Found ${k} project issue(s)${v}`)),f&&console.log(l.bold.red("\u274C System requirements not met")),e.fix?await ne([n.project],true):k>0&&await ne([n.project],false);}else console.log(l.bold.green(`
41
+ \u2705 All checks passed! Project is healthy.`));}else {console.log(l.bold(`System Tools:
42
+ `));let r=await ge(),n=r.python,c=r.poetry,d=r.pipx,u=r.go,m=r.rapidkitCore;P(n,"Python"),P(c,"Poetry"),P(d,"pipx"),P(u,"Go"),P(m,"RapidKit Core"),[n,m].some(h=>h.status==="error")?(console.log(l.bold.red(`
43
+ \u274C Some required tools are missing`)),e.fix&&console.log(l.gray(`
44
+ Tip: Project auto-fix runs in workspace mode. Run from a workspace and use "rapidkit doctor workspace --fix"`)),console.log(l.gray(`
45
+ Tip: Run "rapidkit doctor workspace" for detailed project checks`))):(console.log(l.bold.green(`
46
+ \u2705 All required tools are installed!`)),e.fix&&console.log(l.gray(`
47
+ Tip: Project auto-fix runs in workspace mode. Run from a workspace and use "rapidkit doctor workspace --fix"`)),console.log(l.gray(`
48
+ Tip: Run "rapidkit doctor workspace" for detailed project checks`)));}console.log("");}export{Ht as runDoctor};
package/dist/index.d.ts CHANGED
@@ -11,6 +11,7 @@ declare function detectWindowsDoctorWorkspaceShadow(params: {
11
11
  scope?: string;
12
12
  workspaceFlag?: boolean;
13
13
  }, cwd?: string, platform?: NodeJS.Platform): Promise<DoctorWorkspaceShadowDiagnostic>;
14
+ declare function installWorkspaceDependencies(workspacePath: string): Promise<number>;
14
15
  declare function handleBootstrapCommand(args: string[], initRunner?: (nextArgs: string[]) => Promise<number>): Promise<number>;
15
16
  declare function handleSetupCommand(args: string[]): Promise<number>;
16
17
  declare function handleCacheCommand(args: string[]): Promise<number>;
@@ -18,4 +19,4 @@ declare function handleMirrorCommand(args: string[]): Promise<number>;
18
19
  declare function handleInitCommand(args: string[]): Promise<number>;
19
20
  declare function shouldForwardToCore(args: string[]): Promise<boolean>;
20
21
 
21
- export { type DoctorWorkspaceShadowDiagnostic, NPM_ONLY_TOP_LEVEL_COMMANDS, WRAPPER_ORCHESTRATED_PROJECT_COMMANDS, detectWindowsDoctorWorkspaceShadow, handleBootstrapCommand, handleCacheCommand, handleCreateOrFallback, handleInitCommand, handleMirrorCommand, handleSetupCommand, shouldForwardToCore };
22
+ export { type DoctorWorkspaceShadowDiagnostic, NPM_ONLY_TOP_LEVEL_COMMANDS, WRAPPER_ORCHESTRATED_PROJECT_COMMANDS, detectWindowsDoctorWorkspaceShadow, handleBootstrapCommand, handleCacheCommand, handleCreateOrFallback, handleInitCommand, handleMirrorCommand, handleSetupCommand, installWorkspaceDependencies, shouldForwardToCore };