typescript-virtual-container 1.1.1-b → 1.1.1-c

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 (185) hide show
  1. package/.vscode/settings.json +1 -1
  2. package/dist/SSHClient/index.d.ts +138 -0
  3. package/dist/SSHClient/index.d.ts.map +1 -0
  4. package/dist/SSHClient/index.js +216 -0
  5. package/dist/SSHMimic/exec.d.ts +4 -0
  6. package/dist/SSHMimic/exec.d.ts.map +1 -0
  7. package/dist/SSHMimic/exec.js +21 -0
  8. package/dist/SSHMimic/executor.d.ts +9 -0
  9. package/dist/SSHMimic/executor.d.ts.map +1 -0
  10. package/dist/SSHMimic/executor.js +131 -0
  11. package/dist/SSHMimic/hostKey.d.ts +2 -0
  12. package/dist/SSHMimic/hostKey.d.ts.map +1 -0
  13. package/dist/SSHMimic/hostKey.js +17 -0
  14. package/dist/SSHMimic/index.d.ts +39 -0
  15. package/dist/SSHMimic/index.d.ts.map +1 -0
  16. package/dist/SSHMimic/index.js +113 -0
  17. package/dist/SSHMimic/loginFormat.d.ts +2 -0
  18. package/dist/SSHMimic/loginFormat.d.ts.map +1 -0
  19. package/dist/SSHMimic/loginFormat.js +10 -0
  20. package/dist/SSHMimic/prompt.d.ts +2 -0
  21. package/dist/SSHMimic/prompt.d.ts.map +1 -0
  22. package/dist/SSHMimic/prompt.js +9 -0
  23. package/dist/VirtualFileSystem/archive.d.ts +5 -0
  24. package/dist/VirtualFileSystem/archive.d.ts.map +1 -0
  25. package/dist/VirtualFileSystem/archive.js +56 -0
  26. package/dist/VirtualFileSystem/index.d.ts +131 -0
  27. package/dist/VirtualFileSystem/index.d.ts.map +1 -0
  28. package/dist/VirtualFileSystem/index.js +355 -0
  29. package/dist/VirtualFileSystem/internalTypes.d.ts +18 -0
  30. package/dist/VirtualFileSystem/internalTypes.d.ts.map +1 -0
  31. package/dist/VirtualFileSystem/internalTypes.js +0 -0
  32. package/dist/VirtualFileSystem/path.d.ts +9 -0
  33. package/dist/VirtualFileSystem/path.d.ts.map +1 -0
  34. package/dist/VirtualFileSystem/path.js +49 -0
  35. package/dist/VirtualFileSystem/snapshot.d.ts +5 -0
  36. package/dist/VirtualFileSystem/snapshot.d.ts.map +1 -0
  37. package/dist/VirtualFileSystem/snapshot.js +59 -0
  38. package/dist/VirtualFileSystem/tree.d.ts +3 -0
  39. package/dist/VirtualFileSystem/tree.d.ts.map +1 -0
  40. package/dist/VirtualFileSystem/tree.js +19 -0
  41. package/dist/VirtualShell/index.d.ts +86 -0
  42. package/dist/VirtualShell/index.d.ts.map +1 -0
  43. package/dist/VirtualShell/index.js +129 -0
  44. package/dist/VirtualShell/shell.d.ts +5 -0
  45. package/dist/VirtualShell/shell.d.ts.map +1 -0
  46. package/dist/VirtualShell/shell.js +473 -0
  47. package/dist/VirtualShell/shellParser.d.ts +4 -0
  48. package/dist/VirtualShell/shellParser.d.ts.map +1 -0
  49. package/dist/VirtualShell/shellParser.js +207 -0
  50. package/dist/VirtualUserManager/index.d.ts +168 -0
  51. package/dist/VirtualUserManager/index.d.ts.map +1 -0
  52. package/dist/VirtualUserManager/index.js +375 -0
  53. package/dist/commands/adduser.d.ts +3 -0
  54. package/dist/commands/adduser.d.ts.map +1 -0
  55. package/dist/commands/adduser.js +18 -0
  56. package/dist/commands/cat.d.ts +3 -0
  57. package/dist/commands/cat.d.ts.map +1 -0
  58. package/dist/commands/cat.js +15 -0
  59. package/dist/commands/cd.d.ts +3 -0
  60. package/dist/commands/cd.d.ts.map +1 -0
  61. package/dist/commands/cd.js +17 -0
  62. package/dist/commands/clear.d.ts +3 -0
  63. package/dist/commands/clear.d.ts.map +1 -0
  64. package/dist/commands/clear.js +5 -0
  65. package/dist/commands/command-helpers.d.ts +23 -0
  66. package/dist/commands/command-helpers.d.ts.map +1 -0
  67. package/dist/commands/command-helpers.js +139 -0
  68. package/dist/commands/curl.d.ts +3 -0
  69. package/dist/commands/curl.d.ts.map +1 -0
  70. package/dist/commands/curl.js +44 -0
  71. package/dist/commands/deluser.d.ts +3 -0
  72. package/dist/commands/deluser.d.ts.map +1 -0
  73. package/dist/commands/deluser.js +15 -0
  74. package/dist/commands/echo.d.ts +3 -0
  75. package/dist/commands/echo.d.ts.map +1 -0
  76. package/dist/commands/echo.js +22 -0
  77. package/dist/commands/env.d.ts +3 -0
  78. package/dist/commands/env.d.ts.map +1 -0
  79. package/dist/commands/env.js +18 -0
  80. package/dist/commands/exit.d.ts +3 -0
  81. package/dist/commands/exit.d.ts.map +1 -0
  82. package/dist/commands/exit.js +5 -0
  83. package/dist/commands/export.d.ts +3 -0
  84. package/dist/commands/export.d.ts.map +1 -0
  85. package/dist/commands/export.js +34 -0
  86. package/dist/commands/grep.d.ts +3 -0
  87. package/dist/commands/grep.d.ts.map +1 -0
  88. package/dist/commands/grep.js +69 -0
  89. package/dist/commands/help.d.ts +3 -0
  90. package/dist/commands/help.d.ts.map +1 -0
  91. package/dist/commands/help.js +7 -0
  92. package/dist/commands/helpers.d.ts +26 -0
  93. package/dist/commands/helpers.d.ts.map +1 -0
  94. package/dist/commands/helpers.js +160 -0
  95. package/dist/commands/hostname.d.ts +3 -0
  96. package/dist/commands/hostname.d.ts.map +1 -0
  97. package/dist/commands/hostname.js +5 -0
  98. package/dist/commands/htop.d.ts +3 -0
  99. package/dist/commands/htop.d.ts.map +1 -0
  100. package/dist/commands/htop.js +10 -0
  101. package/dist/commands/index.d.ts +8 -0
  102. package/dist/commands/index.d.ts.map +1 -0
  103. package/dist/commands/index.js +212 -0
  104. package/dist/commands/ls.d.ts +3 -0
  105. package/dist/commands/ls.d.ts.map +1 -0
  106. package/dist/commands/ls.js +47 -0
  107. package/dist/commands/mkdir.d.ts +3 -0
  108. package/dist/commands/mkdir.d.ts.map +1 -0
  109. package/dist/commands/mkdir.js +21 -0
  110. package/dist/commands/nano.d.ts +3 -0
  111. package/dist/commands/nano.d.ts.map +1 -0
  112. package/dist/commands/nano.js +27 -0
  113. package/dist/commands/neofetch.d.ts +3 -0
  114. package/dist/commands/neofetch.d.ts.map +1 -0
  115. package/dist/commands/neofetch.js +32 -0
  116. package/dist/commands/pwd.d.ts +3 -0
  117. package/dist/commands/pwd.d.ts.map +1 -0
  118. package/dist/commands/pwd.js +5 -0
  119. package/dist/commands/rm.d.ts +3 -0
  120. package/dist/commands/rm.d.ts.map +1 -0
  121. package/dist/commands/rm.js +29 -0
  122. package/dist/commands/set.d.ts +7 -0
  123. package/dist/commands/set.d.ts.map +1 -0
  124. package/dist/commands/set.js +64 -0
  125. package/dist/commands/sh.d.ts +4 -0
  126. package/dist/commands/sh.d.ts.map +1 -0
  127. package/dist/commands/sh.js +45 -0
  128. package/dist/commands/su.d.ts +3 -0
  129. package/dist/commands/su.d.ts.map +1 -0
  130. package/dist/commands/su.js +24 -0
  131. package/dist/commands/sudo.d.ts +3 -0
  132. package/dist/commands/sudo.d.ts.map +1 -0
  133. package/dist/commands/sudo.js +47 -0
  134. package/dist/commands/touch.d.ts +3 -0
  135. package/dist/commands/touch.d.ts.map +1 -0
  136. package/dist/commands/touch.js +18 -0
  137. package/dist/commands/tree.d.ts +3 -0
  138. package/dist/commands/tree.d.ts.map +1 -0
  139. package/dist/commands/tree.js +11 -0
  140. package/dist/commands/unset.d.ts +3 -0
  141. package/dist/commands/unset.d.ts.map +1 -0
  142. package/dist/commands/unset.js +15 -0
  143. package/dist/commands/wget.d.ts +3 -0
  144. package/dist/commands/wget.d.ts.map +1 -0
  145. package/dist/commands/wget.js +113 -0
  146. package/dist/commands/who.d.ts +3 -0
  147. package/dist/commands/who.d.ts.map +1 -0
  148. package/dist/commands/who.js +15 -0
  149. package/dist/commands/whoami.d.ts +3 -0
  150. package/dist/commands/whoami.d.ts.map +1 -0
  151. package/dist/commands/whoami.js +5 -0
  152. package/dist/index.d.ts +11 -0
  153. package/dist/index.d.ts.map +1 -0
  154. package/dist/index.js +7 -0
  155. package/dist/modules/neofetch.d.ts +19 -0
  156. package/dist/modules/neofetch.d.ts.map +1 -0
  157. package/dist/modules/neofetch.js +284 -0
  158. package/dist/modules/shellInteractive.d.ts +6 -0
  159. package/dist/modules/shellInteractive.d.ts.map +1 -0
  160. package/dist/modules/shellInteractive.js +26 -0
  161. package/dist/modules/shellRuntime.d.ts +11 -0
  162. package/dist/modules/shellRuntime.d.ts.map +1 -0
  163. package/dist/modules/shellRuntime.js +52 -0
  164. package/dist/standalone.d.ts +2 -0
  165. package/dist/standalone.d.ts.map +1 -0
  166. package/dist/standalone.js +25 -0
  167. package/dist/types/commands.d.ts +89 -0
  168. package/dist/types/commands.d.ts.map +1 -0
  169. package/dist/types/commands.js +0 -0
  170. package/dist/types/pipeline.d.ts +23 -0
  171. package/dist/types/pipeline.d.ts.map +1 -0
  172. package/dist/types/pipeline.js +0 -0
  173. package/dist/types/streams.d.ts +32 -0
  174. package/dist/types/streams.d.ts.map +1 -0
  175. package/dist/types/streams.js +0 -0
  176. package/dist/types/vfs.d.ts +71 -0
  177. package/dist/types/vfs.d.ts.map +1 -0
  178. package/dist/types/vfs.js +0 -0
  179. package/package.json +4 -2
  180. package/src/VirtualShell/shell.ts +3 -3
  181. package/src/commands/neofetch.ts +1 -1
  182. package/{modules → src/modules}/neofetch.ts +56 -51
  183. package/{modules → src/modules}/shellInteractive.ts +16 -4
  184. package/tsconfig.json +19 -8
  185. /package/{modules → src/modules}/shellRuntime.ts +0 -0
