fauxnix-cli 0.7.1 → 0.9.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.
@@ -268,13 +268,23 @@ const grep = (args) => {
268
268
  const excludeDirGlobs = filterOptions
269
269
  .filter((o) => o.name === '--exclude-dir')
270
270
  .map((o) => o.value.replace(/[\\/]+$/, ''));
271
- const { flags, operandWords, values, missingValue } = parseWords(args, ['A', 'B', 'C'], filterOptionNames);
272
- const missingFilterOption = missingValue.find((o) => filterOptionNames.includes(o));
271
+ const { flags, operandWords, values, missingValue } = parseWords(args, ['A', 'B', 'C', 'm', 'e'], [...filterOptionNames, '--max-count', '--regexp']);
272
+ const missingFilterOption = missingValue.find((o) => [...filterOptionNames, '-m', '--max-count', '-e', '--regexp'].includes(o));
273
273
  if (missingFilterOption) {
274
274
  return ('[Console]::Error.WriteLine(' +
275
275
  psStr("grep: option '" + missingFilterOption + "' requires an argument") +
276
276
  '); $script:fx_exit = 2');
277
277
  }
278
+ const maxCountRaw = values.get('-m') ?? values.get('--max-count');
279
+ let maxCount = null;
280
+ if (maxCountRaw !== undefined) {
281
+ if (!/^\d+$/.test(maxCountRaw)) {
282
+ return ('[Console]::Error.WriteLine(' +
283
+ psStr("grep: invalid max count '" + maxCountRaw + "'") +
284
+ '); $script:fx_exit = 2');
285
+ }
286
+ maxCount = parseInt(maxCountRaw, 10);
287
+ }
278
288
  const ci = flags.has('i');
279
289
  const inv = flags.has('v');
280
290
  const num = flags.has('n');
@@ -294,11 +304,12 @@ const grep = (args) => {
294
304
  };
295
305
  const ctxA = Math.max(toInt(values.get('-A')), toInt(values.get('-C')));
296
306
  const ctxB = Math.max(toInt(values.get('-B')), toInt(values.get('-C')));
297
- if (operandWords.length === 0) {
307
+ const ePat = values.get('-e') ?? values.get('--regexp');
308
+ if (ePat === undefined && operandWords.length === 0) {
298
309
  return ("[Console]::Error.WriteLine('usage: grep [OPTION]... PATTERN [FILE]...'); $script:fx_exit = 2");
299
310
  }
300
- const patternWord = operandWords[0];
301
- const fileWords = operandWords.slice(1);
311
+ const patternWord = ePat !== undefined ? [{ kind: 'Text', text: ePat }] : operandWords[0];
312
+ const fileWords = ePat !== undefined ? operandWords : operandWords.slice(1);
302
313
  const patLit = literalOfWord(patternWord);
303
314
  let patExpr;
304
315
  if (fixed || patLit === null) {
@@ -435,10 +446,16 @@ const grep = (args) => {
435
446
  lines.push('}');
436
447
  // --- per-source scan body ----------------------------------------------
437
448
  const scan = [];
449
+ if (maxCount !== null)
450
+ scan.push('$fx_mleft = ' + maxCount);
438
451
  if (cntMode) {
439
452
  scan.push('$fx_c = 0');
440
453
  scan.push('for ($fx_i = 0; $fx_i -lt $fx_ls.Count; $fx_i++) {');
441
- scan.push(' if (fx-gmatch $fx_ls[$fx_i]) { $fx_c++ }');
454
+ if (maxCount !== null)
455
+ scan.push(' if ($fx_mleft -le 0) { break }');
456
+ scan.push(' if (fx-gmatch $fx_ls[$fx_i]) { $fx_c++' +
457
+ (maxCount !== null ? '; $fx_mleft--; if ($fx_mleft -le 0) { break }' : '') +
458
+ ' }');
442
459
  scan.push('}');
443
460
  scan.push('if ($fx_c -gt 0) { $fx_any = $true }');
444
461
  scan.push('if ($fx_pre) { $fx_disp + \':\' + [string]$fx_c } else { [string]$fx_c }');
@@ -446,21 +463,29 @@ const grep = (args) => {
446
463
  else if (listMode) {
447
464
  scan.push('$fx_hit1 = $false');
448
465
  scan.push('for ($fx_i = 0; $fx_i -lt $fx_ls.Count; $fx_i++) {');
466
+ if (maxCount !== null)
467
+ scan.push(' if ($fx_mleft -le 0) { break }');
449
468
  scan.push(' if (fx-gmatch $fx_ls[$fx_i]) { $fx_hit1 = $true; break }');
450
469
  scan.push('}');
451
470
  scan.push('if ($fx_hit1) { $fx_any = $true; $fx_disp }');
452
471
  }
453
472
  else if (quiet) {
454
473
  scan.push('for ($fx_i = 0; $fx_i -lt $fx_ls.Count; $fx_i++) {');
474
+ if (maxCount !== null)
475
+ scan.push(' if ($fx_mleft -le 0) { break }');
455
476
  scan.push(' if (fx-gmatch $fx_ls[$fx_i]) { $fx_any = $true; break }');
456
477
  scan.push('}');
457
478
  }
458
479
  else {
459
480
  scan.push('$fx_hits = @()');
460
481
  scan.push('for ($fx_i = 0; $fx_i -lt $fx_ls.Count; $fx_i++) {');
482
+ if (maxCount !== null)
483
+ scan.push(' if ($fx_mleft -le 0) { break }');
461
484
  scan.push(' $fx_l = $fx_ls[$fx_i]');
462
485
  scan.push(' if (fx-gmatch $fx_l) {');
463
486
  scan.push(' $fx_any = $true');
487
+ if (maxCount !== null)
488
+ scan.push(' $fx_mleft--');
464
489
  if (onlyMatch && !inv) {
465
490
  if (fixed) {
466
491
  if (ci) {
@@ -492,6 +517,8 @@ const grep = (args) => {
492
517
  else if (!onlyMatch) {
493
518
  scan.push(' $fx_hits += $fx_i');
494
519
  }
520
+ if (maxCount !== null)
521
+ scan.push(' if ($fx_mleft -le 0) { break }');
495
522
  scan.push(' }');
496
523
  scan.push('}');
497
524
  if (!onlyMatch) {
@@ -2347,8 +2374,41 @@ const tr = (args) => {
2347
2374
  return lines.join('\n');
2348
2375
  };
2349
2376
  /* ------------------------------------------------------------------ */
2377
+ export const specs = [
2378
+ {
2379
+ names: ['grep'],
2380
+ options: [
2381
+ { short: 'i', support: 'implemented' },
2382
+ { short: 'v', support: 'implemented' },
2383
+ { short: 'n', support: 'implemented' },
2384
+ { short: 'c', support: 'implemented' },
2385
+ { short: 'l', support: 'implemented' },
2386
+ { short: 'r', support: 'implemented' },
2387
+ { short: 'R', support: 'implemented' },
2388
+ { short: 'E', support: 'implemented' },
2389
+ { short: 'F', support: 'implemented' },
2390
+ { short: 'w', support: 'implemented' },
2391
+ { short: 'q', support: 'implemented' },
2392
+ { short: 'o', support: 'implemented' },
2393
+ { short: 'h', support: 'implemented' },
2394
+ { short: 'H', support: 'implemented' },
2395
+ { short: 'A', takesValue: true, support: 'implemented' },
2396
+ { short: 'B', takesValue: true, support: 'implemented' },
2397
+ { short: 'C', takesValue: true, support: 'implemented' },
2398
+ { short: 'm', long: '--max-count', takesValue: true, support: 'implemented' },
2399
+ { short: 'e', long: '--regexp', takesValue: true, support: 'implemented' },
2400
+ { long: '--include', takesValue: true, support: 'implemented' },
2401
+ { long: '--exclude', takesValue: true, support: 'implemented' },
2402
+ { long: '--exclude-dir', takesValue: true, support: 'implemented' },
2403
+ ],
2404
+ effects: ['read'],
2405
+ platform: 'windows-ps51',
2406
+ dispatch: 'translated',
2407
+ usageExit: 2,
2408
+ handler: grep,
2409
+ },
2410
+ ];
2350
2411
  export const handlers = {
2351
- grep,
2352
2412
  egrep: (args, ctx) => grep([[{ kind: 'Text', text: '-E' }], ...args], ctx), // egrep = grep -E
2353
2413
  sed,
2354
2414
  awk,
@@ -1,2 +1,3 @@
1
- import { Handler } from '../registry.js';
1
+ import { CommandSpec, Handler } from '../registry.js';
2
+ export declare const specs: CommandSpec[];
2
3
  export declare const handlers: Record<string, Handler>;
@@ -419,6 +419,37 @@ const head = (args, ctx) => {
419
419
  continue;
420
420
  }
421
421
  if (t.startsWith('--')) {
422
+ const eq = t.indexOf('=');
423
+ const name = eq >= 0 ? t.slice(0, eq) : t;
424
+ const inline = eq >= 0 ? t.slice(eq + 1) : null;
425
+ if (name === '--lines' || name === '--bytes') {
426
+ let val = inline;
427
+ if (val === null) {
428
+ if (i + 1 >= args.length) {
429
+ return psErrExpr(psStr('head: option requires an argument -- ' + name.slice(2)));
430
+ }
431
+ val = wordToString(args[i + 1]);
432
+ i += 2;
433
+ }
434
+ else {
435
+ i++;
436
+ }
437
+ if (name === '--bytes')
438
+ nBytes = val;
439
+ else
440
+ nLines = val;
441
+ continue;
442
+ }
443
+ if (name === '--quiet' || name === '--silent') {
444
+ quiet = true;
445
+ i++;
446
+ continue;
447
+ }
448
+ if (name === '--verbose') {
449
+ verbose = true;
450
+ i++;
451
+ continue;
452
+ }
422
453
  i++;
423
454
  continue;
424
455
  }
@@ -464,6 +495,9 @@ const head = (args, ctx) => {
464
495
  }
465
496
  const bytesMode = nBytes !== null;
466
497
  const countLit = bytesMode ? nBytes : nLines !== null ? nLines : '10';
498
+ if (!/^[+-]?\d+$/.test(countLit)) {
499
+ return psErrExpr(psStr("head: invalid number of " + (bytesMode ? 'bytes' : 'lines') + ": '" + countLit + "'"));
500
+ }
467
501
  const lines = [
468
502
  PS_GLOB_FN,
469
503
  PS_READTEXT_FN,
@@ -516,6 +550,39 @@ const tail = (args, ctx) => {
516
550
  continue;
517
551
  }
518
552
  if (t.startsWith('--')) {
553
+ const eq = t.indexOf('=');
554
+ const name = eq >= 0 ? t.slice(0, eq) : t;
555
+ const inline = eq >= 0 ? t.slice(eq + 1) : null;
556
+ if (name === '--lines' || name === '--bytes') {
557
+ let val = inline;
558
+ if (val === null) {
559
+ if (i + 1 >= args.length) {
560
+ return psErrExpr(psStr('tail: option requires an argument -- ' + name.slice(2)));
561
+ }
562
+ val = wordToString(args[i + 1]);
563
+ i += 2;
564
+ }
565
+ else {
566
+ i++;
567
+ }
568
+ if (name === '--bytes')
569
+ nBytes = val;
570
+ else if (val.startsWith('+'))
571
+ fromLine = val.slice(1);
572
+ else
573
+ nLines = val.replace(/^-/, '');
574
+ continue;
575
+ }
576
+ if (name === '--quiet' || name === '--silent') {
577
+ quiet = true;
578
+ i++;
579
+ continue;
580
+ }
581
+ if (name === '--verbose') {
582
+ verbose = true;
583
+ i++;
584
+ continue;
585
+ }
519
586
  i++;
520
587
  continue;
521
588
  }
@@ -691,8 +758,8 @@ const wc = (args) => {
691
758
  /* tee */
692
759
  /* ------------------------------------------------------------------ */
693
760
  const tee = (args, ctx) => {
694
- const { flags, operandWords } = parseWords(args);
695
- const append = flags.has('a') || flags.has('append');
761
+ const { flags, longs, operandWords } = parseWords(args);
762
+ const append = flags.has('a') || longs.has('--append');
696
763
  return [
697
764
  PS_WRITE_FN,
698
765
  fxTermLine(ctx.position),
@@ -1142,14 +1209,38 @@ const xargs = (args) => {
1142
1209
  ].join('\n');
1143
1210
  };
1144
1211
  /* ------------------------------------------------------------------ */
1212
+ export const specs = [
1213
+ {
1214
+ names: ['tee'],
1215
+ options: [
1216
+ { short: 'a', long: '--append', support: 'implemented' },
1217
+ ],
1218
+ effects: ['read', 'write'],
1219
+ platform: 'windows-ps51',
1220
+ dispatch: 'translated',
1221
+ handler: tee,
1222
+ },
1223
+ {
1224
+ names: ['head'],
1225
+ options: [
1226
+ { short: 'n', long: '--lines', takesValue: true, support: 'implemented' },
1227
+ { short: 'c', long: '--bytes', takesValue: true, support: 'implemented' },
1228
+ { short: 'q', long: '--quiet', support: 'implemented' },
1229
+ { long: '--silent', support: 'implemented' },
1230
+ { short: 'v', long: '--verbose', support: 'implemented' },
1231
+ ],
1232
+ effects: ['read'],
1233
+ platform: 'windows-ps51',
1234
+ dispatch: 'translated',
1235
+ handler: head,
1236
+ },
1237
+ ];
1145
1238
  export const handlers = {
1146
1239
  echo,
1147
1240
  printf,
1148
1241
  cat,
1149
- head,
1150
1242
  tail,
1151
1243
  wc,
1152
- tee,
1153
1244
  nl,
1154
1245
  tac,
1155
1246
  md5sum,
@@ -3,14 +3,22 @@ export interface ExecResult {
3
3
  stdout: string;
4
4
  stderr: string;
5
5
  exitCode: number;
6
+ timedOut: boolean;
7
+ cancelled: boolean;
8
+ truncated: boolean;
9
+ spawnError?: 'ENOENT' | 'START';
6
10
  }
7
11
  export interface ExecOptions {
8
12
  timeoutMs?: number;
9
13
  /** Extra environment layered over the session (used by MCP per-call cwd). */
10
14
  cwd?: string;
15
+ signal?: AbortSignal;
16
+ stdoutLimit?: number;
17
+ stderrLimit?: number;
11
18
  }
12
19
  /** Session persists cwd and env across segments, like a real shell. */
13
20
  export declare class FauxnixSession {
21
+ id: string;
14
22
  cwd: string | null;
15
23
  env: Record<string, string>;
16
24
  /** Exit code of the previous segment — powers bash's `$?`. */
@@ -20,14 +28,18 @@ export declare class FauxnixSession {
20
28
  private scriptFile;
21
29
  private hostFile;
22
30
  private host;
23
- private runLock;
31
+ private lifecycleLock;
24
32
  constructor();
25
33
  private bindFiles;
34
+ private withLock;
26
35
  private syncFromDisk;
27
36
  private ensureHost;
28
37
  /** Boot powershell.exe now so the first run() is not the 1.1s cold start. */
29
38
  prewarm(): Promise<void>;
30
39
  dispose(): Promise<void>;
40
+ /** Kill the host and re-prewarm the same session object (no second FauxnixSession). */
41
+ reset(): Promise<void>;
42
+ private disposeUnlocked;
31
43
  /** env for the child powershell process. */
32
44
  childEnv(cwdOverride?: string, stdinFile?: string | null): NodeJS.ProcessEnv;
33
45
  run(plans: SegmentPlan[], opts?: ExecOptions): Promise<ExecResult>;
package/dist/executor.js CHANGED
@@ -5,7 +5,7 @@ import path from 'node:path';
5
5
  import { normalizeLiteralPath, wrapScript } from './translator.js';
6
6
  import { decodeOutput, normalizeHostNewlines, resolveNativePref } from './encoding.js';
7
7
  import { normalizeStderr } from './errors.js';
8
- import { PowerShellHost, PS_MISSING_MESSAGE } from './ps-host.js';
8
+ import { DEFAULT_STDERR_LIMIT, DEFAULT_STDOUT_LIMIT, PowerShellHost, PS_MISSING_MESSAGE, } from './ps-host.js';
9
9
  const DEFAULT_TIMEOUT_MS = 120_000;
10
10
  const DEFAULT_WINDOWS_PATHEXT = '.COM;.EXE;.BAT;.CMD';
11
11
  function hasEnvKey(env, name) {
@@ -153,6 +153,7 @@ function planRedirects(redirects) {
153
153
  }
154
154
  /** Session persists cwd and env across segments, like a real shell. */
155
155
  export class FauxnixSession {
156
+ id;
156
157
  cwd = null;
157
158
  env = {};
158
159
  /** Exit code of the previous segment — powers bash's `$?`. */
@@ -162,16 +163,23 @@ export class FauxnixSession {
162
163
  scriptFile;
163
164
  hostFile;
164
165
  host = null;
165
- runLock = Promise.resolve();
166
+ lifecycleLock = Promise.resolve();
166
167
  constructor() {
167
- this.bindFiles(randomUUID().slice(0, 8));
168
+ this.id = randomUUID().slice(0, 8);
169
+ this.bindFiles(this.id);
168
170
  }
169
171
  bindFiles(id) {
172
+ this.id = id;
170
173
  this.cwdFile = path.join(os.tmpdir(), 'fauxnix-' + id + '-cwd.txt');
171
174
  this.envFile = path.join(os.tmpdir(), 'fauxnix-' + id + '-env.json');
172
175
  this.scriptFile = path.join(os.tmpdir(), 'fauxnix-' + id + '-script.ps1');
173
176
  this.hostFile = path.join(os.tmpdir(), 'fauxnix-' + id + '-host.ps1');
174
177
  }
178
+ withLock(fn) {
179
+ const done = this.lifecycleLock.then(fn, fn);
180
+ this.lifecycleLock = done.then(() => undefined, () => undefined);
181
+ return done;
182
+ }
175
183
  syncFromDisk() {
176
184
  try {
177
185
  if (existsSync(this.cwdFile)) {
@@ -201,10 +209,22 @@ export class FauxnixSession {
201
209
  return this.host;
202
210
  }
203
211
  /** Boot powershell.exe now so the first run() is not the 1.1s cold start. */
204
- async prewarm() {
205
- await this.ensureHost().ready();
212
+ prewarm() {
213
+ return this.withLock(async () => {
214
+ await this.ensureHost().ready();
215
+ });
216
+ }
217
+ dispose() {
218
+ return this.withLock(() => this.disposeUnlocked());
219
+ }
220
+ /** Kill the host and re-prewarm the same session object (no second FauxnixSession). */
221
+ reset() {
222
+ return this.withLock(async () => {
223
+ await this.disposeUnlocked();
224
+ await this.ensureHost().ready();
225
+ });
206
226
  }
207
- async dispose() {
227
+ async disposeUnlocked() {
208
228
  if (this.host) {
209
229
  await this.host.stop();
210
230
  this.host = null;
@@ -255,18 +275,22 @@ export class FauxnixSession {
255
275
  return env;
256
276
  }
257
277
  run(plans, opts = {}) {
258
- const done = this.runLock.then(() => runPlans(plans, this, opts, () => this.syncFromDisk(), () => this.ensureHost()));
259
- this.runLock = done.then(() => undefined, () => undefined);
260
- return done;
278
+ return this.withLock(() => runPlans(plans, this, opts, () => this.syncFromDisk(), () => this.ensureHost()));
261
279
  }
262
280
  }
263
281
  async function runPlans(plans, session, opts, afterSegment, ensureHost) {
264
282
  const timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS;
265
283
  const deadline = Date.now() + timeoutMs;
284
+ const stdoutLimit = opts.stdoutLimit ?? DEFAULT_STDOUT_LIMIT;
285
+ const stderrLimit = opts.stderrLimit ?? DEFAULT_STDERR_LIMIT;
266
286
  const timeoutMessage = '\nbash: command timed out after ' + Math.round(timeoutMs / 1000) + 's';
267
287
  let stdout = '';
268
288
  let stderr = '';
269
289
  let exitCode = 0;
290
+ let timedOut = false;
291
+ let cancelled = false;
292
+ let truncated = false;
293
+ let spawnError;
270
294
  // bash list semantics: `a && b ; c` runs c regardless of a; `a && b && c`
271
295
  // skips b AND c when a fails. chainOk models the value of the current
272
296
  // &&/|| chain; `;` segments always run and restart the chain.
@@ -282,9 +306,16 @@ async function runPlans(plans, session, opts, afterSegment, ensureHost) {
282
306
  continue;
283
307
  if (plan.op === '||' && chainOk)
284
308
  continue;
309
+ if (opts.signal?.aborted) {
310
+ cancelled = true;
311
+ exitCode = 130;
312
+ session.prevExit = exitCode;
313
+ break;
314
+ }
285
315
  if (Date.now() >= deadline) {
286
316
  stderr += timeoutMessage;
287
317
  exitCode = 124;
318
+ timedOut = true;
288
319
  session.prevExit = exitCode;
289
320
  break;
290
321
  }
@@ -361,9 +392,16 @@ async function runPlans(plans, session, opts, afterSegment, ensureHost) {
361
392
  continue;
362
393
  }
363
394
  const remainingMs = deadline - Date.now();
395
+ if (opts.signal?.aborted) {
396
+ cancelled = true;
397
+ exitCode = 130;
398
+ session.prevExit = exitCode;
399
+ break;
400
+ }
364
401
  if (remainingMs <= 0) {
365
402
  stderr += timeoutMessage;
366
403
  exitCode = 124;
404
+ timedOut = true;
367
405
  session.prevExit = exitCode;
368
406
  break;
369
407
  }
@@ -372,14 +410,22 @@ async function runPlans(plans, session, opts, afterSegment, ensureHost) {
372
410
  FAUXNIX_CWD: currentDir,
373
411
  FAUXNIX_PREV_EXIT: session.prevExit === null ? '' : String(session.prevExit),
374
412
  FAUXNIX_STDIN_FILE: red.stdinFile || '',
375
- }, remainingMs);
376
- if (inv.spawnError === 'ENOENT') {
413
+ }, remainingMs, opts.signal, { stdoutLimit, stderrLimit });
414
+ if (inv.spawnError === 'ENOENT' || inv.spawnError === 'START') {
377
415
  stderr += inv.stderr.toString('utf8') || PS_MISSING_MESSAGE;
378
416
  exitCode = 127;
417
+ spawnError = inv.spawnError;
379
418
  session.prevExit = exitCode;
380
419
  chainOk = false;
381
420
  continue;
382
421
  }
422
+ if (inv.cancelled) {
423
+ cancelled = true;
424
+ exitCode = 130;
425
+ session.prevExit = exitCode;
426
+ chainOk = false;
427
+ break;
428
+ }
383
429
  afterSegment();
384
430
  const decodePref = resolveNativePref();
385
431
  // GNU line discipline: the PS host terminates Write-Output lines with
@@ -430,7 +476,11 @@ async function runPlans(plans, session, opts, afterSegment, ensureHost) {
430
476
  }
431
477
  stdout += segOut;
432
478
  stderr += segErr;
433
- exitCode = inv.timedOut ? 124 : inv.exitCode;
479
+ if (inv.truncated)
480
+ truncated = true;
481
+ exitCode = inv.timedOut ? 124 : inv.cancelled ? 130 : inv.exitCode;
482
+ if (inv.timedOut)
483
+ timedOut = true;
434
484
  session.prevExit = exitCode;
435
485
  chainOk = exitCode === 0;
436
486
  // Only inherit cwd from a segment that actually ran and whose
@@ -445,5 +495,25 @@ async function runPlans(plans, session, opts, afterSegment, ensureHost) {
445
495
  closePrepFds(prepFds);
446
496
  }
447
497
  }
448
- return { stdout, stderr, exitCode };
498
+ const clippedOut = clipUtf8(stdout, stdoutLimit);
499
+ const clippedErr = clipUtf8(stderr, stderrLimit);
500
+ if (clippedOut.truncated || clippedErr.truncated)
501
+ truncated = true;
502
+ return {
503
+ stdout: clippedOut.text,
504
+ stderr: clippedErr.text,
505
+ exitCode,
506
+ timedOut,
507
+ cancelled,
508
+ truncated,
509
+ spawnError,
510
+ };
511
+ }
512
+ function clipUtf8(text, limit) {
513
+ if (Buffer.byteLength(text, 'utf8') <= limit)
514
+ return { text, truncated: false };
515
+ let end = text.length;
516
+ while (end > 0 && Buffer.byteLength(text.slice(0, end), 'utf8') > limit)
517
+ end--;
518
+ return { text: text.slice(0, end), truncated: true };
449
519
  }
package/dist/mcp.d.ts CHANGED
@@ -1,4 +1,23 @@
1
+ import { ExecResult } from './executor.js';
1
2
  import { translatePipelineBody } from './translator.js';
2
3
  import './commands/install-all.js';
4
+ export declare function formatBashText(r: Pick<ExecResult, 'stdout' | 'stderr' | 'exitCode' | 'timedOut' | 'cancelled'>): string;
5
+ export declare function bashToolResult(r: ExecResult, sessionId: string, infra: boolean): {
6
+ isError?: true | undefined;
7
+ content: {
8
+ type: "text";
9
+ text: string;
10
+ }[];
11
+ structuredContent: {
12
+ schemaVersion: 1;
13
+ stdout: string;
14
+ stderr: string;
15
+ exitCode: number;
16
+ timedOut: boolean;
17
+ cancelled: boolean;
18
+ truncated: boolean;
19
+ sessionId: string;
20
+ };
21
+ };
3
22
  export declare function startMcpServer(): Promise<void>;
4
23
  export { translatePipelineBody };