fauxnix-cli 0.11.0 → 0.12.0
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 +52 -28
- package/dist/cli.d.ts +2 -1
- package/dist/cli.js +61 -21
- package/dist/commands/archive.js +87 -24
- package/dist/commands/install-all.js +2 -1
- package/dist/commands/net.d.ts +9 -0
- package/dist/commands/net.js +51 -15
- package/dist/commands/sysinfo.d.ts +2 -1
- package/dist/commands/sysinfo.js +564 -72
- package/dist/commands/text-filters.js +36 -11
- package/dist/commands/text-io.js +72 -43
- package/dist/doctor.d.ts +1 -0
- package/dist/doctor.js +44 -3
- package/dist/errors.js +14 -4
- package/dist/executor.d.ts +4 -1
- package/dist/executor.js +194 -51
- package/dist/install.js +43 -2
- package/dist/mcp.d.ts +13 -0
- package/dist/mcp.js +15 -14
- package/dist/parser.js +11 -3
- package/dist/powershell.d.ts +22 -0
- package/dist/powershell.js +129 -0
- package/dist/ps-host.d.ts +41 -13
- package/dist/ps-host.js +302 -40
- package/dist/qwen-launch.d.ts +12 -0
- package/dist/qwen-launch.js +29 -0
- package/dist/registry.d.ts +22 -0
- package/dist/registry.js +109 -1
- package/dist/translator.d.ts +13 -6
- package/dist/translator.js +411 -86
- package/package.json +3 -1
|
@@ -3,7 +3,7 @@ import os from 'node:os';
|
|
|
3
3
|
import path from 'node:path';
|
|
4
4
|
import { FauxnixParseError, wordToString } from '../ast.js';
|
|
5
5
|
import { parseWords, psStr } from '../registry.js';
|
|
6
|
-
import { argListExpr, exprOfWord, literalOfWord, operandExpr } from '../translator.js';
|
|
6
|
+
import { argListExpr, exprOfWord, literalOfWord, operandExpr, PURE_SED_FILE_MESSAGE, } from '../translator.js';
|
|
7
7
|
/* ------------------------------------------------------------------ */
|
|
8
8
|
/* Shared PS snippets (same shape as files.ts) */
|
|
9
9
|
/* ------------------------------------------------------------------ */
|
|
@@ -981,7 +981,7 @@ function parseSedScript(src, isEre) {
|
|
|
981
981
|
}
|
|
982
982
|
return out;
|
|
983
983
|
}
|
|
984
|
-
const sed = (args) => {
|
|
984
|
+
const sed = (args, ctx) => {
|
|
985
985
|
// custom argv parse: -i takes an ATTACHED suffix; -e/-f take attached or next
|
|
986
986
|
const raw = args.map((w) => wordToString(w));
|
|
987
987
|
let noPrint = false;
|
|
@@ -1030,6 +1030,9 @@ const sed = (args) => {
|
|
|
1030
1030
|
throw new FauxnixParseError('fauxnix: sed -' + ch + ' requires an argument');
|
|
1031
1031
|
}
|
|
1032
1032
|
if (ch === 'f') {
|
|
1033
|
+
if (ctx.translationMode === 'pure') {
|
|
1034
|
+
throw new FauxnixParseError(PURE_SED_FILE_MESSAGE);
|
|
1035
|
+
}
|
|
1033
1036
|
try {
|
|
1034
1037
|
val = readFileSync(nodePathOf(val), 'utf8');
|
|
1035
1038
|
}
|
|
@@ -1775,20 +1778,42 @@ const awk = (args) => {
|
|
|
1775
1778
|
const { values, operandWords } = parseWords(args, ['F', 'v']);
|
|
1776
1779
|
// -v may repeat; collect all of them
|
|
1777
1780
|
const vvars = [];
|
|
1781
|
+
const addVVar = (nv) => {
|
|
1782
|
+
const eq = nv.indexOf('=');
|
|
1783
|
+
if (eq < 1) {
|
|
1784
|
+
throw new FauxnixParseError("fauxnix: awk invalid -v assignment '" + nv + "'");
|
|
1785
|
+
}
|
|
1786
|
+
const name = nv.slice(0, eq);
|
|
1787
|
+
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(name)) {
|
|
1788
|
+
throw new FauxnixParseError("fauxnix: awk invalid variable name '" + name + "'");
|
|
1789
|
+
}
|
|
1790
|
+
vvars.push([name, nv.slice(eq + 1)]);
|
|
1791
|
+
};
|
|
1792
|
+
let onlyOperands = false;
|
|
1778
1793
|
for (let i = 0; i < args.length; i++) {
|
|
1779
1794
|
const t = wordToString(args[i]);
|
|
1780
|
-
if (t === '
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1795
|
+
if (t === '--') {
|
|
1796
|
+
onlyOperands = true;
|
|
1797
|
+
continue;
|
|
1798
|
+
}
|
|
1799
|
+
if (onlyOperands)
|
|
1800
|
+
continue;
|
|
1801
|
+
if (t === '-F') {
|
|
1802
|
+
if (i + 1 < args.length)
|
|
1803
|
+
i++;
|
|
1804
|
+
continue;
|
|
1805
|
+
}
|
|
1806
|
+
if (t.startsWith('-F') && t.length > 2)
|
|
1807
|
+
continue;
|
|
1808
|
+
if (t === '-v') {
|
|
1809
|
+
if (i + 1 >= args.length) {
|
|
1810
|
+
throw new FauxnixParseError('fauxnix: awk -v requires an argument');
|
|
1811
|
+
}
|
|
1812
|
+
addVVar(wordToString(args[i + 1]));
|
|
1785
1813
|
i++;
|
|
1786
1814
|
}
|
|
1787
1815
|
else if (t.startsWith('-v') && t.length > 2) {
|
|
1788
|
-
|
|
1789
|
-
const eq = nv.indexOf('=');
|
|
1790
|
-
if (eq > 0)
|
|
1791
|
-
vvars.push([nv.slice(0, eq), nv.slice(eq + 1)]);
|
|
1816
|
+
addVVar(t.slice(2));
|
|
1792
1817
|
}
|
|
1793
1818
|
}
|
|
1794
1819
|
if (operandWords.length === 0) {
|
package/dist/commands/text-io.js
CHANGED
|
@@ -523,6 +523,20 @@ const head = (args, ctx) => {
|
|
|
523
523
|
/* ------------------------------------------------------------------ */
|
|
524
524
|
/* tail */
|
|
525
525
|
/* ------------------------------------------------------------------ */
|
|
526
|
+
/** A count embedded in generated PS must be a canonical Int32 literal. */
|
|
527
|
+
function tailCountLiteral(raw) {
|
|
528
|
+
if (!/^[+-]?\d+$/.test(raw))
|
|
529
|
+
return null;
|
|
530
|
+
try {
|
|
531
|
+
const n = BigInt(raw.replace(/^[+-]/, ''));
|
|
532
|
+
if (n > 2147483647n)
|
|
533
|
+
return null;
|
|
534
|
+
return n.toString();
|
|
535
|
+
}
|
|
536
|
+
catch {
|
|
537
|
+
return null;
|
|
538
|
+
}
|
|
539
|
+
}
|
|
526
540
|
const tail = (args, ctx) => {
|
|
527
541
|
const pre = parseWords(args);
|
|
528
542
|
if (pre.flags.has('f') || pre.flags.has('F')) {
|
|
@@ -533,9 +547,35 @@ const tail = (args, ctx) => {
|
|
|
533
547
|
let nLines = null;
|
|
534
548
|
let fromLine = null;
|
|
535
549
|
let nBytes = null;
|
|
550
|
+
let fromByte = false;
|
|
536
551
|
const operandWords = [];
|
|
537
552
|
let quiet = false;
|
|
538
553
|
let verbose = false;
|
|
554
|
+
const setCount = (kind, raw) => {
|
|
555
|
+
const literal = tailCountLiteral(raw);
|
|
556
|
+
if (literal === null) {
|
|
557
|
+
return psErrExpr(psStr("tail: invalid number of " + kind + ": '" + raw + "'"));
|
|
558
|
+
}
|
|
559
|
+
if (kind === 'bytes') {
|
|
560
|
+
nBytes = literal;
|
|
561
|
+
fromByte = raw.startsWith('+');
|
|
562
|
+
nLines = null;
|
|
563
|
+
fromLine = null;
|
|
564
|
+
}
|
|
565
|
+
else {
|
|
566
|
+
nBytes = null;
|
|
567
|
+
fromByte = false;
|
|
568
|
+
if (raw.startsWith('+')) {
|
|
569
|
+
fromLine = literal;
|
|
570
|
+
nLines = null;
|
|
571
|
+
}
|
|
572
|
+
else {
|
|
573
|
+
nLines = literal;
|
|
574
|
+
fromLine = null;
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
return null;
|
|
578
|
+
};
|
|
539
579
|
{
|
|
540
580
|
let i = 0;
|
|
541
581
|
let onlyOps = false;
|
|
@@ -567,12 +607,9 @@ const tail = (args, ctx) => {
|
|
|
567
607
|
else {
|
|
568
608
|
i++;
|
|
569
609
|
}
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
fromLine = val.slice(1);
|
|
574
|
-
else
|
|
575
|
-
nLines = val.replace(/^-/, '');
|
|
610
|
+
const err = setCount(name === '--bytes' ? 'bytes' : 'lines', val);
|
|
611
|
+
if (err !== null)
|
|
612
|
+
return err;
|
|
576
613
|
continue;
|
|
577
614
|
}
|
|
578
615
|
if (name === '--quiet' || name === '--silent') {
|
|
@@ -589,49 +626,45 @@ const tail = (args, ctx) => {
|
|
|
589
626
|
continue;
|
|
590
627
|
}
|
|
591
628
|
let m;
|
|
592
|
-
if (t === '-n' || t === '-c') {
|
|
593
|
-
const val = i + 1 < args.length ? wordToString(args[i + 1]) : null;
|
|
594
|
-
if (val === null) {
|
|
595
|
-
return psErrExpr(psStr('tail: option requires an argument -- ' + t.slice(1)));
|
|
596
|
-
}
|
|
597
|
-
if (t === '-c')
|
|
598
|
-
nBytes = val;
|
|
599
|
-
else if (val.startsWith('+'))
|
|
600
|
-
fromLine = val.slice(1);
|
|
601
|
-
else
|
|
602
|
-
nLines = val.replace(/^-/, ''); // -n -N ≡ -n N (last N)
|
|
603
|
-
i += 2;
|
|
604
|
-
continue;
|
|
605
|
-
}
|
|
606
|
-
if ((m = t.match(/^-[nc](.*)$/)) !== null) {
|
|
607
|
-
const val = m[1];
|
|
608
|
-
if (t[1] === 'c')
|
|
609
|
-
nBytes = val;
|
|
610
|
-
else if (val.startsWith('+'))
|
|
611
|
-
fromLine = val.slice(1);
|
|
612
|
-
else
|
|
613
|
-
nLines = val.replace(/^-/, '');
|
|
614
|
-
i++;
|
|
615
|
-
continue;
|
|
616
|
-
}
|
|
617
629
|
if ((m = t.match(/^-(\d+)$/)) !== null) {
|
|
618
|
-
|
|
630
|
+
const err = setCount('lines', t);
|
|
631
|
+
if (err !== null)
|
|
632
|
+
return err;
|
|
619
633
|
i++;
|
|
620
634
|
continue;
|
|
621
635
|
}
|
|
622
636
|
if ((m = t.match(/^\+(\d+)$/)) !== null) {
|
|
623
|
-
|
|
637
|
+
const err = setCount('lines', t);
|
|
638
|
+
if (err !== null)
|
|
639
|
+
return err;
|
|
624
640
|
i++;
|
|
625
641
|
continue;
|
|
626
642
|
}
|
|
627
643
|
if (t.startsWith('-') && t.length > 1) {
|
|
628
|
-
|
|
644
|
+
const body = t.slice(1);
|
|
645
|
+
let usedNext = false;
|
|
646
|
+
for (let c = 0; c < body.length; c++) {
|
|
647
|
+
const ch = body[c];
|
|
629
648
|
if (ch === 'q')
|
|
630
649
|
quiet = true;
|
|
631
650
|
else if (ch === 'v')
|
|
632
651
|
verbose = true;
|
|
652
|
+
else if (ch === 'n' || ch === 'c') {
|
|
653
|
+
let val = body.slice(c + 1);
|
|
654
|
+
if (val === '') {
|
|
655
|
+
if (i + 1 >= args.length) {
|
|
656
|
+
return psErrExpr(psStr('tail: option requires an argument -- ' + ch));
|
|
657
|
+
}
|
|
658
|
+
val = wordToString(args[i + 1]);
|
|
659
|
+
usedNext = true;
|
|
660
|
+
}
|
|
661
|
+
const err = setCount(ch === 'c' ? 'bytes' : 'lines', val);
|
|
662
|
+
if (err !== null)
|
|
663
|
+
return err;
|
|
664
|
+
break;
|
|
665
|
+
}
|
|
633
666
|
}
|
|
634
|
-
i
|
|
667
|
+
i += usedNext ? 2 : 1;
|
|
635
668
|
continue;
|
|
636
669
|
}
|
|
637
670
|
operandWords.push(args[i]);
|
|
@@ -639,13 +672,7 @@ const tail = (args, ctx) => {
|
|
|
639
672
|
}
|
|
640
673
|
}
|
|
641
674
|
const bytesMode = nBytes !== null;
|
|
642
|
-
const countLit = bytesMode
|
|
643
|
-
? nBytes
|
|
644
|
-
: fromLine !== null
|
|
645
|
-
? fromLine
|
|
646
|
-
: nLines !== null
|
|
647
|
-
? nLines
|
|
648
|
-
: '10';
|
|
675
|
+
const countLit = bytesMode ? nBytes : fromLine ?? nLines ?? '10';
|
|
649
676
|
const lines = [
|
|
650
677
|
PS_GLOB_FN,
|
|
651
678
|
PS_READTEXT_FN,
|
|
@@ -659,7 +686,9 @@ const tail = (args, ctx) => {
|
|
|
659
686
|
lines.push(STDIN_INLINES);
|
|
660
687
|
lines.push(...psCollectFiles(operandWords, (g) => qErr('tail', g, 'No such file or directory'), (g) => qErr('tail', g, 'Is a directory', 'error reading ')), '$fx_count = [int](' + countLit + ')', '$fx_from = ' + pb(fromLine !== null && !bytesMode), '$fx_hdr = ((($fx_srcs.Count -gt 1) -and ' + pb(!quiet) + ') -or ' + pb(verbose) + ')', '$fx_first = $true');
|
|
661
688
|
if (bytesMode) {
|
|
662
|
-
lines.push('$fx_out = New-Object System.Text.StringBuilder', 'for ($fx_k = 0; $fx_k -lt $fx_srcs.Count; $fx_k++) {', ' $fx_g = $fx_srcs[$fx_k]', " if ($fx_g -eq '-') { $fx_txt = (fx-stdinraw $fx_items); $fx_disp = 'standard input' }", ' else { $fx_txt = fx-read $fx_g; $fx_disp = $fx_names[$fx_k] }', ' if ($fx_hdr) {', ' if (-not $fx_first) { [void]$fx_out.Append([string][char]10) }', " [void]$fx_out.Append('==> ' + $fx_disp + ' <==' + [string][char]10)", ' }', ' $fx_first = $false',
|
|
689
|
+
lines.push('$fx_out = New-Object System.Text.StringBuilder', 'for ($fx_k = 0; $fx_k -lt $fx_srcs.Count; $fx_k++) {', ' $fx_g = $fx_srcs[$fx_k]', " if ($fx_g -eq '-') { $fx_txt = (fx-stdinraw $fx_items); $fx_disp = 'standard input' }", ' else { $fx_txt = fx-read $fx_g; $fx_disp = $fx_names[$fx_k] }', ' if ($fx_hdr) {', ' if (-not $fx_first) { [void]$fx_out.Append([string][char]10) }', " [void]$fx_out.Append('==> ' + $fx_disp + ' <==' + [string][char]10)", ' }', ' $fx_first = $false', fromByte
|
|
690
|
+
? ' $fx_st = $fx_count - 1'
|
|
691
|
+
: ' $fx_st = $fx_txt.Length - $fx_count', ' if ($fx_st -lt 0) { $fx_st = 0 }', ' if ($fx_st -lt $fx_txt.Length) { [void]$fx_out.Append($fx_txt.Substring($fx_st)) }', '}', 'fx-write $fx_out.ToString() $fx_term');
|
|
663
692
|
}
|
|
664
693
|
else {
|
|
665
694
|
lines.push('for ($fx_k = 0; $fx_k -lt $fx_srcs.Count; $fx_k++) {', ' $fx_g = $fx_srcs[$fx_k]', " if ($fx_g -eq '-') { $fx_ls = @($fx_in); $fx_disp = 'standard input' }", ' else { $fx_ls = @(fx-splitlines (fx-read $fx_g)); $fx_disp = $fx_names[$fx_k] }', ' if ($fx_hdr) {', " if (-not $fx_first) { '' }", " '==> ' + $fx_disp + ' <=='", ' }', ' $fx_first = $false', ' if ($fx_from) {', ' $fx_st = $fx_count - 1', ' if ($fx_st -lt 0) { $fx_st = 0 }', ' } else {', ' $fx_st = $fx_ls.Count - $fx_count', ' if ($fx_st -lt 0) { $fx_st = 0 }', ' }', ' for ($fx_i = $fx_st; $fx_i -lt $fx_ls.Count; $fx_i++) { $fx_ls[$fx_i] }', '}');
|
package/dist/doctor.d.ts
CHANGED
|
@@ -18,3 +18,4 @@ export declare function hasCodexFauxnix(text: string): boolean;
|
|
|
18
18
|
export declare function hasOpenCodeFauxnix(data: unknown): boolean;
|
|
19
19
|
export declare function isServerMap(value: unknown): boolean;
|
|
20
20
|
export declare function serverMapHasFauxnix(value: unknown): boolean;
|
|
21
|
+
export declare function fauxnixServerNames(value: unknown): string[];
|
package/dist/doctor.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { existsSync, readFileSync } from 'node:fs';
|
|
2
2
|
import { homedir } from 'node:os';
|
|
3
3
|
import { join } from 'node:path';
|
|
4
|
+
import { resolveQwenLaunchTuple, sameQwenLaunchTuple } from './qwen-launch.js';
|
|
4
5
|
const VALUE_INDENT = ' ';
|
|
5
6
|
export async function collectDoctorReport(opts = {}) {
|
|
6
7
|
const home = opts.home ?? homedir();
|
|
@@ -13,6 +14,7 @@ export async function collectDoctorReport(opts = {}) {
|
|
|
13
14
|
lines.push(field('claude', detectClaude(home, cwd, env)));
|
|
14
15
|
lines.push(field('codex', detectCodex(home, env)));
|
|
15
16
|
lines.push(field('opencode', detectOpenCode(home, env)));
|
|
17
|
+
lines.push(field('qwen', detectQwen(home)));
|
|
16
18
|
lines.push('');
|
|
17
19
|
const mcp = await mcpLines(nodeVersion, opts.loadMcp);
|
|
18
20
|
lines.push(...mcp.lines);
|
|
@@ -159,6 +161,41 @@ function detectOpenCode(home, env) {
|
|
|
159
161
|
return `fauxnix MCP configured (${path})`;
|
|
160
162
|
return `found ${path}, fauxnix MCP not listed — add mcp.fauxnix (see README)`;
|
|
161
163
|
}
|
|
164
|
+
function detectQwen(home) {
|
|
165
|
+
const path = join(home, '.qwen', 'settings.json');
|
|
166
|
+
if (!existsSync(path))
|
|
167
|
+
return 'not detected — see README';
|
|
168
|
+
const text = readText(path);
|
|
169
|
+
if (text === undefined)
|
|
170
|
+
return `found ${path} (unreadable) — see README`;
|
|
171
|
+
let data;
|
|
172
|
+
try {
|
|
173
|
+
data = JSON.parse(stripBom(text));
|
|
174
|
+
}
|
|
175
|
+
catch {
|
|
176
|
+
return `found ${path} (unreadable JSON) — see README`;
|
|
177
|
+
}
|
|
178
|
+
if (!data || typeof data !== 'object' || Array.isArray(data)) {
|
|
179
|
+
return `found ${path} (not a JSON object) — see README`;
|
|
180
|
+
}
|
|
181
|
+
const servers = data.mcpServers;
|
|
182
|
+
if (!isServerMap(servers)) {
|
|
183
|
+
return `found ${path}, fauxnix MCP not listed — run: fauxnix install --qwen`;
|
|
184
|
+
}
|
|
185
|
+
const extraNames = fauxnixServerNames(servers).filter((name) => name !== 'fauxnix');
|
|
186
|
+
if (extraNames.length) {
|
|
187
|
+
return `found ${path}, additional fauxnix MCP entries (${extraNames.join(', ')}) — remove them, then run: fauxnix install --qwen`;
|
|
188
|
+
}
|
|
189
|
+
const config = servers.fauxnix;
|
|
190
|
+
const expected = resolveQwenLaunchTuple();
|
|
191
|
+
if (expected.ok && sameQwenLaunchTuple(config, expected.value)) {
|
|
192
|
+
return `fauxnix MCP configured with an absolute launcher (${path})`;
|
|
193
|
+
}
|
|
194
|
+
if (config != null || serverMapHasFauxnix(servers)) {
|
|
195
|
+
return `found ${path}, fauxnix MCP launcher does not match this installation — run: fauxnix install --qwen`;
|
|
196
|
+
}
|
|
197
|
+
return `found ${path}, fauxnix MCP not listed — run: fauxnix install --qwen`;
|
|
198
|
+
}
|
|
162
199
|
export function hasOpenCodeFauxnix(data) {
|
|
163
200
|
if (!data || typeof data !== 'object' || Array.isArray(data))
|
|
164
201
|
return false;
|
|
@@ -174,15 +211,19 @@ export function isServerMap(value) {
|
|
|
174
211
|
return !!value && typeof value === 'object' && !Array.isArray(value);
|
|
175
212
|
}
|
|
176
213
|
export function serverMapHasFauxnix(value) {
|
|
214
|
+
return fauxnixServerNames(value).length > 0;
|
|
215
|
+
}
|
|
216
|
+
export function fauxnixServerNames(value) {
|
|
177
217
|
if (!isServerMap(value))
|
|
178
|
-
return
|
|
218
|
+
return [];
|
|
219
|
+
const names = [];
|
|
179
220
|
for (const [name, cfg] of Object.entries(value)) {
|
|
180
221
|
if (name === 'servers')
|
|
181
222
|
continue;
|
|
182
223
|
if (looksLikeFauxnixServer(name, cfg))
|
|
183
|
-
|
|
224
|
+
names.push(name);
|
|
184
225
|
}
|
|
185
|
-
return
|
|
226
|
+
return names;
|
|
186
227
|
}
|
|
187
228
|
function looksLikeFauxnixServer(name, cfg) {
|
|
188
229
|
if (/^fauxnix(-cli)?$/i.test(name))
|
package/dist/errors.js
CHANGED
|
@@ -43,7 +43,7 @@ function unescapeClixml(t) {
|
|
|
43
43
|
.trim();
|
|
44
44
|
}
|
|
45
45
|
/**
|
|
46
|
-
* When stderr is redirected,
|
|
46
|
+
* When stderr is redirected, PowerShell can serialize error records as
|
|
47
47
|
* CLIXML (`#< CLIXML` + XML). Unwrap the real message lines and drop
|
|
48
48
|
* progress records, so agents see plain bash-style text.
|
|
49
49
|
*/
|
|
@@ -76,8 +76,10 @@ export function normalizeStderr(stderr) {
|
|
|
76
76
|
let m = line.match(/^The term '(.+?)' is not recognized/);
|
|
77
77
|
if (m)
|
|
78
78
|
return commandNotFound(m[1]);
|
|
79
|
-
// zh-CN:
|
|
80
|
-
|
|
79
|
+
// zh-CN: & : 无法将“x”项识别为 cmdlet、函数、脚本文件或可运行程序的名称。
|
|
80
|
+
// Require the PowerShell-specific suffix so ordinary Chinese prose that
|
|
81
|
+
// happens to contain “无法将…项识别为” is not rewritten.
|
|
82
|
+
m = line.match(/^(?:\S+\s*:\s*)?无法将[“"'‘]?(.+?)[”"'’]?项识别为\s*cmdlet、函数、脚本文件或可运行程序的名称(?:。|$)/);
|
|
81
83
|
if (m)
|
|
82
84
|
return commandNotFound(m[1]);
|
|
83
85
|
// "x : The term 'y' is not recognized ..." (with source prefix)
|
|
@@ -94,18 +96,26 @@ export function normalizeStderr(stderr) {
|
|
|
94
96
|
': No such file or directory');
|
|
95
97
|
}
|
|
96
98
|
// zh-CN: "Get-Content : 找不到路径“X”,因为该路径不存在。"
|
|
97
|
-
m = line.match(/^(\S+)\s*:\s*找不到路径[“'
|
|
99
|
+
m = line.match(/^(\S+)\s*:\s*找不到路径[“"'‘](.+?)[”"'’],因为该路径不存在[。.]?$/);
|
|
98
100
|
if (m) {
|
|
99
101
|
return m[1].toLowerCase() + ': ' + m[2].replace(/\\/g, '/') + ': No such file or directory';
|
|
100
102
|
}
|
|
101
103
|
// "cat : Cannot find drive. A drive with the name 'z' does not exist."
|
|
102
104
|
m = line.match(/^(\S+)\s*:\s*Cannot find drive\..*name '(.+?)'.*$/);
|
|
105
|
+
if (m)
|
|
106
|
+
return m[1].toLowerCase() + ': ' + m[2] + ': No such file or directory';
|
|
107
|
+
// zh-CN: "Get-Content : 找不到驱动器。名为“Z”的驱动器不存在。"
|
|
108
|
+
m = line.match(/^(\S+)\s*:\s*找不到驱动器[。.]\s*名为[“"'‘](.+?)[”"'’]的驱动器不存在[。.]?$/);
|
|
103
109
|
if (m)
|
|
104
110
|
return m[1].toLowerCase() + ': ' + m[2] + ': No such file or directory';
|
|
105
111
|
// "rm : Cannot remove item ... Access is denied"
|
|
106
112
|
m = line.match(/^(\S+)\s*:\s*(.*)Access to the path '(.+?)' is denied\.?$/);
|
|
107
113
|
if (m)
|
|
108
114
|
return m[1].toLowerCase() + ': cannot remove \'' + m[3] + '\': Permission denied';
|
|
115
|
+
// zh-CN: "rm : 对路径“C:\\protected”的访问被拒绝。"
|
|
116
|
+
m = line.match(/^(\S+)\s*:\s*对路径[“"'‘](.+?)[”"'’]的访问被拒绝[。.]?$/);
|
|
117
|
+
if (m)
|
|
118
|
+
return m[1].toLowerCase() + ': cannot remove \'' + m[2] + '\': Permission denied';
|
|
109
119
|
// leftover PS not-recognized lines that the rewrites above did not catch
|
|
110
120
|
if (/\.sh'?/.test(line) && /is not recognized/.test(line)) {
|
|
111
121
|
return line + SH_SCRIPT_WINDOWS_HINT;
|
package/dist/executor.d.ts
CHANGED
|
@@ -29,12 +29,15 @@ export declare class FauxnixSession {
|
|
|
29
29
|
private hostFile;
|
|
30
30
|
private host;
|
|
31
31
|
private lifecycleLock;
|
|
32
|
+
/** True once `env` was loaded from the host's complete environment snapshot. */
|
|
33
|
+
private hasEnvSnapshot;
|
|
34
|
+
private readonly powerShell;
|
|
32
35
|
constructor();
|
|
33
36
|
private bindFiles;
|
|
34
37
|
private withLock;
|
|
35
38
|
private syncFromDisk;
|
|
36
39
|
private ensureHost;
|
|
37
|
-
/** Boot
|
|
40
|
+
/** Boot the selected PowerShell now so the first run() is not a cold start. */
|
|
38
41
|
prewarm(): Promise<void>;
|
|
39
42
|
dispose(): Promise<void>;
|
|
40
43
|
/** Kill the host and re-prewarm the same session object (no second FauxnixSession). */
|