shell-dsl 0.0.40 → 0.0.42

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.
Files changed (57) hide show
  1. package/README.md +89 -0
  2. package/dist/cjs/package.json +1 -1
  3. package/dist/cjs/src/index.cjs +8 -1
  4. package/dist/cjs/src/index.cjs.map +3 -3
  5. package/dist/cjs/src/input-analysis.cjs +154 -0
  6. package/dist/cjs/src/input-analysis.cjs.map +10 -0
  7. package/dist/cjs/src/interpreter/context.cjs +3 -1
  8. package/dist/cjs/src/interpreter/context.cjs.map +3 -3
  9. package/dist/cjs/src/interpreter/interpreter.cjs +146 -19
  10. package/dist/cjs/src/interpreter/interpreter.cjs.map +3 -3
  11. package/dist/cjs/src/io/async-queue.cjs +105 -0
  12. package/dist/cjs/src/io/async-queue.cjs.map +10 -0
  13. package/dist/cjs/src/io/index.cjs +4 -1
  14. package/dist/cjs/src/io/index.cjs.map +3 -3
  15. package/dist/cjs/src/io/input-controller.cjs +113 -0
  16. package/dist/cjs/src/io/input-controller.cjs.map +10 -0
  17. package/dist/cjs/src/io/stdout.cjs +9 -6
  18. package/dist/cjs/src/io/stdout.cjs.map +3 -3
  19. package/dist/cjs/src/shell-dsl.cjs +13 -5
  20. package/dist/cjs/src/shell-dsl.cjs.map +3 -3
  21. package/dist/cjs/src/shell-session.cjs +222 -0
  22. package/dist/cjs/src/shell-session.cjs.map +10 -0
  23. package/dist/cjs/src/types.cjs.map +2 -2
  24. package/dist/mjs/package.json +1 -1
  25. package/dist/mjs/src/index.mjs +17 -2
  26. package/dist/mjs/src/index.mjs.map +3 -3
  27. package/dist/mjs/src/input-analysis.mjs +114 -0
  28. package/dist/mjs/src/input-analysis.mjs.map +10 -0
  29. package/dist/mjs/src/interpreter/context.mjs +3 -1
  30. package/dist/mjs/src/interpreter/context.mjs.map +3 -3
  31. package/dist/mjs/src/interpreter/interpreter.mjs +146 -19
  32. package/dist/mjs/src/interpreter/interpreter.mjs.map +3 -3
  33. package/dist/mjs/src/io/async-queue.mjs +64 -0
  34. package/dist/mjs/src/io/async-queue.mjs.map +10 -0
  35. package/dist/mjs/src/io/index.mjs +4 -1
  36. package/dist/mjs/src/io/index.mjs.map +3 -3
  37. package/dist/mjs/src/io/input-controller.mjs +72 -0
  38. package/dist/mjs/src/io/input-controller.mjs.map +10 -0
  39. package/dist/mjs/src/io/stdout.mjs +9 -6
  40. package/dist/mjs/src/io/stdout.mjs.map +3 -3
  41. package/dist/mjs/src/shell-dsl.mjs +13 -5
  42. package/dist/mjs/src/shell-dsl.mjs.map +3 -3
  43. package/dist/mjs/src/shell-session.mjs +182 -0
  44. package/dist/mjs/src/shell-session.mjs.map +10 -0
  45. package/dist/mjs/src/types.mjs.map +2 -2
  46. package/dist/types/src/index.d.ts +5 -2
  47. package/dist/types/src/input-analysis.d.ts +14 -0
  48. package/dist/types/src/interpreter/context.d.ts +3 -1
  49. package/dist/types/src/interpreter/interpreter.d.ts +12 -1
  50. package/dist/types/src/io/async-queue.d.ts +12 -0
  51. package/dist/types/src/io/index.d.ts +1 -0
  52. package/dist/types/src/io/input-controller.d.ts +15 -0
  53. package/dist/types/src/io/stdout.d.ts +4 -3
  54. package/dist/types/src/shell-dsl.d.ts +2 -0
  55. package/dist/types/src/shell-session.d.ts +30 -0
  56. package/dist/types/src/types.d.ts +58 -0
  57. package/package.json +1 -1
