typescript-virtual-container 1.4.4 → 1.4.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 (884) hide show
  1. package/README.md +1 -1
  2. package/builds/self-standalone.js +321 -272
  3. package/builds/self-standalone.js.map +4 -4
  4. package/builds/standalone-wo-sftp.js +262 -212
  5. package/builds/standalone-wo-sftp.js.map +4 -4
  6. package/builds/standalone.cjs +491 -0
  7. package/builds/standalone.cjs.map +7 -0
  8. package/builds/standalone.js +266 -216
  9. package/builds/standalone.js.map +4 -4
  10. package/builds/web-full-api.min.js +5 -5
  11. package/builds/web-full-api.min.js.map +3 -3
  12. package/builds/web.min.js +5 -5
  13. package/builds/web.min.js.map +3 -3
  14. package/bun.lock +97 -0
  15. package/dist/Honeypot/index.d.ts.map +1 -0
  16. package/dist/Honeypot/index.js +299 -0
  17. package/dist/Honeypot/index.js.map +1 -0
  18. package/dist/SSHClient/index.d.ts.map +1 -0
  19. package/dist/SSHClient/index.js +238 -0
  20. package/dist/SSHClient/index.js.map +1 -0
  21. package/dist/SSHMimic/exec.d.ts.map +1 -0
  22. package/dist/SSHMimic/exec.js +28 -0
  23. package/dist/SSHMimic/exec.js.map +1 -0
  24. package/dist/SSHMimic/executor.d.ts.map +1 -0
  25. package/dist/SSHMimic/executor.js +161 -0
  26. package/dist/SSHMimic/executor.js.map +1 -0
  27. package/dist/SSHMimic/hostKey.d.ts.map +1 -0
  28. package/dist/SSHMimic/hostKey.js +18 -0
  29. package/dist/SSHMimic/hostKey.js.map +1 -0
  30. package/dist/SSHMimic/index.d.ts.map +1 -0
  31. package/dist/SSHMimic/index.js +250 -0
  32. package/dist/SSHMimic/index.js.map +1 -0
  33. package/dist/SSHMimic/loginBanner.d.ts.map +1 -0
  34. package/dist/SSHMimic/loginBanner.js +23 -0
  35. package/dist/SSHMimic/loginBanner.js.map +1 -0
  36. package/dist/SSHMimic/loginFormat.d.ts.map +1 -0
  37. package/dist/SSHMimic/loginFormat.js +11 -0
  38. package/dist/SSHMimic/loginFormat.js.map +1 -0
  39. package/dist/SSHMimic/prompt.d.ts.map +1 -0
  40. package/dist/SSHMimic/prompt.js +10 -0
  41. package/dist/SSHMimic/prompt.js.map +1 -0
  42. package/dist/SSHMimic/sftp.d.ts.map +1 -0
  43. package/dist/SSHMimic/sftp.js +620 -0
  44. package/dist/SSHMimic/sftp.js.map +1 -0
  45. package/dist/VirtualFileSystem/binaryPack.d.ts.map +1 -0
  46. package/dist/VirtualFileSystem/binaryPack.js +217 -0
  47. package/dist/VirtualFileSystem/binaryPack.js.map +1 -0
  48. package/dist/VirtualFileSystem/index.d.ts.map +1 -0
  49. package/dist/VirtualFileSystem/index.js +690 -0
  50. package/dist/VirtualFileSystem/index.js.map +1 -0
  51. package/dist/VirtualFileSystem/internalTypes.d.ts.map +1 -0
  52. package/dist/VirtualFileSystem/internalTypes.js +1 -0
  53. package/dist/VirtualFileSystem/internalTypes.js.map +1 -0
  54. package/dist/VirtualFileSystem/path.d.ts.map +1 -0
  55. package/dist/VirtualFileSystem/path.js +50 -0
  56. package/dist/VirtualFileSystem/path.js.map +1 -0
  57. package/dist/VirtualPackageManager/index.d.ts.map +1 -0
  58. package/dist/VirtualPackageManager/index.js +854 -0
  59. package/dist/VirtualPackageManager/index.js.map +1 -0
  60. package/dist/VirtualShell/index.d.ts.map +1 -0
  61. package/dist/VirtualShell/index.js +285 -0
  62. package/dist/VirtualShell/index.js.map +1 -0
  63. package/dist/VirtualShell/shell.d.ts.map +1 -0
  64. package/dist/VirtualShell/shell.js +503 -0
  65. package/dist/VirtualShell/shell.js.map +1 -0
  66. package/dist/VirtualShell/shellParser.d.ts.map +1 -0
  67. package/dist/VirtualShell/shellParser.js +266 -0
  68. package/dist/VirtualShell/shellParser.js.map +1 -0
  69. package/dist/VirtualUserManager/index.d.ts.map +1 -0
  70. package/dist/VirtualUserManager/index.js +608 -0
  71. package/dist/VirtualUserManager/index.js.map +1 -0
  72. package/dist/commands/adduser.d.ts.map +1 -0
  73. package/dist/commands/adduser.js +90 -0
  74. package/dist/commands/adduser.js.map +1 -0
  75. package/dist/commands/alias.d.ts.map +1 -0
  76. package/dist/commands/alias.js +69 -0
  77. package/dist/commands/alias.js.map +1 -0
  78. package/dist/commands/apt.d.ts.map +1 -0
  79. package/dist/commands/apt.js +211 -0
  80. package/dist/commands/apt.js.map +1 -0
  81. package/dist/commands/awk.d.ts.map +1 -0
  82. package/dist/commands/awk.js +170 -0
  83. package/dist/commands/awk.js.map +1 -0
  84. package/dist/commands/base64.d.ts.map +1 -0
  85. package/dist/commands/base64.js +29 -0
  86. package/dist/commands/base64.js.map +1 -0
  87. package/dist/commands/cat.d.ts.map +1 -0
  88. package/dist/commands/cat.js +45 -0
  89. package/dist/commands/cat.js.map +1 -0
  90. package/dist/commands/cd.d.ts.map +1 -0
  91. package/dist/commands/cd.js +22 -0
  92. package/dist/commands/cd.js.map +1 -0
  93. package/dist/commands/chmod.d.ts.map +1 -0
  94. package/dist/commands/chmod.js +88 -0
  95. package/dist/commands/chmod.js.map +1 -0
  96. package/dist/commands/clear.d.ts.map +1 -0
  97. package/dist/commands/clear.js +14 -0
  98. package/dist/commands/clear.js.map +1 -0
  99. package/dist/commands/command-helpers.d.ts.map +1 -0
  100. package/dist/commands/command-helpers.js +222 -0
  101. package/dist/commands/command-helpers.js.map +1 -0
  102. package/dist/commands/cp.d.ts.map +1 -0
  103. package/dist/commands/cp.js +76 -0
  104. package/dist/commands/cp.js.map +1 -0
  105. package/dist/commands/curl.d.ts.map +1 -0
  106. package/dist/commands/curl.js +128 -0
  107. package/dist/commands/curl.js.map +1 -0
  108. package/dist/commands/cut.d.ts.map +1 -0
  109. package/dist/commands/cut.js +35 -0
  110. package/dist/commands/cut.js.map +1 -0
  111. package/dist/commands/date.d.ts.map +1 -0
  112. package/dist/commands/date.js +29 -0
  113. package/dist/commands/date.js.map +1 -0
  114. package/dist/commands/declare.d.ts.map +1 -0
  115. package/dist/commands/declare.js +45 -0
  116. package/dist/commands/declare.js.map +1 -0
  117. package/dist/commands/deluser.d.ts.map +1 -0
  118. package/dist/commands/deluser.js +84 -0
  119. package/dist/commands/deluser.js.map +1 -0
  120. package/dist/commands/df.d.ts.map +1 -0
  121. package/dist/commands/df.js +22 -0
  122. package/dist/commands/df.js.map +1 -0
  123. package/dist/commands/diff.d.ts.map +1 -0
  124. package/dist/commands/diff.js +46 -0
  125. package/dist/commands/diff.js.map +1 -0
  126. package/dist/commands/dpkg.d.ts.map +1 -0
  127. package/dist/commands/dpkg.js +162 -0
  128. package/dist/commands/dpkg.js.map +1 -0
  129. package/dist/commands/du.d.ts.map +1 -0
  130. package/dist/commands/du.js +51 -0
  131. package/dist/commands/du.js.map +1 -0
  132. package/dist/commands/echo.d.ts.map +1 -0
  133. package/dist/commands/echo.js +46 -0
  134. package/dist/commands/echo.js.map +1 -0
  135. package/dist/commands/env.d.ts.map +1 -0
  136. package/dist/commands/env.js +21 -0
  137. package/dist/commands/env.js.map +1 -0
  138. package/dist/commands/exit.d.ts.map +1 -0
  139. package/dist/commands/exit.js +17 -0
  140. package/dist/commands/exit.js.map +1 -0
  141. package/dist/commands/export.d.ts.map +1 -0
  142. package/dist/commands/export.js +34 -0
  143. package/dist/commands/export.js.map +1 -0
  144. package/dist/commands/find.d.ts.map +1 -0
  145. package/dist/commands/find.js +56 -0
  146. package/dist/commands/find.js.map +1 -0
  147. package/dist/commands/free.d.ts.map +1 -0
  148. package/dist/commands/free.js +44 -0
  149. package/dist/commands/free.js.map +1 -0
  150. package/dist/commands/grep.d.ts.map +1 -0
  151. package/dist/commands/grep.js +121 -0
  152. package/dist/commands/grep.js.map +1 -0
  153. package/dist/commands/groups.d.ts.map +1 -0
  154. package/dist/commands/groups.js +18 -0
  155. package/dist/commands/groups.js.map +1 -0
  156. package/dist/commands/gzip.d.ts.map +1 -0
  157. package/dist/commands/gzip.js +83 -0
  158. package/dist/commands/gzip.js.map +1 -0
  159. package/dist/commands/head.d.ts.map +1 -0
  160. package/dist/commands/head.js +47 -0
  161. package/dist/commands/head.js.map +1 -0
  162. package/dist/commands/help.d.ts.map +1 -0
  163. package/dist/commands/help.js +124 -0
  164. package/dist/commands/help.js.map +1 -0
  165. package/dist/commands/helpers.d.ts.map +1 -0
  166. package/dist/commands/helpers.js +167 -0
  167. package/dist/commands/helpers.js.map +1 -0
  168. package/dist/commands/history.d.ts.map +1 -0
  169. package/dist/commands/history.js +27 -0
  170. package/dist/commands/history.js.map +1 -0
  171. package/dist/commands/hostname.d.ts.map +1 -0
  172. package/dist/commands/hostname.js +13 -0
  173. package/dist/commands/hostname.js.map +1 -0
  174. package/dist/commands/htop.d.ts.map +1 -0
  175. package/dist/commands/htop.js +18 -0
  176. package/dist/commands/htop.js.map +1 -0
  177. package/dist/commands/id.d.ts.map +1 -0
  178. package/dist/commands/id.js +18 -0
  179. package/dist/commands/id.js.map +1 -0
  180. package/dist/commands/index.d.ts.map +1 -0
  181. package/dist/commands/index.js +3 -0
  182. package/dist/commands/index.js.map +1 -0
  183. package/dist/commands/kill.d.ts.map +1 -0
  184. package/dist/commands/kill.js +19 -0
  185. package/dist/commands/kill.js.map +1 -0
  186. package/dist/commands/ln.d.ts.map +1 -0
  187. package/dist/commands/ln.js +67 -0
  188. package/dist/commands/ln.js.map +1 -0
  189. package/dist/commands/ls.d.ts.map +1 -0
  190. package/dist/commands/ls.js +201 -0
  191. package/dist/commands/ls.js.map +1 -0
  192. package/dist/commands/lsb-release.d.ts.map +1 -0
  193. package/dist/commands/lsb-release.js +62 -0
  194. package/dist/commands/lsb-release.js.map +1 -0
  195. package/dist/commands/man.d.ts.map +1 -0
  196. package/dist/commands/man.js +50 -0
  197. package/dist/commands/man.js.map +1 -0
  198. package/dist/commands/mkdir.d.ts.map +1 -0
  199. package/dist/commands/mkdir.js +29 -0
  200. package/dist/commands/mkdir.js.map +1 -0
  201. package/dist/commands/mv.d.ts.map +1 -0
  202. package/dist/commands/mv.js +43 -0
  203. package/dist/commands/mv.js.map +1 -0
  204. package/dist/commands/nano.d.ts.map +1 -0
  205. package/dist/commands/nano.js +35 -0
  206. package/dist/commands/nano.js.map +1 -0
  207. package/dist/commands/neofetch.d.ts.map +1 -0
  208. package/dist/commands/neofetch.js +49 -0
  209. package/dist/commands/neofetch.js.map +1 -0
  210. package/dist/commands/node.d.ts.map +1 -0
  211. package/dist/commands/node.js +317 -0
  212. package/dist/commands/node.js.map +1 -0
  213. package/dist/commands/npm.d.ts.map +1 -0
  214. package/dist/commands/npm.js +110 -0
  215. package/dist/commands/npm.js.map +1 -0
  216. package/dist/commands/passwd.d.ts.map +1 -0
  217. package/dist/commands/passwd.js +45 -0
  218. package/dist/commands/passwd.js.map +1 -0
  219. package/dist/commands/ping.d.ts.map +1 -0
  220. package/dist/commands/ping.js +29 -0
  221. package/dist/commands/ping.js.map +1 -0
  222. package/dist/commands/printf.d.ts.map +1 -0
  223. package/dist/commands/printf.js +145 -0
  224. package/dist/commands/printf.js.map +1 -0
  225. package/dist/commands/ps.d.ts.map +1 -0
  226. package/dist/commands/ps.js +47 -0
  227. package/dist/commands/ps.js.map +1 -0
  228. package/dist/commands/pwd.d.ts.map +1 -0
  229. package/dist/commands/pwd.js +8 -0
  230. package/dist/commands/pwd.js.map +1 -0
  231. package/dist/commands/python.d.ts.map +1 -0
  232. package/dist/commands/python.js +2059 -0
  233. package/dist/commands/python.js.map +1 -0
  234. package/dist/commands/read.d.ts.map +1 -0
  235. package/dist/commands/read.js +40 -0
  236. package/dist/commands/read.js.map +1 -0
  237. package/dist/commands/registry.d.ts.map +1 -0
  238. package/dist/commands/registry.js +235 -0
  239. package/dist/commands/registry.js.map +1 -0
  240. package/dist/commands/rm.d.ts.map +1 -0
  241. package/dist/commands/rm.js +37 -0
  242. package/dist/commands/rm.js.map +1 -0
  243. package/dist/commands/runtime.d.ts.map +1 -0
  244. package/dist/commands/runtime.js +286 -0
  245. package/dist/commands/runtime.js.map +1 -0
  246. package/dist/commands/sed.d.ts.map +1 -0
  247. package/dist/commands/sed.js +61 -0
  248. package/dist/commands/sed.js.map +1 -0
  249. package/dist/commands/seq.d.ts.map +1 -0
  250. package/dist/commands/seq.js +51 -0
  251. package/dist/commands/seq.js.map +1 -0
  252. package/dist/commands/set.d.ts.map +1 -0
  253. package/dist/commands/set.js +27 -0
  254. package/dist/commands/set.js.map +1 -0
  255. package/dist/commands/sh.d.ts.map +1 -0
  256. package/dist/commands/sh.js +432 -0
  257. package/dist/commands/sh.js.map +1 -0
  258. package/dist/commands/shift.d.ts.map +1 -0
  259. package/dist/commands/shift.js +63 -0
  260. package/dist/commands/shift.js.map +1 -0
  261. package/dist/commands/sleep.d.ts.map +1 -0
  262. package/dist/commands/sleep.js +19 -0
  263. package/dist/commands/sleep.js.map +1 -0
  264. package/dist/commands/sort.d.ts.map +1 -0
  265. package/dist/commands/sort.js +45 -0
  266. package/dist/commands/sort.js.map +1 -0
  267. package/dist/commands/source.d.ts.map +1 -0
  268. package/dist/commands/source.js +40 -0
  269. package/dist/commands/source.js.map +1 -0
  270. package/dist/commands/stat.d.ts.map +1 -0
  271. package/dist/commands/stat.js +57 -0
  272. package/dist/commands/stat.js.map +1 -0
  273. package/dist/commands/su.d.ts.map +1 -0
  274. package/dist/commands/su.js +58 -0
  275. package/dist/commands/su.js.map +1 -0
  276. package/dist/commands/sudo.d.ts.map +1 -0
  277. package/dist/commands/sudo.js +55 -0
  278. package/dist/commands/sudo.js.map +1 -0
  279. package/dist/commands/tail.d.ts.map +1 -0
  280. package/dist/commands/tail.js +48 -0
  281. package/dist/commands/tail.js.map +1 -0
  282. package/dist/commands/tar.d.ts.map +1 -0
  283. package/dist/commands/tar.js +103 -0
  284. package/dist/commands/tar.js.map +1 -0
  285. package/dist/commands/tee.d.ts.map +1 -0
  286. package/dist/commands/tee.js +37 -0
  287. package/dist/commands/tee.js.map +1 -0
  288. package/dist/commands/test.d.ts.map +1 -0
  289. package/dist/commands/test.js +115 -0
  290. package/dist/commands/test.js.map +1 -0
  291. package/dist/commands/touch.d.ts.map +1 -0
  292. package/dist/commands/touch.js +26 -0
  293. package/dist/commands/touch.js.map +1 -0
  294. package/dist/commands/tr.d.ts.map +1 -0
  295. package/dist/commands/tr.js +62 -0
  296. package/dist/commands/tr.js.map +1 -0
  297. package/dist/commands/tree.d.ts.map +1 -0
  298. package/dist/commands/tree.js +19 -0
  299. package/dist/commands/tree.js.map +1 -0
  300. package/dist/commands/true.d.ts.map +1 -0
  301. package/dist/commands/true.js +25 -0
  302. package/dist/commands/true.js.map +1 -0
  303. package/dist/commands/type.d.ts.map +1 -0
  304. package/dist/commands/type.js +40 -0
  305. package/dist/commands/type.js.map +1 -0
  306. package/dist/commands/uname.d.ts.map +1 -0
  307. package/dist/commands/uname.js +30 -0
  308. package/dist/commands/uname.js.map +1 -0
  309. package/dist/commands/uniq.d.ts.map +1 -0
  310. package/dist/commands/uniq.js +39 -0
  311. package/dist/commands/uniq.js.map +1 -0
  312. package/dist/commands/unset.d.ts.map +1 -0
  313. package/dist/commands/unset.js +17 -0
  314. package/dist/commands/unset.js.map +1 -0
  315. package/dist/commands/uptime.d.ts.map +1 -0
  316. package/dist/commands/uptime.js +49 -0
  317. package/dist/commands/uptime.js.map +1 -0
  318. package/dist/commands/wc.d.ts.map +1 -0
  319. package/dist/commands/wc.js +56 -0
  320. package/dist/commands/wc.js.map +1 -0
  321. package/dist/commands/wget.d.ts.map +1 -0
  322. package/dist/commands/wget.js +127 -0
  323. package/dist/commands/wget.js.map +1 -0
  324. package/dist/commands/which.d.ts.map +1 -0
  325. package/dist/commands/which.js +33 -0
  326. package/dist/commands/which.js.map +1 -0
  327. package/dist/commands/who.d.ts.map +1 -0
  328. package/dist/commands/who.js +23 -0
  329. package/dist/commands/who.js.map +1 -0
  330. package/dist/commands/whoami.d.ts.map +1 -0
  331. package/dist/commands/whoami.js +13 -0
  332. package/dist/commands/whoami.js.map +1 -0
  333. package/dist/commands/xargs.d.ts.map +1 -0
  334. package/dist/commands/xargs.js +22 -0
  335. package/dist/commands/xargs.js.map +1 -0
  336. package/dist/index.d.ts.map +1 -0
  337. package/dist/index.js +10 -0
  338. package/dist/index.js.map +1 -0
  339. package/dist/modules/linuxRootfs.d.ts.map +1 -0
  340. package/dist/modules/linuxRootfs.js +620 -0
  341. package/dist/modules/linuxRootfs.js.map +1 -0
  342. package/dist/modules/neofetch.d.ts.map +1 -0
  343. package/dist/modules/neofetch.js +285 -0
  344. package/dist/modules/neofetch.js.map +1 -0
  345. package/dist/modules/shellInteractive.d.ts.map +1 -0
  346. package/dist/modules/shellInteractive.js +27 -0
  347. package/dist/modules/shellInteractive.js.map +1 -0
  348. package/dist/modules/shellRuntime.d.ts.map +1 -0
  349. package/dist/modules/shellRuntime.js +53 -0
  350. package/dist/modules/shellRuntime.js.map +1 -0
  351. package/dist/self-standalone.d.ts.map +1 -0
  352. package/dist/self-standalone.js +420 -0
  353. package/dist/self-standalone.js.map +1 -0
  354. package/dist/standalone-wo-sftp.d.ts.map +1 -0
  355. package/dist/standalone-wo-sftp.js +31 -0
  356. package/dist/standalone-wo-sftp.js.map +1 -0
  357. package/dist/standalone.d.ts.map +1 -0
  358. package/dist/standalone.js +40 -0
  359. package/dist/standalone.js.map +1 -0
  360. package/dist/types/commands.d.ts.map +1 -0
  361. package/dist/types/commands.js +1 -0
  362. package/dist/types/commands.js.map +1 -0
  363. package/dist/types/pipeline.d.ts.map +1 -0
  364. package/dist/types/pipeline.js +1 -0
  365. package/dist/types/pipeline.js.map +1 -0
  366. package/dist/types/streams.d.ts.map +1 -0
  367. package/dist/types/streams.js +1 -0
  368. package/dist/types/streams.js.map +1 -0
  369. package/dist/types/vfs.d.ts.map +1 -0
  370. package/dist/types/vfs.js +1 -0
  371. package/dist/types/vfs.js.map +1 -0
  372. package/dist/utils/expand.d.ts.map +1 -0
  373. package/dist/utils/expand.js +477 -0
  374. package/dist/utils/expand.js.map +1 -0
  375. package/dist/utils/perfLogger.d.ts.map +1 -0
  376. package/dist/utils/perfLogger.js +50 -0
  377. package/dist/utils/perfLogger.js.map +1 -0
  378. package/dist/utils/tokenize.d.ts.map +1 -0
  379. package/dist/utils/tokenize.js +115 -0
  380. package/dist/utils/tokenize.js.map +1 -0
  381. package/dist/utils/vfsDiff.d.ts.map +1 -0
  382. package/dist/utils/vfsDiff.js +178 -0
  383. package/dist/utils/vfsDiff.js.map +1 -0
  384. package/dist/web-api.d.ts.map +1 -0
  385. package/dist/web-api.js +47 -0
  386. package/dist/web-api.js.map +1 -0
  387. package/dist/web-full.d.ts.map +1 -0
  388. package/dist/web-full.js +9 -0
  389. package/dist/web-full.js.map +1 -0
  390. package/dist/web.d.ts.map +1 -0
  391. package/dist/web.js +774 -0
  392. package/dist/web.js.map +1 -0
  393. package/docs/.nojekyll +1 -0
  394. package/docs/assets/hierarchy.js +1 -0
  395. package/docs/assets/highlight.css +162 -0
  396. package/docs/assets/icons.js +18 -0
  397. package/docs/assets/icons.svg +1 -0
  398. package/docs/assets/main.js +60 -0
  399. package/docs/assets/navigation.js +1 -0
  400. package/docs/assets/search.js +1 -0
  401. package/docs/assets/style.css +1633 -0
  402. package/docs/classes/HoneyPot.html +31 -0
  403. package/docs/classes/SshClient.html +66 -0
  404. package/docs/classes/VirtualFileSystem.html +262 -0
  405. package/docs/classes/VirtualPackageManager.html +63 -0
  406. package/docs/classes/VirtualSftpServer.html +169 -0
  407. package/docs/classes/VirtualShell.html +265 -0
  408. package/docs/classes/VirtualSshServer.html +177 -0
  409. package/docs/classes/VirtualUserManager.html +276 -0
  410. package/docs/functions/assertDiff.html +6 -0
  411. package/docs/functions/diffSnapshots.html +7 -0
  412. package/docs/functions/formatDiff.html +6 -0
  413. package/docs/functions/getArg.html +13 -0
  414. package/docs/functions/getFlag.html +15 -0
  415. package/docs/functions/ifFlag.html +11 -0
  416. package/docs/hierarchy.html +1 -0
  417. package/docs/index.html +1842 -0
  418. package/docs/interfaces/AuditLogEntry.html +6 -0
  419. package/docs/interfaces/CommandContext.html +22 -0
  420. package/docs/interfaces/CommandResult.html +26 -0
  421. package/docs/interfaces/ExecStream.html +11 -0
  422. package/docs/interfaces/HoneyPotStats.html +14 -0
  423. package/docs/interfaces/InstalledPackage.html +20 -0
  424. package/docs/interfaces/NanoEditorSession.html +8 -0
  425. package/docs/interfaces/PackageDefinition.html +30 -0
  426. package/docs/interfaces/PackageFile.html +8 -0
  427. package/docs/interfaces/RemoveOptions.html +4 -0
  428. package/docs/interfaces/ShellEnv.html +6 -0
  429. package/docs/interfaces/ShellModule.html +14 -0
  430. package/docs/interfaces/ShellProperties.html +14 -0
  431. package/docs/interfaces/ShellStream.html +11 -0
  432. package/docs/interfaces/SudoChallenge.html +24 -0
  433. package/docs/interfaces/VfsBaseNode.html +12 -0
  434. package/docs/interfaces/VfsDiff.html +10 -0
  435. package/docs/interfaces/VfsDiffEntry.html +6 -0
  436. package/docs/interfaces/VfsDiffModified.html +10 -0
  437. package/docs/interfaces/VfsDirectoryNode.html +15 -0
  438. package/docs/interfaces/VfsFileNode.html +17 -0
  439. package/docs/interfaces/VfsOptions.html +12 -0
  440. package/docs/interfaces/VfsSnapshot.html +3 -0
  441. package/docs/interfaces/VfsSnapshotBaseNode.html +8 -0
  442. package/docs/interfaces/VfsSnapshotDirectoryNode.html +10 -0
  443. package/docs/interfaces/VfsSnapshotFileNode.html +12 -0
  444. package/docs/interfaces/WriteFileOptions.html +6 -0
  445. package/docs/media/LICENSE +21 -0
  446. package/docs/modules.html +1 -0
  447. package/docs/types/CommandMode.html +2 -0
  448. package/docs/types/CommandOutcome.html +2 -0
  449. package/docs/types/VfsNodeStats.html +2 -0
  450. package/docs/types/VfsNodeType.html +2 -0
  451. package/docs/types/VfsPersistenceMode.html +5 -0
  452. package/docs/types/VfsSnapshotNode.html +2 -0
  453. package/examples/web.min.js +5 -5
  454. package/package.json +6 -4
  455. package/src/commands/man.ts +1 -1
  456. package/src/self-standalone.ts +1 -1
  457. package/src/standalone.ts +8 -3
  458. package/tsconfig.json +7 -2
  459. package/src/Honeypot/index.d.ts.map +0 -1
  460. package/src/Honeypot/index.js +0 -298
  461. package/src/SSHClient/index.d.ts.map +0 -1
  462. package/src/SSHClient/index.js +0 -237
  463. package/src/SSHMimic/exec.d.ts.map +0 -1
  464. package/src/SSHMimic/exec.js +0 -27
  465. package/src/SSHMimic/executor.d.ts.map +0 -1
  466. package/src/SSHMimic/executor.js +0 -160
  467. package/src/SSHMimic/hostKey.d.ts.map +0 -1
  468. package/src/SSHMimic/hostKey.js +0 -17
  469. package/src/SSHMimic/index.d.ts.map +0 -1
  470. package/src/SSHMimic/index.js +0 -249
  471. package/src/SSHMimic/loginBanner.d.ts.map +0 -1
  472. package/src/SSHMimic/loginBanner.js +0 -22
  473. package/src/SSHMimic/loginFormat.d.ts.map +0 -1
  474. package/src/SSHMimic/loginFormat.js +0 -10
  475. package/src/SSHMimic/prompt.d.ts.map +0 -1
  476. package/src/SSHMimic/prompt.js +0 -9
  477. package/src/SSHMimic/sftp.d.ts.map +0 -1
  478. package/src/SSHMimic/sftp.js +0 -619
  479. package/src/VirtualFileSystem/binaryPack.d.ts.map +0 -1
  480. package/src/VirtualFileSystem/binaryPack.js +0 -216
  481. package/src/VirtualFileSystem/index.d.ts.map +0 -1
  482. package/src/VirtualFileSystem/index.js +0 -689
  483. package/src/VirtualFileSystem/internalTypes.d.ts.map +0 -1
  484. package/src/VirtualFileSystem/internalTypes.js +0 -0
  485. package/src/VirtualFileSystem/path.d.ts.map +0 -1
  486. package/src/VirtualFileSystem/path.js +0 -49
  487. package/src/VirtualPackageManager/index.d.ts.map +0 -1
  488. package/src/VirtualPackageManager/index.js +0 -853
  489. package/src/VirtualShell/index.d.ts.map +0 -1
  490. package/src/VirtualShell/index.js +0 -284
  491. package/src/VirtualShell/shell.d.ts.map +0 -1
  492. package/src/VirtualShell/shell.js +0 -502
  493. package/src/VirtualShell/shellParser.d.ts.map +0 -1
  494. package/src/VirtualShell/shellParser.js +0 -265
  495. package/src/VirtualUserManager/index.d.ts.map +0 -1
  496. package/src/VirtualUserManager/index.js +0 -607
  497. package/src/commands/adduser.d.ts.map +0 -1
  498. package/src/commands/adduser.js +0 -89
  499. package/src/commands/alias.d.ts.map +0 -1
  500. package/src/commands/alias.js +0 -68
  501. package/src/commands/apt.d.ts.map +0 -1
  502. package/src/commands/apt.js +0 -210
  503. package/src/commands/awk.d.ts.map +0 -1
  504. package/src/commands/awk.js +0 -169
  505. package/src/commands/base64.d.ts.map +0 -1
  506. package/src/commands/base64.js +0 -28
  507. package/src/commands/cat.d.ts.map +0 -1
  508. package/src/commands/cat.js +0 -44
  509. package/src/commands/cd.d.ts.map +0 -1
  510. package/src/commands/cd.js +0 -21
  511. package/src/commands/chmod.d.ts.map +0 -1
  512. package/src/commands/chmod.js +0 -87
  513. package/src/commands/clear.d.ts.map +0 -1
  514. package/src/commands/clear.js +0 -13
  515. package/src/commands/command-helpers.d.ts.map +0 -1
  516. package/src/commands/command-helpers.js +0 -221
  517. package/src/commands/cp.d.ts.map +0 -1
  518. package/src/commands/cp.js +0 -75
  519. package/src/commands/curl.d.ts.map +0 -1
  520. package/src/commands/curl.js +0 -127
  521. package/src/commands/cut.d.ts.map +0 -1
  522. package/src/commands/cut.js +0 -34
  523. package/src/commands/date.d.ts.map +0 -1
  524. package/src/commands/date.js +0 -28
  525. package/src/commands/declare.d.ts.map +0 -1
  526. package/src/commands/declare.js +0 -44
  527. package/src/commands/deluser.d.ts.map +0 -1
  528. package/src/commands/deluser.js +0 -83
  529. package/src/commands/df.d.ts.map +0 -1
  530. package/src/commands/df.js +0 -21
  531. package/src/commands/diff.d.ts.map +0 -1
  532. package/src/commands/diff.js +0 -45
  533. package/src/commands/dpkg.d.ts.map +0 -1
  534. package/src/commands/dpkg.js +0 -161
  535. package/src/commands/du.d.ts.map +0 -1
  536. package/src/commands/du.js +0 -50
  537. package/src/commands/echo.d.ts.map +0 -1
  538. package/src/commands/echo.js +0 -45
  539. package/src/commands/env.d.ts.map +0 -1
  540. package/src/commands/env.js +0 -20
  541. package/src/commands/exit.d.ts.map +0 -1
  542. package/src/commands/exit.js +0 -16
  543. package/src/commands/export.d.ts.map +0 -1
  544. package/src/commands/export.js +0 -33
  545. package/src/commands/find.d.ts.map +0 -1
  546. package/src/commands/find.js +0 -55
  547. package/src/commands/free.d.ts.map +0 -1
  548. package/src/commands/free.js +0 -43
  549. package/src/commands/grep.d.ts.map +0 -1
  550. package/src/commands/grep.js +0 -120
  551. package/src/commands/groups.d.ts.map +0 -1
  552. package/src/commands/groups.js +0 -17
  553. package/src/commands/gzip.d.ts.map +0 -1
  554. package/src/commands/gzip.js +0 -82
  555. package/src/commands/head.d.ts.map +0 -1
  556. package/src/commands/head.js +0 -46
  557. package/src/commands/help.d.ts.map +0 -1
  558. package/src/commands/help.js +0 -123
  559. package/src/commands/helpers.d.ts.map +0 -1
  560. package/src/commands/helpers.js +0 -166
  561. package/src/commands/history.d.ts.map +0 -1
  562. package/src/commands/history.js +0 -26
  563. package/src/commands/hostname.d.ts.map +0 -1
  564. package/src/commands/hostname.js +0 -12
  565. package/src/commands/htop.d.ts.map +0 -1
  566. package/src/commands/htop.js +0 -17
  567. package/src/commands/id.d.ts.map +0 -1
  568. package/src/commands/id.js +0 -17
  569. package/src/commands/index.d.ts.map +0 -1
  570. package/src/commands/index.js +0 -2
  571. package/src/commands/kill.d.ts.map +0 -1
  572. package/src/commands/kill.js +0 -18
  573. package/src/commands/ln.d.ts.map +0 -1
  574. package/src/commands/ln.js +0 -66
  575. package/src/commands/ls.d.ts.map +0 -1
  576. package/src/commands/ls.js +0 -200
  577. package/src/commands/lsb-release.d.ts.map +0 -1
  578. package/src/commands/lsb-release.js +0 -61
  579. package/src/commands/man.d.ts.map +0 -1
  580. package/src/commands/man.js +0 -49
  581. package/src/commands/mkdir.d.ts.map +0 -1
  582. package/src/commands/mkdir.js +0 -28
  583. package/src/commands/mv.d.ts.map +0 -1
  584. package/src/commands/mv.js +0 -42
  585. package/src/commands/nano.d.ts.map +0 -1
  586. package/src/commands/nano.js +0 -34
  587. package/src/commands/neofetch.d.ts.map +0 -1
  588. package/src/commands/neofetch.js +0 -48
  589. package/src/commands/node.d.ts.map +0 -1
  590. package/src/commands/node.js +0 -316
  591. package/src/commands/npm.d.ts.map +0 -1
  592. package/src/commands/npm.js +0 -109
  593. package/src/commands/passwd.d.ts.map +0 -1
  594. package/src/commands/passwd.js +0 -44
  595. package/src/commands/ping.d.ts.map +0 -1
  596. package/src/commands/ping.js +0 -28
  597. package/src/commands/printf.d.ts.map +0 -1
  598. package/src/commands/printf.js +0 -144
  599. package/src/commands/ps.d.ts.map +0 -1
  600. package/src/commands/ps.js +0 -46
  601. package/src/commands/pwd.d.ts.map +0 -1
  602. package/src/commands/pwd.js +0 -7
  603. package/src/commands/python.d.ts.map +0 -1
  604. package/src/commands/python.js +0 -2058
  605. package/src/commands/read.d.ts.map +0 -1
  606. package/src/commands/read.js +0 -39
  607. package/src/commands/registry.d.ts.map +0 -1
  608. package/src/commands/registry.js +0 -234
  609. package/src/commands/rm.d.ts.map +0 -1
  610. package/src/commands/rm.js +0 -36
  611. package/src/commands/runtime.d.ts.map +0 -1
  612. package/src/commands/runtime.js +0 -285
  613. package/src/commands/sed.d.ts.map +0 -1
  614. package/src/commands/sed.js +0 -60
  615. package/src/commands/seq.d.ts.map +0 -1
  616. package/src/commands/seq.js +0 -50
  617. package/src/commands/set.d.ts.map +0 -1
  618. package/src/commands/set.js +0 -26
  619. package/src/commands/sh.d.ts.map +0 -1
  620. package/src/commands/sh.js +0 -431
  621. package/src/commands/shift.d.ts.map +0 -1
  622. package/src/commands/shift.js +0 -62
  623. package/src/commands/sleep.d.ts.map +0 -1
  624. package/src/commands/sleep.js +0 -18
  625. package/src/commands/sort.d.ts.map +0 -1
  626. package/src/commands/sort.js +0 -44
  627. package/src/commands/source.d.ts.map +0 -1
  628. package/src/commands/source.js +0 -39
  629. package/src/commands/stat.d.ts.map +0 -1
  630. package/src/commands/stat.js +0 -56
  631. package/src/commands/su.d.ts.map +0 -1
  632. package/src/commands/su.js +0 -57
  633. package/src/commands/sudo.d.ts.map +0 -1
  634. package/src/commands/sudo.js +0 -54
  635. package/src/commands/tail.d.ts.map +0 -1
  636. package/src/commands/tail.js +0 -47
  637. package/src/commands/tar.d.ts.map +0 -1
  638. package/src/commands/tar.js +0 -102
  639. package/src/commands/tee.d.ts.map +0 -1
  640. package/src/commands/tee.js +0 -36
  641. package/src/commands/test.d.ts.map +0 -1
  642. package/src/commands/test.js +0 -114
  643. package/src/commands/touch.d.ts.map +0 -1
  644. package/src/commands/touch.js +0 -25
  645. package/src/commands/tr.d.ts.map +0 -1
  646. package/src/commands/tr.js +0 -61
  647. package/src/commands/tree.d.ts.map +0 -1
  648. package/src/commands/tree.js +0 -18
  649. package/src/commands/true.d.ts.map +0 -1
  650. package/src/commands/true.js +0 -24
  651. package/src/commands/type.d.ts.map +0 -1
  652. package/src/commands/type.js +0 -39
  653. package/src/commands/uname.d.ts.map +0 -1
  654. package/src/commands/uname.js +0 -29
  655. package/src/commands/uniq.d.ts.map +0 -1
  656. package/src/commands/uniq.js +0 -38
  657. package/src/commands/unset.d.ts.map +0 -1
  658. package/src/commands/unset.js +0 -16
  659. package/src/commands/uptime.d.ts.map +0 -1
  660. package/src/commands/uptime.js +0 -48
  661. package/src/commands/wc.d.ts.map +0 -1
  662. package/src/commands/wc.js +0 -55
  663. package/src/commands/wget.d.ts.map +0 -1
  664. package/src/commands/wget.js +0 -126
  665. package/src/commands/which.d.ts.map +0 -1
  666. package/src/commands/which.js +0 -32
  667. package/src/commands/who.d.ts.map +0 -1
  668. package/src/commands/who.js +0 -22
  669. package/src/commands/whoami.d.ts.map +0 -1
  670. package/src/commands/whoami.js +0 -12
  671. package/src/commands/xargs.d.ts.map +0 -1
  672. package/src/commands/xargs.js +0 -21
  673. package/src/index.d.ts.map +0 -1
  674. package/src/index.js +0 -9
  675. package/src/modules/linuxRootfs.d.ts.map +0 -1
  676. package/src/modules/linuxRootfs.js +0 -619
  677. package/src/modules/neofetch.d.ts.map +0 -1
  678. package/src/modules/neofetch.js +0 -284
  679. package/src/modules/shellInteractive.d.ts.map +0 -1
  680. package/src/modules/shellInteractive.js +0 -26
  681. package/src/modules/shellRuntime.d.ts.map +0 -1
  682. package/src/modules/shellRuntime.js +0 -52
  683. package/src/self-standalone.d.ts.map +0 -1
  684. package/src/self-standalone.js +0 -418
  685. package/src/standalone-wo-sftp.d.ts.map +0 -1
  686. package/src/standalone-wo-sftp.js +0 -30
  687. package/src/standalone.d.ts.map +0 -1
  688. package/src/standalone.js +0 -35
  689. package/src/types/commands.d.ts.map +0 -1
  690. package/src/types/commands.js +0 -0
  691. package/src/types/pipeline.d.ts.map +0 -1
  692. package/src/types/pipeline.js +0 -0
  693. package/src/types/streams.d.ts.map +0 -1
  694. package/src/types/streams.js +0 -0
  695. package/src/types/vfs.d.ts.map +0 -1
  696. package/src/types/vfs.js +0 -0
  697. package/src/utils/expand.d.ts.map +0 -1
  698. package/src/utils/expand.js +0 -476
  699. package/src/utils/perfLogger.d.ts.map +0 -1
  700. package/src/utils/perfLogger.js +0 -49
  701. package/src/utils/tokenize.d.ts.map +0 -1
  702. package/src/utils/tokenize.js +0 -114
  703. package/src/utils/vfsDiff.d.ts.map +0 -1
  704. package/src/utils/vfsDiff.js +0 -177
  705. package/src/web-api.d.ts.map +0 -1
  706. package/src/web-api.js +0 -46
  707. package/src/web-full.d.ts.map +0 -1
  708. package/src/web-full.js +0 -8
  709. package/src/web.d.ts.map +0 -1
  710. package/src/web.js +0 -773
  711. package/tests/command-helpers.test.d.ts +0 -2
  712. package/tests/command-helpers.test.d.ts.map +0 -1
  713. package/tests/command-helpers.test.js +0 -92
  714. package/tests/commands-admin-net.test.d.ts +0 -2
  715. package/tests/commands-admin-net.test.d.ts.map +0 -1
  716. package/tests/commands-admin-net.test.js +0 -353
  717. package/tests/commands-advanced.test.d.ts +0 -2
  718. package/tests/commands-advanced.test.d.ts.map +0 -1
  719. package/tests/commands-advanced.test.js +0 -378
  720. package/tests/commands-core.test.d.ts +0 -2
  721. package/tests/commands-core.test.d.ts.map +0 -1
  722. package/tests/commands-core.test.js +0 -477
  723. package/tests/commands-missing.test.d.ts +0 -2
  724. package/tests/commands-missing.test.d.ts.map +0 -1
  725. package/tests/commands-missing.test.js +0 -470
  726. package/tests/commands-specific-units.test.d.ts +0 -2
  727. package/tests/commands-specific-units.test.d.ts.map +0 -1
  728. package/tests/commands-specific-units.test.js +0 -264
  729. package/tests/commands-text-sys.test.d.ts +0 -2
  730. package/tests/commands-text-sys.test.d.ts.map +0 -1
  731. package/tests/commands-text-sys.test.js +0 -366
  732. package/tests/expand.test.d.ts +0 -2
  733. package/tests/expand.test.d.ts.map +0 -1
  734. package/tests/expand.test.js +0 -138
  735. package/tests/helpers.test.d.ts +0 -2
  736. package/tests/helpers.test.d.ts.map +0 -1
  737. package/tests/helpers.test.js +0 -52
  738. package/tests/new-features.test.d.ts +0 -2
  739. package/tests/new-features.test.d.ts.map +0 -1
  740. package/tests/new-features.test.js +0 -850
  741. package/tests/parser-executor.test.d.ts +0 -2
  742. package/tests/parser-executor.test.d.ts.map +0 -1
  743. package/tests/parser-executor.test.js +0 -25
  744. package/tests/sftp.test.d.ts +0 -2
  745. package/tests/sftp.test.d.ts.map +0 -1
  746. package/tests/sftp.test.js +0 -246
  747. package/tests/ssh-exec.test.d.ts +0 -2
  748. package/tests/ssh-exec.test.d.ts.map +0 -1
  749. package/tests/ssh-exec.test.js +0 -39
  750. package/tests/test-helper.d.ts +0 -56
  751. package/tests/test-helper.d.ts.map +0 -1
  752. package/tests/test-helper.js +0 -71
  753. package/tests/users.test.d.ts +0 -2
  754. package/tests/users.test.d.ts.map +0 -1
  755. package/tests/users.test.js +0 -71
  756. package/tests/web.test.d.ts +0 -2
  757. package/tests/web.test.d.ts.map +0 -1
  758. package/tests/web.test.js +0 -149
  759. /package/{src → dist}/Honeypot/index.d.ts +0 -0
  760. /package/{src → dist}/SSHClient/index.d.ts +0 -0
  761. /package/{src → dist}/SSHMimic/exec.d.ts +0 -0
  762. /package/{src → dist}/SSHMimic/executor.d.ts +0 -0
  763. /package/{src → dist}/SSHMimic/hostKey.d.ts +0 -0
  764. /package/{src → dist}/SSHMimic/index.d.ts +0 -0
  765. /package/{src → dist}/SSHMimic/loginBanner.d.ts +0 -0
  766. /package/{src → dist}/SSHMimic/loginFormat.d.ts +0 -0
  767. /package/{src → dist}/SSHMimic/prompt.d.ts +0 -0
  768. /package/{src → dist}/SSHMimic/sftp.d.ts +0 -0
  769. /package/{src → dist}/VirtualFileSystem/binaryPack.d.ts +0 -0
  770. /package/{src → dist}/VirtualFileSystem/index.d.ts +0 -0
  771. /package/{src → dist}/VirtualFileSystem/internalTypes.d.ts +0 -0
  772. /package/{src → dist}/VirtualFileSystem/path.d.ts +0 -0
  773. /package/{src → dist}/VirtualPackageManager/index.d.ts +0 -0
  774. /package/{src → dist}/VirtualShell/index.d.ts +0 -0
  775. /package/{src → dist}/VirtualShell/shell.d.ts +0 -0
  776. /package/{src → dist}/VirtualShell/shellParser.d.ts +0 -0
  777. /package/{src → dist}/VirtualUserManager/index.d.ts +0 -0
  778. /package/{src → dist}/commands/adduser.d.ts +0 -0
  779. /package/{src → dist}/commands/alias.d.ts +0 -0
  780. /package/{src → dist}/commands/apt.d.ts +0 -0
  781. /package/{src → dist}/commands/awk.d.ts +0 -0
  782. /package/{src → dist}/commands/base64.d.ts +0 -0
  783. /package/{src → dist}/commands/cat.d.ts +0 -0
  784. /package/{src → dist}/commands/cd.d.ts +0 -0
  785. /package/{src → dist}/commands/chmod.d.ts +0 -0
  786. /package/{src → dist}/commands/clear.d.ts +0 -0
  787. /package/{src → dist}/commands/command-helpers.d.ts +0 -0
  788. /package/{src → dist}/commands/cp.d.ts +0 -0
  789. /package/{src → dist}/commands/curl.d.ts +0 -0
  790. /package/{src → dist}/commands/cut.d.ts +0 -0
  791. /package/{src → dist}/commands/date.d.ts +0 -0
  792. /package/{src → dist}/commands/declare.d.ts +0 -0
  793. /package/{src → dist}/commands/deluser.d.ts +0 -0
  794. /package/{src → dist}/commands/df.d.ts +0 -0
  795. /package/{src → dist}/commands/diff.d.ts +0 -0
  796. /package/{src → dist}/commands/dpkg.d.ts +0 -0
  797. /package/{src → dist}/commands/du.d.ts +0 -0
  798. /package/{src → dist}/commands/echo.d.ts +0 -0
  799. /package/{src → dist}/commands/env.d.ts +0 -0
  800. /package/{src → dist}/commands/exit.d.ts +0 -0
  801. /package/{src → dist}/commands/export.d.ts +0 -0
  802. /package/{src → dist}/commands/find.d.ts +0 -0
  803. /package/{src → dist}/commands/free.d.ts +0 -0
  804. /package/{src → dist}/commands/grep.d.ts +0 -0
  805. /package/{src → dist}/commands/groups.d.ts +0 -0
  806. /package/{src → dist}/commands/gzip.d.ts +0 -0
  807. /package/{src → dist}/commands/head.d.ts +0 -0
  808. /package/{src → dist}/commands/help.d.ts +0 -0
  809. /package/{src → dist}/commands/helpers.d.ts +0 -0
  810. /package/{src → dist}/commands/history.d.ts +0 -0
  811. /package/{src → dist}/commands/hostname.d.ts +0 -0
  812. /package/{src → dist}/commands/htop.d.ts +0 -0
  813. /package/{src → dist}/commands/id.d.ts +0 -0
  814. /package/{src → dist}/commands/index.d.ts +0 -0
  815. /package/{src → dist}/commands/kill.d.ts +0 -0
  816. /package/{src → dist}/commands/ln.d.ts +0 -0
  817. /package/{src → dist}/commands/ls.d.ts +0 -0
  818. /package/{src → dist}/commands/lsb-release.d.ts +0 -0
  819. /package/{src → dist}/commands/man.d.ts +0 -0
  820. /package/{src → dist}/commands/mkdir.d.ts +0 -0
  821. /package/{src → dist}/commands/mv.d.ts +0 -0
  822. /package/{src → dist}/commands/nano.d.ts +0 -0
  823. /package/{src → dist}/commands/neofetch.d.ts +0 -0
  824. /package/{src → dist}/commands/node.d.ts +0 -0
  825. /package/{src → dist}/commands/npm.d.ts +0 -0
  826. /package/{src → dist}/commands/passwd.d.ts +0 -0
  827. /package/{src → dist}/commands/ping.d.ts +0 -0
  828. /package/{src → dist}/commands/printf.d.ts +0 -0
  829. /package/{src → dist}/commands/ps.d.ts +0 -0
  830. /package/{src → dist}/commands/pwd.d.ts +0 -0
  831. /package/{src → dist}/commands/python.d.ts +0 -0
  832. /package/{src → dist}/commands/read.d.ts +0 -0
  833. /package/{src → dist}/commands/registry.d.ts +0 -0
  834. /package/{src → dist}/commands/rm.d.ts +0 -0
  835. /package/{src → dist}/commands/runtime.d.ts +0 -0
  836. /package/{src → dist}/commands/sed.d.ts +0 -0
  837. /package/{src → dist}/commands/seq.d.ts +0 -0
  838. /package/{src → dist}/commands/set.d.ts +0 -0
  839. /package/{src → dist}/commands/sh.d.ts +0 -0
  840. /package/{src → dist}/commands/shift.d.ts +0 -0
  841. /package/{src → dist}/commands/sleep.d.ts +0 -0
  842. /package/{src → dist}/commands/sort.d.ts +0 -0
  843. /package/{src → dist}/commands/source.d.ts +0 -0
  844. /package/{src → dist}/commands/stat.d.ts +0 -0
  845. /package/{src → dist}/commands/su.d.ts +0 -0
  846. /package/{src → dist}/commands/sudo.d.ts +0 -0
  847. /package/{src → dist}/commands/tail.d.ts +0 -0
  848. /package/{src → dist}/commands/tar.d.ts +0 -0
  849. /package/{src → dist}/commands/tee.d.ts +0 -0
  850. /package/{src → dist}/commands/test.d.ts +0 -0
  851. /package/{src → dist}/commands/touch.d.ts +0 -0
  852. /package/{src → dist}/commands/tr.d.ts +0 -0
  853. /package/{src → dist}/commands/tree.d.ts +0 -0
  854. /package/{src → dist}/commands/true.d.ts +0 -0
  855. /package/{src → dist}/commands/type.d.ts +0 -0
  856. /package/{src → dist}/commands/uname.d.ts +0 -0
  857. /package/{src → dist}/commands/uniq.d.ts +0 -0
  858. /package/{src → dist}/commands/unset.d.ts +0 -0
  859. /package/{src → dist}/commands/uptime.d.ts +0 -0
  860. /package/{src → dist}/commands/wc.d.ts +0 -0
  861. /package/{src → dist}/commands/wget.d.ts +0 -0
  862. /package/{src → dist}/commands/which.d.ts +0 -0
  863. /package/{src → dist}/commands/who.d.ts +0 -0
  864. /package/{src → dist}/commands/whoami.d.ts +0 -0
  865. /package/{src → dist}/commands/xargs.d.ts +0 -0
  866. /package/{src → dist}/index.d.ts +0 -0
  867. /package/{src → dist}/modules/linuxRootfs.d.ts +0 -0
  868. /package/{src → dist}/modules/neofetch.d.ts +0 -0
  869. /package/{src → dist}/modules/shellInteractive.d.ts +0 -0
  870. /package/{src → dist}/modules/shellRuntime.d.ts +0 -0
  871. /package/{src → dist}/self-standalone.d.ts +0 -0
  872. /package/{src → dist}/standalone-wo-sftp.d.ts +0 -0
  873. /package/{src → dist}/standalone.d.ts +0 -0
  874. /package/{src → dist}/types/commands.d.ts +0 -0
  875. /package/{src → dist}/types/pipeline.d.ts +0 -0
  876. /package/{src → dist}/types/streams.d.ts +0 -0
  877. /package/{src → dist}/types/vfs.d.ts +0 -0
  878. /package/{src → dist}/utils/expand.d.ts +0 -0
  879. /package/{src → dist}/utils/perfLogger.d.ts +0 -0
  880. /package/{src → dist}/utils/tokenize.d.ts +0 -0
  881. /package/{src → dist}/utils/vfsDiff.d.ts +0 -0
  882. /package/{src → dist}/web-api.d.ts +0 -0
  883. /package/{src → dist}/web-full.d.ts +0 -0
  884. /package/{src → dist}/web.d.ts +0 -0
