typescript-virtual-container 1.2.4 → 1.2.6

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 (267) hide show
  1. package/README.md +1056 -1239
  2. package/benchmark-results.txt +20 -20
  3. package/dist/SSHMimic/exec.js +2 -2
  4. package/dist/SSHMimic/executor.d.ts +6 -7
  5. package/dist/SSHMimic/executor.d.ts.map +1 -1
  6. package/dist/SSHMimic/executor.js +77 -60
  7. package/dist/SSHMimic/index.d.ts +19 -2
  8. package/dist/SSHMimic/index.d.ts.map +1 -1
  9. package/dist/SSHMimic/index.js +106 -24
  10. package/dist/SSHMimic/sftp.d.ts.map +1 -1
  11. package/dist/SSHMimic/sftp.js +14 -0
  12. package/dist/VirtualFileSystem/index.d.ts +115 -88
  13. package/dist/VirtualFileSystem/index.d.ts.map +1 -1
  14. package/dist/VirtualFileSystem/index.js +389 -264
  15. package/dist/VirtualShell/index.d.ts +3 -4
  16. package/dist/VirtualShell/index.d.ts.map +1 -1
  17. package/dist/VirtualShell/index.js +4 -6
  18. package/dist/VirtualShell/shell.d.ts.map +1 -1
  19. package/dist/VirtualShell/shell.js +19 -2
  20. package/dist/VirtualShell/shellParser.d.ts +20 -2
  21. package/dist/VirtualShell/shellParser.d.ts.map +1 -1
  22. package/dist/VirtualShell/shellParser.js +229 -120
  23. package/dist/VirtualUserManager/index.d.ts +25 -0
  24. package/dist/VirtualUserManager/index.d.ts.map +1 -1
  25. package/dist/VirtualUserManager/index.js +33 -0
  26. package/dist/commands/adduser.d.ts.map +1 -1
  27. package/dist/commands/adduser.js +2 -0
  28. package/dist/commands/awk.d.ts +3 -0
  29. package/dist/commands/awk.d.ts.map +1 -0
  30. package/dist/commands/awk.js +29 -0
  31. package/dist/commands/base64.d.ts +3 -0
  32. package/dist/commands/base64.d.ts.map +1 -0
  33. package/dist/commands/base64.js +20 -0
  34. package/dist/commands/cat.d.ts.map +1 -1
  35. package/dist/commands/cat.js +2 -0
  36. package/dist/commands/cd.d.ts.map +1 -1
  37. package/dist/commands/cd.js +2 -0
  38. package/dist/commands/chmod.d.ts +3 -0
  39. package/dist/commands/chmod.d.ts.map +1 -0
  40. package/dist/commands/chmod.js +33 -0
  41. package/dist/commands/clear.d.ts.map +1 -1
  42. package/dist/commands/clear.js +4 -1
  43. package/dist/commands/cp.d.ts +3 -0
  44. package/dist/commands/cp.d.ts.map +1 -0
  45. package/dist/commands/cp.js +70 -0
  46. package/dist/commands/curl.d.ts.map +1 -1
  47. package/dist/commands/curl.js +2 -0
  48. package/dist/commands/cut.d.ts +3 -0
  49. package/dist/commands/cut.d.ts.map +1 -0
  50. package/dist/commands/cut.js +27 -0
  51. package/dist/commands/date.d.ts +3 -0
  52. package/dist/commands/date.d.ts.map +1 -0
  53. package/dist/commands/date.js +22 -0
  54. package/dist/commands/deluser.d.ts.map +1 -1
  55. package/dist/commands/deluser.js +2 -0
  56. package/dist/commands/df.d.ts +3 -0
  57. package/dist/commands/df.d.ts.map +1 -0
  58. package/dist/commands/df.js +16 -0
  59. package/dist/commands/diff.d.ts +3 -0
  60. package/dist/commands/diff.d.ts.map +1 -0
  61. package/dist/commands/diff.js +40 -0
  62. package/dist/commands/du.d.ts +3 -0
  63. package/dist/commands/du.d.ts.map +1 -0
  64. package/dist/commands/du.js +39 -0
  65. package/dist/commands/echo.d.ts.map +1 -1
  66. package/dist/commands/echo.js +2 -0
  67. package/dist/commands/env.d.ts.map +1 -1
  68. package/dist/commands/env.js +6 -14
  69. package/dist/commands/export.d.ts.map +1 -1
  70. package/dist/commands/export.js +11 -21
  71. package/dist/commands/find.d.ts +3 -0
  72. package/dist/commands/find.d.ts.map +1 -0
  73. package/dist/commands/find.js +50 -0
  74. package/dist/commands/grep.d.ts.map +1 -1
  75. package/dist/commands/grep.js +58 -35
  76. package/dist/commands/groups.d.ts +3 -0
  77. package/dist/commands/groups.d.ts.map +1 -0
  78. package/dist/commands/groups.js +12 -0
  79. package/dist/commands/gzip.d.ts +4 -0
  80. package/dist/commands/gzip.d.ts.map +1 -0
  81. package/dist/commands/gzip.js +40 -0
  82. package/dist/commands/head.d.ts +3 -0
  83. package/dist/commands/head.d.ts.map +1 -0
  84. package/dist/commands/head.js +32 -0
  85. package/dist/commands/help.d.ts +1 -1
  86. package/dist/commands/help.d.ts.map +1 -1
  87. package/dist/commands/help.js +75 -3
  88. package/dist/commands/hostname.d.ts.map +1 -1
  89. package/dist/commands/hostname.js +2 -0
  90. package/dist/commands/htop.d.ts.map +1 -1
  91. package/dist/commands/htop.js +2 -0
  92. package/dist/commands/id.d.ts +3 -0
  93. package/dist/commands/id.d.ts.map +1 -0
  94. package/dist/commands/id.js +14 -0
  95. package/dist/commands/index.d.ts +5 -2
  96. package/dist/commands/index.d.ts.map +1 -1
  97. package/dist/commands/index.js +104 -87
  98. package/dist/commands/kill.d.ts +3 -0
  99. package/dist/commands/kill.d.ts.map +1 -0
  100. package/dist/commands/kill.js +13 -0
  101. package/dist/commands/ln.d.ts +3 -0
  102. package/dist/commands/ln.d.ts.map +1 -0
  103. package/dist/commands/ln.js +44 -0
  104. package/dist/commands/ls.d.ts.map +1 -1
  105. package/dist/commands/ls.js +2 -0
  106. package/dist/commands/mkdir.d.ts.map +1 -1
  107. package/dist/commands/mkdir.js +2 -0
  108. package/dist/commands/mv.d.ts +3 -0
  109. package/dist/commands/mv.d.ts.map +1 -0
  110. package/dist/commands/mv.js +37 -0
  111. package/dist/commands/nano.d.ts.map +1 -1
  112. package/dist/commands/nano.js +2 -0
  113. package/dist/commands/neofetch.d.ts.map +1 -1
  114. package/dist/commands/neofetch.js +2 -0
  115. package/dist/commands/passwd.d.ts.map +1 -1
  116. package/dist/commands/passwd.js +2 -0
  117. package/dist/commands/ping.d.ts +3 -0
  118. package/dist/commands/ping.d.ts.map +1 -0
  119. package/dist/commands/ping.js +18 -0
  120. package/dist/commands/ps.d.ts +3 -0
  121. package/dist/commands/ps.d.ts.map +1 -0
  122. package/dist/commands/ps.js +17 -0
  123. package/dist/commands/pwd.d.ts.map +1 -1
  124. package/dist/commands/pwd.js +2 -0
  125. package/dist/commands/rm.d.ts.map +1 -1
  126. package/dist/commands/rm.js +2 -0
  127. package/dist/commands/sed.d.ts +3 -0
  128. package/dist/commands/sed.d.ts.map +1 -0
  129. package/dist/commands/sed.js +47 -0
  130. package/dist/commands/set.d.ts +3 -0
  131. package/dist/commands/set.d.ts.map +1 -1
  132. package/dist/commands/set.js +19 -46
  133. package/dist/commands/sh.d.ts +0 -1
  134. package/dist/commands/sh.d.ts.map +1 -1
  135. package/dist/commands/sh.js +228 -35
  136. package/dist/commands/sleep.d.ts +3 -0
  137. package/dist/commands/sleep.d.ts.map +1 -0
  138. package/dist/commands/sleep.js +13 -0
  139. package/dist/commands/sort.d.ts +3 -0
  140. package/dist/commands/sort.d.ts.map +1 -0
  141. package/dist/commands/sort.js +37 -0
  142. package/dist/commands/su.d.ts.map +1 -1
  143. package/dist/commands/su.js +2 -0
  144. package/dist/commands/sudo.d.ts.map +1 -1
  145. package/dist/commands/sudo.js +2 -0
  146. package/dist/commands/tail.d.ts +3 -0
  147. package/dist/commands/tail.d.ts.map +1 -0
  148. package/dist/commands/tail.js +35 -0
  149. package/dist/commands/tar.d.ts +3 -0
  150. package/dist/commands/tar.d.ts.map +1 -0
  151. package/dist/commands/tar.js +64 -0
  152. package/dist/commands/tee.d.ts +3 -0
  153. package/dist/commands/tee.d.ts.map +1 -0
  154. package/dist/commands/tee.js +29 -0
  155. package/dist/commands/touch.d.ts.map +1 -1
  156. package/dist/commands/touch.js +2 -0
  157. package/dist/commands/tr.d.ts +3 -0
  158. package/dist/commands/tr.d.ts.map +1 -0
  159. package/dist/commands/tr.js +24 -0
  160. package/dist/commands/tree.d.ts.map +1 -1
  161. package/dist/commands/tree.js +2 -0
  162. package/dist/commands/uname.d.ts +3 -0
  163. package/dist/commands/uname.d.ts.map +1 -0
  164. package/dist/commands/uname.js +21 -0
  165. package/dist/commands/uniq.d.ts +3 -0
  166. package/dist/commands/uniq.d.ts.map +1 -0
  167. package/dist/commands/uniq.js +33 -0
  168. package/dist/commands/unset.d.ts.map +1 -1
  169. package/dist/commands/unset.js +6 -10
  170. package/dist/commands/wc.d.ts +3 -0
  171. package/dist/commands/wc.d.ts.map +1 -0
  172. package/dist/commands/wc.js +50 -0
  173. package/dist/commands/wget.d.ts.map +1 -1
  174. package/dist/commands/wget.js +2 -0
  175. package/dist/commands/who.d.ts.map +1 -1
  176. package/dist/commands/who.js +2 -0
  177. package/dist/commands/whoami.d.ts.map +1 -1
  178. package/dist/commands/whoami.js +2 -0
  179. package/dist/commands/xargs.d.ts +3 -0
  180. package/dist/commands/xargs.d.ts.map +1 -0
  181. package/dist/commands/xargs.js +16 -0
  182. package/dist/index.d.ts +1 -0
  183. package/dist/index.d.ts.map +1 -1
  184. package/dist/types/commands.d.ts +13 -0
  185. package/dist/types/commands.d.ts.map +1 -1
  186. package/dist/types/pipeline.d.ts +20 -0
  187. package/dist/types/pipeline.d.ts.map +1 -1
  188. package/package.json +5 -2
  189. package/scripts/publish-package.sh +70 -0
  190. package/src/SSHMimic/exec.ts +2 -2
  191. package/src/SSHMimic/executor.ts +95 -98
  192. package/src/SSHMimic/index.ts +138 -57
  193. package/src/SSHMimic/sftp.ts +15 -0
  194. package/src/VirtualFileSystem/index.ts +464 -292
  195. package/src/VirtualShell/index.ts +4 -6
  196. package/src/VirtualShell/shell.ts +19 -2
  197. package/src/VirtualShell/shellParser.ts +202 -168
  198. package/src/VirtualUserManager/index.ts +36 -0
  199. package/src/commands/adduser.ts +2 -0
  200. package/src/commands/awk.ts +30 -0
  201. package/src/commands/base64.ts +18 -0
  202. package/src/commands/cat.ts +2 -0
  203. package/src/commands/cd.ts +2 -0
  204. package/src/commands/chmod.ts +35 -0
  205. package/src/commands/clear.ts +4 -1
  206. package/src/commands/cp.ts +78 -0
  207. package/src/commands/curl.ts +2 -0
  208. package/src/commands/cut.ts +29 -0
  209. package/src/commands/date.ts +24 -0
  210. package/src/commands/deluser.ts +2 -0
  211. package/src/commands/df.ts +18 -0
  212. package/src/commands/diff.ts +29 -0
  213. package/src/commands/du.ts +39 -0
  214. package/src/commands/echo.ts +2 -0
  215. package/src/commands/env.ts +6 -16
  216. package/src/commands/export.ts +11 -24
  217. package/src/commands/find.ts +63 -0
  218. package/src/commands/grep.ts +51 -38
  219. package/src/commands/groups.ts +14 -0
  220. package/src/commands/gzip.ts +31 -0
  221. package/src/commands/head.ts +37 -0
  222. package/src/commands/help.ts +81 -3
  223. package/src/commands/hostname.ts +2 -0
  224. package/src/commands/htop.ts +2 -0
  225. package/src/commands/id.ts +16 -0
  226. package/src/commands/index.ts +114 -133
  227. package/src/commands/kill.ts +14 -0
  228. package/src/commands/ln.ts +49 -0
  229. package/src/commands/ls.ts +2 -0
  230. package/src/commands/mkdir.ts +2 -0
  231. package/src/commands/mv.ts +45 -0
  232. package/src/commands/nano.ts +2 -0
  233. package/src/commands/neofetch.ts +2 -0
  234. package/src/commands/passwd.ts +2 -0
  235. package/src/commands/ping.ts +20 -0
  236. package/src/commands/ps.ts +19 -0
  237. package/src/commands/pwd.ts +2 -0
  238. package/src/commands/rm.ts +2 -0
  239. package/src/commands/sed.ts +45 -0
  240. package/src/commands/set.ts +19 -50
  241. package/src/commands/sh.ts +192 -43
  242. package/src/commands/sleep.ts +14 -0
  243. package/src/commands/sort.ts +37 -0
  244. package/src/commands/su.ts +2 -0
  245. package/src/commands/sudo.ts +2 -0
  246. package/src/commands/tail.ts +39 -0
  247. package/src/commands/tar.ts +58 -0
  248. package/src/commands/tee.ts +25 -0
  249. package/src/commands/touch.ts +2 -0
  250. package/src/commands/tr.ts +24 -0
  251. package/src/commands/tree.ts +2 -0
  252. package/src/commands/uname.ts +20 -0
  253. package/src/commands/uniq.ts +28 -0
  254. package/src/commands/unset.ts +5 -12
  255. package/src/commands/wc.ts +50 -0
  256. package/src/commands/wget.ts +2 -0
  257. package/src/commands/who.ts +2 -0
  258. package/src/commands/whoami.ts +2 -0
  259. package/src/commands/xargs.ts +17 -0
  260. package/src/index.ts +1 -0
  261. package/src/types/commands.ts +14 -0
  262. package/src/types/pipeline.ts +23 -0
  263. package/standalone.js +93 -55
  264. package/standalone.js.map +4 -4
  265. package/tests/bun-test-shim.ts +1 -0
  266. package/tests/sftp.test.ts +115 -191
  267. package/tests/users.test.ts +42 -88
