@wrongstack/tools 0.272.2 → 0.273.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/dist/audit.js.map +1 -1
- package/dist/bash.js +225 -24
- package/dist/bash.js.map +1 -1
- package/dist/builtin.js +344 -110
- package/dist/builtin.js.map +1 -1
- package/dist/codebase-index/index.js +9 -5
- package/dist/codebase-index/index.js.map +1 -1
- package/dist/codebase-index/worker.js +9 -5
- package/dist/codebase-index/worker.js.map +1 -1
- package/dist/exec.d.ts +20 -1
- package/dist/exec.js +132 -71
- package/dist/exec.js.map +1 -1
- package/dist/format.js.map +1 -1
- package/dist/index.d.ts +111 -2
- package/dist/index.js +415 -140
- package/dist/index.js.map +1 -1
- package/dist/install.js.map +1 -1
- package/dist/lint.js.map +1 -1
- package/dist/outdated.js.map +1 -1
- package/dist/pack.js +344 -110
- package/dist/pack.js.map +1 -1
- package/dist/replace.js +2 -2
- package/dist/replace.js.map +1 -1
- package/dist/test.js.map +1 -1
- package/dist/typecheck.js.map +1 -1
- package/package.json +2 -2
package/dist/bash.js
CHANGED
|
@@ -2,6 +2,7 @@ import { spawn } from 'node:child_process';
|
|
|
2
2
|
import * as os2 from 'node:os';
|
|
3
3
|
import * as Core from '@wrongstack/core';
|
|
4
4
|
import { buildChildEnv, expectDefined, wstackGlobalRoot } from '@wrongstack/core';
|
|
5
|
+
import * as fs2 from 'node:fs';
|
|
5
6
|
import { mkdirSync, createWriteStream } from 'node:fs';
|
|
6
7
|
import * as fs from 'node:fs/promises';
|
|
7
8
|
import * as path from 'node:path';
|
|
@@ -699,6 +700,21 @@ function getProcessRegistry() {
|
|
|
699
700
|
return _registry;
|
|
700
701
|
}
|
|
701
702
|
var REGISTRY_FILE = ".wrongstack/process-registry.json";
|
|
703
|
+
function toErrorMessage(err) {
|
|
704
|
+
return err instanceof Error ? err.message : String(err);
|
|
705
|
+
}
|
|
706
|
+
function emitStructuredLog(level, event, message, error) {
|
|
707
|
+
const payload = {
|
|
708
|
+
level,
|
|
709
|
+
event,
|
|
710
|
+
message,
|
|
711
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
712
|
+
};
|
|
713
|
+
if (error !== void 0) {
|
|
714
|
+
payload.error = toErrorMessage(error);
|
|
715
|
+
}
|
|
716
|
+
console.log(JSON.stringify(payload));
|
|
717
|
+
}
|
|
702
718
|
var HEARTBEAT_INTERVAL_MS = 5e3;
|
|
703
719
|
var STALE_THRESHOLD_MS = 3e4;
|
|
704
720
|
var LOCKFILE = ".wrongstack/.process-registry.lock";
|
|
@@ -708,6 +724,9 @@ function generateInstanceId() {
|
|
|
708
724
|
const random = Math.random().toString(36).slice(2, 8);
|
|
709
725
|
return `${hostname2}:${pid}:${random}`;
|
|
710
726
|
}
|
|
727
|
+
function isNodeError(err) {
|
|
728
|
+
return typeof err === "object" && err !== null && "code" in err;
|
|
729
|
+
}
|
|
711
730
|
async function acquireLock(lockfilePath, timeoutMs = 5e3) {
|
|
712
731
|
const start = Date.now();
|
|
713
732
|
const pidStr = String(process.pid);
|
|
@@ -722,7 +741,7 @@ async function acquireLock(lockfilePath, timeoutMs = 5e3) {
|
|
|
722
741
|
}
|
|
723
742
|
};
|
|
724
743
|
} catch (err) {
|
|
725
|
-
if (err.code === "EEXIST") {
|
|
744
|
+
if (isNodeError(err) && err.code === "EEXIST") {
|
|
726
745
|
try {
|
|
727
746
|
const content = await fs.readFile(lockfilePath, "utf-8");
|
|
728
747
|
const parts = content.split(":");
|
|
@@ -759,7 +778,7 @@ async function readRegistryFile(filePath) {
|
|
|
759
778
|
}
|
|
760
779
|
return parsed;
|
|
761
780
|
} catch (err) {
|
|
762
|
-
if (err.code === "ENOENT") {
|
|
781
|
+
if (isNodeError(err) && err.code === "ENOENT") {
|
|
763
782
|
return {
|
|
764
783
|
version: 1,
|
|
765
784
|
instances: /* @__PURE__ */ new Map(),
|
|
@@ -795,7 +814,7 @@ var PersistentProcessRegistry = class {
|
|
|
795
814
|
this.lockPath = path.join(homeDir, LOCKFILE);
|
|
796
815
|
this.baseRegistry = baseRegistry ?? getProcessRegistry();
|
|
797
816
|
this.ensureDirectory().catch((err) => {
|
|
798
|
-
|
|
817
|
+
emitStructuredLog("warn", "process_registry.dir_create_failed", "PersistentProcessRegistry: failed to create .wrongstack directory", err);
|
|
799
818
|
});
|
|
800
819
|
}
|
|
801
820
|
async ensureDirectory() {
|
|
@@ -803,7 +822,7 @@ var PersistentProcessRegistry = class {
|
|
|
803
822
|
try {
|
|
804
823
|
await fs.mkdir(dir, { recursive: true });
|
|
805
824
|
} catch (err) {
|
|
806
|
-
if (err.code !== "EEXIST") throw err;
|
|
825
|
+
if (!isNodeError(err) || err.code !== "EEXIST") throw err;
|
|
807
826
|
}
|
|
808
827
|
}
|
|
809
828
|
/**
|
|
@@ -883,6 +902,7 @@ var PersistentProcessRegistry = class {
|
|
|
883
902
|
try {
|
|
884
903
|
const data = await readRegistryFile(this.registryPath);
|
|
885
904
|
data.instances.set(String(entry.pid), entry);
|
|
905
|
+
const child = null;
|
|
886
906
|
this.baseRegistry.register({
|
|
887
907
|
pid: entry.pid,
|
|
888
908
|
name: entry.name,
|
|
@@ -890,8 +910,7 @@ var PersistentProcessRegistry = class {
|
|
|
890
910
|
startedAt: entry.startedAt,
|
|
891
911
|
sessionId: entry.sessionId,
|
|
892
912
|
protected: entry.protected,
|
|
893
|
-
child
|
|
894
|
-
// Main process has no child handle
|
|
913
|
+
child
|
|
895
914
|
});
|
|
896
915
|
await writeRegistryFile(this.registryPath, data);
|
|
897
916
|
} finally {
|
|
@@ -939,7 +958,7 @@ var PersistentProcessRegistry = class {
|
|
|
939
958
|
data.lastCleanup = now;
|
|
940
959
|
await writeRegistryFile(this.registryPath, data);
|
|
941
960
|
} catch (err) {
|
|
942
|
-
|
|
961
|
+
emitStructuredLog("warn", "process_registry.sync_failed", "PersistentProcessRegistry: sync failed", err);
|
|
943
962
|
} finally {
|
|
944
963
|
await release();
|
|
945
964
|
}
|
|
@@ -960,7 +979,11 @@ var PersistentProcessRegistry = class {
|
|
|
960
979
|
if (process.platform !== "win32") {
|
|
961
980
|
process.kill(entry.pid, 0);
|
|
962
981
|
} else {
|
|
963
|
-
|
|
982
|
+
emitStructuredLog(
|
|
983
|
+
"debug",
|
|
984
|
+
"process_registry.stale_pid_check",
|
|
985
|
+
`PersistentProcessRegistry: checking stale pid ${entry.pid} (${age}ms old)`
|
|
986
|
+
);
|
|
964
987
|
}
|
|
965
988
|
} catch {
|
|
966
989
|
stalePids.push(_pidStr);
|
|
@@ -974,7 +997,7 @@ var PersistentProcessRegistry = class {
|
|
|
974
997
|
await writeRegistryFile(this.registryPath, data);
|
|
975
998
|
}
|
|
976
999
|
} catch (err) {
|
|
977
|
-
|
|
1000
|
+
emitStructuredLog("warn", "process_registry.cleanup_failed", "PersistentProcessRegistry: cleanup failed", err);
|
|
978
1001
|
} finally {
|
|
979
1002
|
await release();
|
|
980
1003
|
}
|
|
@@ -1197,7 +1220,7 @@ async function isKillProtected(kill) {
|
|
|
1197
1220
|
const entries = await getProtectedEntries();
|
|
1198
1221
|
const killNameLower = kill.name.toLowerCase();
|
|
1199
1222
|
for (const entry of entries) {
|
|
1200
|
-
if (entry.name
|
|
1223
|
+
if (entry.name?.toLowerCase().includes(killNameLower)) {
|
|
1201
1224
|
return true;
|
|
1202
1225
|
}
|
|
1203
1226
|
}
|
|
@@ -1252,6 +1275,145 @@ async function checkAndBlockKillCommand(command) {
|
|
|
1252
1275
|
}
|
|
1253
1276
|
return { blocked: false };
|
|
1254
1277
|
}
|
|
1278
|
+
function pickShell(platform3, command, env) {
|
|
1279
|
+
const override = env.get("WRONGSTACK_SHELL")?.trim().toLowerCase();
|
|
1280
|
+
if (override === "cmd" || override === "cmd.exe") return "cmd";
|
|
1281
|
+
if (override === "powershell" || override === "powershell.exe") return "powershell";
|
|
1282
|
+
if (override === "pwsh" || override === "pwsh.exe") return "pwsh";
|
|
1283
|
+
if (looksLikePowerShell(command)) return "pwsh";
|
|
1284
|
+
return "cmd";
|
|
1285
|
+
}
|
|
1286
|
+
function looksLikePowerShell(command) {
|
|
1287
|
+
if (!command) return false;
|
|
1288
|
+
const trimmed = command.trimStart();
|
|
1289
|
+
if (/\.ps1\b/i.test(trimmed)) return true;
|
|
1290
|
+
if (/^\s*#requires\s/i.test(trimmed)) return true;
|
|
1291
|
+
if (/^\s*param\s*\(/i.test(trimmed)) return true;
|
|
1292
|
+
if (/\$[\w:{]/i.test(trimmed)) return true;
|
|
1293
|
+
if (/\$\(/.test(trimmed)) return true;
|
|
1294
|
+
if (/@\s*['"]/.test(trimmed)) return true;
|
|
1295
|
+
if (/&\s+\$/.test(trimmed)) return true;
|
|
1296
|
+
if (/(^|\s)@\s*\(/.test(trimmed)) return true;
|
|
1297
|
+
if (/(^|\s)@\{/.test(trimmed)) return true;
|
|
1298
|
+
if (/(?:^|[\s\[\(\{,;])(?:-eq|-ne|-lt|-gt|-le|-ge|-like|-notlike|-match|-notmatch|-contains|-notcontains|-in|-notin|-and|-or|-not|-band|-bor|-bxor|-replace|-isplit|-csplit|-osplit|-join|-is|-as|-f)(?:$|[\s\]\)\},;])/i.test(trimmed)) {
|
|
1299
|
+
return true;
|
|
1300
|
+
}
|
|
1301
|
+
if (PS_VERB_RE.test(trimmed)) return true;
|
|
1302
|
+
if (/(?:^|[\s;&|])(gci|gi|gp|gcm|gps|sl|rm|cat|cp|mv)\b/i.test(trimmed)) {
|
|
1303
|
+
return true;
|
|
1304
|
+
}
|
|
1305
|
+
if (looksLikePowerShellExtended(command)) return true;
|
|
1306
|
+
return false;
|
|
1307
|
+
}
|
|
1308
|
+
function looksLikePowerShellExtended(command) {
|
|
1309
|
+
if (!command) return false;
|
|
1310
|
+
const trimmed = command.trimStart();
|
|
1311
|
+
if (/(?:^|\s)[-/](?:WhatIf|Confirm|ErrorAction)(?::[^\s]+|\s|=|$)/i.test(trimmed)) {
|
|
1312
|
+
return true;
|
|
1313
|
+
}
|
|
1314
|
+
if (/(?:^|[\s;&|])(Where-Object|ForEach-Object|Select-Object|Sort-Object|Group-Object|Measure-Object|Compare-Object|Tee-Object)(?:\s|$)/i.test(trimmed)) {
|
|
1315
|
+
return true;
|
|
1316
|
+
}
|
|
1317
|
+
if (/\bWrite-(?:Host|Output|Error|Warning|Verbose|Debug|Information)(?:\s|$)/i.test(trimmed)) {
|
|
1318
|
+
return true;
|
|
1319
|
+
}
|
|
1320
|
+
if (/HK(?:LM|CU|CR|U|CC|DD|PD):\\/i.test(trimmed)) return true;
|
|
1321
|
+
if (/\[(?:string|int|bool|xml|double|float|decimal|char|byte|long|System\.)/i.test(trimmed)) {
|
|
1322
|
+
return true;
|
|
1323
|
+
}
|
|
1324
|
+
if (/^\s*<#|#>\s*$/m.test(trimmed)) return true;
|
|
1325
|
+
if (/(?:^|\s)[-/\/](?:AsPlainText|PipelineVariable|pv|FilterHashtable|OutVariable|ov)(?:\s|=|$)/i.test(trimmed)) {
|
|
1326
|
+
return true;
|
|
1327
|
+
}
|
|
1328
|
+
return false;
|
|
1329
|
+
}
|
|
1330
|
+
function wrapPowerShellScript(command) {
|
|
1331
|
+
const bootstrap = "[Console]::OutputEncoding = [System.Text.Encoding]::UTF8;$ConfirmPreference='None';$WhatIfPreference=$false";
|
|
1332
|
+
return "\uFEFF" + bootstrap + "\ntry {\n" + command + "\n} finally { exit $LASTEXITCODE }";
|
|
1333
|
+
}
|
|
1334
|
+
var PS_VERB_RE = new RegExp(
|
|
1335
|
+
// Boundaries: start-of-string, whitespace, `;`, `&`, `|`, `(`, `{`, `,`.
|
|
1336
|
+
"(?:^|[\\s;&|\\(\\{,])(?:Get|Set|New|Remove|Add|Clear|Copy|Move|Rename|Test|Update|Write|Read|Push|Pop|Invoke|Start|Stop|Wait|Out|Format|Group|Measure|Compare|Resolve|ConvertTo|ConvertFrom|Convert|Import|Export|Select|Where|ForEach|Sort|Tee|Split|Join|Limit|Skip|Step|Trace|Debug|Register|Unregister|Enable|Disable|Restart|Suspend|Resume|Save|Open|Close|Lock|Unlock|Mount|Dismount|Enter|Exit|Use|Show|Hide|Find|Search|Watch|Initialize|Optimize|Compress|Expand|Merge|Checkpoint|Undo|Redo|Approve|Deny|Block|Grant|Revoke|Assert|Confirm|Receive|Send|Connect|Disconnect|Reset|Backup|Restore|Publish|Unpublish|Install|Uninstall|Build|Rebuild|Deploy|Submit|Process|Complete|Approve|Revoke|Pay|Refund|Decline|Receive|Send)-[A-Za-z][A-Za-z0-9]+(?:[\\-\\+][A-Za-z][A-Za-z0-9]+)*(?:$|[\\s\\-\\;\\&\\|\\(\\)\\{\\},])",
|
|
1337
|
+
"i"
|
|
1338
|
+
);
|
|
1339
|
+
function shellArgs(shell) {
|
|
1340
|
+
if (shell === "powershell" || shell === "pwsh") {
|
|
1341
|
+
return ["-NoLogo", "-NoProfile", "-NonInteractive", "-Command", "-"];
|
|
1342
|
+
}
|
|
1343
|
+
return ["/c"];
|
|
1344
|
+
}
|
|
1345
|
+
function diagnoseBashism(command, shell) {
|
|
1346
|
+
if (!command) return void 0;
|
|
1347
|
+
const isCmd = shell === "cmd";
|
|
1348
|
+
const hints = [];
|
|
1349
|
+
const add = (h) => {
|
|
1350
|
+
if (!hints.includes(h)) hints.push(h);
|
|
1351
|
+
};
|
|
1352
|
+
if (/\/dev\/null/.test(command)) {
|
|
1353
|
+
add(
|
|
1354
|
+
isCmd ? "use `nul` instead of `/dev/null` (e.g. `2>nul`)" : "use `$null` instead of `/dev/null` (e.g. `2>$null`)"
|
|
1355
|
+
);
|
|
1356
|
+
}
|
|
1357
|
+
if (/(^|[;&|]\s*)export\s+[A-Za-z_]\w*=/.test(command)) {
|
|
1358
|
+
add(
|
|
1359
|
+
isCmd ? "set env vars with `set NAME=value`, not `export`" : "set env vars with `$env:NAME = 'value'`, not `export`"
|
|
1360
|
+
);
|
|
1361
|
+
}
|
|
1362
|
+
if (/<<-?\s*['"]?[A-Za-z_]\w*/.test(command)) {
|
|
1363
|
+
add(
|
|
1364
|
+
isCmd ? "cmd has no heredocs \u2014 write the content to a file or use multiple `echo` lines" : "PowerShell has no heredocs \u2014 use a single-quoted here-string `@'\u2026'@` (closing `'@` at column 0)"
|
|
1365
|
+
);
|
|
1366
|
+
}
|
|
1367
|
+
if (shell === "powershell" && /(&&|\|\|)/.test(command)) {
|
|
1368
|
+
add("Windows PowerShell 5.1 has no `&&`/`||` \u2014 separate commands with `;` (check `$LASTEXITCODE`)");
|
|
1369
|
+
}
|
|
1370
|
+
if (/\brm\s+-[A-Za-z]*[rf]/.test(command)) {
|
|
1371
|
+
add(
|
|
1372
|
+
isCmd ? "`rm` is not a cmd builtin \u2014 use `del` (files) or `rmdir /s /q` (dirs)" : "use `Remove-Item -Recurse -Force` \u2014 the `rm -rf` bash flags don't exist in PowerShell"
|
|
1373
|
+
);
|
|
1374
|
+
}
|
|
1375
|
+
if (/\bwhich\s+\S/.test(command)) {
|
|
1376
|
+
add(isCmd ? "use `where <cmd>` instead of `which`" : "use `Get-Command <cmd>` instead of `which`");
|
|
1377
|
+
}
|
|
1378
|
+
if (hints.length === 0) return void 0;
|
|
1379
|
+
const label = isCmd ? "cmd.exe" : shell === "pwsh" ? "PowerShell 7" : "Windows PowerShell";
|
|
1380
|
+
return `[wrongstack] This command failed and contains bash/POSIX syntax that ${label} does not accept \u2014 ${hints.join("; ")}. Rewrite it in ${isCmd ? "cmd" : "PowerShell"} syntax and retry.`;
|
|
1381
|
+
}
|
|
1382
|
+
function resolveWin32Command(cmd) {
|
|
1383
|
+
if (process.platform !== "win32") return cmd;
|
|
1384
|
+
if (cmd.includes("/") || cmd.includes("\\") || path.extname(cmd.replace(/\//g, "\\"))) {
|
|
1385
|
+
return cmd;
|
|
1386
|
+
}
|
|
1387
|
+
const pathext = (process.env["PATHEXT"] ?? ".COM;.EXE;.BAT;.CMD;.VBS;.JS;.WS;.MSC").toLowerCase().split(";");
|
|
1388
|
+
const pathDirs = (process.env["PATH"] ?? "").split(path.delimiter);
|
|
1389
|
+
for (const dir of pathDirs) {
|
|
1390
|
+
const base = path.join(dir, cmd);
|
|
1391
|
+
for (const ext of pathext) {
|
|
1392
|
+
const full = `${base}${ext}`;
|
|
1393
|
+
try {
|
|
1394
|
+
fs2.accessSync(full, fs2.constants.X_OK);
|
|
1395
|
+
return full;
|
|
1396
|
+
} catch {
|
|
1397
|
+
}
|
|
1398
|
+
}
|
|
1399
|
+
}
|
|
1400
|
+
return cmd;
|
|
1401
|
+
}
|
|
1402
|
+
function resolvePowerShell(cmd) {
|
|
1403
|
+
if (process.platform !== "win32") return cmd;
|
|
1404
|
+
const lower = cmd.toLowerCase();
|
|
1405
|
+
if (lower !== "pwsh" && lower !== "powershell" && lower !== "pwsh.exe" && lower !== "powershell.exe") {
|
|
1406
|
+
return resolveWin32Command(cmd);
|
|
1407
|
+
}
|
|
1408
|
+
const primary = lower.startsWith("pwsh") ? "pwsh.exe" : "powershell.exe";
|
|
1409
|
+
const fallback = lower.startsWith("pwsh") ? "powershell.exe" : "pwsh.exe";
|
|
1410
|
+
const resolved = resolveWin32Command(primary);
|
|
1411
|
+
if (resolved !== primary) {
|
|
1412
|
+
const fb = resolveWin32Command(fallback);
|
|
1413
|
+
return fb === fallback ? cmd : fb;
|
|
1414
|
+
}
|
|
1415
|
+
return resolved;
|
|
1416
|
+
}
|
|
1255
1417
|
|
|
1256
1418
|
// src/bash.ts
|
|
1257
1419
|
var MAX_OUTPUT = 32768;
|
|
@@ -1348,18 +1510,36 @@ var bashTool = {
|
|
|
1348
1510
|
}
|
|
1349
1511
|
const timeoutMs = Math.max(1, Math.min(input.timeout_ms ?? DEFAULT_TIMEOUT_MS, 6e5));
|
|
1350
1512
|
const isWin = os2.platform() === "win32";
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1513
|
+
let plan;
|
|
1514
|
+
let winShellKind;
|
|
1515
|
+
if (isWin) {
|
|
1516
|
+
const shell2 = pickShell("win32", input.command, {
|
|
1517
|
+
get: (k) => process.env[k]
|
|
1518
|
+
});
|
|
1519
|
+
winShellKind = shell2;
|
|
1520
|
+
const bin = shell2 === "powershell" ? resolvePowerShell("powershell.exe") : shell2 === "pwsh" ? resolvePowerShell("pwsh.exe") : process.env["COMSPEC"] ?? "cmd.exe";
|
|
1521
|
+
plan = {
|
|
1522
|
+
bin,
|
|
1523
|
+
argv: shellArgs(shell2),
|
|
1524
|
+
useStdin: shell2 === "powershell" || shell2 === "pwsh",
|
|
1525
|
+
stdinBody: shell2 === "powershell" || shell2 === "pwsh" ? wrapPowerShellScript(input.command) : void 0
|
|
1526
|
+
};
|
|
1527
|
+
} else {
|
|
1528
|
+
const explicit = process.env["WRONGSTACK_SHELL"];
|
|
1529
|
+
let bin;
|
|
1530
|
+
if (explicit) bin = explicit;
|
|
1531
|
+
else {
|
|
1532
|
+
const fromEnv = process.env["SHELL"];
|
|
1533
|
+
if (fromEnv) {
|
|
1534
|
+
const name = fromEnv.split("/").pop() ?? "";
|
|
1535
|
+
if (["bash", "zsh", "sh", "dash", "fish"].includes(name)) bin = fromEnv;
|
|
1536
|
+
else bin = "/bin/bash";
|
|
1537
|
+
} else bin = "/bin/bash";
|
|
1359
1538
|
}
|
|
1360
|
-
|
|
1361
|
-
}
|
|
1362
|
-
const
|
|
1539
|
+
plan = { bin, argv: ["-c"], useStdin: false, stdinBody: void 0 };
|
|
1540
|
+
}
|
|
1541
|
+
const shell = plan.bin;
|
|
1542
|
+
const args = plan.useStdin ? [...plan.argv] : [...plan.argv, input.command];
|
|
1363
1543
|
const env = buildChildEnv(ctx.session?.id);
|
|
1364
1544
|
const detached = !isWin;
|
|
1365
1545
|
const startedAt = Date.now();
|
|
@@ -1369,7 +1549,9 @@ var bashTool = {
|
|
|
1369
1549
|
const child2 = spawn(shell, args, {
|
|
1370
1550
|
cwd: ctx.projectRoot,
|
|
1371
1551
|
env,
|
|
1372
|
-
|
|
1552
|
+
// PowerShell takes the script on stdin (no argv quoting); cmd.exe
|
|
1553
|
+
// and POSIX shells ignore stdin when given the command inline.
|
|
1554
|
+
stdio: [plan.useStdin ? "pipe" : "ignore", "pipe", "pipe"],
|
|
1373
1555
|
// win32: CreateProcess IGNORES CREATE_NO_WINDOW (windowsHide) when
|
|
1374
1556
|
// DETACHED_PROCESS (detached: true) is set, so the console-less
|
|
1375
1557
|
// cmd.exe's grandchildren (node, dev servers) each allocate a fresh
|
|
@@ -1380,6 +1562,13 @@ var bashTool = {
|
|
|
1380
1562
|
detached: !isWin,
|
|
1381
1563
|
windowsHide: true
|
|
1382
1564
|
});
|
|
1565
|
+
if (plan.useStdin) {
|
|
1566
|
+
try {
|
|
1567
|
+
child2.stdin?.write(plan.stdinBody ?? input.command);
|
|
1568
|
+
child2.stdin?.end();
|
|
1569
|
+
} catch {
|
|
1570
|
+
}
|
|
1571
|
+
}
|
|
1383
1572
|
const pid2 = child2.pid;
|
|
1384
1573
|
if (typeof pid2 === "number") {
|
|
1385
1574
|
registry.register({
|
|
@@ -1434,11 +1623,20 @@ var bashTool = {
|
|
|
1434
1623
|
const child = spawn(shell, args, {
|
|
1435
1624
|
cwd: ctx.projectRoot,
|
|
1436
1625
|
env,
|
|
1437
|
-
|
|
1626
|
+
// PowerShell takes the script on stdin (no argv quoting); cmd.exe
|
|
1627
|
+
// and POSIX shells ignore stdin when given the command inline.
|
|
1628
|
+
stdio: [plan.useStdin ? "pipe" : "ignore", "pipe", "pipe"],
|
|
1438
1629
|
detached,
|
|
1439
1630
|
windowsHide: true,
|
|
1440
1631
|
...isWin ? {} : { signal: opts.signal }
|
|
1441
1632
|
});
|
|
1633
|
+
if (plan.useStdin) {
|
|
1634
|
+
try {
|
|
1635
|
+
child.stdin?.write(plan.stdinBody ?? input.command);
|
|
1636
|
+
child.stdin?.end();
|
|
1637
|
+
} catch {
|
|
1638
|
+
}
|
|
1639
|
+
}
|
|
1442
1640
|
const pid = child.pid;
|
|
1443
1641
|
if (typeof pid === "number") {
|
|
1444
1642
|
registry.register({
|
|
@@ -1589,10 +1787,13 @@ var bashTool = {
|
|
|
1589
1787
|
yield { type: "partial_output", text: remainder };
|
|
1590
1788
|
}
|
|
1591
1789
|
const spooled = spool.finalize();
|
|
1790
|
+
const hint = !timedOut && typeof c.code === "number" && c.code !== 0 && winShellKind ? diagnoseBashism(input.command, winShellKind) : void 0;
|
|
1592
1791
|
yield {
|
|
1593
1792
|
type: "final",
|
|
1594
1793
|
output: {
|
|
1595
|
-
output: normalizeCommandOutput(buf) + (spooled ? spoolNote(spooled) : "")
|
|
1794
|
+
output: normalizeCommandOutput(buf) + (spooled ? spoolNote(spooled) : "") + (hint ? `
|
|
1795
|
+
|
|
1796
|
+
${hint}` : ""),
|
|
1596
1797
|
exit_code: c.code,
|
|
1597
1798
|
timed_out: timedOut
|
|
1598
1799
|
}
|