numux 1.4.0 → 1.5.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 +27 -17
- package/dist/bin.js +2611 -0
- package/dist/config.d.ts +4 -0
- package/dist/config.js +7 -0
- package/dist/types.d.ts +53 -0
- package/package.json +13 -9
- package/src/cli.ts +0 -217
- package/src/completions.ts +0 -121
- package/src/config/expand-scripts.ts +0 -96
- package/src/config/interpolate.ts +0 -50
- package/src/config/loader.ts +0 -76
- package/src/config/resolver.ts +0 -67
- package/src/config/validator.ts +0 -150
- package/src/config.ts +0 -8
- package/src/index.ts +0 -258
- package/src/process/manager.ts +0 -379
- package/src/process/ready.ts +0 -45
- package/src/process/runner.ts +0 -243
- package/src/types.ts +0 -57
- package/src/ui/app.ts +0 -454
- package/src/ui/pane.ts +0 -125
- package/src/ui/prefix.ts +0 -207
- package/src/ui/status-bar.ts +0 -58
- package/src/ui/tabs.ts +0 -246
- package/src/utils/color.ts +0 -93
- package/src/utils/env-file.ts +0 -58
- package/src/utils/log-writer.ts +0 -48
- package/src/utils/logger.ts +0 -32
- package/src/utils/shutdown.ts +0 -39
- package/src/utils/watcher.ts +0 -53
package/src/utils/log-writer.ts
DELETED
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
import { closeSync, mkdirSync, openSync, writeSync } from 'node:fs'
|
|
2
|
-
import { join } from 'node:path'
|
|
3
|
-
import type { ProcessEvent } from '../types'
|
|
4
|
-
import { stripAnsi } from './color'
|
|
5
|
-
|
|
6
|
-
/** Writes process output to per-process log files in the given directory. */
|
|
7
|
-
export class LogWriter {
|
|
8
|
-
private dir: string
|
|
9
|
-
private files = new Map<string, number>()
|
|
10
|
-
private decoder = new TextDecoder()
|
|
11
|
-
private encoder = new TextEncoder()
|
|
12
|
-
|
|
13
|
-
constructor(dir: string) {
|
|
14
|
-
this.dir = dir
|
|
15
|
-
mkdirSync(dir, { recursive: true })
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
private errored = false
|
|
19
|
-
|
|
20
|
-
/** Event listener — pass to ProcessManager.on() */
|
|
21
|
-
handleEvent = (event: ProcessEvent): void => {
|
|
22
|
-
if (event.type !== 'output' || this.errored) return
|
|
23
|
-
|
|
24
|
-
try {
|
|
25
|
-
let fd = this.files.get(event.name)
|
|
26
|
-
if (fd === undefined) {
|
|
27
|
-
const path = join(this.dir, `${event.name}.log`)
|
|
28
|
-
fd = openSync(path, 'w')
|
|
29
|
-
this.files.set(event.name, fd)
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
const text = this.decoder.decode(event.data, { stream: true })
|
|
33
|
-
const clean = stripAnsi(text)
|
|
34
|
-
writeSync(fd, this.encoder.encode(clean))
|
|
35
|
-
} catch {
|
|
36
|
-
// Disk full, permissions, deleted dir — warn once and stop writing
|
|
37
|
-
this.errored = true
|
|
38
|
-
process.stderr.write(`numux: log writing failed for ${this.dir}, disabling log output\n`)
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
close(): void {
|
|
43
|
-
for (const fd of this.files.values()) {
|
|
44
|
-
closeSync(fd)
|
|
45
|
-
}
|
|
46
|
-
this.files.clear()
|
|
47
|
-
}
|
|
48
|
-
}
|
package/src/utils/logger.ts
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import { appendFileSync, existsSync, mkdirSync } from 'node:fs'
|
|
2
|
-
import { resolve } from 'node:path'
|
|
3
|
-
|
|
4
|
-
let enabled = false
|
|
5
|
-
let logFile = ''
|
|
6
|
-
|
|
7
|
-
export function enableDebugLog(dir?: string): void {
|
|
8
|
-
const logDir = dir ?? resolve(process.cwd(), '.numux')
|
|
9
|
-
logFile = resolve(logDir, 'debug.log')
|
|
10
|
-
if (!existsSync(logDir)) {
|
|
11
|
-
mkdirSync(logDir, { recursive: true })
|
|
12
|
-
}
|
|
13
|
-
enabled = true
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export function log(message: string, ...args: unknown[]): void {
|
|
17
|
-
if (!enabled) return
|
|
18
|
-
try {
|
|
19
|
-
const timestamp = new Date().toISOString()
|
|
20
|
-
const formatted = args.length > 0 ? `${message} ${args.map(a => JSON.stringify(a)).join(' ')}` : message
|
|
21
|
-
appendFileSync(logFile, `[${timestamp}] ${formatted}\n`)
|
|
22
|
-
} catch {
|
|
23
|
-
// Disk errors in debug logging should not crash the app
|
|
24
|
-
enabled = false
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
/** Reset logger state (for testing only) */
|
|
29
|
-
export function _resetLogger(): void {
|
|
30
|
-
enabled = false
|
|
31
|
-
logFile = ''
|
|
32
|
-
}
|
package/src/utils/shutdown.ts
DELETED
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import type { App } from '../ui/app'
|
|
2
|
-
import type { LogWriter } from './log-writer'
|
|
3
|
-
import { log } from './logger'
|
|
4
|
-
|
|
5
|
-
export function setupShutdownHandlers(app: App, logWriter?: LogWriter): void {
|
|
6
|
-
let shuttingDown = false
|
|
7
|
-
|
|
8
|
-
const shutdown = () => {
|
|
9
|
-
if (shuttingDown) {
|
|
10
|
-
process.exit(1)
|
|
11
|
-
}
|
|
12
|
-
shuttingDown = true
|
|
13
|
-
app.shutdown().finally(() => {
|
|
14
|
-
logWriter?.close()
|
|
15
|
-
process.exit(app.hasFailures() ? 1 : 0)
|
|
16
|
-
})
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
process.on('SIGINT', shutdown)
|
|
20
|
-
process.on('SIGTERM', shutdown)
|
|
21
|
-
process.on('uncaughtException', err => {
|
|
22
|
-
log('Uncaught exception:', err?.message ?? err)
|
|
23
|
-
process.stderr.write(`numux: unexpected error: ${err?.stack ?? err}\n`)
|
|
24
|
-
app.shutdown().finally(() => {
|
|
25
|
-
logWriter?.close()
|
|
26
|
-
process.exit(1)
|
|
27
|
-
})
|
|
28
|
-
})
|
|
29
|
-
|
|
30
|
-
process.on('unhandledRejection', (reason: unknown) => {
|
|
31
|
-
const message = reason instanceof Error ? reason.message : String(reason)
|
|
32
|
-
log('Unhandled rejection:', message)
|
|
33
|
-
process.stderr.write(`numux: unhandled rejection: ${message}\n`)
|
|
34
|
-
app.shutdown().finally(() => {
|
|
35
|
-
logWriter?.close()
|
|
36
|
-
process.exit(1)
|
|
37
|
-
})
|
|
38
|
-
})
|
|
39
|
-
}
|
package/src/utils/watcher.ts
DELETED
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
import { type FSWatcher, watch } from 'node:fs'
|
|
2
|
-
import { log } from './logger'
|
|
3
|
-
|
|
4
|
-
const DEBOUNCE_MS = 300
|
|
5
|
-
const IGNORED_SEGMENTS = new Set(['node_modules', '.git'])
|
|
6
|
-
|
|
7
|
-
export class FileWatcher {
|
|
8
|
-
private watchers: FSWatcher[] = []
|
|
9
|
-
private debounceTimers = new Map<string, ReturnType<typeof setTimeout>>()
|
|
10
|
-
|
|
11
|
-
watch(name: string, patterns: string[], cwd: string, onChanged: (path: string) => void): void {
|
|
12
|
-
const globs = patterns.map(p => new Bun.Glob(p))
|
|
13
|
-
|
|
14
|
-
try {
|
|
15
|
-
const watcher = watch(cwd, { recursive: true }, (_event, filename) => {
|
|
16
|
-
if (!filename) return
|
|
17
|
-
|
|
18
|
-
// Skip node_modules, .git, etc.
|
|
19
|
-
const segments = filename.split('/')
|
|
20
|
-
if (segments.some(s => IGNORED_SEGMENTS.has(s))) return
|
|
21
|
-
|
|
22
|
-
// Check if changed file matches any pattern
|
|
23
|
-
if (!globs.some(g => g.match(filename))) return
|
|
24
|
-
|
|
25
|
-
// Debounce per process
|
|
26
|
-
const existing = this.debounceTimers.get(name)
|
|
27
|
-
if (existing) clearTimeout(existing)
|
|
28
|
-
this.debounceTimers.set(
|
|
29
|
-
name,
|
|
30
|
-
setTimeout(() => {
|
|
31
|
-
this.debounceTimers.delete(name)
|
|
32
|
-
onChanged(filename)
|
|
33
|
-
}, DEBOUNCE_MS)
|
|
34
|
-
)
|
|
35
|
-
})
|
|
36
|
-
this.watchers.push(watcher)
|
|
37
|
-
log(`[${name}] Watching: ${patterns.join(', ')}`)
|
|
38
|
-
} catch (err) {
|
|
39
|
-
log(`[${name}] Failed to set up file watcher: ${err}`)
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
close(): void {
|
|
44
|
-
for (const timer of this.debounceTimers.values()) {
|
|
45
|
-
clearTimeout(timer)
|
|
46
|
-
}
|
|
47
|
-
this.debounceTimers.clear()
|
|
48
|
-
for (const watcher of this.watchers) {
|
|
49
|
-
watcher.close()
|
|
50
|
-
}
|
|
51
|
-
this.watchers = []
|
|
52
|
-
}
|
|
53
|
-
}
|