command-stream 0.8.1 → 0.8.3

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "command-stream",
3
- "version": "0.8.1",
3
+ "version": "0.8.3",
4
4
  "description": "Modern $ shell utility library with streaming, async iteration, and EventEmitter support, optimized for Bun runtime",
5
5
  "type": "module",
6
6
  "main": "src/$.mjs",
package/src/$.mjs CHANGED
@@ -12,14 +12,30 @@ import { parseShellCommand, needsRealShell } from './shell-parser.mjs';
12
12
 
13
13
  const isBun = typeof globalThis.Bun !== 'undefined';
14
14
 
15
- const VERBOSE =
16
- process.env.COMMAND_STREAM_VERBOSE === 'true' || process.env.CI === 'true';
17
-
18
15
  // Trace function for verbose logging
19
- function trace(category, messageOrFunc) {
16
+ // Can be controlled via COMMAND_STREAM_VERBOSE or COMMAND_STREAM_TRACE env vars
17
+ // Can be disabled per-command via trace: false option
18
+ // CI environment no longer auto-enables tracing
19
+ function trace(category, messageOrFunc, runner = null) {
20
+ // Check if runner explicitly disabled tracing
21
+ if (runner && runner.options && runner.options.trace === false) {
22
+ return;
23
+ }
24
+
25
+ // Check global trace setting (evaluated dynamically for runtime changes)
26
+ const TRACE_ENV = process.env.COMMAND_STREAM_TRACE;
27
+ const VERBOSE_ENV = process.env.COMMAND_STREAM_VERBOSE === 'true';
28
+
29
+ // COMMAND_STREAM_TRACE=false explicitly disables tracing even if COMMAND_STREAM_VERBOSE=true
30
+ // COMMAND_STREAM_TRACE=true explicitly enables tracing
31
+ // Otherwise, use COMMAND_STREAM_VERBOSE
32
+ const VERBOSE =
33
+ TRACE_ENV === 'false' ? false : TRACE_ENV === 'true' ? true : VERBOSE_ENV;
34
+
20
35
  if (!VERBOSE) {
21
36
  return;
22
37
  }
38
+
23
39
  const message =
24
40
  typeof messageOrFunc === 'function' ? messageOrFunc() : messageOrFunc;
25
41
  const timestamp = new Date().toISOString();
@@ -42,7 +58,40 @@ function findAvailableShell() {
42
58
  return cachedShell;
43
59
  }
44
60
 
45
- const shellsToTry = [
61
+ const isWindows = process.platform === 'win32';
62
+
63
+ // Windows-specific shells
64
+ const windowsShells = [
65
+ // Git Bash is the most Unix-compatible option on Windows
66
+ // Check common installation paths
67
+ {
68
+ cmd: 'C:\\Program Files\\Git\\bin\\bash.exe',
69
+ args: ['-c'],
70
+ checkPath: true,
71
+ },
72
+ {
73
+ cmd: 'C:\\Program Files\\Git\\usr\\bin\\bash.exe',
74
+ args: ['-c'],
75
+ checkPath: true,
76
+ },
77
+ {
78
+ cmd: 'C:\\Program Files (x86)\\Git\\bin\\bash.exe',
79
+ args: ['-c'],
80
+ checkPath: true,
81
+ },
82
+ // Git Bash via PATH (if added to PATH by user)
83
+ { cmd: 'bash.exe', args: ['-c'], checkPath: false },
84
+ // WSL bash as fallback
85
+ { cmd: 'wsl.exe', args: ['bash', '-c'], checkPath: false },
86
+ // PowerShell as last resort (different syntax for commands)
87
+ { cmd: 'powershell.exe', args: ['-Command'], checkPath: false },
88
+ { cmd: 'pwsh.exe', args: ['-Command'], checkPath: false },
89
+ // cmd.exe as final fallback
90
+ { cmd: 'cmd.exe', args: ['/c'], checkPath: false },
91
+ ];
92
+
93
+ // Unix-specific shells
94
+ const unixShells = [
46
95
  // Try absolute paths first (most reliable)
47
96
  { cmd: '/bin/sh', args: ['-l', '-c'], checkPath: true },
48
97
  { cmd: '/usr/bin/sh', args: ['-l', '-c'], checkPath: true },
@@ -71,6 +120,9 @@ function findAvailableShell() {
71
120
  { cmd: 'zsh', args: ['-l', '-c'], checkPath: false },
72
121
  ];
73
122
 
123
+ // Select shells based on platform
124
+ const shellsToTry = isWindows ? windowsShells : unixShells;
125
+
74
126
  for (const shell of shellsToTry) {
75
127
  try {
76
128
  if (shell.checkPath) {
@@ -84,12 +136,15 @@ function findAvailableShell() {
84
136
  return cachedShell;
85
137
  }
86
138
  } else {
87
- // Try to execute 'which' to check if command is in PATH
88
- const result = cp.spawnSync('which', [shell.cmd], {
139
+ // On Windows, use 'where' instead of 'which'
140
+ const whichCmd = isWindows ? 'where' : 'which';
141
+ const result = cp.spawnSync(whichCmd, [shell.cmd], {
89
142
  encoding: 'utf-8',
143
+ // On Windows, we need shell: true for 'where' to work
144
+ shell: isWindows,
90
145
  });
91
146
  if (result.status === 0 && result.stdout) {
92
- const shellPath = result.stdout.trim();
147
+ const shellPath = result.stdout.trim().split('\n')[0]; // Take first result
93
148
  trace(
94
149
  'ShellDetection',
95
150
  () => `Found shell in PATH: ${shell.cmd} => ${shellPath}`
@@ -100,15 +155,27 @@ function findAvailableShell() {
100
155
  }
101
156
  } catch (e) {
102
157
  // Continue to next shell option
158
+ trace(
159
+ 'ShellDetection',
160
+ () => `Failed to check shell ${shell.cmd}: ${e.message}`
161
+ );
103
162
  }
104
163
  }
105
164
 
106
- // Final fallback - use absolute path to sh
107
- trace(
108
- 'ShellDetection',
109
- () => 'WARNING: No shell found, using /bin/sh as fallback'
110
- );
111
- cachedShell = { cmd: '/bin/sh', args: ['-l', '-c'] };
165
+ // Final fallback based on platform
166
+ if (isWindows) {
167
+ trace(
168
+ 'ShellDetection',
169
+ () => 'WARNING: No shell found, using cmd.exe as fallback on Windows'
170
+ );
171
+ cachedShell = { cmd: 'cmd.exe', args: ['/c'] };
172
+ } else {
173
+ trace(
174
+ 'ShellDetection',
175
+ () => 'WARNING: No shell found, using /bin/sh as fallback'
176
+ );
177
+ cachedShell = { cmd: '/bin/sh', args: ['-l', '-c'] };
178
+ }
112
179
  return cachedShell;
113
180
  }
114
181
 
package/src/$.utils.mjs CHANGED
@@ -1,11 +1,23 @@
1
1
  import path from 'path';
2
2
 
3
- const VERBOSE = process.env.COMMAND_STREAM_VERBOSE === 'true';
4
-
3
+ // Trace function for verbose logging - consistent with src/$.mjs
4
+ // Can be controlled via COMMAND_STREAM_VERBOSE or COMMAND_STREAM_TRACE env vars
5
+ // CI environment no longer auto-enables tracing
5
6
  export function trace(category, messageOrFunc) {
7
+ // Check global trace setting (evaluated dynamically for runtime changes)
8
+ const TRACE_ENV = process.env.COMMAND_STREAM_TRACE;
9
+ const VERBOSE_ENV = process.env.COMMAND_STREAM_VERBOSE === 'true';
10
+
11
+ // COMMAND_STREAM_TRACE=false explicitly disables tracing even if COMMAND_STREAM_VERBOSE=true
12
+ // COMMAND_STREAM_TRACE=true explicitly enables tracing
13
+ // Otherwise, use COMMAND_STREAM_VERBOSE
14
+ const VERBOSE =
15
+ TRACE_ENV === 'false' ? false : TRACE_ENV === 'true' ? true : VERBOSE_ENV;
16
+
6
17
  if (!VERBOSE) {
7
18
  return;
8
19
  }
20
+
9
21
  const message =
10
22
  typeof messageOrFunc === 'function' ? messageOrFunc() : messageOrFunc;
11
23
  const timestamp = new Date().toISOString();
@@ -2,7 +2,7 @@ import fs from 'fs';
2
2
  import path from 'path';
3
3
  import { trace, VirtualUtils } from '../$.utils.mjs';
4
4
 
5
- export default async function cp({ args, stdin, cwd }) {
5
+ export default async function cp({ args, stdin: _stdin, cwd }) {
6
6
  const argError = VirtualUtils.validateArgs(args, 2, 'cp');
7
7
  if (argError) {
8
8
  return VirtualUtils.invalidArgumentError(
@@ -1,6 +1,6 @@
1
1
  import { VirtualUtils } from '../$.utils.mjs';
2
2
 
3
- export default async function env({ args, stdin, env }) {
3
+ export default async function env({ args, stdin: _stdin, env }) {
4
4
  if (args.length === 0) {
5
5
  // Use custom env if provided, otherwise use process.env
6
6
  const envVars = env || process.env;
@@ -2,7 +2,7 @@ import fs from 'fs';
2
2
  import path from 'path';
3
3
  import { trace, VirtualUtils } from '../$.utils.mjs';
4
4
 
5
- export default async function ls({ args, stdin, cwd }) {
5
+ export default async function ls({ args, stdin: _stdin, cwd }) {
6
6
  try {
7
7
  // Parse flags
8
8
  const flags = new Set();
@@ -1,7 +1,7 @@
1
1
  import fs from 'fs';
2
2
  import { trace, VirtualUtils } from '../$.utils.mjs';
3
3
 
4
- export default async function mkdir({ args, stdin, cwd }) {
4
+ export default async function mkdir({ args, stdin: _stdin, cwd }) {
5
5
  const argError = VirtualUtils.validateArgs(args, 1, 'mkdir');
6
6
  if (argError) {
7
7
  return argError;
@@ -2,7 +2,7 @@ import fs from 'fs';
2
2
  import path from 'path';
3
3
  import { trace, VirtualUtils } from '../$.utils.mjs';
4
4
 
5
- export default async function mv({ args, stdin, cwd }) {
5
+ export default async function mv({ args, stdin: _stdin, cwd }) {
6
6
  const argError = VirtualUtils.validateArgs(args, 2, 'mv');
7
7
  if (argError) {
8
8
  return VirtualUtils.invalidArgumentError(
@@ -62,7 +62,7 @@ export default async function mv({ args, stdin, cwd }) {
62
62
  const sourcePath = VirtualUtils.resolvePath(source, cwd);
63
63
 
64
64
  try {
65
- const sourceStats = fs.statSync(sourcePath);
65
+ const _sourceStats = fs.statSync(sourcePath);
66
66
  let finalDestPath = destPath;
67
67
 
68
68
  if (destIsDir) {
@@ -1,6 +1,6 @@
1
1
  import { trace, VirtualUtils } from '../$.utils.mjs';
2
2
 
3
- export default async function pwd({ args, stdin, cwd }) {
3
+ export default async function pwd({ args: _args, stdin: _stdin, cwd }) {
4
4
  // If cwd option is provided, return that instead of process.cwd()
5
5
  const dir = cwd || process.cwd();
6
6
  trace(
@@ -1,7 +1,7 @@
1
1
  import fs from 'fs';
2
2
  import { trace, VirtualUtils } from '../$.utils.mjs';
3
3
 
4
- export default async function rm({ args, stdin, cwd }) {
4
+ export default async function rm({ args, stdin: _stdin, cwd }) {
5
5
  const argError = VirtualUtils.validateArgs(args, 1, 'rm');
6
6
  if (argError) {
7
7
  return argError;
@@ -1,7 +1,7 @@
1
1
  import fs from 'fs';
2
2
  import { trace, VirtualUtils } from '../$.utils.mjs';
3
3
 
4
- export default async function touch({ args, stdin, cwd }) {
4
+ export default async function touch({ args, stdin: _stdin, cwd }) {
5
5
  const argError = VirtualUtils.validateArgs(args, 1, 'touch');
6
6
  if (argError) {
7
7
  return VirtualUtils.missingOperandError(
@@ -2,7 +2,7 @@ import { trace } from '../$.utils.mjs';
2
2
 
3
3
  export default async function* yes({
4
4
  args,
5
- stdin,
5
+ stdin: _stdin,
6
6
  isCancelled,
7
7
  abortSignal,
8
8
  ...rest