(projectRoot: string, runId: string)
| 100 | } |
| 101 | |
| 102 | function readRunMeta(projectRoot: string, runId: string): { dashboardPort?: number; dashboardPid?: number } | null { |
| 103 | try { |
| 104 | const p = runMetaPath(projectRoot, runId) |
| 105 | if (!fs.existsSync(p)) return null |
| 106 | const raw = fs.readFileSync(p, 'utf8') |
| 107 | const j = JSON.parse(raw) |
| 108 | const port = typeof j?.dashboardPort === 'number' ? j.dashboardPort : undefined |
| 109 | const pid = typeof j?.dashboardPid === 'number' ? j.dashboardPid : undefined |
| 110 | return { dashboardPort: port, dashboardPid: pid } |
| 111 | } catch { |
| 112 | return null |
| 113 | } |
| 114 | } |
| 115 | |
| 116 | function parseTaskNameFromYamlText(yamlText: string): string | null { |
| 117 | // Very small heuristic: the editor always writes `name: ...` at the top. |
no test coverage detected