@@ -1,2058 +0,0 @@
1
- import { ifFlag } from "./command-helpers";
2
- import { resolvePath } from "./helpers";
3
- const VERSION = "Python 3.11.2";
4
- const _VERSION_SHORT = "3.11.2";
5
- const VERSION_INFO = "3.11.2 (default, Mar 13 2023, 12:18:29) [GCC 12.2.0]";
6
- const NONE = { __pytype__: "none" };
7
- function pyDict(entries = []) {
8
- return { __pytype__: "dict", data: new Map(entries) };
9
- }
10
- function pyRange(start, stop, step = 1) {
11
- return { __pytype__: "range", start, stop, step };
12
- }
13
- function isPyDict(v) {
14
- return (!!v &&
15
- typeof v === "object" &&
16
- !Array.isArray(v) &&
17
- v.__pytype__ === "dict");
18
- }
19
- function isPyRange(v) {
20
- return (!!v &&
21
- typeof v === "object" &&
22
- !Array.isArray(v) &&
23
- v.__pytype__ === "range");
24
- }
25
- function isPyFunc(v) {
26
- return (!!v &&
27
- typeof v === "object" &&
28
- !Array.isArray(v) &&
29
- v.__pytype__ === "func");
30
- }
31
- function isPyClass(v) {
32
- return (!!v &&
33
- typeof v === "object" &&
34
- !Array.isArray(v) &&
35
- v.__pytype__ === "class");
36
- }
37
- function isPyInstance(v) {
38
- return (!!v &&
39
- typeof v === "object" &&
40
- !Array.isArray(v) &&
41
- v.__pytype__ === "instance");
42
- }
43
- function isPyNone(v) {
44
- return (!!v &&
45
- typeof v === "object" &&
46
- !Array.isArray(v) &&
47
- v.__pytype__ === "none");
48
- }
49
- // ─── repr / str ───────────────────────────────────────────────────────────────
50
- function pyRepr(v) {
51
- if (v === null || isPyNone(v))
52
- return "None";
53
- if (v === true)
54
- return "True";
55
- if (v === false)
56
- return "False";
57
- if (typeof v === "number")
58
- return Number.isInteger(v)
59
- ? String(v)
60
- : v.toPrecision(12).replace(/\.?0+$/, "");
61
- if (typeof v === "string")
62
- return `'${v.replace(/'/g, "\\'")}'`;
63
- if (Array.isArray(v))
64
- return `[${v.map(pyRepr).join(", ")}]`;
65
- if (isPyDict(v))
66
- return `{${[...v.data.entries()].map(([k, val]) => `'${k}': ${pyRepr(val)}`).join(", ")}}`;
67
- if (isPyRange(v))
68
- return `range(${v.start}, ${v.stop}${v.step !== 1 ? `, ${v.step}` : ""})`;
69
- if (isPyFunc(v))
70
- return `<function ${v.name} at 0x...>`;
71
- if (isPyClass(v))
72
- return `<class '${v.name}'>`;
73
- if (isPyInstance(v))
74
- return `<${v.cls.name} object at 0x...>`;
75
- return String(v);
76
- }
77
- function pyStr(v) {
78
- if (v === null || isPyNone(v))
79
- return "None";
80
- if (v === true)
81
- return "True";
82
- if (v === false)
83
- return "False";
84
- if (typeof v === "number")
85
- return Number.isInteger(v)
86
- ? String(v)
87
- : v.toPrecision(12).replace(/\.?0+$/, "");
88
- if (typeof v === "string")
89
- return v;
90
- if (Array.isArray(v))
91
- return `[${v.map(pyRepr).join(", ")}]`;
92
- if (isPyDict(v))
93
- return `{${[...v.data.entries()].map(([k, val]) => `'${k}': ${pyRepr(val)}`).join(", ")}}`;
94
- if (isPyRange(v))
95
- return `range(${v.start}, ${v.stop}${v.step !== 1 ? `, ${v.step}` : ""})`;
96
- return pyRepr(v);
97
- }
98
- function pyBool(v) {
99
- if (v === null || isPyNone(v))
100
- return false;
101
- if (typeof v === "boolean")
102
- return v;
103
- if (typeof v === "number")
104
- return v !== 0;
105
- if (typeof v === "string")
106
- return v.length > 0;
107
- if (Array.isArray(v))
108
- return v.length > 0;
109
- if (isPyDict(v))
110
- return v.data.size > 0;
111
- if (isPyRange(v))
112
- return pyRangeLength(v) > 0;
113
- return true;
114
- }
115
- function pyRangeLength(r) {
116
- if (r.step === 0)
117
- return 0;
118
- const n = Math.ceil((r.stop - r.start) / r.step);
119
- return Math.max(0, n);
120
- }
121
- function pyRangeItems(r) {
122
- const items = [];
123
- for (let i = r.start; r.step > 0 ? i < r.stop : i > r.stop; i += r.step) {
124
- items.push(i);
125
- if (items.length > 10000)
126
- break;
127
- }
128
- return items;
129
- }
130
- function pyIter(v) {
131
- if (Array.isArray(v))
132
- return v;
133
- if (typeof v === "string")
134
- return [...v];
135
- if (isPyRange(v))
136
- return pyRangeItems(v);
137
- if (isPyDict(v))
138
- return [...v.data.keys()];
139
- throw new PyError("TypeError", `'${pyTypeName(v)}' object is not iterable`);
140
- }
141
- function pyTypeName(v) {
142
- if (v === null || isPyNone(v))
143
- return "NoneType";
144
- if (typeof v === "boolean")
145
- return "bool";
146
- if (typeof v === "number")
147
- return Number.isInteger(v) ? "int" : "float";
148
- if (typeof v === "string")
149
- return "str";
150
- if (Array.isArray(v))
151
- return "list";
152
- if (isPyDict(v))
153
- return "dict";
154
- if (isPyRange(v))
155
- return "range";
156
- if (isPyFunc(v))
157
- return "function";
158
- if (isPyClass(v))
159
- return "type";
160
- if (isPyInstance(v))
161
- return v.cls.name;
162
- return "object";
163
- }
164
- class PyError {
165
- type;
166
- message;
167
- constructor(type, message) {
168
- this.type = type;
169
- this.message = message;
170
- }
171
- toString() {
172
- return `${this.type}: ${this.message}`;
173
- }
174
- }
175
- class ReturnSignal {
176
- value;
177
- constructor(value) {
178
- this.value = value;
179
- }
180
- }
181
- class BreakSignal {
182
- }
183
- class ContinueSignal {
184
- }
185
- class ExitSignal {
186
- code;
187
- constructor(code) {
188
- this.code = code;
189
- }
190
- }
191
- function makeRootScope(cwd) {
192
- const scope = new Map();
193
- // Built-in modules (lazy)
194
- const osModule = pyDict([
195
- ["sep", "/"],
196
- ["linesep", "\n"],
197
- ["curdir", "."],
198
- ["pardir", ".."],
199
- ]);
200
- osModule.__methods__ = {
201
- getcwd: () => cwd,
202
- getenv: (k) => typeof k === "string" ? (process.env[k] ?? NONE) : NONE,
203
- path: pyDict([
204
- ["join", NONE],
205
- ["exists", NONE],
206
- ["dirname", NONE],
207
- ["basename", NONE],
208
- ]),
209
- listdir: () => [],
210
- };
211
- scope.set("__builtins__", NONE);
212
- scope.set("__name__", "__main__");
213
- scope.set("__cwd__", cwd);
214
- return scope;
215
- }
216
- // ─── built-in modules ─────────────────────────────────────────────────────────
217
- function makeOsModule(cwd) {
218
- const path = pyDict([
219
- ["sep", "/"],
220
- ["curdir", "."],
221
- ]);
222
- const os = pyDict([
223
- ["sep", "/"],
224
- ["linesep", "\n"],
225
- ["name", "posix"],
226
- ]);
227
- // We'll handle method calls in callMethod
228
- os._cwd = cwd;
229
- path._cwd = cwd;
230
- os.path = path;
231
- return os;
232
- }
233
- function makeSysModule() {
234
- return pyDict([
235
- ["version", VERSION_INFO],
236
- [
237
- "version_info",
238
- pyDict([
239
- ["major", 3],
240
- ["minor", 11],
241
- ["micro", 2],
242
- ].map(([k, v]) => [k, v])),
243
- ],
244
- ["platform", "linux"],
245
- ["executable", "/usr/bin/python3"],
246
- ["prefix", "/usr"],
247
- ["path", ["/usr/lib/python3.11", "/usr/lib/python3.11/lib-dynload"]],
248
- ["argv", [""]],
249
- ["maxsize", 9007199254740991],
250
- ]);
251
- }
252
- function makeMathModule() {
253
- return pyDict([
254
- ["pi", Math.PI],
255
- ["e", Math.E],
256
- ["tau", Math.PI * 2],
257
- ["inf", Infinity],
258
- ["nan", NaN],
259
- ["sqrt", NONE],
260
- ["floor", NONE],
261
- ["ceil", NONE],
262
- ["log", NONE],
263
- ["pow", NONE],
264
- ["sin", NONE],
265
- ["cos", NONE],
266
- ["tan", NONE],
267
- ["fabs", NONE],
268
- ["factorial", NONE],
269
- ]);
270
- }
271
- function makeJsonModule() {
272
- return pyDict([
273
- ["dumps", NONE],
274
- ["loads", NONE],
275
- ]);
276
- }
277
- function makeReModule() {
278
- return pyDict([
279
- ["match", NONE],
280
- ["search", NONE],
281
- ["findall", NONE],
282
- ["sub", NONE],
283
- ["split", NONE],
284
- ["compile", NONE],
285
- ]);
286
- }
287
- const MODULE_FACTORIES = {
288
- os: makeOsModule,
289
- sys: () => makeSysModule(),
290
- math: () => makeMathModule(),
291
- json: () => makeJsonModule(),
292
- re: () => makeReModule(),
293
- random: () => pyDict([
294
- ["random", NONE],
295
- ["randint", NONE],
296
- ["choice", NONE],
297
- ["shuffle", NONE],
298
- ]),
299
- time: () => pyDict([
300
- ["time", NONE],
301
- ["sleep", NONE],
302
- ["ctime", NONE],
303
- ]),
304
- datetime: () => pyDict([
305
- ["datetime", NONE],
306
- ["date", NONE],
307
- ["timedelta", NONE],
308
- ]),
309
- collections: () => pyDict([
310
- ["Counter", NONE],
311
- ["defaultdict", NONE],
312
- ["OrderedDict", NONE],
313
- ]),
314
- itertools: () => pyDict([
315
- ["chain", NONE],
316
- ["product", NONE],
317
- ["combinations", NONE],
318
- ["permutations", NONE],
319
- ]),
320
- functools: () => pyDict([
321
- ["reduce", NONE],
322
- ["partial", NONE],
323
- ["lru_cache", NONE],
324
- ]),
325
- string: () => pyDict([
326
- ["ascii_letters", "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"],
327
- ["digits", "0123456789"],
328
- ["punctuation", "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~"],
329
- ]),
330
- };
331
- // ─── interpreter ─────────────────────────────────────────────────────────────
332
- class Interpreter {
333
- cwd;
334
- output = [];
335
- stderr = [];
336
- modules = new Map();
337
- constructor(cwd) {
338
- this.cwd = cwd;
339
- }
340
- getOutput() {
341
- return this.output.join("\n") + (this.output.length ? "\n" : "");
342
- }
343
- getStderr() {
344
- return this.stderr.join("\n") + (this.stderr.length ? "\n" : "");
345
- }
346
- // ── tokenizer / parser helpers ──────────────────────────────────────────
347
- splitArgs(s) {
348
- // Split on commas respecting balanced parens, brackets, braces, quotes
349
- const args = [];
350
- let depth = 0, cur = "", inStr = false, strChar = "";
351
- for (let i = 0; i < s.length; i++) {
352
- const ch = s[i];
353
- if (inStr) {
354
- cur += ch;
355
- if (ch === strChar && s[i - 1] !== "\\")
356
- inStr = false;
357
- }
358
- else if (ch === '"' || ch === "'") {
359
- inStr = true;
360
- strChar = ch;
361
- cur += ch;
362
- }
363
- else if ("([{".includes(ch)) {
364
- depth++;
365
- cur += ch;
366
- }
367
- else if (")]}".includes(ch)) {
368
- depth--;
369
- cur += ch;
370
- }
371
- else if (ch === "," && depth === 0) {
372
- args.push(cur.trim());
373
- cur = "";
374
- }
375
- else {
376
- cur += ch;
377
- }
378
- }
379
- if (cur.trim())
380
- args.push(cur.trim());
381
- return args;
382
- }
383
- // ── expression evaluator ─────────────────────────────────────────────────
384
- pyEval(expr, scope) {
385
- expr = expr.trim();
386
- if (!expr)
387
- return NONE;
388
- // None True False literals
389
- if (expr === "None")
390
- return NONE;
391
- if (expr === "True")
392
- return true;
393
- if (expr === "False")
394
- return false;
395
- if (expr === "...")
396
- return NONE;
397
- // Number literals
398
- if (/^-?\d+$/.test(expr))
399
- return parseInt(expr, 10);
400
- if (/^-?\d+\.\d*$/.test(expr))
401
- return parseFloat(expr);
402
- if (/^0x[0-9a-fA-F]+$/.test(expr))
403
- return parseInt(expr, 16);
404
- if (/^0o[0-7]+$/.test(expr))
405
- return parseInt(expr.slice(2), 8);
406
- // String literals (single, double, triple)
407
- if (/^('''[\s\S]*'''|"""[\s\S]*""")$/.test(expr)) {
408
- return expr.slice(3, -3);
409
- }
410
- if (/^(['"])(.*)\1$/s.test(expr)) {
411
- const inner = expr.slice(1, -1);
412
- return inner
413
- .replace(/\\n/g, "\n")
414
- .replace(/\\t/g, "\t")
415
- .replace(/\\r/g, "\r")
416
- .replace(/\\\\/g, "\\")
417
- .replace(/\\'/g, "'")
418
- .replace(/\\"/g, '"');
419
- }
420
- // f-strings
421
- const fMatch = expr.match(/^f(['"])([\s\S]*)\1$/);
422
- if (fMatch) {
423
- let result = fMatch[2];
424
- result = result.replace(/\{([^{}]+)\}/g, (_, inner) => {
425
- try {
426
- return pyStr(this.pyEval(inner.trim(), scope));
427
- }
428
- catch {
429
- return `{${inner}}`;
430
- }
431
- });
432
- return result;
433
- }
434
- // Byte strings b"..." — treat as string
435
- const bMatch = expr.match(/^b(['"])(.*)\1$/s);
436
- if (bMatch)
437
- return bMatch[2];
438
- // List literal [...]
439
- if (expr.startsWith("[") && expr.endsWith("]")) {
440
- const inner = expr.slice(1, -1).trim();
441
- if (!inner)
442
- return [];
443
- // List comprehension
444
- const compMatch = inner.match(/^(.+?)\s+for\s+(\w+)\s+in\s+(.+?)(?:\s+if\s+(.+))?$/);
445
- if (compMatch) {
446
- const [, itemExpr, varName, iterExpr, condExpr] = compMatch;
447
- const iterable = pyIter(this.pyEval(iterExpr.trim(), scope));
448
- const result = [];
449
- for (const item of iterable) {
450
- const inner2 = new Map(scope);
451
- inner2.set(varName, item);
452
- if (condExpr && !pyBool(this.pyEval(condExpr, inner2)))
453
- continue;
454
- result.push(this.pyEval(itemExpr.trim(), inner2));
455
- }
456
- return result;
457
- }
458
- return this.splitArgs(inner).map((a) => this.pyEval(a, scope));
459
- }
460
- // Tuple (...)
461
- if (expr.startsWith("(") && expr.endsWith(")")) {
462
- const inner = expr.slice(1, -1).trim();
463
- if (!inner)
464
- return [];
465
- const parts = this.splitArgs(inner);
466
- if (parts.length === 1 && !inner.endsWith(","))
467
- return this.pyEval(parts[0], scope);
468
- return parts.map((a) => this.pyEval(a, scope));
469
- }
470
- // Dict literal {...}
471
- if (expr.startsWith("{") && expr.endsWith("}")) {
472
- const inner = expr.slice(1, -1).trim();
473
- if (!inner)
474
- return pyDict();
475
- const dict = pyDict();
476
- for (const entry of this.splitArgs(inner)) {
477
- const colonIdx = entry.indexOf(":");
478
- if (colonIdx === -1)
479
- continue;
480
- const k = pyStr(this.pyEval(entry.slice(0, colonIdx).trim(), scope));
481
- const v = this.pyEval(entry.slice(colonIdx + 1).trim(), scope);
482
- dict.data.set(k, v);
483
- }
484
- return dict;
485
- }
486
- // not expr
487
- const notMatch = expr.match(/^not\s+(.+)$/);
488
- if (notMatch)
489
- return !pyBool(this.pyEval(notMatch[1], scope));
490
- // Binary operators (right-to-left scan at lowest depth)
491
- const binaryOps = [
492
- ["or"],
493
- ["and"],
494
- ["in", "not in", "is not", "is", "==", "!=", "<=", ">=", "<", ">"],
495
- ["+", "-"],
496
- ["**"],
497
- ["*", "//", "/", "%"],
498
- ];
499
- for (const ops of binaryOps) {
500
- const result = this.tryBinaryOp(expr, ops, scope);
501
- if (result !== undefined)
502
- return result;
503
- }
504
- // Unary minus
505
- if (expr.startsWith("-")) {
506
- const val = this.pyEval(expr.slice(1), scope);
507
- if (typeof val === "number")
508
- return -val;
509
- }
510
- // Subscript: expr[key] or expr[start:stop]
511
- if (process.env.PY_DEBUG)
512
- console.error("eval:", JSON.stringify(expr));
513
- if (expr.endsWith("]") && !expr.startsWith("[")) {
514
- const bracketStart = this.findMatchingBracket(expr, "[");
515
- if (bracketStart !== -1) {
516
- const obj = this.pyEval(expr.slice(0, bracketStart), scope);
517
- const key = expr.slice(bracketStart + 1, -1);
518
- return this.subscript(obj, key, scope);
519
- }
520
- }
521
- // Function call: name(args...) — must come BEFORE dotMatch to avoid
522
- // print('x'.upper()) being parsed as dotMatch("print('x'", "upper", "()")
523
- const callMatch = expr.match(/^([A-Za-z_][A-Za-z0-9_]*)\s*\(([\s\S]*)\)$/);
524
- if (callMatch) {
525
- const [, name, argsStr] = callMatch;
526
- const callArgs = (argsStr?.trim() ? this.splitArgs(argsStr) : []).map((a) => this.pyEval(a, scope));
527
- return this.callBuiltin(name, callArgs, scope);
528
- }
529
- // Attribute access / method call: expr.attr or expr.method(args)
530
- // Uses a depth-aware scanner to find the rightmost dot at depth 0
531
- const dotResult = this.findDotAccess(expr);
532
- if (dotResult) {
533
- const { objExpr, attr, callPart } = dotResult;
534
- const obj = this.pyEval(objExpr, scope);
535
- if (callPart !== undefined) {
536
- const argsInner = callPart.slice(1, -1);
537
- const callArgs = argsInner.trim()
538
- ? this.splitArgs(argsInner).map((a) => this.pyEval(a, scope))
539
- : [];
540
- return this.callMethod(obj, attr, callArgs, scope);
541
- }
542
- return this.getAttr(obj, attr, scope);
543
- }
544
- // Variable lookup
545
- if (/^[A-Za-z_][A-Za-z0-9_]*$/.test(expr)) {
546
- if (scope.has(expr))
547
- return scope.get(expr);
548
- // Check parent scopes (for closures)
549
- throw new PyError("NameError", `name '${expr}' is not defined`);
550
- }
551
- // Dotted name lookup (module.attr)
552
- if (/^[A-Za-z_][A-Za-z0-9_.]+$/.test(expr)) {
553
- const parts = expr.split(".");
554
- let val = scope.get(parts[0]) ??
555
- (() => {
556
- throw new PyError("NameError", `name '${parts[0]}' is not defined`);
557
- })();
558
- for (const part of parts.slice(1)) {
559
- val = this.getAttr(val, part, scope);
560
- }
561
- return val;
562
- }
563
- return NONE;
564
- }
565
- findMatchingBracket(s, open) {
566
- const close = open === "[" ? "]" : open === "(" ? ")" : "}";
567
- let depth = 0;
568
- for (let i = s.length - 1; i >= 0; i--) {
569
- if (s[i] === close)
570
- depth++;
571
- if (s[i] === open) {
572
- depth--;
573
- if (depth === 0)
574
- return i;
575
- }
576
- }
577
- return -1;
578
- }
579
- /**
580
- * Find the rightmost dot-attribute access at depth 0, respecting strings/parens.
581
- * Returns {objExpr, attr, callPart} or null if not a dot-access expression.
582
- */
583
- findDotAccess(expr) {
584
- // Scan right to left for a dot at depth 0 (not inside strings/brackets)
585
- let depth = 0, inStr = false, strChar = "";
586
- for (let i = expr.length - 1; i > 0; i--) {
587
- const ch = expr[i];
588
- if (inStr) {
589
- if (ch === strChar && expr[i - 1] !== "\\")
590
- inStr = false;
591
- continue;
592
- }
593
- if (ch === '"' || ch === "'") {
594
- inStr = true;
595
- strChar = ch;
596
- continue;
597
- }
598
- if (")]}".includes(ch)) {
599
- depth++;
600
- continue;
601
- }
602
- if ("([{".includes(ch)) {
603
- depth--;
604
- continue;
605
- }
606
- if (depth !== 0)
607
- continue;
608
- if (ch !== ".")
609
- continue;
610
- // Found a dot at depth 0
611
- const objExpr = expr.slice(0, i).trim();
612
- const rest = expr.slice(i + 1); // "attr" or "attr(args)"
613
- const attrMatch = rest.match(/^(\w+)(\([\s\S]*\))?$/);
614
- if (!attrMatch)
615
- continue;
616
- // Skip float literals like 1.5
617
- if (/^-?\d+$/.test(objExpr))
618
- continue;
619
- return { objExpr, attr: attrMatch[1], callPart: attrMatch[2] };
620
- }
621
- return null;
622
- }
623
- tryBinaryOp(expr, ops, scope) {
624
- let depth = 0, inStr = false, strChar = "";
625
- for (let i = expr.length - 1; i >= 0; i--) {
626
- const ch = expr[i];
627
- if (inStr) {
628
- if (ch === strChar && expr[i - 1] !== "\\")
629
- inStr = false;
630
- continue;
631
- }
632
- if (ch === '"' || ch === "'") {
633
- inStr = true;
634
- strChar = ch;
635
- continue;
636
- }
637
- if (")]}".includes(ch)) {
638
- depth++;
639
- continue;
640
- }
641
- if ("([{".includes(ch)) {
642
- depth--;
643
- continue;
644
- }
645
- if (depth !== 0)
646
- continue;
647
- for (const op of ops) {
648
- if (expr.slice(i, i + op.length) === op) {
649
- // Skip "*" if it's actually part of "**"
650
- if (op === "*" && (expr[i + 1] === "*" || expr[i - 1] === "*"))
651
- continue;
652
- // Ensure it's a standalone operator (not part of identifier)
653
- const before = expr[i - 1];
654
- const after = expr[i + op.length];
655
- const wordOp = /^[a-z]/.test(op);
656
- if (wordOp) {
657
- if (before && /\w/.test(before))
658
- continue;
659
- if (after && /\w/.test(after))
660
- continue;
661
- }
662
- const left = expr.slice(0, i).trim();
663
- const right = expr.slice(i + op.length).trim();
664
- if (!left || !right)
665
- continue;
666
- return this.applyBinaryOp(op, left, right, scope);
667
- }
668
- }
669
- }
670
- return undefined;
671
- }
672
- applyBinaryOp(op, leftExpr, rightExpr, scope) {
673
- if (op === "and") {
674
- const l = this.pyEval(leftExpr, scope);
675
- return pyBool(l) ? this.pyEval(rightExpr, scope) : l;
676
- }
677
- if (op === "or") {
678
- const l = this.pyEval(leftExpr, scope);
679
- return pyBool(l) ? l : this.pyEval(rightExpr, scope);
680
- }
681
- const left = this.pyEval(leftExpr, scope);
682
- const right = this.pyEval(rightExpr, scope);
683
- switch (op) {
684
- case "+":
685
- if (typeof left === "string" && typeof right === "string")
686
- return left + right;
687
- if (Array.isArray(left) && Array.isArray(right))
688
- return [...left, ...right];
689
- return left + right;
690
- case "-":
691
- return left - right;
692
- case "*":
693
- if (typeof left === "string" && typeof right === "number")
694
- return left.repeat(right);
695
- if (Array.isArray(left) && typeof right === "number") {
696
- const arr = [];
697
- for (let i = 0; i < right; i++)
698
- arr.push(...left);
699
- return arr;
700
- }
701
- return left * right;
702
- case "/": {
703
- if (right === 0)
704
- throw new PyError("ZeroDivisionError", "division by zero");
705
- return left / right;
706
- }
707
- case "//": {
708
- if (right === 0)
709
- throw new PyError("ZeroDivisionError", "integer division or modulo by zero");
710
- return Math.floor(left / right);
711
- }
712
- case "%": {
713
- if (typeof left === "string")
714
- return this.pyStringFormat(left, Array.isArray(right) ? right : [right]);
715
- if (right === 0)
716
- throw new PyError("ZeroDivisionError", "integer division or modulo by zero");
717
- return left % right;
718
- }
719
- case "**":
720
- return left ** right;
721
- case "==":
722
- return pyRepr(left) === pyRepr(right) || left === right;
723
- case "!=":
724
- return pyRepr(left) !== pyRepr(right) && left !== right;
725
- case "<":
726
- return left < right;
727
- case "<=":
728
- return left <= right;
729
- case ">":
730
- return left > right;
731
- case ">=":
732
- return left >= right;
733
- case "in":
734
- return this.pyIn(right, left);
735
- case "not in":
736
- return !this.pyIn(right, left);
737
- case "is":
738
- return (left === right ||
739
- (isPyNone(left) && isPyNone(right)));
740
- case "is not":
741
- return !(left === right ||
742
- (isPyNone(left) && isPyNone(right)));
743
- }
744
- return NONE;
745
- }
746
- pyIn(container, item) {
747
- if (typeof container === "string")
748
- return typeof item === "string" && container.includes(item);
749
- if (Array.isArray(container))
750
- return container.some((v) => pyRepr(v) === pyRepr(item));
751
- if (isPyDict(container))
752
- return container.data.has(pyStr(item));
753
- return false;
754
- }
755
- subscript(obj, key, scope) {
756
- // Slice
757
- if (key.includes(":")) {
758
- const parts = key.split(":").map((p) => p.trim());
759
- const start = parts[0]
760
- ? this.pyEval(parts[0], scope)
761
- : undefined;
762
- const stop = parts[1]
763
- ? this.pyEval(parts[1], scope)
764
- : undefined;
765
- if (typeof obj === "string")
766
- return obj.slice(start, stop);
767
- if (Array.isArray(obj))
768
- return obj.slice(start, stop);
769
- return NONE;
770
- }
771
- const k = this.pyEval(key, scope);
772
- if (Array.isArray(obj)) {
773
- let idx = k;
774
- if (idx < 0)
775
- idx = obj.length + idx;
776
- return obj[idx] ?? NONE;
777
- }
778
- if (typeof obj === "string") {
779
- let idx = k;
780
- if (idx < 0)
781
- idx = obj.length + idx;
782
- return obj[idx] ?? NONE;
783
- }
784
- if (isPyDict(obj))
785
- return obj.data.get(pyStr(k)) ?? NONE;
786
- throw new PyError("TypeError", `'${pyTypeName(obj)}' is not subscriptable`);
787
- }
788
- // ── attribute access ─────────────────────────────────────────────────────
789
- getAttr(obj, attr, _scope) {
790
- if (isPyDict(obj)) {
791
- if (obj.data.has(attr))
792
- return obj.data.get(attr);
793
- // Special dict attributes
794
- if (attr === "path" && obj.path)
795
- return obj.path;
796
- return NONE;
797
- }
798
- if (isPyInstance(obj))
799
- return obj.attrs.get(attr) ?? NONE;
800
- if (typeof obj === "string") {
801
- // String attributes
802
- const strMethods = {
803
- __class__: { __pytype__: "class", name: "str" },
804
- };
805
- return strMethods[attr] ?? NONE;
806
- }
807
- return NONE;
808
- }
809
- // ── method calls ──────────────────────────────────────────────────────────
810
- callMethod(obj, method, args, _scope) {
811
- // String methods
812
- if (typeof obj === "string") {
813
- switch (method) {
814
- case "upper":
815
- return obj.toUpperCase();
816
- case "lower":
817
- return obj.toLowerCase();
818
- case "strip":
819
- return (args[0] ? obj.replace(new RegExp(`[${args[0]}]+`, "g"), "") : obj).trim();
820
- case "lstrip":
821
- return obj.trimStart();
822
- case "rstrip":
823
- return obj.trimEnd();
824
- case "split":
825
- return obj
826
- .split(typeof args[0] === "string" ? args[0] : /\s+/)
827
- .filter((s, i) => i > 0 || s !== "");
828
- case "splitlines":
829
- return obj.split("\n");
830
- case "join":
831
- return pyIter(args[0] ?? [])
832
- .map(pyStr)
833
- .join(obj);
834
- case "replace":
835
- return obj.replaceAll(pyStr(args[0] ?? ""), pyStr(args[1] ?? ""));
836
- case "startswith":
837
- return obj.startsWith(pyStr(args[0] ?? ""));
838
- case "endswith":
839
- return obj.endsWith(pyStr(args[0] ?? ""));
840
- case "find":
841
- return obj.indexOf(pyStr(args[0] ?? ""));
842
- case "index": {
843
- const i = obj.indexOf(pyStr(args[0] ?? ""));
844
- if (i === -1)
845
- throw new PyError("ValueError", "substring not found");
846
- return i;
847
- }
848
- case "count":
849
- return obj.split(pyStr(args[0] ?? "")).length - 1;
850
- case "format":
851
- return this.pyStringFormat(obj, args);
852
- case "encode":
853
- return obj; // bytes stub
854
- case "decode":
855
- return obj;
856
- case "isdigit":
857
- return /^\d+$/.test(obj);
858
- case "isalpha":
859
- return /^[a-zA-Z]+$/.test(obj);
860
- case "isalnum":
861
- return /^[a-zA-Z0-9]+$/.test(obj);
862
- case "isspace":
863
- return /^\s+$/.test(obj);
864
- case "isupper":
865
- return obj === obj.toUpperCase() && obj !== obj.toLowerCase();
866
- case "islower":
867
- return obj === obj.toLowerCase() && obj !== obj.toUpperCase();
868
- case "center": {
869
- const w = args[0] ?? 0;
870
- const f = pyStr(args[1] ?? " ");
871
- return obj.padStart(Math.floor((w + obj.length) / 2), f).padEnd(w, f);
872
- }
873
- case "ljust":
874
- return obj.padEnd(args[0] ?? 0, pyStr(args[1] ?? " "));
875
- case "rjust":
876
- return obj.padStart(args[0] ?? 0, pyStr(args[1] ?? " "));
877
- case "zfill":
878
- return obj.padStart(args[0] ?? 0, "0");
879
- case "title":
880
- return obj.replace(/\b\w/g, (c) => c.toUpperCase());
881
- case "capitalize":
882
- return obj[0]?.toUpperCase() + obj.slice(1).toLowerCase();
883
- case "swapcase":
884
- return [...obj]
885
- .map((c) => c === c.toUpperCase() ? c.toLowerCase() : c.toUpperCase())
886
- .join("");
887
- }
888
- }
889
- // List methods
890
- if (Array.isArray(obj)) {
891
- switch (method) {
892
- case "append":
893
- obj.push(args[0] ?? NONE);
894
- return NONE;
895
- case "extend":
896
- for (const v of pyIter(args[0] ?? []))
897
- obj.push(v);
898
- return NONE;
899
- case "insert":
900
- obj.splice(args[0] ?? 0, 0, args[1] ?? NONE);
901
- return NONE;
902
- case "pop": {
903
- const idx = args[0] !== undefined ? args[0] : -1;
904
- const i = idx < 0 ? obj.length + idx : idx;
905
- return obj.splice(i, 1)[0] ?? NONE;
906
- }
907
- case "remove": {
908
- const i = obj.findIndex((v) => pyRepr(v) === pyRepr(args[0] ?? NONE));
909
- if (i !== -1)
910
- obj.splice(i, 1);
911
- return NONE;
912
- }
913
- case "index": {
914
- const i = obj.findIndex((v) => pyRepr(v) === pyRepr(args[0] ?? NONE));
915
- if (i === -1)
916
- throw new PyError("ValueError", "is not in list");
917
- return i;
918
- }
919
- case "count":
920
- return obj.filter((v) => pyRepr(v) === pyRepr(args[0] ?? NONE))
921
- .length;
922
- case "sort":
923
- obj.sort((a, b) => typeof a === "number" && typeof b === "number"
924
- ? a - b
925
- : pyStr(a).localeCompare(pyStr(b)));
926
- return NONE;
927
- case "reverse":
928
- obj.reverse();
929
- return NONE;
930
- case "copy":
931
- return [...obj];
932
- case "clear":
933
- obj.splice(0);
934
- return NONE;
935
- }
936
- }
937
- // Dict methods
938
- if (isPyDict(obj)) {
939
- switch (method) {
940
- case "keys":
941
- return [...obj.data.keys()];
942
- case "values":
943
- return [...obj.data.values()];
944
- case "items":
945
- return [...obj.data.entries()].map(([k, v]) => [k, v]);
946
- case "get":
947
- return obj.data.get(pyStr(args[0] ?? "")) ?? args[1] ?? NONE;
948
- case "update": {
949
- if (isPyDict(args[0] ?? NONE))
950
- for (const [k, v] of args[0].data)
951
- obj.data.set(k, v);
952
- return NONE;
953
- }
954
- case "pop": {
955
- const k = pyStr(args[0] ?? "");
956
- const v = obj.data.get(k) ?? args[1] ?? NONE;
957
- obj.data.delete(k);
958
- return v;
959
- }
960
- case "clear":
961
- obj.data.clear();
962
- return NONE;
963
- case "copy":
964
- return pyDict([...obj.data.entries()]);
965
- case "setdefault": {
966
- const k = pyStr(args[0] ?? "");
967
- if (!obj.data.has(k))
968
- obj.data.set(k, args[1] ?? NONE);
969
- return obj.data.get(k) ?? NONE;
970
- }
971
- }
972
- }
973
- // os module methods
974
- if (isPyDict(obj) &&
975
- obj.data.has("name") &&
976
- obj.data.get("name") === "posix") {
977
- switch (method) {
978
- case "getcwd":
979
- return this.cwd;
980
- case "getenv":
981
- return typeof args[0] === "string"
982
- ? (process.env[args[0]] ?? args[1] ?? NONE)
983
- : NONE;
984
- case "listdir":
985
- return [];
986
- case "path":
987
- return obj; // return self
988
- }
989
- }
990
- // os.path methods
991
- if (isPyDict(obj)) {
992
- switch (method) {
993
- case "join":
994
- return args.map(pyStr).join("/").replace(/\/+/g, "/");
995
- case "exists":
996
- return false; // no real fs access
997
- case "dirname": {
998
- const p = pyStr(args[0] ?? "");
999
- return p.split("/").slice(0, -1).join("/") || "/";
1000
- }
1001
- case "basename": {
1002
- const p = pyStr(args[0] ?? "");
1003
- return p.split("/").pop() ?? "";
1004
- }
1005
- case "abspath":
1006
- return pyStr(args[0] ?? "");
1007
- case "splitext": {
1008
- const p = pyStr(args[0] ?? "");
1009
- const d = p.lastIndexOf(".");
1010
- return d > 0 ? [p.slice(0, d), p.slice(d)] : [p, ""];
1011
- }
1012
- case "isfile":
1013
- return false;
1014
- case "isdir":
1015
- return false;
1016
- }
1017
- }
1018
- // sys module
1019
- if (isPyDict(obj) &&
1020
- obj.data.has("version") &&
1021
- obj.data.get("version") === VERSION_INFO) {
1022
- switch (method) {
1023
- case "exit":
1024
- throw new ExitSignal(args[0] ?? 0);
1025
- }
1026
- }
1027
- // math module
1028
- if (isPyDict(obj)) {
1029
- const mathFns = {
1030
- sqrt: Math.sqrt,
1031
- floor: Math.floor,
1032
- ceil: Math.ceil,
1033
- fabs: Math.abs,
1034
- log: Math.log,
1035
- log2: Math.log2,
1036
- log10: Math.log10,
1037
- sin: Math.sin,
1038
- cos: Math.cos,
1039
- tan: Math.tan,
1040
- asin: Math.asin,
1041
- acos: Math.acos,
1042
- atan: Math.atan,
1043
- atan2: Math.atan2,
1044
- pow: Math.pow,
1045
- exp: Math.exp,
1046
- hypot: Math.hypot,
1047
- };
1048
- if (method in mathFns) {
1049
- const fn = mathFns[method];
1050
- return fn(...args.map((a) => a));
1051
- }
1052
- if (method === "factorial") {
1053
- let n = args[0] ?? 0;
1054
- let r = 1;
1055
- while (n > 1) {
1056
- r *= n--;
1057
- }
1058
- return r;
1059
- }
1060
- if (method === "gcd") {
1061
- let a = Math.abs(args[0] ?? 0);
1062
- let b = Math.abs(args[1] ?? 0);
1063
- while (b) {
1064
- [a, b] = [b, a % b];
1065
- }
1066
- return a;
1067
- }
1068
- }
1069
- // json module
1070
- if (isPyDict(obj)) {
1071
- if (method === "dumps") {
1072
- const opts = isPyDict(args[1] ?? NONE)
1073
- ? args[1]
1074
- : undefined;
1075
- const indent = opts ? opts.data.get("indent") : undefined;
1076
- return JSON.stringify(this.pyToJs(args[0] ?? NONE), null, indent);
1077
- }
1078
- if (method === "loads") {
1079
- return this.jsToPy(JSON.parse(pyStr(args[0] ?? "")));
1080
- }
1081
- }
1082
- // Instance method calls
1083
- if (isPyInstance(obj)) {
1084
- const fn = obj.attrs.get(method) ?? obj.cls.methods.get(method) ?? NONE;
1085
- if (isPyFunc(fn)) {
1086
- const callScope = new Map(fn.closure);
1087
- callScope.set("self", obj);
1088
- fn.params.slice(1).forEach((p, i) => callScope.set(p, args[i] ?? NONE));
1089
- return this.execBlock(fn.body, callScope);
1090
- }
1091
- }
1092
- throw new PyError("AttributeError", `'${pyTypeName(obj)}' object has no attribute '${method}'`);
1093
- }
1094
- pyStringFormat(fmt, args) {
1095
- let i = 0;
1096
- return fmt.replace(/%([diouxXeEfFgGcrs%])/g, (_, spec) => {
1097
- if (spec === "%")
1098
- return "%";
1099
- const val = args[i++];
1100
- switch (spec) {
1101
- case "d":
1102
- case "i":
1103
- return String(Math.trunc(val));
1104
- case "f":
1105
- return val.toFixed(6);
1106
- case "s":
1107
- return pyStr(val ?? NONE);
1108
- case "r":
1109
- return pyRepr(val ?? NONE);
1110
- default:
1111
- return String(val);
1112
- }
1113
- });
1114
- }
1115
- pyToJs(v) {
1116
- if (isPyNone(v))
1117
- return null;
1118
- if (isPyDict(v))
1119
- return Object.fromEntries([...v.data.entries()].map(([k, val]) => [k, this.pyToJs(val)]));
1120
- if (Array.isArray(v))
1121
- return v.map((i) => this.pyToJs(i));
1122
- return v;
1123
- }
1124
- jsToPy(v) {
1125
- if (v === null || v === undefined)
1126
- return NONE;
1127
- if (typeof v === "boolean")
1128
- return v;
1129
- if (typeof v === "number")
1130
- return v;
1131
- if (typeof v === "string")
1132
- return v;
1133
- if (Array.isArray(v))
1134
- return v.map((i) => this.jsToPy(i));
1135
- if (typeof v === "object")
1136
- return pyDict(Object.entries(v).map(([k, val]) => [
1137
- k,
1138
- this.jsToPy(val),
1139
- ]));
1140
- return NONE;
1141
- }
1142
- // ── built-in functions ────────────────────────────────────────────────────
1143
- callBuiltin(name, args, scope) {
1144
- // User-defined functions
1145
- if (scope.has(name)) {
1146
- const fn = scope.get(name) ?? NONE;
1147
- if (isPyFunc(fn))
1148
- return this.callFunc(fn, args, scope);
1149
- if (isPyClass(fn))
1150
- return this.instantiate(fn, args, scope);
1151
- return fn;
1152
- }
1153
- switch (name) {
1154
- // Output
1155
- case "print": {
1156
- const sep = " ", end = "\n";
1157
- this.output.push(args.map(pyStr).join(sep) + end.replace(/\\n/g, ""));
1158
- return NONE;
1159
- }
1160
- case "input": {
1161
- this.output.push(pyStr(args[0] ?? ""));
1162
- return "";
1163
- }
1164
- // Type constructors
1165
- case "int": {
1166
- if (args.length === 0)
1167
- return 0;
1168
- const base = args[1] ?? 10;
1169
- const n = parseInt(pyStr(args[0] ?? 0), base);
1170
- return Number.isNaN(n)
1171
- ? (() => {
1172
- throw new PyError("ValueError", `invalid literal for int()`);
1173
- })()
1174
- : n;
1175
- }
1176
- case "float": {
1177
- if (args.length === 0)
1178
- return 0.0;
1179
- const f = parseFloat(pyStr(args[0] ?? 0));
1180
- return Number.isNaN(f)
1181
- ? (() => {
1182
- throw new PyError("ValueError", `could not convert to float`);
1183
- })()
1184
- : f;
1185
- }
1186
- case "str":
1187
- return args.length === 0 ? "" : pyStr(args[0] ?? NONE);
1188
- case "bool":
1189
- return args.length === 0 ? false : pyBool(args[0] ?? NONE);
1190
- case "list":
1191
- return args.length === 0 ? [] : pyIter(args[0] ?? []);
1192
- case "tuple":
1193
- return args.length === 0 ? [] : pyIter(args[0] ?? []);
1194
- case "set":
1195
- return args.length === 0
1196
- ? []
1197
- : [...new Set(pyIter(args[0] ?? []).map(pyRepr))].map((s) => {
1198
- const v = pyIter(args[0] ?? []).find((item) => pyRepr(item) === s);
1199
- return v ?? NONE;
1200
- });
1201
- case "dict":
1202
- return args.length === 0
1203
- ? pyDict()
1204
- : isPyDict(args[0] ?? NONE)
1205
- ? args[0]
1206
- : pyDict();
1207
- case "bytes":
1208
- return typeof args[0] === "string" ? args[0] : pyStr(args[0] ?? "");
1209
- case "bytearray":
1210
- return args.length === 0 ? "" : pyStr(args[0] ?? "");
1211
- // Type inspection
1212
- case "type": {
1213
- if (args.length === 1)
1214
- return `<class '${pyTypeName(args[0] ?? NONE)}'>`;
1215
- return NONE;
1216
- }
1217
- case "isinstance":
1218
- return pyTypeName(args[0] ?? NONE) === pyStr(args[1] ?? "");
1219
- case "issubclass":
1220
- return false;
1221
- case "callable":
1222
- return isPyFunc(args[0] ?? NONE);
1223
- case "hasattr":
1224
- return isPyDict(args[0] ?? NONE)
1225
- ? args[0].data.has(pyStr(args[1] ?? ""))
1226
- : false;
1227
- case "getattr": {
1228
- if (!isPyDict(args[0] ?? NONE))
1229
- return args[2] ?? NONE;
1230
- return (args[0].data.get(pyStr(args[1] ?? "")) ?? args[2] ?? NONE);
1231
- }
1232
- case "setattr": {
1233
- if (isPyDict(args[0] ?? NONE))
1234
- args[0].data.set(pyStr(args[1] ?? ""), args[2] ?? NONE);
1235
- return NONE;
1236
- }
1237
- // Functional
1238
- case "len": {
1239
- const v = args[0] ?? NONE;
1240
- if (typeof v === "string")
1241
- return v.length;
1242
- if (Array.isArray(v))
1243
- return v.length;
1244
- if (isPyDict(v))
1245
- return v.data.size;
1246
- if (isPyRange(v))
1247
- return pyRangeLength(v);
1248
- throw new PyError("TypeError", `object of type '${pyTypeName(v)}' has no len()`);
1249
- }
1250
- case "range": {
1251
- if (args.length === 1)
1252
- return pyRange(0, args[0]);
1253
- if (args.length === 2)
1254
- return pyRange(args[0], args[1]);
1255
- return pyRange(args[0], args[1], args[2]);
1256
- }
1257
- case "enumerate": {
1258
- const start = args[1] ?? 0;
1259
- return pyIter(args[0] ?? []).map((v, i) => [i + start, v]);
1260
- }
1261
- case "zip": {
1262
- const iters = args.map(pyIter);
1263
- const len = Math.min(...iters.map((it) => it.length));
1264
- return Array.from({ length: len }, (_, i) => iters.map((it) => it[i] ?? NONE));
1265
- }
1266
- case "map": {
1267
- const fn = args[0] ?? NONE;
1268
- return pyIter(args[1] ?? []).map((v) => isPyFunc(fn) ? this.callFunc(fn, [v], scope) : NONE);
1269
- }
1270
- case "filter": {
1271
- const fn = args[0] ?? NONE;
1272
- return pyIter(args[1] ?? []).filter((v) => isPyFunc(fn) ? pyBool(this.callFunc(fn, [v], scope)) : pyBool(v));
1273
- }
1274
- case "reduce": {
1275
- const fn = args[0] ?? NONE;
1276
- const items = pyIter(args[1] ?? []);
1277
- if (items.length === 0)
1278
- return args[2] ?? NONE;
1279
- let acc = args[2] !== undefined ? args[2] : items[0];
1280
- for (const item of args[2] !== undefined ? items : items.slice(1)) {
1281
- acc = isPyFunc(fn)
1282
- ? this.callFunc(fn, [acc, item], scope)
1283
- : NONE;
1284
- }
1285
- return acc;
1286
- }
1287
- case "sorted": {
1288
- const items = [...pyIter(args[0] ?? [])];
1289
- const sortArg1 = args[1] ?? NONE;
1290
- const keyFn = isPyDict(sortArg1)
1291
- ? (sortArg1.data.get("key") ?? NONE)
1292
- : sortArg1;
1293
- items.sort((a, b) => {
1294
- const ka = isPyFunc(keyFn)
1295
- ? this.callFunc(keyFn, [a], scope)
1296
- : a;
1297
- const kb = isPyFunc(keyFn)
1298
- ? this.callFunc(keyFn, [b], scope)
1299
- : b;
1300
- return typeof ka === "number" && typeof kb === "number"
1301
- ? ka - kb
1302
- : pyStr(ka).localeCompare(pyStr(kb));
1303
- });
1304
- return items;
1305
- }
1306
- case "reversed":
1307
- return [...pyIter(args[0] ?? [])].reverse();
1308
- case "any":
1309
- return pyIter(args[0] ?? []).some(pyBool);
1310
- case "all":
1311
- return pyIter(args[0] ?? []).every(pyBool);
1312
- case "sum":
1313
- return pyIter(args[0] ?? []).reduce((acc, v) => acc + v, (args[1] ?? 0));
1314
- case "max": {
1315
- const items = args.length === 1 ? pyIter(args[0] ?? []) : args;
1316
- return items.reduce((a, b) => (a >= b ? a : b));
1317
- }
1318
- case "min": {
1319
- const items = args.length === 1 ? pyIter(args[0] ?? []) : args;
1320
- return items.reduce((a, b) => (a <= b ? a : b));
1321
- }
1322
- case "abs":
1323
- return Math.abs(args[0] ?? 0);
1324
- case "round":
1325
- return args[1] !== undefined
1326
- ? parseFloat(args[0].toFixed(args[1]))
1327
- : Math.round(args[0] ?? 0);
1328
- case "divmod": {
1329
- const a = args[0], b = args[1];
1330
- return [Math.floor(a / b), a % b];
1331
- }
1332
- case "pow":
1333
- return args[0] ** args[1];
1334
- case "hex":
1335
- return `0x${args[0].toString(16)}`;
1336
- case "oct":
1337
- return `0o${args[0].toString(8)}`;
1338
- case "bin":
1339
- return `0b${args[0].toString(2)}`;
1340
- case "ord":
1341
- return pyStr(args[0] ?? "").charCodeAt(0);
1342
- case "chr":
1343
- return String.fromCharCode(args[0] ?? 0);
1344
- case "id":
1345
- return Math.floor(Math.random() * 0xffffffff);
1346
- case "hash":
1347
- return typeof args[0] === "number"
1348
- ? args[0]
1349
- : pyStr(args[0] ?? "")
1350
- .split("")
1351
- .reduce((h, c) => (h * 31 + c.charCodeAt(0)) | 0, 0);
1352
- // I/O
1353
- case "open":
1354
- throw new PyError("PermissionError", "open() not available in virtual runtime");
1355
- case "repr":
1356
- return pyRepr(args[0] ?? NONE);
1357
- // Iteration helpers
1358
- case "iter":
1359
- return args[0] ?? NONE; // simplification
1360
- case "next": {
1361
- if (Array.isArray(args[0]) && args[0].length > 0)
1362
- return args[0].shift();
1363
- return (args[1] ??
1364
- (() => {
1365
- throw new PyError("StopIteration", "");
1366
- })());
1367
- }
1368
- // vars/globals/locals
1369
- case "vars":
1370
- return pyDict([...scope.entries()].map(([k, v]) => [k, v]));
1371
- case "globals":
1372
- return pyDict([...scope.entries()].map(([k, v]) => [k, v]));
1373
- case "locals":
1374
- return pyDict([...scope.entries()].map(([k, v]) => [k, v]));
1375
- case "dir": {
1376
- if (args.length === 0)
1377
- return [...scope.keys()];
1378
- const obj = args[0] ?? NONE;
1379
- if (typeof obj === "string")
1380
- return [
1381
- "upper",
1382
- "lower",
1383
- "strip",
1384
- "split",
1385
- "join",
1386
- "replace",
1387
- "find",
1388
- "format",
1389
- "encode",
1390
- "startswith",
1391
- "endswith",
1392
- "count",
1393
- "isdigit",
1394
- "isalpha",
1395
- "title",
1396
- "capitalize",
1397
- ];
1398
- if (Array.isArray(obj))
1399
- return [
1400
- "append",
1401
- "extend",
1402
- "insert",
1403
- "pop",
1404
- "remove",
1405
- "index",
1406
- "count",
1407
- "sort",
1408
- "reverse",
1409
- "copy",
1410
- "clear",
1411
- ];
1412
- if (isPyDict(obj))
1413
- return [
1414
- "keys",
1415
- "values",
1416
- "items",
1417
- "get",
1418
- "update",
1419
- "pop",
1420
- "clear",
1421
- "copy",
1422
- "setdefault",
1423
- ];
1424
- return [];
1425
- }
1426
- // Exception
1427
- case "Exception":
1428
- case "ValueError":
1429
- case "TypeError":
1430
- case "KeyError":
1431
- case "IndexError":
1432
- case "AttributeError":
1433
- case "NameError":
1434
- case "RuntimeError":
1435
- case "StopIteration":
1436
- case "NotImplementedError":
1437
- case "OSError":
1438
- case "IOError":
1439
- throw new PyError(name, pyStr(args[0] ?? ""));
1440
- // exec/eval
1441
- case "exec": {
1442
- this.execScript(pyStr(args[0] ?? ""), scope);
1443
- return NONE;
1444
- }
1445
- case "eval":
1446
- return this.pyEval(pyStr(args[0] ?? ""), scope);
1447
- default:
1448
- throw new PyError("NameError", `name '${name}' is not defined`);
1449
- }
1450
- }
1451
- callFunc(fn, args, _scope) {
1452
- const callScope = new Map(fn.closure);
1453
- fn.params.forEach((p, i) => {
1454
- if (p.startsWith("*")) {
1455
- callScope.set(p.slice(1), args.slice(i));
1456
- return;
1457
- }
1458
- callScope.set(p, args[i] ?? NONE);
1459
- });
1460
- try {
1461
- return this.execBlock(fn.body, callScope);
1462
- }
1463
- catch (e) {
1464
- if (e instanceof ReturnSignal)
1465
- return e.value;
1466
- throw e;
1467
- }
1468
- }
1469
- instantiate(cls, args, scope) {
1470
- const inst = { __pytype__: "instance", cls, attrs: new Map() };
1471
- const init = cls.methods.get("__init__");
1472
- if (init)
1473
- this.callMethod(inst, "__init__", args, scope);
1474
- return inst;
1475
- }
1476
- // ── statement executor ────────────────────────────────────────────────────
1477
- execScript(code, scope) {
1478
- const lines = code.split("\n");
1479
- this.execLines(lines, 0, scope);
1480
- }
1481
- execLines(lines, startIdx, scope) {
1482
- let i = startIdx;
1483
- while (i < lines.length) {
1484
- const raw = lines[i];
1485
- if (!raw.trim() || raw.trim().startsWith("#")) {
1486
- i++;
1487
- continue;
1488
- }
1489
- i = this.execStatement(lines, i, scope);
1490
- }
1491
- return i;
1492
- }
1493
- execBlock(bodyLines, scope) {
1494
- try {
1495
- this.execLines(bodyLines, 0, scope);
1496
- }
1497
- catch (e) {
1498
- if (e instanceof ReturnSignal)
1499
- return e.value;
1500
- throw e;
1501
- }
1502
- return NONE;
1503
- }
1504
- getIndent(line) {
1505
- let n = 0;
1506
- for (const ch of line) {
1507
- if (ch === " ")
1508
- n++;
1509
- else if (ch === "\t")
1510
- n += 4;
1511
- else
1512
- break;
1513
- }
1514
- return n;
1515
- }
1516
- collectBlock(lines, startIdx, baseIndent) {
1517
- const block = [];
1518
- for (let i = startIdx; i < lines.length; i++) {
1519
- const l = lines[i];
1520
- if (!l.trim()) {
1521
- block.push("");
1522
- continue;
1523
- }
1524
- if (this.getIndent(l) <= baseIndent)
1525
- break;
1526
- block.push(l.slice(baseIndent + 4));
1527
- }
1528
- return block;
1529
- }
1530
- execStatement(lines, idx, scope) {
1531
- const raw = lines[idx];
1532
- const line = raw.trim();
1533
- const indent = this.getIndent(raw);
1534
- // pass
1535
- if (line === "pass")
1536
- return idx + 1;
1537
- // break / continue
1538
- if (line === "break") {
1539
- throw new BreakSignal();
1540
- }
1541
- if (line === "continue") {
1542
- throw new ContinueSignal();
1543
- }
1544
- // return
1545
- const retMatch = line.match(/^return(?:\s+(.+))?$/);
1546
- if (retMatch)
1547
- throw new ReturnSignal(retMatch[1] ? this.pyEval(retMatch[1], scope) : NONE);
1548
- // raise
1549
- const raiseMatch = line.match(/^raise(?:\s+(.+))?$/);
1550
- if (raiseMatch) {
1551
- if (raiseMatch[1]) {
1552
- const ex = this.pyEval(raiseMatch[1], scope);
1553
- throw new PyError(typeof ex === "string" ? ex : pyTypeName(ex), pyStr(ex));
1554
- }
1555
- throw new PyError("RuntimeError", "");
1556
- }
1557
- // assert
1558
- const assertMatch = line.match(/^assert\s+(.+?)(?:,\s*(.+))?$/);
1559
- if (assertMatch) {
1560
- if (!pyBool(this.pyEval(assertMatch[1], scope))) {
1561
- throw new PyError("AssertionError", assertMatch[2] ? pyStr(this.pyEval(assertMatch[2], scope)) : "");
1562
- }
1563
- return idx + 1;
1564
- }
1565
- // del
1566
- const delMatch = line.match(/^del\s+(.+)$/);
1567
- if (delMatch) {
1568
- scope.delete(delMatch[1].trim());
1569
- return idx + 1;
1570
- }
1571
- // import / from
1572
- const importMatch = line.match(/^import\s+(\w+)(?:\s+as\s+(\w+))?$/);
1573
- if (importMatch) {
1574
- const [, modName, alias] = importMatch;
1575
- const factory = MODULE_FACTORIES[modName];
1576
- if (factory) {
1577
- const mod = factory(this.cwd);
1578
- this.modules.set(modName, mod);
1579
- scope.set(alias ?? modName, mod);
1580
- }
1581
- return idx + 1;
1582
- }
1583
- const fromMatch = line.match(/^from\s+(\w+)\s+import\s+(.+)$/);
1584
- if (fromMatch) {
1585
- const [, modName, imports] = fromMatch;
1586
- const factory = MODULE_FACTORIES[modName];
1587
- if (factory) {
1588
- const mod = factory(this.cwd);
1589
- if (imports?.trim() === "*") {
1590
- for (const [k, v] of mod.data)
1591
- scope.set(k, v);
1592
- }
1593
- else {
1594
- for (const name of imports.split(",").map((s) => s.trim())) {
1595
- scope.set(name, mod.data.get(name) ?? NONE);
1596
- }
1597
- }
1598
- }
1599
- return idx + 1;
1600
- }
1601
- // def
1602
- const defMatch = line.match(/^def\s+(\w+)\s*\(([^)]*)\)\s*:$/);
1603
- if (defMatch) {
1604
- const [, fnName, paramsStr] = defMatch;
1605
- const params = paramsStr
1606
- .split(",")
1607
- .map((p) => p.trim())
1608
- .filter(Boolean);
1609
- const body = this.collectBlock(lines, idx + 1, indent);
1610
- const fn = {
1611
- __pytype__: "func",
1612
- name: fnName,
1613
- params,
1614
- body,
1615
- closure: new Map(scope),
1616
- };
1617
- scope.set(fnName, fn);
1618
- return idx + 1 + body.length;
1619
- }
1620
- // class
1621
- const classMatch = line.match(/^class\s+(\w+)(?:\(([^)]*)\))?\s*:$/);
1622
- if (classMatch) {
1623
- const [, className, basesStr] = classMatch;
1624
- const bases = basesStr ? basesStr.split(",").map((s) => s.trim()) : [];
1625
- const body = this.collectBlock(lines, idx + 1, indent);
1626
- const cls = {
1627
- __pytype__: "class",
1628
- name: className,
1629
- methods: new Map(),
1630
- bases,
1631
- };
1632
- // Parse method definitions from body
1633
- let j = 0;
1634
- while (j < body.length) {
1635
- const bl = body[j].trim();
1636
- const mMatch = bl.match(/^def\s+(\w+)\s*\(([^)]*)\)\s*:$/);
1637
- if (mMatch) {
1638
- const [, mName, mParams] = mMatch;
1639
- const params = mParams
1640
- .split(",")
1641
- .map((p) => p.trim())
1642
- .filter(Boolean);
1643
- const mBody = this.collectBlock(body, j + 1, 0);
1644
- cls.methods.set(mName, {
1645
- __pytype__: "func",
1646
- name: mName,
1647
- params,
1648
- body: mBody,
1649
- closure: new Map(scope),
1650
- });
1651
- j += 1 + mBody.length;
1652
- }
1653
- else {
1654
- j++;
1655
- }
1656
- }
1657
- scope.set(className, cls);
1658
- return idx + 1 + body.length;
1659
- }
1660
- // if / elif / else
1661
- if (line.startsWith("if ") && line.endsWith(":")) {
1662
- const cond = line.slice(3, -1).trim();
1663
- const body = this.collectBlock(lines, idx + 1, indent);
1664
- const _skip = body.length + 1;
1665
- if (pyBool(this.pyEval(cond, scope))) {
1666
- this.execBlock(body, new Map(scope).also?.((s) => {
1667
- for (const [k, v] of scope)
1668
- s.set(k, v);
1669
- }) ?? scope);
1670
- // Update scope from block (assignments)
1671
- this.runBlockInScope(body, scope);
1672
- // Skip elif/else
1673
- let j = idx + 1 + body.length;
1674
- while (j < lines.length) {
1675
- const l = lines[j].trim();
1676
- if (this.getIndent(lines[j]) < indent ||
1677
- (!l.startsWith("elif") && !l.startsWith("else")))
1678
- break;
1679
- const bk = this.collectBlock(lines, j + 1, indent);
1680
- j += 1 + bk.length;
1681
- }
1682
- return j;
1683
- }
1684
- // Check elif / else
1685
- let j = idx + 1 + body.length;
1686
- while (j < lines.length) {
1687
- const el = lines[j];
1688
- const elt = el.trim();
1689
- if (this.getIndent(el) !== indent)
1690
- break;
1691
- const elifMatch = elt.match(/^elif\s+(.+):$/);
1692
- if (elifMatch) {
1693
- const eBody = this.collectBlock(lines, j + 1, indent);
1694
- if (pyBool(this.pyEval(elifMatch[1], scope))) {
1695
- this.runBlockInScope(eBody, scope);
1696
- j += 1 + eBody.length;
1697
- // Skip remaining elif/else
1698
- while (j < lines.length) {
1699
- const sl = lines[j].trim();
1700
- if (this.getIndent(lines[j]) !== indent ||
1701
- (!sl.startsWith("elif") && !sl.startsWith("else")))
1702
- break;
1703
- const sb = this.collectBlock(lines, j + 1, indent);
1704
- j += 1 + sb.length;
1705
- }
1706
- return j;
1707
- }
1708
- j += 1 + eBody.length;
1709
- continue;
1710
- }
1711
- if (elt === "else:") {
1712
- const eBody = this.collectBlock(lines, j + 1, indent);
1713
- this.runBlockInScope(eBody, scope);
1714
- return j + 1 + eBody.length;
1715
- }
1716
- break;
1717
- }
1718
- return j;
1719
- }
1720
- // for
1721
- const forMatch = line.match(/^for\s+(.+?)\s+in\s+(.+?)\s*:$/);
1722
- if (forMatch) {
1723
- const [, target, iterExpr] = forMatch;
1724
- const iterable = pyIter(this.pyEval(iterExpr.trim(), scope));
1725
- const body = this.collectBlock(lines, idx + 1, indent);
1726
- // Check for else clause
1727
- let elseBody = [];
1728
- let afterIdx = idx + 1 + body.length;
1729
- if (afterIdx < lines.length && lines[afterIdx]?.trim() === "else:") {
1730
- elseBody = this.collectBlock(lines, afterIdx + 1, indent);
1731
- afterIdx += 1 + elseBody.length;
1732
- }
1733
- let broken = false;
1734
- for (const item of iterable) {
1735
- // Unpack
1736
- if (target.includes(",")) {
1737
- const targets = target.split(",").map((t) => t.trim());
1738
- const items = Array.isArray(item) ? item : [item];
1739
- targets.forEach((t, i) => scope.set(t, items[i] ?? NONE));
1740
- }
1741
- else {
1742
- scope.set(target.trim(), item);
1743
- }
1744
- try {
1745
- this.runBlockInScope(body, scope);
1746
- }
1747
- catch (e) {
1748
- if (e instanceof BreakSignal) {
1749
- broken = true;
1750
- break;
1751
- }
1752
- if (e instanceof ContinueSignal)
1753
- continue;
1754
- throw e;
1755
- }
1756
- }
1757
- if (!broken && elseBody.length)
1758
- this.runBlockInScope(elseBody, scope);
1759
- return afterIdx;
1760
- }
1761
- // while
1762
- const whileMatch = line.match(/^while\s+(.+?)\s*:$/);
1763
- if (whileMatch) {
1764
- const cond = whileMatch[1];
1765
- const body = this.collectBlock(lines, idx + 1, indent);
1766
- let iterations = 0;
1767
- while (pyBool(this.pyEval(cond, scope)) && iterations++ < 100000) {
1768
- try {
1769
- this.runBlockInScope(body, scope);
1770
- }
1771
- catch (e) {
1772
- if (e instanceof BreakSignal)
1773
- break;
1774
- if (e instanceof ContinueSignal)
1775
- continue;
1776
- throw e;
1777
- }
1778
- }
1779
- return idx + 1 + body.length;
1780
- }
1781
- // try / except
1782
- if (line === "try:") {
1783
- const tryBody = this.collectBlock(lines, idx + 1, indent);
1784
- let j = idx + 1 + tryBody.length;
1785
- const exceptClauses = [];
1786
- let finallyBody = [];
1787
- let elseBody = [];
1788
- while (j < lines.length) {
1789
- const el = lines[j];
1790
- const elt = el.trim();
1791
- if (this.getIndent(el) !== indent)
1792
- break;
1793
- if (elt.startsWith("except")) {
1794
- const excMatch = elt.match(/^except(?:\s+(\w+)(?:\s+as\s+(\w+))?)?\s*:$/);
1795
- const excName = excMatch?.[1] ?? null;
1796
- const excAlias = excMatch?.[2];
1797
- const excBody = this.collectBlock(lines, j + 1, indent);
1798
- exceptClauses.push({ exc: excName, body: excBody });
1799
- if (excAlias)
1800
- scope.set(excAlias, "");
1801
- j += 1 + excBody.length;
1802
- }
1803
- else if (elt === "else:") {
1804
- elseBody = this.collectBlock(lines, j + 1, indent);
1805
- j += 1 + elseBody.length;
1806
- }
1807
- else if (elt === "finally:") {
1808
- finallyBody = this.collectBlock(lines, j + 1, indent);
1809
- j += 1 + finallyBody.length;
1810
- }
1811
- else
1812
- break;
1813
- }
1814
- let _caughtErr = null;
1815
- try {
1816
- this.runBlockInScope(tryBody, scope);
1817
- if (elseBody.length)
1818
- this.runBlockInScope(elseBody, scope);
1819
- }
1820
- catch (e) {
1821
- if (e instanceof PyError) {
1822
- _caughtErr = e;
1823
- let handled = false;
1824
- for (const clause of exceptClauses) {
1825
- if (clause.exc === null ||
1826
- clause.exc === e.type ||
1827
- clause.exc === "Exception") {
1828
- this.runBlockInScope(clause.body, scope);
1829
- handled = true;
1830
- break;
1831
- }
1832
- }
1833
- if (!handled)
1834
- throw e;
1835
- }
1836
- else
1837
- throw e;
1838
- }
1839
- finally {
1840
- if (finallyBody.length)
1841
- this.runBlockInScope(finallyBody, scope);
1842
- }
1843
- return j;
1844
- }
1845
- // with
1846
- const withMatch = line.match(/^with\s+(.+?)\s+as\s+(\w+)\s*:$/);
1847
- if (withMatch) {
1848
- const body = this.collectBlock(lines, idx + 1, indent);
1849
- scope.set(withMatch[2], NONE); // stub: just set to None
1850
- this.runBlockInScope(body, scope);
1851
- return idx + 1 + body.length;
1852
- }
1853
- // Augmented assignments: +=, -=, *=, /=, //=, %= **=
1854
- const augMatch = line.match(/^([A-Za-z_][A-Za-z0-9_]*)\s*(\+=|-=|\*=|\/\/=|\/=|%=|\*\*=|&=|\|=)\s*(.+)$/);
1855
- if (augMatch) {
1856
- const [, name, op, rhsExpr] = augMatch;
1857
- const lhs = scope.get(name) ?? 0;
1858
- const rhs = this.pyEval(rhsExpr, scope);
1859
- let result;
1860
- switch (op) {
1861
- case "+=":
1862
- result =
1863
- typeof lhs === "string"
1864
- ? lhs + pyStr(rhs)
1865
- : lhs + rhs;
1866
- break;
1867
- case "-=":
1868
- result = lhs - rhs;
1869
- break;
1870
- case "*=":
1871
- result = lhs * rhs;
1872
- break;
1873
- case "/=":
1874
- result = lhs / rhs;
1875
- break;
1876
- case "//=":
1877
- result = Math.floor(lhs / rhs);
1878
- break;
1879
- case "%=":
1880
- result = lhs % rhs;
1881
- break;
1882
- case "**=":
1883
- result = lhs ** rhs;
1884
- break;
1885
- default:
1886
- result = rhs;
1887
- }
1888
- scope.set(name, result);
1889
- return idx + 1;
1890
- }
1891
- // Subscript assignment: obj[key] = val
1892
- const subAssignMatch = line.match(/^([A-Za-z_][A-Za-z0-9_]*)\[(.+)\]\s*=\s*(.+)$/);
1893
- if (subAssignMatch) {
1894
- const [, name, key, valExpr] = subAssignMatch;
1895
- const obj = scope.get(name) ?? NONE;
1896
- const val = this.pyEval(valExpr, scope) ?? NONE;
1897
- const k = this.pyEval(key, scope) ?? NONE;
1898
- if (Array.isArray(obj))
1899
- obj[k] = val;
1900
- else if (isPyDict(obj))
1901
- obj.data.set(pyStr(k), val);
1902
- return idx + 1;
1903
- }
1904
- // Attribute assignment: obj.attr = val
1905
- const attrAssignMatch = line.match(/^([A-Za-z_][A-Za-z0-9_.]+)\s*=\s*(.+)$/);
1906
- if (attrAssignMatch) {
1907
- const dotIdx = attrAssignMatch[1].lastIndexOf(".");
1908
- if (dotIdx !== -1) {
1909
- const objExpr = attrAssignMatch[1].slice(0, dotIdx);
1910
- const attr = attrAssignMatch[1].slice(dotIdx + 1);
1911
- const val = this.pyEval(attrAssignMatch[2], scope);
1912
- const obj = this.pyEval(objExpr, scope);
1913
- if (isPyDict(obj))
1914
- obj.data.set(attr, val);
1915
- else if (isPyInstance(obj))
1916
- obj.attrs.set(attr, val);
1917
- return idx + 1;
1918
- }
1919
- }
1920
- // Tuple / multi-assignment: a, b = expr
1921
- const multiAssignMatch = line.match(/^([A-Za-z_][A-Za-z0-9_,\s]*),\s*([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(.+)$/);
1922
- if (multiAssignMatch) {
1923
- const rhs = this.pyEval(multiAssignMatch[3], scope);
1924
- const targets = line
1925
- .split("=")[0]
1926
- .split(",")
1927
- .map((s) => s.trim());
1928
- const values = pyIter(rhs);
1929
- targets.forEach((t, i) => scope.set(t, values[i] ?? NONE));
1930
- return idx + 1;
1931
- }
1932
- // Simple assignment: name = expr (or name: type = expr)
1933
- const assignMatch = line.match(/^([A-Za-z_][A-Za-z0-9_]*)\s*(?::[^=]+)?\s*=\s*(.+)$/);
1934
- if (assignMatch) {
1935
- const [, name, rhs] = assignMatch;
1936
- scope.set(name, this.pyEval(rhs, scope));
1937
- return idx + 1;
1938
- }
1939
- // Expression statement (function call, etc.)
1940
- try {
1941
- this.pyEval(line, scope);
1942
- }
1943
- catch (e) {
1944
- if (e instanceof PyError || e instanceof ExitSignal)
1945
- throw e;
1946
- // Ignore eval errors for expression statements
1947
- }
1948
- return idx + 1;
1949
- }
1950
- runBlockInScope(body, scope) {
1951
- this.execLines(body, 0, scope);
1952
- }
1953
- run(code) {
1954
- const scope = makeRootScope(this.cwd);
1955
- try {
1956
- this.execScript(code, scope);
1957
- }
1958
- catch (e) {
1959
- if (e instanceof ExitSignal)
1960
- return {
1961
- stdout: this.getOutput(),
1962
- stderr: this.getStderr(),
1963
- exitCode: e.code,
1964
- };
1965
- if (e instanceof PyError) {
1966
- this.stderr.push(e.toString());
1967
- return {
1968
- stdout: this.getOutput(),
1969
- stderr: this.getStderr(),
1970
- exitCode: 1,
1971
- };
1972
- }
1973
- if (e instanceof ReturnSignal)
1974
- return {
1975
- stdout: this.getOutput(),
1976
- stderr: this.getStderr(),
1977
- exitCode: 0,
1978
- };
1979
- this.stderr.push(`RuntimeError: ${e}`);
1980
- return {
1981
- stdout: this.getOutput(),
1982
- stderr: this.getStderr(),
1983
- exitCode: 1,
1984
- };
1985
- }
1986
- return { stdout: this.getOutput(), stderr: this.getStderr(), exitCode: 0 };
1987
- }
1988
- }
1989
- // ─── command ──────────────────────────────────────────────────────────────────
1990
- /**
1991
- * Virtual Python 3 interpreter command. Implements a small Python subset
1992
- * for scripts and `-c` invocations. Requires `apt install python3` in the
1993
- * virtual package manager to be available.
1994
- * @category system
1995
- * @params ["[--version] [-c <code>] [-V] [file]"]
1996
- */
1997
- export const python3Command = {
1998
- name: "python3",
1999
- aliases: ["python"],
2000
- description: "Python 3 interpreter (virtual)",
2001
- category: "system",
2002
- params: ["[--version] [-c <code>] [-V] [file]"],
2003
- run: ({ args, shell, cwd }) => {
2004
- // Require explicit installation via `apt install python3`
2005
- if (!shell.packageManager.isInstalled("python3")) {
2006
- return {
2007
- stderr: "bash: python3: command not found\nHint: install it with: apt install python3\n",
2008
- exitCode: 127,
2009
- };
2010
- }
2011
- if (ifFlag(args, ["--version", "-V"])) {
2012
- return { stdout: `${VERSION}\n`, exitCode: 0 };
2013
- }
2014
- if (ifFlag(args, ["--version-full"])) {
2015
- return { stdout: `${VERSION_INFO}\n`, exitCode: 0 };
2016
- }
2017
- const cIdx = args.indexOf("-c");
2018
- if (cIdx !== -1) {
2019
- const code = args[cIdx + 1];
2020
- if (!code)
2021
- return {
2022
- stderr: "python3: -c requires a code argument\n",
2023
- exitCode: 1,
2024
- };
2025
- // Handle \n as actual newlines
2026
- const normalised = code.replace(/\\n/g, "\n").replace(/\\t/g, "\t");
2027
- const interp = new Interpreter(cwd);
2028
- const { stdout, stderr, exitCode } = interp.run(normalised);
2029
- return {
2030
- stdout: stdout || undefined,
2031
- stderr: stderr || undefined,
2032
- exitCode,
2033
- };
2034
- }
2035
- const file = args.find((a) => !a.startsWith("-"));
2036
- if (file) {
2037
- const filePath = resolvePath(cwd, file);
2038
- if (!shell.vfs.exists(filePath)) {
2039
- return {
2040
- stderr: `python3: can't open file '${file}': [Errno 2] No such file or directory\n`,
2041
- exitCode: 2,
2042
- };
2043
- }
2044
- const code = shell.vfs.readFile(filePath);
2045
- const interp = new Interpreter(cwd);
2046
- const { stdout, stderr, exitCode } = interp.run(code);
2047
- return {
2048
- stdout: stdout || undefined,
2049
- stderr: stderr || undefined,
2050
- exitCode,
2051
- };
2052
- }
2053
- return {
2054
- stdout: `${VERSION_INFO}\nType "help", "copyright", "credits" or "license" for more information.\n>>> `,
2055
- exitCode: 0,
2056
- };
2057
- },
2058
- };