@@ -0,0 +1,113 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropNames = Object.getOwnPropertyNames;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
5
+ function __accessProp(key) {
6
+ return this[key];
7
+ }
8
+ var __toCommonJS = (from) => {
9
+ var entry = (__moduleCache ??= new WeakMap).get(from), desc;
10
+ if (entry)
11
+ return entry;
12
+ entry = __defProp({}, "__esModule", { value: true });
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (var key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(entry, key))
16
+ __defProp(entry, key, {
17
+ get: __accessProp.bind(from, key),
18
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
19
+ });
20
+ }
21
+ __moduleCache.set(from, entry);
22
+ return entry;
23
+ };
24
+ var __moduleCache;
25
+ var __returnValue = (v) => v;
26
+ function __exportSetter(name, newValue) {
27
+ this[name] = __returnValue.bind(null, newValue);
28
+ }
29
+ var __export = (target, all) => {
30
+ for (var name in all)
31
+ __defProp(target, name, {
32
+ get: all[name],
33
+ enumerable: true,
34
+ configurable: true,
35
+ set: __exportSetter.bind(all, name)
36
+ });
37
+ };
38
+
39
+ // src/io/input-controller.ts
40
+ var exports_input_controller = {};
41
+ __export(exports_input_controller, {
42
+ createShellInput: () => createShellInput,
43
+ ShellInputControllerImpl: () => ShellInputControllerImpl
44
+ });
45
+ module.exports = __toCommonJS(exports_input_controller);
46
+
47
+ class ShellInputControllerImpl {
48
+ chunks = [];
49
+ closed = false;
50
+ aborted = false;
51
+ abortReason;
52
+ waiters = [];
53
+ async write(chunk) {
54
+ if (this.closed) {
55
+ throw new Error("Input stream is closed");
56
+ }
57
+ if (this.aborted) {
58
+ throw this.abortReason ?? new Error("Input stream aborted");
59
+ }
60
+ this.chunks.push(typeof chunk === "string" ? new TextEncoder().encode(chunk) : chunk);
61
+ this.wake();
62
+ }
63
+ close() {
64
+ if (this.closed) {
65
+ return;
66
+ }
67
+ this.closed = true;
68
+ this.wake();
69
+ }
70
+ abort(reason) {
71
+ if (this.aborted) {
72
+ return;
73
+ }
74
+ this.aborted = true;
75
+ this.abortReason = reason ?? new Error("Input stream aborted");
76
+ this.wakeWithError(this.abortReason);
77
+ }
78
+ async* [Symbol.asyncIterator]() {
79
+ while (true) {
80
+ while (this.chunks.length > 0) {
81
+ yield this.chunks.shift();
82
+ }
83
+ if (this.aborted) {
84
+ throw this.abortReason ?? new Error("Input stream aborted");
85
+ }
86
+ if (this.closed) {
87
+ break;
88
+ }
89
+ await new Promise((resolve, reject) => {
90
+ this.waiters.push({ resolve, reject });
91
+ });
92
+ }
93
+ }
94
+ wake() {
95
+ const waiters = this.waiters;
96
+ this.waiters = [];
97
+ for (const waiter of waiters) {
98
+ waiter.resolve();
99
+ }
100
+ }
101
+ wakeWithError(reason) {
102
+ const waiters = this.waiters;
103
+ this.waiters = [];
104
+ for (const waiter of waiters) {
105
+ waiter.reject(reason);
106
+ }
107
+ }
108
+ }
109
+ function createShellInput() {
110
+ return new ShellInputControllerImpl;
111
+ }
112
+
113
+ //# debugId=23B26B983781CA8B64756E2164756E21
@@ -0,0 +1,10 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/io/input-controller.ts"],
4
+ "sourcesContent": [
5
+ "import type { ShellInputController } from \"../types.cjs\";\n\ntype Waiter = {\n resolve: () => void;\n reject: (reason?: unknown) => void;\n};\n\nexport class ShellInputControllerImpl implements ShellInputController {\n private chunks: Uint8Array[] = [];\n private closed = false;\n private aborted = false;\n private abortReason: unknown;\n private waiters: Waiter[] = [];\n\n async write(chunk: Uint8Array | string): Promise<void> {\n if (this.closed) {\n throw new Error(\"Input stream is closed\");\n }\n if (this.aborted) {\n throw this.abortReason ?? new Error(\"Input stream aborted\");\n }\n\n this.chunks.push(typeof chunk === \"string\" ? new TextEncoder().encode(chunk) : chunk);\n this.wake();\n }\n\n close(): void {\n if (this.closed) {\n return;\n }\n this.closed = true;\n this.wake();\n }\n\n abort(reason?: unknown): void {\n if (this.aborted) {\n return;\n }\n this.aborted = true;\n this.abortReason = reason ?? new Error(\"Input stream aborted\");\n this.wakeWithError(this.abortReason);\n }\n\n async *[Symbol.asyncIterator](): AsyncIterator<Uint8Array> {\n while (true) {\n while (this.chunks.length > 0) {\n yield this.chunks.shift()!;\n }\n\n if (this.aborted) {\n throw this.abortReason ?? new Error(\"Input stream aborted\");\n }\n if (this.closed) {\n break;\n }\n\n await new Promise<void>((resolve, reject) => {\n this.waiters.push({ resolve, reject });\n });\n }\n }\n\n private wake(): void {\n const waiters = this.waiters;\n this.waiters = [];\n for (const waiter of waiters) {\n waiter.resolve();\n }\n }\n\n private wakeWithError(reason?: unknown): void {\n const waiters = this.waiters;\n this.waiters = [];\n for (const waiter of waiters) {\n waiter.reject(reason);\n }\n }\n}\n\nexport function createShellInput(): ShellInputController {\n return new ShellInputControllerImpl();\n}\n"
6
+ ],
7
+ "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAOO,MAAM,yBAAyD;AAAA,EAC5D,SAAuB,CAAC;AAAA,EACxB,SAAS;AAAA,EACT,UAAU;AAAA,EACV;AAAA,EACA,UAAoB,CAAC;AAAA,OAEvB,MAAK,CAAC,OAA2C;AAAA,IACrD,IAAI,KAAK,QAAQ;AAAA,MACf,MAAM,IAAI,MAAM,wBAAwB;AAAA,IAC1C;AAAA,IACA,IAAI,KAAK,SAAS;AAAA,MAChB,MAAM,KAAK,eAAe,IAAI,MAAM,sBAAsB;AAAA,IAC5D;AAAA,IAEA,KAAK,OAAO,KAAK,OAAO,UAAU,WAAW,IAAI,YAAY,EAAE,OAAO,KAAK,IAAI,KAAK;AAAA,IACpF,KAAK,KAAK;AAAA;AAAA,EAGZ,KAAK,GAAS;AAAA,IACZ,IAAI,KAAK,QAAQ;AAAA,MACf;AAAA,IACF;AAAA,IACA,KAAK,SAAS;AAAA,IACd,KAAK,KAAK;AAAA;AAAA,EAGZ,KAAK,CAAC,QAAwB;AAAA,IAC5B,IAAI,KAAK,SAAS;AAAA,MAChB;AAAA,IACF;AAAA,IACA,KAAK,UAAU;AAAA,IACf,KAAK,cAAc,UAAU,IAAI,MAAM,sBAAsB;AAAA,IAC7D,KAAK,cAAc,KAAK,WAAW;AAAA;AAAA,UAG7B,OAAO,cAAc,GAA8B;AAAA,IACzD,OAAO,MAAM;AAAA,MACX,OAAO,KAAK,OAAO,SAAS,GAAG;AAAA,QAC7B,MAAM,KAAK,OAAO,MAAM;AAAA,MAC1B;AAAA,MAEA,IAAI,KAAK,SAAS;AAAA,QAChB,MAAM,KAAK,eAAe,IAAI,MAAM,sBAAsB;AAAA,MAC5D;AAAA,MACA,IAAI,KAAK,QAAQ;AAAA,QACf;AAAA,MACF;AAAA,MAEA,MAAM,IAAI,QAAc,CAAC,SAAS,WAAW;AAAA,QAC3C,KAAK,QAAQ,KAAK,EAAE,SAAS,OAAO,CAAC;AAAA,OACtC;AAAA,IACH;AAAA;AAAA,EAGM,IAAI,GAAS;AAAA,IACnB,MAAM,UAAU,KAAK;AAAA,IACrB,KAAK,UAAU,CAAC;AAAA,IAChB,WAAW,UAAU,SAAS;AAAA,MAC5B,OAAO,QAAQ;AAAA,IACjB;AAAA;AAAA,EAGM,aAAa,CAAC,QAAwB;AAAA,IAC5C,MAAM,UAAU,KAAK;AAAA,IACrB,KAAK,UAAU,CAAC;AAAA,IAChB,WAAW,UAAU,SAAS;AAAA,MAC5B,OAAO,OAAO,MAAM;AAAA,IACtB;AAAA;AAEJ;AAEO,SAAS,gBAAgB,GAAyB;AAAA,EACvD,OAAO,IAAI;AAAA;",
8
+ "debugId": "23B26B983781CA8B64756E2164756E21",
9
+ "names": []
10
+ }
@@ -56,14 +56,17 @@ class OutputCollectorImpl {
56
56
  resolveWait = null;
57
57
  waitPromise = null;
58
58
  isTTY;
59
- constructor(isTTY = false) {
59
+ onWrite;
60
+ constructor(isTTY = false, onWrite) {
60
61
  this.isTTY = isTTY;
62
+ this.onWrite = onWrite;
61
63
  }
62
64
  async write(chunk) {
63
65
  if (this.closed) {
64
66
  throw new Error("Output stream is closed");
65
67
  }
66
68
  this.chunks.push(chunk);
69
+ await this.onWrite?.(chunk);
67
70
  if (this.resolveWait) {
68
71
  this.resolveWait();
69
72
  this.resolveWait = null;
@@ -162,11 +165,11 @@ class PipeBuffer {
162
165
  }
163
166
  }
164
167
  }
165
- function createStdout(isTTY = false) {
166
- return new OutputCollectorImpl(isTTY);
168
+ function createStdout(isTTY = false, onWrite) {
169
+ return new OutputCollectorImpl(isTTY, onWrite);
167
170
  }
168
- function createStderr(isTTY = false) {
169
- return new OutputCollectorImpl(isTTY);
171
+ function createStderr(isTTY = false, onWrite) {
172
+ return new OutputCollectorImpl(isTTY, onWrite);
170
173
  }
171
174
  function createPipe() {
172
175
  return new PipeBuffer;
@@ -216,4 +219,4 @@ function createBufferTargetCollector(target) {
216
219
  return new BufferTargetCollector(target);
217
220
  }
218
221
 
219
- //# debugId=00CF2D6942739CDC64756E2164756E21
222
+ //# debugId=2F5A4E06A0B3D2B364756E2164756E21
@@ -2,9 +2,9 @@
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/io/stdout.ts"],
4
4
  "sourcesContent": [
5
- "import type { Stdout, Stderr, OutputCollector } from \"../types.cjs\";\n\nexport class OutputCollectorImpl implements OutputCollector {\n private chunks: Uint8Array[] = [];\n private closed: boolean = false;\n private closeResolvers: Array<() => void> = [];\n private resolveWait: (() => void) | null = null;\n private waitPromise: Promise<void> | null = null;\n public isTTY: boolean;\n\n constructor(isTTY: boolean = false) {\n this.isTTY = isTTY;\n }\n\n async write(chunk: Uint8Array): Promise<void> {\n if (this.closed) {\n throw new Error(\"Output stream is closed\");\n }\n this.chunks.push(chunk);\n if (this.resolveWait) {\n this.resolveWait();\n this.resolveWait = null;\n this.waitPromise = null;\n }\n }\n\n async writeText(str: string): Promise<void> {\n await this.write(new TextEncoder().encode(str));\n }\n\n close(): void {\n this.closed = true;\n if (this.resolveWait) {\n this.resolveWait();\n this.resolveWait = null;\n this.waitPromise = null;\n }\n // Wake up anyone waiting for close\n for (const resolve of this.closeResolvers) {\n resolve();\n }\n this.closeResolvers = [];\n }\n\n async collect(): Promise<Buffer> {\n // Wait until closed\n while (!this.closed) {\n await new Promise<void>((resolve) => {\n this.closeResolvers.push(resolve);\n });\n }\n return Buffer.concat(this.chunks);\n }\n\n async *getReadableStream(): AsyncIterable<Uint8Array> {\n let index = 0;\n\n while (true) {\n while (index < this.chunks.length) {\n yield this.chunks[index]!;\n index++;\n }\n\n if (this.closed) {\n break;\n }\n\n // Wait for more data or close\n if (!this.waitPromise) {\n this.waitPromise = new Promise<void>((resolve) => {\n this.resolveWait = resolve;\n });\n }\n await this.waitPromise;\n }\n }\n}\n\nexport class PipeBuffer implements OutputCollector, Stdout {\n private chunks: Uint8Array[] = [];\n private closed: boolean = false;\n private waitingReaders: Array<() => void> = [];\n private readIndex: number = 0;\n public readonly isTTY: boolean = false;\n\n async write(chunk: Uint8Array): Promise<void> {\n if (this.closed) {\n throw new Error(\"Pipe is closed\");\n }\n this.chunks.push(chunk);\n // Wake up any waiting readers\n for (const resolve of this.waitingReaders) {\n resolve();\n }\n this.waitingReaders = [];\n }\n\n async writeText(str: string): Promise<void> {\n await this.write(new TextEncoder().encode(str));\n }\n\n close(): void {\n this.closed = true;\n // Wake up any waiting readers\n for (const resolve of this.waitingReaders) {\n resolve();\n }\n this.waitingReaders = [];\n }\n\n async collect(): Promise<Buffer> {\n // Wait until closed\n while (!this.closed) {\n await new Promise<void>((resolve) => {\n this.waitingReaders.push(resolve);\n });\n }\n return Buffer.concat(this.chunks);\n }\n\n async *getReadableStream(): AsyncIterable<Uint8Array> {\n while (true) {\n // Yield any available chunks\n while (this.readIndex < this.chunks.length) {\n yield this.chunks[this.readIndex]!;\n this.readIndex++;\n }\n\n if (this.closed) {\n break;\n }\n\n // Wait for more data\n await new Promise<void>((resolve) => {\n this.waitingReaders.push(resolve);\n });\n }\n }\n}\n\nexport function createStdout(isTTY: boolean = false): OutputCollector {\n return new OutputCollectorImpl(isTTY);\n}\n\nexport function createStderr(isTTY: boolean = false): OutputCollector {\n return new OutputCollectorImpl(isTTY);\n}\n\nexport function createPipe(): PipeBuffer {\n return new PipeBuffer();\n}\n\nexport class BufferTargetCollector implements OutputCollector {\n private target: Buffer;\n private offset: number = 0;\n private closed: boolean = false;\n private closeResolvers: Array<() => void> = [];\n public readonly isTTY: boolean = false;\n\n constructor(target: Buffer) {\n this.target = target;\n }\n\n async write(chunk: Uint8Array): Promise<void> {\n if (this.closed) {\n throw new Error(\"Output stream is closed\");\n }\n for (let i = 0; i < chunk.length && this.offset < this.target.length; i++) {\n this.target[this.offset++] = chunk[i]!;\n }\n }\n\n async writeText(str: string): Promise<void> {\n const bytes = new TextEncoder().encode(str);\n await this.write(bytes);\n }\n\n close(): void {\n this.closed = true;\n for (const resolve of this.closeResolvers) {\n resolve();\n }\n this.closeResolvers = [];\n }\n\n async collect(): Promise<Buffer> {\n while (!this.closed) {\n await new Promise<void>((resolve) => {\n this.closeResolvers.push(resolve);\n });\n }\n return this.target.subarray(0, this.offset) as Buffer;\n }\n\n async *getReadableStream(): AsyncIterable<Uint8Array> {\n yield this.target.subarray(0, this.offset);\n }\n}\n\nexport function createBufferTargetCollector(target: Buffer): OutputCollector {\n return new BufferTargetCollector(target);\n}\n"
5
+ "import type { Stdout, Stderr, OutputCollector } from \"../types.cjs\";\n\nexport class OutputCollectorImpl implements OutputCollector {\n private chunks: Uint8Array[] = [];\n private closed: boolean = false;\n private closeResolvers: Array<() => void> = [];\n private resolveWait: (() => void) | null = null;\n private waitPromise: Promise<void> | null = null;\n public isTTY: boolean;\n private onWrite?: (chunk: Uint8Array) => void | Promise<void>;\n\n constructor(isTTY: boolean = false, onWrite?: (chunk: Uint8Array) => void | Promise<void>) {\n this.isTTY = isTTY;\n this.onWrite = onWrite;\n }\n\n async write(chunk: Uint8Array): Promise<void> {\n if (this.closed) {\n throw new Error(\"Output stream is closed\");\n }\n this.chunks.push(chunk);\n await this.onWrite?.(chunk);\n if (this.resolveWait) {\n this.resolveWait();\n this.resolveWait = null;\n this.waitPromise = null;\n }\n }\n\n async writeText(str: string): Promise<void> {\n await this.write(new TextEncoder().encode(str));\n }\n\n close(): void {\n this.closed = true;\n if (this.resolveWait) {\n this.resolveWait();\n this.resolveWait = null;\n this.waitPromise = null;\n }\n // Wake up anyone waiting for close\n for (const resolve of this.closeResolvers) {\n resolve();\n }\n this.closeResolvers = [];\n }\n\n async collect(): Promise<Buffer> {\n // Wait until closed\n while (!this.closed) {\n await new Promise<void>((resolve) => {\n this.closeResolvers.push(resolve);\n });\n }\n return Buffer.concat(this.chunks);\n }\n\n async *getReadableStream(): AsyncIterable<Uint8Array> {\n let index = 0;\n\n while (true) {\n while (index < this.chunks.length) {\n yield this.chunks[index]!;\n index++;\n }\n\n if (this.closed) {\n break;\n }\n\n // Wait for more data or close\n if (!this.waitPromise) {\n this.waitPromise = new Promise<void>((resolve) => {\n this.resolveWait = resolve;\n });\n }\n await this.waitPromise;\n }\n }\n}\n\nexport class PipeBuffer implements OutputCollector, Stdout {\n private chunks: Uint8Array[] = [];\n private closed: boolean = false;\n private waitingReaders: Array<() => void> = [];\n private readIndex: number = 0;\n public readonly isTTY: boolean = false;\n\n async write(chunk: Uint8Array): Promise<void> {\n if (this.closed) {\n throw new Error(\"Pipe is closed\");\n }\n this.chunks.push(chunk);\n // Wake up any waiting readers\n for (const resolve of this.waitingReaders) {\n resolve();\n }\n this.waitingReaders = [];\n }\n\n async writeText(str: string): Promise<void> {\n await this.write(new TextEncoder().encode(str));\n }\n\n close(): void {\n this.closed = true;\n // Wake up any waiting readers\n for (const resolve of this.waitingReaders) {\n resolve();\n }\n this.waitingReaders = [];\n }\n\n async collect(): Promise<Buffer> {\n // Wait until closed\n while (!this.closed) {\n await new Promise<void>((resolve) => {\n this.waitingReaders.push(resolve);\n });\n }\n return Buffer.concat(this.chunks);\n }\n\n async *getReadableStream(): AsyncIterable<Uint8Array> {\n while (true) {\n // Yield any available chunks\n while (this.readIndex < this.chunks.length) {\n yield this.chunks[this.readIndex]!;\n this.readIndex++;\n }\n\n if (this.closed) {\n break;\n }\n\n // Wait for more data\n await new Promise<void>((resolve) => {\n this.waitingReaders.push(resolve);\n });\n }\n }\n}\n\nexport function createStdout(\n isTTY: boolean = false,\n onWrite?: (chunk: Uint8Array) => void | Promise<void>\n): OutputCollector {\n return new OutputCollectorImpl(isTTY, onWrite);\n}\n\nexport function createStderr(\n isTTY: boolean = false,\n onWrite?: (chunk: Uint8Array) => void | Promise<void>\n): OutputCollector {\n return new OutputCollectorImpl(isTTY, onWrite);\n}\n\nexport function createPipe(): PipeBuffer {\n return new PipeBuffer();\n}\n\nexport class BufferTargetCollector implements OutputCollector {\n private target: Buffer;\n private offset: number = 0;\n private closed: boolean = false;\n private closeResolvers: Array<() => void> = [];\n public readonly isTTY: boolean = false;\n\n constructor(target: Buffer) {\n this.target = target;\n }\n\n async write(chunk: Uint8Array): Promise<void> {\n if (this.closed) {\n throw new Error(\"Output stream is closed\");\n }\n for (let i = 0; i < chunk.length && this.offset < this.target.length; i++) {\n this.target[this.offset++] = chunk[i]!;\n }\n }\n\n async writeText(str: string): Promise<void> {\n const bytes = new TextEncoder().encode(str);\n await this.write(bytes);\n }\n\n close(): void {\n this.closed = true;\n for (const resolve of this.closeResolvers) {\n resolve();\n }\n this.closeResolvers = [];\n }\n\n async collect(): Promise<Buffer> {\n while (!this.closed) {\n await new Promise<void>((resolve) => {\n this.closeResolvers.push(resolve);\n });\n }\n return this.target.subarray(0, this.offset) as Buffer;\n }\n\n async *getReadableStream(): AsyncIterable<Uint8Array> {\n yield this.target.subarray(0, this.offset);\n }\n}\n\nexport function createBufferTargetCollector(target: Buffer): OutputCollector {\n return new BufferTargetCollector(target);\n}\n"
6
6
  ],
7
- "mappings": "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",
8
- "debugId": "00CF2D6942739CDC64756E2164756E21",
7
+ "mappings": "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",
8
+ "debugId": "2F5A4E06A0B3D2B364756E2164756E21",
9
9
  "names": []
10
10
  }
@@ -59,6 +59,8 @@ class ShellDSL {
59
59
  commands;
60
60
  shouldThrow = true;
61
61
  isTTY;
62
+ terminal;
63
+ externalCommand;
62
64
  constructor(config) {
63
65
  this.fs = config.fs;
64
66
  this.initialCwd = config.cwd;
@@ -66,7 +68,9 @@ class ShellDSL {
66
68
  this.currentCwd = config.cwd;
67
69
  this.currentEnv = { ...config.env };
68
70
  this.commands = config.commands;
69
- this.isTTY = config.isTTY ?? false;
71
+ this.terminal = config.terminal ?? { isTTY: config.isTTY ?? false };
72
+ this.isTTY = this.terminal.isTTY;
73
+ this.externalCommand = config.externalCommand;
70
74
  }
71
75
  tag(strings, ...values) {
72
76
  let source = strings[0] ?? "";
@@ -117,7 +121,8 @@ class ShellDSL {
117
121
  env,
118
122
  commands: shell.commands,
119
123
  redirectObjects: options?.redirectObjects,
120
- isTTY: shell.isTTY
124
+ terminal: shell.terminal,
125
+ externalCommand: shell.externalCommand
121
126
  });
122
127
  const tokens = shell.lex(source);
123
128
  const ast = shell.parse(tokens);
@@ -164,7 +169,8 @@ class ShellDSL {
164
169
  cwd: this.currentCwd,
165
170
  env: this.currentEnv,
166
171
  commands: this.commands,
167
- isTTY: this.isTTY
172
+ terminal: this.terminal,
173
+ externalCommand: this.externalCommand
168
174
  });
169
175
  return interpreter.execute(program.ast);
170
176
  }
@@ -183,7 +189,9 @@ function createShellDSL(config) {
183
189
  currentEnv: shell.currentEnv,
184
190
  commands: shell.commands,
185
191
  shouldThrow: shell.shouldThrow,
186
- isTTY: shell.isTTY
192
+ isTTY: shell.isTTY,
193
+ terminal: shell.terminal,
194
+ externalCommand: shell.externalCommand
187
195
  });
188
196
  tag.cwd = shell.cwd.bind(shell);
189
197
  tag.env = shell.env.bind(shell);
@@ -199,4 +207,4 @@ function createShellDSL(config) {
199
207
  return tag;
200
208
  }
201
209
 
202
- //# debugId=B7BC9122B94DF74D64756E2164756E21
210
+ //# debugId=ECF0DF1AD7027E4E64756E2164756E21
@@ -2,9 +2,9 @@
2
2
  "version": 3,
3
3
  "sources": ["../../../src/shell-dsl.ts"],
4
4
  "sourcesContent": [
5
- "import type { ShellConfig, Command, VirtualFS, ExecResult, RedirectObjectMap } from \"./types.cjs\";\nimport { isRawValue, isRedirectObject } from \"./types.cjs\";\nimport type { Token } from \"./lexer/tokens.cjs\";\nimport type { ASTNode } from \"./parser/ast.cjs\";\nimport { Lexer } from \"./lexer/lexer.cjs\";\nimport { Parser } from \"./parser/parser.cjs\";\nimport { Interpreter } from \"./interpreter/interpreter.cjs\";\nimport { ShellPromise } from \"./shell-promise.cjs\";\nimport { escape, escapeForInterpolation } from \"./utils/escape.cjs\";\n\nexport interface Program {\n ast: ASTNode;\n source: string;\n}\n\nexport class ShellDSL {\n private fs: VirtualFS;\n private initialCwd: string;\n private initialEnv: Record<string, string>;\n private currentCwd: string;\n private currentEnv: Record<string, string>;\n private commands: Record<string, Command>;\n private shouldThrow: boolean = true;\n private isTTY: boolean;\n\n constructor(config: ShellConfig) {\n this.fs = config.fs;\n this.initialCwd = config.cwd;\n this.initialEnv = { ...config.env };\n this.currentCwd = config.cwd;\n this.currentEnv = { ...config.env };\n this.commands = config.commands;\n this.isTTY = config.isTTY ?? false;\n }\n\n // Template tag function\n tag(strings: TemplateStringsArray, ...values: unknown[]): ShellPromise {\n // Build the command string with escaped interpolations\n let source = strings[0] ?? \"\";\n const redirectObjects: RedirectObjectMap = {};\n let objIndex = 0;\n\n for (let i = 0; i < values.length; i++) {\n const value = values[i];\n const precedingString = strings[i] ?? \"\";\n\n if (isRawValue(value)) {\n source += value.raw;\n } else if (this.isRedirectTarget(precedingString, value)) {\n // Value appears after a redirect operator - store as redirect object\n const marker = `__REDIR_OBJ_${objIndex++}__`;\n redirectObjects[marker] = value as Buffer | Blob | Response | string;\n source += marker;\n } else {\n source += escapeForInterpolation(value);\n }\n source += strings[i + 1] ?? \"\";\n }\n\n return this.createPromise(source, { redirectObjects });\n }\n\n private isRedirectTarget(precedingString: string, value: unknown): boolean {\n // Check if value is a redirect object type AND appears after redirect operator\n if (!isRedirectObject(value) || isRawValue(value)) {\n return false;\n }\n // Check if preceding string ends with redirect operator\n const trimmed = precedingString.trimEnd();\n const afterRedirectOp = /(<|>|>>|2>|2>>|&>|&>>)\\s*$/.test(trimmed);\n\n if (!afterRedirectOp) {\n return false;\n }\n\n // Buffer, Blob, Response are always treated as redirect objects\n if (Buffer.isBuffer(value) || value instanceof Blob || value instanceof Response) {\n return true;\n }\n\n // For strings after input redirect (<), treat as content per spec\n // For strings after output redirect (>), they must be Buffers\n if (typeof value === \"string\") {\n // Only input redirection supports string content\n return /<\\s*$/.test(trimmed);\n }\n\n return false;\n }\n\n private createPromise(source: string, options?: { cwd?: string; env?: Record<string, string>; shouldThrow?: boolean; redirectObjects?: RedirectObjectMap }): ShellPromise {\n const shell = this;\n\n return new ShellPromise({\n execute: async (overrides) => {\n const cwd = overrides?.cwd ?? options?.cwd ?? shell.currentCwd;\n const env = { ...shell.currentEnv, ...options?.env, ...overrides?.env };\n\n const interpreter = new Interpreter({\n fs: shell.fs,\n cwd,\n env,\n commands: shell.commands,\n redirectObjects: options?.redirectObjects,\n isTTY: shell.isTTY,\n });\n\n const tokens = shell.lex(source);\n const ast = shell.parse(tokens);\n return interpreter.execute(ast);\n },\n cwdOverride: options?.cwd,\n envOverride: options?.env,\n shouldThrow: options?.shouldThrow ?? this.shouldThrow,\n });\n }\n\n // Global defaults\n cwd(path: string): void {\n this.currentCwd = path;\n }\n\n env(vars: Record<string, string>): void {\n Object.assign(this.currentEnv, vars);\n }\n\n throws(enable: boolean): void {\n this.shouldThrow = enable;\n }\n\n resetCwd(): void {\n this.currentCwd = this.initialCwd;\n }\n\n resetEnv(): void {\n this.currentEnv = { ...this.initialEnv };\n }\n\n // Utility\n escape(str: string): string {\n return escape(str);\n }\n\n // Low-level API\n lex(source: string): Token[] {\n return new Lexer(source, { preserveNewlines: true }).tokenize();\n }\n\n parse(tokens: Token[]): ASTNode {\n return new Parser(tokens).parse();\n }\n\n compile(ast: ASTNode): Program {\n // For now, the \"program\" is just the AST with source reconstruction\n return {\n ast,\n source: \"\", // Could reconstruct source from AST if needed\n };\n }\n\n async run(program: Program): Promise<ExecResult> {\n const interpreter = new Interpreter({\n fs: this.fs,\n cwd: this.currentCwd,\n env: this.currentEnv,\n commands: this.commands,\n isTTY: this.isTTY,\n });\n\n return interpreter.execute(program.ast);\n }\n}\n\n// Factory function that returns a callable template tag\nexport function createShellDSL(config: ShellConfig): ShellDSL & ((strings: TemplateStringsArray, ...values: unknown[]) => ShellPromise) {\n const shell = new ShellDSL(config);\n\n // Create a function that acts as both tag and shell instance\n const tag = (strings: TemplateStringsArray, ...values: unknown[]) => {\n return shell.tag(strings, ...values);\n };\n\n // Copy all properties and methods from shell to tag function\n Object.setPrototypeOf(tag, ShellDSL.prototype);\n Object.assign(tag, {\n fs: (shell as any).fs,\n initialCwd: (shell as any).initialCwd,\n initialEnv: (shell as any).initialEnv,\n currentCwd: (shell as any).currentCwd,\n currentEnv: (shell as any).currentEnv,\n commands: (shell as any).commands,\n shouldThrow: (shell as any).shouldThrow,\n isTTY: (shell as any).isTTY,\n });\n\n // Bind methods\n (tag as any).cwd = shell.cwd.bind(shell);\n (tag as any).env = shell.env.bind(shell);\n (tag as any).throws = shell.throws.bind(shell);\n (tag as any).resetCwd = shell.resetCwd.bind(shell);\n (tag as any).resetEnv = shell.resetEnv.bind(shell);\n (tag as any).escape = shell.escape.bind(shell);\n (tag as any).lex = shell.lex.bind(shell);\n (tag as any).parse = shell.parse.bind(shell);\n (tag as any).compile = shell.compile.bind(shell);\n (tag as any).run = shell.run.bind(shell);\n (tag as any).tag = shell.tag.bind(shell);\n\n return tag as ShellDSL & ((strings: TemplateStringsArray, ...values: unknown[]) => ShellPromise);\n}\n"
5
+ "import type {\n ShellConfig,\n Command,\n VirtualFS,\n ExecResult,\n RedirectObjectMap,\n TerminalInfo,\n ShellCommandFallback,\n} from \"./types.cjs\";\nimport { isRawValue, isRedirectObject } from \"./types.cjs\";\nimport type { Token } from \"./lexer/tokens.cjs\";\nimport type { ASTNode } from \"./parser/ast.cjs\";\nimport { Lexer } from \"./lexer/lexer.cjs\";\nimport { Parser } from \"./parser/parser.cjs\";\nimport { Interpreter } from \"./interpreter/interpreter.cjs\";\nimport { ShellPromise } from \"./shell-promise.cjs\";\nimport { escape, escapeForInterpolation } from \"./utils/escape.cjs\";\n\nexport interface Program {\n ast: ASTNode;\n source: string;\n}\n\nexport class ShellDSL {\n private fs: VirtualFS;\n private initialCwd: string;\n private initialEnv: Record<string, string>;\n private currentCwd: string;\n private currentEnv: Record<string, string>;\n private commands: Record<string, Command>;\n private shouldThrow: boolean = true;\n private isTTY: boolean;\n private terminal: TerminalInfo;\n private externalCommand?: ShellCommandFallback;\n\n constructor(config: ShellConfig) {\n this.fs = config.fs;\n this.initialCwd = config.cwd;\n this.initialEnv = { ...config.env };\n this.currentCwd = config.cwd;\n this.currentEnv = { ...config.env };\n this.commands = config.commands;\n this.terminal = config.terminal ?? { isTTY: config.isTTY ?? false };\n this.isTTY = this.terminal.isTTY;\n this.externalCommand = config.externalCommand;\n }\n\n // Template tag function\n tag(strings: TemplateStringsArray, ...values: unknown[]): ShellPromise {\n // Build the command string with escaped interpolations\n let source = strings[0] ?? \"\";\n const redirectObjects: RedirectObjectMap = {};\n let objIndex = 0;\n\n for (let i = 0; i < values.length; i++) {\n const value = values[i];\n const precedingString = strings[i] ?? \"\";\n\n if (isRawValue(value)) {\n source += value.raw;\n } else if (this.isRedirectTarget(precedingString, value)) {\n // Value appears after a redirect operator - store as redirect object\n const marker = `__REDIR_OBJ_${objIndex++}__`;\n redirectObjects[marker] = value as Buffer | Blob | Response | string;\n source += marker;\n } else {\n source += escapeForInterpolation(value);\n }\n source += strings[i + 1] ?? \"\";\n }\n\n return this.createPromise(source, { redirectObjects });\n }\n\n private isRedirectTarget(precedingString: string, value: unknown): boolean {\n // Check if value is a redirect object type AND appears after redirect operator\n if (!isRedirectObject(value) || isRawValue(value)) {\n return false;\n }\n // Check if preceding string ends with redirect operator\n const trimmed = precedingString.trimEnd();\n const afterRedirectOp = /(<|>|>>|2>|2>>|&>|&>>)\\s*$/.test(trimmed);\n\n if (!afterRedirectOp) {\n return false;\n }\n\n // Buffer, Blob, Response are always treated as redirect objects\n if (Buffer.isBuffer(value) || value instanceof Blob || value instanceof Response) {\n return true;\n }\n\n // For strings after input redirect (<), treat as content per spec\n // For strings after output redirect (>), they must be Buffers\n if (typeof value === \"string\") {\n // Only input redirection supports string content\n return /<\\s*$/.test(trimmed);\n }\n\n return false;\n }\n\n private createPromise(source: string, options?: { cwd?: string; env?: Record<string, string>; shouldThrow?: boolean; redirectObjects?: RedirectObjectMap }): ShellPromise {\n const shell = this;\n\n return new ShellPromise({\n execute: async (overrides) => {\n const cwd = overrides?.cwd ?? options?.cwd ?? shell.currentCwd;\n const env = { ...shell.currentEnv, ...options?.env, ...overrides?.env };\n\n const interpreter = new Interpreter({\n fs: shell.fs,\n cwd,\n env,\n commands: shell.commands,\n redirectObjects: options?.redirectObjects,\n terminal: shell.terminal,\n externalCommand: shell.externalCommand,\n });\n\n const tokens = shell.lex(source);\n const ast = shell.parse(tokens);\n return interpreter.execute(ast);\n },\n cwdOverride: options?.cwd,\n envOverride: options?.env,\n shouldThrow: options?.shouldThrow ?? this.shouldThrow,\n });\n }\n\n // Global defaults\n cwd(path: string): void {\n this.currentCwd = path;\n }\n\n env(vars: Record<string, string>): void {\n Object.assign(this.currentEnv, vars);\n }\n\n throws(enable: boolean): void {\n this.shouldThrow = enable;\n }\n\n resetCwd(): void {\n this.currentCwd = this.initialCwd;\n }\n\n resetEnv(): void {\n this.currentEnv = { ...this.initialEnv };\n }\n\n // Utility\n escape(str: string): string {\n return escape(str);\n }\n\n // Low-level API\n lex(source: string): Token[] {\n return new Lexer(source, { preserveNewlines: true }).tokenize();\n }\n\n parse(tokens: Token[]): ASTNode {\n return new Parser(tokens).parse();\n }\n\n compile(ast: ASTNode): Program {\n // For now, the \"program\" is just the AST with source reconstruction\n return {\n ast,\n source: \"\", // Could reconstruct source from AST if needed\n };\n }\n\n async run(program: Program): Promise<ExecResult> {\n const interpreter = new Interpreter({\n fs: this.fs,\n cwd: this.currentCwd,\n env: this.currentEnv,\n commands: this.commands,\n terminal: this.terminal,\n externalCommand: this.externalCommand,\n });\n\n return interpreter.execute(program.ast);\n }\n}\n\n// Factory function that returns a callable template tag\nexport function createShellDSL(config: ShellConfig): ShellDSL & ((strings: TemplateStringsArray, ...values: unknown[]) => ShellPromise) {\n const shell = new ShellDSL(config);\n\n // Create a function that acts as both tag and shell instance\n const tag = (strings: TemplateStringsArray, ...values: unknown[]) => {\n return shell.tag(strings, ...values);\n };\n\n // Copy all properties and methods from shell to tag function\n Object.setPrototypeOf(tag, ShellDSL.prototype);\n Object.assign(tag, {\n fs: (shell as any).fs,\n initialCwd: (shell as any).initialCwd,\n initialEnv: (shell as any).initialEnv,\n currentCwd: (shell as any).currentCwd,\n currentEnv: (shell as any).currentEnv,\n commands: (shell as any).commands,\n shouldThrow: (shell as any).shouldThrow,\n isTTY: (shell as any).isTTY,\n terminal: (shell as any).terminal,\n externalCommand: (shell as any).externalCommand,\n });\n\n // Bind methods\n (tag as any).cwd = shell.cwd.bind(shell);\n (tag as any).env = shell.env.bind(shell);\n (tag as any).throws = shell.throws.bind(shell);\n (tag as any).resetCwd = shell.resetCwd.bind(shell);\n (tag as any).resetEnv = shell.resetEnv.bind(shell);\n (tag as any).escape = shell.escape.bind(shell);\n (tag as any).lex = shell.lex.bind(shell);\n (tag as any).parse = shell.parse.bind(shell);\n (tag as any).compile = shell.compile.bind(shell);\n (tag as any).run = shell.run.bind(shell);\n (tag as any).tag = shell.tag.bind(shell);\n\n return tag as ShellDSL & ((strings: TemplateStringsArray, ...values: unknown[]) => ShellPromise);\n}\n"
6
6
  ],
7
- "mappings": "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",
8
- "debugId": "B7BC9122B94DF74D64756E2164756E21",
7
+ "mappings": "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",
8
+ "debugId": "ECF0DF1AD7027E4E64756E2164756E21",
9
9
  "names": []
10
10
  }
@@ -0,0 +1,222 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropNames = Object.getOwnPropertyNames;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
5
+ function __accessProp(key) {
6
+ return this[key];
7
+ }
8
+ var __toCommonJS = (from) => {
9
+ var entry = (__moduleCache ??= new WeakMap).get(from), desc;
10
+ if (entry)
11
+ return entry;
12
+ entry = __defProp({}, "__esModule", { value: true });
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (var key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(entry, key))
16
+ __defProp(entry, key, {
17
+ get: __accessProp.bind(from, key),
18
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
19
+ });
20
+ }
21
+ __moduleCache.set(from, entry);
22
+ return entry;
23
+ };
24
+ var __moduleCache;
25
+ var __returnValue = (v) => v;
26
+ function __exportSetter(name, newValue) {
27
+ this[name] = __returnValue.bind(null, newValue);
28
+ }
29
+ var __export = (target, all) => {
30
+ for (var name in all)
31
+ __defProp(target, name, {
32
+ get: all[name],
33
+ enumerable: true,
34
+ configurable: true,
35
+ set: __exportSetter.bind(all, name)
36
+ });
37
+ };
38
+
39
+ // src/shell-session.ts
40
+ var exports_shell_session = {};
41
+ __export(exports_shell_session, {
42
+ createShellSession: () => createShellSession,
43
+ ShellSession: () => ShellSession
44
+ });
45
+ module.exports = __toCommonJS(exports_shell_session);
46
+ var import_lexer = require("./lexer/lexer.cjs");
47
+ var import_parser = require("./parser/parser.cjs");
48
+ var import_interpreter = require("./interpreter/interpreter.cjs");
49
+ var import_stdout = require("./io/stdout.cjs");
50
+ var import_async_queue = require("./io/async-queue.cjs");
51
+
52
+ class ShellSession {
53
+ fs;
54
+ commands;
55
+ completions;
56
+ terminal;
57
+ interpreter;
58
+ constructor(options) {
59
+ this.fs = options.fs;
60
+ this.commands = options.commands;
61
+ this.completions = options.completions ?? {};
62
+ this.terminal = options.terminal ?? { isTTY: options.isTTY ?? false };
63
+ this.interpreter = new import_interpreter.Interpreter({
64
+ fs: options.fs,
65
+ cwd: options.cwd,
66
+ env: options.env,
67
+ commands: options.commands,
68
+ terminal: this.terminal,
69
+ externalCommand: options.externalCommand
70
+ });
71
+ }
72
+ run(source, options = {}) {
73
+ try {
74
+ const tokens = new import_lexer.Lexer(source, { preserveNewlines: true }).tokenize();
75
+ if (tokens.every((token) => token.type === "newline" || token.type === "eof")) {
76
+ return this.createImmediateExecution(0, "", "");
77
+ }
78
+ const ast = new import_parser.Parser(tokens).parse();
79
+ return this.interpreter.executeStreaming(ast, options);
80
+ } catch (err) {
81
+ const message = err instanceof Error ? err.message : String(err);
82
+ return this.createImmediateExecution(2, "", `sh: ${message}
83
+ `);
84
+ }
85
+ }
86
+ runProgram(program, options = {}) {
87
+ return this.interpreter.executeStreaming(program.ast, options);
88
+ }
89
+ getCwd() {
90
+ return this.interpreter.getCwd();
91
+ }
92
+ getEnv() {
93
+ return this.interpreter.getEnv();
94
+ }
95
+ getLastExitCode() {
96
+ return this.interpreter.getLastExitCode();
97
+ }
98
+ async complete(source, cursor = source.length) {
99
+ const boundedCursor = Math.max(0, Math.min(cursor, source.length));
100
+ const prefix = source.slice(0, boundedCursor);
101
+ const { word, start } = getCurrentWord(prefix);
102
+ if (isCommandPosition(prefix, start) && !looksLikePath(word)) {
103
+ return {
104
+ replacement: word,
105
+ matches: Object.keys(this.commands).filter((name) => name.startsWith(word)).sort().map((name) => `${name} `)
106
+ };
107
+ }
108
+ const commandLine = getCurrentCommandLine(prefix, start);
109
+ const [command = "", ...args] = splitCompletionWords(commandLine);
110
+ const completer = command === "" ? undefined : this.completions[command];
111
+ if (completer) {
112
+ return completer({
113
+ source,
114
+ cursor: boundedCursor,
115
+ command,
116
+ args,
117
+ word,
118
+ wordStart: start,
119
+ wordEnd: boundedCursor,
120
+ cwd: this.getCwd(),
121
+ env: this.getEnv(),
122
+ fs: this.fs,
123
+ terminal: this.terminal
124
+ });
125
+ }
126
+ return this.completePath(word);
127
+ }
128
+ async dispose() {}
129
+ async completePath(word) {
130
+ const slash = word.lastIndexOf("/");
131
+ const dirPart = slash === -1 ? "" : word.slice(0, slash + 1);
132
+ const namePrefix = slash === -1 ? word : word.slice(slash + 1);
133
+ const basePath = dirPart === "" ? this.getCwd() : dirPart.startsWith("/") ? dirPart : this.fs.resolve(this.getCwd(), dirPart);
134
+ let entries;
135
+ try {
136
+ entries = await this.fs.readdir(basePath);
137
+ } catch {
138
+ return { replacement: word, matches: [] };
139
+ }
140
+ const matches = await Promise.all(entries.filter((entry) => entry.startsWith(namePrefix)).sort().map(async (entry) => {
141
+ const candidate = `${dirPart}${escapeCompletionSegment(entry)}`;
142
+ const path = this.fs.resolve(basePath, entry);
143
+ try {
144
+ const stat = await this.fs.stat(path);
145
+ return stat.isDirectory() ? `${candidate}/` : candidate;
146
+ } catch {
147
+ return candidate;
148
+ }
149
+ }));
150
+ if (matches.length === 1 && !matches[0].endsWith("/")) {
151
+ matches[0] = `${matches[0]} `;
152
+ }
153
+ return { replacement: word, matches };
154
+ }
155
+ createImmediateExecution(exitCode, stdoutText, stderrText) {
156
+ const stdout = import_stdout.createStdout();
157
+ const stderr = import_stdout.createStderr();
158
+ const output = new import_async_queue.AsyncQueue;
159
+ const exit = (async () => {
160
+ if (stdoutText.length > 0) {
161
+ const chunk = new TextEncoder().encode(stdoutText);
162
+ output.push({ fd: 1, chunk });
163
+ await stdout.write(chunk);
164
+ }
165
+ if (stderrText.length > 0) {
166
+ const chunk = new TextEncoder().encode(stderrText);
167
+ output.push({ fd: 2, chunk });
168
+ await stderr.write(chunk);
169
+ }
170
+ stdout.close();
171
+ stderr.close();
172
+ output.close();
173
+ return {
174
+ stdout: await stdout.collect(),
175
+ stderr: await stderr.collect(),
176
+ exitCode
177
+ };
178
+ })();
179
+ return {
180
+ stdout: stdout.getReadableStream(),
181
+ stderr: stderr.getReadableStream(),
182
+ output,
183
+ exit,
184
+ kill: () => {}
185
+ };
186
+ }
187
+ }
188
+ function createShellSession(config) {
189
+ return new ShellSession(config);
190
+ }
191
+ function getCurrentWord(prefix) {
192
+ let start = prefix.length;
193
+ while (start > 0 && !/\s/.test(prefix[start - 1])) {
194
+ start--;
195
+ }
196
+ return { word: prefix.slice(start), start };
197
+ }
198
+ function isCommandPosition(prefix, wordStart) {
199
+ const beforeWord = prefix.slice(0, wordStart);
200
+ const segmentStart = Math.max(beforeWord.lastIndexOf(";"), beforeWord.lastIndexOf("|"), beforeWord.lastIndexOf("&"));
201
+ const segment = beforeWord.slice(segmentStart + 1).trim();
202
+ if (segment === "") {
203
+ return true;
204
+ }
205
+ return segment.split(/\s+/).every((part) => /^[A-Za-z_][A-Za-z0-9_]*=/.test(part));
206
+ }
207
+ function getCurrentCommandLine(prefix, wordStart) {
208
+ const beforeWord = prefix.slice(0, wordStart);
209
+ const segmentStart = Math.max(beforeWord.lastIndexOf(";"), beforeWord.lastIndexOf("|"), beforeWord.lastIndexOf("&"));
210
+ return prefix.slice(segmentStart + 1).trimStart();
211
+ }
212
+ function splitCompletionWords(source) {
213
+ return source.trim().split(/\s+/).filter(Boolean);
214
+ }
215
+ function looksLikePath(word) {
216
+ return word.startsWith("/") || word.startsWith(".") || word.includes("/");
217
+ }
218
+ function escapeCompletionSegment(segment) {
219
+ return segment.replace(/([\s\\'"$`!#&;|<>()[\]{}*?])/g, "\\$1");
220
+ }
221
+
222
+ //# debugId=C807EA9CC9D2A2E164756E2164756E21
@@ -0,0 +1,10 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/shell-session.ts"],
4
+ "sourcesContent": [
5
+ "import type {\n Command,\n CommandCompleter,\n CompletionResult,\n ExecResult,\n ShellCommandFallback,\n ShellConfig,\n ShellExecution,\n ShellExecutionOptions,\n TerminalInfo,\n VirtualFS,\n} from \"./types.cjs\";\nimport type { Program } from \"./shell-dsl.cjs\";\nimport { Lexer } from \"./lexer/lexer.cjs\";\nimport { Parser } from \"./parser/parser.cjs\";\nimport { Interpreter } from \"./interpreter/interpreter.cjs\";\nimport { createStderr, createStdout } from \"./io/stdout.cjs\";\nimport { AsyncQueue } from \"./io/async-queue.cjs\";\nimport type { ShellOutputEvent } from \"./types.cjs\";\n\nexport interface ShellSessionOptions {\n fs: VirtualFS;\n cwd: string;\n env: Record<string, string>;\n commands: Record<string, Command>;\n completions?: Record<string, CommandCompleter>;\n isTTY?: boolean;\n terminal?: TerminalInfo;\n externalCommand?: ShellCommandFallback;\n}\n\nexport class ShellSession {\n private fs: VirtualFS;\n private commands: Record<string, Command>;\n private completions: Record<string, CommandCompleter>;\n private terminal: TerminalInfo;\n private interpreter: Interpreter;\n\n constructor(options: ShellSessionOptions) {\n this.fs = options.fs;\n this.commands = options.commands;\n this.completions = options.completions ?? {};\n this.terminal = options.terminal ?? { isTTY: options.isTTY ?? false };\n this.interpreter = new Interpreter({\n fs: options.fs,\n cwd: options.cwd,\n env: options.env,\n commands: options.commands,\n terminal: this.terminal,\n externalCommand: options.externalCommand,\n });\n }\n\n run(source: string, options: ShellExecutionOptions = {}): ShellExecution {\n try {\n const tokens = new Lexer(source, { preserveNewlines: true }).tokenize();\n if (tokens.every((token) => token.type === \"newline\" || token.type === \"eof\")) {\n return this.createImmediateExecution(0, \"\", \"\");\n }\n const ast = new Parser(tokens).parse();\n return this.interpreter.executeStreaming(ast, options);\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n return this.createImmediateExecution(2, \"\", `sh: ${message}\\n`);\n }\n }\n\n runProgram(program: Program, options: ShellExecutionOptions = {}): ShellExecution {\n return this.interpreter.executeStreaming(program.ast, options);\n }\n\n getCwd(): string {\n return this.interpreter.getCwd();\n }\n\n getEnv(): Record<string, string> {\n return this.interpreter.getEnv();\n }\n\n getLastExitCode(): number {\n return this.interpreter.getLastExitCode();\n }\n\n async complete(source: string, cursor: number = source.length): Promise<CompletionResult> {\n const boundedCursor = Math.max(0, Math.min(cursor, source.length));\n const prefix = source.slice(0, boundedCursor);\n const { word, start } = getCurrentWord(prefix);\n\n if (isCommandPosition(prefix, start) && !looksLikePath(word)) {\n return {\n replacement: word,\n matches: Object.keys(this.commands)\n .filter((name) => name.startsWith(word))\n .sort()\n .map((name) => `${name} `),\n };\n }\n\n const commandLine = getCurrentCommandLine(prefix, start);\n const [command = \"\", ...args] = splitCompletionWords(commandLine);\n const completer = command === \"\" ? undefined : this.completions[command];\n if (completer) {\n return completer({\n source,\n cursor: boundedCursor,\n command,\n args,\n word,\n wordStart: start,\n wordEnd: boundedCursor,\n cwd: this.getCwd(),\n env: this.getEnv(),\n fs: this.fs,\n terminal: this.terminal,\n });\n }\n\n return this.completePath(word);\n }\n\n async dispose(): Promise<void> {\n // Reserved for future resources owned by a session.\n }\n\n private async completePath(word: string): Promise<CompletionResult> {\n const slash = word.lastIndexOf(\"/\");\n const dirPart = slash === -1 ? \"\" : word.slice(0, slash + 1);\n const namePrefix = slash === -1 ? word : word.slice(slash + 1);\n const basePath = dirPart === \"\"\n ? this.getCwd()\n : dirPart.startsWith(\"/\")\n ? dirPart\n : this.fs.resolve(this.getCwd(), dirPart);\n\n let entries: string[];\n try {\n entries = await this.fs.readdir(basePath);\n } catch {\n return { replacement: word, matches: [] };\n }\n\n const matches = await Promise.all(\n entries\n .filter((entry) => entry.startsWith(namePrefix))\n .sort()\n .map(async (entry) => {\n const candidate = `${dirPart}${escapeCompletionSegment(entry)}`;\n const path = this.fs.resolve(basePath, entry);\n try {\n const stat = await this.fs.stat(path);\n return stat.isDirectory() ? `${candidate}/` : candidate;\n } catch {\n return candidate;\n }\n })\n );\n\n if (matches.length === 1 && !matches[0]!.endsWith(\"/\")) {\n matches[0] = `${matches[0]} `;\n }\n\n return { replacement: word, matches };\n }\n\n private createImmediateExecution(exitCode: number, stdoutText: string, stderrText: string): ShellExecution {\n const stdout = createStdout();\n const stderr = createStderr();\n const output = new AsyncQueue<ShellOutputEvent>();\n\n const exit = (async (): Promise<ExecResult> => {\n if (stdoutText.length > 0) {\n const chunk = new TextEncoder().encode(stdoutText);\n output.push({ fd: 1, chunk });\n await stdout.write(chunk);\n }\n if (stderrText.length > 0) {\n const chunk = new TextEncoder().encode(stderrText);\n output.push({ fd: 2, chunk });\n await stderr.write(chunk);\n }\n stdout.close();\n stderr.close();\n output.close();\n return {\n stdout: await stdout.collect(),\n stderr: await stderr.collect(),\n exitCode,\n };\n })();\n\n return {\n stdout: stdout.getReadableStream(),\n stderr: stderr.getReadableStream(),\n output,\n exit,\n kill: () => {},\n };\n }\n}\n\nexport function createShellSession(config: ShellConfig): ShellSession {\n return new ShellSession(config);\n}\n\nfunction getCurrentWord(prefix: string): { word: string; start: number } {\n let start = prefix.length;\n while (start > 0 && !/\\s/.test(prefix[start - 1]!)) {\n start--;\n }\n return { word: prefix.slice(start), start };\n}\n\nfunction isCommandPosition(prefix: string, wordStart: number): boolean {\n const beforeWord = prefix.slice(0, wordStart);\n const segmentStart = Math.max(\n beforeWord.lastIndexOf(\";\"),\n beforeWord.lastIndexOf(\"|\"),\n beforeWord.lastIndexOf(\"&\")\n );\n const segment = beforeWord.slice(segmentStart + 1).trim();\n if (segment === \"\") {\n return true;\n }\n return segment.split(/\\s+/).every((part) => /^[A-Za-z_][A-Za-z0-9_]*=/.test(part));\n}\n\nfunction getCurrentCommandLine(prefix: string, wordStart: number): string {\n const beforeWord = prefix.slice(0, wordStart);\n const segmentStart = Math.max(\n beforeWord.lastIndexOf(\";\"),\n beforeWord.lastIndexOf(\"|\"),\n beforeWord.lastIndexOf(\"&\")\n );\n return prefix.slice(segmentStart + 1).trimStart();\n}\n\nfunction splitCompletionWords(source: string): string[] {\n return source.trim().split(/\\s+/).filter(Boolean);\n}\n\nfunction looksLikePath(word: string): boolean {\n return word.startsWith(\"/\") || word.startsWith(\".\") || word.includes(\"/\");\n}\n\nfunction escapeCompletionSegment(segment: string): string {\n return segment.replace(/([\\s\\\\'\"$`!#&;|<>()[\\]{}*?])/g, \"\\\\$1\");\n}\n"
6
+ ],
7
+ "mappings": "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",
8
+ "debugId": "C807EA9CC9D2A2E164756E2164756E21",
9
+ "names": []
10
+ }
@@ -2,9 +2,9 @@
2
2
  "version": 3,
3
3
  "sources": ["../../../src/types.ts"],
4
4
  "sourcesContent": [
5
- "// Virtual Filesystem Interface\nexport interface VirtualFSWritable {\n write(chunk: Uint8Array): Promise<void>;\n close(): Promise<void>;\n abort?(reason?: unknown): Promise<void>;\n}\n\nexport interface VirtualFS {\n readFile(path: string): Promise<Buffer>;\n readFile(path: string, encoding: BufferEncoding): Promise<string>;\n readStream(path: string): AsyncIterable<Uint8Array>;\n readdir(path: string): Promise<string[]>;\n stat(path: string): Promise<FileStat>;\n exists(path: string): Promise<boolean>;\n\n writeFile(path: string, data: Buffer | string): Promise<void>;\n appendFile(path: string, data: Buffer | string): Promise<void>;\n writeStream(path: string, opts?: { append?: boolean }): Promise<VirtualFSWritable>;\n mkdir(path: string, opts?: { recursive?: boolean }): Promise<void>;\n\n rm(path: string, opts?: { recursive?: boolean; force?: boolean }): Promise<void>;\n\n resolve(...paths: string[]): string;\n dirname(path: string): string;\n basename(path: string): string;\n glob(pattern: string, opts?: { cwd?: string }): Promise<string[]>;\n}\n\nexport interface FileStat {\n isFile(): boolean;\n isDirectory(): boolean;\n size: number;\n mtime: Date;\n mtimeMs: number;\n}\n\n// Command Interfaces\nexport type Command = (ctx: CommandContext) => Promise<number>;\n\nexport interface ShellRunOptions {\n argv0?: string;\n args?: string[];\n}\n\nexport interface ShellCommandApi {\n eval(source: string): Promise<number>;\n source(path: string, args?: string[]): Promise<number>;\n runScript(path: string, args?: string[]): Promise<number>;\n runShell(source: string, options?: ShellRunOptions): Promise<number>;\n getLastExitCode(): number;\n exit(exitCode?: number): never;\n}\n\nexport interface CommandContext {\n args: string[];\n stdin: Stdin;\n stdout: Stdout;\n stderr: Stderr;\n fs: VirtualFS;\n cwd: string;\n env: Record<string, string>;\n setCwd: (path: string) => void;\n exec?: (name: string, args: string[]) => Promise<ExecResult>;\n shell?: ShellCommandApi;\n}\n\nexport interface Stdin {\n stream(): AsyncIterable<Uint8Array>;\n buffer(): Promise<Buffer>;\n text(): Promise<string>;\n lines(): AsyncIterable<string>;\n}\n\nexport interface Stdout {\n write(chunk: Uint8Array): Promise<void>;\n writeText(str: string): Promise<void>;\n isTTY: boolean;\n}\n\nexport interface Stderr {\n write(chunk: Uint8Array): Promise<void>;\n writeText(str: string): Promise<void>;\n isTTY: boolean;\n}\n\nexport interface OutputCollector extends Stdout {\n close(): void;\n collect(): Promise<Buffer>;\n getReadableStream(): AsyncIterable<Uint8Array>;\n}\n\n// Execution Result\nexport interface ExecResult {\n stdout: Buffer;\n stderr: Buffer;\n exitCode: number;\n}\n\n// Shell Configuration\nexport interface ShellConfig {\n fs: VirtualFS;\n cwd: string;\n env: Record<string, string>;\n commands: Record<string, Command>;\n isTTY?: boolean;\n}\n\n// Raw escape hatch type\nexport interface RawValue {\n raw: string;\n}\n\nexport function isRawValue(value: unknown): value is RawValue {\n return (\n typeof value === \"object\" &&\n value !== null &&\n \"raw\" in value &&\n typeof (value as RawValue).raw === \"string\"\n );\n}\n\n// JS Object Redirection types\nexport type RedirectObject = Buffer | Blob | Response | string;\n\nexport interface RedirectObjectMap {\n [marker: string]: RedirectObject;\n}\n\nexport function isRedirectObject(value: unknown): value is RedirectObject {\n return (\n Buffer.isBuffer(value) ||\n value instanceof Blob ||\n value instanceof Response ||\n typeof value === \"string\"\n );\n}\n"
5
+ "// Virtual Filesystem Interface\nexport interface VirtualFSWritable {\n write(chunk: Uint8Array): Promise<void>;\n close(): Promise<void>;\n abort?(reason?: unknown): Promise<void>;\n}\n\nexport interface VirtualFS {\n readFile(path: string): Promise<Buffer>;\n readFile(path: string, encoding: BufferEncoding): Promise<string>;\n readStream(path: string): AsyncIterable<Uint8Array>;\n readdir(path: string): Promise<string[]>;\n stat(path: string): Promise<FileStat>;\n exists(path: string): Promise<boolean>;\n\n writeFile(path: string, data: Buffer | string): Promise<void>;\n appendFile(path: string, data: Buffer | string): Promise<void>;\n writeStream(path: string, opts?: { append?: boolean }): Promise<VirtualFSWritable>;\n mkdir(path: string, opts?: { recursive?: boolean }): Promise<void>;\n\n rm(path: string, opts?: { recursive?: boolean; force?: boolean }): Promise<void>;\n\n resolve(...paths: string[]): string;\n dirname(path: string): string;\n basename(path: string): string;\n glob(pattern: string, opts?: { cwd?: string }): Promise<string[]>;\n}\n\nexport interface FileStat {\n isFile(): boolean;\n isDirectory(): boolean;\n size: number;\n mtime: Date;\n mtimeMs: number;\n}\n\n// Command Interfaces\nexport type Command = (ctx: CommandContext) => Promise<number>;\n\nexport interface ShellRunOptions {\n argv0?: string;\n args?: string[];\n}\n\nexport interface ShellCommandApi {\n eval(source: string): Promise<number>;\n source(path: string, args?: string[]): Promise<number>;\n runScript(path: string, args?: string[]): Promise<number>;\n runShell(source: string, options?: ShellRunOptions): Promise<number>;\n getLastExitCode(): number;\n exit(exitCode?: number): never;\n}\n\nexport interface TerminalInfo {\n isTTY: boolean;\n columns?: number;\n rows?: number;\n colorDepth?: number;\n}\n\nexport interface CompletionContext {\n source: string;\n cursor: number;\n command: string;\n args: string[];\n word: string;\n wordStart: number;\n wordEnd: number;\n cwd: string;\n env: Record<string, string>;\n fs: VirtualFS;\n terminal: TerminalInfo;\n}\n\nexport interface CompletionResult {\n replacement: string;\n matches: string[];\n}\n\nexport type CommandCompleter = (ctx: CompletionContext) => CompletionResult | Promise<CompletionResult>;\n\nexport interface CommandContext {\n args: string[];\n stdin: Stdin;\n stdout: Stdout;\n stderr: Stderr;\n fs: VirtualFS;\n cwd: string;\n env: Record<string, string>;\n terminal: TerminalInfo;\n signal: AbortSignal;\n setCwd: (path: string) => void;\n exec?: (name: string, args: string[]) => Promise<ExecResult>;\n shell?: ShellCommandApi;\n}\n\nexport interface ExternalCommandContext extends CommandContext {\n name: string;\n}\n\nexport type ShellCommandFallback = (ctx: ExternalCommandContext) => Promise<number>;\n\nexport interface Stdin {\n stream(): AsyncIterable<Uint8Array>;\n buffer(): Promise<Buffer>;\n text(): Promise<string>;\n lines(): AsyncIterable<string>;\n}\n\nexport interface ShellInputController extends AsyncIterable<Uint8Array> {\n write(chunk: Uint8Array | string): Promise<void>;\n close(): void;\n abort(reason?: unknown): void;\n}\n\nexport interface Stdout {\n write(chunk: Uint8Array): Promise<void>;\n writeText(str: string): Promise<void>;\n isTTY: boolean;\n}\n\nexport interface Stderr {\n write(chunk: Uint8Array): Promise<void>;\n writeText(str: string): Promise<void>;\n isTTY: boolean;\n}\n\nexport interface OutputCollector extends Stdout {\n close(): void;\n collect(): Promise<Buffer>;\n getReadableStream(): AsyncIterable<Uint8Array>;\n}\n\n// Execution Result\nexport interface ExecResult {\n stdout: Buffer;\n stderr: Buffer;\n exitCode: number;\n}\n\nexport interface ShellOutputEvent {\n fd: 1 | 2;\n chunk: Uint8Array;\n}\n\nexport type ShellInputSource = AsyncIterable<Uint8Array> | Buffer | string | null;\n\nexport interface ShellExecutionOptions {\n stdin?: ShellInputSource;\n stdout?: Stdout;\n stderr?: Stderr;\n terminal?: TerminalInfo;\n signal?: AbortSignal;\n outputMode?: \"separate\" | \"merged\";\n}\n\nexport interface ShellExecution {\n stdout: AsyncIterable<Uint8Array>;\n stderr: AsyncIterable<Uint8Array>;\n output: AsyncIterable<ShellOutputEvent>;\n exit: Promise<ExecResult>;\n kill(reason?: unknown): void;\n}\n\n// Shell Configuration\nexport interface ShellConfig {\n fs: VirtualFS;\n cwd: string;\n env: Record<string, string>;\n commands: Record<string, Command>;\n completions?: Record<string, CommandCompleter>;\n isTTY?: boolean;\n terminal?: TerminalInfo;\n externalCommand?: ShellCommandFallback;\n}\n\n// Raw escape hatch type\nexport interface RawValue {\n raw: string;\n}\n\nexport function isRawValue(value: unknown): value is RawValue {\n return (\n typeof value === \"object\" &&\n value !== null &&\n \"raw\" in value &&\n typeof (value as RawValue).raw === \"string\"\n );\n}\n\n// JS Object Redirection types\nexport type RedirectObject = Buffer | Blob | Response | string;\n\nexport interface RedirectObjectMap {\n [marker: string]: RedirectObject;\n}\n\nexport function isRedirectObject(value: unknown): value is RedirectObject {\n return (\n Buffer.isBuffer(value) ||\n value instanceof Blob ||\n value instanceof Response ||\n typeof value === \"string\"\n );\n}\n"
6
6
  ],
7
- "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgHO,SAAS,UAAU,CAAC,OAAmC;AAAA,EAC5D,OACE,OAAO,UAAU,YACjB,UAAU,QACV,SAAS,SACT,OAAQ,MAAmB,QAAQ;AAAA;AAWhC,SAAS,gBAAgB,CAAC,OAAyC;AAAA,EACxE,OACE,OAAO,SAAS,KAAK,KACrB,iBAAiB,QACjB,iBAAiB,YACjB,OAAO,UAAU;AAAA;",
7
+ "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAqLO,SAAS,UAAU,CAAC,OAAmC;AAAA,EAC5D,OACE,OAAO,UAAU,YACjB,UAAU,QACV,SAAS,SACT,OAAQ,MAAmB,QAAQ;AAAA;AAWhC,SAAS,gBAAgB,CAAC,OAAyC;AAAA,EACxE,OACE,OAAO,SAAS,KAAK,KACrB,iBAAiB,QACjB,iBAAiB,YACjB,OAAO,UAAU;AAAA;",
8
8
  "debugId": "324A9AF65A2908F664756E2164756E21",
9
9
  "names": []
10
10
  }
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "shell-dsl",
3
- "version": "0.0.40",
3
+ "version": "0.0.42",
4
4
  "type": "module"
5
5
  }