hlidskjalf 0.4.1 → 0.4.2
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/CHANGELOG.md +9 -0
- package/README.md +8 -11
- package/dist/index.js +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,15 @@ All notable changes to this project are documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [0.4.2]
|
|
9
|
+
|
|
10
|
+
### Changed
|
|
11
|
+
|
|
12
|
+
- **Boolean flags take a value** — disable file watching with `--watch=false` and
|
|
13
|
+
metrics with `--metrics=false` (both also accept `=true`, and a bare `--watch` /
|
|
14
|
+
`--metrics` still reads as `true`). Replaces the `--no-watch` / `--no-metrics`
|
|
15
|
+
forms. The config forms (`watch: false`, `metrics: true`) are unchanged.
|
|
16
|
+
|
|
8
17
|
## [0.4.1]
|
|
9
18
|
|
|
10
19
|
### Added
|
package/README.md
CHANGED
|
@@ -30,12 +30,12 @@ pnpm dev
|
|
|
30
30
|
|
|
31
31
|
| Option | Description |
|
|
32
32
|
| --- | --- |
|
|
33
|
-
| `filter` | Include specific workspaces (`--filter=web`). Append `...` for transitive
|
|
34
|
-
| `order` | Sort by `alphabetical`
|
|
33
|
+
| `filter` | Include specific workspaces (`--filter=web`). Append `...` for transitive dependencies (`--filter=web...`). |
|
|
34
|
+
| `order` | Sort by `alphabetical` or `run` (`--order=run`). Defaults to `alphabetical`. |
|
|
35
35
|
| `title` | Custom title for the header (`--title="My App"`). Defaults to `Hlidskjalf`. |
|
|
36
|
+
| `theme` | Colour theme (`--theme=niflheim` or `--theme=ice`). Defaults to `bifrost`. |
|
|
36
37
|
| `metrics` | Show CPU and memory usage per workspace. Defaults to `false`. |
|
|
37
|
-
| `watch` | Re-discover workspaces when `package.json` files change. Defaults to `true`; disable with `--
|
|
38
|
-
| `theme` | Colour theme (`--theme=niflheim` or `--theme=ice`). One of `bifrost` (default), `niflheim`, `muspelheim`, and `yggdrasil`. |
|
|
38
|
+
| `watch` | Re-discover workspaces when `package.json` files change. Defaults to `true`; disable with `--watch=false`. |
|
|
39
39
|
|
|
40
40
|
## Themes
|
|
41
41
|
|
|
@@ -43,7 +43,7 @@ Named for the realms of Norse cosmology, to match the all-seeing high seat the t
|
|
|
43
43
|
|
|
44
44
|
| Theme | Alias | Mood |
|
|
45
45
|
| --- | --- | --- |
|
|
46
|
-
| `bifrost` | — | Default -
|
|
46
|
+
| `bifrost` | — | Default - electric purples, sky blues, and starlight whites. |
|
|
47
47
|
| `niflheim` | `ice` | Ice — glacial blues, frost-white highlights. |
|
|
48
48
|
| `muspelheim` | `fire` | Fire — molten oranges, ember golds. |
|
|
49
49
|
| `yggdrasil` | `earth` | Earth — mosses, leaf-greens, bark greys. |
|
|
@@ -51,11 +51,9 @@ Named for the realms of Norse cosmology, to match the all-seeing high seat the t
|
|
|
51
51
|
Each realm also answers to its elemental alias, so `--theme=ice` is the same as
|
|
52
52
|
`--theme=niflheim`.
|
|
53
53
|
|
|
54
|
-
Status colours (running / warning / error) stay legible in every theme, so a glyph never misreads.
|
|
55
|
-
|
|
56
54
|
## Configuration
|
|
57
55
|
|
|
58
|
-
Persist any of the options above
|
|
56
|
+
Persist any of the options above.
|
|
59
57
|
Create a `hlidskjalf.config.ts` at the repo root:
|
|
60
58
|
|
|
61
59
|
```ts
|
|
@@ -69,8 +67,7 @@ export default defineConfig({
|
|
|
69
67
|
})
|
|
70
68
|
```
|
|
71
69
|
|
|
72
|
-
`defineConfig` is optional — a plain `export default { ... }` works too
|
|
73
|
-
`hlidskjalf.config.js` / `hlidskjalf.config.mjs` are also recognized. The `.ts`
|
|
70
|
+
`defineConfig` is optional — a plain `export default { ... }` works too. `hlidskjalf.config.js` / `hlidskjalf.config.mjs` are also recognized. The `.ts`
|
|
74
71
|
form needs no build step: it's loaded directly via Node's type stripping
|
|
75
72
|
(Node ≥ 22.18).
|
|
76
73
|
|
|
@@ -93,7 +90,7 @@ defaults**, so a flag always wins over a stored value.
|
|
|
93
90
|
While running, hlidskjalf watches your `packages`, `apps`, and `services`
|
|
94
91
|
directories. When a workspace's `package.json` is added, removed, or changed it
|
|
95
92
|
re-runs discovery: new workspaces start automatically and removed ones are
|
|
96
|
-
stopped and dropped from the dashboard. Pass `--
|
|
93
|
+
stopped and dropped from the dashboard. Pass `--watch=false` (or set
|
|
97
94
|
`watch: false`) to turn this off.
|
|
98
95
|
|
|
99
96
|
## Controls
|
package/dist/index.js
CHANGED
|
@@ -221,7 +221,7 @@ Read about how to prevent this error on https://github.com/vadimdemedes/ink/#isr
|
|
|
221
221
|
`)key.name="enter";else if(s===" ")key.name="tab";else if(s==="\b"||s==="\x1B\b")key.name="backspace",key.meta=s.charAt(0)==="\x1B";else if(s==="\x7F"||s==="\x1B\x7F")key.name="delete",key.meta=s.charAt(0)==="\x1B";else if(s==="\x1B"||s==="\x1B\x1B")key.name="escape",key.meta=s.length===2;else if(s===" "||s==="\x1B ")key.name="space",key.meta=s.length===2;else if(s.length===1&&s<="")key.name=String.fromCharCode(s.charCodeAt(0)+97-1),key.ctrl=true;else if(s.length===1&&s>="0"&&s<="9")key.name="number";else if(s.length===1&&s>="a"&&s<="z")key.name=s;else if(s.length===1&&s>="A"&&s<="Z")key.name=s.toLowerCase(),key.shift=true;else if(parts=metaKeyCodeRe.exec(s))key.meta=true,key.shift=/^[A-Z]$/.test(parts[1]);else if(parts=fnKeyRe.exec(s)){let segs=[...s];segs[0]==="\x1B"&&segs[1]==="\x1B"&&(key.option=true);let code=[parts[1],parts[2],parts[4],parts[6]].filter(Boolean).join(""),modifier=(parts[3]||parts[5]||1)-1;key.ctrl=!!(modifier&4),key.meta=!!(modifier&10),key.shift=!!(modifier&1),key.code=code,key.name=keyName[code],key.shift=isShiftKey(code)||key.shift,key.ctrl=isCtrlKey(code)||key.ctrl;}return key},parse_keypress_default=parseKeypress;var import_react15=__toESM(require_react(),1);var useStdin=()=>(0, import_react15.useContext)(StdinContext_default),use_stdin_default=useStdin;var useInput=(inputHandler,options2={})=>{let{stdin,setRawMode,internal_exitOnCtrlC,internal_eventEmitter}=use_stdin_default();(0, import_react16.useEffect)(()=>{if(options2.isActive!==false)return setRawMode(true),()=>{setRawMode(false);}},[options2.isActive,setRawMode]),(0, import_react16.useEffect)(()=>{if(options2.isActive===false)return;let handleData=data=>{let keypress=parse_keypress_default(data),key={upArrow:keypress.name==="up",downArrow:keypress.name==="down",leftArrow:keypress.name==="left",rightArrow:keypress.name==="right",pageDown:keypress.name==="pagedown",pageUp:keypress.name==="pageup",return:keypress.name==="return",escape:keypress.name==="escape",ctrl:keypress.ctrl,shift:keypress.shift,tab:keypress.name==="tab",backspace:keypress.name==="backspace",delete:keypress.name==="delete",meta:keypress.meta||keypress.name==="escape"||keypress.option},input=keypress.ctrl?keypress.name:keypress.sequence;nonAlphanumericKeys.includes(keypress.name)&&(input=""),input.startsWith("\x1B")&&(input=input.slice(1)),input.length===1&&typeof input[0]=="string"&&/[A-Z]/.test(input[0])&&(key.shift=true),(!(input==="c"&&key.ctrl)||!internal_exitOnCtrlC)&&reconciler_default.batchedUpdates(()=>{inputHandler(input,key);});};return internal_eventEmitter?.on("input",handleData),()=>{internal_eventEmitter?.removeListener("input",handleData);}},[options2.isActive,stdin,internal_exitOnCtrlC,inputHandler]);},use_input_default=useInput;var import_react17=__toESM(require_react(),1);var useApp=()=>(0, import_react17.useContext)(AppContext_default),use_app_default=useApp;var import_react18=__toESM(require_react(),1);var useStdout=()=>(0, import_react18.useContext)(StdoutContext_default),use_stdout_default=useStdout;__toESM(require_react(),1);__toESM(require_react(),1);__toESM(require_react(),1);var import_react26=__toESM(require_react(),1);var HEARTBEAT_INTERVAL_MS=1e4,IDLE_THRESHOLD_MS=3e5,PROBE_TIMEOUT_MS=3e3;async function probe(url){try{return await(await fetch(url,{signal:AbortSignal.timeout(PROBE_TIMEOUT_MS)})).body?.cancel(),!0}catch{return false}}function createHeartbeat(deps){return {stop:every(HEARTBEAT_INTERVAL_MS,()=>{let now=Date.now();for(let[name,entry]of deps.entries()){let{status,url}=entry.process;if(status==="idle"&&url){probe(url).then(alive=>{alive&&entry.process.status==="idle"&&(entry.lastOutputAt=Date.now(),deps.setStatus(name,entry.lastGoodStatus??"ready"));});continue}status!=="watching"&&status!=="ready"||entry.lastOutputAt&&now-entry.lastOutputAt>IDLE_THRESHOLD_MS&&(url?probe(url).then(alive=>{alive?entry.lastOutputAt=Date.now():(entry.process.status==="watching"||entry.process.status==="ready")&&deps.setStatus(name,"idle");}):deps.setStatus(name,"idle"));}})}}function appendLog(logs,line){logs.push(line),logs.length>1e3&&logs.splice(0,logs.length-500);}function visibleLogRange(total,height,scroll){let maxScroll=Math.max(0,total-height),clamped=Math.min(Math.max(0,scroll),maxScroll),end=total-clamped;return {start:Math.max(0,end-height),end,maxScroll}}var ENV_ALLOWLIST=new Set(["HOME","USER","LOGNAME","SHELL","PATH","LANG","LC_ALL","LC_CTYPE","TERM","TERM_PROGRAM","COLORTERM","NODE_ENV","NODE_OPTIONS","NODE_PATH","NPM_CONFIG_REGISTRY","PNPM_HOME","COREPACK_HOME","XDG_CONFIG_HOME","XDG_DATA_HOME","XDG_CACHE_HOME","TMPDIR","TMP","TEMP","EDITOR","DISPLAY","HOSTNAME"]);function safeEnv(source=process.env){let filtered={};for(let key of Object.keys(source))ENV_ALLOWLIST.has(key)&&(filtered[key]=source[key]);return filtered.FORCE_COLOR="1",filtered}function collectDescendants(rootPid,children){let result=[],stack=[rootPid];for(;stack.length>0;){let pid=stack.pop();result.push(pid);let kids=children.get(pid);if(kids)for(let kid of kids)stack.push(kid);}return result}function parseCpuTime(raw){let rest=raw.trim();if(!rest)return 0;let days=0,dash=rest.indexOf("-");if(dash!==-1){if(days=Number.parseInt(rest.slice(0,dash),10),Number.isNaN(days))return 0;rest=rest.slice(dash+1);}let parts=rest.split(":"),seconds=0,multiplier=1;for(let i=parts.length-1;i>=0;i--){let value=Number.parseFloat(parts[i]??"");if(Number.isNaN(value))return 0;seconds+=value*multiplier,multiplier*=60;}return seconds+=days*86400,Math.round(seconds*100)}function parsePsOutput(output){let children=new Map,stats=new Map;for(let line of output.trim().split(`
|
|
222
222
|
`).slice(1)){let parts=line.trim().split(/\s+/);if(parts.length<4)continue;let pid=Number.parseInt(parts[0]??"",10),ppid=Number.parseInt(parts[1]??"",10),cputimeTicks=parseCpuTime(parts[2]??""),rssKb=Number.parseInt(parts[3]??"",10);if(Number.isNaN(pid)||Number.isNaN(ppid))continue;stats.set(pid,{cputimeTicks,rss:(Number.isNaN(rssKb)?0:rssKb)*1024});let kids=children.get(ppid);kids||(kids=[],children.set(ppid,kids)),kids.push(pid);}return {children,stats}}function sumTickDeltas(prev,curr){if(!prev)return 0;let delta=0;for(let[pid,ticks]of curr){let before=prev.get(pid);before!==void 0&&ticks>before&&(delta+=ticks-before);}return delta}function parseProcStat(content,pageSize=4096){let closeParen=content.lastIndexOf(")");if(closeParen===-1)return null;let fields=content.slice(closeParen+2).split(" "),ppid=Number.parseInt(fields[1]??"",10),utime=Number.parseInt(fields[11]??"",10),stime=Number.parseInt(fields[12]??"",10),rss=Number.parseInt(fields[21]??"",10)*pageSize;return Number.isNaN(ppid)?null:{ppid,utime,stime,rss}}function cpuPercentFromTicks(tickDelta,elapsedMs,numCpus,ticksPerSec=100){if(elapsedMs<=0||numCpus<=0)return 0;let elapsedSec=elapsedMs/1e3;return Math.max(0,tickDelta/ticksPerSec/elapsedSec/numCpus*100)}var METRICS_INTERVAL_MS=3e3,MIN_METRICS_INTERVAL_MS=1e3,PS_TIMEOUT_MS=5e3;function createMeter(deps){let prevCpuSnapshot=new Map,numCpus=os.availableParallelism(),timer=null,lastSampleAt=0,stopped=false,apply=(name,pids,now,statOf)=>{let prev=prevCpuSnapshot.get(name),perPid=new Map,totalMem=0;for(let pid of pids){let stat=statOf(pid);stat&&(perPid.set(pid,stat.ticks),totalMem+=stat.rss);}let cpu=prev?cpuPercentFromTicks(sumTickDeltas(prev.perPid,perPid),now-prev.time,numCpus):0;return prevCpuSnapshot.set(name,{time:now,perPid}),deps.setMetrics(name,{cpu,mem:totalMem})},readProcTree=()=>{let children=new Map,stats=new Map,entries;try{entries=fs__default.readdirSync("/proc");}catch{return {children,stats}}for(let entry of entries){if(!/^\d+$/.test(entry))continue;let pid=Number.parseInt(entry,10);try{let parsed=parseProcStat(fs__default.readFileSync(`/proc/${pid}/stat`,"utf8"));if(!parsed)continue;let{ppid,utime,stime,rss}=parsed;stats.set(pid,{utime,stime,rss});let kids=children.get(ppid);kids||(kids=[],children.set(ppid,kids)),kids.push(pid);}catch{}}return {children,stats}},collectProc=roots=>{let tree=readProcTree(),now=Date.now(),changed=false;for(let[rootPid,name]of roots){let pids=collectDescendants(rootPid,tree.children),updated=apply(name,pids,now,pid=>{let stat=tree.stats.get(pid);return stat?{ticks:stat.utime+stat.stime,rss:stat.rss}:void 0});changed=changed||updated;}changed&&deps.onChange();},collectPs=roots=>{let output;try{output=execFileSync("ps",["-eo","pid,ppid,time,rss"],{encoding:"utf8",timeout:PS_TIMEOUT_MS});}catch{return}let{children,stats}=parsePsOutput(output),now=Date.now(),changed=false;for(let[rootPid,name]of roots){let pids=collectDescendants(rootPid,children),updated=apply(name,pids,now,pid=>{let stat=stats.get(pid);return stat?{ticks:stat.cputimeTicks,rss:stat.rss}:void 0});changed=changed||updated;}changed&&deps.onChange();},collect=()=>{if(stopped)return;lastSampleAt=Date.now();let roots=deps.roots();roots.size!==0&&(process.platform==="linux"?collectProc(roots):collectPs(roots));},schedule=delay=>{timer&&clearTimeout(timer),timer=setTimeout(()=>{timer=null,collect(),stopped||schedule(METRICS_INTERVAL_MS);},delay),timer.unref();};return collect(),schedule(METRICS_INTERVAL_MS),{request(){if(stopped)return;let sinceLast=Date.now()-lastSampleAt;schedule(Math.max(0,MIN_METRICS_INTERVAL_MS-sinceLast));},reset(name){prevCpuSnapshot.delete(name);},stop(){stopped=true,timer&&(clearTimeout(timer),timer=null);}}}var MAX_PARSE_LENGTH=4096,LOCAL_HOSTS=new Set(["localhost","127.0.0.1","[::1]","0.0.0.0"]);function localOrigin(raw){let cleaned=raw.replace(/[.,;:!?)}\]]+$/,""),parsed;try{parsed=new URL(cleaned);}catch{return}if(!(parsed.protocol!=="http:"&&parsed.protocol!=="https:")&&parsed.port&&LOCAL_HOSTS.has(parsed.hostname))return parsed.origin}var DTS=/\bDTS\b/,baseMatchers=[{pattern:/running on (https?:\/\/\S+)/,status:"ready"},{pattern:/listening on (https?:\/\/\S+)/,status:"ready"},{pattern:/listening at (https?:\/\/\S+)/,status:"ready"},{pattern:/started.*?(https?:\/\/localhost:\d+)/,status:"ready"},{pattern:/\bVITE\b.*?\bready in\b/i,status:"ready"},{pattern:/\bLocal:\s+(https?:\/\/\S+)/,status:"ready"},{pattern:/⚡️?\s*Build success/,status:"watching"},{pattern:/Build start/,status:"building"},{pattern:/Watching for changes/,status:"watching"},{pattern:/\[ERROR\]/,status:"error"},{pattern:/error[\s:]/i,status:"error"},{pattern:/process exit/,status:"error"},{pattern:/\blistening\b/i,status:"ready"}],matchers=baseMatchers.map(m=>({...m,needsHttp:m.pattern.source.includes("http")}));function parseLine(line){let truncated=line.length>MAX_PARSE_LENGTH?line.slice(0,MAX_PARSE_LENGTH):line;if(DTS.test(truncated))return {};let hasHttp=truncated.includes("http");for(let{pattern,status,needsHttp}of matchers){if(needsHttp&&!hasHttp)continue;let match=truncated.match(pattern);if(match){let url=match[1]?localOrigin(match[1]):void 0;return {status,url}}}return {}}function stripAnsi2(text){return text.includes("\x1B")?stripVTControlCharacters(text):text}var NON_SGR_ESCAPES=/\x1b(?:\][^\x07\x1b]*(?:\x07|\x1b\\)|\[[?>=]*[\d;]*[A-Za-ln-z@~`]|\([A-Za-z]|[^[(\]\x1b])/g,BARE_CONTROLS=/[\x00-\x08\x0b-\x1a\x1c-\x1f\x7f]/g;function sanitizeForDisplay(text){let hasEscape=text.includes("\x1B"),hasControl=text.search(BARE_CONTROLS)!==-1;if(!hasEscape&&!hasControl)return text;let out=text;return hasEscape&&(out=out.replace(NON_SGR_ESCAPES,"")),hasControl&&(out=out.replace(BARE_CONTROLS,"")),out}var WORKSPACE_DIRS=["packages","apps","services"],DEBOUNCE_MS=300;function watchWorkspaces(root2,onChange){let parentWatchers=[],childWatchers=new Map,timer=null,closed=false,schedule=()=>{closed||(timer&&clearTimeout(timer),timer=setTimeout(()=>{timer=null,onChange();},DEBOUNCE_MS),timer.unref());},watchChild=dir=>{if(!(closed||childWatchers.has(dir)))try{let w=watch(dir,(_event,filename)=>{(!filename||filename.toString()==="package.json")&&schedule();});w.on("error",()=>{}),childWatchers.set(dir,w);}catch{}},syncChildren=()=>{if(!closed){for(let dir of WORKSPACE_DIRS){let base=join(root2,dir);try{for(let entry of readdirSync(base,{withFileTypes:!0}))entry.isDirectory()&&watchChild(join(base,entry.name));}catch{}}for(let[dir,w]of childWatchers)existsSync(dir)||(w.close(),childWatchers.delete(dir));}};for(let dir of WORKSPACE_DIRS){let base=join(root2,dir);if(existsSync(base))try{let w=watch(base,()=>{syncChildren(),schedule();});w.on("error",()=>{}),parentWatchers.push(w);}catch{}}return syncChildren(),{close(){closed=true,timer&&clearTimeout(timer);for(let w of parentWatchers)w.close();for(let w of childWatchers.values())w.close();childWatchers.clear();}}}var ERROR_RECOVERY_MS=5e3,MAX_RESTART_RETRIES=3,RESTART_DELAY_MS=1e3,STARTUP_TIMEOUT_MS=12e4,MAX_BUFFER_SIZE=65536,MAX_LINE_LENGTH=8192,KILL_GRACE_MS=5e3;function isRunning(child){return !!child&&child.exitCode===null&&child.signalCode===null}function killTree(child,signal){let{pid}=child;if(pid!==void 0)try{process.kill(-pid,signal);return}catch{}try{child.kill(signal);}catch{}}function escalateKill(child){let timer=setTimeout(()=>{child.exitCode===null&&killTree(child,"SIGKILL");},KILL_GRACE_MS);return timer.unref(),timer}var ProcessStore=class _ProcessStore{entries=new Map;order=[];listeners=new Set;snapshot=[];dirty=true;pendingRebuilds=new Set;heartbeat=null;meter=null;watcher=null;allWorkspaces=[];stopping=false;root;order_;filter;metricsEnabled;watchEnabled;constructor(opts){this.root=opts.root,this.order_=opts.order,this.filter=opts.filter,this.metricsEnabled=opts.metrics,this.watchEnabled=opts.watch;}subscribe(listener){return this.listeners.add(listener),()=>this.listeners.delete(listener)}getSnapshot(){return this.dirty&&(this.snapshot=this.order.flatMap(name=>{let proc=this.entries.get(name)?.process;return proc?[proc]:[]}),this.dirty=false),this.snapshot}changed(){this.dirty=true;for(let listener of this.listeners)listener();}discoverFiltered(){let found=discover(this.root);return this.filter?filterWorkspaces(found,this.filter):found}sortForDisplay(workspaces){return this.order_==="run"?sortByDeps(workspaces):sortByName(workspaces)}async start(){let workspaces=this.discoverFiltered();if(workspaces.length===0)return false;let startOrder=sortByDeps(workspaces),sorted=this.sortForDisplay(workspaces);this.order=sorted.map(w=>w.name);for(let workspace of workspaces)this.entries.set(workspace.name,_ProcessStore.newEntry(workspace));return this.changed(),this.watchEnabled&&(this.watcher=watchWorkspaces(this.root,()=>this.rediscover())),this.spawnAll(startOrder),true}async spawnAll(workspaces){this.allWorkspaces=workspaces;let packages=workspaces.filter(w=>w.kind==="package"),apps=workspaces.filter(w=>w.kind!=="package");for(let workspace of packages)this.spawn(workspace);packages.length>0&&await this.waitForPackages(packages.map(p=>p.name));let failedPackages=new Set;for(let pkg of packages){let s=this.entries.get(pkg.name)?.process.status;(s==="error"||s==="stopped"||s==="timeout")&&failedPackages.add(pkg.name);}for(let workspace of apps){let failedDeps=workspace.deps.filter(d=>failedPackages.has(d));if(failedDeps.length>0){let entry=this.entries.get(workspace.name);entry&&(this.note(entry,`warning: dependency ${failedDeps.join(", ")} failed \u2014 starting anyway`),this.changed());}this.spawn(workspace);}this.heartbeat=createHeartbeat({entries:()=>this.entries,setStatus:(name,status)=>this.setStatus(name,status)}),this.metricsEnabled&&(this.meter=createMeter({roots:()=>this.runningRoots(),setMetrics:(name,metrics2)=>{let entry=this.entries.get(name);return entry?(entry.process.metrics=metrics2,true):false},onChange:()=>this.changed()}));}runningRoots(){let roots=new Map;for(let[name,entry]of this.entries)isRunning(entry.child)&&entry.child.pid!==void 0&&roots.set(entry.child.pid,name);return roots}async shutdown(){this.stopping=true,this.watcher?.close(),this.heartbeat?.stop(),this.meter?.stop();for(let entry of this.entries.values())this.clearTimers(entry);for(let child of this.pendingRebuilds)child.kill("SIGTERM");let waiting=[];for(let entry of this.entries.values()){let{child}=entry;isRunning(child)&&waiting.push(new Promise(resolve=>{let escalate=escalateKill(child);child.on("close",()=>{clearTimeout(escalate),resolve();}),killTree(child,"SIGTERM");}));}await Promise.all(waiting);}rediscover(){if(this.stopping)return;let fresh=this.discoverFiltered(),freshNames=new Set(fresh.map(w=>w.name)),currentNames=new Set(this.order),added=fresh.filter(w=>!currentNames.has(w.name)),removed=[...currentNames].filter(name=>!freshNames.has(name));if(!(added.length===0&&removed.length===0)){for(let name of removed)this.removeWorkspace(name);for(let workspace of added)this.addWorkspace(workspace);this.order=this.sortForDisplay(fresh).map(w=>w.name),this.changed();}}static newEntry(workspace){return {process:{workspace,status:"pending",logs:[]},child:null,errorTimer:null,restartTimer:null,startupTimer:null,lastGoodStatus:null,restartRetries:0,lastOutputAt:0,intentionalExit:false,teardownStarted:false,onClose:null}}note(entry,message){appendLog(entry.process.logs,`[hlidskjalf] ${message}`);}clearTimers(entry){entry.restartTimer&&(clearTimeout(entry.restartTimer),entry.restartTimer=null),entry.errorTimer&&(clearTimeout(entry.errorTimer),entry.errorTimer=null),entry.startupTimer&&(clearTimeout(entry.startupTimer),entry.startupTimer=null);}beginTeardown(entry,onClosed){entry.intentionalExit=true;let{child}=entry;if(!isRunning(child)){entry.child=null,onClosed();return}if(entry.onClose=onClosed,!entry.teardownStarted){entry.teardownStarted=true;let escalate=escalateKill(child);child.on("close",()=>{clearTimeout(escalate),entry.child=null,entry.teardownStarted=false;let action=entry.onClose;entry.onClose=null,action?.();});}killTree(child,"SIGTERM");}waitForPackages(names){let remaining=new Set(names);return new Promise(resolve=>{let check=()=>{for(let name of [...remaining]){let s=this.entries.get(name)?.process.status;(s==="watching"||s==="error"||s==="stopped"||s==="timeout")&&remaining.delete(name);}remaining.size===0&&(this.listeners.delete(check),resolve());};this.listeners.add(check),check();})}spawn(workspace){let child=spawn("pnpm",["--filter",workspace.name,"run","dev"],{cwd:this.root,stdio:"pipe",env:safeEnv(),detached:true}),entry=this.entries.get(workspace.name);entry&&(entry.child=child,entry.intentionalExit=false),this.setStatus(workspace.name,"building");let startupTimer=setTimeout(()=>{let e=this.entries.get(workspace.name);e&&(e.startupTimer=null,e.process.status!=="watching"&&e.process.status!=="ready"&&(this.note(e,`startup timeout after ${STARTUP_TIMEOUT_MS/1e3}s`),this.setStatus(workspace.name,"timeout")));},STARTUP_TIMEOUT_MS);startupTimer.unref(),entry&&(entry.startupTimer=startupTimer);let buffer="",onData=data=>{if(buffer+=data.toString(),!buffer.includes(`
|
|
223
223
|
`)&&buffer.length>MAX_BUFFER_SIZE){this.handleLine(workspace.name,buffer),buffer="";return}let lines=buffer.split(`
|
|
224
|
-
`);buffer=lines.pop()??"";for(let raw of lines){let line=raw.trimEnd();line&&this.handleLine(workspace.name,line);}};child.stdout?.on("data",onData),child.stderr?.on("data",onData),child.on("close",(code,signal)=>{buffer.trim()&&this.handleLine(workspace.name,buffer.trimEnd()),buffer="",!this.stopping&&(this.entries.get(workspace.name)?.intentionalExit||this.handleUnexpectedExit(workspace,code,signal));}),child.on("error",()=>{let e=this.entries.get(workspace.name);e?.startupTimer&&(clearTimeout(e.startupTimer),e.startupTimer=null),this.setStatus(workspace.name,"error");});}handleLine(name,raw){if(this.stopping)return;let entry=this.entries.get(name);if(!entry)return;let line=raw.length>MAX_LINE_LENGTH?raw.slice(0,MAX_LINE_LENGTH):raw,{process:proc}=entry;appendLog(proc.logs,sanitizeForDisplay(line)),entry.lastOutputAt=Date.now();let prevStatus=proc.status;proc.status==="idle"&&(proc.status=entry.lastGoodStatus??"ready");let{status,url}=parseLine(stripAnsi2(line));status&&(status==="error"?this.scheduleErrorRecovery(name):(entry.lastGoodStatus=status,this.clearErrorTimer(name),entry.restartRetries=0,(status==="watching"||status==="ready")&&entry.startupTimer&&(clearTimeout(entry.startupTimer),entry.startupTimer=null)),proc.status=status),url&&(proc.url=url),proc.status!==prevStatus&&this.meter?.request(),this.changed();}handleUnexpectedExit(workspace,code,signal){if(code===0){this.setStatus(workspace.name,"stopped");return}let entry=this.entries.get(workspace.name);if(!entry)return;entry.restartRetries+=1;let{restartRetries}=entry;if(restartRetries>MAX_RESTART_RETRIES){this.note(entry,`process exited ${MAX_RESTART_RETRIES} times \u2014 giving up.`),this.setStatus(workspace.name,"error");return}let delay=RESTART_DELAY_MS*2**(restartRetries-1);if(this.note(entry,`process exited unexpectedly (attempt ${restartRetries}/${MAX_RESTART_RETRIES}) \u2014 restarting in ${delay/1e3}s...`),this.setStatus(workspace.name,"error"),signal==="SIGABRT"){this.rebuildFsevents().then(()=>{let e=this.entries.get(workspace.name);!this.stopping&&e&&!e.intentionalExit&&this.spawn(workspace);}).catch(()=>this.setStatus(workspace.name,"error"));return}let timer=setTimeout(()=>{entry.restartTimer=null,this.stopping||this.spawn(workspace);},delay);timer.unref(),entry.restartTimer=timer;}rebuildFsevents(){return new Promise(resolve=>{let child=spawn("pnpm",["rebuild","fsevents"],{cwd:this.root,stdio:"pipe",env:safeEnv()});this.pendingRebuilds.add(child);let done=()=>{this.pendingRebuilds.delete(child),resolve();};child.on("close",done),child.on("error",done);})}scheduleErrorRecovery(name){this.clearErrorTimer(name);let entry=this.entries.get(name);if(!entry)return;let timer=setTimeout(()=>{entry.errorTimer=null,entry.process.status==="error"&&this.setStatus(name,entry.lastGoodStatus??"ready");},ERROR_RECOVERY_MS);timer.unref(),entry.errorTimer=timer;}clearErrorTimer(name){let entry=this.entries.get(name);entry?.errorTimer&&(clearTimeout(entry.errorTimer),entry.errorTimer=null);}setStatus(name,status){let entry=this.entries.get(name);if(!entry)return;let changed=entry.process.status!==status;entry.process.status=status,status==="stopped"&&(entry.process.metrics=void 0),status==="error"&&entry.process.workspace.kind==="package"&&this.notifyDependents(name),changed&&this.meter?.request(),this.changed();}stopProcess(name){if(this.stopping)return;let entry=this.entries.get(name);if(!entry)return;this.clearTimers(entry);let wasLive=isRunning(entry.child);this.beginTeardown(entry,()=>{entry.restartRetries=0,this.setStatus(name,"stopped");}),wasLive&&(this.note(entry,"stopping process..."),this.changed());}restartProcess(name){if(this.stopping)return;let entry=this.entries.get(name);if(!entry)return;let workspace=entry.process.workspace,doRestart=()=>{this.stopping||(entry.restartRetries=0,entry.process.url=void 0,this.note(entry,"restarting process..."),this.spawn(workspace));};this.clearTimers(entry);let wasLive=isRunning(entry.child);this.beginTeardown(entry,doRestart),wasLive&&(this.note(entry,"stopping process for restart..."),this.changed());}clearLogs(name){let entry=this.entries.get(name);entry&&(entry.process.logs.length=0,this.changed());}addWorkspace(workspace){this.stopping||this.entries.has(workspace.name)||(this.allWorkspaces.push(workspace),this.entries.set(workspace.name,_ProcessStore.newEntry(workspace)),this.order.includes(workspace.name)||this.order.push(workspace.name),this.spawn(workspace));}removeWorkspace(name){let entry=this.entries.get(name);entry&&(this.clearTimers(entry),this.beginTeardown(entry,()=>{}),this.entries.delete(name),this.order=this.order.filter(n=>n!==name),this.allWorkspaces=this.allWorkspaces.filter(w=>w.name!==name),this.meter?.reset(name),this.changed());}notifyDependents(failedName){for(let workspace of this.allWorkspaces){if(!workspace.deps.includes(failedName))continue;let entry=this.entries.get(workspace.name);entry&&this.note(entry,`warning: dependency ${failedName} entered error state`);}}};function createStore(opts){return new ProcessStore(opts)}var import_react22=__toESM(require_react(),1);var import_cli_spinners=__toESM(require_cli_spinners(),1);function Spinner({type="dots"}){let[frame,setFrame]=(0, import_react22.useState)(0),spinner=import_cli_spinners.default[type];return (0, import_react22.useEffect)(()=>{let timer=setInterval(()=>{setFrame(previousFrame=>previousFrame===spinner.frames.length-1?0:previousFrame+1);},spinner.interval);return ()=>{clearInterval(timer);}},[spinner]),import_react22.default.createElement(Text,null,spinner.frames[frame])}var build_default=Spinner;var import_react23=__toESM(require_react(),1),FALLBACK={columns:80,rows:24},RESIZE_SETTLE_MS=120;function readSize(stdout){return {columns:stdout?.columns??FALLBACK.columns,rows:stdout?.rows??FALLBACK.rows}}function useTerminalSize(){let{stdout}=use_stdout_default(),[size,setSize]=(0, import_react23.useState)(()=>readSize(stdout));return (0, import_react23.useEffect)(()=>{if(!stdout)return;let timer,apply=()=>{setSize(prev=>{let next=readSize(stdout);return next.columns===prev.columns&&next.rows===prev.rows?prev:next});},onResize=()=>{timer&&clearTimeout(timer),timer=setTimeout(apply,RESIZE_SETTLE_MS);};return stdout.on("resize",onResize),apply(),()=>{timer&&clearTimeout(timer),stdout.off("resize",onResize);}},[stdout]),size}var import_jsx_runtime=__toESM(require_jsx_runtime(),1);function Cell({width,children}){return (0, import_jsx_runtime.jsx)(Box_default,{width,children})}function Panel({children,...box}){return (0, import_jsx_runtime.jsx)(Box_default,{flexDirection:"column",borderStyle:"round",borderColor:colors.separator,paddingX:1,...box,children})}function StatusGlyph({status,icon}){return status==="building"?(0, import_jsx_runtime.jsx)(build_default,{type:"dots"}):(0, import_jsx_runtime.jsx)(Text,{children:icon})}var import_jsx_runtime2=__toESM(require_jsx_runtime(),1);function Header({title:title2,ready=false,columns,hints}){let showHints=hints&&columns>=10+hints.length+4;return (0, import_jsx_runtime2.jsx)(Box_default,{flexDirection:"column",paddingX:1,paddingTop:1,paddingBottom:1,borderStyle:"single",borderColor:colors.separator,borderTop:false,borderLeft:false,borderRight:false,children:(0, import_jsx_runtime2.jsxs)(Box_default,{gap:2,children:[(0, import_jsx_runtime2.jsxs)(Box_default,{flexShrink:0,gap:1,children:[(0, import_jsx_runtime2.jsx)(Text,{color:ready?colors.success:colors.dim,children:ready?"\u25CF":"\u25CB"}),(0, import_jsx_runtime2.jsx)(Text,{color:colors.accentBright,bold:true,children:title2})]}),showHints&&(0, import_jsx_runtime2.jsx)(Box_default,{flexGrow:1,justifyContent:"flex-end",children:(0, import_jsx_runtime2.jsx)(Text,{color:colors.dim,wrap:"truncate-end",children:hints})})]})})}function Loading({title:title2}){let{columns}=useTerminalSize();return (0, import_jsx_runtime2.jsxs)(Box_default,{flexDirection:"column",children:[(0, import_jsx_runtime2.jsx)(Header,{title:title2,columns}),(0, import_jsx_runtime2.jsxs)(Box_default,{marginTop:1,paddingX:2,children:[(0, import_jsx_runtime2.jsxs)(Text,{color:colors.accent,children:[(0, import_jsx_runtime2.jsx)(build_default,{type:"dots"})," "]}),(0, import_jsx_runtime2.jsx)(Text,{color:colors.muted,children:"Discovering workspaces..."})]})]})}var BINDINGS=[["\u2191/\u2193","Navigate proccesses"],["s","Stop / start process"],["r","Restart process"],["c","Clear logs"],["PgUp/PgDn","Scroll logs"],["?","Toggle help"],["q","Quit"]];function Help({title:title2}){let{columns}=useTerminalSize(),keyWidth=Math.max(...BINDINGS.map(([keys])=>keys.length));return (0, import_jsx_runtime2.jsxs)(Box_default,{flexDirection:"column",children:[(0, import_jsx_runtime2.jsx)(Header,{title:title2,columns,hints:HINTS}),(0, import_jsx_runtime2.jsxs)(Panel,{alignSelf:"flex-start",marginX:1,marginTop:1,paddingX:2,paddingY:1,children:[(0, import_jsx_runtime2.jsx)(Box_default,{marginBottom:1,children:(0, import_jsx_runtime2.jsx)(Text,{color:colors.accentBright,bold:true,children:"Keybindings"})}),BINDINGS.map(([keys,action])=>(0, import_jsx_runtime2.jsxs)(Box_default,{gap:2,children:[(0, import_jsx_runtime2.jsx)(Cell,{width:keyWidth,children:(0, import_jsx_runtime2.jsx)(Text,{color:colors.highlight,children:keys})}),(0, import_jsx_runtime2.jsx)(Text,{color:colors.muted,children:action})]},keys)),(0, import_jsx_runtime2.jsx)(Box_default,{marginTop:1,children:(0, import_jsx_runtime2.jsx)(Text,{color:colors.dim,children:"Press ? or Esc to close"})})]})]})}var import_react25=__toESM(require_react(),1);var import_react24=__toESM(require_react(),1);var ESC2="\x1B",HOME_SEQUENCES=new Set([`${ESC2}[H`,`${ESC2}[1~`,`${ESC2}[7~`,`${ESC2}OH`]),END_SEQUENCES=new Set([`${ESC2}[F`,`${ESC2}[4~`,`${ESC2}[8~`,`${ESC2}OF`]);function useLogScroll(total,height,selectionKey,enabled){let[scroll,setScroll]=(0, import_react24.useState)(0),[prevKey,setPrevKey]=(0, import_react24.useState)(selectionKey);selectionKey!==prevKey&&(setPrevKey(selectionKey),setScroll(0));let[prevTotal,setPrevTotal]=(0, import_react24.useState)(total);if(total!==prevTotal){let delta=total-prevTotal;setPrevTotal(total),scroll>0&&delta>0&&setScroll(s=>s+delta);}let maxScroll=Math.max(0,total-height),maxScrollRef=(0, import_react24.useRef)(maxScroll);maxScrollRef.current=maxScroll,use_input_default((input,key)=>{key.pageUp?setScroll(s=>Math.min(Math.min(s,maxScroll)+height,maxScroll)):key.pageDown?setScroll(s=>Math.max(0,Math.min(s,maxScroll)-height)):HOME_SEQUENCES.has(input)?setScroll(maxScrollRef.current):END_SEQUENCES.has(input)&&setScroll(0);},{isActive:enabled});let{start,end}=visibleLogRange(total,height,scroll);return {start,end,atBottom:Math.min(scroll,maxScroll)===0}}function nameColumnWidth(processes,min=14){let width=min;for(let proc of processes){let candidate=proc.workspace.name.length+2;candidate>width&&(width=candidate);}return width}function urlContentWidth(processes){let width=0;for(let proc of processes){let length=proc.url?.length??0;length>width&&(width=length);}return width}var COLUMN_WIDTHS={indicator:2,kind:6,status:14,cpu:8,mem:9},ROW_PADDING_X=1,ROW_CHROME_WIDTH=ROW_PADDING_X*2+COLUMN_WIDTHS.indicator+COLUMN_WIDTHS.kind+COLUMN_WIDTHS.status,METRICS_WIDTH=COLUMN_WIDTHS.cpu+COLUMN_WIDTHS.mem;function columnWidths(columns,naturalNameWidth,urlContent,metrics2){let available=columns-ROW_CHROME_WIDTH-(metrics2?METRICS_WIDTH:0);if(available<=1)return {name:Math.max(1,available),url:0};let url=Math.max(0,Math.min(urlContent,available-14));return {name:Math.max(1,Math.min(naturalNameWidth,available-url)),url}}var MIN_LOG_PANEL_HEIGHT=3,NON_LOG_CHROME=12;function logPanelHeight(rows,processCount){return Math.max(0,rows-processCount-NON_LOG_CHROME)}var import_jsx_runtime3=__toESM(require_jsx_runtime(),1),kindLabel={package:"pkg",app:"app",service:"svc"};function MetricsCells({metrics:metrics2}){return metrics2?(0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment,{children:[(0, import_jsx_runtime3.jsx)(Cell,{width:COLUMN_WIDTHS.cpu,children:(0, import_jsx_runtime3.jsx)(Text,{color:cpuColor(metrics2),children:formatCpu(metrics2.cpu)})}),(0, import_jsx_runtime3.jsx)(Cell,{width:COLUMN_WIDTHS.mem,children:(0, import_jsx_runtime3.jsx)(Text,{color:memColor(metrics2.mem),children:formatMem(metrics2.mem)})})]}):(0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment,{children:[(0, import_jsx_runtime3.jsx)(Cell,{width:COLUMN_WIDTHS.cpu,children:(0, import_jsx_runtime3.jsx)(Text,{color:colors.dim,children:"\u2014"})}),(0, import_jsx_runtime3.jsx)(Cell,{width:COLUMN_WIDTHS.mem,children:(0, import_jsx_runtime3.jsx)(Text,{color:colors.dim,children:"\u2014"})})]})}function ProcessRow({process:proc,selected,nameWidth,showMetrics,urlWidth}){let{color,label,icon}=statusDisplay[proc.status];return (0, import_jsx_runtime3.jsxs)(Box_default,{paddingX:1,children:[(0, import_jsx_runtime3.jsx)(Text,{color:selected?colors.highlight:colors.dim,children:selected?"\u25B8":" "}),(0, import_jsx_runtime3.jsx)(Text,{children:" "}),(0, import_jsx_runtime3.jsx)(Cell,{width:nameWidth,children:(0, import_jsx_runtime3.jsx)(Text,{color:selected?colors.highlight:void 0,bold:selected,wrap:"truncate",children:proc.workspace.name})}),(0, import_jsx_runtime3.jsx)(Cell,{width:COLUMN_WIDTHS.kind,children:(0, import_jsx_runtime3.jsx)(Text,{color:colors.muted,children:kindLabel[proc.workspace.kind]})}),(0, import_jsx_runtime3.jsx)(Cell,{width:COLUMN_WIDTHS.status,children:(0, import_jsx_runtime3.jsxs)(Text,{color,children:[(0, import_jsx_runtime3.jsx)(StatusGlyph,{status:proc.status,icon})," ",label]})}),showMetrics&&(0, import_jsx_runtime3.jsx)(MetricsCells,{metrics:proc.metrics}),proc.url&&urlWidth>0&&(0, import_jsx_runtime3.jsx)(Cell,{width:urlWidth,children:(0, import_jsx_runtime3.jsx)(Text,{color:colors.url,wrap:"truncate",children:hyperlink(proc.url,truncateEnd(proc.url,urlWidth))})})]})}function LogPanel({process:proc,height,start,end,atBottom}){let logLines=proc.logs.slice(start,end),fillCount=height-logLines.length,hidden=proc.logs.length-end;return (0, import_jsx_runtime3.jsxs)(Panel,{height:height+3,overflow:"hidden",marginX:1,marginTop:1,children:[(0, import_jsx_runtime3.jsxs)(Box_default,{marginBottom:1,children:[(0, import_jsx_runtime3.jsx)(Text,{color:colors.accentBright,bold:true,children:"Logs"}),!atBottom&&(0, import_jsx_runtime3.jsxs)(Text,{color:colors.warning,children:[" ","\u23F8 scrolled \xB7 ",hidden," below \xB7 End to follow"]})]}),logLines.map((line,i)=>(0, import_jsx_runtime3.jsx)(Text,{wrap:"truncate",children:line},i)),Array.from({length:fillCount},(_,i)=>(0, import_jsx_runtime3.jsx)(Text,{children:" "},`fill-${i}`))]})}function Dashboard({processes,selectedIndex,title:title2,metrics:metrics2=false}){let{columns:cols,rows}=useTerminalSize(),allReady=(0, import_react25.useMemo)(()=>processes.length>0&&processes.every(p=>p.status==="ready"||p.status==="watching"),[processes]),naturalNameWidth=(0, import_react25.useMemo)(()=>nameColumnWidth(processes),[processes]),urlContent=(0, import_react25.useMemo)(()=>urlContentWidth(processes),[processes]),{name:nameWidth,url:urlWidth}=columnWidths(cols,naturalNameWidth,urlContent,metrics2),logHeight=logPanelHeight(rows,processes.length),safeIndex=Math.min(selectedIndex,Math.max(0,processes.length-1)),selected=processes[safeIndex],scroll=useLogScroll(selected?.logs.length??0,logHeight,selected?.workspace.name??"",!!selected);return (0, import_jsx_runtime3.jsxs)(Box_default,{flexDirection:"column",children:[(0, import_jsx_runtime3.jsx)(Header,{title:title2,ready:allReady,columns:cols,hints:HINTS}),(0, import_jsx_runtime3.jsxs)(Box_default,{paddingX:1,marginLeft:2,marginTop:1,children:[(0, import_jsx_runtime3.jsx)(Cell,{width:nameWidth,children:(0, import_jsx_runtime3.jsx)(Text,{color:colors.muted,bold:true,children:"Name"})}),(0, import_jsx_runtime3.jsx)(Cell,{width:COLUMN_WIDTHS.kind,children:(0, import_jsx_runtime3.jsx)(Text,{color:colors.muted,bold:true,children:"Kind"})}),(0, import_jsx_runtime3.jsx)(Cell,{width:COLUMN_WIDTHS.status,children:(0, import_jsx_runtime3.jsx)(Text,{color:colors.muted,bold:true,children:"Status"})}),metrics2&&(0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment,{children:[(0, import_jsx_runtime3.jsx)(Cell,{width:COLUMN_WIDTHS.cpu,children:(0, import_jsx_runtime3.jsx)(Text,{color:colors.muted,bold:true,children:"CPU"})}),(0, import_jsx_runtime3.jsx)(Cell,{width:COLUMN_WIDTHS.mem,children:(0, import_jsx_runtime3.jsx)(Text,{color:colors.muted,bold:true,children:"MEM"})})]}),(0, import_jsx_runtime3.jsx)(Text,{color:colors.muted,bold:true,children:"URL"})]}),processes.map((proc,i)=>(0, import_jsx_runtime3.jsx)(ProcessRow,{process:proc,selected:i===safeIndex,nameWidth,showMetrics:metrics2,urlWidth},proc.workspace.name)),selected&&logHeight>=MIN_LOG_PANEL_HEIGHT&&(0, import_jsx_runtime3.jsx)(LogPanel,{process:selected,height:logHeight,start:scroll.start,end:scroll.end,atBottom:scroll.atBottom})]})}var import_jsx_runtime4=__toESM(require_jsx_runtime(),1);function App2({options:options2}){let{exit}=use_app_default(),[store]=(0, import_react26.useState)(()=>createStore(options2)),subscribe=(0, import_react26.useCallback)(onStoreChange=>{let pending,unsubscribe=store.subscribe(()=>{pending||(pending=setImmediate(()=>{pending=void 0,onStoreChange();}));});return ()=>{pending&&clearImmediate(pending),unsubscribe();}},[store]),getSnapshot=(0, import_react26.useCallback)(()=>store.getSnapshot(),[store]),live=(0, import_react26.useSyncExternalStore)(subscribe,getSnapshot),processes=(0, import_react26.useDeferredValue)(live),[phase,setPhase]=(0, import_react26.useState)("loading"),[showHelp,setShowHelp]=(0, import_react26.useState)(false),[cursorState,setCursor]=(0, import_react26.useState)(0),stopping=(0, import_react26.useRef)(false),stop=(0, import_react26.useCallback)(()=>{stopping.current||(stopping.current=true,store.shutdown().catch(()=>{}).finally(()=>exit()));},[store,exit]);(0, import_react26.useEffect)(()=>{let active=true;return store.start().then(started=>{active&&(started?setPhase("running"):(console.error("No matching workspaces found."),exit()));}).catch(err=>{console.error("Fatal:",err instanceof Error?err.message:"unexpected error"),exit();}),process.on("SIGTERM",stop),()=>{active=false,process.off("SIGTERM",stop),store.shutdown();}},[store,exit,stop]);let cursor=Math.min(cursorState,Math.max(0,processes.length-1));return use_input_default((input,key)=>{if(input==="q"||key.ctrl&&input==="c"){stop();return}if(input==="?"){setShowHelp(open=>!open);return}if(showHelp){key.escape&&setShowHelp(false);return}if(processes.length===0)return;if(key.upArrow||input==="k"){setCursor(i=>Math.max(0,i-1));return}if(key.downArrow||input==="j"){setCursor(i=>Math.min(processes.length-1,i+1));return}let selected=processes[cursor];if(!selected)return;let{name}=selected.workspace;input==="s"?selected.status==="stopped"?store.restartProcess(name):store.stopProcess(name):input==="r"?store.restartProcess(name):input==="c"&&store.clearLogs(name);}),phase==="loading"?(0, import_jsx_runtime4.jsx)(Loading,{title:options2.title}):showHelp?(0, import_jsx_runtime4.jsx)(Help,{title:options2.title}):(0, import_jsx_runtime4.jsx)(Dashboard,{processes,selectedIndex:cursor,title:options2.title,metrics:options2.metrics})}var import_jsx_runtime5=__toESM(require_jsx_runtime(),1),argv=process.argv.slice(2),explicit={},args=argv.filter(arg=>arg==="--no-metrics"?(explicit.metrics=false,false):arg==="--no-watch"?(explicit.watch=false,false):true),{values}=parseArgs({args,options:{filter:{type:"string",multiple:true},order:{type:"string"},title:{type:"string"},metrics:{type:"boolean"},watch:{type:"boolean"},theme:{type:"string"}}}),root=process.cwd(),config=await loadConfig(root),cliFilter=values.filter?normalizeFilters(values.filter):void 0,filter=cliFilter?.length?cliFilter:config.filter,rawOrder=values.order??config.order,order=rawOrder==="run"?"run":"alphabetical",title=values.title??config.title??"Hlidskjalf",metrics=explicit.metrics??values.metrics??config.metrics??false,watch2=explicit.watch??values.watch??config.watch??true,flagTheme=parseTheme(values.theme);if(values.theme!==void 0&&flagTheme===void 0){let accepted=[...Object.keys(themes),...Object.keys(THEME_ALIASES)].join(", ");console.error(`Ignoring --theme "${values.theme}": expected one of ${accepted}.`);}var theme=flagTheme??config.theme??DEFAULT_THEME;setTheme(theme);var options={root,order,filter:filter?.length?filter:void 0,title,metrics,watch:watch2,theme},restoreScreen=enterAltScreen();try{let{waitUntilExit}=render_default((0,import_jsx_runtime5.jsx)(App2,{options}),{exitOnCtrlC:!1});await waitUntilExit();}finally{restoreScreen();}process.exit(0);
|
|
224
|
+
`);buffer=lines.pop()??"";for(let raw of lines){let line=raw.trimEnd();line&&this.handleLine(workspace.name,line);}};child.stdout?.on("data",onData),child.stderr?.on("data",onData),child.on("close",(code,signal)=>{buffer.trim()&&this.handleLine(workspace.name,buffer.trimEnd()),buffer="",!this.stopping&&(this.entries.get(workspace.name)?.intentionalExit||this.handleUnexpectedExit(workspace,code,signal));}),child.on("error",()=>{let e=this.entries.get(workspace.name);e?.startupTimer&&(clearTimeout(e.startupTimer),e.startupTimer=null),this.setStatus(workspace.name,"error");});}handleLine(name,raw){if(this.stopping)return;let entry=this.entries.get(name);if(!entry)return;let line=raw.length>MAX_LINE_LENGTH?raw.slice(0,MAX_LINE_LENGTH):raw,{process:proc}=entry;appendLog(proc.logs,sanitizeForDisplay(line)),entry.lastOutputAt=Date.now();let prevStatus=proc.status;proc.status==="idle"&&(proc.status=entry.lastGoodStatus??"ready");let{status,url}=parseLine(stripAnsi2(line));status&&(status==="error"?this.scheduleErrorRecovery(name):(entry.lastGoodStatus=status,this.clearErrorTimer(name),entry.restartRetries=0,(status==="watching"||status==="ready")&&entry.startupTimer&&(clearTimeout(entry.startupTimer),entry.startupTimer=null)),proc.status=status),url&&(proc.url=url),proc.status!==prevStatus&&this.meter?.request(),this.changed();}handleUnexpectedExit(workspace,code,signal){if(code===0){this.setStatus(workspace.name,"stopped");return}let entry=this.entries.get(workspace.name);if(!entry)return;entry.restartRetries+=1;let{restartRetries}=entry;if(restartRetries>MAX_RESTART_RETRIES){this.note(entry,`process exited ${MAX_RESTART_RETRIES} times \u2014 giving up.`),this.setStatus(workspace.name,"error");return}let delay=RESTART_DELAY_MS*2**(restartRetries-1);if(this.note(entry,`process exited unexpectedly (attempt ${restartRetries}/${MAX_RESTART_RETRIES}) \u2014 restarting in ${delay/1e3}s...`),this.setStatus(workspace.name,"error"),signal==="SIGABRT"){this.rebuildFsevents().then(()=>{let e=this.entries.get(workspace.name);!this.stopping&&e&&!e.intentionalExit&&this.spawn(workspace);}).catch(()=>this.setStatus(workspace.name,"error"));return}let timer=setTimeout(()=>{entry.restartTimer=null,this.stopping||this.spawn(workspace);},delay);timer.unref(),entry.restartTimer=timer;}rebuildFsevents(){return new Promise(resolve=>{let child=spawn("pnpm",["rebuild","fsevents"],{cwd:this.root,stdio:"pipe",env:safeEnv()});this.pendingRebuilds.add(child);let done=()=>{this.pendingRebuilds.delete(child),resolve();};child.on("close",done),child.on("error",done);})}scheduleErrorRecovery(name){this.clearErrorTimer(name);let entry=this.entries.get(name);if(!entry)return;let timer=setTimeout(()=>{entry.errorTimer=null,entry.process.status==="error"&&this.setStatus(name,entry.lastGoodStatus??"ready");},ERROR_RECOVERY_MS);timer.unref(),entry.errorTimer=timer;}clearErrorTimer(name){let entry=this.entries.get(name);entry?.errorTimer&&(clearTimeout(entry.errorTimer),entry.errorTimer=null);}setStatus(name,status){let entry=this.entries.get(name);if(!entry)return;let changed=entry.process.status!==status;entry.process.status=status,status==="stopped"&&(entry.process.metrics=void 0),status==="error"&&entry.process.workspace.kind==="package"&&this.notifyDependents(name),changed&&this.meter?.request(),this.changed();}stopProcess(name){if(this.stopping)return;let entry=this.entries.get(name);if(!entry)return;this.clearTimers(entry);let wasLive=isRunning(entry.child);this.beginTeardown(entry,()=>{entry.restartRetries=0,this.setStatus(name,"stopped");}),wasLive&&(this.note(entry,"stopping process..."),this.changed());}restartProcess(name){if(this.stopping)return;let entry=this.entries.get(name);if(!entry)return;let workspace=entry.process.workspace,doRestart=()=>{this.stopping||(entry.restartRetries=0,entry.process.url=void 0,this.note(entry,"restarting process..."),this.spawn(workspace));};this.clearTimers(entry);let wasLive=isRunning(entry.child);this.beginTeardown(entry,doRestart),wasLive&&(this.note(entry,"stopping process for restart..."),this.changed());}clearLogs(name){let entry=this.entries.get(name);entry&&(entry.process.logs.length=0,this.changed());}addWorkspace(workspace){this.stopping||this.entries.has(workspace.name)||(this.allWorkspaces.push(workspace),this.entries.set(workspace.name,_ProcessStore.newEntry(workspace)),this.order.includes(workspace.name)||this.order.push(workspace.name),this.spawn(workspace));}removeWorkspace(name){let entry=this.entries.get(name);entry&&(this.clearTimers(entry),this.beginTeardown(entry,()=>{}),this.entries.delete(name),this.order=this.order.filter(n=>n!==name),this.allWorkspaces=this.allWorkspaces.filter(w=>w.name!==name),this.meter?.reset(name),this.changed());}notifyDependents(failedName){for(let workspace of this.allWorkspaces){if(!workspace.deps.includes(failedName))continue;let entry=this.entries.get(workspace.name);entry&&this.note(entry,`warning: dependency ${failedName} entered error state`);}}};function createStore(opts){return new ProcessStore(opts)}var import_react22=__toESM(require_react(),1);var import_cli_spinners=__toESM(require_cli_spinners(),1);function Spinner({type="dots"}){let[frame,setFrame]=(0, import_react22.useState)(0),spinner=import_cli_spinners.default[type];return (0, import_react22.useEffect)(()=>{let timer=setInterval(()=>{setFrame(previousFrame=>previousFrame===spinner.frames.length-1?0:previousFrame+1);},spinner.interval);return ()=>{clearInterval(timer);}},[spinner]),import_react22.default.createElement(Text,null,spinner.frames[frame])}var build_default=Spinner;var import_react23=__toESM(require_react(),1),FALLBACK={columns:80,rows:24},RESIZE_SETTLE_MS=120;function readSize(stdout){return {columns:stdout?.columns??FALLBACK.columns,rows:stdout?.rows??FALLBACK.rows}}function useTerminalSize(){let{stdout}=use_stdout_default(),[size,setSize]=(0, import_react23.useState)(()=>readSize(stdout));return (0, import_react23.useEffect)(()=>{if(!stdout)return;let timer,apply=()=>{setSize(prev=>{let next=readSize(stdout);return next.columns===prev.columns&&next.rows===prev.rows?prev:next});},onResize=()=>{timer&&clearTimeout(timer),timer=setTimeout(apply,RESIZE_SETTLE_MS);};return stdout.on("resize",onResize),apply(),()=>{timer&&clearTimeout(timer),stdout.off("resize",onResize);}},[stdout]),size}var import_jsx_runtime=__toESM(require_jsx_runtime(),1);function Cell({width,children}){return (0, import_jsx_runtime.jsx)(Box_default,{width,children})}function Panel({children,...box}){return (0, import_jsx_runtime.jsx)(Box_default,{flexDirection:"column",borderStyle:"round",borderColor:colors.separator,paddingX:1,...box,children})}function StatusGlyph({status,icon}){return status==="building"?(0, import_jsx_runtime.jsx)(build_default,{type:"dots"}):(0, import_jsx_runtime.jsx)(Text,{children:icon})}var import_jsx_runtime2=__toESM(require_jsx_runtime(),1);function Header({title:title2,ready=false,columns,hints}){let showHints=hints&&columns>=10+hints.length+4;return (0, import_jsx_runtime2.jsx)(Box_default,{flexDirection:"column",paddingX:1,paddingTop:1,paddingBottom:1,borderStyle:"single",borderColor:colors.separator,borderTop:false,borderLeft:false,borderRight:false,children:(0, import_jsx_runtime2.jsxs)(Box_default,{gap:2,children:[(0, import_jsx_runtime2.jsxs)(Box_default,{flexShrink:0,gap:1,children:[(0, import_jsx_runtime2.jsx)(Text,{color:ready?colors.success:colors.dim,children:ready?"\u25CF":"\u25CB"}),(0, import_jsx_runtime2.jsx)(Text,{color:colors.accentBright,bold:true,children:title2})]}),showHints&&(0, import_jsx_runtime2.jsx)(Box_default,{flexGrow:1,justifyContent:"flex-end",children:(0, import_jsx_runtime2.jsx)(Text,{color:colors.dim,wrap:"truncate-end",children:hints})})]})})}function Loading({title:title2}){let{columns}=useTerminalSize();return (0, import_jsx_runtime2.jsxs)(Box_default,{flexDirection:"column",children:[(0, import_jsx_runtime2.jsx)(Header,{title:title2,columns}),(0, import_jsx_runtime2.jsxs)(Box_default,{marginTop:1,paddingX:2,children:[(0, import_jsx_runtime2.jsxs)(Text,{color:colors.accent,children:[(0, import_jsx_runtime2.jsx)(build_default,{type:"dots"})," "]}),(0, import_jsx_runtime2.jsx)(Text,{color:colors.muted,children:"Discovering workspaces..."})]})]})}var BINDINGS=[["\u2191/\u2193","Navigate proccesses"],["s","Stop / start process"],["r","Restart process"],["c","Clear logs"],["PgUp/PgDn","Scroll logs"],["?","Toggle help"],["q","Quit"]];function Help({title:title2}){let{columns}=useTerminalSize(),keyWidth=Math.max(...BINDINGS.map(([keys])=>keys.length));return (0, import_jsx_runtime2.jsxs)(Box_default,{flexDirection:"column",children:[(0, import_jsx_runtime2.jsx)(Header,{title:title2,columns,hints:HINTS}),(0, import_jsx_runtime2.jsxs)(Panel,{alignSelf:"flex-start",marginX:1,marginTop:1,paddingX:2,paddingY:1,children:[(0, import_jsx_runtime2.jsx)(Box_default,{marginBottom:1,children:(0, import_jsx_runtime2.jsx)(Text,{color:colors.accentBright,bold:true,children:"Keybindings"})}),BINDINGS.map(([keys,action])=>(0, import_jsx_runtime2.jsxs)(Box_default,{gap:2,children:[(0, import_jsx_runtime2.jsx)(Cell,{width:keyWidth,children:(0, import_jsx_runtime2.jsx)(Text,{color:colors.highlight,children:keys})}),(0, import_jsx_runtime2.jsx)(Text,{color:colors.muted,children:action})]},keys)),(0, import_jsx_runtime2.jsx)(Box_default,{marginTop:1,children:(0, import_jsx_runtime2.jsx)(Text,{color:colors.dim,children:"Press ? or Esc to close"})})]})]})}var import_react25=__toESM(require_react(),1);var import_react24=__toESM(require_react(),1);var ESC2="\x1B",HOME_SEQUENCES=new Set([`${ESC2}[H`,`${ESC2}[1~`,`${ESC2}[7~`,`${ESC2}OH`]),END_SEQUENCES=new Set([`${ESC2}[F`,`${ESC2}[4~`,`${ESC2}[8~`,`${ESC2}OF`]);function useLogScroll(total,height,selectionKey,enabled){let[scroll,setScroll]=(0, import_react24.useState)(0),[prevKey,setPrevKey]=(0, import_react24.useState)(selectionKey);selectionKey!==prevKey&&(setPrevKey(selectionKey),setScroll(0));let[prevTotal,setPrevTotal]=(0, import_react24.useState)(total);if(total!==prevTotal){let delta=total-prevTotal;setPrevTotal(total),scroll>0&&delta>0&&setScroll(s=>s+delta);}let maxScroll=Math.max(0,total-height),maxScrollRef=(0, import_react24.useRef)(maxScroll);maxScrollRef.current=maxScroll,use_input_default((input,key)=>{key.pageUp?setScroll(s=>Math.min(Math.min(s,maxScroll)+height,maxScroll)):key.pageDown?setScroll(s=>Math.max(0,Math.min(s,maxScroll)-height)):HOME_SEQUENCES.has(input)?setScroll(maxScrollRef.current):END_SEQUENCES.has(input)&&setScroll(0);},{isActive:enabled});let{start,end}=visibleLogRange(total,height,scroll);return {start,end,atBottom:Math.min(scroll,maxScroll)===0}}function nameColumnWidth(processes,min=14){let width=min;for(let proc of processes){let candidate=proc.workspace.name.length+2;candidate>width&&(width=candidate);}return width}function urlContentWidth(processes){let width=0;for(let proc of processes){let length=proc.url?.length??0;length>width&&(width=length);}return width}var COLUMN_WIDTHS={indicator:2,kind:6,status:14,cpu:8,mem:9},ROW_PADDING_X=1,ROW_CHROME_WIDTH=ROW_PADDING_X*2+COLUMN_WIDTHS.indicator+COLUMN_WIDTHS.kind+COLUMN_WIDTHS.status,METRICS_WIDTH=COLUMN_WIDTHS.cpu+COLUMN_WIDTHS.mem;function columnWidths(columns,naturalNameWidth,urlContent,metrics2){let available=columns-ROW_CHROME_WIDTH-(metrics2?METRICS_WIDTH:0);if(available<=1)return {name:Math.max(1,available),url:0};let url=Math.max(0,Math.min(urlContent,available-14));return {name:Math.max(1,Math.min(naturalNameWidth,available-url)),url}}var MIN_LOG_PANEL_HEIGHT=3,NON_LOG_CHROME=12;function logPanelHeight(rows,processCount){return Math.max(0,rows-processCount-NON_LOG_CHROME)}var import_jsx_runtime3=__toESM(require_jsx_runtime(),1),kindLabel={package:"pkg",app:"app",service:"svc"};function MetricsCells({metrics:metrics2}){return metrics2?(0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment,{children:[(0, import_jsx_runtime3.jsx)(Cell,{width:COLUMN_WIDTHS.cpu,children:(0, import_jsx_runtime3.jsx)(Text,{color:cpuColor(metrics2),children:formatCpu(metrics2.cpu)})}),(0, import_jsx_runtime3.jsx)(Cell,{width:COLUMN_WIDTHS.mem,children:(0, import_jsx_runtime3.jsx)(Text,{color:memColor(metrics2.mem),children:formatMem(metrics2.mem)})})]}):(0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment,{children:[(0, import_jsx_runtime3.jsx)(Cell,{width:COLUMN_WIDTHS.cpu,children:(0, import_jsx_runtime3.jsx)(Text,{color:colors.dim,children:"\u2014"})}),(0, import_jsx_runtime3.jsx)(Cell,{width:COLUMN_WIDTHS.mem,children:(0, import_jsx_runtime3.jsx)(Text,{color:colors.dim,children:"\u2014"})})]})}function ProcessRow({process:proc,selected,nameWidth,showMetrics,urlWidth}){let{color,label,icon}=statusDisplay[proc.status];return (0, import_jsx_runtime3.jsxs)(Box_default,{paddingX:1,children:[(0, import_jsx_runtime3.jsx)(Text,{color:selected?colors.highlight:colors.dim,children:selected?"\u25B8":" "}),(0, import_jsx_runtime3.jsx)(Text,{children:" "}),(0, import_jsx_runtime3.jsx)(Cell,{width:nameWidth,children:(0, import_jsx_runtime3.jsx)(Text,{color:selected?colors.highlight:void 0,bold:selected,wrap:"truncate",children:proc.workspace.name})}),(0, import_jsx_runtime3.jsx)(Cell,{width:COLUMN_WIDTHS.kind,children:(0, import_jsx_runtime3.jsx)(Text,{color:colors.muted,children:kindLabel[proc.workspace.kind]})}),(0, import_jsx_runtime3.jsx)(Cell,{width:COLUMN_WIDTHS.status,children:(0, import_jsx_runtime3.jsxs)(Text,{color,children:[(0, import_jsx_runtime3.jsx)(StatusGlyph,{status:proc.status,icon})," ",label]})}),showMetrics&&(0, import_jsx_runtime3.jsx)(MetricsCells,{metrics:proc.metrics}),proc.url&&urlWidth>0&&(0, import_jsx_runtime3.jsx)(Cell,{width:urlWidth,children:(0, import_jsx_runtime3.jsx)(Text,{color:colors.url,wrap:"truncate",children:hyperlink(proc.url,truncateEnd(proc.url,urlWidth))})})]})}function LogPanel({process:proc,height,start,end,atBottom}){let logLines=proc.logs.slice(start,end),fillCount=height-logLines.length,hidden=proc.logs.length-end;return (0, import_jsx_runtime3.jsxs)(Panel,{height:height+3,overflow:"hidden",marginX:1,marginTop:1,children:[(0, import_jsx_runtime3.jsxs)(Box_default,{marginBottom:1,children:[(0, import_jsx_runtime3.jsx)(Text,{color:colors.accentBright,bold:true,children:"Logs"}),!atBottom&&(0, import_jsx_runtime3.jsxs)(Text,{color:colors.warning,children:[" ","\u23F8 scrolled \xB7 ",hidden," below \xB7 End to follow"]})]}),logLines.map((line,i)=>(0, import_jsx_runtime3.jsx)(Text,{wrap:"truncate",children:line},i)),Array.from({length:fillCount},(_,i)=>(0, import_jsx_runtime3.jsx)(Text,{children:" "},`fill-${i}`))]})}function Dashboard({processes,selectedIndex,title:title2,metrics:metrics2=false}){let{columns:cols,rows}=useTerminalSize(),allReady=(0, import_react25.useMemo)(()=>processes.length>0&&processes.every(p=>p.status==="ready"||p.status==="watching"),[processes]),naturalNameWidth=(0, import_react25.useMemo)(()=>nameColumnWidth(processes),[processes]),urlContent=(0, import_react25.useMemo)(()=>urlContentWidth(processes),[processes]),{name:nameWidth,url:urlWidth}=columnWidths(cols,naturalNameWidth,urlContent,metrics2),logHeight=logPanelHeight(rows,processes.length),safeIndex=Math.min(selectedIndex,Math.max(0,processes.length-1)),selected=processes[safeIndex],scroll=useLogScroll(selected?.logs.length??0,logHeight,selected?.workspace.name??"",!!selected);return (0, import_jsx_runtime3.jsxs)(Box_default,{flexDirection:"column",children:[(0, import_jsx_runtime3.jsx)(Header,{title:title2,ready:allReady,columns:cols,hints:HINTS}),(0, import_jsx_runtime3.jsxs)(Box_default,{paddingX:1,marginLeft:2,marginTop:1,children:[(0, import_jsx_runtime3.jsx)(Cell,{width:nameWidth,children:(0, import_jsx_runtime3.jsx)(Text,{color:colors.muted,bold:true,children:"Name"})}),(0, import_jsx_runtime3.jsx)(Cell,{width:COLUMN_WIDTHS.kind,children:(0, import_jsx_runtime3.jsx)(Text,{color:colors.muted,bold:true,children:"Kind"})}),(0, import_jsx_runtime3.jsx)(Cell,{width:COLUMN_WIDTHS.status,children:(0, import_jsx_runtime3.jsx)(Text,{color:colors.muted,bold:true,children:"Status"})}),metrics2&&(0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment,{children:[(0, import_jsx_runtime3.jsx)(Cell,{width:COLUMN_WIDTHS.cpu,children:(0, import_jsx_runtime3.jsx)(Text,{color:colors.muted,bold:true,children:"CPU"})}),(0, import_jsx_runtime3.jsx)(Cell,{width:COLUMN_WIDTHS.mem,children:(0, import_jsx_runtime3.jsx)(Text,{color:colors.muted,bold:true,children:"MEM"})})]}),(0, import_jsx_runtime3.jsx)(Text,{color:colors.muted,bold:true,children:"URL"})]}),processes.map((proc,i)=>(0, import_jsx_runtime3.jsx)(ProcessRow,{process:proc,selected:i===safeIndex,nameWidth,showMetrics:metrics2,urlWidth},proc.workspace.name)),selected&&logHeight>=MIN_LOG_PANEL_HEIGHT&&(0, import_jsx_runtime3.jsx)(LogPanel,{process:selected,height:logHeight,start:scroll.start,end:scroll.end,atBottom:scroll.atBottom})]})}var import_jsx_runtime4=__toESM(require_jsx_runtime(),1);function App2({options:options2}){let{exit}=use_app_default(),[store]=(0, import_react26.useState)(()=>createStore(options2)),subscribe=(0, import_react26.useCallback)(onStoreChange=>{let pending,unsubscribe=store.subscribe(()=>{pending||(pending=setImmediate(()=>{pending=void 0,onStoreChange();}));});return ()=>{pending&&clearImmediate(pending),unsubscribe();}},[store]),getSnapshot=(0, import_react26.useCallback)(()=>store.getSnapshot(),[store]),live=(0, import_react26.useSyncExternalStore)(subscribe,getSnapshot),processes=(0, import_react26.useDeferredValue)(live),[phase,setPhase]=(0, import_react26.useState)("loading"),[showHelp,setShowHelp]=(0, import_react26.useState)(false),[cursorState,setCursor]=(0, import_react26.useState)(0),stopping=(0, import_react26.useRef)(false),stop=(0, import_react26.useCallback)(()=>{stopping.current||(stopping.current=true,store.shutdown().catch(()=>{}).finally(()=>exit()));},[store,exit]);(0, import_react26.useEffect)(()=>{let active=true;return store.start().then(started=>{active&&(started?setPhase("running"):(console.error("No matching workspaces found."),exit()));}).catch(err=>{console.error("Fatal:",err instanceof Error?err.message:"unexpected error"),exit();}),process.on("SIGTERM",stop),()=>{active=false,process.off("SIGTERM",stop),store.shutdown();}},[store,exit,stop]);let cursor=Math.min(cursorState,Math.max(0,processes.length-1));return use_input_default((input,key)=>{if(input==="q"||key.ctrl&&input==="c"){stop();return}if(input==="?"){setShowHelp(open=>!open);return}if(showHelp){key.escape&&setShowHelp(false);return}if(processes.length===0)return;if(key.upArrow||input==="k"){setCursor(i=>Math.max(0,i-1));return}if(key.downArrow||input==="j"){setCursor(i=>Math.min(processes.length-1,i+1));return}let selected=processes[cursor];if(!selected)return;let{name}=selected.workspace;input==="s"?selected.status==="stopped"?store.restartProcess(name):store.stopProcess(name):input==="r"?store.restartProcess(name):input==="c"&&store.clearLogs(name);}),phase==="loading"?(0, import_jsx_runtime4.jsx)(Loading,{title:options2.title}):showHelp?(0, import_jsx_runtime4.jsx)(Help,{title:options2.title}):(0, import_jsx_runtime4.jsx)(Dashboard,{processes,selectedIndex:cursor,title:options2.title,metrics:options2.metrics})}var import_jsx_runtime5=__toESM(require_jsx_runtime(),1),argv=process.argv.slice(2),explicit={},args=argv.filter(arg=>arg==="--metrics"||arg==="--metrics=true"?(explicit.metrics=true,false):arg==="--metrics=false"?(explicit.metrics=false,false):arg==="--watch"||arg==="--watch=true"?(explicit.watch=true,false):arg==="--watch=false"?(explicit.watch=false,false):true),{values}=parseArgs({args,options:{filter:{type:"string",multiple:true},order:{type:"string"},title:{type:"string"},theme:{type:"string"}}}),root=process.cwd(),config=await loadConfig(root),cliFilter=values.filter?normalizeFilters(values.filter):void 0,filter=cliFilter?.length?cliFilter:config.filter,rawOrder=values.order??config.order,order=rawOrder==="run"?"run":"alphabetical",title=values.title??config.title??"Hlidskjalf",metrics=explicit.metrics??config.metrics??false,watch2=explicit.watch??config.watch??true,flagTheme=parseTheme(values.theme);if(values.theme!==void 0&&flagTheme===void 0){let accepted=[...Object.keys(themes),...Object.keys(THEME_ALIASES)].join(", ");console.error(`Ignoring --theme "${values.theme}": expected one of ${accepted}.`);}var theme=flagTheme??config.theme??DEFAULT_THEME;setTheme(theme);var options={root,order,filter:filter?.length?filter:void 0,title,metrics,watch:watch2,theme},restoreScreen=enterAltScreen();try{let{waitUntilExit}=render_default((0,import_jsx_runtime5.jsx)(App2,{options}),{exitOnCtrlC:!1});await waitUntilExit();}finally{restoreScreen();}process.exit(0);
|
|
225
225
|
/*! Bundled license information:
|
|
226
226
|
|
|
227
227
|
react/cjs/react.production.min.js:
|