hlidskjalf 0.4.0 → 0.4.1
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 +10 -0
- package/README.md +18 -0
- package/dist/chunk-WSO44QZR.js +10 -0
- package/dist/config.d.ts +77 -0
- package/dist/config.js +1 -1
- package/dist/index.js +3 -3
- package/package.json +1 -1
- package/dist/chunk-26F2AUTG.js +0 -10
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,16 @@ 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.1]
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- **Colour themes** — pick a palette with `--theme` or a `theme` key in the config.
|
|
13
|
+
Four built-ins named for the realms of Norse cosmology: `bifrost` (default),
|
|
14
|
+
`niflheim` (ice), `muspelheim` (fire), and `yggdrasil` (earth). Each realm also
|
|
15
|
+
answers to an elemental alias — `ice`, `fire`, and `earth`.
|
|
16
|
+
Status colours stay legible across every theme.
|
|
17
|
+
|
|
8
18
|
## [0.4.0]
|
|
9
19
|
|
|
10
20
|
### Changed
|
package/README.md
CHANGED
|
@@ -35,6 +35,23 @@ pnpm dev
|
|
|
35
35
|
| `title` | Custom title for the header (`--title="My App"`). Defaults to `Hlidskjalf`. |
|
|
36
36
|
| `metrics` | Show CPU and memory usage per workspace. Defaults to `false`. |
|
|
37
37
|
| `watch` | Re-discover workspaces when `package.json` files change. Defaults to `true`; disable with `--no-watch`. |
|
|
38
|
+
| `theme` | Colour theme (`--theme=niflheim` or `--theme=ice`). One of `bifrost` (default), `niflheim`, `muspelheim`, and `yggdrasil`. |
|
|
39
|
+
|
|
40
|
+
## Themes
|
|
41
|
+
|
|
42
|
+
Named for the realms of Norse cosmology, to match the all-seeing high seat the tool is named after:
|
|
43
|
+
|
|
44
|
+
| Theme | Alias | Mood |
|
|
45
|
+
| --- | --- | --- |
|
|
46
|
+
| `bifrost` | — | Default - Rainbow bridge — indigo + teal |
|
|
47
|
+
| `niflheim` | `ice` | Ice — glacial blues, frost-white highlights. |
|
|
48
|
+
| `muspelheim` | `fire` | Fire — molten oranges, ember golds. |
|
|
49
|
+
| `yggdrasil` | `earth` | Earth — mosses, leaf-greens, bark greys. |
|
|
50
|
+
|
|
51
|
+
Each realm also answers to its elemental alias, so `--theme=ice` is the same as
|
|
52
|
+
`--theme=niflheim`.
|
|
53
|
+
|
|
54
|
+
Status colours (running / warning / error) stay legible in every theme, so a glyph never misreads.
|
|
38
55
|
|
|
39
56
|
## Configuration
|
|
40
57
|
|
|
@@ -48,6 +65,7 @@ export default defineConfig({
|
|
|
48
65
|
order: 'run',
|
|
49
66
|
metrics: true,
|
|
50
67
|
filter: ['web...'],
|
|
68
|
+
theme: 'niflheim',
|
|
51
69
|
})
|
|
52
70
|
```
|
|
53
71
|
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { createRequire } from 'node:module';
|
|
3
|
+
import { existsSync, readdirSync, realpathSync, readFileSync } from 'fs';
|
|
4
|
+
import { resolve, join, sep } from 'path';
|
|
5
|
+
import { pathToFileURL } from 'url';
|
|
6
|
+
|
|
7
|
+
createRequire(import.meta.url);
|
|
8
|
+
var SHARED={success:"#15FA5A",warning:"#FACC15",error:"#F87171",pending:"#8D93A0",highlight:"#faf9f6",muted:"#8D93A0",dim:"#6B7280",separator:"#353940"},themes={bifrost:{accent:"#7C8EF2",accentBright:"#BEC7F9",url:"#E8EBFD",...SHARED},niflheim:{accent:"#22D3EE",accentBright:"#92E9F7",url:"#E7FAFD",...SHARED},muspelheim:{accent:"#F97316",accentBright:"#FCBB8D",url:"#FEF0E6",...SHARED},yggdrasil:{accent:"#22C55E",accentBright:"#73E79E",url:"#E9FBF0",...SHARED}},THEME_ALIASES={ice:"niflheim",fire:"muspelheim",earth:"yggdrasil"},DEFAULT_THEME="bifrost";function parseTheme(value){if(typeof value=="string")return value in themes?value:value in THEME_ALIASES?THEME_ALIASES[value]:void 0}var colors=themes[DEFAULT_THEME];function buildStatusDisplay(c){return {pending:{color:c.pending,label:"pending",icon:"\u25CB"},building:{color:c.warning,label:"building",icon:"\u25D1"},watching:{color:c.success,label:"watching",icon:"\u25CF"},ready:{color:c.success,label:"watching",icon:"\u25CF"},error:{color:c.error,label:"error",icon:"\u2716"},stopped:{color:c.pending,label:"stopped",icon:"\u25CB"},idle:{color:c.warning,label:"idle",icon:"\u25D1"},timeout:{color:c.error,label:"timeout",icon:"\u2716"}}}var statusDisplay=buildStatusDisplay(colors);function setTheme(name){colors=themes[name],statusDisplay=buildStatusDisplay(colors);}var HINTS="\u2191/\u2193 navigate | ? help | q quit";function formatCpu(cpu){return `${cpu.toFixed(1)}%`.padStart(6)}function formatMem(bytes){let s;return bytes<1024*1024?s=`${(bytes/1024).toFixed(0)} K`:bytes<1024*1024*1024?s=`${(bytes/(1024*1024)).toFixed(1)} M`:s=`${(bytes/(1024*1024*1024)).toFixed(1)} G`,s.padStart(7)}function memColor(bytes){return bytes>512*1024*1024?colors.error:bytes>256*1024*1024?colors.warning:colors.muted}function cpuColor(metrics){return metrics.cpu>80?colors.error:colors.muted}var ESC="\x1B",OSC8=`${ESC}]8;;`,BEL="\x07";function hyperlink(url,label=url){return `${OSC8}${url}${BEL}${label}${OSC8}${BEL}`}function truncateEnd(text,width){return width<=0?"":text.length<=width?text:width===1?"...":`${text.slice(0,width-1)}...`}var ENTER_ALT_SCREEN="\x1B[?1049h",EXIT_ALT_SCREEN="\x1B[?1049l";function enterAltScreen(stream=process.stdout){if(!stream.isTTY)return ()=>{};stream.write(ENTER_ALT_SCREEN);let restored=false,restore=()=>{restored||(restored=true,stream.write(EXIT_ALT_SCREEN));};return process.once("exit",restore),restore}function every(ms,fn){let t=setInterval(fn,ms);return t.unref(),()=>clearInterval(t)}function isPlainObject(value){return typeof value=="object"&&value!==null&&!Array.isArray(value)}var VALID_PKG_NAME=/^(@[a-z0-9\-~][a-z0-9\-._~]*\/)?[a-z0-9\-~][a-z0-9\-._~]*$/;function isValidPackageName(name){return VALID_PKG_NAME.test(name)&&name.length<=214}function normalizeFilters(raw){return raw.map(v=>v.replace(/^\{(.+)\}$/,"$1")).filter(v=>{let name=v.endsWith("...")?v.slice(0,-3):v;return isValidPackageName(name)?true:(console.error(`Ignoring invalid filter: ${name}`),false)})}function stringRecord(value){if(!isPlainObject(value))return;let result={};for(let[key,v]of Object.entries(value))typeof v=="string"&&(result[key]=v);return result}function readJson(path){try{let raw=JSON.parse(readFileSync(path,"utf-8"));return isPlainObject(raw)?{name:typeof raw.name=="string"?raw.name:void 0,scripts:stringRecord(raw.scripts),dependencies:stringRecord(raw.dependencies)}:null}catch{return null}}function workspaceDeps(pkg){return Object.entries(pkg.dependencies??{}).filter(([name,v])=>v.startsWith("workspace:")&&isValidPackageName(name)).map(([name])=>name)}var kindOrder={package:0,app:1,service:1};function discover(root){let results=[],dirs=[["packages","package"],["apps","app"],["services","service"]],resolvedRoot=resolve(root);for(let[dir,kind]of dirs){let base=join(resolvedRoot,dir);if(existsSync(base))for(let entry of readdirSync(base,{withFileTypes:true})){if(!entry.isDirectory())continue;let entryPath=join(base,entry.name);try{if(!realpathSync(entryPath).startsWith(resolvedRoot+sep))continue}catch{continue}let pkg=readJson(join(entryPath,"package.json"));pkg?.name&&isValidPackageName(pkg.name)&&pkg.name!=="hlidskjalf"&&pkg.scripts?.dev&&results.push({name:pkg.name,kind,deps:workspaceDeps(pkg)});}}return results}function sortByDeps(workspaces){let names=new Set(workspaces.map(w=>w.name)),depCount=new Map;for(let workspace of workspaces){let count=0;for(let dep of workspace.deps)names.has(dep)&&count++;depCount.set(workspace,count);}return [...workspaces].sort((a,b)=>a.kind!==b.kind?kindOrder[a.kind]-kindOrder[b.kind]:(depCount.get(a)??0)-(depCount.get(b)??0))}function sortByName(workspaces){return [...workspaces].sort((a,b)=>a.kind!==b.kind?kindOrder[a.kind]-kindOrder[b.kind]:a.name.localeCompare(b.name))}function filterWorkspaces(workspaces,patterns){let byName=new Map(workspaces.map(w=>[w.name,w])),matches=new Set;for(let pattern of patterns){let transitive=pattern.endsWith("..."),name=transitive?pattern.slice(0,-3):pattern;byName.has(name)&&matches.add(name),transitive&&collectDeps(name,byName,matches);}return workspaces.filter(w=>matches.has(w.name))}function collectDeps(name,byName,collected){let workspace=byName.get(name);if(workspace)for(let dep of workspace.deps)byName.has(dep)&&!collected.has(dep)&&(collected.add(dep),collectDeps(dep,byName,collected));}function defineConfig(config){return config}var CONFIG_FILES=["hlidskjalf.config.ts","hlidskjalf.config.mjs","hlidskjalf.config.js"],PACKAGE_JSON_KEY="hlidskjalf";function validate(raw,source){if(!isPlainObject(raw))return console.error(`Ignoring ${source}: expected a config object.`),{};let config={};if(Array.isArray(raw.filter)){let strings=raw.filter.filter(v=>typeof v=="string"),filter=normalizeFilters(strings);filter.length&&(config.filter=filter);}(raw.order==="run"||raw.order==="alphabetical")&&(config.order=raw.order),typeof raw.title=="string"&&(config.title=raw.title),typeof raw.metrics=="boolean"&&(config.metrics=raw.metrics),typeof raw.watch=="boolean"&&(config.watch=raw.watch);let theme=parseTheme(raw.theme);return theme&&(config.theme=theme),config}function fromPackageJson(root){let path=join(root,"package.json");if(!existsSync(path))return {};let parsed;try{parsed=JSON.parse(readFileSync(path,"utf-8"));}catch{return {}}if(!isPlainObject(parsed))return {};let key=parsed[PACKAGE_JSON_KEY];return key===void 0?{}:validate(key,`package.json "${PACKAGE_JSON_KEY}" key`)}async function fromConfigFile(root){for(let name of CONFIG_FILES){let path=join(root,name);if(existsSync(path))try{let mod=await import(pathToFileURL(path).href);return validate(mod.default??mod,name)}catch(err){return console.error(`Ignoring ${name}: ${err instanceof Error?err.message:"failed to load"}`),{}}}return {}}async function loadConfig(root){let fromPkg=fromPackageJson(root),fromFile=await fromConfigFile(root);return {...fromPkg,...fromFile}}
|
|
9
|
+
|
|
10
|
+
export { DEFAULT_THEME, HINTS, THEME_ALIASES, colors, cpuColor, defineConfig, discover, enterAltScreen, every, filterWorkspaces, formatCpu, formatMem, hyperlink, loadConfig, memColor, normalizeFilters, parseTheme, setTheme, sortByDeps, sortByName, statusDisplay, themes, truncateEnd };
|
package/dist/config.d.ts
CHANGED
|
@@ -1,3 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared presentation layer: the colour palette and status glyphs, the terminal
|
|
3
|
+
* primitives the dashboard leans on (OSC 8 hyperlinks, alternate screen), value
|
|
4
|
+
* formatters, and the timer helpers used across the polling code. Kept free of
|
|
5
|
+
* Ink/React imports so every helper here can be unit tested directly.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Built-in palettes, named for the realms of Norse cosmology (fitting for a tool named
|
|
10
|
+
* after Odin's all-seeing high seat). `success`/`warning`/`error` stay semantically
|
|
11
|
+
* legible — green-ish / amber-ish / red-ish — in every theme so a status glyph never
|
|
12
|
+
* misreads; the personality lives in the accent and status colours, with the neutral
|
|
13
|
+
* slots pulled from {@link SHARED}.
|
|
14
|
+
*/
|
|
15
|
+
declare const themes: {
|
|
16
|
+
readonly bifrost: {
|
|
17
|
+
readonly success: string;
|
|
18
|
+
readonly warning: string;
|
|
19
|
+
readonly error: string;
|
|
20
|
+
readonly pending: string;
|
|
21
|
+
readonly highlight: string;
|
|
22
|
+
readonly muted: string;
|
|
23
|
+
readonly dim: string;
|
|
24
|
+
readonly separator: string;
|
|
25
|
+
readonly accent: "#7C8EF2";
|
|
26
|
+
readonly accentBright: "#BEC7F9";
|
|
27
|
+
readonly url: "#E8EBFD";
|
|
28
|
+
};
|
|
29
|
+
readonly niflheim: {
|
|
30
|
+
readonly success: string;
|
|
31
|
+
readonly warning: string;
|
|
32
|
+
readonly error: string;
|
|
33
|
+
readonly pending: string;
|
|
34
|
+
readonly highlight: string;
|
|
35
|
+
readonly muted: string;
|
|
36
|
+
readonly dim: string;
|
|
37
|
+
readonly separator: string;
|
|
38
|
+
readonly accent: "#22D3EE";
|
|
39
|
+
readonly accentBright: "#92E9F7";
|
|
40
|
+
readonly url: "#E7FAFD";
|
|
41
|
+
};
|
|
42
|
+
readonly muspelheim: {
|
|
43
|
+
readonly success: string;
|
|
44
|
+
readonly warning: string;
|
|
45
|
+
readonly error: string;
|
|
46
|
+
readonly pending: string;
|
|
47
|
+
readonly highlight: string;
|
|
48
|
+
readonly muted: string;
|
|
49
|
+
readonly dim: string;
|
|
50
|
+
readonly separator: string;
|
|
51
|
+
readonly accent: "#F97316";
|
|
52
|
+
readonly accentBright: "#FCBB8D";
|
|
53
|
+
readonly url: "#FEF0E6";
|
|
54
|
+
};
|
|
55
|
+
readonly yggdrasil: {
|
|
56
|
+
readonly success: string;
|
|
57
|
+
readonly warning: string;
|
|
58
|
+
readonly error: string;
|
|
59
|
+
readonly pending: string;
|
|
60
|
+
readonly highlight: string;
|
|
61
|
+
readonly muted: string;
|
|
62
|
+
readonly dim: string;
|
|
63
|
+
readonly separator: string;
|
|
64
|
+
readonly accent: "#22C55E";
|
|
65
|
+
readonly accentBright: "#73E79E";
|
|
66
|
+
readonly url: "#E9FBF0";
|
|
67
|
+
};
|
|
68
|
+
};
|
|
69
|
+
/** Selectable theme names — the keys of {@link themes}. */
|
|
70
|
+
type ThemeName = keyof typeof themes;
|
|
71
|
+
|
|
1
72
|
type SortOrder = 'alphabetical' | 'run';
|
|
2
73
|
|
|
3
74
|
/**
|
|
@@ -21,6 +92,12 @@ interface Config {
|
|
|
21
92
|
metrics?: boolean;
|
|
22
93
|
/** Re-discover workspaces when `package.json` files change. Defaults to `true`. */
|
|
23
94
|
watch?: boolean;
|
|
95
|
+
/**
|
|
96
|
+
* Colour theme. Defaults to `bifrost` (icy blues and purples). Accepts a realm name
|
|
97
|
+
* (`niflheim`, `muspelheim`, `yggdrasil`) or an elemental alias (`ice`, `fire`, `earth`).
|
|
98
|
+
* See {@link themes} for the palettes or define your own with {@link parseTheme}.
|
|
99
|
+
*/
|
|
100
|
+
theme?: ThemeName;
|
|
24
101
|
}
|
|
25
102
|
/**
|
|
26
103
|
* Identity helper that gives a `hlidskjalf.config.ts` full type checking:
|
package/dist/config.js
CHANGED
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createRequire } from 'node:module';
|
|
3
|
-
import { loadConfig, normalizeFilters, discover, filterWorkspaces, sortByDeps, sortByName } from './chunk-
|
|
3
|
+
import { loadConfig, normalizeFilters, parseTheme, themes, THEME_ALIASES, DEFAULT_THEME, setTheme, enterAltScreen, colors, HINTS, discover, filterWorkspaces, sortByDeps, sortByName, statusDisplay, hyperlink, truncateEnd, every, formatCpu, cpuColor, formatMem, memColor } from './chunk-WSO44QZR.js';
|
|
4
4
|
import { __commonJS, __require, __toESM, __export } from './chunk-4PLEQYIC.js';
|
|
5
5
|
import { parseArgs, stripVTControlCharacters } from 'util';
|
|
6
6
|
import { Stream, PassThrough } from 'stream';
|
|
@@ -218,10 +218,10 @@ Read about how to prevent this error on https://github.com/vadimdemedes/ink/#isr
|
|
|
218
218
|
Read about how to prevent this error on https://github.com/vadimdemedes/ink/#israwmodesupported`);if(stdin.setEncoding("utf8"),isEnabled){this.rawModeEnabledCount===0&&(stdin.ref(),stdin.setRawMode(true),stdin.addListener("readable",this.handleReadable)),this.rawModeEnabledCount++;return}--this.rawModeEnabledCount===0&&(stdin.setRawMode(false),stdin.removeListener("readable",this.handleReadable),stdin.unref());};handleReadable=()=>{let chunk;for(;(chunk=this.props.stdin.read())!==null;)this.handleInput(chunk),this.internal_eventEmitter.emit("input",chunk);};handleInput=input=>{input===""&&this.props.exitOnCtrlC&&this.handleExit(),input===escape&&this.state.activeFocusId&&this.setState({activeFocusId:void 0}),this.state.isFocusEnabled&&this.state.focusables.length>0&&(input===tab&&this.focusNext(),input===shiftTab&&this.focusPrevious());};handleExit=error=>{this.isRawModeSupported()&&this.handleSetRawMode(false),this.props.onExit(error);};enableFocus=()=>{this.setState({isFocusEnabled:true});};disableFocus=()=>{this.setState({isFocusEnabled:false});};focus=id=>{this.setState(previousState=>previousState.focusables.some(focusable=>focusable?.id===id)?{activeFocusId:id}:previousState);};focusNext=()=>{this.setState(previousState=>{let firstFocusableId=previousState.focusables.find(focusable=>focusable.isActive)?.id;return {activeFocusId:this.findNextFocusable(previousState)??firstFocusableId}});};focusPrevious=()=>{this.setState(previousState=>{let lastFocusableId=previousState.focusables.findLast(focusable=>focusable.isActive)?.id;return {activeFocusId:this.findPreviousFocusable(previousState)??lastFocusableId}});};addFocusable=(id,{autoFocus})=>{this.setState(previousState=>{let nextFocusId=previousState.activeFocusId;return !nextFocusId&&autoFocus&&(nextFocusId=id),{activeFocusId:nextFocusId,focusables:[...previousState.focusables,{id,isActive:true}]}});};removeFocusable=id=>{this.setState(previousState=>({activeFocusId:previousState.activeFocusId===id?void 0:previousState.activeFocusId,focusables:previousState.focusables.filter(focusable=>focusable.id!==id)}));};activateFocusable=id=>{this.setState(previousState=>({focusables:previousState.focusables.map(focusable=>focusable.id!==id?focusable:{id,isActive:true})}));};deactivateFocusable=id=>{this.setState(previousState=>({activeFocusId:previousState.activeFocusId===id?void 0:previousState.activeFocusId,focusables:previousState.focusables.map(focusable=>focusable.id!==id?focusable:{id,isActive:false})}));};findNextFocusable=state=>{let activeIndex=state.focusables.findIndex(focusable=>focusable.id===state.activeFocusId);for(let index=activeIndex+1;index<state.focusables.length;index++){let focusable=state.focusables[index];if(focusable?.isActive)return focusable.id}};findPreviousFocusable=state=>{let activeIndex=state.focusables.findIndex(focusable=>focusable.id===state.activeFocusId);for(let index=activeIndex-1;index>=0;index--){let focusable=state.focusables[index];if(focusable?.isActive)return focusable.id}}};var noop=()=>{},Ink=class{options;log;throttledLog;isUnmounted;lastOutput;container;rootNode;fullStaticOutput;exitPromise;restoreConsole;unsubscribeResize;constructor(options2){autoBind(this),this.options=options2,this.rootNode=createNode("ink-root"),this.rootNode.onComputeLayout=this.calculateLayout,this.rootNode.onRender=options2.debug?this.onRender:throttle(this.onRender,32,{leading:true,trailing:true}),this.rootNode.onImmediateRender=this.onRender,this.log=log_update_default.create(options2.stdout),this.throttledLog=options2.debug?this.log:throttle(this.log,void 0,{leading:true,trailing:true}),this.isUnmounted=false,this.lastOutput="",this.fullStaticOutput="",this.container=reconciler_default.createContainer(this.rootNode,0,null,false,null,"id",()=>{},null),this.unsubscribeExit=(0, import_signal_exit2.default)(this.unmount,{alwaysLast:false}),process2.env.DEV==="true"&&reconciler_default.injectIntoDevTools({bundleType:0,version:"16.13.1",rendererPackageName:"ink"}),options2.patchConsole&&this.patchConsole(),is_in_ci_default||(options2.stdout.on("resize",this.resized),this.unsubscribeResize=()=>{options2.stdout.off("resize",this.resized);});}resized=()=>{this.calculateLayout(),this.onRender();};resolveExitPromise=()=>{};rejectExitPromise=()=>{};unsubscribeExit=()=>{};calculateLayout=()=>{let terminalWidth=this.options.stdout.columns||80;this.rootNode.yogaNode.setWidth(terminalWidth),this.rootNode.yogaNode.calculateLayout(void 0,void 0,src_default.DIRECTION_LTR);};onRender=()=>{if(this.isUnmounted)return;let{output,outputHeight,staticOutput}=renderer_default(this.rootNode),hasStaticOutput=staticOutput&&staticOutput!==`
|
|
219
219
|
`;if(this.options.debug){hasStaticOutput&&(this.fullStaticOutput+=staticOutput),this.options.stdout.write(this.fullStaticOutput+output);return}if(is_in_ci_default){hasStaticOutput&&this.options.stdout.write(staticOutput),this.lastOutput=output;return}if(hasStaticOutput&&(this.fullStaticOutput+=staticOutput),outputHeight>=this.options.stdout.rows){this.options.stdout.write(base_exports.clearTerminal+this.fullStaticOutput+output),this.lastOutput=output;return}hasStaticOutput&&(this.log.clear(),this.options.stdout.write(staticOutput),this.log(output)),!hasStaticOutput&&output!==this.lastOutput&&this.throttledLog(output),this.lastOutput=output;};render(node){let tree=import_react10.default.createElement(App,{stdin:this.options.stdin,stdout:this.options.stdout,stderr:this.options.stderr,writeToStdout:this.writeToStdout,writeToStderr:this.writeToStderr,exitOnCtrlC:this.options.exitOnCtrlC,onExit:this.unmount},node);reconciler_default.updateContainer(tree,this.container,null,noop);}writeToStdout(data){if(!this.isUnmounted){if(this.options.debug){this.options.stdout.write(data+this.fullStaticOutput+this.lastOutput);return}if(is_in_ci_default){this.options.stdout.write(data);return}this.log.clear(),this.options.stdout.write(data),this.log(this.lastOutput);}}writeToStderr(data){if(!this.isUnmounted){if(this.options.debug){this.options.stderr.write(data),this.options.stdout.write(this.fullStaticOutput+this.lastOutput);return}if(is_in_ci_default){this.options.stderr.write(data);return}this.log.clear(),this.options.stderr.write(data),this.log(this.lastOutput);}}unmount(error){this.isUnmounted||(this.calculateLayout(),this.onRender(),this.unsubscribeExit(),typeof this.restoreConsole=="function"&&this.restoreConsole(),typeof this.unsubscribeResize=="function"&&this.unsubscribeResize(),is_in_ci_default?this.options.stdout.write(this.lastOutput+`
|
|
220
220
|
`):this.options.debug||this.log.done(),this.isUnmounted=true,reconciler_default.updateContainer(null,this.container,null,noop),instances_default.delete(this.options.stdout),error instanceof Error?this.rejectExitPromise(error):this.resolveExitPromise());}async waitUntilExit(){return this.exitPromise||=new Promise((resolve,reject)=>{this.resolveExitPromise=resolve,this.rejectExitPromise=reject;}),this.exitPromise}clear(){!is_in_ci_default&&!this.options.debug&&this.log.clear();}patchConsole(){this.options.debug||(this.restoreConsole=dist_default((stream,data)=>{stream==="stdout"&&this.writeToStdout(data),stream==="stderr"&&(data.startsWith("The above error occurred")||this.writeToStderr(data));}));}};var render=(node,options2)=>{let inkOptions={stdout:process2.stdout,stdin:process2.stdin,stderr:process2.stderr,debug:false,exitOnCtrlC:true,patchConsole:true,...getOptions(options2)},instance=getInstance(inkOptions.stdout,()=>new Ink(inkOptions));return instance.render(node),{rerender:instance.render,unmount(){instance.unmount();},waitUntilExit:instance.waitUntilExit,cleanup:()=>instances_default.delete(inkOptions.stdout),clear:instance.clear}},render_default=render,getOptions=(stdout={})=>stdout instanceof Stream?{stdout,stdin:process2.stdin}:stdout,getInstance=(stdout,createInstance)=>{let instance=instances_default.get(stdout);return instance||(instance=createInstance(),instances_default.set(stdout,instance)),instance};__toESM(require_react(),1);__toESM(require_react(),1);__toESM(require_react(),1);__toESM(require_react(),1);var import_react16=__toESM(require_react(),1);var metaKeyCodeRe=/^(?:\x1b)([a-zA-Z0-9])$/,fnKeyRe=/^(?:\x1b+)(O|N|\[|\[\[)(?:(\d+)(?:;(\d+))?([~^$])|(?:1;)?(\d+)?([a-zA-Z]))/,keyName={OP:"f1",OQ:"f2",OR:"f3",OS:"f4","[11~":"f1","[12~":"f2","[13~":"f3","[14~":"f4","[[A":"f1","[[B":"f2","[[C":"f3","[[D":"f4","[[E":"f5","[15~":"f5","[17~":"f6","[18~":"f7","[19~":"f8","[20~":"f9","[21~":"f10","[23~":"f11","[24~":"f12","[A":"up","[B":"down","[C":"right","[D":"left","[E":"clear","[F":"end","[H":"home",OA:"up",OB:"down",OC:"right",OD:"left",OE:"clear",OF:"end",OH:"home","[1~":"home","[2~":"insert","[3~":"delete","[4~":"end","[5~":"pageup","[6~":"pagedown","[[5~":"pageup","[[6~":"pagedown","[7~":"home","[8~":"end","[a":"up","[b":"down","[c":"right","[d":"left","[e":"clear","[2$":"insert","[3$":"delete","[5$":"pageup","[6$":"pagedown","[7$":"home","[8$":"end",Oa:"up",Ob:"down",Oc:"right",Od:"left",Oe:"clear","[2^":"insert","[3^":"delete","[5^":"pageup","[6^":"pagedown","[7^":"home","[8^":"end","[Z":"tab"},nonAlphanumericKeys=[...Object.values(keyName),"backspace"],isShiftKey=code=>["[a","[b","[c","[d","[e","[2$","[3$","[5$","[6$","[7$","[8$","[Z"].includes(code),isCtrlKey=code=>["Oa","Ob","Oc","Od","Oe","[2^","[3^","[5^","[6^","[7^","[8^"].includes(code),parseKeypress=(s="")=>{let parts;Buffer$1.isBuffer(s)?s[0]>127&&s[1]===void 0?(s[0]-=128,s="\x1B"+String(s)):s=String(s):s!==void 0&&typeof s!="string"?s=String(s):s||(s="");let key={name:"",ctrl:false,meta:false,shift:false,option:false,sequence:s,raw:s};if(key.sequence=key.sequence||s||key.name,s==="\r")key.raw=void 0,key.name="return";else if(s===`
|
|
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
|
|
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.accent,children:"\u25CF"}),(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 ESC3="\x1B",HOME_SEQUENCES=new Set([`${ESC3}[H`,`${ESC3}[1~`,`${ESC3}[7~`,`${ESC3}OH`]),END_SEQUENCES=new Set([`${ESC3}[F`,`${ESC3}[4~`,`${ESC3}[8~`,`${ESC3}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"}}}),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,options={root,order,filter:filter?.length?filter:void 0,title,metrics,watch:watch2},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==="--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);
|
|
225
225
|
/*! Bundled license information:
|
|
226
226
|
|
|
227
227
|
react/cjs/react.production.min.js:
|
package/package.json
CHANGED
package/dist/chunk-26F2AUTG.js
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import { createRequire } from 'node:module';
|
|
3
|
-
import { existsSync, readdirSync, realpathSync, readFileSync } from 'fs';
|
|
4
|
-
import { resolve, join, sep } from 'path';
|
|
5
|
-
import { pathToFileURL } from 'url';
|
|
6
|
-
|
|
7
|
-
createRequire(import.meta.url);
|
|
8
|
-
function isPlainObject(value){return typeof value=="object"&&value!==null&&!Array.isArray(value)}var VALID_PKG_NAME=/^(@[a-z0-9\-~][a-z0-9\-._~]*\/)?[a-z0-9\-~][a-z0-9\-._~]*$/;function isValidPackageName(name){return VALID_PKG_NAME.test(name)&&name.length<=214}function normalizeFilters(raw){return raw.map(v=>v.replace(/^\{(.+)\}$/,"$1")).filter(v=>{let name=v.endsWith("...")?v.slice(0,-3):v;return isValidPackageName(name)?true:(console.error(`Ignoring invalid filter: ${name}`),false)})}function stringRecord(value){if(!isPlainObject(value))return;let result={};for(let[key,v]of Object.entries(value))typeof v=="string"&&(result[key]=v);return result}function readJson(path){try{let raw=JSON.parse(readFileSync(path,"utf-8"));return isPlainObject(raw)?{name:typeof raw.name=="string"?raw.name:void 0,scripts:stringRecord(raw.scripts),dependencies:stringRecord(raw.dependencies)}:null}catch{return null}}function workspaceDeps(pkg){return Object.entries(pkg.dependencies??{}).filter(([name,v])=>v.startsWith("workspace:")&&isValidPackageName(name)).map(([name])=>name)}var kindOrder={package:0,app:1,service:1};function discover(root){let results=[],dirs=[["packages","package"],["apps","app"],["services","service"]],resolvedRoot=resolve(root);for(let[dir,kind]of dirs){let base=join(resolvedRoot,dir);if(existsSync(base))for(let entry of readdirSync(base,{withFileTypes:true})){if(!entry.isDirectory())continue;let entryPath=join(base,entry.name);try{if(!realpathSync(entryPath).startsWith(resolvedRoot+sep))continue}catch{continue}let pkg=readJson(join(entryPath,"package.json"));pkg?.name&&isValidPackageName(pkg.name)&&pkg.name!=="hlidskjalf"&&pkg.scripts?.dev&&results.push({name:pkg.name,kind,deps:workspaceDeps(pkg)});}}return results}function sortByDeps(workspaces){let names=new Set(workspaces.map(w=>w.name)),depCount=new Map;for(let workspace of workspaces){let count=0;for(let dep of workspace.deps)names.has(dep)&&count++;depCount.set(workspace,count);}return [...workspaces].sort((a,b)=>a.kind!==b.kind?kindOrder[a.kind]-kindOrder[b.kind]:(depCount.get(a)??0)-(depCount.get(b)??0))}function sortByName(workspaces){return [...workspaces].sort((a,b)=>a.kind!==b.kind?kindOrder[a.kind]-kindOrder[b.kind]:a.name.localeCompare(b.name))}function filterWorkspaces(workspaces,patterns){let byName=new Map(workspaces.map(w=>[w.name,w])),matches=new Set;for(let pattern of patterns){let transitive=pattern.endsWith("..."),name=transitive?pattern.slice(0,-3):pattern;byName.has(name)&&matches.add(name),transitive&&collectDeps(name,byName,matches);}return workspaces.filter(w=>matches.has(w.name))}function collectDeps(name,byName,collected){let workspace=byName.get(name);if(workspace)for(let dep of workspace.deps)byName.has(dep)&&!collected.has(dep)&&(collected.add(dep),collectDeps(dep,byName,collected));}function defineConfig(config){return config}var CONFIG_FILES=["hlidskjalf.config.ts","hlidskjalf.config.mjs","hlidskjalf.config.js"],PACKAGE_JSON_KEY="hlidskjalf";function validate(raw,source){if(!isPlainObject(raw))return console.error(`Ignoring ${source}: expected a config object.`),{};let config={};if(Array.isArray(raw.filter)){let strings=raw.filter.filter(v=>typeof v=="string"),filter=normalizeFilters(strings);filter.length&&(config.filter=filter);}return (raw.order==="run"||raw.order==="alphabetical")&&(config.order=raw.order),typeof raw.title=="string"&&(config.title=raw.title),typeof raw.metrics=="boolean"&&(config.metrics=raw.metrics),typeof raw.watch=="boolean"&&(config.watch=raw.watch),config}function fromPackageJson(root){let path=join(root,"package.json");if(!existsSync(path))return {};let parsed;try{parsed=JSON.parse(readFileSync(path,"utf-8"));}catch{return {}}if(!isPlainObject(parsed))return {};let key=parsed[PACKAGE_JSON_KEY];return key===void 0?{}:validate(key,`package.json "${PACKAGE_JSON_KEY}" key`)}async function fromConfigFile(root){for(let name of CONFIG_FILES){let path=join(root,name);if(existsSync(path))try{let mod=await import(pathToFileURL(path).href);return validate(mod.default??mod,name)}catch(err){return console.error(`Ignoring ${name}: ${err instanceof Error?err.message:"failed to load"}`),{}}}return {}}async function loadConfig(root){let fromPkg=fromPackageJson(root),fromFile=await fromConfigFile(root);return {...fromPkg,...fromFile}}
|
|
9
|
-
|
|
10
|
-
export { defineConfig, discover, filterWorkspaces, loadConfig, normalizeFilters, sortByDeps, sortByName };
|