@@ -0,0 +1,24 @@
1
+ import type { ShellModule } from "../types/commands";
2
+ import { ifFlag } from "./command-helpers";
3
+
4
+ export const trCommand: ShellModule = {
5
+ name: "tr",
6
+ description: "Translate or delete characters",
7
+ category: "text",
8
+ params: ["[-d] <set1> [set2]"],
9
+ run: ({ args, stdin }) => {
10
+ const del = ifFlag(args, ["-d"]);
11
+ const positionals = args.filter((a) => !a.startsWith("-"));
12
+ const set1 = positionals[0] ?? "";
13
+ const set2 = positionals[1] ?? "";
14
+ let input = stdin ?? "";
15
+ if (del) {
16
+ for (const c of set1) input = input.split(c).join("");
17
+ } else if (set2) {
18
+ for (let i = 0; i < set1.length; i++) {
19
+ input = input.split(set1[i]!).join(set2[i] ?? set2[set2.length - 1] ?? "");
20
+ }
21
+ }
22
+ return { stdout: input, exitCode: 0 };
23
+ },
24
+ };
@@ -4,6 +4,8 @@ import { assertPathAccess, resolvePath } from "./helpers";
4
4
 
5
5
  export const treeCommand: ShellModule = {
6
6
  name: "tree",
7
+ description: "Display directory tree",
8
+ category: "navigation",
7
9
  params: ["[path]"],
8
10
  run: ({ authUser, shell, cwd, args }) => {
9
11
  const target = resolvePath(cwd, getArg(args, 0) ?? cwd);
@@ -0,0 +1,20 @@
1
+ import type { ShellModule } from "../types/commands";
2
+ import { ifFlag } from "./command-helpers";
3
+
4
+ export const unameCommand: ShellModule = {
5
+ name: "uname",
6
+ description: "Print system information",
7
+ category: "system",
8
+ params: ["[-a] [-s] [-r] [-m]"],
9
+ run: ({ shell, args }) => {
10
+ const all = ifFlag(args, ["-a"]);
11
+ const sysname = "Linux";
12
+ const release = shell.properties?.kernel ?? "5.15.0";
13
+ const machine = shell.properties?.arch ?? "x86_64";
14
+ const hostname = shell.hostname;
15
+ if (all) return { stdout: `${sysname} ${hostname} ${release} #1 SMP ${machine} GNU/Linux`, exitCode: 0 };
16
+ if (ifFlag(args, ["-r"])) return { stdout: release, exitCode: 0 };
17
+ if (ifFlag(args, ["-m"])) return { stdout: machine, exitCode: 0 };
18
+ return { stdout: sysname, exitCode: 0 };
19
+ },
20
+ };
@@ -0,0 +1,28 @@
1
+ import type { ShellModule } from "../types/commands";
2
+ import { ifFlag } from "./command-helpers";
3
+
4
+ export const uniqCommand: ShellModule = {
5
+ name: "uniq",
6
+ description: "Report or filter out repeated lines",
7
+ category: "text",
8
+ params: ["[-c] [-d] [-u] [file]"],
9
+ run: ({ args, stdin }) => {
10
+ const count = ifFlag(args, ["-c"]);
11
+ const dupOnly = ifFlag(args, ["-d"]);
12
+ const uniqOnly = ifFlag(args, ["-u"]);
13
+ const lines = (stdin ?? "").split("\n");
14
+ const out: string[] = [];
15
+ let i = 0;
16
+ while (i < lines.length) {
17
+ let j = i;
18
+ while (j < lines.length && lines[j] === lines[i]) j++;
19
+ const n = j - i;
20
+ const line = lines[i]!;
21
+ if (dupOnly && n === 1) { i = j; continue; }
22
+ if (uniqOnly && n > 1) { i = j; continue; }
23
+ out.push(count ? `${String(n).padStart(4)} ${line}` : line);
24
+ i = j;
25
+ }
26
+ return { stdout: out.join("\n"), exitCode: 0 };
27
+ },
28
+ };
@@ -1,19 +1,12 @@
1
1
  import type { ShellModule } from "../types/commands";
2
- import { setEnvVar } from "./set";
3
2
 
4
3
  export const unsetCommand: ShellModule = {
5
4
  name: "unset",
6
- params: ["<VAR...>"],
7
- run: ({ args }) => {
8
- if (args.length === 0) {
9
- return { stderr: "unset: missing variable name", exitCode: 1 };
10
- }
11
-
12
- // Unset (remove) all specified variables
13
- for (const varName of args) {
14
- setEnvVar(varName, "");
15
- }
16
-
5
+ description: "Remove shell variable",
6
+ category: "shell",
7
+ params: ["<VAR>"],
8
+ run: ({ args, env }) => {
9
+ for (const name of args) delete env.vars[name];
17
10
  return { exitCode: 0 };
18
11
  },
19
12
  };
@@ -0,0 +1,50 @@
1
+ import type { ShellModule } from "../types/commands";
2
+ import { ifFlag } from "./command-helpers";
3
+ import { assertPathAccess, resolvePath } from "./helpers";
4
+
5
+ export const wcCommand: ShellModule = {
6
+ name: "wc",
7
+ description: "Count words/lines/bytes",
8
+ category: "text",
9
+ params: ["[-l] [-w] [-c] [file...]"],
10
+ run: ({ authUser, shell, cwd, args, stdin }) => {
11
+ const lines = ifFlag(args, ["-l"]);
12
+ const words = ifFlag(args, ["-w"]);
13
+ const bytes = ifFlag(args, ["-c"]);
14
+ const showAll = !lines && !words && !bytes;
15
+ const positionals = args.filter((a) => !a.startsWith("-"));
16
+
17
+ const count = (content: string, label: string): string => {
18
+ const l = content.split("\n").length - (content.endsWith("\n") ? 1 : 0);
19
+ const w = content.trim().split(/\s+/).filter(Boolean).length;
20
+ const c = Buffer.byteLength(content, "utf8");
21
+ const parts: string[] = [];
22
+ if (showAll || lines) parts.push(String(l).padStart(7));
23
+ if (showAll || words) parts.push(String(w).padStart(7));
24
+ if (showAll || bytes) parts.push(String(c).padStart(7));
25
+ if (label) parts.push(` ${label}`);
26
+ return parts.join("");
27
+ };
28
+
29
+ if (positionals.length === 0) {
30
+ const content = stdin ?? "";
31
+ return { stdout: count(content, ""), exitCode: 0 };
32
+ }
33
+
34
+ const results: string[] = [];
35
+ for (const file of positionals) {
36
+ const filePath = resolvePath(cwd, file);
37
+ try {
38
+ assertPathAccess(authUser, filePath, "wc");
39
+ const content = shell.vfs.readFile(filePath);
40
+ results.push(count(content, file));
41
+ } catch {
42
+ return {
43
+ stderr: `wc: ${file}: No such file or directory`,
44
+ exitCode: 1,
45
+ };
46
+ }
47
+ }
48
+ return { stdout: results.join("\n"), exitCode: 0 };
49
+ },
50
+ };
@@ -82,6 +82,8 @@ function runHostWget(args: string[]): Promise<{
82
82
 
83
83
  export const wgetCommand: ShellModule = {
84
84
  name: "wget",
85
+ description: "File downloader",
86
+ category: "network",
85
87
  params: ["[url]"],
86
88
  run: async ({ authUser, cwd, args, shell }) => {
87
89
  const { flagsWithValues, positionals } = parseArgs(args, {
@@ -3,6 +3,8 @@ import type { ShellModule } from "../types/commands";
3
3
 
4
4
  export const whoCommand: ShellModule = {
5
5
  name: "who",
6
+ description: "Show active sessions",
7
+ category: "system",
6
8
  params: [],
7
9
  run: ({ shell }) => {
8
10
  const lines = shell.users.listActiveSessions().map((session) => {
@@ -2,6 +2,8 @@ import type { ShellModule } from "../types/commands";
2
2
 
3
3
  export const whoamiCommand: ShellModule = {
4
4
  name: "whoami",
5
+ description: "Print current user",
6
+ category: "system",
5
7
  params: [],
6
8
  run: ({ authUser }) => ({ stdout: authUser, exitCode: 0 }),
7
9
  };
@@ -0,0 +1,17 @@
1
+ import type { ShellModule } from "../types/commands";
2
+ import { runCommand } from "./index";
3
+
4
+ export const xargsCommand: ShellModule = {
5
+ name: "xargs",
6
+ description: "Build and execute command lines from stdin",
7
+ category: "text",
8
+ params: ["[command] [args...]"],
9
+ run: async ({ authUser, hostname, mode, cwd, args, stdin, shell, env }) => {
10
+ const baseCmd = args[0] ?? "echo";
11
+ const extraArgs = args.slice(1);
12
+ const items = (stdin ?? "").trim().split(/\s+/).filter(Boolean);
13
+ if (items.length === 0) return { exitCode: 0 };
14
+ const fullCmd = [baseCmd, ...extraArgs, ...items].join(" ");
15
+ return runCommand(fullCmd, authUser, hostname, mode, cwd, shell, undefined, env);
16
+ },
17
+ };
package/src/index.ts CHANGED
@@ -33,6 +33,7 @@ export type {
33
33
  VfsSnapshotNode,
34
34
  WriteFileOptions,
35
35
  } from "./types/vfs";
36
+ export type { VfsOptions, VfsPersistenceMode } from "./VirtualFileSystem/index";
36
37
 
37
38
  export {
38
39
  HoneyPot,
@@ -57,6 +57,14 @@ export interface NanoEditorSession {
57
57
  initialContent: string;
58
58
  }
59
59
 
60
+ /** Per-session shell environment (variables, last exit code). */
61
+ export interface ShellEnv {
62
+ /** Environment variables visible to commands. */
63
+ vars: Record<string, string>;
64
+ /** Exit status of the last executed command. */
65
+ lastExitCode: number;
66
+ }
67
+
60
68
  /** Runtime context object passed to each command module. */
61
69
  export interface CommandContext {
62
70
  /** Authenticated user currently bound to stream. */
@@ -77,6 +85,8 @@ export interface CommandContext {
77
85
  stdin?: string;
78
86
  /** Current working directory for command execution. */
79
87
  cwd: string;
88
+ /** Per-session environment available to command modules. */
89
+ env: ShellEnv;
80
90
  }
81
91
 
82
92
  /** Contract implemented by each shell command module. */
@@ -89,6 +99,10 @@ export interface ShellModule {
89
99
  run: (ctx: CommandContext) => CommandResult | Promise<CommandResult>;
90
100
  /** Optional alternative command names. */
91
101
  aliases?: string[];
102
+ /** Short description shown in `help`. */
103
+ description?: string;
104
+ /** Category used for grouped help output. */
105
+ category?: string;
92
106
  }
93
107
 
94
108
  /** Command return union allowing sync or async handlers. */
@@ -12,6 +12,9 @@ export interface PipelineCommand {
12
12
  appendOutput?: boolean;
13
13
  }
14
14
 
15
+ /** Logical operator connecting two statement groups. */
16
+ export type LogicalOp = "&&" | "||" | ";";
17
+
15
18
  /** Represents a parsed shell pipeline */
16
19
  export interface Pipeline {
17
20
  /** List of commands in the pipeline */
@@ -21,3 +24,23 @@ export interface Pipeline {
21
24
  /** Error message if parsing failed */
22
25
  error?: string;
23
26
  }
27
+
28
+ /** A statement: one pipeline optionally followed by && / || / ; and the next statement */
29
+ export interface Statement {
30
+ /** Pipeline to execute for this statement. */
31
+ pipeline: Pipeline;
32
+ /** Operator connecting this statement to the next one. */
33
+ op?: LogicalOp;
34
+ /** Optional next statement in sequence. */
35
+ next?: Statement;
36
+ }
37
+
38
+ /** Top-level parse result for a script. */
39
+ export interface Script {
40
+ /** Statements contained in the script. */
41
+ statements: Statement[];
42
+ /** Whether the script was parsed successfully. */
43
+ isValid: boolean;
44
+ /** Optional parse error message. */
45
+ error?: string;
46
+ }