@@ -0,0 +1,212 @@
1
+ import { adduserCommand } from "./adduser";
2
+ import { catCommand } from "./cat";
3
+ import { cdCommand } from "./cd";
4
+ import { clearCommand } from "./clear";
5
+ import { curlCommand } from "./curl";
6
+ import { deluserCommand } from "./deluser";
7
+ import { echoCommand } from "./echo";
8
+ import { envCommand } from "./env";
9
+ import { exitCommand } from "./exit";
10
+ import { exportCommand } from "./export";
11
+ import { grepCommand } from "./grep";
12
+ import { createHelpCommand } from "./help";
13
+ import { hostnameCommand } from "./hostname";
14
+ import { htopCommand } from "./htop";
15
+ import { lsCommand } from "./ls";
16
+ import { mkdirCommand } from "./mkdir";
17
+ import { nanoCommand } from "./nano";
18
+ import { neofetchCommand } from "./neofetch";
19
+ import { pwdCommand } from "./pwd";
20
+ import { rmCommand } from "./rm";
21
+ import { setCommand } from "./set";
22
+ import { shCommand } from "./sh";
23
+ import { suCommand } from "./su";
24
+ import { sudoCommand } from "./sudo";
25
+ import { touchCommand } from "./touch";
26
+ import { treeCommand } from "./tree";
27
+ import { unsetCommand } from "./unset";
28
+ import { wgetCommand } from "./wget";
29
+ import { whoCommand } from "./who";
30
+ import { whoamiCommand } from "./whoami";
31
+ const BASE_COMMANDS = [
32
+ pwdCommand,
33
+ whoamiCommand,
34
+ whoCommand,
35
+ hostnameCommand,
36
+ lsCommand,
37
+ cdCommand,
38
+ catCommand,
39
+ echoCommand,
40
+ mkdirCommand,
41
+ touchCommand,
42
+ rmCommand,
43
+ treeCommand,
44
+ nanoCommand,
45
+ neofetchCommand,
46
+ htopCommand,
47
+ adduserCommand,
48
+ deluserCommand,
49
+ sudoCommand,
50
+ suCommand,
51
+ curlCommand,
52
+ envCommand,
53
+ wgetCommand,
54
+ grepCommand,
55
+ exportCommand,
56
+ setCommand,
57
+ unsetCommand,
58
+ shCommand,
59
+ clearCommand,
60
+ exitCommand,
61
+ ];
62
+ const customCommands = [];
63
+ const helpCommand = createHelpCommand(() => getCommandModules().map((cmd) => cmd.name));
64
+ const commandRegistry = new Map();
65
+ let cachedCommandNames = null;
66
+ function buildCache() {
67
+ for (const mod of getCommandModules()) {
68
+ commandRegistry.set(mod.name, mod);
69
+ for (const alias of mod.aliases ?? []) {
70
+ commandRegistry.set(alias, mod);
71
+ }
72
+ }
73
+ cachedCommandNames = Array.from(commandRegistry.keys()).sort();
74
+ }
75
+ function getCommandModules() {
76
+ // console.log("Loading command modules...");
77
+ // console.log(
78
+ // `Base commands: ${BASE_COMMANDS.map((cmd) => cmd.name).join(", ")}`,
79
+ // );
80
+ // console.log(
81
+ // `Custom commands: ${customCommands.map((cmd) => cmd.name).join(", ")}`,
82
+ // );
83
+ return [...BASE_COMMANDS, ...customCommands, helpCommand];
84
+ }
85
+ export function registerCommand(module) {
86
+ const normalized = {
87
+ ...module,
88
+ name: module.name.trim().toLowerCase(),
89
+ aliases: module.aliases?.map((alias) => alias.trim().toLowerCase()),
90
+ };
91
+ const names = [normalized.name, ...(normalized.aliases ?? [])];
92
+ if (names.some((name) => name.length === 0 || /\s/.test(name))) {
93
+ throw new Error("Command names and aliases must be non-empty and contain no spaces");
94
+ }
95
+ for (const name of names) {
96
+ if (commandRegistry.has(name)) {
97
+ throw new Error(`Command '${name}' already exists`);
98
+ }
99
+ commandRegistry.set(name, normalized);
100
+ }
101
+ buildCache();
102
+ }
103
+ export function createCustomCommand(name, params, run) {
104
+ return {
105
+ name,
106
+ params,
107
+ run,
108
+ };
109
+ }
110
+ export function getCommandNames() {
111
+ if (!cachedCommandNames) {
112
+ buildCache();
113
+ }
114
+ return cachedCommandNames;
115
+ }
116
+ export function resolveModule(name) {
117
+ if (!cachedCommandNames) {
118
+ buildCache();
119
+ }
120
+ return commandRegistry.get(name.toLowerCase());
121
+ }
122
+ function splitArgsRespectingQuotes(input) {
123
+ const tokens = [];
124
+ let current = "";
125
+ let inQuotes = false;
126
+ let quoteChar = "";
127
+ for (let i = 0; i < input.length; i += 1) {
128
+ const ch = input[i] || "";
129
+ const prev = i > 0 ? input[i - 1] : "";
130
+ if ((ch === '"' || ch === "'") && prev !== "\\") {
131
+ if (!inQuotes) {
132
+ inQuotes = true;
133
+ quoteChar = ch;
134
+ continue;
135
+ }
136
+ if (ch === quoteChar) {
137
+ inQuotes = false;
138
+ quoteChar = "";
139
+ continue;
140
+ }
141
+ }
142
+ if (/\s/.test(ch) && !inQuotes) {
143
+ if (current.length > 0) {
144
+ tokens.push(current);
145
+ current = "";
146
+ }
147
+ continue;
148
+ }
149
+ current += ch;
150
+ }
151
+ if (current.length > 0) {
152
+ tokens.push(current);
153
+ }
154
+ return tokens;
155
+ }
156
+ function parseInput(rawInput) {
157
+ const parts = splitArgsRespectingQuotes(rawInput.trim());
158
+ return {
159
+ commandName: parts[0]?.toLowerCase() ?? "",
160
+ args: parts.slice(1),
161
+ };
162
+ }
163
+ // Internal async function for pipeline execution
164
+ export async function runCommand(rawInput, authUser, hostname, mode, cwd, shell, stdin) {
165
+ const trimmed = rawInput.trim();
166
+ if (trimmed.length === 0) {
167
+ return { exitCode: 0 };
168
+ }
169
+ if (trimmed.includes("|") || trimmed.includes(">") || trimmed.includes("<")) {
170
+ const { parseShellPipeline } = await import("../VirtualShell/shellParser");
171
+ const { executePipeline } = await import("../SSHMimic/executor");
172
+ const pipeline = parseShellPipeline(trimmed);
173
+ if (!pipeline.isValid) {
174
+ return {
175
+ stderr: pipeline.error || "Syntax error",
176
+ exitCode: 1,
177
+ };
178
+ }
179
+ try {
180
+ return await executePipeline(pipeline, authUser, hostname, mode, cwd, shell);
181
+ }
182
+ catch (error) {
183
+ const message = error instanceof Error ? error.message : "Pipeline execution failed";
184
+ return { stderr: message, exitCode: 1 };
185
+ }
186
+ }
187
+ const { commandName, args } = parseInput(trimmed);
188
+ const mod = resolveModule(commandName);
189
+ if (!mod) {
190
+ return {
191
+ stderr: `Command '${trimmed}' not found`,
192
+ exitCode: 127,
193
+ };
194
+ }
195
+ try {
196
+ return await mod.run({
197
+ authUser,
198
+ hostname,
199
+ activeSessions: shell.users.listActiveSessions(),
200
+ rawInput: trimmed,
201
+ mode,
202
+ args,
203
+ stdin,
204
+ cwd,
205
+ shell,
206
+ });
207
+ }
208
+ catch (error) {
209
+ const message = error instanceof Error ? error.message : "Command failed";
210
+ return { stderr: message, exitCode: 1 };
211
+ }
212
+ }
@@ -0,0 +1,3 @@
1
+ import type { ShellModule } from "../types/commands";
2
+ export declare const lsCommand: ShellModule;
3
+ //# sourceMappingURL=ls.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ls.d.ts","sourceRoot":"","sources":["../../src/commands/ls.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AA4BrD,eAAO,MAAM,SAAS,EAAE,WAuBvB,CAAC"}
@@ -0,0 +1,47 @@
1
+ import { getArg, ifFlag } from "./command-helpers";
2
+ import { assertPathAccess, joinListWithType, resolvePath } from "./helpers";
3
+ function formatPermissions(mode, isDirectory) {
4
+ const fileType = isDirectory ? "d" : "-";
5
+ const permissionBits = [
6
+ [0o400, "r"],
7
+ [0o200, "w"],
8
+ [0o100, "x"],
9
+ [0o040, "r"],
10
+ [0o020, "w"],
11
+ [0o010, "x"],
12
+ [0o004, "r"],
13
+ [0o002, "w"],
14
+ [0o001, "x"],
15
+ ];
16
+ const permissions = permissionBits
17
+ .map(([bit, symbol]) => (mode & bit ? symbol : "-"))
18
+ .join("");
19
+ return `${fileType}${permissions}`;
20
+ }
21
+ function formatDate(date) {
22
+ return date.toISOString().replace("T", " ").slice(0, 16);
23
+ }
24
+ export const lsCommand = {
25
+ name: "ls",
26
+ params: ["[path]"],
27
+ run: ({ authUser, shell, cwd, args }) => {
28
+ const longFormat = ifFlag(args, ["-l", "--long"]);
29
+ const targetArg = getArg(args, 0, { flags: ["-l", "--long"] });
30
+ const target = resolvePath(cwd, targetArg ?? cwd);
31
+ assertPathAccess(authUser, target, "ls");
32
+ const items = shell.vfs
33
+ .list(target)
34
+ .filter((name) => !name.startsWith("."));
35
+ const rendered = longFormat
36
+ ? items
37
+ .map((name) => {
38
+ const childPath = resolvePath(target, name);
39
+ const stat = shell.vfs.stat(childPath);
40
+ const size = stat.type === "file" ? stat.size : stat.childrenCount;
41
+ return `${formatPermissions(stat.mode, stat.type === "directory")} 1 ${size} ${formatDate(stat.updatedAt)} ${name}${stat.type === "directory" ? "/" : ""}`;
42
+ })
43
+ .join("\n")
44
+ : joinListWithType(target, items, (p) => shell.vfs.stat(p));
45
+ return { stdout: rendered, exitCode: 0 };
46
+ },
47
+ };
@@ -0,0 +1,3 @@
1
+ import type { ShellModule } from "../types/commands";
2
+ export declare const mkdirCommand: ShellModule;
3
+ //# sourceMappingURL=mkdir.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mkdir.d.ts","sourceRoot":"","sources":["../../src/commands/mkdir.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAIrD,eAAO,MAAM,YAAY,EAAE,WAmB1B,CAAC"}
@@ -0,0 +1,21 @@
1
+ import { getArg } from "./command-helpers";
2
+ import { assertPathAccess, resolvePath } from "./helpers";
3
+ export const mkdirCommand = {
4
+ name: "mkdir",
5
+ params: ["<dir>"],
6
+ run: ({ authUser, shell, cwd, args }) => {
7
+ if (args.length === 0) {
8
+ return { stderr: "mkdir: missing operand", exitCode: 1 };
9
+ }
10
+ for (let index = 0; index < args.length; index++) {
11
+ const dir = getArg(args, index);
12
+ if (!dir) {
13
+ return { stderr: "mkdir: missing operand", exitCode: 1 };
14
+ }
15
+ const target = resolvePath(cwd, dir);
16
+ assertPathAccess(authUser, target, "mkdir");
17
+ shell.vfs.mkdir(target);
18
+ }
19
+ return { exitCode: 0 };
20
+ },
21
+ };
@@ -0,0 +1,3 @@
1
+ import type { ShellModule } from "../types/commands";
2
+ export declare const nanoCommand: ShellModule;
3
+ //# sourceMappingURL=nano.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nano.d.ts","sourceRoot":"","sources":["../../src/commands/nano.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAGrD,eAAO,MAAM,WAAW,EAAE,WA0BzB,CAAC"}
@@ -0,0 +1,27 @@
1
+ import * as path from "node:path";
2
+ import { assertPathAccess, resolvePath } from "./helpers";
3
+ export const nanoCommand = {
4
+ name: "nano",
5
+ params: ["<file>"],
6
+ run: ({ authUser, shell, cwd, args }) => {
7
+ const fileArg = args[0];
8
+ if (!fileArg) {
9
+ return { stderr: "nano: missing file operand", exitCode: 1 };
10
+ }
11
+ const targetPath = resolvePath(cwd, fileArg);
12
+ assertPathAccess(authUser, targetPath, "nano");
13
+ const initialContent = shell.vfs.exists(targetPath)
14
+ ? shell.vfs.readFile(targetPath)
15
+ : "";
16
+ const safeName = path.posix.basename(targetPath) || "buffer";
17
+ const tempPath = `/tmp/sshmimic-nano-${Date.now()}-${safeName}.tmp`;
18
+ return {
19
+ openEditor: {
20
+ targetPath,
21
+ tempPath,
22
+ initialContent,
23
+ },
24
+ exitCode: 0,
25
+ };
26
+ },
27
+ };
@@ -0,0 +1,3 @@
1
+ import type { ShellModule } from "../types/commands";
2
+ export declare const neofetchCommand: ShellModule;
3
+ //# sourceMappingURL=neofetch.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"neofetch.d.ts","sourceRoot":"","sources":["../../src/commands/neofetch.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAIrD,eAAO,MAAM,eAAe,EAAE,WA+B7B,CAAC"}
@@ -0,0 +1,32 @@
1
+ import { buildNeofetchOutput } from "../modules/neofetch";
2
+ import { ifFlag } from "./command-helpers";
3
+ import { getAllEnvVars } from "./set";
4
+ export const neofetchCommand = {
5
+ name: "neofetch",
6
+ params: ["[--off]"],
7
+ run: ({ args, authUser, hostname, shell }) => {
8
+ const env = getAllEnvVars(authUser);
9
+ if (ifFlag(args, "--help")) {
10
+ return {
11
+ stdout: "Usage: neofetch [--off]",
12
+ exitCode: 0,
13
+ };
14
+ }
15
+ if (ifFlag(args, "--off")) {
16
+ return {
17
+ stdout: `${authUser}@${hostname}`,
18
+ exitCode: 0,
19
+ };
20
+ }
21
+ return {
22
+ stdout: buildNeofetchOutput({
23
+ user: authUser,
24
+ host: hostname,
25
+ shell: env.SHELL,
26
+ shellProps: shell.properties,
27
+ terminal: env.TERM,
28
+ }),
29
+ exitCode: 0,
30
+ };
31
+ },
32
+ };
@@ -0,0 +1,3 @@
1
+ import type { ShellModule } from "../types/commands";
2
+ export declare const pwdCommand: ShellModule;
3
+ //# sourceMappingURL=pwd.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pwd.d.ts","sourceRoot":"","sources":["../../src/commands/pwd.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAErD,eAAO,MAAM,UAAU,EAAE,WAIxB,CAAC"}
@@ -0,0 +1,5 @@
1
+ export const pwdCommand = {
2
+ name: "pwd",
3
+ params: [],
4
+ run: ({ cwd }) => ({ stdout: cwd, exitCode: 0 }),
5
+ };
@@ -0,0 +1,3 @@
1
+ import type { ShellModule } from "../types/commands";
2
+ export declare const rmCommand: ShellModule;
3
+ //# sourceMappingURL=rm.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rm.d.ts","sourceRoot":"","sources":["../../src/commands/rm.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAIrD,eAAO,MAAM,SAAS,EAAE,WA8BvB,CAAC"}
@@ -0,0 +1,29 @@
1
+ import { getArg, ifFlag } from "./command-helpers";
2
+ import { assertPathAccess, resolvePath } from "./helpers";
3
+ export const rmCommand = {
4
+ name: "rm",
5
+ params: ["[-r|-rf] <path>"],
6
+ run: ({ authUser, shell, cwd, args }) => {
7
+ if (args.length === 0) {
8
+ return { stderr: "rm: missing operand", exitCode: 1 };
9
+ }
10
+ const recursive = ifFlag(args, ["-r", "-rf", "-fr"]);
11
+ const targets = [];
12
+ for (let index = 0;; index += 1) {
13
+ const target = getArg(args, index, { flags: ["-r", "-rf", "-fr"] });
14
+ if (!target) {
15
+ break;
16
+ }
17
+ targets.push(target);
18
+ }
19
+ if (targets.length === 0) {
20
+ return { stderr: "rm: missing operand", exitCode: 1 };
21
+ }
22
+ for (const target of targets) {
23
+ const resolvedTarget = resolvePath(cwd, target);
24
+ assertPathAccess(authUser, resolvedTarget, "rm");
25
+ shell.vfs.remove(resolvedTarget, { recursive });
26
+ }
27
+ return { exitCode: 0 };
28
+ },
29
+ };
@@ -0,0 +1,7 @@
1
+ /** biome-ignore-all lint/style/useNamingConvention: env variables */
2
+ import type { ShellModule } from "../types/commands";
3
+ export declare function getEnvVar(name: string): string | undefined;
4
+ export declare function setEnvVar(name: string, value: string): void;
5
+ export declare function getAllEnvVars(authUser: string): Record<string, string>;
6
+ export declare const setCommand: ShellModule;
7
+ //# sourceMappingURL=set.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"set.d.ts","sourceRoot":"","sources":["../../src/commands/set.ts"],"names":[],"mappings":"AAAA,qEAAqE;AACrE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAarD,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAE1D;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAE3D;AAED,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAItE;AAED,eAAO,MAAM,UAAU,EAAE,WA4CxB,CAAC"}
@@ -0,0 +1,64 @@
1
+ import { getArg } from "./command-helpers";
2
+ // Simple in-memory environment variables store
3
+ // In a real implementation, this would be per-session/per-user
4
+ const envVars = {
5
+ PATH: "/usr/local/bin:/usr/bin:/bin",
6
+ HOME: "/home/user",
7
+ SHELL: "/bin/sh",
8
+ TERM: "xterm-256color",
9
+ USER: "user",
10
+ };
11
+ export function getEnvVar(name) {
12
+ return envVars[name];
13
+ }
14
+ export function setEnvVar(name, value) {
15
+ envVars[name] = value;
16
+ }
17
+ export function getAllEnvVars(authUser) {
18
+ envVars.USER = authUser;
19
+ envVars.HOME = `/home/${authUser}`;
20
+ return { ...envVars };
21
+ }
22
+ export const setCommand = {
23
+ name: "set",
24
+ params: ["[VAR=value]"],
25
+ run: ({ args }) => {
26
+ // No arguments: display all environment variables
27
+ if (args.length === 0) {
28
+ const output = Object.entries(envVars)
29
+ .map(([key, value]) => `${key}=${value}`)
30
+ .sort()
31
+ .join("\n");
32
+ return { stdout: output, exitCode: 0 };
33
+ }
34
+ // Parse VAR=value format
35
+ const assignments = [];
36
+ for (let index = 0;; index += 1) {
37
+ const arg = getArg(args, index);
38
+ if (!arg) {
39
+ break;
40
+ }
41
+ if (arg.includes("=")) {
42
+ const [varName, varValue] = arg.split("=", 2);
43
+ if (varName && varValue !== undefined) {
44
+ setEnvVar(varName, varValue);
45
+ assignments.push(arg);
46
+ }
47
+ }
48
+ else {
49
+ // If no '=' present, display that specific variable
50
+ const value = getEnvVar(arg);
51
+ if (value !== undefined) {
52
+ assignments.push(`${arg}=${value}`);
53
+ }
54
+ else {
55
+ assignments.push(`${arg}: not set`);
56
+ }
57
+ }
58
+ }
59
+ return {
60
+ stdout: assignments.length > 0 ? assignments.join("\n") : "",
61
+ exitCode: 0,
62
+ };
63
+ },
64
+ };
@@ -0,0 +1,4 @@
1
+ import type { ShellModule } from "../types/commands";
2
+ /** Simple shell script executor with basic variable support */
3
+ export declare const shCommand: ShellModule;
4
+ //# sourceMappingURL=sh.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sh.d.ts","sourceRoot":"","sources":["../../src/commands/sh.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAkB,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAIrE,+DAA+D;AAC/D,eAAO,MAAM,SAAS,EAAE,WAmDvB,CAAC"}
@@ -0,0 +1,45 @@
1
+ import { getArg, getFlag } from "./command-helpers";
2
+ import { runCommand } from "./index";
3
+ /** Simple shell script executor with basic variable support */
4
+ export const shCommand = {
5
+ name: "sh",
6
+ params: ["-c <script>", "[<file>]"],
7
+ aliases: ["bash"],
8
+ run: async (ctx) => {
9
+ const { args, authUser, hostname, mode, cwd } = ctx;
10
+ // Handle -c option: sh -c "command"
11
+ if (getFlag(args, "-c") && args.length >= 2) {
12
+ const script = getArg(args, 1) ?? "";
13
+ if (!script) {
14
+ return { stderr: "sh: -c requires a script", exitCode: 1 };
15
+ }
16
+ const scriptArgs = args.slice(2);
17
+ // Split by semicolon and newline
18
+ const lines = script
19
+ .split(/[;\n]/)
20
+ .map((line) => line.trim())
21
+ .filter((line) => line && !line.startsWith("#"));
22
+ let output = "";
23
+ const exitCode = 0;
24
+ for (const line of lines) {
25
+ // Simple variable substitution
26
+ let command = line;
27
+ for (let i = 0; i < scriptArgs.length; i++) {
28
+ const arg = scriptArgs[i] ?? "";
29
+ command = command.replaceAll(`$${i}`, arg);
30
+ }
31
+ command = command.replaceAll("$@", scriptArgs.join(" "));
32
+ // Execute the command
33
+ const result = await Promise.resolve(runCommand(command, authUser, hostname, mode, cwd, ctx.shell));
34
+ if (result.stdout) {
35
+ output += `${result.stdout}\n`;
36
+ }
37
+ if (result.stderr) {
38
+ return { stderr: result.stderr, exitCode: result.exitCode ?? 1 };
39
+ }
40
+ }
41
+ return { stdout: output.trim(), exitCode };
42
+ }
43
+ return { stderr: "sh: invalid usage", exitCode: 1 };
44
+ },
45
+ };
@@ -0,0 +1,3 @@
1
+ import type { ShellModule } from "../types/commands";
2
+ export declare const suCommand: ShellModule;
3
+ //# sourceMappingURL=su.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"su.d.ts","sourceRoot":"","sources":["../../src/commands/su.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAGrD,eAAO,MAAM,SAAS,EAAE,WA4BvB,CAAC"}
@@ -0,0 +1,24 @@
1
+ import { getArg } from "./command-helpers";
2
+ export const suCommand = {
3
+ name: "su",
4
+ params: ["- <username>"],
5
+ run: ({ authUser, shell, args }) => {
6
+ const users = shell.users;
7
+ const targetUser = getArg(args, 0, { flags: ["-"] });
8
+ if (!targetUser) {
9
+ return { stderr: "su: missing username", exitCode: 1 };
10
+ }
11
+ if (!users.isSudoer(authUser) && authUser !== "root") {
12
+ return { stderr: "su: permission denied", exitCode: 1 };
13
+ }
14
+ if (!users.verifyPassword(targetUser, getArg(args, 1) ?? "") &&
15
+ authUser !== "root") {
16
+ return { stderr: "su: authentication failure", exitCode: 1 };
17
+ }
18
+ return {
19
+ switchUser: targetUser,
20
+ nextCwd: `/home/${targetUser}`,
21
+ exitCode: 0,
22
+ };
23
+ },
24
+ };
@@ -0,0 +1,3 @@
1
+ import type { ShellModule } from "../types/commands";
2
+ export declare const sudoCommand: ShellModule;
3
+ //# sourceMappingURL=sudo.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sudo.d.ts","sourceRoot":"","sources":["../../src/commands/sudo.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAqBrD,eAAO,MAAM,WAAW,EAAE,WA+CzB,CAAC"}
@@ -0,0 +1,47 @@
1
+ import { parseArgs } from "./command-helpers";
2
+ import { runCommand } from "./index";
3
+ function parseSudoArgs(args) {
4
+ const { flags, flagsWithValues, positionals } = parseArgs(args, {
5
+ flags: ["-i", "-S"],
6
+ flagsWithValue: ["-u", "--user"],
7
+ });
8
+ const loginShell = flags.has("-i");
9
+ const targetUser = flagsWithValues.get("-u") || flagsWithValues.get("--user") || "root";
10
+ const commandLine = positionals.length > 0 ? positionals.join(" ") : null;
11
+ return { targetUser, loginShell, commandLine };
12
+ }
13
+ export const sudoCommand = {
14
+ name: "sudo",
15
+ params: ["<command...>"],
16
+ run: async ({ authUser, hostname, mode, cwd, shell, args }) => {
17
+ const { targetUser, loginShell, commandLine } = parseSudoArgs(args);
18
+ if (authUser !== "root" && !shell.users.isSudoer(authUser)) {
19
+ return { stderr: "sudo: permission denied", exitCode: 1 };
20
+ }
21
+ const effectiveUser = targetUser || "root";
22
+ const prompt = `[sudo] password for ${authUser}: `;
23
+ if (authUser === "root") {
24
+ if (!commandLine && loginShell) {
25
+ return {
26
+ switchUser: effectiveUser,
27
+ nextCwd: `/home/${effectiveUser}`,
28
+ exitCode: 0,
29
+ };
30
+ }
31
+ if (!commandLine) {
32
+ return { stderr: "sudo: missing command", exitCode: 1 };
33
+ }
34
+ return runCommand(commandLine, effectiveUser, hostname, mode, loginShell ? `/home/${effectiveUser}` : cwd, shell);
35
+ }
36
+ return {
37
+ sudoChallenge: {
38
+ username: authUser,
39
+ targetUser: effectiveUser,
40
+ commandLine,
41
+ loginShell,
42
+ prompt,
43
+ },
44
+ exitCode: 0,
45
+ };
46
+ },
47
+ };
@@ -0,0 +1,3 @@
1
+ import type { ShellModule } from "../types/commands";
2
+ export declare const touchCommand: ShellModule;
3
+ //# sourceMappingURL=touch.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"touch.d.ts","sourceRoot":"","sources":["../../src/commands/touch.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAGrD,eAAO,MAAM,YAAY,EAAE,WAiB1B,CAAC"}