Lines 1-104javascript
3 * dsh-win32 CLI: `doctor` diagnoses the known DSH-on-Windows traps,
4 * `setup` installs the minimal-windows agent preset (and optionally a
5 * desktop shortcut). Zero dependencies.
8import { execFileSync } from 'node:child_process'
9import { existsSync, mkdirSync, readdirSync, readFileSync, realpathSync, rmSync, writeFileSync } from 'node:fs'
HighChild Process
Package source references child process execution.
bin/cli.mjsView on unpkg · L7 10import { homedir } from 'node:os'
11import { dirname, join, resolve } from 'node:path'
12import { fileURLToPath } from 'node:url'
13import process from 'node:process'
14// Shared with the runtime so the two never drift; lib/ always ships with bin/.
15import { findGitBash, installPreset, busyboxPath } from '../lib/preset-install.js'
17const WIN = process.platform === 'win32'
18const DSH_HOME = process.env.DSH_HOME ?? join(homedir(), '.dsh')
19const PRESET_ID = 'minimal-windows'
20const PRESET_SRC = join(dirname(fileURLToPath(import.meta.url)), '..', 'preset', PRESET_ID)
21const REPO = 'https://github.com/sjh9714/dsh-win32'
22const SELF_VERSION = JSON.parse(
HighSame File Env Network Execution
A single source file combines environment access, network access, and code or shell execution; review context before blocking.
bin/cli.mjsView on unpkg · L7 23 readFileSync(join(dirname(fileURLToPath(import.meta.url)), '..', 'package.json'), 'utf8'),
26const ok = message => console.log(` ok ${message}`)
27const warn = message => console.log(` WARN ${message}`)
28const bad = message => console.log(` FAIL ${message}`)
29const info = message => console.log(` tip ${message}`)
31function tryExec(file, args) {
33 return execFileSync(file, args, { encoding: 'utf8', windowsHide: true, stdio: ['ignore', 'pipe', 'ignore'] })
40 if (process.env.ProgramFiles !== undefined) {
41 const candidate = join(process.env.ProgramFiles, 'PowerShell', '7', 'pwsh.exe')
42 if (existsSync(candidate)) return candidate
44 const located = tryExec('where.exe', ['pwsh'])
45 const first = (located ?? '').split(/\r?\n/)[0]?.trim()
46 return first !== undefined && first !== '' ? first : undefined
50 * pnpm backs the profile-directory install: `dsh plugin add` forwards to it,
51 * so a box without pnpm fails the bundle wiring with a bare
52 * "'pnpm' is not recognized" and no hint about what is actually missing (#13).
55 const located = tryExec(WIN ? 'where.exe' : 'which', ['pnpm'])
56 const first = (located ?? '').split(/\r?\n/)[0]?.trim()
57 return first !== undefined && first !== '' ? first : undefined
60/** node ships corepack, so a missing pnpm is recoverable without a download. */
64 execFileSync(WIN ? 'corepack.cmd' : 'corepack', ['enable', 'pnpm'], {
75/** koffi 3.1.3/3.1.4 ship a broken win32-x64 prebuilt (segfault chain: install failures, picker crash, silent session-save crash). */
78 const profilesDir = join(DSH_HOME, 'profiles')
79 if (!existsSync(profilesDir)) return results
80 for (const profile of readdirSync(profilesDir)) {
81 const manifest = join(profilesDir, profile, 'node_modules', 'koffi', 'package.json')
82 if (!existsSync(manifest)) continue
84 const version = JSON.parse(readFileSync(manifest, 'utf8')).version
85 const loadable = tryExec(process.execPath, ['-e', 'require(process.argv[1])', dirname(manifest)]) !== undefined
86 results.push({ profile, version, loadable })
MediumDynamic Require
Package source references dynamic require/import behavior.
bin/cli.mjsView on unpkg · L84 88 // Unreadable manifest: nothing to report for this profile.
95 * True for `Git\bin\bash.exe`, the 47KB wrapper that respawns the real shell
96 * in `Git\usr\bin`. Note that the real path also ends in `\bin\bash.exe`,
97 * so the `usr` segment is what tells them apart and matching only the tail
98 * flags the correct shell as the wrapper.
100export function isBashWrapper(path) {
101 const normalized = path.replaceAll('\\', '/')
102 return /\/bin\/bash\.exe$/i.test(normalized) && !/\/usr\/bin\/bash\.exe$/i.test(normalized)