@wolfstar/cli 1.0.0-next-20260919162943 → 2.0.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/README.md +20 -3
- package/dist/{_shared-dVR2pKjb.js → _shared-B5EYpDS-.js} +3 -2
- package/dist/_shared-B5EYpDS-.js.map +1 -0
- package/dist/{build-BUhQQ1E5.js → build-Df5jpHx-.js} +5 -5
- package/dist/build-Df5jpHx-.js.map +1 -0
- package/dist/cli.js +1 -1
- package/dist/{codegen-hmnFzRjK.js → codegen-DDkAozhq.js} +4 -4
- package/dist/codegen-DDkAozhq.js.map +1 -0
- package/dist/{commands-BApoAbpQ.js → commands-BuQLzWfi.js} +4 -4
- package/dist/commands-BuQLzWfi.js.map +1 -0
- package/dist/{dev-B0RlN46N.js → dev-zxmvjryt.js} +9 -9
- package/dist/dev-zxmvjryt.js.map +1 -0
- package/dist/{diagnostics-C98hnJB5.js → diagnostics-CZBVxlpj.js} +2 -2
- package/dist/diagnostics-CZBVxlpj.js.map +1 -0
- package/dist/{errors-D1UU8atd.js → errors-Crt4hu0b.js} +3 -3
- package/dist/errors-Crt4hu0b.js.map +1 -0
- package/dist/{external-DVEYf7yD.js → external-CxFKxwi3.js} +2 -2
- package/dist/external-CxFKxwi3.js.map +1 -0
- package/dist/framework-auto-imports-Gu_PXSyr.js +14 -0
- package/dist/framework-auto-imports-Gu_PXSyr.js.map +1 -0
- package/dist/index.d.ts +3 -3
- package/dist/index.js +4 -4
- package/dist/{info-DN4vUx1S.js → info-C23rw2wp.js} +3 -3
- package/dist/info-C23rw2wp.js.map +1 -0
- package/dist/{locales-khJEemUn.js → locales-wTnYUPpl.js} +6 -6
- package/dist/locales-wTnYUPpl.js.map +1 -0
- package/dist/log-buffer-CY82aqnb.js.map +1 -1
- package/dist/nitro-sP2F3SQu.js +18 -0
- package/dist/nitro-sP2F3SQu.js.map +1 -0
- package/dist/none-uC_wi_l4.js.map +1 -1
- package/dist/plugin-registrations-Dr_BicfC.js +3 -0
- package/dist/{prepare-wGp-cAa9.js → prepare-es4Udgqh.js} +5 -5
- package/dist/prepare-es4Udgqh.js.map +1 -0
- package/dist/{project-DT3wg_lf.js → project-MD4dIo2X.js} +2 -2
- package/dist/{project-DT3wg_lf.js.map → project-MD4dIo2X.js.map} +1 -1
- package/dist/{run-D_j2tqWF.js → run-Bxf2ws_n.js} +8 -8
- package/dist/{run-D_j2tqWF.js.map → run-Bxf2ws_n.js.map} +1 -1
- package/dist/{tsc-Bex5dwzD.js → tsc-DO7D_uCl.js} +3 -3
- package/dist/tsc-DO7D_uCl.js.map +1 -0
- package/dist/tsc-YnAWKn3n.js +3 -0
- package/dist/{tsdown-scDokwb0.js → tsdown-BlPFHbIw.js} +5 -4
- package/dist/tsdown-BlPFHbIw.js.map +1 -0
- package/dist/tui-BRddrLQP.js.map +1 -1
- package/dist/{tunnel-BHHUb9Tq.js → tunnel-DiL0Wxi_.js} +2 -2
- package/dist/tunnel-DiL0Wxi_.js.map +1 -0
- package/dist/vite-CLyB6wl7.js +18 -0
- package/dist/vite-CLyB6wl7.js.map +1 -0
- package/package.json +12 -4
- package/dist/_shared-dVR2pKjb.js.map +0 -1
- package/dist/build-BUhQQ1E5.js.map +0 -1
- package/dist/codegen-hmnFzRjK.js.map +0 -1
- package/dist/commands-BApoAbpQ.js.map +0 -1
- package/dist/dev-B0RlN46N.js.map +0 -1
- package/dist/diagnostics-C98hnJB5.js.map +0 -1
- package/dist/errors-D1UU8atd.js.map +0 -1
- package/dist/external-DVEYf7yD.js.map +0 -1
- package/dist/info-DN4vUx1S.js.map +0 -1
- package/dist/locales-khJEemUn.js.map +0 -1
- package/dist/nitro-Cki2gTpt.js +0 -145
- package/dist/nitro-Cki2gTpt.js.map +0 -1
- package/dist/plugin-registrations-4PA_qWXF.js +0 -34
- package/dist/plugin-registrations-4PA_qWXF.js.map +0 -1
- package/dist/prepare-wGp-cAa9.js.map +0 -1
- package/dist/tsc-Bex5dwzD.js.map +0 -1
- package/dist/tsc-dzhKrr7T.js +0 -3
- package/dist/tsdown-scDokwb0.js.map +0 -1
- package/dist/tunnel-BHHUb9Tq.js.map +0 -1
- package/dist/vite-C-szLSGb.js +0 -109
- package/dist/vite-C-szLSGb.js.map +0 -1
package/dist/tui-BRddrLQP.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tui-BRddrLQP.js","names":[],"sources":["../src/dev/tui/ink/theme.tsx","../src/dev/tui/ink/components/HelpOverlay.tsx","../src/dev/tui/ink/hooks/useLogVersion.ts","../src/dev/tui/ink/components/Hints.tsx","../src/dev/tui/ink/components/LogBrowser.tsx","../src/dev/tui/ink/hooks/useDevStatus.ts","../src/dev/tui/ink/hooks/useUptime.ts","../src/dev/tui/panel-logic.ts","../src/dev/tui/ink/components/InfoOverlay.tsx","../src/dev/tui/ink/components/Panel.tsx","../src/dev/tui/ink/hooks/useLogCounters.ts","../src/dev/tui/ink/hooks/useBuildClock.ts","../src/dev/open-url.ts","../src/dev/tui/ink/components/ThemeOverlay.tsx","../src/dev/tui/ink/DevApp.tsx","../src/dev/tui/capture-output.ts","../src/dev/tui/tui.tsx"],"sourcesContent":["import { createContext, useContext, type ReactNode } from 'react';\nimport { THEMES, type ThemeName, type ThemeToken } from '../../../utils/theme.js';\n\ninterface ThemeState {\n\t/** Whether the UI may use colour. */\n\tcolor: boolean;\n\ttheme: ThemeName;\n}\n\n/**\n * `stars dev` decides once whether the UI may use colour (`NO_COLOR`, `FORCE_COLOR`, TTY detection) and which theme\n * to paint with; every component reads both from here instead of re-deriving them.\n */\nconst ThemeContext = createContext<ThemeState>({ color: true, theme: 'dark' });\n\nexport function ThemeProvider({ color, theme, children }: ThemeState & { children: ReactNode }) {\n\treturn <ThemeContext value={{ color, theme }}>{children}</ThemeContext>;\n}\n\n/**\n * Returns a theme colour only when colour is enabled, so `<Text color={usePaint()('success')}>` degrades to plain text.\n */\nexport function usePaint(): (token: ThemeToken) => string | undefined {\n\tconst { color, theme } = useContext(ThemeContext);\n\treturn (token) => (color ? THEMES[theme][token] : undefined);\n}\n\nexport function useColorEnabled(): boolean {\n\treturn useContext(ThemeContext).color;\n}\n","import { Box, Text, useInput } from 'ink';\nimport { usePaint } from '../theme.js';\n\nconst KEYS: [string, string][] = [\n\t['r', 'restart the bot now'],\n\t['o', 'open the local URL in a browser'],\n\t['t', 'toggle the public tunnel'],\n\t['i', 'show versions, URLs and session info'],\n\t['T', 'pick a colour theme (dark, light, colour-blind friendly, ANSI)'],\n\t['l', 'open the logs (scroll, filter by source or level)'],\n\t['e', 'jump to the last error, keeping its context'],\n\t['c / Ctrl+L', 'clear the log history'],\n\t['q / Ctrl+C', 'stop the bot and quit'],\n\t['?', 'toggle this help']\n];\n\nexport interface HelpOverlayProps {\n\theight: number;\n\twidth: number;\n\tonClose: () => void;\n}\n\n/** The static keys reference, opened with `?` from the pinned panel. */\nexport function HelpOverlay({ height, width, onClose }: HelpOverlayProps) {\n\tconst paint = usePaint();\n\tuseInput((input, key) => {\n\t\tif (!key.ctrl && (key.escape || ['q', 'h', '?'].includes(input))) onClose();\n\t});\n\n\treturn (\n\t\t<Box flexDirection=\"column\" height={height}>\n\t\t\t<Text bold> keyboard shortcuts</Text>\n\t\t\t<Text dimColor>{'─'.repeat(width)}</Text>\n\t\t\t{KEYS.slice(0, Math.max(0, height - 3)).map(([key, description]) => (\n\t\t\t\t<Text key={key} wrap=\"truncate-end\">\n\t\t\t\t\t{' '}\n\t\t\t\t\t<Text bold color={paint('text')}>\n\t\t\t\t\t\t{key.padEnd(14)}\n\t\t\t\t\t</Text>\n\t\t\t\t\t<Text dimColor>{description}</Text>\n\t\t\t\t</Text>\n\t\t\t))}\n\t\t\t<Box flexGrow={1} />\n\t\t\t<Text dimColor> q close</Text>\n\t\t</Box>\n\t);\n}\n","import { useEffect, useState } from 'react';\nimport type { LogBuffer } from '../../../../utils/log-buffer.js';\n\n/** Bumps whenever the buffer changes, so a consumer can re-derive a filtered view without re-filtering on every render. */\nexport function useLogVersion(logs: LogBuffer): number {\n\tconst [version, setVersion] = useState(0);\n\n\tuseEffect(() => {\n\t\tconst bump = () => setVersion((current) => current + 1);\n\t\tlogs.on('entry', bump);\n\t\tlogs.on('clear', bump);\n\t\tbump();\n\t\treturn () => {\n\t\t\tlogs.off('entry', bump);\n\t\t\tlogs.off('clear', bump);\n\t\t};\n\t}, [logs]);\n\n\treturn version;\n}\n","import { Text } from 'ink';\n\nexport interface Hint {\n\tkey: string;\n\tlabel: string;\n\tpriority: number;\n}\n\nexport const PANEL_HINTS: Hint[] = [\n\t{ key: 'r', label: 'restart', priority: 80 },\n\t{ key: 'o', label: 'open', priority: 40 },\n\t{ key: 't', label: 'tunnel', priority: 60 },\n\t{ key: 'i', label: 'info', priority: 50 },\n\t{ key: 'T', label: 'theme', priority: 30 },\n\t{ key: 'l', label: 'logs', priority: 70 },\n\t{ key: '?', label: 'help', priority: 100 },\n\t{ key: 'q', label: 'quit', priority: 90 }\n];\n\n/** Drop the lowest-priority shortcuts first; help and the last error survive narrow panes. */\nexport function Hints({ hints, width }: { hints: readonly Hint[]; width: number }) {\n\tconst shown = [...hints];\n\tconst length = () => shown.reduce((size, hint) => size + hint.key.length + hint.label.length + 4, -2);\n\twhile (shown.length > 1 && length() > width) {\n\t\tconst weakest = shown.reduce((a, b) => (a.priority <= b.priority ? a : b));\n\t\tshown.splice(shown.indexOf(weakest), 1);\n\t}\n\treturn (\n\t\t<Text wrap=\"truncate-end\">\n\t\t\t{' '}\n\t\t\t{shown.map(({ key, label }, i) => (\n\t\t\t\t<Text key={key}>\n\t\t\t\t\t{i > 0 && <Text dimColor> · </Text>}\n\t\t\t\t\t<Text bold>{key}</Text>\n\t\t\t\t\t<Text dimColor>{` ${label}`}</Text>\n\t\t\t\t</Text>\n\t\t\t))}\n\t\t</Text>\n\t);\n}\n","import { Box, Text, useInput } from 'ink';\nimport { useMemo, useState } from 'react';\nimport { stripVTControlCharacters } from 'node:util';\nimport type { DevService } from '../../../dev-service.js';\nimport { isErrorDetail, type LogEntry, type LogLevel } from '../../../../utils/log-buffer.js';\nimport { useLogVersion } from '../hooks/useLogVersion.js';\nimport { usePaint } from '../theme.js';\nimport { Hints } from './Hints.js';\n\nexport interface LogBrowserProps {\n\tservice: DevService;\n\theight: number;\n\twidth: number;\n\tlastError?: boolean;\n\tonClose: () => void;\n\tonCopy?: (text: string) => void;\n}\n\nconst group = (entry: LogEntry) => (entry.source === 'app' ? 'runtime' : entry.source === 'build' || entry.source === 'tsc' ? 'build' : 'cli');\n\n/** Filterable history, using Nuxt's keys and selecting the last error without discarding its context. */\nexport function LogBrowser({ service, height, width, lastError = false, onClose, onCopy }: LogBrowserProps) {\n\tconst paint = usePaint();\n\tconst [sources, setSources] = useState({ cli: true, build: true, runtime: true });\n\tconst [level, setLevel] = useState<LogLevel | null>(null);\n\tconst [query, setQuery] = useState('');\n\tconst [searching, setSearching] = useState(false);\n\tconst [selected, setSelected] = useState<number | null>(() =>\n\t\tlastError ? (service.logs.entries().findLast((entry) => entry.level === 'error' && !isErrorDetail(entry))?.id ?? null) : null\n\t);\n\tconst version = useLogVersion(service.logs);\n\tconst entries = useMemo(\n\t\t() =>\n\t\t\tservice.logs\n\t\t\t\t.filter({ level })\n\t\t\t\t.filter((entry) => sources[group(entry)] && stripVTControlCharacters(entry.text).toLowerCase().includes(query.toLowerCase())),\n\t\t[service, sources, level, query, version]\n\t);\n\tconst bodyHeight = Math.max(0, height - 3);\n\tconst index = entries.findIndex((entry) => entry.id === selected);\n\tconst rows = entries.flatMap((entry) =>\n\t\tstripVTControlCharacters(entry.text)\n\t\t\t.split('\\n')\n\t\t\t.map((line, i) => ({\n\t\t\t\tentry,\n\t\t\t\ttext: i === 0 ? `${new Date(entry.time).toLocaleTimeString()} ${entry.source.padEnd(6)} ${line}` : ` ${line}`\n\t\t\t}))\n\t);\n\tconst selectedStart = rows.findIndex((row) => row.entry.id === selected);\n\tconst selectedEnd = rows.findLastIndex((row) => row.entry.id === selected) + 1;\n\tconst end =\n\t\tindex < 0 ? rows.length : Math.min(rows.length, selectedStart + Math.max(bodyHeight, Math.min(selectedEnd - selectedStart, bodyHeight)));\n\tconst visible = rows.slice(Math.max(0, end - bodyHeight), end);\n\tconst move = (delta: number) => {\n\t\tif (!entries.length) return;\n\t\tconst next = index < 0 ? (delta < 0 ? entries.length - 1 : 0) : Math.max(0, Math.min(entries.length - 1, index + delta));\n\t\tsetSelected(entries[next]!.id);\n\t};\n\n\tuseInput((input, key) => {\n\t\tif (key.ctrl) return;\n\t\tif (searching) {\n\t\t\tif (key.escape) {\n\t\t\t\tsetSearching(false);\n\t\t\t\tsetQuery('');\n\t\t\t} else if (key.return) setSearching(false);\n\t\t\telse if (key.backspace || key.delete) setQuery((value) => [...value].slice(0, -1).join(''));\n\t\t\telse if (input && !key.upArrow && !key.downArrow) setQuery((value) => value + input);\n\t\t\tsetSelected(null);\n\t\t\treturn;\n\t\t}\n\t\tif (key.escape || input === 'l' || input === 'q') return onClose();\n\t\tif (input === '/') return setSearching(true);\n\t\tif (input === 'e' || input === 'w' || input === 'a') {\n\t\t\tconst next = input === 'e' ? 'error' : input === 'w' ? 'warn' : null;\n\t\t\tsetLevel((current) => (current === next ? null : next));\n\t\t\treturn setSelected(null);\n\t\t}\n\t\tif (input === 'c' || input === 'b' || input === 'r') {\n\t\t\tconst source = input === 'c' ? 'cli' : input === 'b' ? 'build' : 'runtime';\n\t\t\tsetSources((current) => {\n\t\t\t\tconst next = { ...current, [source]: !current[source] };\n\t\t\t\treturn Object.values(next).some(Boolean) ? next : current;\n\t\t\t});\n\t\t\treturn setSelected(null);\n\t\t}\n\t\tif (input === 'x') {\n\t\t\tservice.clearLogs();\n\t\t\treturn setSelected(null);\n\t\t}\n\t\tif (key.upArrow || input === 'k') return move(-1);\n\t\tif (key.downArrow || input === 'j') return move(1);\n\t\tif (key.pageUp) return move(-Math.max(1, bodyHeight));\n\t\tif (key.pageDown) return move(Math.max(1, bodyHeight));\n\t\tif (key.home || input === 'g') return setSelected(entries[0]?.id ?? null);\n\t\tif (key.end || input === 'G') return setSelected(null);\n\t\tif ((key.return || input === 'y') && index >= 0) onCopy?.(stripVTControlCharacters(entries[index]!.text));\n\t});\n\n\tconst hints = searching\n\t\t? [\n\t\t\t\t['enter', 'apply'],\n\t\t\t\t['esc', 'cancel']\n\t\t\t]\n\t\t: [\n\t\t\t\t['↑/↓', 'select'],\n\t\t\t\t['g/G', 'top/bottom'],\n\t\t\t\t['e', 'errors'],\n\t\t\t\t['w', 'warnings'],\n\t\t\t\t['a', 'all'],\n\t\t\t\t['c/b/r', 'sources'],\n\t\t\t\t['/', 'search'],\n\t\t\t\t['x', 'clear'],\n\t\t\t\t['enter', 'copy'],\n\t\t\t\t['q', 'close']\n\t\t\t];\n\treturn (\n\t\t<Box flexDirection=\"column\" height={height}>\n\t\t\t<Text wrap=\"truncate-end\">\n\t\t\t\t{' '}\n\t\t\t\t<Text bold>logs</Text>\n\t\t\t\t<Text dimColor>{` · ${Object.entries(sources)\n\t\t\t\t\t.filter(([, shown]) => shown)\n\t\t\t\t\t.map(([source]) => source)\n\t\t\t\t\t.join(\n\t\t\t\t\t\t'+'\n\t\t\t\t\t)} · ${level ? `${level}+ only` : 'all levels'}${query || searching ? ` · search ${query}${searching ? '▏' : ''}` : ''}`}</Text>\n\t\t\t</Text>\n\t\t\t<Text dimColor>{'─'.repeat(width)}</Text>\n\t\t\t<Box flexDirection=\"column\" height={bodyHeight} overflow=\"hidden\">\n\t\t\t\t{visible.length === 0 && <Text dimColor> no matching logs</Text>}\n\t\t\t\t{visible.map(({ entry, text }, i) => (\n\t\t\t\t\t<Text key={`${entry.id}-${i}`} wrap=\"truncate-end\">\n\t\t\t\t\t\t<Text color={paint('brand')}>{entry.id === selected ? '▎ ' : ' '}</Text>\n\t\t\t\t\t\t<Text\n\t\t\t\t\t\t\tcolor={paint(\n\t\t\t\t\t\t\t\tentry.level === 'error'\n\t\t\t\t\t\t\t\t\t? 'error'\n\t\t\t\t\t\t\t\t\t: entry.level === 'warn'\n\t\t\t\t\t\t\t\t\t\t? 'warning'\n\t\t\t\t\t\t\t\t\t\t: entry.level === 'success'\n\t\t\t\t\t\t\t\t\t\t\t? 'success'\n\t\t\t\t\t\t\t\t\t\t\t: 'text'\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\tdimColor={isErrorDetail(entry)}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{text}\n\t\t\t\t\t\t</Text>\n\t\t\t\t\t</Text>\n\t\t\t\t))}\n\t\t\t</Box>\n\t\t\t<Hints\n\t\t\t\twidth={width}\n\t\t\t\thints={hints.map(([key, label], i) => ({ key: key!, label: label!, priority: i === hints.length - 1 ? 100 : hints.length - i }))}\n\t\t\t/>\n\t\t</Box>\n\t);\n}\n","import { useEffect, useState } from 'react';\nimport type { DevService, DevStatus } from '../../../dev-service.js';\n\n/**\n * Mirrors the service's status into React state. The service stays the single source of truth: the UI only\n * subscribes to it, exactly like the plain renderer does.\n */\nexport function useDevStatus(service: DevService): DevStatus {\n\tconst [status, setStatus] = useState<DevStatus>(() => service.status);\n\n\tuseEffect(() => {\n\t\tconst onStatus = (next: DevStatus) => setStatus(next);\n\t\tservice.on('status', onStatus);\n\t\tsetStatus(service.status);\n\t\treturn () => {\n\t\t\tservice.off('status', onStatus);\n\t\t};\n\t}, [service]);\n\n\treturn status;\n}\n","import { useEffect, useState } from 'react';\n\n/**\n * Re-renders once a second while the bot is up, so the uptime in the header keeps counting.\n */\nexport function useUptime(startedAt: number | null): number | null {\n\tconst [now, setNow] = useState(() => Date.now());\n\n\tuseEffect(() => {\n\t\tif (startedAt === null) return;\n\n\t\tsetNow(Date.now());\n\t\tconst timer = setInterval(() => setNow(Date.now()), 1000);\n\t\treturn () => clearInterval(timer);\n\t}, [startedAt]);\n\n\treturn startedAt === null ? null : now - startedAt;\n}\n","import type { DevStatus } from '../dev-service.js';\n\nexport type Badge = 'starting' | 'building' | 'restarting' | 'ready' | 'error';\n\n/**\n * The badge and standing description for the panel's status row, mirroring the states Nuxt CLI v4's own dev panel\n * cycles through (`STARTING`/`BUILDING`/`RESTART`/`READY`/`ERROR`).\n */\nexport function describeBadge(status: DevStatus): { badge: Badge; note: string } {\n\tif (status.build === 'building') return { badge: status.startedAt === null ? 'starting' : 'building', note: status.progress.message };\n\tif (status.process === 'starting') return { badge: 'starting', note: 'starting the bot' };\n\tif (status.process === 'stopping') return { badge: 'restarting', note: 'restarting the bot' };\n\tif (status.build === 'failed') return { badge: 'error', note: 'build failed, waiting for changes' };\n\tif (status.process === 'crashed') return { badge: 'error', note: 'the bot crashed, press r to restart' };\n\tif (status.health === 'down') return { badge: 'error', note: 'health check failed' };\n\tif (status.typecheck === 'failed') return { badge: 'error', note: 'type check failed, press e to view it' };\n\tif (status.process === 'stopped') return { badge: 'error', note: 'the bot stopped, press r to restart' };\n\tif (status.progress.fraction < 1) return { badge: 'starting', note: status.progress.message };\n\tif (status.process === 'running') return { badge: 'ready', note: 'watching for changes' };\n\treturn { badge: 'starting', note: 'waiting for the first build' };\n}\n\n/** Formats a duration the way a dev session reads it: `mm:ss` under an hour, `h:mm:ss` above. */\nexport function formatDuration(milliseconds: number): string {\n\tconst total = Math.max(0, Math.floor(milliseconds / 1000));\n\tconst seconds = total % 60;\n\tconst minutes = Math.floor(total / 60) % 60;\n\tconst hours = Math.floor(total / 3600);\n\tconst pad = (value: number) => value.toString().padStart(2, '0');\n\n\treturn hours > 0 ? `${hours}:${pad(minutes)}:${pad(seconds)}` : `${pad(minutes)}:${pad(seconds)}`;\n}\n","import { Box, Text, useInput } from 'ink';\nimport type { DevService } from '../../../dev-service.js';\nimport { useDevStatus } from '../hooks/useDevStatus.js';\nimport { useUptime } from '../hooks/useUptime.js';\nimport { formatDuration } from '../../panel-logic.js';\n\nexport function InfoOverlay({ service, height, width, onClose }: { service: DevService; height: number; width: number; onClose: () => void }) {\n\tconst status = useDevStatus(service);\n\tconst uptime = useUptime(status.startedAt);\n\tuseInput((input, key) => {\n\t\tif (!key.ctrl && (key.escape || ['q', 'i'].includes(input))) onClose();\n\t});\n\tconst lines = [\n\t\t['Project', service.config.packageJson?.name ?? 'stars project'],\n\t\t['Root', service.config.root],\n\t\t['Node', process.version],\n\t\t['Builder', service.builder.tool],\n\t\t['Local', status.url ?? '—'],\n\t\t['Tunnel', status.tunnelUrl ?? status.tunnel],\n\t\t['Process', `${status.process}${status.pid ? ` (${status.pid})` : ''}`],\n\t\t['Uptime', uptime === null ? '—' : formatDuration(uptime)],\n\t\t['Restarts', String(status.restarts)],\n\t\t['Health', service.config.dev.health ? status.health : 'not configured (READY reports process state)'],\n\t\t['Types', `${status.typecheck}${status.typeErrors ? ` (${status.typeErrors} errors)` : ''}`],\n\t\t['Log file', service.config.dev.logFile ?? 'disabled']\n\t];\n\treturn (\n\t\t<Box flexDirection=\"column\" height={height}>\n\t\t\t<Text bold wrap=\"truncate-end\">\n\t\t\t\t{' '}\n\t\t\t\tsession info\n\t\t\t</Text>\n\t\t\t<Text dimColor>{'─'.repeat(width)}</Text>\n\t\t\t{lines.slice(0, Math.max(0, height - 3)).map(([label, value]) => (\n\t\t\t\t<Text key={label} wrap=\"truncate-end\">\n\t\t\t\t\t{' '}\n\t\t\t\t\t<Text bold>{label!.padEnd(10)}</Text>\n\t\t\t\t\t<Text dimColor>{value}</Text>\n\t\t\t\t</Text>\n\t\t\t))}\n\t\t\t<Box flexGrow={1} />\n\t\t\t<Text dimColor> q close</Text>\n\t\t</Box>\n\t);\n}\n","import { Box, Text } from 'ink';\nimport type { ReactNode } from 'react';\nimport type { ResolvedStarsConfig } from '@wolfstar/http-framework/config';\nimport type { DevStatus } from '../../../dev-service.js';\nimport { readOwnPackageJson } from '../../../../utils/version.js';\nimport type { LogCounters } from '../hooks/useLogCounters.js';\nimport { describeBadge } from '../../panel-logic.js';\nimport { usePaint } from '../theme.js';\nimport { Hints, PANEL_HINTS } from './Hints.js';\n\nexport interface PanelProps {\n\tstatus: DevStatus;\n\tconfig: ResolvedStarsConfig;\n\tcounters: LogCounters;\n\tframe: number;\n\telapsedMs: number;\n\twidth: number;\n\theight: number;\n\tconfirmQuit: boolean;\n}\n\n/** Nuxt's wordmark / URLs / progress / status / hints layout, with Stars branding. */\nexport function Panel({ status, config, counters, frame, elapsedMs, width, height, confirmQuit }: PanelProps) {\n\tconst paint = usePaint();\n\tconst state = describeBadge(status);\n\tconst busy = state.badge !== 'ready' && state.badge !== 'error';\n\tconst badge = !busy && counters.errors > 0 ? 'error' : state.badge;\n\tconst note = badge === 'error' && state.badge === 'ready' ? 'an error was logged · press e to view it' : state.note;\n\tconst filled = Math.round(Math.min(1, Math.max(0, status.progress.fraction)) * 20);\n\tconst wordmark = config.dev.banner === false ? [] : (config.dev.banner?.flatMap((line) => line.split('\\n')) ?? [null]);\n\tconst blocks: { name: string; content: ReactNode }[] = [\n\t\t...wordmark.slice(0, 4).map((line, index) => ({\n\t\t\tname: 'wordmark',\n\t\t\tcontent: (\n\t\t\t\t<Box key={index} justifyContent=\"space-between\">\n\t\t\t\t\t<Text wrap=\"truncate-end\">\n\t\t\t\t\t\t{' '}\n\t\t\t\t\t\t{line === null ? (\n\t\t\t\t\t\t\t<>\n\t\t\t\t\t\t\t\t<Text color={paint('brand')}>\n\t\t\t\t\t\t\t\t\t{[...'·✦★✦'].map((cell, i) => (\n\t\t\t\t\t\t\t\t\t\t<Text key={i} dimColor={busy && i !== frame % 4}>\n\t\t\t\t\t\t\t\t\t\t\t{cell}\n\t\t\t\t\t\t\t\t\t\t</Text>\n\t\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t\t</Text>\n\t\t\t\t\t\t\t\t{' '}\n\t\t\t\t\t\t\t\t<Text bold color={paint('brand')}>\n\t\t\t\t\t\t\t\t\tStars\n\t\t\t\t\t\t\t\t</Text>\n\t\t\t\t\t\t\t\t<Text dimColor>{` ${readOwnPackageJson().version}`}</Text>\n\t\t\t\t\t\t\t</>\n\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t<Text color={paint('brand')}>{line}</Text>\n\t\t\t\t\t\t)}\n\t\t\t\t\t</Text>\n\t\t\t\t\t{index === 0 && width >= 60 && badge === 'ready' && status.progress.readyMs !== null && (\n\t\t\t\t\t\t<Text dimColor>{`ready in ${(status.progress.readyMs / 1000).toFixed(2)}s `}</Text>\n\t\t\t\t\t)}\n\t\t\t\t</Box>\n\t\t\t)\n\t\t})),\n\t\t{ name: 'space', content: <Text> </Text> },\n\t\t...(status.url\n\t\t\t? [\n\t\t\t\t\t{\n\t\t\t\t\t\tname: 'urls',\n\t\t\t\t\t\tcontent: (\n\t\t\t\t\t\t\t<Text wrap=\"truncate-end\">\n\t\t\t\t\t\t\t\t{' '}\n\t\t\t\t\t\t\t\t<Text dimColor>{'Local '}</Text>\n\t\t\t\t\t\t\t\t<Text color={paint('url')} dimColor={busy}>\n\t\t\t\t\t\t\t\t\t{status.url}\n\t\t\t\t\t\t\t\t</Text>\n\t\t\t\t\t\t\t\t{busy && <Text color={paint('busy')}>{` ${['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'][frame % 10]}`}</Text>}\n\t\t\t\t\t\t\t</Text>\n\t\t\t\t\t\t)\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t: []),\n\t\t...(status.tunnelUrl\n\t\t\t? [\n\t\t\t\t\t{\n\t\t\t\t\t\tname: 'urls',\n\t\t\t\t\t\tcontent: (\n\t\t\t\t\t\t\t<Text wrap=\"truncate-end\">\n\t\t\t\t\t\t\t\t{' '}\n\t\t\t\t\t\t\t\t<Text dimColor>{'Tunnel '}</Text>\n\t\t\t\t\t\t\t\t<Text color={paint('tunnel')}>{status.tunnelUrl}</Text>\n\t\t\t\t\t\t\t</Text>\n\t\t\t\t\t\t)\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t: []),\n\t\t{ name: 'space', content: <Text> </Text> },\n\t\t{\n\t\t\tname: 'summary',\n\t\t\tcontent: busy ? (\n\t\t\t\t<Text wrap=\"truncate-end\">\n\t\t\t\t\t{' '}\n\t\t\t\t\t<Text color={paint('brand')}>{'━'.repeat(filled)}</Text>\n\t\t\t\t\t<Text dimColor>\n\t\t\t\t\t\t{'━'.repeat(20 - filled)}\n\t\t\t\t\t\t{` ${Math.round(status.progress.fraction * 100)}% · ${(elapsedMs / 1000).toFixed(1)}s`}\n\t\t\t\t\t</Text>\n\t\t\t\t</Text>\n\t\t\t) : (\n\t\t\t\t<Text wrap=\"truncate-end\">\n\t\t\t\t\t{' '}\n\t\t\t\t\t{counters.warnings > 0 && (\n\t\t\t\t\t\t<Text color={paint('warning')}>{`⚠ ${counters.warnings} ${plural(counters.warnings, 'warning')} `}</Text>\n\t\t\t\t\t)}\n\t\t\t\t\t{counters.errors > 0 && <Text bold color={paint('error')}>{`✖ ${counters.errors} ${plural(counters.errors, 'error')} `}</Text>}\n\t\t\t\t\t{counters.errors === 0 && counters.warnings === 0 && (\n\t\t\t\t\t\t<Text dimColor>\n\t\t\t\t\t\t\t{status.typecheck === 'checking'\n\t\t\t\t\t\t\t\t? 'checking types'\n\t\t\t\t\t\t\t\t: status.tunnel === 'failed'\n\t\t\t\t\t\t\t\t\t? 'tunnel failed · press l to view logs'\n\t\t\t\t\t\t\t\t\t: 'logs folded away · press l to view'}\n\t\t\t\t\t\t</Text>\n\t\t\t\t\t)}\n\t\t\t\t</Text>\n\t\t\t)\n\t\t},\n\t\t{ name: 'space', content: <Text> </Text> },\n\t\t{\n\t\t\tname: 'status',\n\t\t\tcontent: (\n\t\t\t\t<Text wrap=\"truncate-end\">\n\t\t\t\t\t{' '}\n\t\t\t\t\t<Text\n\t\t\t\t\t\tbold\n\t\t\t\t\t\tbackgroundColor={paint(confirmQuit || busy ? 'busy' : badge === 'error' ? 'error' : 'success')}\n\t\t\t\t\t\tcolor={paint(badge === 'error' && !confirmQuit ? 'onError' : 'onBright')}\n\t\t\t\t\t>{` ${confirmQuit ? 'QUIT?' : badge === 'restarting' ? 'RESTART' : badge.toUpperCase()} `}</Text>\n\t\t\t\t\t{' '}\n\t\t\t\t\t<Text dimColor>{confirmQuit ? 'press y to confirm, esc to stay' : note}</Text>\n\t\t\t\t</Text>\n\t\t\t)\n\t\t},\n\t\t{\n\t\t\tname: 'hints',\n\t\t\tcontent: confirmQuit ? (\n\t\t\t\t<Text> </Text>\n\t\t\t) : (\n\t\t\t\t<Hints width={width} hints={[...(counters.errors ? [{ key: 'e', label: 'last error', priority: Infinity }] : []), ...PANEL_HINTS]} />\n\t\t\t)\n\t\t}\n\t];\n\tlet shown = blocks;\n\tconst budget = Math.max(2, Math.min(height, 14));\n\tfor (const name of ['space', 'summary', 'urls', 'wordmark']) {\n\t\tif (shown.length <= budget) break;\n\t\tshown = shown.filter((block) => block.name !== name);\n\t}\n\tshown = shown.filter((block, i, all) => block.name !== 'space' || (i > 0 && i < all.length - 1 && all[i - 1]?.name !== 'space'));\n\treturn (\n\t\t<Box flexDirection=\"column\">\n\t\t\t{shown.map((block, index) => (\n\t\t\t\t<Box key={index} flexDirection=\"column\" height={1}>\n\t\t\t\t\t{block.content}\n\t\t\t\t</Box>\n\t\t\t))}\n\t\t</Box>\n\t);\n}\n\nfunction plural(count: number, word: string): string {\n\treturn count === 1 ? word : `${word}s`;\n}\n","import { useEffect, useState } from 'react';\nimport type { DevService, DevStatus } from '../../../dev-service.js';\nimport { isErrorDetail, type LogEntry } from '../../../../utils/log-buffer.js';\n\nexport interface LogCounters {\n\twarnings: number;\n\terrors: number;\n}\n\n/**\n * Warnings and errors logged since the last successful build, the way Nuxt CLI v4's own panel counts them: the\n * badge's job is the current state, this line is what happened getting there.\n */\nexport function useLogCounters(service: DevService): LogCounters {\n\tconst count = () =>\n\t\tservice.logs.entries().reduce<LogCounters>(\n\t\t\t(total, entry) => ({\n\t\t\t\twarnings: total.warnings + Number(entry.level === 'warn'),\n\t\t\t\terrors: total.errors + Number(entry.level === 'error' && !isErrorDetail(entry))\n\t\t\t}),\n\t\t\t{ warnings: 0, errors: 0 }\n\t\t);\n\tconst [counters, setCounters] = useState<LogCounters>(count);\n\n\tuseEffect(() => {\n\t\tlet previousBuild: DevStatus['build'] = service.status.build;\n\t\tlet previousStart = service.status.startedAt;\n\n\t\tconst onEntry = (entry: LogEntry) => {\n\t\t\tif (entry.level === 'warn') setCounters((current) => ({ ...current, warnings: current.warnings + 1 }));\n\t\t\telse if (entry.level === 'error' && !isErrorDetail(entry)) setCounters((current) => ({ ...current, errors: current.errors + 1 }));\n\t\t};\n\n\t\tconst onStatus = (status: DevStatus) => {\n\t\t\tif (\n\t\t\t\t(status.build === 'building' && previousBuild !== 'building' && previousBuild !== 'idle') ||\n\t\t\t\t(status.lastRestartReason === 'manual' && status.startedAt !== null && status.startedAt !== previousStart)\n\t\t\t)\n\t\t\t\tsetCounters({ warnings: 0, errors: 0 });\n\t\t\tpreviousBuild = status.build;\n\t\t\tpreviousStart = status.startedAt;\n\t\t};\n\n\t\tservice.logs.on('entry', onEntry);\n\t\tconst onClear = () => setCounters({ warnings: 0, errors: 0 });\n\t\tservice.logs.on('clear', onClear);\n\t\tservice.on('status', onStatus);\n\t\tsetCounters(count());\n\t\treturn () => {\n\t\t\tservice.logs.off('entry', onEntry);\n\t\t\tservice.logs.off('clear', onClear);\n\t\t\tservice.off('status', onStatus);\n\t\t};\n\t}, [service]);\n\n\treturn counters;\n}\n","import { useEffect, useState } from 'react';\n\n/** The clock moves during a long compiler phase; the percentage only moves on real build events. */\nexport function useBuildClock(startedAt: number, active: boolean, reducedMotion: boolean) {\n\tconst [now, setNow] = useState(Date.now);\n\tuseEffect(() => {\n\t\tif (!active) return;\n\t\tsetNow(Date.now());\n\t\tconst timer = setInterval(() => setNow(Date.now()), reducedMotion ? 1000 : 120);\n\t\treturn () => clearInterval(timer);\n\t}, [startedAt, active, reducedMotion]);\n\tconst elapsedMs = Math.max(0, now - startedAt);\n\treturn { elapsedMs, frame: reducedMotion ? 0 : Math.floor(elapsedMs / 120) };\n}\n","import { execFile } from 'node:child_process';\n\n/** Called only on an explicit `o` keypress, with no shell interpolation. */\nexport function openDevUrl(value: string | null): Promise<void> {\n\tif (!value) return Promise.resolve();\n\tconst url = new URL(value);\n\tif (url.protocol !== 'http:' && url.protocol !== 'https:') return Promise.reject(new Error('Only HTTP(S) URLs can be opened.'));\n\tconst [command, args] =\n\t\tprocess.platform === 'win32'\n\t\t\t? (['rundll32', ['url.dll,FileProtocolHandler', url.href]] as const)\n\t\t\t: process.platform === 'darwin'\n\t\t\t\t? (['open', [url.href]] as const)\n\t\t\t\t: (['xdg-open', [url.href]] as const);\n\treturn new Promise((resolve, reject) =>\n\t\texecFile(command, [...args], (error) => (error ? reject(new Error(`Could not open the browser: ${error.message}`)) : resolve()))\n\t);\n}\n","import { Box, Text, useInput } from 'ink';\nimport { useState } from 'react';\nimport { THEME_SETTINGS, THEMES, detectTerminalBackground, type ThemeSetting } from '../../../../utils/theme.js';\nimport { useColorEnabled } from '../theme.js';\n\nconst DESCRIPTIONS: Record<ThemeSetting, string> = {\n\tauto: 'match the terminal background',\n\tdark: 'for dark terminals',\n\tlight: 'for light terminals',\n\t'dark-daltonized': 'dark, colour-blind friendly (blue/orange)',\n\t'light-daltonized': 'light, colour-blind friendly (blue/orange)',\n\t'dark-ansi': 'dark, only your terminal palette',\n\t'light-ansi': 'light, only your terminal palette'\n};\n\nexport interface ThemeOverlayProps {\n\t/** The theme setting in effect when the picker opened. */\n\tcurrent: ThemeSetting;\n\theight: number;\n\twidth: number;\n\t/** Called while moving through the list, so the whole UI previews the highlighted theme. */\n\tonPreview: (setting: ThemeSetting) => void;\n\tonSelect: (setting: ThemeSetting) => void;\n\t/** Closes without saving; the caller restores the theme that was in effect. */\n\tonClose: () => void;\n}\n\n/** Like Claude Code's `/theme`: arrows preview live, `Enter` keeps the choice and saves it, `Esc` restores. */\nexport function ThemeOverlay({ current, height, width, onPreview, onSelect, onClose }: ThemeOverlayProps) {\n\tconst color = useColorEnabled();\n\tconst [index, setIndex] = useState(Math.max(0, THEME_SETTINGS.indexOf(current)));\n\n\tconst move = (delta: number) => {\n\t\tconst next = (index + delta + THEME_SETTINGS.length) % THEME_SETTINGS.length;\n\t\tsetIndex(next);\n\t\tonPreview(THEME_SETTINGS[next]!);\n\t};\n\n\tuseInput((input, key) => {\n\t\tif (key.ctrl) return;\n\t\tif (key.escape || input === 'q' || input === 'T') return onClose();\n\t\tif (key.return) return onSelect(THEME_SETTINGS[index]!);\n\t\tif (key.upArrow || input === 'k') return move(-1);\n\t\tif (key.downArrow || input === 'j') return move(1);\n\t});\n\n\treturn (\n\t\t<Box flexDirection=\"column\" height={height}>\n\t\t\t<Text bold> colour theme</Text>\n\t\t\t<Text dimColor>{'─'.repeat(width)}</Text>\n\t\t\t{THEME_SETTINGS.slice(0, Math.max(0, height - 3)).map((setting, i) => {\n\t\t\t\tconst swatch = THEMES[setting === 'auto' ? detectTerminalBackground() : setting];\n\t\t\t\treturn (\n\t\t\t\t\t<Text key={setting} wrap=\"truncate-end\">\n\t\t\t\t\t\t{i === index ? ' ▎ ' : ' '}\n\t\t\t\t\t\t<Text bold={i === index}>{setting.padEnd(18)}</Text>\n\t\t\t\t\t\t{color && (\n\t\t\t\t\t\t\t<Text>\n\t\t\t\t\t\t\t\t<Text color={swatch.success}>● </Text>\n\t\t\t\t\t\t\t\t<Text color={swatch.warning}>● </Text>\n\t\t\t\t\t\t\t\t<Text color={swatch.error}>● </Text>\n\t\t\t\t\t\t\t\t<Text color={swatch.url}>● </Text>\n\t\t\t\t\t\t\t</Text>\n\t\t\t\t\t\t)}\n\t\t\t\t\t\t<Text dimColor>{` ${DESCRIPTIONS[setting]}${setting === current ? ' (current)' : ''}`}</Text>\n\t\t\t\t\t</Text>\n\t\t\t\t);\n\t\t\t})}\n\t\t\t<Box flexGrow={1} />\n\t\t\t<Text dimColor> ↑/↓ preview · enter save · esc cancel</Text>\n\t\t</Box>\n\t);\n}\n","import { Box, useInput, useWindowSize } from 'ink';\nimport { useState } from 'react';\nimport type { DevService } from '../../dev-service.js';\nimport { HelpOverlay } from './components/HelpOverlay.js';\nimport { LogBrowser } from './components/LogBrowser.js';\nimport { InfoOverlay } from './components/InfoOverlay.js';\nimport { Panel } from './components/Panel.js';\nimport { useDevStatus } from './hooks/useDevStatus.js';\nimport { useLogCounters } from './hooks/useLogCounters.js';\nimport { useBuildClock } from './hooks/useBuildClock.js';\nimport { describeBadge } from '../panel-logic.js';\nimport { openDevUrl } from '../../open-url.js';\nimport { ThemeProvider } from './theme.js';\nimport { ThemeOverlay } from './components/ThemeOverlay.js';\nimport { resolveTheme, type ThemeSetting } from '../../../utils/theme.js';\n\nexport interface DevAppProps {\n\tservice: DevService;\n\tcolor: boolean;\n\t/** The theme setting to start with; `auto` follows the terminal background. */\n\ttheme: ThemeSetting;\n\treducedMotion: boolean;\n\t/** Called when the user asks to quit, so the CLI can stop the bot and exit. */\n\tonQuit: () => void;\n\tonViewChange: (overlay: boolean) => void;\n\tonCopy: (text: string) => void;\n\t/** Called when the user keeps a theme in the picker, so the CLI can remember it. */\n\tonThemeSave: (setting: ThemeSetting) => void;\n}\n\ntype View = 'panel' | 'logs' | 'errors' | 'help' | 'info' | 'theme';\n\n/**\n * A bottom-aligned panel in the normal buffer, with logs folded away. Only the browsable overlays use the\n * alternate screen, preserving the terminal's history and the panel when they close.\n */\nexport function DevApp({ service, color, theme, reducedMotion, onQuit, onViewChange, onCopy, onThemeSave }: DevAppProps) {\n\tconst { columns, rows } = useWindowSize();\n\tconst [view, setView] = useState<View>('panel');\n\tconst [confirmQuit, setConfirmQuit] = useState(false);\n\t// `saved` is what Esc restores after previewing other themes in the picker.\n\tconst [saved, setSaved] = useState(theme);\n\tconst [preview, setPreview] = useState(theme);\n\n\tconst status = useDevStatus(service);\n\tconst counters = useLogCounters(service);\n\tconst badge = describeBadge(status).badge;\n\tconst busy = badge !== 'ready' && badge !== 'error';\n\tconst clock = useBuildClock(status.progress.startedAt, busy && view === 'panel', reducedMotion);\n\n\tconst width = Math.max(1, columns);\n\tconst height = Math.max(2, rows - 1);\n\n\tconst changeView = (next: View) => {\n\t\tonViewChange(next !== 'panel');\n\t\tsetView(next);\n\t};\n\n\tuseInput((input, key) => {\n\t\tif (key.ctrl && input === 'c') return onQuit();\n\t\tif (key.ctrl && input === 'l') return service.clearLogs();\n\t\tif (view !== 'panel') return;\n\t\tif (confirmQuit) {\n\t\t\tif (input === 'y') return onQuit();\n\t\t\treturn setConfirmQuit(false);\n\t\t}\n\t\tif (key.ctrl && input === 'r') return void service.restart('manual');\n\t\tif (key.ctrl && input === 'd') return busy ? setConfirmQuit(true) : onQuit();\n\n\t\tswitch (input) {\n\t\t\tcase 'q':\n\t\t\t\treturn busy ? setConfirmQuit(true) : onQuit();\n\t\t\tcase 'r':\n\t\t\t\treturn void service.restart('manual');\n\t\t\tcase 'l':\n\t\t\t\treturn changeView('logs');\n\t\t\tcase 'e':\n\t\t\t\treturn changeView('errors');\n\t\t\tcase 'c':\n\t\t\t\treturn service.clearLogs();\n\t\t\tcase 'o':\n\t\t\t\treturn void openDevUrl(status.url).catch((error: Error) => service.log('stars', 'warn', error.message));\n\t\t\tcase 't':\n\t\t\t\treturn void service.toggleTunnel();\n\t\t\tcase 'i':\n\t\t\t\treturn changeView('info');\n\t\t\tcase 'T':\n\t\t\t\treturn changeView('theme');\n\t\t\tcase 'h':\n\t\t\tcase '?':\n\t\t\t\treturn changeView('help');\n\t\t\tdefault:\n\t\t\t\tbreak;\n\t\t}\n\t});\n\n\treturn (\n\t\t<ThemeProvider color={color} theme={resolveTheme(preview)}>\n\t\t\t<Box width={width} height={height} flexDirection=\"column\" justifyContent={view === 'panel' ? 'flex-end' : 'flex-start'}>\n\t\t\t\t{(view === 'logs' || view === 'errors') && (\n\t\t\t\t\t<LogBrowser\n\t\t\t\t\t\tservice={service}\n\t\t\t\t\t\theight={height}\n\t\t\t\t\t\twidth={width}\n\t\t\t\t\t\tlastError={view === 'errors'}\n\t\t\t\t\t\tonCopy={onCopy}\n\t\t\t\t\t\tonClose={() => changeView('panel')}\n\t\t\t\t\t/>\n\t\t\t\t)}\n\t\t\t\t{view === 'help' && <HelpOverlay height={height} width={width} onClose={() => changeView('panel')} />}\n\t\t\t\t{view === 'info' && <InfoOverlay service={service} height={height} width={width} onClose={() => changeView('panel')} />}\n\t\t\t\t{view === 'theme' && (\n\t\t\t\t\t<ThemeOverlay\n\t\t\t\t\t\tcurrent={saved}\n\t\t\t\t\t\theight={height}\n\t\t\t\t\t\twidth={width}\n\t\t\t\t\t\tonPreview={setPreview}\n\t\t\t\t\t\tonSelect={(setting) => {\n\t\t\t\t\t\t\tsetSaved(setting);\n\t\t\t\t\t\t\tsetPreview(setting);\n\t\t\t\t\t\t\tonThemeSave(setting);\n\t\t\t\t\t\t\tchangeView('panel');\n\t\t\t\t\t\t}}\n\t\t\t\t\t\tonClose={() => {\n\t\t\t\t\t\t\tsetPreview(saved);\n\t\t\t\t\t\t\tchangeView('panel');\n\t\t\t\t\t\t}}\n\t\t\t\t\t/>\n\t\t\t\t)}\n\t\t\t\t{view === 'panel' && (\n\t\t\t\t\t<Panel\n\t\t\t\t\t\tstatus={status}\n\t\t\t\t\t\tconfig={service.config}\n\t\t\t\t\t\tcounters={counters}\n\t\t\t\t\t\t{...clock}\n\t\t\t\t\t\twidth={width}\n\t\t\t\t\t\theight={height}\n\t\t\t\t\t\tconfirmQuit={confirmQuit}\n\t\t\t\t\t/>\n\t\t\t\t)}\n\t\t\t</Box>\n\t\t</ThemeProvider>\n\t);\n}\n","import { StringDecoder } from 'node:string_decoder';\nimport type { DevService } from '../dev-service.js';\nimport { classifyAppLine, type LogLevel } from '../../utils/log-buffer.js';\n\n/** Capture third-party writes before build plugins run. Ink writes through a separate, unpatched sink. */\nexport function captureOutput(service: DevService, stream: NodeJS.WriteStream, fallback: LogLevel): () => void {\n\tconst original = stream.write;\n\tconst decoder = new StringDecoder('utf8');\n\tlet pending = '';\n\tconst emit = (text: string) => {\n\t\tif (text.trim()) service.log('build', classifyAppLine(text, fallback), text);\n\t};\n\tconst write: typeof stream.write = (chunk: unknown, encoding?: unknown, callback?: unknown) => {\n\t\tpending += typeof chunk === 'string' ? chunk : chunk instanceof Uint8Array ? decoder.write(Buffer.from(chunk)) : String(chunk);\n\t\tconst lines = pending.split(/\\r?\\n/);\n\t\tpending = lines.pop() ?? '';\n\t\tfor (const line of lines) emit(line);\n\t\t// A tool without newlines must not grow the capture indefinitely.\n\t\tif (pending.length > 65536) {\n\t\t\temit(pending);\n\t\t\tpending = '';\n\t\t}\n\t\tconst done = typeof encoding === 'function' ? encoding : callback;\n\t\tif (typeof done === 'function') queueMicrotask(() => done());\n\t\treturn true;\n\t};\n\tstream.write = write;\n\treturn () => {\n\t\tif (stream.write === write) stream.write = original;\n\t\temit(pending + decoder.end());\n\t\tpending = '';\n\t};\n}\n","import { render } from 'ink';\nimport type { DevService } from '../dev-service.js';\nimport { DevApp } from './ink/DevApp.js';\nimport type { Renderer } from './plain.js';\nimport { captureOutput } from './capture-output.js';\nimport { isErrorDetail } from '../../utils/log-buffer.js';\nimport type { ThemeSetting } from '../../utils/theme.js';\n\nexport interface TuiRendererOptions {\n\tstdout?: NodeJS.WriteStream;\n\tstdin?: NodeJS.ReadStream;\n\tcolor?: boolean;\n\t/** Defaults to `auto`. */\n\ttheme?: ThemeSetting;\n\t/** Called when the user keeps a theme in the picker. */\n\tonThemeSave?: (setting: ThemeSetting) => void;\n\t/** Freezes spinners, for `STARS_REDUCED_MOTION=1`. */\n\treducedMotion?: boolean;\n\t/** Caps how often Ink repaints; the default is Ink's own. */\n\tfps?: number;\n}\n\n/**\n * A normal-buffer, bottom-aligned panel and alternate-buffer overlays. External output is captured for the log\n * browser; the renderer alone writes to the terminal. Switching views and teardown restore the original buffer.\n *\n * `start()` resolves when the user quits, which is what `stars dev` waits on before shutting the bot down.\n */\nexport function createTuiRenderer(service: DevService, options: TuiRendererOptions = {}): Renderer {\n\tconst stdout = options.stdout ?? process.stdout;\n\tconst stdin = options.stdin ?? process.stdin;\n\tconst write = stdout.write.bind(stdout);\n\t// Bind methods to the real stream (resize subscriptions included), except write which bypasses capture.\n\tconst sink = new Proxy(stdout, {\n\t\tget(target, property) {\n\t\t\tif (property === 'write') return write;\n\t\t\tconst value = Reflect.get(target, property, target);\n\t\t\treturn typeof value === 'function' ? value.bind(target) : value;\n\t\t}\n\t});\n\tconst restoreOutput =\n\t\tstdout === process.stdout ? [captureOutput(service, process.stdout, 'info'), captureOutput(service, process.stderr, 'warn')] : [];\n\tlet alternate = false;\n\tlet stopped = false;\n\tconst switchView = (overlay: boolean) => {\n\t\tif (overlay === alternate || stopped) return;\n\t\tinstance.clear();\n\t\twrite(overlay ? '\\u001B[?1049h\\u001B[H' : '\\u001B[?1049l');\n\t\talternate = overlay;\n\t};\n\n\tlet quit!: () => void;\n\tconst quitting = new Promise<void>((resolve) => {\n\t\tquit = resolve;\n\t});\n\n\tconst instance = render(\n\t\t<DevApp\n\t\t\tservice={service}\n\t\t\tcolor={options.color ?? false}\n\t\t\ttheme={options.theme ?? 'auto'}\n\t\t\tonThemeSave={options.onThemeSave ?? (() => {})}\n\t\t\treducedMotion={options.reducedMotion ?? false}\n\t\t\tonQuit={quit}\n\t\t\tonViewChange={switchView}\n\t\t\tonCopy={(text) => write(`\\u001B]52;c;${Buffer.from(text.slice(0, 65536)).toString('base64')}\\u0007`)}\n\t\t/>,\n\t\t{\n\t\t\tstdout: sink,\n\t\t\tstdin,\n\t\t\t// `stars dev` owns the shutdown: it stops the bot, then exits with the right code.\n\t\t\texitOnCtrlC: false,\n\t\t\tpatchConsole: false,\n\t\t\t// `createTuiRenderer` only runs once `resolveOutputMode()` already picked 'tui' (never in CI or on a\n\t\t\t// non-TTY stdout), so Ink is told to trust that instead of re-deriving it from `process.env.CI`: on a\n\t\t\t// CI runner that env var is set even for this package's own test process, which would otherwise force\n\t\t\t// Ink's non-interactive mode (no repaint until unmount) despite the fake stdin/stdout looking like a\n\t\t\t// real TTY.\n\t\t\tinteractive: true,\n\t\t\t...(options.fps === undefined ? {} : { maxFps: options.fps })\n\t\t}\n\t);\n\n\treturn {\n\t\tasync start() {\n\t\t\tawait Promise.race([quitting, instance.waitUntilExit()]);\n\t\t},\n\t\tstop() {\n\t\t\tif (stopped) return;\n\t\t\tstopped = true;\n\t\t\tif (alternate) instance.clear();\n\t\t\tinstance.unmount();\n\t\t\tif (alternate) write('\\u001B[?1049l');\n\t\t\twrite('\\u001B[?25h');\n\t\t\tfor (const restore of restoreOutput) restore();\n\t\t\t// A fatal startup must not leave the user with only a folded error and no way to read it.\n\t\t\tif (service.status.progress.readyMs === null) {\n\t\t\t\tconst error = service.logs.entries().findLast((entry) => entry.level === 'error' && !isErrorDetail(entry));\n\t\t\t\tif (error) write(`\\n${error.text}\\n`);\n\t\t\t}\n\t\t\tquit();\n\t\t}\n\t};\n}\n\nexport { formatDuration } from './panel-logic.js';\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"tui-BRddrLQP.js","names":[],"sources":["../src/dev/tui/ink/theme.tsx","../src/dev/tui/ink/components/HelpOverlay.tsx","../src/dev/tui/ink/hooks/useLogVersion.ts","../src/dev/tui/ink/components/Hints.tsx","../src/dev/tui/ink/components/LogBrowser.tsx","../src/dev/tui/ink/hooks/useDevStatus.ts","../src/dev/tui/ink/hooks/useUptime.ts","../src/dev/tui/panel-logic.ts","../src/dev/tui/ink/components/InfoOverlay.tsx","../src/dev/tui/ink/components/Panel.tsx","../src/dev/tui/ink/hooks/useLogCounters.ts","../src/dev/tui/ink/hooks/useBuildClock.ts","../src/dev/open-url.ts","../src/dev/tui/ink/components/ThemeOverlay.tsx","../src/dev/tui/ink/DevApp.tsx","../src/dev/tui/capture-output.ts","../src/dev/tui/tui.tsx"],"sourcesContent":["import { createContext, useContext, type ReactNode } from 'react';\nimport { THEMES, type ThemeName, type ThemeToken } from '../../../utils/theme.js';\n\ninterface ThemeState {\n\t/** Whether the UI may use colour. */\n\tcolor: boolean;\n\ttheme: ThemeName;\n}\n\n/**\n * `stars dev` decides once whether the UI may use colour (`NO_COLOR`, `FORCE_COLOR`, TTY detection) and which theme\n * to paint with; every component reads both from here instead of re-deriving them.\n */\nconst ThemeContext = createContext<ThemeState>({ color: true, theme: 'dark' });\n\nexport function ThemeProvider({ color, theme, children }: ThemeState & { children: ReactNode }) {\n\treturn <ThemeContext value={{ color, theme }}>{children}</ThemeContext>;\n}\n\n/**\n * Returns a theme colour only when colour is enabled, so `<Text color={usePaint()('success')}>` degrades to plain text.\n */\nexport function usePaint(): (token: ThemeToken) => string | undefined {\n\tconst { color, theme } = useContext(ThemeContext);\n\treturn (token) => (color ? THEMES[theme][token] : undefined);\n}\n\nexport function useColorEnabled(): boolean {\n\treturn useContext(ThemeContext).color;\n}\n","import { Box, Text, useInput } from 'ink';\nimport { usePaint } from '../theme.js';\n\nconst KEYS: [string, string][] = [\n\t['r', 'restart the bot now'],\n\t['o', 'open the local URL in a browser'],\n\t['t', 'toggle the public tunnel'],\n\t['i', 'show versions, URLs and session info'],\n\t['T', 'pick a colour theme (dark, light, colour-blind friendly, ANSI)'],\n\t['l', 'open the logs (scroll, filter by source or level)'],\n\t['e', 'jump to the last error, keeping its context'],\n\t['c / Ctrl+L', 'clear the log history'],\n\t['q / Ctrl+C', 'stop the bot and quit'],\n\t['?', 'toggle this help']\n];\n\nexport interface HelpOverlayProps {\n\theight: number;\n\twidth: number;\n\tonClose: () => void;\n}\n\n/** The static keys reference, opened with `?` from the pinned panel. */\nexport function HelpOverlay({ height, width, onClose }: HelpOverlayProps) {\n\tconst paint = usePaint();\n\tuseInput((input, key) => {\n\t\tif (!key.ctrl && (key.escape || ['q', 'h', '?'].includes(input))) onClose();\n\t});\n\n\treturn (\n\t\t<Box flexDirection=\"column\" height={height}>\n\t\t\t<Text bold> keyboard shortcuts</Text>\n\t\t\t<Text dimColor>{'─'.repeat(width)}</Text>\n\t\t\t{KEYS.slice(0, Math.max(0, height - 3)).map(([key, description]) => (\n\t\t\t\t<Text key={key} wrap=\"truncate-end\">\n\t\t\t\t\t{' '}\n\t\t\t\t\t<Text bold color={paint('text')}>\n\t\t\t\t\t\t{key.padEnd(14)}\n\t\t\t\t\t</Text>\n\t\t\t\t\t<Text dimColor>{description}</Text>\n\t\t\t\t</Text>\n\t\t\t))}\n\t\t\t<Box flexGrow={1} />\n\t\t\t<Text dimColor> q close</Text>\n\t\t</Box>\n\t);\n}\n","import { useEffect, useState } from 'react';\nimport type { LogBuffer } from '../../../../utils/log-buffer.js';\n\n/** Bumps whenever the buffer changes, so a consumer can re-derive a filtered view without re-filtering on every render. */\nexport function useLogVersion(logs: LogBuffer): number {\n\tconst [version, setVersion] = useState(0);\n\n\tuseEffect(() => {\n\t\tconst bump = () => setVersion((current) => current + 1);\n\t\tlogs.on('entry', bump);\n\t\tlogs.on('clear', bump);\n\t\tbump();\n\t\treturn () => {\n\t\t\tlogs.off('entry', bump);\n\t\t\tlogs.off('clear', bump);\n\t\t};\n\t}, [logs]);\n\n\treturn version;\n}\n","import { Text } from 'ink';\n\nexport interface Hint {\n\tkey: string;\n\tlabel: string;\n\tpriority: number;\n}\n\nexport const PANEL_HINTS: Hint[] = [\n\t{ key: 'r', label: 'restart', priority: 80 },\n\t{ key: 'o', label: 'open', priority: 40 },\n\t{ key: 't', label: 'tunnel', priority: 60 },\n\t{ key: 'i', label: 'info', priority: 50 },\n\t{ key: 'T', label: 'theme', priority: 30 },\n\t{ key: 'l', label: 'logs', priority: 70 },\n\t{ key: '?', label: 'help', priority: 100 },\n\t{ key: 'q', label: 'quit', priority: 90 }\n];\n\n/** Drop the lowest-priority shortcuts first; help and the last error survive narrow panes. */\nexport function Hints({ hints, width }: { hints: readonly Hint[]; width: number }) {\n\tconst shown = [...hints];\n\tconst length = () => shown.reduce((size, hint) => size + hint.key.length + hint.label.length + 4, -2);\n\twhile (shown.length > 1 && length() > width) {\n\t\tconst weakest = shown.reduce((a, b) => (a.priority <= b.priority ? a : b));\n\t\tshown.splice(shown.indexOf(weakest), 1);\n\t}\n\treturn (\n\t\t<Text wrap=\"truncate-end\">\n\t\t\t{' '}\n\t\t\t{shown.map(({ key, label }, i) => (\n\t\t\t\t<Text key={key}>\n\t\t\t\t\t{i > 0 && <Text dimColor> · </Text>}\n\t\t\t\t\t<Text bold>{key}</Text>\n\t\t\t\t\t<Text dimColor>{` ${label}`}</Text>\n\t\t\t\t</Text>\n\t\t\t))}\n\t\t</Text>\n\t);\n}\n","import { Box, Text, useInput } from 'ink';\nimport { useMemo, useState } from 'react';\nimport { stripVTControlCharacters } from 'node:util';\nimport type { DevService } from '../../../dev-service.js';\nimport { isErrorDetail, type LogEntry, type LogLevel } from '../../../../utils/log-buffer.js';\nimport { useLogVersion } from '../hooks/useLogVersion.js';\nimport { usePaint } from '../theme.js';\nimport { Hints } from './Hints.js';\n\nexport interface LogBrowserProps {\n\tservice: DevService;\n\theight: number;\n\twidth: number;\n\tlastError?: boolean;\n\tonClose: () => void;\n\tonCopy?: (text: string) => void;\n}\n\nconst group = (entry: LogEntry) => (entry.source === 'app' ? 'runtime' : entry.source === 'build' || entry.source === 'tsc' ? 'build' : 'cli');\n\n/** Filterable history, using Nuxt's keys and selecting the last error without discarding its context. */\nexport function LogBrowser({ service, height, width, lastError = false, onClose, onCopy }: LogBrowserProps) {\n\tconst paint = usePaint();\n\tconst [sources, setSources] = useState({ cli: true, build: true, runtime: true });\n\tconst [level, setLevel] = useState<LogLevel | null>(null);\n\tconst [query, setQuery] = useState('');\n\tconst [searching, setSearching] = useState(false);\n\tconst [selected, setSelected] = useState<number | null>(() =>\n\t\tlastError ? (service.logs.entries().findLast((entry) => entry.level === 'error' && !isErrorDetail(entry))?.id ?? null) : null\n\t);\n\tconst version = useLogVersion(service.logs);\n\tconst entries = useMemo(\n\t\t() =>\n\t\t\tservice.logs\n\t\t\t\t.filter({ level })\n\t\t\t\t.filter((entry) => sources[group(entry)] && stripVTControlCharacters(entry.text).toLowerCase().includes(query.toLowerCase())),\n\t\t[service, sources, level, query, version]\n\t);\n\tconst bodyHeight = Math.max(0, height - 3);\n\tconst index = entries.findIndex((entry) => entry.id === selected);\n\tconst rows = entries.flatMap((entry) =>\n\t\tstripVTControlCharacters(entry.text)\n\t\t\t.split('\\n')\n\t\t\t.map((line, i) => ({\n\t\t\t\tentry,\n\t\t\t\ttext: i === 0 ? `${new Date(entry.time).toLocaleTimeString()} ${entry.source.padEnd(6)} ${line}` : ` ${line}`\n\t\t\t}))\n\t);\n\tconst selectedStart = rows.findIndex((row) => row.entry.id === selected);\n\tconst selectedEnd = rows.findLastIndex((row) => row.entry.id === selected) + 1;\n\tconst end =\n\t\tindex < 0 ? rows.length : Math.min(rows.length, selectedStart + Math.max(bodyHeight, Math.min(selectedEnd - selectedStart, bodyHeight)));\n\tconst visible = rows.slice(Math.max(0, end - bodyHeight), end);\n\tconst move = (delta: number) => {\n\t\tif (!entries.length) return;\n\t\tconst next = index < 0 ? (delta < 0 ? entries.length - 1 : 0) : Math.max(0, Math.min(entries.length - 1, index + delta));\n\t\tsetSelected(entries[next]!.id);\n\t};\n\n\tuseInput((input, key) => {\n\t\tif (key.ctrl) return;\n\t\tif (searching) {\n\t\t\tif (key.escape) {\n\t\t\t\tsetSearching(false);\n\t\t\t\tsetQuery('');\n\t\t\t} else if (key.return) setSearching(false);\n\t\t\telse if (key.backspace || key.delete) setQuery((value) => [...value].slice(0, -1).join(''));\n\t\t\telse if (input && !key.upArrow && !key.downArrow) setQuery((value) => value + input);\n\t\t\tsetSelected(null);\n\t\t\treturn;\n\t\t}\n\t\tif (key.escape || input === 'l' || input === 'q') return onClose();\n\t\tif (input === '/') return setSearching(true);\n\t\tif (input === 'e' || input === 'w' || input === 'a') {\n\t\t\tconst next = input === 'e' ? 'error' : input === 'w' ? 'warn' : null;\n\t\t\tsetLevel((current) => (current === next ? null : next));\n\t\t\treturn setSelected(null);\n\t\t}\n\t\tif (input === 'c' || input === 'b' || input === 'r') {\n\t\t\tconst source = input === 'c' ? 'cli' : input === 'b' ? 'build' : 'runtime';\n\t\t\tsetSources((current) => {\n\t\t\t\tconst next = { ...current, [source]: !current[source] };\n\t\t\t\treturn Object.values(next).some(Boolean) ? next : current;\n\t\t\t});\n\t\t\treturn setSelected(null);\n\t\t}\n\t\tif (input === 'x') {\n\t\t\tservice.clearLogs();\n\t\t\treturn setSelected(null);\n\t\t}\n\t\tif (key.upArrow || input === 'k') return move(-1);\n\t\tif (key.downArrow || input === 'j') return move(1);\n\t\tif (key.pageUp) return move(-Math.max(1, bodyHeight));\n\t\tif (key.pageDown) return move(Math.max(1, bodyHeight));\n\t\tif (key.home || input === 'g') return setSelected(entries[0]?.id ?? null);\n\t\tif (key.end || input === 'G') return setSelected(null);\n\t\tif ((key.return || input === 'y') && index >= 0) onCopy?.(stripVTControlCharacters(entries[index]!.text));\n\t});\n\n\tconst hints = searching\n\t\t? [\n\t\t\t\t['enter', 'apply'],\n\t\t\t\t['esc', 'cancel']\n\t\t\t]\n\t\t: [\n\t\t\t\t['↑/↓', 'select'],\n\t\t\t\t['g/G', 'top/bottom'],\n\t\t\t\t['e', 'errors'],\n\t\t\t\t['w', 'warnings'],\n\t\t\t\t['a', 'all'],\n\t\t\t\t['c/b/r', 'sources'],\n\t\t\t\t['/', 'search'],\n\t\t\t\t['x', 'clear'],\n\t\t\t\t['enter', 'copy'],\n\t\t\t\t['q', 'close']\n\t\t\t];\n\treturn (\n\t\t<Box flexDirection=\"column\" height={height}>\n\t\t\t<Text wrap=\"truncate-end\">\n\t\t\t\t{' '}\n\t\t\t\t<Text bold>logs</Text>\n\t\t\t\t<Text dimColor>{` · ${Object.entries(sources)\n\t\t\t\t\t.filter(([, shown]) => shown)\n\t\t\t\t\t.map(([source]) => source)\n\t\t\t\t\t.join(\n\t\t\t\t\t\t'+'\n\t\t\t\t\t)} · ${level ? `${level}+ only` : 'all levels'}${query || searching ? ` · search ${query}${searching ? '▏' : ''}` : ''}`}</Text>\n\t\t\t</Text>\n\t\t\t<Text dimColor>{'─'.repeat(width)}</Text>\n\t\t\t<Box flexDirection=\"column\" height={bodyHeight} overflow=\"hidden\">\n\t\t\t\t{visible.length === 0 && <Text dimColor> no matching logs</Text>}\n\t\t\t\t{visible.map(({ entry, text }, i) => (\n\t\t\t\t\t<Text key={`${entry.id}-${i}`} wrap=\"truncate-end\">\n\t\t\t\t\t\t<Text color={paint('brand')}>{entry.id === selected ? '▎ ' : ' '}</Text>\n\t\t\t\t\t\t<Text\n\t\t\t\t\t\t\tcolor={paint(\n\t\t\t\t\t\t\t\tentry.level === 'error'\n\t\t\t\t\t\t\t\t\t? 'error'\n\t\t\t\t\t\t\t\t\t: entry.level === 'warn'\n\t\t\t\t\t\t\t\t\t\t? 'warning'\n\t\t\t\t\t\t\t\t\t\t: entry.level === 'success'\n\t\t\t\t\t\t\t\t\t\t\t? 'success'\n\t\t\t\t\t\t\t\t\t\t\t: 'text'\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\tdimColor={isErrorDetail(entry)}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{text}\n\t\t\t\t\t\t</Text>\n\t\t\t\t\t</Text>\n\t\t\t\t))}\n\t\t\t</Box>\n\t\t\t<Hints\n\t\t\t\twidth={width}\n\t\t\t\thints={hints.map(([key, label], i) => ({ key: key!, label: label!, priority: i === hints.length - 1 ? 100 : hints.length - i }))}\n\t\t\t/>\n\t\t</Box>\n\t);\n}\n","import { useEffect, useState } from 'react';\nimport type { DevService, DevStatus } from '../../../dev-service.js';\n\n/**\n * Mirrors the service's status into React state. The service stays the single source of truth: the UI only\n * subscribes to it, exactly like the plain renderer does.\n */\nexport function useDevStatus(service: DevService): DevStatus {\n\tconst [status, setStatus] = useState<DevStatus>(() => service.status);\n\n\tuseEffect(() => {\n\t\tconst onStatus = (next: DevStatus) => setStatus(next);\n\t\tservice.on('status', onStatus);\n\t\tsetStatus(service.status);\n\t\treturn () => {\n\t\t\tservice.off('status', onStatus);\n\t\t};\n\t}, [service]);\n\n\treturn status;\n}\n","import { useEffect, useState } from 'react';\n\n/**\n * Re-renders once a second while the bot is up, so the uptime in the header keeps counting.\n */\nexport function useUptime(startedAt: number | null): number | null {\n\tconst [now, setNow] = useState(() => Date.now());\n\n\tuseEffect(() => {\n\t\tif (startedAt === null) return;\n\n\t\tsetNow(Date.now());\n\t\tconst timer = setInterval(() => setNow(Date.now()), 1000);\n\t\treturn () => clearInterval(timer);\n\t}, [startedAt]);\n\n\treturn startedAt === null ? null : now - startedAt;\n}\n","import type { DevStatus } from '../dev-service.js';\n\nexport type Badge = 'starting' | 'building' | 'restarting' | 'ready' | 'error';\n\n/**\n * The badge and standing description for the panel's status row, mirroring the states Nuxt CLI v4's own dev panel\n * cycles through (`STARTING`/`BUILDING`/`RESTART`/`READY`/`ERROR`).\n */\nexport function describeBadge(status: DevStatus): { badge: Badge; note: string } {\n\tif (status.build === 'building') return { badge: status.startedAt === null ? 'starting' : 'building', note: status.progress.message };\n\tif (status.process === 'starting') return { badge: 'starting', note: 'starting the bot' };\n\tif (status.process === 'stopping') return { badge: 'restarting', note: 'restarting the bot' };\n\tif (status.build === 'failed') return { badge: 'error', note: 'build failed, waiting for changes' };\n\tif (status.process === 'crashed') return { badge: 'error', note: 'the bot crashed, press r to restart' };\n\tif (status.health === 'down') return { badge: 'error', note: 'health check failed' };\n\tif (status.typecheck === 'failed') return { badge: 'error', note: 'type check failed, press e to view it' };\n\tif (status.process === 'stopped') return { badge: 'error', note: 'the bot stopped, press r to restart' };\n\tif (status.progress.fraction < 1) return { badge: 'starting', note: status.progress.message };\n\tif (status.process === 'running') return { badge: 'ready', note: 'watching for changes' };\n\treturn { badge: 'starting', note: 'waiting for the first build' };\n}\n\n/** Formats a duration the way a dev session reads it: `mm:ss` under an hour, `h:mm:ss` above. */\nexport function formatDuration(milliseconds: number): string {\n\tconst total = Math.max(0, Math.floor(milliseconds / 1000));\n\tconst seconds = total % 60;\n\tconst minutes = Math.floor(total / 60) % 60;\n\tconst hours = Math.floor(total / 3600);\n\tconst pad = (value: number) => value.toString().padStart(2, '0');\n\n\treturn hours > 0 ? `${hours}:${pad(minutes)}:${pad(seconds)}` : `${pad(minutes)}:${pad(seconds)}`;\n}\n","import { Box, Text, useInput } from 'ink';\nimport type { DevService } from '../../../dev-service.js';\nimport { useDevStatus } from '../hooks/useDevStatus.js';\nimport { useUptime } from '../hooks/useUptime.js';\nimport { formatDuration } from '../../panel-logic.js';\n\nexport function InfoOverlay({ service, height, width, onClose }: { service: DevService; height: number; width: number; onClose: () => void }) {\n\tconst status = useDevStatus(service);\n\tconst uptime = useUptime(status.startedAt);\n\tuseInput((input, key) => {\n\t\tif (!key.ctrl && (key.escape || ['q', 'i'].includes(input))) onClose();\n\t});\n\tconst lines = [\n\t\t['Project', service.config.packageJson?.name ?? 'stars project'],\n\t\t['Root', service.config.root],\n\t\t['Node', process.version],\n\t\t['Builder', service.builder.tool],\n\t\t['Local', status.url ?? '—'],\n\t\t['Tunnel', status.tunnelUrl ?? status.tunnel],\n\t\t['Process', `${status.process}${status.pid ? ` (${status.pid})` : ''}`],\n\t\t['Uptime', uptime === null ? '—' : formatDuration(uptime)],\n\t\t['Restarts', String(status.restarts)],\n\t\t['Health', service.config.dev.health ? status.health : 'not configured (READY reports process state)'],\n\t\t['Types', `${status.typecheck}${status.typeErrors ? ` (${status.typeErrors} errors)` : ''}`],\n\t\t['Log file', service.config.dev.logFile ?? 'disabled']\n\t];\n\treturn (\n\t\t<Box flexDirection=\"column\" height={height}>\n\t\t\t<Text bold wrap=\"truncate-end\">\n\t\t\t\t{' '}\n\t\t\t\tsession info\n\t\t\t</Text>\n\t\t\t<Text dimColor>{'─'.repeat(width)}</Text>\n\t\t\t{lines.slice(0, Math.max(0, height - 3)).map(([label, value]) => (\n\t\t\t\t<Text key={label} wrap=\"truncate-end\">\n\t\t\t\t\t{' '}\n\t\t\t\t\t<Text bold>{label!.padEnd(10)}</Text>\n\t\t\t\t\t<Text dimColor>{value}</Text>\n\t\t\t\t</Text>\n\t\t\t))}\n\t\t\t<Box flexGrow={1} />\n\t\t\t<Text dimColor> q close</Text>\n\t\t</Box>\n\t);\n}\n","import { Box, Text } from 'ink';\nimport type { ReactNode } from 'react';\nimport type { ResolvedStarsConfig } from '@wolfstar/schema';\nimport type { DevStatus } from '../../../dev-service.js';\nimport { readOwnPackageJson } from '../../../../utils/version.js';\nimport type { LogCounters } from '../hooks/useLogCounters.js';\nimport { describeBadge } from '../../panel-logic.js';\nimport { usePaint } from '../theme.js';\nimport { Hints, PANEL_HINTS } from './Hints.js';\n\nexport interface PanelProps {\n\tstatus: DevStatus;\n\tconfig: ResolvedStarsConfig;\n\tcounters: LogCounters;\n\tframe: number;\n\telapsedMs: number;\n\twidth: number;\n\theight: number;\n\tconfirmQuit: boolean;\n}\n\n/** Nuxt's wordmark / URLs / progress / status / hints layout, with Stars branding. */\nexport function Panel({ status, config, counters, frame, elapsedMs, width, height, confirmQuit }: PanelProps) {\n\tconst paint = usePaint();\n\tconst state = describeBadge(status);\n\tconst busy = state.badge !== 'ready' && state.badge !== 'error';\n\tconst badge = !busy && counters.errors > 0 ? 'error' : state.badge;\n\tconst note = badge === 'error' && state.badge === 'ready' ? 'an error was logged · press e to view it' : state.note;\n\tconst filled = Math.round(Math.min(1, Math.max(0, status.progress.fraction)) * 20);\n\tconst wordmark = config.dev.banner === false ? [] : (config.dev.banner?.flatMap((line) => line.split('\\n')) ?? [null]);\n\tconst blocks: { name: string; content: ReactNode }[] = [\n\t\t...wordmark.slice(0, 4).map((line, index) => ({\n\t\t\tname: 'wordmark',\n\t\t\tcontent: (\n\t\t\t\t<Box key={index} justifyContent=\"space-between\">\n\t\t\t\t\t<Text wrap=\"truncate-end\">\n\t\t\t\t\t\t{' '}\n\t\t\t\t\t\t{line === null ? (\n\t\t\t\t\t\t\t<>\n\t\t\t\t\t\t\t\t<Text color={paint('brand')}>\n\t\t\t\t\t\t\t\t\t{[...'·✦★✦'].map((cell, i) => (\n\t\t\t\t\t\t\t\t\t\t<Text key={i} dimColor={busy && i !== frame % 4}>\n\t\t\t\t\t\t\t\t\t\t\t{cell}\n\t\t\t\t\t\t\t\t\t\t</Text>\n\t\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t\t</Text>\n\t\t\t\t\t\t\t\t{' '}\n\t\t\t\t\t\t\t\t<Text bold color={paint('brand')}>\n\t\t\t\t\t\t\t\t\tStars\n\t\t\t\t\t\t\t\t</Text>\n\t\t\t\t\t\t\t\t<Text dimColor>{` ${readOwnPackageJson().version}`}</Text>\n\t\t\t\t\t\t\t</>\n\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t<Text color={paint('brand')}>{line}</Text>\n\t\t\t\t\t\t)}\n\t\t\t\t\t</Text>\n\t\t\t\t\t{index === 0 && width >= 60 && badge === 'ready' && status.progress.readyMs !== null && (\n\t\t\t\t\t\t<Text dimColor>{`ready in ${(status.progress.readyMs / 1000).toFixed(2)}s `}</Text>\n\t\t\t\t\t)}\n\t\t\t\t</Box>\n\t\t\t)\n\t\t})),\n\t\t{ name: 'space', content: <Text> </Text> },\n\t\t...(status.url\n\t\t\t? [\n\t\t\t\t\t{\n\t\t\t\t\t\tname: 'urls',\n\t\t\t\t\t\tcontent: (\n\t\t\t\t\t\t\t<Text wrap=\"truncate-end\">\n\t\t\t\t\t\t\t\t{' '}\n\t\t\t\t\t\t\t\t<Text dimColor>{'Local '}</Text>\n\t\t\t\t\t\t\t\t<Text color={paint('url')} dimColor={busy}>\n\t\t\t\t\t\t\t\t\t{status.url}\n\t\t\t\t\t\t\t\t</Text>\n\t\t\t\t\t\t\t\t{busy && <Text color={paint('busy')}>{` ${['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'][frame % 10]}`}</Text>}\n\t\t\t\t\t\t\t</Text>\n\t\t\t\t\t\t)\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t: []),\n\t\t...(status.tunnelUrl\n\t\t\t? [\n\t\t\t\t\t{\n\t\t\t\t\t\tname: 'urls',\n\t\t\t\t\t\tcontent: (\n\t\t\t\t\t\t\t<Text wrap=\"truncate-end\">\n\t\t\t\t\t\t\t\t{' '}\n\t\t\t\t\t\t\t\t<Text dimColor>{'Tunnel '}</Text>\n\t\t\t\t\t\t\t\t<Text color={paint('tunnel')}>{status.tunnelUrl}</Text>\n\t\t\t\t\t\t\t</Text>\n\t\t\t\t\t\t)\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t: []),\n\t\t{ name: 'space', content: <Text> </Text> },\n\t\t{\n\t\t\tname: 'summary',\n\t\t\tcontent: busy ? (\n\t\t\t\t<Text wrap=\"truncate-end\">\n\t\t\t\t\t{' '}\n\t\t\t\t\t<Text color={paint('brand')}>{'━'.repeat(filled)}</Text>\n\t\t\t\t\t<Text dimColor>\n\t\t\t\t\t\t{'━'.repeat(20 - filled)}\n\t\t\t\t\t\t{` ${Math.round(status.progress.fraction * 100)}% · ${(elapsedMs / 1000).toFixed(1)}s`}\n\t\t\t\t\t</Text>\n\t\t\t\t</Text>\n\t\t\t) : (\n\t\t\t\t<Text wrap=\"truncate-end\">\n\t\t\t\t\t{' '}\n\t\t\t\t\t{counters.warnings > 0 && (\n\t\t\t\t\t\t<Text color={paint('warning')}>{`⚠ ${counters.warnings} ${plural(counters.warnings, 'warning')} `}</Text>\n\t\t\t\t\t)}\n\t\t\t\t\t{counters.errors > 0 && <Text bold color={paint('error')}>{`✖ ${counters.errors} ${plural(counters.errors, 'error')} `}</Text>}\n\t\t\t\t\t{counters.errors === 0 && counters.warnings === 0 && (\n\t\t\t\t\t\t<Text dimColor>\n\t\t\t\t\t\t\t{status.typecheck === 'checking'\n\t\t\t\t\t\t\t\t? 'checking types'\n\t\t\t\t\t\t\t\t: status.tunnel === 'failed'\n\t\t\t\t\t\t\t\t\t? 'tunnel failed · press l to view logs'\n\t\t\t\t\t\t\t\t\t: 'logs folded away · press l to view'}\n\t\t\t\t\t\t</Text>\n\t\t\t\t\t)}\n\t\t\t\t</Text>\n\t\t\t)\n\t\t},\n\t\t{ name: 'space', content: <Text> </Text> },\n\t\t{\n\t\t\tname: 'status',\n\t\t\tcontent: (\n\t\t\t\t<Text wrap=\"truncate-end\">\n\t\t\t\t\t{' '}\n\t\t\t\t\t<Text\n\t\t\t\t\t\tbold\n\t\t\t\t\t\tbackgroundColor={paint(confirmQuit || busy ? 'busy' : badge === 'error' ? 'error' : 'success')}\n\t\t\t\t\t\tcolor={paint(badge === 'error' && !confirmQuit ? 'onError' : 'onBright')}\n\t\t\t\t\t>{` ${confirmQuit ? 'QUIT?' : badge === 'restarting' ? 'RESTART' : badge.toUpperCase()} `}</Text>\n\t\t\t\t\t{' '}\n\t\t\t\t\t<Text dimColor>{confirmQuit ? 'press y to confirm, esc to stay' : note}</Text>\n\t\t\t\t</Text>\n\t\t\t)\n\t\t},\n\t\t{\n\t\t\tname: 'hints',\n\t\t\tcontent: confirmQuit ? (\n\t\t\t\t<Text> </Text>\n\t\t\t) : (\n\t\t\t\t<Hints width={width} hints={[...(counters.errors ? [{ key: 'e', label: 'last error', priority: Infinity }] : []), ...PANEL_HINTS]} />\n\t\t\t)\n\t\t}\n\t];\n\tlet shown = blocks;\n\tconst budget = Math.max(2, Math.min(height, 14));\n\tfor (const name of ['space', 'summary', 'urls', 'wordmark']) {\n\t\tif (shown.length <= budget) break;\n\t\tshown = shown.filter((block) => block.name !== name);\n\t}\n\tshown = shown.filter((block, i, all) => block.name !== 'space' || (i > 0 && i < all.length - 1 && all[i - 1]?.name !== 'space'));\n\treturn (\n\t\t<Box flexDirection=\"column\">\n\t\t\t{shown.map((block, index) => (\n\t\t\t\t<Box key={index} flexDirection=\"column\" height={1}>\n\t\t\t\t\t{block.content}\n\t\t\t\t</Box>\n\t\t\t))}\n\t\t</Box>\n\t);\n}\n\nfunction plural(count: number, word: string): string {\n\treturn count === 1 ? word : `${word}s`;\n}\n","import { useEffect, useState } from 'react';\nimport type { DevService, DevStatus } from '../../../dev-service.js';\nimport { isErrorDetail, type LogEntry } from '../../../../utils/log-buffer.js';\n\nexport interface LogCounters {\n\twarnings: number;\n\terrors: number;\n}\n\n/**\n * Warnings and errors logged since the last successful build, the way Nuxt CLI v4's own panel counts them: the\n * badge's job is the current state, this line is what happened getting there.\n */\nexport function useLogCounters(service: DevService): LogCounters {\n\tconst count = () =>\n\t\tservice.logs.entries().reduce<LogCounters>(\n\t\t\t(total, entry) => ({\n\t\t\t\twarnings: total.warnings + Number(entry.level === 'warn'),\n\t\t\t\terrors: total.errors + Number(entry.level === 'error' && !isErrorDetail(entry))\n\t\t\t}),\n\t\t\t{ warnings: 0, errors: 0 }\n\t\t);\n\tconst [counters, setCounters] = useState<LogCounters>(count);\n\n\tuseEffect(() => {\n\t\tlet previousBuild: DevStatus['build'] = service.status.build;\n\t\tlet previousStart = service.status.startedAt;\n\n\t\tconst onEntry = (entry: LogEntry) => {\n\t\t\tif (entry.level === 'warn') setCounters((current) => ({ ...current, warnings: current.warnings + 1 }));\n\t\t\telse if (entry.level === 'error' && !isErrorDetail(entry)) setCounters((current) => ({ ...current, errors: current.errors + 1 }));\n\t\t};\n\n\t\tconst onStatus = (status: DevStatus) => {\n\t\t\tif (\n\t\t\t\t(status.build === 'building' && previousBuild !== 'building' && previousBuild !== 'idle') ||\n\t\t\t\t(status.lastRestartReason === 'manual' && status.startedAt !== null && status.startedAt !== previousStart)\n\t\t\t)\n\t\t\t\tsetCounters({ warnings: 0, errors: 0 });\n\t\t\tpreviousBuild = status.build;\n\t\t\tpreviousStart = status.startedAt;\n\t\t};\n\n\t\tservice.logs.on('entry', onEntry);\n\t\tconst onClear = () => setCounters({ warnings: 0, errors: 0 });\n\t\tservice.logs.on('clear', onClear);\n\t\tservice.on('status', onStatus);\n\t\tsetCounters(count());\n\t\treturn () => {\n\t\t\tservice.logs.off('entry', onEntry);\n\t\t\tservice.logs.off('clear', onClear);\n\t\t\tservice.off('status', onStatus);\n\t\t};\n\t}, [service]);\n\n\treturn counters;\n}\n","import { useEffect, useState } from 'react';\n\n/** The clock moves during a long compiler phase; the percentage only moves on real build events. */\nexport function useBuildClock(startedAt: number, active: boolean, reducedMotion: boolean) {\n\tconst [now, setNow] = useState(Date.now);\n\tuseEffect(() => {\n\t\tif (!active) return;\n\t\tsetNow(Date.now());\n\t\tconst timer = setInterval(() => setNow(Date.now()), reducedMotion ? 1000 : 120);\n\t\treturn () => clearInterval(timer);\n\t}, [startedAt, active, reducedMotion]);\n\tconst elapsedMs = Math.max(0, now - startedAt);\n\treturn { elapsedMs, frame: reducedMotion ? 0 : Math.floor(elapsedMs / 120) };\n}\n","import { execFile } from 'node:child_process';\n\n/** Called only on an explicit `o` keypress, with no shell interpolation. */\nexport function openDevUrl(value: string | null): Promise<void> {\n\tif (!value) return Promise.resolve();\n\tconst url = new URL(value);\n\tif (url.protocol !== 'http:' && url.protocol !== 'https:') return Promise.reject(new Error('Only HTTP(S) URLs can be opened.'));\n\tconst [command, args] =\n\t\tprocess.platform === 'win32'\n\t\t\t? (['rundll32', ['url.dll,FileProtocolHandler', url.href]] as const)\n\t\t\t: process.platform === 'darwin'\n\t\t\t\t? (['open', [url.href]] as const)\n\t\t\t\t: (['xdg-open', [url.href]] as const);\n\treturn new Promise((resolve, reject) =>\n\t\texecFile(command, [...args], (error) => (error ? reject(new Error(`Could not open the browser: ${error.message}`)) : resolve()))\n\t);\n}\n","import { Box, Text, useInput } from 'ink';\nimport { useState } from 'react';\nimport { THEME_SETTINGS, THEMES, detectTerminalBackground, type ThemeSetting } from '../../../../utils/theme.js';\nimport { useColorEnabled } from '../theme.js';\n\nconst DESCRIPTIONS: Record<ThemeSetting, string> = {\n\tauto: 'match the terminal background',\n\tdark: 'for dark terminals',\n\tlight: 'for light terminals',\n\t'dark-daltonized': 'dark, colour-blind friendly (blue/orange)',\n\t'light-daltonized': 'light, colour-blind friendly (blue/orange)',\n\t'dark-ansi': 'dark, only your terminal palette',\n\t'light-ansi': 'light, only your terminal palette'\n};\n\nexport interface ThemeOverlayProps {\n\t/** The theme setting in effect when the picker opened. */\n\tcurrent: ThemeSetting;\n\theight: number;\n\twidth: number;\n\t/** Called while moving through the list, so the whole UI previews the highlighted theme. */\n\tonPreview: (setting: ThemeSetting) => void;\n\tonSelect: (setting: ThemeSetting) => void;\n\t/** Closes without saving; the caller restores the theme that was in effect. */\n\tonClose: () => void;\n}\n\n/** Like Claude Code's `/theme`: arrows preview live, `Enter` keeps the choice and saves it, `Esc` restores. */\nexport function ThemeOverlay({ current, height, width, onPreview, onSelect, onClose }: ThemeOverlayProps) {\n\tconst color = useColorEnabled();\n\tconst [index, setIndex] = useState(Math.max(0, THEME_SETTINGS.indexOf(current)));\n\n\tconst move = (delta: number) => {\n\t\tconst next = (index + delta + THEME_SETTINGS.length) % THEME_SETTINGS.length;\n\t\tsetIndex(next);\n\t\tonPreview(THEME_SETTINGS[next]!);\n\t};\n\n\tuseInput((input, key) => {\n\t\tif (key.ctrl) return;\n\t\tif (key.escape || input === 'q' || input === 'T') return onClose();\n\t\tif (key.return) return onSelect(THEME_SETTINGS[index]!);\n\t\tif (key.upArrow || input === 'k') return move(-1);\n\t\tif (key.downArrow || input === 'j') return move(1);\n\t});\n\n\treturn (\n\t\t<Box flexDirection=\"column\" height={height}>\n\t\t\t<Text bold> colour theme</Text>\n\t\t\t<Text dimColor>{'─'.repeat(width)}</Text>\n\t\t\t{THEME_SETTINGS.slice(0, Math.max(0, height - 3)).map((setting, i) => {\n\t\t\t\tconst swatch = THEMES[setting === 'auto' ? detectTerminalBackground() : setting];\n\t\t\t\treturn (\n\t\t\t\t\t<Text key={setting} wrap=\"truncate-end\">\n\t\t\t\t\t\t{i === index ? ' ▎ ' : ' '}\n\t\t\t\t\t\t<Text bold={i === index}>{setting.padEnd(18)}</Text>\n\t\t\t\t\t\t{color && (\n\t\t\t\t\t\t\t<Text>\n\t\t\t\t\t\t\t\t<Text color={swatch.success}>● </Text>\n\t\t\t\t\t\t\t\t<Text color={swatch.warning}>● </Text>\n\t\t\t\t\t\t\t\t<Text color={swatch.error}>● </Text>\n\t\t\t\t\t\t\t\t<Text color={swatch.url}>● </Text>\n\t\t\t\t\t\t\t</Text>\n\t\t\t\t\t\t)}\n\t\t\t\t\t\t<Text dimColor>{` ${DESCRIPTIONS[setting]}${setting === current ? ' (current)' : ''}`}</Text>\n\t\t\t\t\t</Text>\n\t\t\t\t);\n\t\t\t})}\n\t\t\t<Box flexGrow={1} />\n\t\t\t<Text dimColor> ↑/↓ preview · enter save · esc cancel</Text>\n\t\t</Box>\n\t);\n}\n","import { Box, useInput, useWindowSize } from 'ink';\nimport { useState } from 'react';\nimport type { DevService } from '../../dev-service.js';\nimport { HelpOverlay } from './components/HelpOverlay.js';\nimport { LogBrowser } from './components/LogBrowser.js';\nimport { InfoOverlay } from './components/InfoOverlay.js';\nimport { Panel } from './components/Panel.js';\nimport { useDevStatus } from './hooks/useDevStatus.js';\nimport { useLogCounters } from './hooks/useLogCounters.js';\nimport { useBuildClock } from './hooks/useBuildClock.js';\nimport { describeBadge } from '../panel-logic.js';\nimport { openDevUrl } from '../../open-url.js';\nimport { ThemeProvider } from './theme.js';\nimport { ThemeOverlay } from './components/ThemeOverlay.js';\nimport { resolveTheme, type ThemeSetting } from '../../../utils/theme.js';\n\nexport interface DevAppProps {\n\tservice: DevService;\n\tcolor: boolean;\n\t/** The theme setting to start with; `auto` follows the terminal background. */\n\ttheme: ThemeSetting;\n\treducedMotion: boolean;\n\t/** Called when the user asks to quit, so the CLI can stop the bot and exit. */\n\tonQuit: () => void;\n\tonViewChange: (overlay: boolean) => void;\n\tonCopy: (text: string) => void;\n\t/** Called when the user keeps a theme in the picker, so the CLI can remember it. */\n\tonThemeSave: (setting: ThemeSetting) => void;\n}\n\ntype View = 'panel' | 'logs' | 'errors' | 'help' | 'info' | 'theme';\n\n/**\n * A bottom-aligned panel in the normal buffer, with logs folded away. Only the browsable overlays use the\n * alternate screen, preserving the terminal's history and the panel when they close.\n */\nexport function DevApp({ service, color, theme, reducedMotion, onQuit, onViewChange, onCopy, onThemeSave }: DevAppProps) {\n\tconst { columns, rows } = useWindowSize();\n\tconst [view, setView] = useState<View>('panel');\n\tconst [confirmQuit, setConfirmQuit] = useState(false);\n\t// `saved` is what Esc restores after previewing other themes in the picker.\n\tconst [saved, setSaved] = useState(theme);\n\tconst [preview, setPreview] = useState(theme);\n\n\tconst status = useDevStatus(service);\n\tconst counters = useLogCounters(service);\n\tconst badge = describeBadge(status).badge;\n\tconst busy = badge !== 'ready' && badge !== 'error';\n\tconst clock = useBuildClock(status.progress.startedAt, busy && view === 'panel', reducedMotion);\n\n\tconst width = Math.max(1, columns);\n\tconst height = Math.max(2, rows - 1);\n\n\tconst changeView = (next: View) => {\n\t\tonViewChange(next !== 'panel');\n\t\tsetView(next);\n\t};\n\n\tuseInput((input, key) => {\n\t\tif (key.ctrl && input === 'c') return onQuit();\n\t\tif (key.ctrl && input === 'l') return service.clearLogs();\n\t\tif (view !== 'panel') return;\n\t\tif (confirmQuit) {\n\t\t\tif (input === 'y') return onQuit();\n\t\t\treturn setConfirmQuit(false);\n\t\t}\n\t\tif (key.ctrl && input === 'r') return void service.restart('manual');\n\t\tif (key.ctrl && input === 'd') return busy ? setConfirmQuit(true) : onQuit();\n\n\t\tswitch (input) {\n\t\t\tcase 'q':\n\t\t\t\treturn busy ? setConfirmQuit(true) : onQuit();\n\t\t\tcase 'r':\n\t\t\t\treturn void service.restart('manual');\n\t\t\tcase 'l':\n\t\t\t\treturn changeView('logs');\n\t\t\tcase 'e':\n\t\t\t\treturn changeView('errors');\n\t\t\tcase 'c':\n\t\t\t\treturn service.clearLogs();\n\t\t\tcase 'o':\n\t\t\t\treturn void openDevUrl(status.url).catch((error: Error) => service.log('stars', 'warn', error.message));\n\t\t\tcase 't':\n\t\t\t\treturn void service.toggleTunnel();\n\t\t\tcase 'i':\n\t\t\t\treturn changeView('info');\n\t\t\tcase 'T':\n\t\t\t\treturn changeView('theme');\n\t\t\tcase 'h':\n\t\t\tcase '?':\n\t\t\t\treturn changeView('help');\n\t\t\tdefault:\n\t\t\t\tbreak;\n\t\t}\n\t});\n\n\treturn (\n\t\t<ThemeProvider color={color} theme={resolveTheme(preview)}>\n\t\t\t<Box width={width} height={height} flexDirection=\"column\" justifyContent={view === 'panel' ? 'flex-end' : 'flex-start'}>\n\t\t\t\t{(view === 'logs' || view === 'errors') && (\n\t\t\t\t\t<LogBrowser\n\t\t\t\t\t\tservice={service}\n\t\t\t\t\t\theight={height}\n\t\t\t\t\t\twidth={width}\n\t\t\t\t\t\tlastError={view === 'errors'}\n\t\t\t\t\t\tonCopy={onCopy}\n\t\t\t\t\t\tonClose={() => changeView('panel')}\n\t\t\t\t\t/>\n\t\t\t\t)}\n\t\t\t\t{view === 'help' && <HelpOverlay height={height} width={width} onClose={() => changeView('panel')} />}\n\t\t\t\t{view === 'info' && <InfoOverlay service={service} height={height} width={width} onClose={() => changeView('panel')} />}\n\t\t\t\t{view === 'theme' && (\n\t\t\t\t\t<ThemeOverlay\n\t\t\t\t\t\tcurrent={saved}\n\t\t\t\t\t\theight={height}\n\t\t\t\t\t\twidth={width}\n\t\t\t\t\t\tonPreview={setPreview}\n\t\t\t\t\t\tonSelect={(setting) => {\n\t\t\t\t\t\t\tsetSaved(setting);\n\t\t\t\t\t\t\tsetPreview(setting);\n\t\t\t\t\t\t\tonThemeSave(setting);\n\t\t\t\t\t\t\tchangeView('panel');\n\t\t\t\t\t\t}}\n\t\t\t\t\t\tonClose={() => {\n\t\t\t\t\t\t\tsetPreview(saved);\n\t\t\t\t\t\t\tchangeView('panel');\n\t\t\t\t\t\t}}\n\t\t\t\t\t/>\n\t\t\t\t)}\n\t\t\t\t{view === 'panel' && (\n\t\t\t\t\t<Panel\n\t\t\t\t\t\tstatus={status}\n\t\t\t\t\t\tconfig={service.config}\n\t\t\t\t\t\tcounters={counters}\n\t\t\t\t\t\t{...clock}\n\t\t\t\t\t\twidth={width}\n\t\t\t\t\t\theight={height}\n\t\t\t\t\t\tconfirmQuit={confirmQuit}\n\t\t\t\t\t/>\n\t\t\t\t)}\n\t\t\t</Box>\n\t\t</ThemeProvider>\n\t);\n}\n","import { StringDecoder } from 'node:string_decoder';\nimport type { DevService } from '../dev-service.js';\nimport { classifyAppLine, type LogLevel } from '../../utils/log-buffer.js';\n\n/** Capture third-party writes before build plugins run. Ink writes through a separate, unpatched sink. */\nexport function captureOutput(service: DevService, stream: NodeJS.WriteStream, fallback: LogLevel): () => void {\n\tconst original = stream.write;\n\tconst decoder = new StringDecoder('utf8');\n\tlet pending = '';\n\tconst emit = (text: string) => {\n\t\tif (text.trim()) service.log('build', classifyAppLine(text, fallback), text);\n\t};\n\tconst write: typeof stream.write = (chunk: unknown, encoding?: unknown, callback?: unknown) => {\n\t\tpending += typeof chunk === 'string' ? chunk : chunk instanceof Uint8Array ? decoder.write(Buffer.from(chunk)) : String(chunk);\n\t\tconst lines = pending.split(/\\r?\\n/);\n\t\tpending = lines.pop() ?? '';\n\t\tfor (const line of lines) emit(line);\n\t\t// A tool without newlines must not grow the capture indefinitely.\n\t\tif (pending.length > 65536) {\n\t\t\temit(pending);\n\t\t\tpending = '';\n\t\t}\n\t\tconst done = typeof encoding === 'function' ? encoding : callback;\n\t\tif (typeof done === 'function') queueMicrotask(() => done());\n\t\treturn true;\n\t};\n\tstream.write = write;\n\treturn () => {\n\t\tif (stream.write === write) stream.write = original;\n\t\temit(pending + decoder.end());\n\t\tpending = '';\n\t};\n}\n","import { render } from 'ink';\nimport type { DevService } from '../dev-service.js';\nimport { DevApp } from './ink/DevApp.js';\nimport type { Renderer } from './plain.js';\nimport { captureOutput } from './capture-output.js';\nimport { isErrorDetail } from '../../utils/log-buffer.js';\nimport type { ThemeSetting } from '../../utils/theme.js';\n\nexport interface TuiRendererOptions {\n\tstdout?: NodeJS.WriteStream;\n\tstdin?: NodeJS.ReadStream;\n\tcolor?: boolean;\n\t/** Defaults to `auto`. */\n\ttheme?: ThemeSetting;\n\t/** Called when the user keeps a theme in the picker. */\n\tonThemeSave?: (setting: ThemeSetting) => void;\n\t/** Freezes spinners, for `STARS_REDUCED_MOTION=1`. */\n\treducedMotion?: boolean;\n\t/** Caps how often Ink repaints; the default is Ink's own. */\n\tfps?: number;\n}\n\n/**\n * A normal-buffer, bottom-aligned panel and alternate-buffer overlays. External output is captured for the log\n * browser; the renderer alone writes to the terminal. Switching views and teardown restore the original buffer.\n *\n * `start()` resolves when the user quits, which is what `stars dev` waits on before shutting the bot down.\n */\nexport function createTuiRenderer(service: DevService, options: TuiRendererOptions = {}): Renderer {\n\tconst stdout = options.stdout ?? process.stdout;\n\tconst stdin = options.stdin ?? process.stdin;\n\tconst write = stdout.write.bind(stdout);\n\t// Bind methods to the real stream (resize subscriptions included), except write which bypasses capture.\n\tconst sink = new Proxy(stdout, {\n\t\tget(target, property) {\n\t\t\tif (property === 'write') return write;\n\t\t\tconst value = Reflect.get(target, property, target);\n\t\t\treturn typeof value === 'function' ? value.bind(target) : value;\n\t\t}\n\t});\n\tconst restoreOutput =\n\t\tstdout === process.stdout ? [captureOutput(service, process.stdout, 'info'), captureOutput(service, process.stderr, 'warn')] : [];\n\tlet alternate = false;\n\tlet stopped = false;\n\tconst switchView = (overlay: boolean) => {\n\t\tif (overlay === alternate || stopped) return;\n\t\tinstance.clear();\n\t\twrite(overlay ? '\\u001B[?1049h\\u001B[H' : '\\u001B[?1049l');\n\t\talternate = overlay;\n\t};\n\n\tlet quit!: () => void;\n\tconst quitting = new Promise<void>((resolve) => {\n\t\tquit = resolve;\n\t});\n\n\tconst instance = render(\n\t\t<DevApp\n\t\t\tservice={service}\n\t\t\tcolor={options.color ?? false}\n\t\t\ttheme={options.theme ?? 'auto'}\n\t\t\tonThemeSave={options.onThemeSave ?? (() => {})}\n\t\t\treducedMotion={options.reducedMotion ?? false}\n\t\t\tonQuit={quit}\n\t\t\tonViewChange={switchView}\n\t\t\tonCopy={(text) => write(`\\u001B]52;c;${Buffer.from(text.slice(0, 65536)).toString('base64')}\\u0007`)}\n\t\t/>,\n\t\t{\n\t\t\tstdout: sink,\n\t\t\tstdin,\n\t\t\t// `stars dev` owns the shutdown: it stops the bot, then exits with the right code.\n\t\t\texitOnCtrlC: false,\n\t\t\tpatchConsole: false,\n\t\t\t// `createTuiRenderer` only runs once `resolveOutputMode()` already picked 'tui' (never in CI or on a\n\t\t\t// non-TTY stdout), so Ink is told to trust that instead of re-deriving it from `process.env.CI`: on a\n\t\t\t// CI runner that env var is set even for this package's own test process, which would otherwise force\n\t\t\t// Ink's non-interactive mode (no repaint until unmount) despite the fake stdin/stdout looking like a\n\t\t\t// real TTY.\n\t\t\tinteractive: true,\n\t\t\t...(options.fps === undefined ? {} : { maxFps: options.fps })\n\t\t}\n\t);\n\n\treturn {\n\t\tasync start() {\n\t\t\tawait Promise.race([quitting, instance.waitUntilExit()]);\n\t\t},\n\t\tstop() {\n\t\t\tif (stopped) return;\n\t\t\tstopped = true;\n\t\t\tif (alternate) instance.clear();\n\t\t\tinstance.unmount();\n\t\t\tif (alternate) write('\\u001B[?1049l');\n\t\t\twrite('\\u001B[?25h');\n\t\t\tfor (const restore of restoreOutput) restore();\n\t\t\t// A fatal startup must not leave the user with only a folded error and no way to read it.\n\t\t\tif (service.status.progress.readyMs === null) {\n\t\t\t\tconst error = service.logs.entries().findLast((entry) => entry.level === 'error' && !isErrorDetail(entry));\n\t\t\t\tif (error) write(`\\n${error.text}\\n`);\n\t\t\t}\n\t\t\tquit();\n\t\t}\n\t};\n}\n\nexport { formatDuration } from './panel-logic.js';\n"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { readProjectEnvFiles } from "@wolfstar/
|
|
1
|
+
import { readProjectEnvFiles } from "@wolfstar/schema";
|
|
2
2
|
import { EventEmitter } from "node:events";
|
|
3
3
|
import { startTunnel } from "untun";
|
|
4
4
|
|
|
@@ -170,4 +170,4 @@ function readProjectEnvFilesCached(root) {
|
|
|
170
170
|
|
|
171
171
|
//#endregion
|
|
172
172
|
export { readDiscordCredentials as n, Tunnel as t };
|
|
173
|
-
//# sourceMappingURL=tunnel-
|
|
173
|
+
//# sourceMappingURL=tunnel-DiL0Wxi_.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tunnel-DiL0Wxi_.js","names":[],"sources":["../src/dev/tunnel.ts"],"sourcesContent":["import { readProjectEnvFiles, type ResolvedStarsConfig, type ResolvedTunnelConfig } from '@wolfstar/schema';\nimport { EventEmitter } from 'node:events';\nimport { startTunnel, type Tunnel as UntunTunnel } from 'untun';\nimport type { LogLevel } from '../utils/log-buffer.js';\n\nexport type TunnelState = 'off' | 'starting' | 'up' | 'failed';\n\nexport interface TunnelEvents {\n\tlog: [level: LogLevel, text: string];\n\tstate: [state: TunnelState, url: string | null];\n}\n\nexport interface TunnelOptions {\n\t/** Override for tests. */\n\tstartTunnel?: typeof startTunnel;\n}\n\n/**\n * Exposes the bot's interactions endpoint publicly while `stars dev` runs.\n *\n * `dev.tunnel: true` opens a `cloudflared` quick tunnel via `untun` (it changes on every run); a configured https\n * URL is only probed, since the user already serves it. Writing the URL to the Discord application is opt-in\n * through `dev.tunnel.updateEndpoint`, because it edits a live application.\n */\nexport class Tunnel extends EventEmitter<TunnelEvents> {\n\t#startTunnel: typeof startTunnel;\n\t#tunnel: UntunTunnel | null = null;\n\t#state: TunnelState = 'off';\n\t#url: string | null = null;\n\t#wanted = false;\n\n\tpublic constructor(\n\t\tprivate readonly config: ResolvedStarsConfig,\n\t\toptions: TunnelOptions = {}\n\t) {\n\t\tsuper();\n\t\tthis.#startTunnel = options.startTunnel ?? startTunnel;\n\t}\n\n\tpublic get state(): TunnelState {\n\t\treturn this.#state;\n\t}\n\n\t/** The public URL of the interactions endpoint, `null` until the tunnel is up. */\n\tpublic get url(): string | null {\n\t\treturn this.#url;\n\t}\n\n\tpublic async start(forceQuick = false): Promise<void> {\n\t\tif (this.#state === 'starting' || this.#state === 'up') return;\n\t\tconst configured = this.config.dev.tunnel;\n\t\tconst tunnel: ResolvedTunnelConfig =\n\t\t\tforceQuick && configured.mode === 'off' ? { mode: 'quick', path: '/', updateEndpoint: false } : configured;\n\t\tif (tunnel.mode === 'off') return;\n\n\t\tthis.#wanted = true;\n\t\tthis.#setState('starting', null);\n\t\tconst url = tunnel.mode === 'url' ? await this.#useConfiguredUrl(tunnel) : await this.#openQuickTunnel();\n\t\tif (!url || !this.#wanted) return;\n\n\t\tthis.#setState('up', endpointUrl(url, tunnel.path));\n\t\tthis.emit('log', 'success', `Tunnel ready at ${this.#url}`);\n\t\tif (tunnel.updateEndpoint) await this.#updateInteractionsEndpoint(this.#url!);\n\t}\n\n\t/** Toggles the configured tunnel, opening a quick tunnel when the project did not configure one. */\n\tpublic toggle(): Promise<void> {\n\t\treturn this.#state === 'starting' || this.#state === 'up' ? this.close() : this.start(true);\n\t}\n\n\tpublic async close(): Promise<void> {\n\t\tthis.#wanted = false;\n\t\tconst tunnel = this.#tunnel;\n\t\tthis.#tunnel = null;\n\t\tthis.#setState('off', null);\n\t\tif (tunnel) await tunnel.close();\n\t}\n\n\tasync #useConfiguredUrl(tunnel: Extract<ResolvedTunnelConfig, { mode: 'url' }>): Promise<string | null> {\n\t\tconst reachable = await probe(endpointUrl(tunnel.url, tunnel.path));\n\t\tif (!reachable) {\n\t\t\tthis.emit('log', 'warn', `${tunnel.url} did not answer; make sure it forwards to ${this.config.dev.url ?? 'the bot'}`);\n\t\t}\n\n\t\treturn tunnel.url;\n\t}\n\n\tasync #openQuickTunnel(): Promise<string | null> {\n\t\tconst target = this.config.dev.url;\n\t\tif (!target) {\n\t\t\tthis.emit('log', 'error', 'A quick tunnel needs `dev.url` to know what to forward to');\n\t\t\tthis.#setState('failed', null);\n\t\t\treturn null;\n\t\t}\n\n\t\tthis.emit('log', 'info', 'Opening a cloudflared quick tunnel…');\n\n\t\ttry {\n\t\t\tconst tunnel = await this.#startTunnel({ url: target, acceptCloudflareNotice: true });\n\t\t\tif (!this.#wanted) {\n\t\t\t\tawait tunnel?.close();\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tif (!tunnel) {\n\t\t\t\tthis.emit('log', 'error', 'cloudflared setup was cancelled');\n\t\t\t\tthis.#setState('failed', null);\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tthis.#tunnel = tunnel;\n\t\t\treturn await tunnel.getURL();\n\t\t} catch (error) {\n\t\t\tthis.emit('log', 'error', `cloudflared failed: ${error instanceof Error ? error.message : String(error)}`);\n\t\t\tthis.#setState('failed', null);\n\t\t\treturn null;\n\t\t}\n\t}\n\n\t/**\n\t * Points the Discord application's interactions endpoint at the tunnel. Discord validates the endpoint with a\n\t * signed ping before accepting it, so the bot has to be up already — this runs after the first successful build.\n\t */\n\tasync #updateInteractionsEndpoint(url: string): Promise<void> {\n\t\tconst credentials = readDiscordCredentials(this.config);\n\t\tif (!credentials) {\n\t\t\tthis.emit('log', 'warn', 'Skipped the interactions endpoint update: DISCORD_TOKEN is not set');\n\t\t\treturn;\n\t\t}\n\n\t\ttry {\n\t\t\tconst response = await fetch('https://discord.com/api/v10/applications/@me', {\n\t\t\t\tmethod: 'PATCH',\n\t\t\t\theaders: { authorization: `Bot ${credentials.token}`, 'content-type': 'application/json' },\n\t\t\t\tbody: JSON.stringify({ interactions_endpoint_url: url }),\n\t\t\t\tsignal: AbortSignal.timeout(10_000)\n\t\t\t});\n\n\t\t\tif (response.ok) this.emit('log', 'success', `Interactions endpoint set to ${url}`);\n\t\t\telse\n\t\t\t\tthis.emit(\n\t\t\t\t\t'log',\n\t\t\t\t\t'error',\n\t\t\t\t\t`Discord rejected the interactions endpoint (${response.status}): ${(await response.text()).slice(0, 300)}`\n\t\t\t\t);\n\t\t} catch (error) {\n\t\t\tthis.emit('log', 'error', `Failed to update the interactions endpoint: ${error instanceof Error ? error.message : String(error)}`);\n\t\t}\n\t}\n\n\t#setState(state: TunnelState, url: string | null): void {\n\t\tthis.#state = state;\n\t\tthis.#url = url;\n\t\tthis.emit('state', state, url);\n\t}\n}\n\n/**\n * Joins the tunnel's origin with the path the interactions endpoint is served on.\n */\nexport function endpointUrl(origin: string, path: string): string {\n\treturn path === '/' ? origin : new URL(path, origin.endsWith('/') ? origin : `${origin}/`).href;\n}\n\nasync function probe(url: string): Promise<boolean> {\n\ttry {\n\t\tconst response = await fetch(url, { method: 'HEAD', signal: AbortSignal.timeout(5000) });\n\t\treturn response.status < 500;\n\t} catch {\n\t\treturn false;\n\t}\n}\n\nexport interface DiscordCredentials {\n\ttoken: string;\n\tapplicationId: string | null;\n}\n\n/**\n * Reads the Discord credentials the CLI needs from the environment, falling back to the project's `.env` files the\n * way the bot itself does once it starts.\n */\nexport function readDiscordCredentials(config: ResolvedStarsConfig, env: NodeJS.ProcessEnv = process.env): DiscordCredentials | null {\n\tconst fromFiles = readProjectEnvFilesCached(config.root);\n\tconst read = (...keys: string[]): string | null => {\n\t\tfor (const key of keys) {\n\t\t\tconst value = config.dev.env[key] ?? env[key] ?? fromFiles[key];\n\t\t\tif (value) return value;\n\t\t}\n\t\treturn null;\n\t};\n\n\tconst token = read('DISCORD_TOKEN', 'TOKEN');\n\tif (!token) return null;\n\n\treturn { token, applicationId: read('DISCORD_APPLICATION_ID', 'APPLICATION_ID', 'DISCORD_CLIENT_ID', 'CLIENT_ID') };\n}\n\nlet envFileCache: { root: string; values: Record<string, string> } | null = null;\n\nfunction readProjectEnvFilesCached(root: string): Record<string, string> {\n\tif (envFileCache?.root !== root) envFileCache = { root, values: readProjectEnvFiles(root, 'development') };\n\treturn envFileCache.values;\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { t as pluginRegistrations } from "./plugin-registrations-Dr_BicfC.js";
|
|
2
|
+
import { n as importFromProject } from "./project-MD4dIo2X.js";
|
|
3
|
+
import { ViteBuilder as ViteBuilder$1 } from "@wolfstar/vite-server";
|
|
4
|
+
|
|
5
|
+
//#region src/builders/vite.ts
|
|
6
|
+
/** Connect the server integration to the CLI's diagnostics and plugin discovery. */
|
|
7
|
+
var ViteBuilder = class extends ViteBuilder$1 {
|
|
8
|
+
constructor(config) {
|
|
9
|
+
super(config, {
|
|
10
|
+
importFromProject,
|
|
11
|
+
pluginRegistrations
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
//#endregion
|
|
17
|
+
export { ViteBuilder };
|
|
18
|
+
//# sourceMappingURL=vite-CLyB6wl7.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vite-CLyB6wl7.js","names":["ServerBuilder"],"sources":["../src/builders/vite.ts"],"sourcesContent":["import { ViteBuilder as ServerBuilder } from '@wolfstar/vite-server';\nimport type { ResolvedStarsConfig } from '@wolfstar/schema';\nimport { pluginRegistrations } from '../utils/plugin-registrations.js';\nimport { importFromProject } from '../utils/project.js';\n\n/** Connect the server integration to the CLI's diagnostics and plugin discovery. */\nexport class ViteBuilder extends ServerBuilder {\n\tpublic constructor(config: ResolvedStarsConfig) {\n\t\tsuper(config, { importFromProject, pluginRegistrations });\n\t}\n}\n"],"mappings":";;;;;;AAMA,IAAa,cAAb,cAAiCA,cAAc;CAC9C,AAAO,YAAY,QAA6B;EAC/C,MAAM,QAAQ;GAAE;GAAmB;EAAoB,CAAC;CACzD;AACD"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wolfstar/cli",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.1",
|
|
4
4
|
"description": "The stars command line interface for @wolfstar/http-framework projects: typed configuration, dev server, build and project info",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"api",
|
|
@@ -42,6 +42,11 @@
|
|
|
42
42
|
"default": "./dist/index.js"
|
|
43
43
|
}
|
|
44
44
|
},
|
|
45
|
+
"./cli": {
|
|
46
|
+
"import": {
|
|
47
|
+
"default": "./dist/cli.js"
|
|
48
|
+
}
|
|
49
|
+
},
|
|
45
50
|
"./package.json": "./package.json"
|
|
46
51
|
},
|
|
47
52
|
"publishConfig": {
|
|
@@ -49,13 +54,16 @@
|
|
|
49
54
|
"provenance": true
|
|
50
55
|
},
|
|
51
56
|
"dependencies": {
|
|
52
|
-
"@clack/prompts": "^1.8.
|
|
57
|
+
"@clack/prompts": "^1.8.1",
|
|
53
58
|
"@sapphire/ts-config": "^5.0.3",
|
|
54
|
-
"@wolfstar/
|
|
59
|
+
"@wolfstar/nitro-server": "^0.2.1",
|
|
60
|
+
"@wolfstar/schema": "^0.2.0",
|
|
61
|
+
"@wolfstar/vite-server": "^0.2.1",
|
|
55
62
|
"chokidar": "^5.0.0",
|
|
56
63
|
"citty": "^0.2.2",
|
|
57
64
|
"colorette": "^2.0.20",
|
|
58
65
|
"ink": "^7.1.1",
|
|
66
|
+
"mlly": "^1.8.2",
|
|
59
67
|
"my-bad": "^0.2.2",
|
|
60
68
|
"nostics": "^1.2.0",
|
|
61
69
|
"react": "^19.3.0",
|
|
@@ -69,7 +77,7 @@
|
|
|
69
77
|
"nitro": "^3.0.260903-beta",
|
|
70
78
|
"tsdown": "^0.23.0",
|
|
71
79
|
"typescript": "~7.0.2",
|
|
72
|
-
"vite": "^8.
|
|
80
|
+
"vite": "^8.3.0",
|
|
73
81
|
"vitest": "^4.1.11"
|
|
74
82
|
},
|
|
75
83
|
"peerDependencies": {
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"_shared-dVR2pKjb.js","names":[],"sources":["../src/utils/tsconfig.ts","../src/commands/_shared.ts"],"sourcesContent":["import type { ResolvedStarsConfig } from '@wolfstar/http-framework/config';\nimport { createRequire } from 'node:module';\nimport { mkdir, readFile, writeFile } from 'node:fs/promises';\nimport { dirname, isAbsolute, join, relative, resolve } from 'node:path';\n\nconst require = createRequire(import.meta.url);\nconst sapphireOptions = Object.assign(\n\t{},\n\t...['@sapphire/ts-config', '@sapphire/ts-config/extra-strict', '@sapphire/ts-config/decorators'].map(\n\t\t(id) => (require(id) as { compilerOptions: Record<string, unknown> }).compilerOptions\n\t)\n) as Record<string, unknown>;\n\n/** Generates an extendable config without changing the project's own tsconfig. */\nexport async function prepareTsconfig(config: ResolvedStarsConfig, check = false) {\n\tconst path = join(config.root, '.stars', 'tsconfig.json');\n\tconst fromGenerated = (target: string) => `./${relative(dirname(path), target).replaceAll('\\\\', '/')}`;\n\tconst paths: Record<string, string[]> = {};\n\tif (config.build.tool === 'tsdown') {\n\t\tconst source = dirname(config.entry);\n\t\tconst defaults = config.build.configFile === null ? { '~': source, '@': source, '~~': config.root, '@@': config.root } : {};\n\t\tconst aliases = { ...defaults, ...(config.tsdown.alias as Record<string, unknown> | undefined) };\n\t\tfor (const [alias, target] of Object.entries(aliases)) {\n\t\t\t// Module redirects belong to the bundler; only filesystem targets become TypeScript paths.\n\t\t\tif (typeof target !== 'string' || (!isAbsolute(target) && !/^\\.\\.?[/\\\\]/.test(target))) continue;\n\t\t\tconst resolved = fromGenerated(resolve(config.root, target));\n\t\t\tpaths[alias] = [resolved];\n\t\t\tpaths[`${alias}/*`] = [`${resolved}/*`];\n\t\t}\n\t} else if (config.experimental.enableNitro) {\n\t\t// `NitroBuilder` turns on Vite's native `resolve.tsconfigPaths` (see https://nitro.build/examples/import-alias),\n\t\t// which reads these `paths` straight out of the generated tsconfig — no `tsdown.alias` equivalent to merge\n\t\t// with, `vite`/Nitro projects only have this file's own `compilerOptions.paths` to extend or replace.\n\t\tconst source = dirname(config.entry);\n\t\tconst defaults = { '~': source, '@': source, '~~': config.root, '@@': config.root };\n\t\tfor (const [alias, target] of Object.entries(defaults)) {\n\t\t\tconst resolved = fromGenerated(resolve(config.root, target));\n\t\t\tpaths[alias] = [resolved];\n\t\t\tpaths[`${alias}/*`] = [`${resolved}/*`];\n\t\t}\n\t}\n\tconst content = `${JSON.stringify(\n\t\t{\n\t\t\tcompilerOptions: {\n\t\t\t\t...sapphireOptions,\n\t\t\t\t// Bundlers emit the application; TypeScript only checks it. Keep Node16 emit for tsc.\n\t\t\t\t...(config.build.tool === 'tsdown' || config.build.tool === 'vite'\n\t\t\t\t\t? {\n\t\t\t\t\t\t\tmodule: 'ESNext',\n\t\t\t\t\t\t\tmoduleResolution: 'Bundler',\n\t\t\t\t\t\t\tmoduleDetection: 'force',\n\t\t\t\t\t\t\tisolatedModules: true,\n\t\t\t\t\t\t\tverbatimModuleSyntax: true,\n\t\t\t\t\t\t\tallowJs: true,\n\t\t\t\t\t\t\tallowImportingTsExtensions: true,\n\t\t\t\t\t\t\tresolvePackageJsonImports: true,\n\t\t\t\t\t\t\tlib: ['ESNext', 'DOM'],\n\t\t\t\t\t\t\tnoEmit: true\n\t\t\t\t\t\t}\n\t\t\t\t\t: {}),\n\t\t\t\ttarget: 'ES2022',\n\t\t\t\tforceConsistentCasingInFileNames: true,\n\t\t\t\tskipLibCheck: true,\n\t\t\t\ttsBuildInfoFile: './tsconfig.tsbuildinfo',\n\t\t\t\tpaths\n\t\t\t},\n\t\t\tinclude: [`${fromGenerated(dirname(config.entry))}/**/*`, ...(config.imports.enabled ? [fromGenerated(config.imports.dts)] : [])],\n\t\t\texclude: [fromGenerated(join(config.root, 'node_modules')), fromGenerated(config.build.outDir)]\n\t\t},\n\t\tnull,\n\t\t2\n\t)}\\n`;\n\tif (check) {\n\t\tconst existing = await readFile(path, 'utf-8').catch(() => null);\n\t\treturn { path, status: existing === content ? ('up-to-date' as const) : ('outdated' as const) };\n\t}\n\tawait mkdir(dirname(path), { recursive: true });\n\tawait writeFile(path, content);\n\treturn { path, status: 'written' as const };\n}\n","import { generateAutoImportsDts } from '@wolfstar/http-framework/auto-imports';\nimport type { ResolvedStarsConfig } from '@wolfstar/http-framework/config';\nimport { mkdir, readFile, writeFile } from 'node:fs/promises';\nimport { dirname } from 'node:path';\nimport { prepareTsconfig } from '../utils/tsconfig.js';\n\nexport type PrepareResult =\n\t| { enabled: false; dts: null; status: null }\n\t| { enabled: true; dts: string; status: 'written' | 'up-to-date' | 'outdated' };\n\n/**\n * Regenerates `imports.dts` unconditionally, used by `stars dev`/`stars build` before the first build so the\n * declaration file exists (and is current) even when the user never ran `stars prepare` themselves.\n */\nexport async function prepareAutoImports(config: ResolvedStarsConfig, check = false): Promise<PrepareResult> {\n\tif (!config.imports.enabled) return { enabled: false, dts: null, status: null };\n\n\tconst { dirs, presets, exclude, dts } = config.imports;\n\tconst content = await generateAutoImportsDts({ root: config.root, dirs, presets, exclude });\n\n\tif (check) {\n\t\tconst existing = await readFile(dts, 'utf-8').catch(() => null);\n\t\treturn { enabled: true, dts, status: existing === content ? 'up-to-date' : 'outdated' };\n\t}\n\n\tawait mkdir(dirname(dts), { recursive: true });\n\tawait writeFile(dts, content);\n\treturn { enabled: true, dts, status: 'written' };\n}\n\n/** Prepares TypeScript configuration and auto import declarations before building. */\nexport async function prepareProject(config: ResolvedStarsConfig, check = false) {\n\tconst tsconfig = await prepareTsconfig(config, check);\n\treturn { ...(await prepareAutoImports(config, check)), tsconfig };\n}\n"],"mappings":";;;;;;AAKA,MAAM,UAAU,cAAc,YAAY,GAAG;AAC7C,MAAM,kBAAkB,OAAO,OAC9B,CAAC,GACD,GAAG;CAAC;CAAuB;CAAoC;AAAgC,CAAC,CAAC,KAC/F,OAAQ,QAAQ,EAAE,CAAC,CAAkD,eACvE,CACD;;AAGA,eAAsB,gBAAgB,QAA6B,QAAQ,OAAO;CACjF,MAAM,OAAO,KAAK,OAAO,MAAM,UAAU,eAAe;CACxD,MAAM,iBAAiB,WAAmB,KAAK,SAAS,QAAQ,IAAI,GAAG,MAAM,CAAC,CAAC,WAAW,MAAM,GAAG;CACnG,MAAM,QAAkC,CAAC;CACzC,IAAI,OAAO,MAAM,SAAS,UAAU;EACnC,MAAM,SAAS,QAAQ,OAAO,KAAK;EAEnC,MAAM,UAAU;GAAE,GADD,OAAO,MAAM,eAAe,OAAO;IAAE,KAAK;IAAQ,KAAK;IAAQ,MAAM,OAAO;IAAM,MAAM,OAAO;GAAK,IAAI,CAAC;GAC3F,GAAI,OAAO,OAAO;EAA8C;EAC/F,KAAK,MAAM,CAAC,OAAO,WAAW,OAAO,QAAQ,OAAO,GAAG;GAEtD,IAAI,OAAO,WAAW,YAAa,CAAC,WAAW,MAAM,KAAK,CAAC,cAAc,KAAK,MAAM,GAAI;GACxF,MAAM,WAAW,cAAc,QAAQ,OAAO,MAAM,MAAM,CAAC;GAC3D,MAAM,SAAS,CAAC,QAAQ;GACxB,MAAM,GAAG,MAAM,OAAO,CAAC,GAAG,SAAS,GAAG;EACvC;CACD,OAAO,IAAI,OAAO,aAAa,aAAa;EAI3C,MAAM,SAAS,QAAQ,OAAO,KAAK;EACnC,MAAM,WAAW;GAAE,KAAK;GAAQ,KAAK;GAAQ,MAAM,OAAO;GAAM,MAAM,OAAO;EAAK;EAClF,KAAK,MAAM,CAAC,OAAO,WAAW,OAAO,QAAQ,QAAQ,GAAG;GACvD,MAAM,WAAW,cAAc,QAAQ,OAAO,MAAM,MAAM,CAAC;GAC3D,MAAM,SAAS,CAAC,QAAQ;GACxB,MAAM,GAAG,MAAM,OAAO,CAAC,GAAG,SAAS,GAAG;EACvC;CACD;CACA,MAAM,UAAU,GAAG,KAAK,UACvB;EACC,iBAAiB;GAChB,GAAG;GAEH,GAAI,OAAO,MAAM,SAAS,YAAY,OAAO,MAAM,SAAS,SACzD;IACA,QAAQ;IACR,kBAAkB;IAClB,iBAAiB;IACjB,iBAAiB;IACjB,sBAAsB;IACtB,SAAS;IACT,4BAA4B;IAC5B,2BAA2B;IAC3B,KAAK,CAAC,UAAU,KAAK;IACrB,QAAQ;GACT,IACC,CAAC;GACJ,QAAQ;GACR,kCAAkC;GAClC,cAAc;GACd,iBAAiB;GACjB;EACD;EACA,SAAS,CAAC,GAAG,cAAc,QAAQ,OAAO,KAAK,CAAC,EAAE,QAAQ,GAAI,OAAO,QAAQ,UAAU,CAAC,cAAc,OAAO,QAAQ,GAAG,CAAC,IAAI,CAAC,CAAE;EAChI,SAAS,CAAC,cAAc,KAAK,OAAO,MAAM,cAAc,CAAC,GAAG,cAAc,OAAO,MAAM,MAAM,CAAC;CAC/F,GACA,MACA,CACD,EAAE;CACF,IAAI,OAEH,OAAO;EAAE;EAAM,QAAQ,MADA,SAAS,MAAM,OAAO,CAAC,CAAC,YAAY,IAAI,MAC3B,UAAW,eAA0B;CAAqB;CAE/F,MAAM,MAAM,QAAQ,IAAI,GAAG,EAAE,WAAW,KAAK,CAAC;CAC9C,MAAM,UAAU,MAAM,OAAO;CAC7B,OAAO;EAAE;EAAM,QAAQ;CAAmB;AAC3C;;;;;;;;ACjEA,eAAsB,mBAAmB,QAA6B,QAAQ,OAA+B;CAC5G,IAAI,CAAC,OAAO,QAAQ,SAAS,OAAO;EAAE,SAAS;EAAO,KAAK;EAAM,QAAQ;CAAK;CAE9E,MAAM,EAAE,MAAM,SAAS,SAAS,QAAQ,OAAO;CAC/C,MAAM,UAAU,MAAM,uBAAuB;EAAE,MAAM,OAAO;EAAM;EAAM;EAAS;CAAQ,CAAC;CAE1F,IAAI,OAEH,OAAO;EAAE,SAAS;EAAM;EAAK,QAAQ,MADd,SAAS,KAAK,OAAO,CAAC,CAAC,YAAY,IAAI,MACZ,UAAU,eAAe;CAAW;CAGvF,MAAM,MAAM,QAAQ,GAAG,GAAG,EAAE,WAAW,KAAK,CAAC;CAC7C,MAAM,UAAU,KAAK,OAAO;CAC5B,OAAO;EAAE,SAAS;EAAM;EAAK,QAAQ;CAAU;AAChD;;AAGA,eAAsB,eAAe,QAA6B,QAAQ,OAAO;CAChF,MAAM,WAAW,MAAM,gBAAgB,QAAQ,KAAK;CACpD,OAAO;EAAE,GAAI,MAAM,mBAAmB,QAAQ,KAAK;EAAI;CAAS;AACjE"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"build-BUhQQ1E5.js","names":[],"sources":["../src/commands/build.ts"],"sourcesContent":["import { displayPath, loadStarsConfig } from '@wolfstar/http-framework/config';\nimport { defineCommand } from 'citty';\nimport { createColors } from 'colorette';\nimport { createBuilder } from '../builders/index.js';\nimport { projectArgs, resolveCwd, type ProjectArgs } from '../utils/args.js';\nimport { cliDiagnostics } from '../utils/diagnostics.js';\nimport { Locales } from '../utils/locales.js';\nimport { shouldUseColor } from '../utils/output-mode.js';\nimport { prepareProject } from './_shared.js';\n\nexport interface BuildTaskOptions extends ProjectArgs {\n\tstdout?: NodeJS.WritableStream;\n}\n\nexport async function runBuild(options: BuildTaskOptions): Promise<void> {\n\tconst stdout = options.stdout ?? process.stdout;\n\tconst colors = createColors({ useColor: shouldUseColor() });\n\tconst config = await loadStarsConfig({ cwd: resolveCwd(options), configFile: options.config });\n\tawait prepareProject(config);\n\n\tif (config.build.tool === 'none') {\n\t\tstdout.write(`${colors.dim('stars')} nothing to build, ${displayPath(config.root, config.entry)} runs as-is (build.tool is 'none')\\n`);\n\t\treturn;\n\t}\n\n\tconst builder = await createBuilder(config);\n\tbuilder.on('log', (level, text) => {\n\t\tconst paint = level === 'error' ? colors.red : level === 'warn' ? colors.yellow : (value: string) => value;\n\t\tstdout.write(`${paint(text)}\\n`);\n\t});\n\n\tstdout.write(`${colors.dim('stars')} building with ${colors.bold(config.build.tool)}…\\n`);\n\tconst outcome = await builder.build();\n\tif (!outcome.ok) {\n\t\tthrow cliDiagnostics.BUILD_FAILED({ message: outcome.message ?? '' });\n\t}\n\tnew Locales(config).copy();\n\n\tstdout.write(`${colors.dim('stars')} ${colors.green(`built in ${outcome.durationMs}ms`)} → ${displayPath(config.root, config.build.output)}\\n`);\n}\n\nexport default defineCommand({\n\tmeta: {\n\t\tname: 'build',\n\t\tdescription: 'Build the project once with the configured build tool'\n\t},\n\targs: { ...projectArgs },\n\tasync run({ args }) {\n\t\tawait runBuild({ config: args.config, cwd: args.cwd });\n\t}\n});\n"],"mappings":";;;;;;;;;;AAcA,eAAsB,SAAS,SAA0C;CACxE,MAAM,SAAS,QAAQ,UAAU,QAAQ;CACzC,MAAM,SAAS,aAAa,EAAE,UAAU,eAAe,EAAE,CAAC;CAC1D,MAAM,SAAS,MAAM,gBAAgB;EAAE,KAAK,WAAW,OAAO;EAAG,YAAY,QAAQ;CAAO,CAAC;CAC7F,MAAM,eAAe,MAAM;CAE3B,IAAI,OAAO,MAAM,SAAS,QAAQ;EACjC,OAAO,MAAM,GAAG,OAAO,IAAI,OAAO,EAAE,qBAAqB,YAAY,OAAO,MAAM,OAAO,KAAK,EAAE,qCAAqC;EACrI;CACD;CAEA,MAAM,UAAU,MAAM,cAAc,MAAM;CAC1C,QAAQ,GAAG,QAAQ,OAAO,SAAS;EAClC,MAAM,QAAQ,UAAU,UAAU,OAAO,MAAM,UAAU,SAAS,OAAO,UAAU,UAAkB;EACrG,OAAO,MAAM,GAAG,MAAM,IAAI,EAAE,GAAG;CAChC,CAAC;CAED,OAAO,MAAM,GAAG,OAAO,IAAI,OAAO,EAAE,iBAAiB,OAAO,KAAK,OAAO,MAAM,IAAI,EAAE,IAAI;CACxF,MAAM,UAAU,MAAM,QAAQ,MAAM;CACpC,IAAI,CAAC,QAAQ,IACZ,MAAM,eAAe,aAAa,EAAE,SAAS,QAAQ,WAAW,GAAG,CAAC;CAErE,IAAI,QAAQ,MAAM,CAAC,CAAC,KAAK;CAEzB,OAAO,MAAM,GAAG,OAAO,IAAI,OAAO,EAAE,GAAG,OAAO,MAAM,YAAY,QAAQ,WAAW,GAAG,EAAE,KAAK,YAAY,OAAO,MAAM,OAAO,MAAM,MAAM,EAAE,GAAG;AAC/I;AAEA,oBAAe,cAAc;CAC5B,MAAM;EACL,MAAM;EACN,aAAa;CACd;CACA,MAAM,EAAE,GAAG,YAAY;CACvB,MAAM,IAAI,EAAE,QAAQ;EACnB,MAAM,SAAS;GAAE,QAAQ,KAAK;GAAQ,KAAK,KAAK;EAAI,CAAC;CACtD;AACD,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"codegen-hmnFzRjK.js","names":[],"sources":["../src/commands/codegen.ts"],"sourcesContent":["import { displayPath, loadStarsConfig, type ResolvedStarsConfig } from '@wolfstar/http-framework/config';\nimport { defineCommand } from 'citty';\nimport { createColors } from 'colorette';\nimport { spawn } from 'node:child_process';\nimport { mkdtemp, readFile, rm } from 'node:fs/promises';\nimport { tmpdir } from 'node:os';\nimport { join } from 'node:path';\nimport { projectArgs, resolveCwd, type ProjectArgs } from '../utils/args.js';\nimport { cliDiagnostics } from '../utils/diagnostics.js';\nimport { shouldUseColor } from '../utils/output-mode.js';\nimport { resolveFromProject } from '../utils/project.js';\n\nexport interface CodegenTaskOptions extends ProjectArgs {\n\tcheck?: boolean;\n\tjson?: boolean;\n\tstdout?: NodeJS.WritableStream;\n}\n\nexport interface CodegenResult {\n\tgenerator: 'i18n';\n\toutput: string;\n\tstatus: 'written' | 'up-to-date' | 'outdated';\n}\n\nexport async function runCodegen(options: CodegenTaskOptions): Promise<void> {\n\tconst stdout = options.stdout ?? process.stdout;\n\tconst colors = createColors({ useColor: shouldUseColor() && !options.json });\n\tconst config = await loadStarsConfig({ cwd: resolveCwd(options), configFile: options.config });\n\tconst results: CodegenResult[] = [];\n\n\tif (config.codegen.i18n) results.push(await runI18n(config, Boolean(options.check)));\n\n\tif (options.json) {\n\t\tstdout.write(`${JSON.stringify({ check: Boolean(options.check), results }, null, 2)}\\n`);\n\t} else if (results.length === 0) {\n\t\tstdout.write(`${colors.dim('stars')} nothing to generate (no code generators are configured)\\n`);\n\t} else {\n\t\tfor (const result of results) {\n\t\t\tconst paint = result.status === 'outdated' ? colors.red : colors.green;\n\t\t\tstdout.write(`${colors.dim('stars')} ${result.generator}: ${paint(result.status)} ${displayPath(config.root, result.output)}\\n`);\n\t\t}\n\t}\n\n\tif (results.some((result) => result.status === 'outdated')) {\n\t\tthrow cliDiagnostics.CODEGEN_OUTDATED({});\n\t}\n}\n\nasync function runI18n(config: ResolvedStarsConfig, check: boolean): Promise<CodegenResult> {\n\tconst { locales, output } = config.codegen.i18n!;\n\tconst cli = resolveFromProject(config.root, '@wolfstar/i18next-type-generator');\n\tif (!cli) {\n\t\tthrow cliDiagnostics.DEPENDENCY_MISSING({\n\t\t\tname: '@wolfstar/i18next-type-generator',\n\t\t\troot: config.root,\n\t\t\thint: 'Install it with `pnpm add -D @wolfstar/i18next-type-generator`, or set `codegen.i18n` to false.'\n\t\t});\n\t}\n\n\tif (!check) {\n\t\tawait generate(config.root, cli, locales, output);\n\t\treturn { generator: 'i18n', output, status: 'written' };\n\t}\n\n\tconst directory = await mkdtemp(join(tmpdir(), 'stars-codegen-'));\n\ttry {\n\t\tconst candidate = join(directory, 'i18next.d.ts');\n\t\tawait generate(config.root, cli, locales, candidate);\n\t\tconst [expected, actual] = await Promise.all([readFile(candidate, 'utf-8'), readFile(output, 'utf-8').catch(() => null)]);\n\t\treturn { generator: 'i18n', output, status: expected === actual ? 'up-to-date' : 'outdated' };\n\t} finally {\n\t\tawait rm(directory, { recursive: true, force: true });\n\t}\n}\n\nfunction generate(root: string, cli: string, locales: string, output: string): Promise<void> {\n\treturn new Promise((resolve, reject) => {\n\t\tconst child = spawn(process.execPath, [cli, locales, output], { cwd: root, stdio: ['ignore', 'ignore', 'pipe'], windowsHide: true });\n\t\tlet stderr = '';\n\t\tchild.stderr?.on('data', (chunk: Buffer) => (stderr += chunk.toString()));\n\t\tchild.once('error', reject);\n\t\tchild.once('exit', (code) => {\n\t\t\tif (code === 0) resolve();\n\t\t\telse reject(cliDiagnostics.CODEGEN_FAILED({ code, stderr: stderr.trim() }));\n\t\t});\n\t});\n}\n\nexport default defineCommand({\n\tmeta: {\n\t\tname: 'codegen',\n\t\tdescription: 'Run the configured code generators (i18next types)'\n\t},\n\targs: {\n\t\t...projectArgs,\n\t\tcheck: {\n\t\t\ttype: 'boolean',\n\t\t\tdescription: 'Fail when the generated files are out of date instead of writing them',\n\t\t\tdefault: false\n\t\t},\n\t\tjson: {\n\t\t\ttype: 'boolean',\n\t\t\tdescription: 'Print machine-readable JSON',\n\t\t\tdefault: false\n\t\t}\n\t},\n\tasync run({ args }) {\n\t\tawait runCodegen({ config: args.config, cwd: args.cwd, check: args.check, json: args.json });\n\t}\n});\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"commands-BApoAbpQ.js","names":[],"sources":["../src/utils/discord.ts","../src/utils/prompts.ts","../src/commands/commands.ts"],"sourcesContent":["import type { ResolvedStarsConfig } from '@wolfstar/http-framework/config';\nimport { cliDiagnostics } from './diagnostics.js';\nimport { readDiscordCredentials } from '../dev/tunnel.js';\n\nconst API = 'https://discord.com/api/v10';\n\nexport interface ApplicationCommand {\n\tid: string;\n\tapplication_id: string;\n\tname: string;\n\tdescription?: string;\n\ttype?: number;\n\tguild_id?: string;\n\tversion?: string;\n}\n\nexport interface DiscordClient {\n\tapplicationId: string;\n\tlistCommands(guildId: string | null): Promise<ApplicationCommand[]>;\n\tdeleteCommand(guildId: string | null, commandId: string): Promise<void>;\n}\n\nexport const COMMAND_TYPE_NAMES: Record<number, string> = { 1: 'chat input', 2: 'user', 3: 'message' };\n\n/**\n * A minimal Discord REST client for what `stars commands` manages. The credentials come from the environment or the\n * project's `.env`, the same place the bot reads them from once it starts.\n */\nexport function createDiscordClient(config: ResolvedStarsConfig, env: NodeJS.ProcessEnv = process.env): DiscordClient {\n\tconst credentials = readDiscordCredentials(config, env);\n\tif (!credentials) {\n\t\tthrow cliDiagnostics.DISCORD_TOKEN_MISSING({});\n\t}\n\n\tif (!credentials.applicationId) {\n\t\tthrow cliDiagnostics.DISCORD_APPLICATION_ID_MISSING({});\n\t}\n\n\tconst applicationId = credentials.applicationId;\n\tconst scope = (guildId: string | null) =>\n\t\tguildId ? `/applications/${applicationId}/guilds/${guildId}/commands` : `/applications/${applicationId}/commands`;\n\n\tconst request = async (method: string, path: string): Promise<unknown> => {\n\t\tconst response = await fetch(`${API}${path}`, {\n\t\t\tmethod,\n\t\t\theaders: { authorization: `Bot ${credentials.token}` },\n\t\t\tsignal: AbortSignal.timeout(15_000)\n\t\t});\n\n\t\tif (response.status === 204) return null;\n\n\t\tconst body: unknown = await response.json().catch(() => null);\n\t\tif (!response.ok) {\n\t\t\tconst detail = typeof body === 'object' && body !== null && 'message' in body ? String((body as { message: unknown }).message) : '';\n\t\t\tthrow cliDiagnostics.DISCORD_REQUEST_FAILED({ status: response.status, detail });\n\t\t}\n\n\t\treturn body;\n\t};\n\n\treturn {\n\t\tapplicationId,\n\t\tasync listCommands(guildId) {\n\t\t\tconst body = await request('GET', scope(guildId));\n\t\t\treturn Array.isArray(body) ? (body as ApplicationCommand[]) : [];\n\t\t},\n\t\tasync deleteCommand(guildId, commandId) {\n\t\t\tawait request('DELETE', `${scope(guildId)}/${commandId}`);\n\t\t}\n\t};\n}\n","import type { Diagnostic } from 'nostics';\nimport type { ApplicationCommand } from './discord.js';\nimport { cliDiagnostics } from './diagnostics.js';\n\nexport interface CommandsPrompt {\n\t/** Asks which of the deployed commands to delete. Returns the chosen ids. */\n\tpick(commands: readonly ApplicationCommand[], scope: string): Promise<string[]>;\n\t/** Final go/no-go before anything is deleted. */\n\tconfirm(message: string): Promise<boolean>;\n}\n\n/**\n * The interactive wizard behind `stars commands clean`: a checklist of what Discord has deployed, then a\n * confirmation, so a destructive cleanup is never one keystroke away. `@clack/prompts` is loaded lazily — the\n * non-interactive paths (`--yes`, `--json`, CI) never pay for it.\n */\nexport function createClackPrompt(): CommandsPrompt {\n\treturn {\n\t\tasync pick(commands, scope) {\n\t\t\tconst { isCancel, multiselect } = await import('@clack/prompts');\n\t\t\tconst answer = await multiselect({\n\t\t\t\tmessage: `Which commands should be deleted from ${scope}?`,\n\t\t\t\toptions: commands.map((command) => ({\n\t\t\t\t\tvalue: command.id,\n\t\t\t\t\tlabel: command.name,\n\t\t\t\t\thint: [describeType(command), command.id].filter(Boolean).join(' · ')\n\t\t\t\t})),\n\t\t\t\trequired: false\n\t\t\t});\n\n\t\t\tif (isCancel(answer)) throw aborted();\n\t\t\treturn answer as string[];\n\t\t},\n\t\tasync confirm(message) {\n\t\t\tconst { confirm, isCancel } = await import('@clack/prompts');\n\t\t\tconst answer = await confirm({ message, initialValue: false });\n\n\t\t\tif (isCancel(answer)) throw aborted();\n\t\t\treturn Boolean(answer);\n\t\t}\n\t};\n}\n\nfunction describeType(command: ApplicationCommand): string {\n\tswitch (command.type) {\n\t\tcase 2:\n\t\t\treturn 'user';\n\t\tcase 3:\n\t\t\treturn 'message';\n\t\tdefault:\n\t\t\treturn 'chat input';\n\t}\n}\n\nfunction aborted(): Diagnostic {\n\treturn cliDiagnostics.ABORTED({});\n}\n","import { loadStarsConfig } from '@wolfstar/http-framework/config';\nimport { defineCommand } from 'citty';\nimport { createColors } from 'colorette';\nimport type { Diagnostic } from 'nostics';\nimport { COMMAND_TYPE_NAMES, createDiscordClient, type ApplicationCommand, type DiscordClient } from '../utils/discord.js';\nimport { cliDiagnostics } from '../utils/diagnostics.js';\nimport { shouldUseColor } from '../utils/output-mode.js';\nimport { createClackPrompt, type CommandsPrompt } from '../utils/prompts.js';\nimport { projectArgs, resolveCwd, type ProjectArgs } from '../utils/args.js';\n\nexport interface CommandsTaskOptions extends ProjectArgs {\n\t/** A guild id to work on the guild-scoped commands instead of the global ones. */\n\tguild?: string;\n\tjson?: boolean;\n\tstdout?: NodeJS.WritableStream;\n\t/** Overrides the client, for tests. */\n\tclient?: DiscordClient;\n}\n\nexport interface CommandsCleanOptions extends CommandsTaskOptions {\n\t/** Names to delete; without any, the wizard asks which of the deployed commands to remove. */\n\tnames?: string[];\n\t/** Deletes without asking. Required in a non-interactive terminal. */\n\tyes?: boolean;\n\tstdin?: NodeJS.ReadableStream & { isTTY?: boolean };\n\t/** Overrides the interactive wizard, for tests. */\n\tprompt?: CommandsPrompt;\n}\n\n/**\n * Lists the application commands Discord currently has deployed, which is not necessarily what the project would\n * register today: renamed and removed commands stay until something deletes them.\n */\nexport async function runCommandsList(options: CommandsTaskOptions): Promise<void> {\n\tconst stdout = options.stdout ?? process.stdout;\n\tconst colors = createColors({ useColor: shouldUseColor() && !options.json });\n\tconst { client, guild } = await connect(options);\n\tconst commands = await client.listCommands(guild);\n\n\tif (options.json) {\n\t\tstdout.write(`${JSON.stringify({ applicationId: client.applicationId, guildId: guild, commands }, null, 2)}\\n`);\n\t\treturn;\n\t}\n\n\tif (commands.length === 0) {\n\t\tstdout.write(`${colors.dim('stars')} no ${guild ? `commands in guild ${guild}` : 'global commands'} are deployed\\n`);\n\t\treturn;\n\t}\n\n\tstdout.write(`${colors.dim('stars')} ${commands.length} ${guild ? `command(s) in guild ${guild}` : 'global command(s)'}\\n`);\n\tfor (const command of commands) stdout.write(` ${colors.bold(describeName(command))} ${colors.dim(command.id)}\\n`);\n}\n\n/**\n * Deletes deployed application commands. Discord keeps whatever was registered last, so this is the way to clear\n * commands a project no longer defines (or a whole guild's test deployment).\n */\nexport async function runCommandsClean(options: CommandsCleanOptions): Promise<void> {\n\tconst stdout = options.stdout ?? process.stdout;\n\tconst colors = createColors({ useColor: shouldUseColor() && !options.json });\n\tconst { client, guild } = await connect(options);\n\tconst deployed = await client.listCommands(guild);\n\tconst wanted = options.names?.filter((name) => name.length > 0) ?? [];\n\n\tconst missing = wanted.filter((name) => !deployed.some((command) => command.name === name));\n\tif (missing.length > 0) {\n\t\tthrow cliDiagnostics.COMMAND_NOT_FOUND({ names: missing.join(', ') });\n\t}\n\n\tif (deployed.length === 0) {\n\t\tif (options.json) stdout.write(`${JSON.stringify({ deleted: [] }, null, 2)}\\n`);\n\t\telse stdout.write(`${colors.dim('stars')} nothing to delete\\n`);\n\t\treturn;\n\t}\n\n\tconst scope = guild ? `guild ${guild}` : 'the global scope';\n\tconst targets = await selectTargets(options, deployed, wanted, scope, stdout, colors);\n\tif (targets.length === 0) {\n\t\tif (options.json) stdout.write(`${JSON.stringify({ deleted: [] }, null, 2)}\\n`);\n\t\telse stdout.write(`${colors.dim('stars')} nothing to delete\\n`);\n\t\treturn;\n\t}\n\n\tfor (const command of targets) {\n\t\tawait client.deleteCommand(guild, command.id);\n\t\tif (!options.json) stdout.write(`${colors.dim('stars')} ${colors.red('deleted')} ${describeName(command)}\\n`);\n\t}\n\n\tif (options.json) stdout.write(`${JSON.stringify({ deleted: targets.map((command) => ({ id: command.id, name: command.name })) }, null, 2)}\\n`);\n}\n\n/**\n * Works out what to delete: `--name` (and `--yes`) keep the command scriptable, while a bare `stars commands clean`\n * on a terminal runs the wizard — a checklist of what Discord has deployed, then a confirmation.\n */\nasync function selectTargets(\n\toptions: CommandsCleanOptions,\n\tdeployed: ApplicationCommand[],\n\twanted: string[],\n\tscope: string,\n\tstdout: NodeJS.WritableStream,\n\tcolors: ReturnType<typeof createColors>\n): Promise<ApplicationCommand[]> {\n\tif (wanted.length > 0) {\n\t\tconst named = deployed.filter((command) => wanted.includes(command.name));\n\t\tif (options.yes) return named;\n\n\t\tawait confirmOrThrow(options, stdout, colors, `delete ${colors.bold(String(named.length))} command(s) from ${scope}?`);\n\t\treturn named;\n\t}\n\n\tif (options.yes) return deployed;\n\n\tconst stdin = options.stdin ?? process.stdin;\n\tif (!options.prompt && !stdin.isTTY) throw confirmationRequired();\n\n\tconst prompt = options.prompt ?? createClackPrompt();\n\tconst chosen = new Set(await prompt.pick(deployed, scope));\n\tconst targets = deployed.filter((command) => chosen.has(command.id));\n\tif (targets.length === 0) return [];\n\n\tconst names = targets.map((command) => command.name).join(', ');\n\tif (!(await prompt.confirm(`Delete ${targets.length} command(s) from ${scope}: ${names}?`))) {\n\t\tthrow cliDiagnostics.ABORTED({});\n\t}\n\n\treturn targets;\n}\n\nasync function connect(options: CommandsTaskOptions): Promise<{ client: DiscordClient; guild: string | null }> {\n\tconst config = await loadStarsConfig({ cwd: resolveCwd(options), configFile: options.config });\n\treturn { client: options.client ?? createDiscordClient(config), guild: options.guild ?? null };\n}\n\nfunction describeName(command: ApplicationCommand): string {\n\tconst type = command.type && command.type !== 1 ? ` (${COMMAND_TYPE_NAMES[command.type] ?? `type ${command.type}`})` : '';\n\treturn `${command.name}${type}`;\n}\n\n/**\n * Deleting deployed commands is not reversible, so a terminal run asks first; scripts pass `--yes`.\n */\nasync function confirmOrThrow(\n\toptions: CommandsCleanOptions,\n\tstdout: NodeJS.WritableStream,\n\tcolors: ReturnType<typeof createColors>,\n\tquestion: string\n): Promise<void> {\n\tif (options.prompt) {\n\t\tif (await options.prompt.confirm(question)) return;\n\t\tthrow cliDiagnostics.ABORTED({});\n\t}\n\n\tconst stdin = options.stdin ?? process.stdin;\n\tif (!stdin.isTTY) throw confirmationRequired();\n\n\tstdout.write(`${colors.dim('stars')} ${question} [y/N] `);\n\treturn new Promise((resolve, reject) => {\n\t\tstdin.setEncoding?.('utf-8');\n\t\tstdin.once('data', (chunk: string) => {\n\t\t\tstdin.pause?.();\n\t\t\tconst answer = chunk.trim().toLowerCase();\n\t\t\tif (answer === 'y' || answer === 'yes') resolve();\n\t\t\telse reject(cliDiagnostics.ABORTED({}));\n\t\t});\n\t\tstdin.resume?.();\n\t});\n}\n\nfunction confirmationRequired(): Diagnostic {\n\treturn cliDiagnostics.CONFIRMATION_REQUIRED({});\n}\n\nconst scopeArgs = {\n\t...projectArgs,\n\tguild: {\n\t\ttype: 'string',\n\t\tdescription: 'Work on a guild’s commands instead of the global ones'\n\t},\n\tjson: {\n\t\ttype: 'boolean',\n\t\tdescription: 'Print machine-readable JSON',\n\t\tdefault: false\n\t}\n} as const;\n\nconst list = defineCommand({\n\tmeta: { name: 'list', description: 'List the application commands Discord has deployed' },\n\targs: scopeArgs,\n\tasync run({ args }) {\n\t\tawait runCommandsList({ config: args.config, cwd: args.cwd, guild: args.guild, json: args.json });\n\t}\n});\n\nconst clean = defineCommand({\n\tmeta: { name: 'clean', description: 'Delete deployed application commands (all of them, or the named ones)' },\n\targs: {\n\t\t...scopeArgs,\n\t\tname: {\n\t\t\ttype: 'string',\n\t\t\tdescription: 'Only delete the command with this name (repeatable)'\n\t\t},\n\t\tyes: {\n\t\t\ttype: 'boolean',\n\t\t\talias: 'y',\n\t\t\tdescription: 'Delete without asking for a confirmation',\n\t\t\tdefault: false\n\t\t}\n\t},\n\tasync run({ args }) {\n\t\tconst names = Array.isArray(args.name) ? args.name : args.name ? [args.name] : [];\n\t\tawait runCommandsClean({ config: args.config, cwd: args.cwd, guild: args.guild, json: args.json, names, yes: args.yes });\n\t}\n});\n\nexport default defineCommand({\n\tmeta: {\n\t\tname: 'commands',\n\t\tdescription: 'Inspect and clean the application commands deployed to Discord'\n\t},\n\tsubCommands: { list, clean },\n\targs: scopeArgs,\n\tasync run({ args, rawArgs }) {\n\t\t// `stars commands` with no subcommand lists, the way `git branch` does.\n\t\tif (rawArgs.some((argument) => argument === 'list' || argument === 'clean')) return;\n\n\t\tawait runCommandsList({ config: args.config, cwd: args.cwd, guild: args.guild, json: args.json });\n\t}\n});\n"],"mappings":";;;;;;;;;AAIA,MAAM,MAAM;AAkBZ,MAAa,qBAA6C;CAAE,GAAG;CAAc,GAAG;CAAQ,GAAG;AAAU;;;;;AAMrG,SAAgB,oBAAoB,QAA6B,MAAyB,QAAQ,KAAoB;CACrH,MAAM,cAAc,uBAAuB,QAAQ,GAAG;CACtD,IAAI,CAAC,aACJ,MAAM,eAAe,sBAAsB,CAAC,CAAC;CAG9C,IAAI,CAAC,YAAY,eAChB,MAAM,eAAe,+BAA+B,CAAC,CAAC;CAGvD,MAAM,gBAAgB,YAAY;CAClC,MAAM,SAAS,YACd,UAAU,iBAAiB,cAAc,UAAU,QAAQ,aAAa,iBAAiB,cAAc;CAExG,MAAM,UAAU,OAAO,QAAgB,SAAmC;EACzE,MAAM,WAAW,MAAM,MAAM,GAAG,MAAM,QAAQ;GAC7C;GACA,SAAS,EAAE,eAAe,OAAO,YAAY,QAAQ;GACrD,QAAQ,YAAY,QAAQ,IAAM;EACnC,CAAC;EAED,IAAI,SAAS,WAAW,KAAK,OAAO;EAEpC,MAAM,OAAgB,MAAM,SAAS,KAAK,CAAC,CAAC,YAAY,IAAI;EAC5D,IAAI,CAAC,SAAS,IAAI;GACjB,MAAM,SAAS,OAAO,SAAS,YAAY,SAAS,QAAQ,aAAa,OAAO,OAAQ,KAA8B,OAAO,IAAI;GACjI,MAAM,eAAe,uBAAuB;IAAE,QAAQ,SAAS;IAAQ;GAAO,CAAC;EAChF;EAEA,OAAO;CACR;CAEA,OAAO;EACN;EACA,MAAM,aAAa,SAAS;GAC3B,MAAM,OAAO,MAAM,QAAQ,OAAO,MAAM,OAAO,CAAC;GAChD,OAAO,MAAM,QAAQ,IAAI,IAAK,OAAgC,CAAC;EAChE;EACA,MAAM,cAAc,SAAS,WAAW;GACvC,MAAM,QAAQ,UAAU,GAAG,MAAM,OAAO,EAAE,GAAG,WAAW;EACzD;CACD;AACD;;;;;;;;;ACtDA,SAAgB,oBAAoC;CACnD,OAAO;EACN,MAAM,KAAK,UAAU,OAAO;GAC3B,MAAM,EAAE,UAAU,gBAAgB,MAAM,OAAO;GAC/C,MAAM,SAAS,MAAM,YAAY;IAChC,SAAS,yCAAyC,MAAM;IACxD,SAAS,SAAS,KAAK,aAAa;KACnC,OAAO,QAAQ;KACf,OAAO,QAAQ;KACf,MAAM,CAAC,aAAa,OAAO,GAAG,QAAQ,EAAE,CAAC,CAAC,OAAO,OAAO,CAAC,CAAC,KAAK,KAAK;IACrE,EAAE;IACF,UAAU;GACX,CAAC;GAED,IAAI,SAAS,MAAM,GAAG,MAAM,QAAQ;GACpC,OAAO;EACR;EACA,MAAM,QAAQ,SAAS;GACtB,MAAM,EAAE,SAAS,aAAa,MAAM,OAAO;GAC3C,MAAM,SAAS,MAAM,QAAQ;IAAE;IAAS,cAAc;GAAM,CAAC;GAE7D,IAAI,SAAS,MAAM,GAAG,MAAM,QAAQ;GACpC,OAAO,QAAQ,MAAM;EACtB;CACD;AACD;AAEA,SAAS,aAAa,SAAqC;CAC1D,QAAQ,QAAQ,MAAhB;EACC,KAAK,GACJ,OAAO;EACR,KAAK,GACJ,OAAO;EACR,SACC,OAAO;CACT;AACD;AAEA,SAAS,UAAsB;CAC9B,OAAO,eAAe,QAAQ,CAAC,CAAC;AACjC;;;;;;;;ACvBA,eAAsB,gBAAgB,SAA6C;CAClF,MAAM,SAAS,QAAQ,UAAU,QAAQ;CACzC,MAAM,SAAS,aAAa,EAAE,UAAU,eAAe,KAAK,CAAC,QAAQ,KAAK,CAAC;CAC3E,MAAM,EAAE,QAAQ,UAAU,MAAM,QAAQ,OAAO;CAC/C,MAAM,WAAW,MAAM,OAAO,aAAa,KAAK;CAEhD,IAAI,QAAQ,MAAM;EACjB,OAAO,MAAM,GAAG,KAAK,UAAU;GAAE,eAAe,OAAO;GAAe,SAAS;GAAO;EAAS,GAAG,MAAM,CAAC,EAAE,GAAG;EAC9G;CACD;CAEA,IAAI,SAAS,WAAW,GAAG;EAC1B,OAAO,MAAM,GAAG,OAAO,IAAI,OAAO,EAAE,MAAM,QAAQ,qBAAqB,UAAU,kBAAkB,gBAAgB;EACnH;CACD;CAEA,OAAO,MAAM,GAAG,OAAO,IAAI,OAAO,EAAE,GAAG,SAAS,OAAO,GAAG,QAAQ,uBAAuB,UAAU,oBAAoB,GAAG;CAC1H,KAAK,MAAM,WAAW,UAAU,OAAO,MAAM,KAAK,OAAO,KAAK,aAAa,OAAO,CAAC,EAAE,GAAG,OAAO,IAAI,QAAQ,EAAE,EAAE,GAAG;AACnH;;;;;AAMA,eAAsB,iBAAiB,SAA8C;CACpF,MAAM,SAAS,QAAQ,UAAU,QAAQ;CACzC,MAAM,SAAS,aAAa,EAAE,UAAU,eAAe,KAAK,CAAC,QAAQ,KAAK,CAAC;CAC3E,MAAM,EAAE,QAAQ,UAAU,MAAM,QAAQ,OAAO;CAC/C,MAAM,WAAW,MAAM,OAAO,aAAa,KAAK;CAChD,MAAM,SAAS,QAAQ,OAAO,QAAQ,SAAS,KAAK,SAAS,CAAC,KAAK,CAAC;CAEpE,MAAM,UAAU,OAAO,QAAQ,SAAS,CAAC,SAAS,MAAM,YAAY,QAAQ,SAAS,IAAI,CAAC;CAC1F,IAAI,QAAQ,SAAS,GACpB,MAAM,eAAe,kBAAkB,EAAE,OAAO,QAAQ,KAAK,IAAI,EAAE,CAAC;CAGrE,IAAI,SAAS,WAAW,GAAG;EAC1B,IAAI,QAAQ,MAAM,OAAO,MAAM,GAAG,KAAK,UAAU,EAAE,SAAS,CAAC,EAAE,GAAG,MAAM,CAAC,EAAE,GAAG;OACzE,OAAO,MAAM,GAAG,OAAO,IAAI,OAAO,EAAE,qBAAqB;EAC9D;CACD;CAGA,MAAM,UAAU,MAAM,cAAc,SAAS,UAAU,QADzC,QAAQ,SAAS,UAAU,oBAC6B,QAAQ,MAAM;CACpF,IAAI,QAAQ,WAAW,GAAG;EACzB,IAAI,QAAQ,MAAM,OAAO,MAAM,GAAG,KAAK,UAAU,EAAE,SAAS,CAAC,EAAE,GAAG,MAAM,CAAC,EAAE,GAAG;OACzE,OAAO,MAAM,GAAG,OAAO,IAAI,OAAO,EAAE,qBAAqB;EAC9D;CACD;CAEA,KAAK,MAAM,WAAW,SAAS;EAC9B,MAAM,OAAO,cAAc,OAAO,QAAQ,EAAE;EAC5C,IAAI,CAAC,QAAQ,MAAM,OAAO,MAAM,GAAG,OAAO,IAAI,OAAO,EAAE,GAAG,OAAO,IAAI,SAAS,EAAE,GAAG,aAAa,OAAO,EAAE,GAAG;CAC7G;CAEA,IAAI,QAAQ,MAAM,OAAO,MAAM,GAAG,KAAK,UAAU,EAAE,SAAS,QAAQ,KAAK,aAAa;EAAE,IAAI,QAAQ;EAAI,MAAM,QAAQ;CAAK,EAAE,EAAE,GAAG,MAAM,CAAC,EAAE,GAAG;AAC/I;;;;;AAMA,eAAe,cACd,SACA,UACA,QACA,OACA,QACA,QACgC;CAChC,IAAI,OAAO,SAAS,GAAG;EACtB,MAAM,QAAQ,SAAS,QAAQ,YAAY,OAAO,SAAS,QAAQ,IAAI,CAAC;EACxE,IAAI,QAAQ,KAAK,OAAO;EAExB,MAAM,eAAe,SAAS,QAAQ,QAAQ,UAAU,OAAO,KAAK,OAAO,MAAM,MAAM,CAAC,EAAE,mBAAmB,MAAM,EAAE;EACrH,OAAO;CACR;CAEA,IAAI,QAAQ,KAAK,OAAO;CAExB,MAAM,QAAQ,QAAQ,SAAS,QAAQ;CACvC,IAAI,CAAC,QAAQ,UAAU,CAAC,MAAM,OAAO,MAAM,qBAAqB;CAEhE,MAAM,SAAS,QAAQ,UAAU,kBAAkB;CACnD,MAAM,SAAS,IAAI,IAAI,MAAM,OAAO,KAAK,UAAU,KAAK,CAAC;CACzD,MAAM,UAAU,SAAS,QAAQ,YAAY,OAAO,IAAI,QAAQ,EAAE,CAAC;CACnE,IAAI,QAAQ,WAAW,GAAG,OAAO,CAAC;CAElC,MAAM,QAAQ,QAAQ,KAAK,YAAY,QAAQ,IAAI,CAAC,CAAC,KAAK,IAAI;CAC9D,IAAI,CAAE,MAAM,OAAO,QAAQ,UAAU,QAAQ,OAAO,mBAAmB,MAAM,IAAI,MAAM,EAAE,GACxF,MAAM,eAAe,QAAQ,CAAC,CAAC;CAGhC,OAAO;AACR;AAEA,eAAe,QAAQ,SAAwF;CAC9G,MAAM,SAAS,MAAM,gBAAgB;EAAE,KAAK,WAAW,OAAO;EAAG,YAAY,QAAQ;CAAO,CAAC;CAC7F,OAAO;EAAE,QAAQ,QAAQ,UAAU,oBAAoB,MAAM;EAAG,OAAO,QAAQ,SAAS;CAAK;AAC9F;AAEA,SAAS,aAAa,SAAqC;CAC1D,MAAM,OAAO,QAAQ,QAAQ,QAAQ,SAAS,IAAI,KAAK,mBAAmB,QAAQ,SAAS,QAAQ,QAAQ,OAAO,KAAK;CACvH,OAAO,GAAG,QAAQ,OAAO;AAC1B;;;;AAKA,eAAe,eACd,SACA,QACA,QACA,UACgB;CAChB,IAAI,QAAQ,QAAQ;EACnB,IAAI,MAAM,QAAQ,OAAO,QAAQ,QAAQ,GAAG;EAC5C,MAAM,eAAe,QAAQ,CAAC,CAAC;CAChC;CAEA,MAAM,QAAQ,QAAQ,SAAS,QAAQ;CACvC,IAAI,CAAC,MAAM,OAAO,MAAM,qBAAqB;CAE7C,OAAO,MAAM,GAAG,OAAO,IAAI,OAAO,EAAE,GAAG,SAAS,QAAQ;CACxD,OAAO,IAAI,SAAS,SAAS,WAAW;EACvC,MAAM,cAAc,OAAO;EAC3B,MAAM,KAAK,SAAS,UAAkB;GACrC,MAAM,QAAQ;GACd,MAAM,SAAS,MAAM,KAAK,CAAC,CAAC,YAAY;GACxC,IAAI,WAAW,OAAO,WAAW,OAAO,QAAQ;QAC3C,OAAO,eAAe,QAAQ,CAAC,CAAC,CAAC;EACvC,CAAC;EACD,MAAM,SAAS;CAChB,CAAC;AACF;AAEA,SAAS,uBAAmC;CAC3C,OAAO,eAAe,sBAAsB,CAAC,CAAC;AAC/C;AAEA,MAAM,YAAY;CACjB,GAAG;CACH,OAAO;EACN,MAAM;EACN,aAAa;CACd;CACA,MAAM;EACL,MAAM;EACN,aAAa;EACb,SAAS;CACV;AACD;AAEA,MAAM,OAAO,cAAc;CAC1B,MAAM;EAAE,MAAM;EAAQ,aAAa;CAAqD;CACxF,MAAM;CACN,MAAM,IAAI,EAAE,QAAQ;EACnB,MAAM,gBAAgB;GAAE,QAAQ,KAAK;GAAQ,KAAK,KAAK;GAAK,OAAO,KAAK;GAAO,MAAM,KAAK;EAAK,CAAC;CACjG;AACD,CAAC;AAED,MAAM,QAAQ,cAAc;CAC3B,MAAM;EAAE,MAAM;EAAS,aAAa;CAAwE;CAC5G,MAAM;EACL,GAAG;EACH,MAAM;GACL,MAAM;GACN,aAAa;EACd;EACA,KAAK;GACJ,MAAM;GACN,OAAO;GACP,aAAa;GACb,SAAS;EACV;CACD;CACA,MAAM,IAAI,EAAE,QAAQ;EACnB,MAAM,QAAQ,MAAM,QAAQ,KAAK,IAAI,IAAI,KAAK,OAAO,KAAK,OAAO,CAAC,KAAK,IAAI,IAAI,CAAC;EAChF,MAAM,iBAAiB;GAAE,QAAQ,KAAK;GAAQ,KAAK,KAAK;GAAK,OAAO,KAAK;GAAO,MAAM,KAAK;GAAM;GAAO,KAAK,KAAK;EAAI,CAAC;CACxH;AACD,CAAC;AAED,uBAAe,cAAc;CAC5B,MAAM;EACL,MAAM;EACN,aAAa;CACd;CACA,aAAa;EAAE;EAAM;CAAM;CAC3B,MAAM;CACN,MAAM,IAAI,EAAE,MAAM,WAAW;EAE5B,IAAI,QAAQ,MAAM,aAAa,aAAa,UAAU,aAAa,OAAO,GAAG;EAE7E,MAAM,gBAAgB;GAAE,QAAQ,KAAK;GAAQ,KAAK,KAAK;GAAK,OAAO,KAAK;GAAO,MAAM,KAAK;EAAK,CAAC;CACjG;AACD,CAAC"}
|