dotdo 0.0.1 → 0.0.2

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 (727) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +446 -315
  3. package/dist/ai/index.js +19 -0
  4. package/dist/ai/index.js.map +1 -0
  5. package/dist/ai/template-literals.js +852 -0
  6. package/dist/ai/template-literals.js.map +1 -0
  7. package/dist/api/analytics/router.js +601 -0
  8. package/dist/api/analytics/router.js.map +1 -0
  9. package/dist/api/index.js +158 -0
  10. package/dist/api/index.js.map +1 -0
  11. package/dist/api/middleware/auth-federation.js +573 -0
  12. package/dist/api/middleware/auth-federation.js.map +1 -0
  13. package/dist/api/middleware/auth.js +544 -0
  14. package/dist/api/middleware/auth.js.map +1 -0
  15. package/dist/api/middleware/error-handling.js +176 -0
  16. package/dist/api/middleware/error-handling.js.map +1 -0
  17. package/dist/api/middleware/request-id.js +21 -0
  18. package/dist/api/middleware/request-id.js.map +1 -0
  19. package/dist/api/pages.js +1180 -0
  20. package/dist/api/pages.js.map +1 -0
  21. package/dist/api/routes/api.js +612 -0
  22. package/dist/api/routes/api.js.map +1 -0
  23. package/dist/api/routes/browsers.js +471 -0
  24. package/dist/api/routes/browsers.js.map +1 -0
  25. package/dist/api/routes/do.js +188 -0
  26. package/dist/api/routes/do.js.map +1 -0
  27. package/dist/api/routes/mcp.js +459 -0
  28. package/dist/api/routes/mcp.js.map +1 -0
  29. package/dist/api/routes/obs.js +445 -0
  30. package/dist/api/routes/obs.js.map +1 -0
  31. package/dist/api/routes/openapi.js +794 -0
  32. package/dist/api/routes/openapi.js.map +1 -0
  33. package/dist/api/routes/rpc.js +1103 -0
  34. package/dist/api/routes/rpc.js.map +1 -0
  35. package/dist/api/routes/sandboxes.js +389 -0
  36. package/dist/api/routes/sandboxes.js.map +1 -0
  37. package/dist/api/test-do.js +38 -0
  38. package/dist/api/test-do.js.map +1 -0
  39. package/dist/api/types.js +11 -0
  40. package/dist/api/types.js.map +1 -0
  41. package/dist/cli/bin.js +2 -0
  42. package/dist/cli/main.js +52342 -0
  43. package/dist/db/actions.js +212 -0
  44. package/dist/db/actions.js.map +1 -0
  45. package/dist/db/auth.js +506 -0
  46. package/dist/db/auth.js.map +1 -0
  47. package/dist/db/branches.js +65 -0
  48. package/dist/db/branches.js.map +1 -0
  49. package/dist/db/clickhouse.js +1074 -0
  50. package/dist/db/clickhouse.js.map +1 -0
  51. package/dist/db/dlq.js +39 -0
  52. package/dist/db/dlq.js.map +1 -0
  53. package/dist/db/events.js +28 -0
  54. package/dist/db/events.js.map +1 -0
  55. package/dist/db/exec.js +64 -0
  56. package/dist/db/exec.js.map +1 -0
  57. package/dist/db/files.js +85 -0
  58. package/dist/db/files.js.map +1 -0
  59. package/dist/db/flags.js +24 -0
  60. package/dist/db/flags.js.map +1 -0
  61. package/dist/db/git.js +116 -0
  62. package/dist/db/git.js.map +1 -0
  63. package/dist/db/iceberg/inverted-index.js +862 -0
  64. package/dist/db/iceberg/inverted-index.js.map +1 -0
  65. package/dist/db/iceberg/puffin.js +878 -0
  66. package/dist/db/iceberg/puffin.js.map +1 -0
  67. package/dist/db/iceberg/search-manifest.js +422 -0
  68. package/dist/db/iceberg/search-manifest.js.map +1 -0
  69. package/dist/db/iceberg/types.js +8 -0
  70. package/dist/db/iceberg/types.js.map +1 -0
  71. package/dist/db/index.js +121 -0
  72. package/dist/db/index.js.map +1 -0
  73. package/dist/db/integrations.js +368 -0
  74. package/dist/db/integrations.js.map +1 -0
  75. package/dist/db/json-indexes.js +332 -0
  76. package/dist/db/json-indexes.js.map +1 -0
  77. package/dist/db/linked-accounts.js +287 -0
  78. package/dist/db/linked-accounts.js.map +1 -0
  79. package/dist/db/nouns.js +183 -0
  80. package/dist/db/nouns.js.map +1 -0
  81. package/dist/db/objects.js +170 -0
  82. package/dist/db/objects.js.map +1 -0
  83. package/dist/db/primitives/dag-scheduler/index.js +869 -0
  84. package/dist/db/primitives/dag-scheduler/index.js.map +1 -0
  85. package/dist/db/primitives/exactly-once-context.js +237 -0
  86. package/dist/db/primitives/exactly-once-context.js.map +1 -0
  87. package/dist/db/primitives/index.js +62 -0
  88. package/dist/db/primitives/index.js.map +1 -0
  89. package/dist/db/primitives/keyed-router.js +145 -0
  90. package/dist/db/primitives/keyed-router.js.map +1 -0
  91. package/dist/db/primitives/observability.js +162 -0
  92. package/dist/db/primitives/observability.js.map +1 -0
  93. package/dist/db/primitives/schema-evolution.js +643 -0
  94. package/dist/db/primitives/schema-evolution.js.map +1 -0
  95. package/dist/db/primitives/stateful-operator/index.js +770 -0
  96. package/dist/db/primitives/stateful-operator/index.js.map +1 -0
  97. package/dist/db/primitives/temporal-store.js +306 -0
  98. package/dist/db/primitives/temporal-store.js.map +1 -0
  99. package/dist/db/primitives/typed-column-store.js +1229 -0
  100. package/dist/db/primitives/typed-column-store.js.map +1 -0
  101. package/dist/db/primitives/utils/duration.js +162 -0
  102. package/dist/db/primitives/utils/duration.js.map +1 -0
  103. package/dist/db/primitives/utils/murmur3.js +118 -0
  104. package/dist/db/primitives/utils/murmur3.js.map +1 -0
  105. package/dist/db/primitives/watermark-service.js +136 -0
  106. package/dist/db/primitives/watermark-service.js.map +1 -0
  107. package/dist/db/primitives/window-manager.js +764 -0
  108. package/dist/db/primitives/window-manager.js.map +1 -0
  109. package/dist/db/relationships.js +66 -0
  110. package/dist/db/relationships.js.map +1 -0
  111. package/dist/db/schema-minimal.js +61 -0
  112. package/dist/db/schema-minimal.js.map +1 -0
  113. package/dist/db/search.js +28 -0
  114. package/dist/db/search.js.map +1 -0
  115. package/dist/db/stores.js +1665 -0
  116. package/dist/db/stores.js.map +1 -0
  117. package/dist/db/things.js +297 -0
  118. package/dist/db/things.js.map +1 -0
  119. package/dist/db/vault.js +171 -0
  120. package/dist/db/vault.js.map +1 -0
  121. package/dist/db/verbs.js +102 -0
  122. package/dist/db/verbs.js.map +1 -0
  123. package/dist/do/base.js +48 -0
  124. package/dist/do/base.js.map +1 -0
  125. package/dist/do/bash.js +35 -0
  126. package/dist/do/bash.js.map +1 -0
  127. package/dist/do/fs.js +25 -0
  128. package/dist/do/fs.js.map +1 -0
  129. package/dist/do/full.js +61 -0
  130. package/dist/do/full.js.map +1 -0
  131. package/dist/do/git.js +28 -0
  132. package/dist/do/git.js.map +1 -0
  133. package/dist/do/index.js +52 -0
  134. package/dist/do/index.js.map +1 -0
  135. package/dist/do/tiny.js +31 -0
  136. package/dist/do/tiny.js.map +1 -0
  137. package/dist/lib/DOAuth.js +261 -0
  138. package/dist/lib/DOAuth.js.map +1 -0
  139. package/dist/lib/DODispatcher.js +72 -0
  140. package/dist/lib/DODispatcher.js.map +1 -0
  141. package/dist/lib/Modifier.js +189 -0
  142. package/dist/lib/Modifier.js.map +1 -0
  143. package/dist/lib/StateStorage.js +403 -0
  144. package/dist/lib/StateStorage.js.map +1 -0
  145. package/dist/lib/TypeRegistry.js +122 -0
  146. package/dist/lib/TypeRegistry.js.map +1 -0
  147. package/dist/lib/agent/tools/bash.js +336 -0
  148. package/dist/lib/agent/tools/bash.js.map +1 -0
  149. package/dist/lib/agent/tools/edit.js +157 -0
  150. package/dist/lib/agent/tools/edit.js.map +1 -0
  151. package/dist/lib/agent/tools/glob.js +137 -0
  152. package/dist/lib/agent/tools/glob.js.map +1 -0
  153. package/dist/lib/agent/tools/grep.js +315 -0
  154. package/dist/lib/agent/tools/grep.js.map +1 -0
  155. package/dist/lib/agent/tools/index.js +71 -0
  156. package/dist/lib/agent/tools/index.js.map +1 -0
  157. package/dist/lib/agent/tools/read.js +212 -0
  158. package/dist/lib/agent/tools/read.js.map +1 -0
  159. package/dist/lib/agent/tools/types.js +197 -0
  160. package/dist/lib/agent/tools/types.js.map +1 -0
  161. package/dist/lib/agent/tools/write.js +159 -0
  162. package/dist/lib/agent/tools/write.js.map +1 -0
  163. package/dist/lib/ai/gateway.js +247 -0
  164. package/dist/lib/ai/gateway.js.map +1 -0
  165. package/dist/lib/ai/tool-loop-agent.js +591 -0
  166. package/dist/lib/ai/tool-loop-agent.js.map +1 -0
  167. package/dist/lib/auto-wiring.js +439 -0
  168. package/dist/lib/auto-wiring.js.map +1 -0
  169. package/dist/lib/browse/browserbase.js +163 -0
  170. package/dist/lib/browse/browserbase.js.map +1 -0
  171. package/dist/lib/browse/cloudflare.js +144 -0
  172. package/dist/lib/browse/cloudflare.js.map +1 -0
  173. package/dist/lib/browse/index.js +62 -0
  174. package/dist/lib/browse/index.js.map +1 -0
  175. package/dist/lib/browse/types.js +13 -0
  176. package/dist/lib/browse/types.js.map +1 -0
  177. package/dist/lib/cache/index.js +37 -0
  178. package/dist/lib/cache/index.js.map +1 -0
  179. package/dist/lib/cache/visibility.js +638 -0
  180. package/dist/lib/cache/visibility.js.map +1 -0
  181. package/dist/lib/capabilities.js +268 -0
  182. package/dist/lib/capabilities.js.map +1 -0
  183. package/dist/lib/channels/base.js +106 -0
  184. package/dist/lib/channels/base.js.map +1 -0
  185. package/dist/lib/channels/discord.js +94 -0
  186. package/dist/lib/channels/discord.js.map +1 -0
  187. package/dist/lib/channels/email.js +204 -0
  188. package/dist/lib/channels/email.js.map +1 -0
  189. package/dist/lib/channels/index.js +90 -0
  190. package/dist/lib/channels/index.js.map +1 -0
  191. package/dist/lib/channels/mdxui-chat.js +95 -0
  192. package/dist/lib/channels/mdxui-chat.js.map +1 -0
  193. package/dist/lib/channels/slack-blockkit.js +121 -0
  194. package/dist/lib/channels/slack-blockkit.js.map +1 -0
  195. package/dist/lib/channels/types.js +7 -0
  196. package/dist/lib/channels/types.js.map +1 -0
  197. package/dist/lib/cloudflare/ai.js +654 -0
  198. package/dist/lib/cloudflare/ai.js.map +1 -0
  199. package/dist/lib/cloudflare/index.js +88 -0
  200. package/dist/lib/cloudflare/index.js.map +1 -0
  201. package/dist/lib/cloudflare/kv.js +342 -0
  202. package/dist/lib/cloudflare/kv.js.map +1 -0
  203. package/dist/lib/cloudflare/queues.js +434 -0
  204. package/dist/lib/cloudflare/queues.js.map +1 -0
  205. package/dist/lib/cloudflare/r2.js +604 -0
  206. package/dist/lib/cloudflare/r2.js.map +1 -0
  207. package/dist/lib/cloudflare/vectorize.js +494 -0
  208. package/dist/lib/cloudflare/vectorize.js.map +1 -0
  209. package/dist/lib/cloudflare/workflows.js +569 -0
  210. package/dist/lib/cloudflare/workflows.js.map +1 -0
  211. package/dist/lib/colo/caching.js +196 -0
  212. package/dist/lib/colo/caching.js.map +1 -0
  213. package/dist/lib/colo/detection.js +194 -0
  214. package/dist/lib/colo/detection.js.map +1 -0
  215. package/dist/lib/colo/external-data.js +219 -0
  216. package/dist/lib/colo/external-data.js.map +1 -0
  217. package/dist/lib/colo/globe-data.js +179 -0
  218. package/dist/lib/colo/globe-data.js.map +1 -0
  219. package/dist/lib/colo/index.js +16 -0
  220. package/dist/lib/colo/index.js.map +1 -0
  221. package/dist/lib/decorators.js +37 -0
  222. package/dist/lib/decorators.js.map +1 -0
  223. package/dist/lib/discovery.js +81 -0
  224. package/dist/lib/discovery.js.map +1 -0
  225. package/dist/lib/executors/AgenticFunctionExecutor.js +619 -0
  226. package/dist/lib/executors/AgenticFunctionExecutor.js.map +1 -0
  227. package/dist/lib/executors/BaseFunctionExecutor.js +328 -0
  228. package/dist/lib/executors/BaseFunctionExecutor.js.map +1 -0
  229. package/dist/lib/executors/CascadeExecutor.js +418 -0
  230. package/dist/lib/executors/CascadeExecutor.js.map +1 -0
  231. package/dist/lib/executors/CodeFunctionExecutor.js +904 -0
  232. package/dist/lib/executors/CodeFunctionExecutor.js.map +1 -0
  233. package/dist/lib/executors/GenerativeFunctionExecutor.js +904 -0
  234. package/dist/lib/executors/GenerativeFunctionExecutor.js.map +1 -0
  235. package/dist/lib/executors/HumanFunctionExecutor.js +884 -0
  236. package/dist/lib/executors/HumanFunctionExecutor.js.map +1 -0
  237. package/dist/lib/executors/ParallelStepExecutor.js +308 -0
  238. package/dist/lib/executors/ParallelStepExecutor.js.map +1 -0
  239. package/dist/lib/executors/types.js +12 -0
  240. package/dist/lib/executors/types.js.map +1 -0
  241. package/dist/lib/experiments.js +89 -0
  242. package/dist/lib/experiments.js.map +1 -0
  243. package/dist/lib/flags/store.js +262 -0
  244. package/dist/lib/flags/store.js.map +1 -0
  245. package/dist/lib/functions/FunctionComposition.js +467 -0
  246. package/dist/lib/functions/FunctionComposition.js.map +1 -0
  247. package/dist/lib/functions/FunctionMiddleware.js +457 -0
  248. package/dist/lib/functions/FunctionMiddleware.js.map +1 -0
  249. package/dist/lib/functions/FunctionRegistry.js +426 -0
  250. package/dist/lib/functions/FunctionRegistry.js.map +1 -0
  251. package/dist/lib/functions/createFunction.js +1048 -0
  252. package/dist/lib/functions/createFunction.js.map +1 -0
  253. package/dist/lib/humans/index.js +68 -0
  254. package/dist/lib/humans/index.js.map +1 -0
  255. package/dist/lib/humans/templates.js +117 -0
  256. package/dist/lib/humans/templates.js.map +1 -0
  257. package/dist/lib/identity.js +98 -0
  258. package/dist/lib/identity.js.map +1 -0
  259. package/dist/lib/index.js +9 -0
  260. package/dist/lib/index.js.map +1 -0
  261. package/dist/lib/logging/error-logger.js +163 -0
  262. package/dist/lib/logging/error-logger.js.map +1 -0
  263. package/dist/lib/logging/index.js +160 -0
  264. package/dist/lib/logging/index.js.map +1 -0
  265. package/dist/lib/mixins/bash.js +825 -0
  266. package/dist/lib/mixins/bash.js.map +1 -0
  267. package/dist/lib/mixins/fs.js +648 -0
  268. package/dist/lib/mixins/fs.js.map +1 -0
  269. package/dist/lib/mixins/git.js +1011 -0
  270. package/dist/lib/mixins/git.js.map +1 -0
  271. package/dist/lib/mixins/index.js +29 -0
  272. package/dist/lib/mixins/index.js.map +1 -0
  273. package/dist/lib/mixins/npm.js +662 -0
  274. package/dist/lib/mixins/npm.js.map +1 -0
  275. package/dist/lib/noun-id.js +278 -0
  276. package/dist/lib/noun-id.js.map +1 -0
  277. package/dist/lib/rate-limit/sliding-window.js +148 -0
  278. package/dist/lib/rate-limit/sliding-window.js.map +1 -0
  279. package/dist/lib/rate-limit.js +110 -0
  280. package/dist/lib/rate-limit.js.map +1 -0
  281. package/dist/lib/rpc/bindings.js +548 -0
  282. package/dist/lib/rpc/bindings.js.map +1 -0
  283. package/dist/lib/rpc/index.js +64 -0
  284. package/dist/lib/rpc/index.js.map +1 -0
  285. package/dist/lib/safe-stringify.js +223 -0
  286. package/dist/lib/safe-stringify.js.map +1 -0
  287. package/dist/lib/sandbox/miniflare-sandbox.js +1007 -0
  288. package/dist/lib/sandbox/miniflare-sandbox.js.map +1 -0
  289. package/dist/lib/sqids.js +110 -0
  290. package/dist/lib/sqids.js.map +1 -0
  291. package/dist/lib/sql/adapters/index.js +10 -0
  292. package/dist/lib/sql/adapters/index.js.map +1 -0
  293. package/dist/lib/sql/adapters/node-sql-parser.js +552 -0
  294. package/dist/lib/sql/adapters/node-sql-parser.js.map +1 -0
  295. package/dist/lib/sql/adapters/pgsql-parser.js +1189 -0
  296. package/dist/lib/sql/adapters/pgsql-parser.js.map +1 -0
  297. package/dist/lib/sql/index.js +277 -0
  298. package/dist/lib/sql/index.js.map +1 -0
  299. package/dist/lib/sql/types.js +56 -0
  300. package/dist/lib/sql/types.js.map +1 -0
  301. package/dist/lib/type-classifier.js +126 -0
  302. package/dist/lib/type-classifier.js.map +1 -0
  303. package/dist/lib/utils/html.js +47 -0
  304. package/dist/lib/utils/html.js.map +1 -0
  305. package/dist/lib/validation.js +48 -0
  306. package/dist/lib/validation.js.map +1 -0
  307. package/dist/lib/vault/store.js +411 -0
  308. package/dist/lib/vault/store.js.map +1 -0
  309. package/dist/metrics/hunch.js +739 -0
  310. package/dist/metrics/hunch.js.map +1 -0
  311. package/dist/objects/API.js +302 -0
  312. package/dist/objects/API.js.map +1 -0
  313. package/dist/objects/Agent.js +179 -0
  314. package/dist/objects/Agent.js.map +1 -0
  315. package/dist/objects/AgenticFunctionExecutor.js +8 -0
  316. package/dist/objects/AgenticFunctionExecutor.js.map +1 -0
  317. package/dist/objects/App.js +83 -0
  318. package/dist/objects/App.js.map +1 -0
  319. package/dist/objects/Browser.js +884 -0
  320. package/dist/objects/Browser.js.map +1 -0
  321. package/dist/objects/Business.js +107 -0
  322. package/dist/objects/Business.js.map +1 -0
  323. package/dist/objects/CLI.js +221 -0
  324. package/dist/objects/CLI.js.map +1 -0
  325. package/dist/objects/CodeFunctionExecutor.js +8 -0
  326. package/dist/objects/CodeFunctionExecutor.js.map +1 -0
  327. package/dist/objects/Collection.js +161 -0
  328. package/dist/objects/Collection.js.map +1 -0
  329. package/dist/objects/DO.js +41 -0
  330. package/dist/objects/DO.js.map +1 -0
  331. package/dist/objects/DOBase.js +2309 -0
  332. package/dist/objects/DOBase.js.map +1 -0
  333. package/dist/objects/DOFull.js +1676 -0
  334. package/dist/objects/DOFull.js.map +1 -0
  335. package/dist/objects/DOTiny.js +207 -0
  336. package/dist/objects/DOTiny.js.map +1 -0
  337. package/dist/objects/Directory.js +199 -0
  338. package/dist/objects/Directory.js.map +1 -0
  339. package/dist/objects/Entity.js +413 -0
  340. package/dist/objects/Entity.js.map +1 -0
  341. package/dist/objects/Function.js +116 -0
  342. package/dist/objects/Function.js.map +1 -0
  343. package/dist/objects/Human.js +231 -0
  344. package/dist/objects/Human.js.map +1 -0
  345. package/dist/objects/HumanFunctionExecutor.js +8 -0
  346. package/dist/objects/HumanFunctionExecutor.js.map +1 -0
  347. package/dist/objects/IcebergMetadataDO.js +938 -0
  348. package/dist/objects/IcebergMetadataDO.js.map +1 -0
  349. package/dist/objects/IntegrationsDO.js +1174 -0
  350. package/dist/objects/IntegrationsDO.js.map +1 -0
  351. package/dist/objects/ObservabilityBroadcaster.js +149 -0
  352. package/dist/objects/ObservabilityBroadcaster.js.map +1 -0
  353. package/dist/objects/Package.js +154 -0
  354. package/dist/objects/Package.js.map +1 -0
  355. package/dist/objects/Product.js +193 -0
  356. package/dist/objects/Product.js.map +1 -0
  357. package/dist/objects/SDK.js +152 -0
  358. package/dist/objects/SDK.js.map +1 -0
  359. package/dist/objects/SaaS.js +235 -0
  360. package/dist/objects/SaaS.js.map +1 -0
  361. package/dist/objects/SandboxDO.js +759 -0
  362. package/dist/objects/SandboxDO.js.map +1 -0
  363. package/dist/objects/Service.js +337 -0
  364. package/dist/objects/Service.js.map +1 -0
  365. package/dist/objects/Site.js +80 -0
  366. package/dist/objects/Site.js.map +1 -0
  367. package/dist/objects/Startup.js +479 -0
  368. package/dist/objects/Startup.js.map +1 -0
  369. package/dist/objects/ThingsDO.js +170 -0
  370. package/dist/objects/ThingsDO.js.map +1 -0
  371. package/dist/objects/VectorShardDO.js +648 -0
  372. package/dist/objects/VectorShardDO.js.map +1 -0
  373. package/dist/objects/Worker.js +144 -0
  374. package/dist/objects/Worker.js.map +1 -0
  375. package/dist/objects/Workflow.js +196 -0
  376. package/dist/objects/Workflow.js.map +1 -0
  377. package/dist/objects/WorkflowFactory.js +313 -0
  378. package/dist/objects/WorkflowFactory.js.map +1 -0
  379. package/dist/objects/WorkflowRuntime.js +863 -0
  380. package/dist/objects/WorkflowRuntime.js.map +1 -0
  381. package/dist/objects/circuit-breaker-bulkhead.js +178 -0
  382. package/dist/objects/circuit-breaker-bulkhead.js.map +1 -0
  383. package/dist/objects/createFunction.js +934 -0
  384. package/dist/objects/createFunction.js.map +1 -0
  385. package/dist/objects/index.js +80 -0
  386. package/dist/objects/index.js.map +1 -0
  387. package/dist/objects/lifecycle/Branch.js +275 -0
  388. package/dist/objects/lifecycle/Branch.js.map +1 -0
  389. package/dist/objects/lifecycle/Clone.js +1499 -0
  390. package/dist/objects/lifecycle/Clone.js.map +1 -0
  391. package/dist/objects/lifecycle/Compact.js +237 -0
  392. package/dist/objects/lifecycle/Compact.js.map +1 -0
  393. package/dist/objects/lifecycle/Promote.js +476 -0
  394. package/dist/objects/lifecycle/Promote.js.map +1 -0
  395. package/dist/objects/lifecycle/Shard.js +560 -0
  396. package/dist/objects/lifecycle/Shard.js.map +1 -0
  397. package/dist/objects/lifecycle/index.js +15 -0
  398. package/dist/objects/lifecycle/index.js.map +1 -0
  399. package/dist/objects/lifecycle/types.js +33 -0
  400. package/dist/objects/lifecycle/types.js.map +1 -0
  401. package/dist/objects/mixins/infrastructure.js +171 -0
  402. package/dist/objects/mixins/infrastructure.js.map +1 -0
  403. package/dist/objects/modules/StoresModule.js +153 -0
  404. package/dist/objects/modules/StoresModule.js.map +1 -0
  405. package/dist/objects/persistence/checkpoint-manager.js +606 -0
  406. package/dist/objects/persistence/checkpoint-manager.js.map +1 -0
  407. package/dist/objects/persistence/index.js +72 -0
  408. package/dist/objects/persistence/index.js.map +1 -0
  409. package/dist/objects/persistence/migration-runner.js +562 -0
  410. package/dist/objects/persistence/migration-runner.js.map +1 -0
  411. package/dist/objects/persistence/replication-manager.js +501 -0
  412. package/dist/objects/persistence/replication-manager.js.map +1 -0
  413. package/dist/objects/persistence/tiered-storage-manager.js +595 -0
  414. package/dist/objects/persistence/tiered-storage-manager.js.map +1 -0
  415. package/dist/objects/persistence/types.js +14 -0
  416. package/dist/objects/persistence/types.js.map +1 -0
  417. package/dist/objects/persistence/wal-manager.js +653 -0
  418. package/dist/objects/persistence/wal-manager.js.map +1 -0
  419. package/dist/objects/presets/index.js +20 -0
  420. package/dist/objects/presets/index.js.map +1 -0
  421. package/dist/objects/presets/primitives.js +188 -0
  422. package/dist/objects/presets/primitives.js.map +1 -0
  423. package/dist/objects/primitives/alarm-adapter.js +141 -0
  424. package/dist/objects/primitives/alarm-adapter.js.map +1 -0
  425. package/dist/objects/primitives/index.js +337 -0
  426. package/dist/objects/primitives/index.js.map +1 -0
  427. package/dist/objects/primitives/storage-adapter.js +182 -0
  428. package/dist/objects/primitives/storage-adapter.js.map +1 -0
  429. package/dist/objects/primitives/with-primitives.js +102 -0
  430. package/dist/objects/primitives/with-primitives.js.map +1 -0
  431. package/dist/objects/services/StoreManager.js +227 -0
  432. package/dist/objects/services/StoreManager.js.map +1 -0
  433. package/dist/objects/services/index.js +13 -0
  434. package/dist/objects/services/index.js.map +1 -0
  435. package/dist/objects/transport/auth-layer.js +1451 -0
  436. package/dist/objects/transport/auth-layer.js.map +1 -0
  437. package/dist/objects/transport/capnweb-target.js +355 -0
  438. package/dist/objects/transport/capnweb-target.js.map +1 -0
  439. package/dist/objects/transport/chain.js +441 -0
  440. package/dist/objects/transport/chain.js.map +1 -0
  441. package/dist/objects/transport/handler.js +58 -0
  442. package/dist/objects/transport/handler.js.map +1 -0
  443. package/dist/objects/transport/index.js +53 -0
  444. package/dist/objects/transport/index.js.map +1 -0
  445. package/dist/objects/transport/mcp-server.js +690 -0
  446. package/dist/objects/transport/mcp-server.js.map +1 -0
  447. package/dist/objects/transport/rest-autowire.js +1507 -0
  448. package/dist/objects/transport/rest-autowire.js.map +1 -0
  449. package/dist/objects/transport/rest-router.js +440 -0
  450. package/dist/objects/transport/rest-router.js.map +1 -0
  451. package/dist/objects/transport/rpc-server.js +1536 -0
  452. package/dist/objects/transport/rpc-server.js.map +1 -0
  453. package/dist/objects/transport/shared.js +575 -0
  454. package/dist/objects/transport/shared.js.map +1 -0
  455. package/dist/objects/transport/sync-engine.js +291 -0
  456. package/dist/objects/transport/sync-engine.js.map +1 -0
  457. package/dist/objects/transport/types.js +8 -0
  458. package/dist/objects/transport/types.js.map +1 -0
  459. package/dist/primitives/bashx/src/ast/analyze.js +1472 -0
  460. package/dist/primitives/bashx/src/ast/analyze.js.map +1 -0
  461. package/dist/primitives/bashx/src/ast/parser.js +1488 -0
  462. package/dist/primitives/bashx/src/ast/parser.js.map +1 -0
  463. package/dist/primitives/bashx/src/do/commands/crypto.js +1954 -0
  464. package/dist/primitives/bashx/src/do/commands/crypto.js.map +1 -0
  465. package/dist/primitives/bashx/src/do/commands/data-processing.js +1812 -0
  466. package/dist/primitives/bashx/src/do/commands/data-processing.js.map +1 -0
  467. package/dist/primitives/bashx/src/do/commands/extended-utils.js +804 -0
  468. package/dist/primitives/bashx/src/do/commands/extended-utils.js.map +1 -0
  469. package/dist/primitives/bashx/src/do/commands/math-control.js +1122 -0
  470. package/dist/primitives/bashx/src/do/commands/math-control.js.map +1 -0
  471. package/dist/primitives/bashx/src/do/commands/posix-utils.js +1015 -0
  472. package/dist/primitives/bashx/src/do/commands/posix-utils.js.map +1 -0
  473. package/dist/primitives/bashx/src/do/commands/system-utils.js +687 -0
  474. package/dist/primitives/bashx/src/do/commands/system-utils.js.map +1 -0
  475. package/dist/primitives/bashx/src/do/commands/test-command.js +523 -0
  476. package/dist/primitives/bashx/src/do/commands/test-command.js.map +1 -0
  477. package/dist/primitives/bashx/src/do/commands/text-processing.js +1550 -0
  478. package/dist/primitives/bashx/src/do/commands/text-processing.js.map +1 -0
  479. package/dist/primitives/bashx/src/do/container-executor.js +429 -0
  480. package/dist/primitives/bashx/src/do/container-executor.js.map +1 -0
  481. package/dist/primitives/bashx/src/do/index.js +668 -0
  482. package/dist/primitives/bashx/src/do/index.js.map +1 -0
  483. package/dist/primitives/bashx/src/do/tiered-executor.js +2647 -0
  484. package/dist/primitives/bashx/src/do/tiered-executor.js.map +1 -0
  485. package/dist/primitives/bashx/src/do/worker.js +352 -0
  486. package/dist/primitives/bashx/src/do/worker.js.map +1 -0
  487. package/dist/primitives/bashx/src/types.js +10 -0
  488. package/dist/primitives/bashx/src/types.js.map +1 -0
  489. package/dist/primitives/fsx/core/backend.js +480 -0
  490. package/dist/primitives/fsx/core/backend.js.map +1 -0
  491. package/dist/primitives/fsx/core/constants.js +140 -0
  492. package/dist/primitives/fsx/core/constants.js.map +1 -0
  493. package/dist/primitives/fsx/core/fsx.js +1184 -0
  494. package/dist/primitives/fsx/core/fsx.js.map +1 -0
  495. package/dist/primitives/fsx/core/glob/glob.js +438 -0
  496. package/dist/primitives/fsx/core/glob/glob.js.map +1 -0
  497. package/dist/primitives/fsx/core/glob/index.js +8 -0
  498. package/dist/primitives/fsx/core/glob/index.js.map +1 -0
  499. package/dist/primitives/fsx/core/glob/match.js +392 -0
  500. package/dist/primitives/fsx/core/glob/match.js.map +1 -0
  501. package/dist/primitives/fsx/core/types.js +307 -0
  502. package/dist/primitives/fsx/core/types.js.map +1 -0
  503. package/dist/sandbox/index.js +258 -0
  504. package/dist/sandbox/index.js.map +1 -0
  505. package/dist/sdk/capnweb-compat.js +42 -0
  506. package/dist/sdk/capnweb-compat.js.map +1 -0
  507. package/dist/sdk/client.js +20 -0
  508. package/dist/sdk/client.js.map +1 -0
  509. package/dist/sdk/index.js +17 -0
  510. package/dist/sdk/index.js.map +1 -0
  511. package/dist/snippets/artifacts-config.js +241 -0
  512. package/dist/snippets/artifacts-config.js.map +1 -0
  513. package/dist/snippets/artifacts-ingest.js +832 -0
  514. package/dist/snippets/artifacts-ingest.js.map +1 -0
  515. package/dist/snippets/artifacts-serve.js +1035 -0
  516. package/dist/snippets/artifacts-serve.js.map +1 -0
  517. package/dist/snippets/artifacts-types.js +161 -0
  518. package/dist/snippets/artifacts-types.js.map +1 -0
  519. package/dist/snippets/cache-probe.js +376 -0
  520. package/dist/snippets/cache-probe.js.map +1 -0
  521. package/dist/snippets/cache.js +10 -0
  522. package/dist/snippets/cache.js.map +1 -0
  523. package/dist/snippets/events.js +469 -0
  524. package/dist/snippets/events.js.map +1 -0
  525. package/dist/snippets/index.js +7 -0
  526. package/dist/snippets/index.js.map +1 -0
  527. package/dist/snippets/proxy.js +495 -0
  528. package/dist/snippets/proxy.js.map +1 -0
  529. package/dist/snippets/search.js +1759 -0
  530. package/dist/snippets/search.js.map +1 -0
  531. package/dist/streams/index.js +30 -0
  532. package/dist/streams/index.js.map +1 -0
  533. package/dist/streams/observability.js +68 -0
  534. package/dist/streams/observability.js.map +1 -0
  535. package/dist/types/AI.js +92 -0
  536. package/dist/types/AI.js.map +1 -0
  537. package/dist/types/AIFunction.js +171 -0
  538. package/dist/types/AIFunction.js.map +1 -0
  539. package/dist/types/BrowseVerb.js +89 -0
  540. package/dist/types/BrowseVerb.js.map +1 -0
  541. package/dist/types/Browser.js +31 -0
  542. package/dist/types/Browser.js.map +1 -0
  543. package/dist/types/Chaos.js +15 -0
  544. package/dist/types/Chaos.js.map +1 -0
  545. package/dist/types/CloudflareBindings.js +109 -0
  546. package/dist/types/CloudflareBindings.js.map +1 -0
  547. package/dist/types/Collection.js +50 -0
  548. package/dist/types/Collection.js.map +1 -0
  549. package/dist/types/DO.js +2 -0
  550. package/dist/types/DO.js.map +1 -0
  551. package/dist/types/DOLocation.js +63 -0
  552. package/dist/types/DOLocation.js.map +1 -0
  553. package/dist/types/EventHandler.js +57 -0
  554. package/dist/types/EventHandler.js.map +1 -0
  555. package/dist/types/Experiment.js +33 -0
  556. package/dist/types/Experiment.js.map +1 -0
  557. package/dist/types/Flag.js +57 -0
  558. package/dist/types/Flag.js.map +1 -0
  559. package/dist/types/Lifecycle.js +13 -0
  560. package/dist/types/Lifecycle.js.map +1 -0
  561. package/dist/types/Location.js +169 -0
  562. package/dist/types/Location.js.map +1 -0
  563. package/dist/types/Noun.js +66 -0
  564. package/dist/types/Noun.js.map +1 -0
  565. package/dist/types/SessionEvent.js +194 -0
  566. package/dist/types/SessionEvent.js.map +1 -0
  567. package/dist/types/Thing.js +55 -0
  568. package/dist/types/Thing.js.map +1 -0
  569. package/dist/types/ThingDO.js +153 -0
  570. package/dist/types/ThingDO.js.map +1 -0
  571. package/dist/types/Things.js +2 -0
  572. package/dist/types/Things.js.map +1 -0
  573. package/dist/types/Verb.js +119 -0
  574. package/dist/types/Verb.js.map +1 -0
  575. package/dist/types/WorkflowContext.js +70 -0
  576. package/dist/types/WorkflowContext.js.map +1 -0
  577. package/dist/types/analytics-api.js +13 -0
  578. package/dist/types/analytics-api.js.map +1 -0
  579. package/dist/types/capabilities.js +135 -0
  580. package/dist/types/capabilities.js.map +1 -0
  581. package/dist/types/drizzle.js +12 -0
  582. package/dist/types/drizzle.js.map +1 -0
  583. package/dist/types/event.js +201 -0
  584. package/dist/types/event.js.map +1 -0
  585. package/dist/types/fn.js +12 -0
  586. package/dist/types/fn.js.map +1 -0
  587. package/dist/types/iceberg.js +48 -0
  588. package/dist/types/iceberg.js.map +1 -0
  589. package/dist/types/ids.js +170 -0
  590. package/dist/types/ids.js.map +1 -0
  591. package/dist/types/index.js +41 -0
  592. package/dist/types/index.js.map +1 -0
  593. package/dist/types/introspect.js +54 -0
  594. package/dist/types/introspect.js.map +1 -0
  595. package/dist/types/observability.js +124 -0
  596. package/dist/types/observability.js.map +1 -0
  597. package/dist/types/sync-protocol.js +175 -0
  598. package/dist/types/sync-protocol.js.map +1 -0
  599. package/dist/types/vector.js +13 -0
  600. package/dist/types/vector.js.map +1 -0
  601. package/dist/workflows/ScheduleManager.js +473 -0
  602. package/dist/workflows/ScheduleManager.js.map +1 -0
  603. package/dist/workflows/StepDOBridge.js +149 -0
  604. package/dist/workflows/StepDOBridge.js.map +1 -0
  605. package/dist/workflows/StepResultStorage.js +232 -0
  606. package/dist/workflows/StepResultStorage.js.map +1 -0
  607. package/dist/workflows/WaitForEventManager.js +461 -0
  608. package/dist/workflows/WaitForEventManager.js.map +1 -0
  609. package/dist/workflows/analyzer.js +332 -0
  610. package/dist/workflows/analyzer.js.map +1 -0
  611. package/dist/workflows/compat/activity-router.js +484 -0
  612. package/dist/workflows/compat/activity-router.js.map +1 -0
  613. package/dist/workflows/compat/backends/cloudflare-workflows.js +431 -0
  614. package/dist/workflows/compat/backends/cloudflare-workflows.js.map +1 -0
  615. package/dist/workflows/compat/backends/index.js +14 -0
  616. package/dist/workflows/compat/backends/index.js.map +1 -0
  617. package/dist/workflows/compat/errors/index.js +375 -0
  618. package/dist/workflows/compat/errors/index.js.map +1 -0
  619. package/dist/workflows/compat/index.js +79 -0
  620. package/dist/workflows/compat/index.js.map +1 -0
  621. package/dist/workflows/compat/inngest/index.js +989 -0
  622. package/dist/workflows/compat/inngest/index.js.map +1 -0
  623. package/dist/workflows/compat/qstash/index.js +1263 -0
  624. package/dist/workflows/compat/qstash/index.js.map +1 -0
  625. package/dist/workflows/compat/temporal/activities.js +739 -0
  626. package/dist/workflows/compat/temporal/activities.js.map +1 -0
  627. package/dist/workflows/compat/temporal/child-workflows.js +154 -0
  628. package/dist/workflows/compat/temporal/child-workflows.js.map +1 -0
  629. package/dist/workflows/compat/temporal/client.js +381 -0
  630. package/dist/workflows/compat/temporal/client.js.map +1 -0
  631. package/dist/workflows/compat/temporal/context.js +309 -0
  632. package/dist/workflows/compat/temporal/context.js.map +1 -0
  633. package/dist/workflows/compat/temporal/determinism.js +216 -0
  634. package/dist/workflows/compat/temporal/determinism.js.map +1 -0
  635. package/dist/workflows/compat/temporal/errors.js +128 -0
  636. package/dist/workflows/compat/temporal/errors.js.map +1 -0
  637. package/dist/workflows/compat/temporal/index.js +2464 -0
  638. package/dist/workflows/compat/temporal/index.js.map +1 -0
  639. package/dist/workflows/compat/temporal/saga.js +504 -0
  640. package/dist/workflows/compat/temporal/saga.js.map +1 -0
  641. package/dist/workflows/compat/temporal/signals.js +364 -0
  642. package/dist/workflows/compat/temporal/signals.js.map +1 -0
  643. package/dist/workflows/compat/temporal/storage.js +271 -0
  644. package/dist/workflows/compat/temporal/storage.js.map +1 -0
  645. package/dist/workflows/compat/temporal/timers.js +347 -0
  646. package/dist/workflows/compat/temporal/timers.js.map +1 -0
  647. package/dist/workflows/compat/temporal/types.js +7 -0
  648. package/dist/workflows/compat/temporal/types.js.map +1 -0
  649. package/dist/workflows/compat/temporal/unified-primitives.js +339 -0
  650. package/dist/workflows/compat/temporal/unified-primitives.js.map +1 -0
  651. package/dist/workflows/compat/trigger/index.js +468 -0
  652. package/dist/workflows/compat/trigger/index.js.map +1 -0
  653. package/dist/workflows/compat/utils/index.js +69 -0
  654. package/dist/workflows/compat/utils/index.js.map +1 -0
  655. package/dist/workflows/context/correlation-capability.js +266 -0
  656. package/dist/workflows/context/correlation-capability.js.map +1 -0
  657. package/dist/workflows/context/correlation.js +484 -0
  658. package/dist/workflows/context/correlation.js.map +1 -0
  659. package/dist/workflows/context/experiment.js +289 -0
  660. package/dist/workflows/context/experiment.js.map +1 -0
  661. package/dist/workflows/context/flag.js +244 -0
  662. package/dist/workflows/context/flag.js.map +1 -0
  663. package/dist/workflows/context/foundation.js +648 -0
  664. package/dist/workflows/context/foundation.js.map +1 -0
  665. package/dist/workflows/context/human-base.js +106 -0
  666. package/dist/workflows/context/human-base.js.map +1 -0
  667. package/dist/workflows/context/human.js +368 -0
  668. package/dist/workflows/context/human.js.map +1 -0
  669. package/dist/workflows/context/measure.js +354 -0
  670. package/dist/workflows/context/measure.js.map +1 -0
  671. package/dist/workflows/context/rate-limit.js +358 -0
  672. package/dist/workflows/context/rate-limit.js.map +1 -0
  673. package/dist/workflows/context/user.js +117 -0
  674. package/dist/workflows/context/user.js.map +1 -0
  675. package/dist/workflows/context/vault.js +360 -0
  676. package/dist/workflows/context/vault.js.map +1 -0
  677. package/dist/workflows/data/entity-events/entity-events.js +489 -0
  678. package/dist/workflows/data/entity-events/entity-events.js.map +1 -0
  679. package/dist/workflows/data/experiment/index.js +599 -0
  680. package/dist/workflows/data/experiment/index.js.map +1 -0
  681. package/dist/workflows/data/goal/context.js +558 -0
  682. package/dist/workflows/data/goal/context.js.map +1 -0
  683. package/dist/workflows/data/goal/index.js +32 -0
  684. package/dist/workflows/data/goal/index.js.map +1 -0
  685. package/dist/workflows/data/measure/index.js +840 -0
  686. package/dist/workflows/data/measure/index.js.map +1 -0
  687. package/dist/workflows/data/stream/index.js +1215 -0
  688. package/dist/workflows/data/stream/index.js.map +1 -0
  689. package/dist/workflows/data/track/context.js +883 -0
  690. package/dist/workflows/data/track/context.js.map +1 -0
  691. package/dist/workflows/data/track/index.js +15 -0
  692. package/dist/workflows/data/track/index.js.map +1 -0
  693. package/dist/workflows/data/view/context.js +864 -0
  694. package/dist/workflows/data/view/context.js.map +1 -0
  695. package/dist/workflows/domain.js +93 -0
  696. package/dist/workflows/domain.js.map +1 -0
  697. package/dist/workflows/flag.js +176 -0
  698. package/dist/workflows/flag.js.map +1 -0
  699. package/dist/workflows/flags.js +217 -0
  700. package/dist/workflows/flags.js.map +1 -0
  701. package/dist/workflows/hash.js +209 -0
  702. package/dist/workflows/hash.js.map +1 -0
  703. package/dist/workflows/index.js +50 -0
  704. package/dist/workflows/index.js.map +1 -0
  705. package/dist/workflows/on.js +378 -0
  706. package/dist/workflows/on.js.map +1 -0
  707. package/dist/workflows/pipeline-promise.js +481 -0
  708. package/dist/workflows/pipeline-promise.js.map +1 -0
  709. package/dist/workflows/pipeline-types.js +20 -0
  710. package/dist/workflows/pipeline-types.js.map +1 -0
  711. package/dist/workflows/proxy.js +76 -0
  712. package/dist/workflows/proxy.js.map +1 -0
  713. package/dist/workflows/runtime.js +310 -0
  714. package/dist/workflows/runtime.js.map +1 -0
  715. package/dist/workflows/schedule-builder.js +327 -0
  716. package/dist/workflows/schedule-builder.js.map +1 -0
  717. package/dist/workflows/visibility/index.js +148 -0
  718. package/dist/workflows/visibility/index.js.map +1 -0
  719. package/dist/workflows/visibility/query-parser.js +150 -0
  720. package/dist/workflows/visibility/query-parser.js.map +1 -0
  721. package/dist/workflows/visibility/store.js +223 -0
  722. package/dist/workflows/visibility/store.js.map +1 -0
  723. package/dist/workflows/visibility/types.js +30 -0
  724. package/dist/workflows/visibility/types.js.map +1 -0
  725. package/dist/workflows/workflow.js +53 -0
  726. package/dist/workflows/workflow.js.map +1 -0
  727. package/package.json +279 -46
@@ -0,0 +1,2647 @@
1
+ /**
2
+ * Tiered Execution System
3
+ *
4
+ * Implements a 4-tier execution model for bash commands:
5
+ *
6
+ * - Tier 1: Native in-Worker via nodejs_compat_v2/ofetch (fastest, most limited)
7
+ * - Tier 2: RPC bindings for jq.do/npm.do (fast, specific tools)
8
+ * - Tier 3: worker_loaders for dynamic npm (flexible, dynamic loading)
9
+ * - Tier 4: Sandbox SDK for true Linux needs (slowest, full capability)
10
+ *
11
+ * The executor auto-detects which tier to use based on command analysis
12
+ * and available bindings.
13
+ *
14
+ * @module bashx/do/tiered-executor
15
+ */
16
+ import { executeBc, executeExpr, executeSeq, executeShuf, executeSleep, executeTimeout, timeoutCommandNotFound, } from './commands/math-control.js';
17
+ import { executeJq, executeYq, executeBase64, executeEnvsubst, parseJqArgs, parseYqArgs, parseBase64Args, parseEnvsubstArgs, JqError, Base64Error, EnvsubstError, } from './commands/data-processing.js';
18
+ import { executeCryptoCommand, } from './commands/crypto.js';
19
+ import { executeSed, executeAwk, executeDiff, executePatch, executeTee, executeXargs, } from './commands/text-processing.js';
20
+ import { executeCut, executeSort, executeTr, executeUniq, executeWc, executeBasename, executeDirname, executeEcho, executePrintf, executeDate, executeDd, executeOd, } from './commands/posix-utils.js';
21
+ import { executeYes, executeWhoami, executeHostname, executePrintenv, } from './commands/system-utils.js';
22
+ import { parseEnvArgs, executeEnv, formatEnv, parseIdArgs, executeId, DEFAULT_WORKER_IDENTITY, parseUnameArgs, executeUname, DEFAULT_WORKER_SYSINFO, parseTacArgs, executeTac, } from './commands/extended-utils.js';
23
+ import { executeTest, createFileInfoProvider, } from './commands/test-command.js';
24
+ // ============================================================================
25
+ // TIER 1: NATIVE COMMANDS
26
+ // ============================================================================
27
+ /**
28
+ * Commands that can be executed natively in-Worker via nodejs_compat_v2
29
+ */
30
+ const TIER_1_NATIVE_COMMANDS = new Set([
31
+ // Basic file operations (read)
32
+ 'cat', 'head', 'tail', 'ls', 'test', '[', 'stat', 'readlink', 'find', 'grep',
33
+ // File operations (write)
34
+ 'mkdir', 'rmdir', 'rm', 'cp', 'mv', 'touch', 'truncate', 'ln',
35
+ // Permission operations
36
+ 'chmod', 'chown',
37
+ // Echo/print (pure computation)
38
+ 'echo', 'printf',
39
+ // Path operations
40
+ 'pwd', 'dirname', 'basename',
41
+ // String/text processing (pure)
42
+ 'wc', 'sort', 'uniq', 'tr', 'cut', 'rev',
43
+ // Date/time (pure)
44
+ 'date',
45
+ // True/false (pure)
46
+ 'true', 'false',
47
+ // HTTP operations (via fetch API)
48
+ 'curl', 'wget',
49
+ // Math & control commands
50
+ 'bc', 'expr', 'seq', 'shuf', 'sleep', 'timeout',
51
+ // Compression commands (native via pako/fflate)
52
+ 'gzip', 'gunzip', 'zcat', 'tar', 'zip', 'unzip',
53
+ // Data processing commands (native implementations)
54
+ 'jq', 'yq', 'base64', 'envsubst',
55
+ // Crypto commands (native via Web Crypto API)
56
+ 'sha256sum', 'sha1sum', 'sha512sum', 'sha384sum', 'md5sum',
57
+ 'uuidgen', 'uuid', 'cksum', 'sum', 'openssl',
58
+ // Text processing commands (native implementations)
59
+ 'sed', 'awk', 'diff', 'patch', 'tee', 'xargs',
60
+ // System utility commands (native implementations)
61
+ 'yes', 'whoami', 'hostname', 'printenv',
62
+ // Extended utility commands (native implementations)
63
+ 'env', 'id', 'uname', 'tac',
64
+ ]);
65
+ /**
66
+ * Commands that specifically require filesystem access for Tier 1
67
+ */
68
+ const TIER_1_FS_COMMANDS = new Set([
69
+ // Read operations
70
+ 'cat', 'head', 'tail', 'ls', 'test', 'stat', 'readlink', 'find', 'grep',
71
+ // Write operations
72
+ 'mkdir', 'rmdir', 'rm', 'cp', 'mv', 'touch', 'truncate', 'ln',
73
+ // Permission operations
74
+ 'chmod', 'chown',
75
+ // Compression commands (need filesystem access)
76
+ 'gzip', 'gunzip', 'zcat', 'tar', 'zip', 'unzip',
77
+ ]);
78
+ /**
79
+ * Commands that use native HTTP (fetch API) for Tier 1
80
+ */
81
+ const TIER_1_HTTP_COMMANDS = new Set(['curl', 'wget']);
82
+ /**
83
+ * Data processing commands with native implementations
84
+ */
85
+ const TIER_1_DATA_COMMANDS = new Set(['jq', 'yq', 'base64', 'envsubst']);
86
+ /**
87
+ * Crypto commands with native Web Crypto API implementations
88
+ */
89
+ const TIER_1_CRYPTO_COMMANDS = new Set([
90
+ 'sha256sum', 'sha1sum', 'sha512sum', 'sha384sum', 'md5sum',
91
+ 'uuidgen', 'uuid', 'cksum', 'sum', 'openssl',
92
+ ]);
93
+ /**
94
+ * Text processing commands with native implementations
95
+ */
96
+ const TIER_1_TEXT_PROCESSING_COMMANDS = new Set([
97
+ 'sed', 'awk', 'diff', 'patch', 'tee', 'xargs',
98
+ ]);
99
+ /**
100
+ * POSIX utility commands with native implementations
101
+ * These include: cut, sort, tr, uniq, wc, basename, dirname, echo, printf, date, dd, od
102
+ */
103
+ const TIER_1_POSIX_UTILS_COMMANDS = new Set([
104
+ 'cut', 'sort', 'tr', 'uniq', 'wc',
105
+ 'basename', 'dirname', 'echo', 'printf',
106
+ 'date', 'dd', 'od',
107
+ ]);
108
+ /**
109
+ * System utility commands with native implementations
110
+ * These include: yes, whoami, hostname, printenv
111
+ * (sleep, seq, pwd are already handled in other command groups)
112
+ */
113
+ const TIER_1_SYSTEM_UTILS_COMMANDS = new Set([
114
+ 'yes', 'whoami', 'hostname', 'printenv',
115
+ ]);
116
+ /**
117
+ * Extended utility commands with native implementations
118
+ * These include: env, id, uname, timeout, tac, shuf
119
+ * Note: timeout and shuf are also in math-control, but extended-utils provides more options
120
+ */
121
+ const TIER_1_EXTENDED_UTILS_COMMANDS = new Set([
122
+ 'env', 'id', 'uname', 'tac',
123
+ // Note: timeout and shuf have extended implementations but also exist in math-control
124
+ ]);
125
+ // ============================================================================
126
+ // TIER 2: RPC COMMANDS
127
+ // ============================================================================
128
+ /**
129
+ * Default RPC services and their commands
130
+ */
131
+ const DEFAULT_RPC_SERVICES = {
132
+ jq: {
133
+ commands: ['jq'],
134
+ endpoint: 'https://jq.do',
135
+ },
136
+ npm: {
137
+ commands: ['npm', 'npx', 'pnpm', 'yarn', 'bun'],
138
+ endpoint: 'https://npm.do',
139
+ },
140
+ git: {
141
+ commands: ['git'],
142
+ endpoint: 'https://git.do',
143
+ },
144
+ };
145
+ // ============================================================================
146
+ // TIER 3: WORKER LOADER MODULES
147
+ // ============================================================================
148
+ /**
149
+ * NPM packages that can be dynamically loaded in Workers
150
+ */
151
+ const TIER_3_LOADABLE_MODULES = new Set([
152
+ // JavaScript/TypeScript tools
153
+ 'esbuild', 'typescript', 'prettier', 'eslint',
154
+ // Data processing
155
+ 'zod', 'ajv', 'yaml', 'toml',
156
+ // Crypto
157
+ 'crypto-js', 'jose',
158
+ // Utility
159
+ 'lodash', 'date-fns', 'uuid',
160
+ ]);
161
+ // ============================================================================
162
+ // TIER 4: SANDBOX-ONLY COMMANDS
163
+ // ============================================================================
164
+ /**
165
+ * Commands that require true Linux sandbox execution
166
+ */
167
+ const TIER_4_SANDBOX_COMMANDS = new Set([
168
+ // System/process management
169
+ 'ps', 'kill', 'killall', 'top', 'htop',
170
+ // Network tools (curl/wget moved to Tier 1 via native fetch)
171
+ 'ping', 'ssh', 'scp', 'nc', 'netstat',
172
+ // Package managers (when not via RPC)
173
+ 'apt', 'apt-get', 'yum', 'dnf', 'brew',
174
+ // Containers
175
+ 'docker', 'docker-compose', 'podman', 'kubectl',
176
+ // Compilers and runtimes
177
+ 'gcc', 'g++', 'clang', 'rustc', 'cargo', 'go', 'python', 'python3', 'ruby', 'perl',
178
+ // System utilities (chmod/chown moved to Tier 1 via FsCapability)
179
+ 'sudo', 'su', 'chgrp',
180
+ // Archive (gzip, tar, zip moved to Tier 1 via pako/fflate)
181
+ // Process substitution, pipes, complex shell features
182
+ 'bash', 'sh', 'zsh',
183
+ ]);
184
+ // ============================================================================
185
+ // TIERED EXECUTOR CLASS
186
+ // ============================================================================
187
+ /**
188
+ * TieredExecutor - Smart executor that routes commands to the appropriate tier.
189
+ *
190
+ * The executor analyzes each command and determines the optimal execution tier:
191
+ * - Tier 1: Fast, in-Worker native operations (cat, ls, echo, etc.)
192
+ * - Tier 2: RPC calls to external services (jq.do, npm.do, git.do)
193
+ * - Tier 3: Dynamic npm module loading (esbuild, prettier, etc.)
194
+ * - Tier 4: Full sandbox execution for Linux-specific commands
195
+ *
196
+ * @example
197
+ * ```typescript
198
+ * const executor = new TieredExecutor({
199
+ * fs: fsCapability,
200
+ * rpcBindings: {
201
+ * jq: { endpoint: 'https://jq.do', commands: ['jq'] },
202
+ * },
203
+ * sandbox: sandboxBinding,
204
+ * })
205
+ *
206
+ * // Auto-routed to Tier 1 (native)
207
+ * await executor.execute('cat file.txt')
208
+ *
209
+ * // Auto-routed to Tier 2 (RPC)
210
+ * await executor.execute('jq .name package.json')
211
+ *
212
+ * // Auto-routed to Tier 4 (sandbox)
213
+ * await executor.execute('docker ps')
214
+ * ```
215
+ */
216
+ export class TieredExecutor {
217
+ fs;
218
+ rpcBindings;
219
+ workerLoaders;
220
+ sandbox;
221
+ defaultTimeout;
222
+ /** @internal Reserved for future optimization strategy selection */
223
+ preferFaster;
224
+ constructor(config) {
225
+ this.fs = config.fs;
226
+ this.rpcBindings = config.rpcBindings ?? {};
227
+ this.workerLoaders = config.workerLoaders ?? {};
228
+ this.sandbox = config.sandbox;
229
+ this.defaultTimeout = config.defaultTimeout ?? 30000;
230
+ this.preferFaster = config.preferFaster ?? true;
231
+ // Merge default RPC services with provided bindings
232
+ for (const [name, service] of Object.entries(DEFAULT_RPC_SERVICES)) {
233
+ if (!this.rpcBindings[name]) {
234
+ this.rpcBindings[name] = {
235
+ name,
236
+ endpoint: service.endpoint,
237
+ commands: service.commands,
238
+ };
239
+ }
240
+ }
241
+ }
242
+ /**
243
+ * Classify a command to determine which tier should execute it.
244
+ *
245
+ * @param command - The command to classify
246
+ * @returns TierClassification with tier level and handler info
247
+ */
248
+ classifyCommand(command) {
249
+ const cmd = this.extractCommandName(command);
250
+ // Tier 1: Native in-Worker commands
251
+ if (TIER_1_NATIVE_COMMANDS.has(cmd)) {
252
+ // If it's a filesystem command, check if fs capability is available
253
+ if (TIER_1_FS_COMMANDS.has(cmd)) {
254
+ if (this.fs) {
255
+ return {
256
+ tier: 1,
257
+ reason: `Native filesystem operation via FsCapability`,
258
+ handler: 'native',
259
+ capability: 'fs',
260
+ };
261
+ }
262
+ // Fall through to sandbox if no fs capability
263
+ }
264
+ else if (TIER_1_HTTP_COMMANDS.has(cmd)) {
265
+ // HTTP commands via native fetch API
266
+ return {
267
+ tier: 1,
268
+ reason: `Native HTTP operation via fetch API (${cmd})`,
269
+ handler: 'native',
270
+ capability: 'http',
271
+ };
272
+ }
273
+ else if (TIER_1_DATA_COMMANDS.has(cmd)) {
274
+ // Data processing commands (jq, yq, base64, envsubst)
275
+ return {
276
+ tier: 1,
277
+ reason: `Native data processing command (${cmd})`,
278
+ handler: 'native',
279
+ capability: cmd, // Use command name as capability
280
+ };
281
+ }
282
+ else if (TIER_1_CRYPTO_COMMANDS.has(cmd)) {
283
+ // Crypto commands via Web Crypto API
284
+ return {
285
+ tier: 1,
286
+ reason: `Native crypto command via Web Crypto API (${cmd})`,
287
+ handler: 'native',
288
+ capability: 'crypto',
289
+ };
290
+ }
291
+ else if (TIER_1_TEXT_PROCESSING_COMMANDS.has(cmd)) {
292
+ // Text processing commands (sed, awk, diff, patch, tee, xargs)
293
+ return {
294
+ tier: 1,
295
+ reason: `Native text processing command (${cmd})`,
296
+ handler: 'native',
297
+ capability: 'text',
298
+ };
299
+ }
300
+ else if (TIER_1_POSIX_UTILS_COMMANDS.has(cmd)) {
301
+ // POSIX utility commands (cut, sort, tr, uniq, wc, basename, dirname, echo, printf, date, dd, od)
302
+ return {
303
+ tier: 1,
304
+ reason: `Native POSIX utility command (${cmd})`,
305
+ handler: 'native',
306
+ capability: 'posix',
307
+ };
308
+ }
309
+ else if (TIER_1_SYSTEM_UTILS_COMMANDS.has(cmd)) {
310
+ // System utility commands (yes, whoami, hostname, printenv)
311
+ return {
312
+ tier: 1,
313
+ reason: `Native system utility command (${cmd})`,
314
+ handler: 'native',
315
+ capability: 'system',
316
+ };
317
+ }
318
+ else if (TIER_1_EXTENDED_UTILS_COMMANDS.has(cmd)) {
319
+ // Extended utility commands (env, id, uname, tac)
320
+ return {
321
+ tier: 1,
322
+ reason: `Native extended utility command (${cmd})`,
323
+ handler: 'native',
324
+ capability: 'extended',
325
+ };
326
+ }
327
+ else {
328
+ // Pure computation commands
329
+ return {
330
+ tier: 1,
331
+ reason: `Pure computation command (${cmd})`,
332
+ handler: 'native',
333
+ capability: 'compute',
334
+ };
335
+ }
336
+ }
337
+ // Tier 2: RPC service commands
338
+ for (const [serviceName, binding] of Object.entries(this.rpcBindings)) {
339
+ if (binding.commands.includes(cmd)) {
340
+ return {
341
+ tier: 2,
342
+ reason: `RPC service available (${serviceName})`,
343
+ handler: 'rpc',
344
+ capability: serviceName,
345
+ };
346
+ }
347
+ }
348
+ // Tier 3: Check for commands that can use dynamically loaded modules
349
+ // This is for Node.js tools that can run in Workers with worker_loaders
350
+ const workerLoaderMatch = this.matchWorkerLoader(command);
351
+ if (workerLoaderMatch) {
352
+ return {
353
+ tier: 3,
354
+ reason: `Dynamic npm module available (${workerLoaderMatch})`,
355
+ handler: 'loader',
356
+ capability: workerLoaderMatch,
357
+ };
358
+ }
359
+ // Tier 4: Sandbox for everything else
360
+ return {
361
+ tier: 4,
362
+ reason: TIER_4_SANDBOX_COMMANDS.has(cmd)
363
+ ? `Requires Linux sandbox (${cmd})`
364
+ : 'No higher tier available for this command',
365
+ handler: 'sandbox',
366
+ capability: 'container',
367
+ };
368
+ }
369
+ /**
370
+ * Execute a command, automatically routing to the appropriate tier.
371
+ *
372
+ * @param command - The command to execute
373
+ * @param options - Optional execution options
374
+ * @returns Promise resolving to the execution result
375
+ */
376
+ async execute(command, options) {
377
+ // Handle input redirection (< filename)
378
+ const redirectMatch = command.match(/^(.+?)\s*<\s*(\S+)\s*$/);
379
+ if (redirectMatch && this.fs) {
380
+ const actualCommand = redirectMatch[1].trim();
381
+ const inputFile = redirectMatch[2];
382
+ try {
383
+ const inputContent = await this.fs.read(inputFile, { encoding: 'utf-8' });
384
+ return this.execute(actualCommand, { ...options, stdin: inputContent });
385
+ }
386
+ catch (error) {
387
+ const message = error instanceof Error ? error.message : String(error);
388
+ return this.createResult(command, '', message, 1, 1);
389
+ }
390
+ }
391
+ // Handle pipelines - split by | and execute in sequence
392
+ const pipelineSegments = this.splitPipeline(command);
393
+ if (pipelineSegments.length > 1) {
394
+ return this.executePipeline(pipelineSegments, options);
395
+ }
396
+ const classification = this.classifyCommand(command);
397
+ try {
398
+ switch (classification.tier) {
399
+ case 1:
400
+ return await this.executeTier1(command, classification, options);
401
+ case 2:
402
+ return await this.executeTier2(command, classification, options);
403
+ case 3:
404
+ return await this.executeTier3(command, classification, options);
405
+ case 4:
406
+ return await this.executeTier4(command, classification, options);
407
+ default:
408
+ throw new Error(`Unknown tier: ${classification.tier}`);
409
+ }
410
+ }
411
+ catch (error) {
412
+ // If a higher tier fails, try falling back to a lower tier
413
+ if (classification.tier < 4 && this.sandbox) {
414
+ console.warn(`Tier ${classification.tier} failed for "${command}", falling back to sandbox:`, error);
415
+ return this.executeTier4(command, { ...classification, tier: 4 }, options);
416
+ }
417
+ throw error;
418
+ }
419
+ }
420
+ /**
421
+ * Spawn a streaming process. Routes to sandbox for full streaming support.
422
+ */
423
+ async spawn(command, args, options) {
424
+ if (!this.sandbox?.spawn) {
425
+ throw new Error('Spawn requires sandbox with spawn support');
426
+ }
427
+ return this.sandbox.spawn(command, args, options);
428
+ }
429
+ /**
430
+ * Split a command into pipeline segments, respecting quotes
431
+ */
432
+ splitPipeline(command) {
433
+ const segments = [];
434
+ let current = '';
435
+ let inSingleQuote = false;
436
+ let inDoubleQuote = false;
437
+ for (let i = 0; i < command.length; i++) {
438
+ const char = command[i];
439
+ if (char === "'" && !inDoubleQuote) {
440
+ inSingleQuote = !inSingleQuote;
441
+ current += char;
442
+ }
443
+ else if (char === '"' && !inSingleQuote) {
444
+ inDoubleQuote = !inDoubleQuote;
445
+ current += char;
446
+ }
447
+ else if (char === '\\' && !inSingleQuote && command[i + 1] === '|') {
448
+ // Escaped pipe - keep it as \|, don't split
449
+ current += '\\|';
450
+ i++;
451
+ }
452
+ else if (char === '|' && !inSingleQuote && !inDoubleQuote) {
453
+ // Check if it's || (logical OR) - skip if so
454
+ if (command[i + 1] === '|') {
455
+ current += '||';
456
+ i++;
457
+ }
458
+ else {
459
+ segments.push(current.trim());
460
+ current = '';
461
+ }
462
+ }
463
+ else {
464
+ current += char;
465
+ }
466
+ }
467
+ if (current.trim()) {
468
+ segments.push(current.trim());
469
+ }
470
+ return segments;
471
+ }
472
+ /**
473
+ * Execute a pipeline of commands, passing stdout of each to stdin of next
474
+ */
475
+ async executePipeline(segments, options) {
476
+ let stdin = options?.stdin || '';
477
+ let lastResult = null;
478
+ for (const segment of segments) {
479
+ const segmentOptions = {
480
+ ...options,
481
+ stdin,
482
+ };
483
+ lastResult = await this.execute(segment, segmentOptions);
484
+ // If command failed, stop the pipeline
485
+ if (lastResult.exitCode !== 0) {
486
+ return lastResult;
487
+ }
488
+ // Pass stdout to next command's stdin
489
+ stdin = lastResult.stdout;
490
+ }
491
+ return lastResult;
492
+ }
493
+ // ============================================================================
494
+ // TIER EXECUTION METHODS
495
+ // ============================================================================
496
+ /**
497
+ * Tier 1: Execute command natively in-Worker
498
+ */
499
+ async executeTier1(command, classification, options) {
500
+ const cmd = this.extractCommandName(command);
501
+ const args = this.extractArgs(command);
502
+ // Handle filesystem commands via FsCapability
503
+ if (classification.capability === 'fs' && this.fs) {
504
+ return this.executeNativeFs(cmd, args, options);
505
+ }
506
+ // Handle HTTP commands via native fetch API
507
+ if (classification.capability === 'http') {
508
+ if (cmd === 'curl') {
509
+ return this.executeCurl(args);
510
+ }
511
+ else if (cmd === 'wget') {
512
+ return this.executeWget(args);
513
+ }
514
+ }
515
+ // Handle data processing commands
516
+ if (TIER_1_DATA_COMMANDS.has(cmd)) {
517
+ return this.executeDataProcessing(cmd, args, command, options);
518
+ }
519
+ // Handle crypto commands via Web Crypto API
520
+ if (TIER_1_CRYPTO_COMMANDS.has(cmd)) {
521
+ return this.executeNativeCrypto(cmd, args, options);
522
+ }
523
+ // Handle text processing commands (sed, awk, diff, patch, tee, xargs)
524
+ if (TIER_1_TEXT_PROCESSING_COMMANDS.has(cmd)) {
525
+ return this.executeTextProcessing(cmd, args, command, options);
526
+ }
527
+ // Handle POSIX utility commands (cut, sort, tr, uniq, wc, basename, dirname, echo, printf, date, dd, od)
528
+ if (TIER_1_POSIX_UTILS_COMMANDS.has(cmd)) {
529
+ return this.executePosixUtils(cmd, args, command, options);
530
+ }
531
+ // Handle system utility commands (yes, whoami, hostname, printenv)
532
+ if (TIER_1_SYSTEM_UTILS_COMMANDS.has(cmd)) {
533
+ return this.executeSystemUtilsCommands(cmd, args, command, options);
534
+ }
535
+ // Handle extended utility commands (env, id, uname, tac)
536
+ if (TIER_1_EXTENDED_UTILS_COMMANDS.has(cmd)) {
537
+ return this.executeExtendedUtilsCommands(cmd, args, command, options);
538
+ }
539
+ // Handle pure computation commands
540
+ return this.executeNativeCompute(cmd, args, options);
541
+ }
542
+ /**
543
+ * Execute native filesystem operations via FsCapability (from fsx.do)
544
+ *
545
+ * fsx.do provides a comprehensive POSIX-like filesystem API. This method
546
+ * uses the following fsx.do methods:
547
+ * - read(path, { encoding: 'utf-8' }) - returns string for text operations
548
+ * - list(path, { withFileTypes: true }) - returns Dirent[] for directory listing
549
+ * - exists(path) - returns boolean for existence checks
550
+ * - stat(path) - returns Stats with isFile()/isDirectory() methods
551
+ */
552
+ async executeNativeFs(cmd, args, options) {
553
+ if (!this.fs) {
554
+ throw new Error('FsCapability not available');
555
+ }
556
+ try {
557
+ let stdout = '';
558
+ let stderr = '';
559
+ let exitCode = 0;
560
+ switch (cmd) {
561
+ case 'cat': {
562
+ if (args.length === 0) {
563
+ return this.createResult(`cat ${args.join(' ')}`, '', 'cat: missing operand', 1, 1);
564
+ }
565
+ // Use encoding: 'utf-8' to ensure we get strings back from fsx.do
566
+ const contents = await Promise.all(args.filter(a => !a.startsWith('-')).map(f => this.fs.read(f, { encoding: 'utf-8' })));
567
+ stdout = contents.join('');
568
+ break;
569
+ }
570
+ case 'ls': {
571
+ const path = args.find(a => !a.startsWith('-')) || '.';
572
+ // Use withFileTypes: true to get Dirent objects from fsx.do
573
+ const entries = await this.fs.list(path, { withFileTypes: true });
574
+ // fsx.do returns Dirent[] when withFileTypes is true
575
+ // Dirent has isDirectory() as a method
576
+ stdout = entries
577
+ .map(e => e.isDirectory() ? `${e.name}/` : e.name)
578
+ .join('\n') + '\n';
579
+ break;
580
+ }
581
+ case 'head': {
582
+ // Parse options: -n N, -n -N (exclude last N), -q (quiet, no headers)
583
+ let headQuiet = false;
584
+ let headLines = 10;
585
+ let headExcludeLast = false;
586
+ const headFiles = [];
587
+ for (let i = 0; i < args.length; i++) {
588
+ const arg = args[i];
589
+ if (arg === '-q' || arg === '--quiet' || arg === '--silent') {
590
+ headQuiet = true;
591
+ }
592
+ else if (arg === '-n' && args[i + 1]) {
593
+ const nArg = args[++i];
594
+ if (nArg.startsWith('-')) {
595
+ // -n -N means exclude last N lines
596
+ headExcludeLast = true;
597
+ headLines = parseInt(nArg.slice(1), 10);
598
+ }
599
+ else {
600
+ headLines = parseInt(nArg, 10);
601
+ }
602
+ }
603
+ else if (arg.startsWith('-n')) {
604
+ const nArg = arg.slice(2);
605
+ if (nArg.startsWith('-')) {
606
+ headExcludeLast = true;
607
+ headLines = parseInt(nArg.slice(1), 10);
608
+ }
609
+ else {
610
+ headLines = parseInt(nArg, 10);
611
+ }
612
+ }
613
+ else if (!arg.startsWith('-')) {
614
+ headFiles.push(arg);
615
+ }
616
+ }
617
+ if (headFiles.length === 0) {
618
+ // Read from stdin
619
+ const stdinContent = options?.stdin || '';
620
+ const stdinLines = stdinContent.split('\n');
621
+ if (headExcludeLast) {
622
+ // Exclude last N lines
623
+ stdout = stdinLines.slice(0, -headLines).join('\n') + '\n';
624
+ }
625
+ else {
626
+ stdout = stdinLines.slice(0, headLines).join('\n') + '\n';
627
+ }
628
+ }
629
+ else {
630
+ const results = [];
631
+ for (let fi = 0; fi < headFiles.length; fi++) {
632
+ const file = headFiles[fi];
633
+ const content = await this.fs.read(file, { encoding: 'utf-8' });
634
+ const fileLines = content.split('\n');
635
+ let selectedLines;
636
+ if (headExcludeLast) {
637
+ selectedLines = fileLines.slice(0, -headLines);
638
+ }
639
+ else {
640
+ selectedLines = fileLines.slice(0, headLines);
641
+ }
642
+ // Add header if multiple files and not quiet
643
+ if (headFiles.length > 1 && !headQuiet) {
644
+ if (fi > 0)
645
+ results.push('');
646
+ results.push(`==> ${file} <==`);
647
+ }
648
+ results.push(...selectedLines);
649
+ }
650
+ stdout = results.join('\n') + '\n';
651
+ }
652
+ break;
653
+ }
654
+ case 'tail': {
655
+ // Parse options: -n N, -n +N (start from line N), -q (quiet, no headers)
656
+ let tailQuiet = false;
657
+ let tailLines = 10;
658
+ let tailStartFrom = false; // +N means start from line N
659
+ const tailFiles = [];
660
+ for (let i = 0; i < args.length; i++) {
661
+ const arg = args[i];
662
+ if (arg === '-q' || arg === '--quiet' || arg === '--silent') {
663
+ tailQuiet = true;
664
+ }
665
+ else if (arg === '-n' && args[i + 1]) {
666
+ const nArg = args[++i];
667
+ if (nArg.startsWith('+')) {
668
+ // -n +N means start from line N (1-indexed)
669
+ tailStartFrom = true;
670
+ tailLines = parseInt(nArg.slice(1), 10);
671
+ }
672
+ else {
673
+ tailLines = parseInt(nArg, 10);
674
+ }
675
+ }
676
+ else if (arg.startsWith('-n')) {
677
+ const nArg = arg.slice(2);
678
+ if (nArg.startsWith('+')) {
679
+ tailStartFrom = true;
680
+ tailLines = parseInt(nArg.slice(1), 10);
681
+ }
682
+ else {
683
+ tailLines = parseInt(nArg, 10);
684
+ }
685
+ }
686
+ else if (!arg.startsWith('-')) {
687
+ tailFiles.push(arg);
688
+ }
689
+ }
690
+ if (tailFiles.length === 0) {
691
+ // Read from stdin
692
+ const stdinContent = options?.stdin || '';
693
+ const stdinLines = stdinContent.split('\n');
694
+ const effectiveStdinLines = stdinLines[stdinLines.length - 1] === '' ? stdinLines.slice(0, -1) : stdinLines;
695
+ if (tailStartFrom) {
696
+ // +N means output starting from line N (1-indexed)
697
+ stdout = effectiveStdinLines.slice(tailLines - 1).join('\n') + '\n';
698
+ }
699
+ else {
700
+ stdout = effectiveStdinLines.slice(-tailLines).join('\n') + '\n';
701
+ }
702
+ }
703
+ else {
704
+ const results = [];
705
+ for (let fi = 0; fi < tailFiles.length; fi++) {
706
+ const file = tailFiles[fi];
707
+ const content = await this.fs.read(file, { encoding: 'utf-8' });
708
+ const allLines = content.split('\n');
709
+ const effectiveLines = allLines[allLines.length - 1] === '' ? allLines.slice(0, -1) : allLines;
710
+ let selectedLines;
711
+ if (tailStartFrom) {
712
+ selectedLines = effectiveLines.slice(tailLines - 1);
713
+ }
714
+ else {
715
+ selectedLines = effectiveLines.slice(-tailLines);
716
+ }
717
+ // Add header if multiple files and not quiet
718
+ if (tailFiles.length > 1 && !tailQuiet) {
719
+ if (fi > 0)
720
+ results.push('');
721
+ results.push(`==> ${file} <==`);
722
+ }
723
+ results.push(...selectedLines);
724
+ }
725
+ stdout = results.join('\n') + '\n';
726
+ }
727
+ break;
728
+ }
729
+ case 'test':
730
+ case '[': {
731
+ // Full test/[ implementation with all POSIX operators
732
+ const fileInfoProvider = this.fs ? createFileInfoProvider(this.fs) : undefined;
733
+ const result = await executeTest(args, fileInfoProvider);
734
+ exitCode = result.exitCode;
735
+ if (result.stderr) {
736
+ stderr = result.stderr;
737
+ }
738
+ break;
739
+ }
740
+ // ========================================================================
741
+ // NEW FILESYSTEM COMMANDS
742
+ // ========================================================================
743
+ case 'mkdir': {
744
+ const mkdirRecursive = args.includes('-p');
745
+ const mkdirPath = args.filter(a => !a.startsWith('-'))[0];
746
+ if (!mkdirPath) {
747
+ return this.createResult('mkdir', '', 'mkdir: missing operand', 1, 1);
748
+ }
749
+ await this.fs.mkdir(mkdirPath, { recursive: mkdirRecursive });
750
+ break;
751
+ }
752
+ case 'rmdir': {
753
+ const rmdirPath = args.filter(a => !a.startsWith('-'))[0];
754
+ if (!rmdirPath) {
755
+ return this.createResult('rmdir', '', 'rmdir: missing operand', 1, 1);
756
+ }
757
+ await this.fs.rmdir(rmdirPath);
758
+ break;
759
+ }
760
+ case 'rm': {
761
+ const rmRecursive = args.includes('-r') || args.includes('-rf') || args.includes('-R');
762
+ const rmForce = args.includes('-f') || args.includes('-rf');
763
+ const rmPaths = args.filter(a => !a.startsWith('-'));
764
+ if (rmPaths.length === 0) {
765
+ return this.createResult('rm', '', 'rm: missing operand', 1, 1);
766
+ }
767
+ for (const p of rmPaths) {
768
+ await this.fs.rm(p, { recursive: rmRecursive, force: rmForce });
769
+ }
770
+ break;
771
+ }
772
+ case 'cp': {
773
+ const cpRecursive = args.includes('-r') || args.includes('-R');
774
+ const cpPaths = args.filter(a => !a.startsWith('-'));
775
+ if (cpPaths.length < 2) {
776
+ return this.createResult('cp', '', 'cp: missing destination file operand', 1, 1);
777
+ }
778
+ const [cpSrc, cpDest] = cpPaths;
779
+ await this.fs.copyFile(cpSrc, cpDest, { recursive: cpRecursive });
780
+ break;
781
+ }
782
+ case 'mv': {
783
+ const mvPaths = args.filter(a => !a.startsWith('-'));
784
+ if (mvPaths.length < 2) {
785
+ return this.createResult('mv', '', 'mv: missing destination file operand', 1, 1);
786
+ }
787
+ const [mvSrc, mvDest] = mvPaths;
788
+ await this.fs.rename(mvSrc, mvDest);
789
+ break;
790
+ }
791
+ case 'touch': {
792
+ const touchPath = args.filter(a => !a.startsWith('-'))[0];
793
+ if (!touchPath) {
794
+ return this.createResult('touch', '', 'touch: missing file operand', 1, 1);
795
+ }
796
+ const touchNow = new Date();
797
+ try {
798
+ await this.fs.utimes(touchPath, touchNow, touchNow);
799
+ }
800
+ catch {
801
+ await this.fs.write(touchPath, '');
802
+ }
803
+ break;
804
+ }
805
+ case 'truncate': {
806
+ let truncSize = 0;
807
+ let truncPath = '';
808
+ for (let i = 0; i < args.length; i++) {
809
+ if (args[i] === '-s' && args[i + 1]) {
810
+ truncSize = parseInt(args[++i], 10);
811
+ }
812
+ else if (!args[i].startsWith('-')) {
813
+ truncPath = args[i];
814
+ }
815
+ }
816
+ if (!truncPath) {
817
+ return this.createResult('truncate', '', 'truncate: missing file operand', 1, 1);
818
+ }
819
+ await this.fs.truncate(truncPath, truncSize);
820
+ break;
821
+ }
822
+ case 'stat': {
823
+ const statPath = args.filter(a => !a.startsWith('-'))[0];
824
+ if (!statPath) {
825
+ return this.createResult('stat', '', 'stat: missing operand', 1, 1);
826
+ }
827
+ const fileStat = await this.fs.stat(statPath);
828
+ const statLines = [
829
+ ` File: ${statPath}`,
830
+ ` Size: ${fileStat.size}`,
831
+ ` Mode: ${fileStat.mode.toString(8)}`,
832
+ `Access: ${fileStat.atime}`,
833
+ `Modify: ${fileStat.mtime}`,
834
+ `Change: ${fileStat.ctime}`,
835
+ ];
836
+ stdout = statLines.join('\n') + '\n';
837
+ break;
838
+ }
839
+ case 'readlink': {
840
+ const readlinkPath = args.filter(a => !a.startsWith('-'))[0];
841
+ if (!readlinkPath) {
842
+ return this.createResult('readlink', '', 'readlink: missing operand', 1, 1);
843
+ }
844
+ const linkTarget = await this.fs.readlink(readlinkPath);
845
+ stdout = linkTarget + '\n';
846
+ break;
847
+ }
848
+ case 'ln': {
849
+ const lnSymbolic = args.includes('-s');
850
+ const lnPaths = args.filter(a => !a.startsWith('-'));
851
+ if (lnPaths.length < 2) {
852
+ return this.createResult('ln', '', 'ln: missing file operand', 1, 1);
853
+ }
854
+ const [lnTarget, lnPath] = lnPaths;
855
+ if (lnSymbolic) {
856
+ await this.fs.symlink(lnTarget, lnPath);
857
+ }
858
+ else {
859
+ await this.fs.link(lnTarget, lnPath);
860
+ }
861
+ break;
862
+ }
863
+ case 'chmod': {
864
+ const chmodNonFlags = args.filter(a => !a.startsWith('-'));
865
+ if (chmodNonFlags.length < 2) {
866
+ return this.createResult('chmod', '', 'chmod: missing operand', 1, 1);
867
+ }
868
+ const [chmodModeStr, chmodPath] = chmodNonFlags;
869
+ let chmodMode;
870
+ if (/^[0-7]+$/.test(chmodModeStr)) {
871
+ chmodMode = parseInt(chmodModeStr, 8);
872
+ }
873
+ else {
874
+ return this.createResult('chmod', '', 'chmod: symbolic modes not yet supported', 1, 1);
875
+ }
876
+ await this.fs.chmod(chmodPath, chmodMode);
877
+ break;
878
+ }
879
+ case 'chown': {
880
+ const chownNonFlags = args.filter(a => !a.startsWith('-'));
881
+ if (chownNonFlags.length < 2) {
882
+ return this.createResult('chown', '', 'chown: missing operand', 1, 1);
883
+ }
884
+ const [chownOwnerGroup, chownPath] = chownNonFlags;
885
+ const [chownUidStr, chownGidStr] = chownOwnerGroup.split(':');
886
+ const chownUid = parseInt(chownUidStr, 10) || 0;
887
+ const chownGid = chownGidStr ? parseInt(chownGidStr, 10) || 0 : chownUid;
888
+ await this.fs.chown(chownPath, chownUid, chownGid);
889
+ break;
890
+ }
891
+ case 'find': {
892
+ let findSearchPath = '.';
893
+ let findNamePattern = null;
894
+ let findTypeFilter = null;
895
+ for (let i = 0; i < args.length; i++) {
896
+ const arg = args[i];
897
+ if (arg === '-name' && args[i + 1]) {
898
+ findNamePattern = args[++i];
899
+ }
900
+ else if (arg === '-type' && args[i + 1]) {
901
+ findTypeFilter = args[++i];
902
+ }
903
+ else if (!arg.startsWith('-')) {
904
+ findSearchPath = arg;
905
+ }
906
+ }
907
+ const findEntries = await this.fs.list(findSearchPath, { recursive: true, withFileTypes: true });
908
+ const findResults = [];
909
+ for (const entry of findEntries) {
910
+ if (findTypeFilter === 'f' && !entry.isFile())
911
+ continue;
912
+ if (findTypeFilter === 'd' && !entry.isDirectory())
913
+ continue;
914
+ if (findNamePattern) {
915
+ const findGlobPattern = findNamePattern.replace(/\./g, '\\.').replace(/\*/g, '.*').replace(/\?/g, '.');
916
+ const findRegex = new RegExp(`^${findGlobPattern}$`);
917
+ if (!findRegex.test(entry.name))
918
+ continue;
919
+ }
920
+ findResults.push(entry.path || `${findSearchPath}/${entry.name}`);
921
+ }
922
+ stdout = findResults.join('\n') + (findResults.length ? '\n' : '');
923
+ break;
924
+ }
925
+ case 'grep': {
926
+ let grepIgnoreCase = false;
927
+ let grepShowLineNumbers = false;
928
+ let grepInvertMatch = false;
929
+ let grepRecursive = false;
930
+ let grepPerlRegex = false; // -P flag: use JavaScript regex (supports lookahead, non-greedy, etc.)
931
+ let grepPattern = '';
932
+ const grepFiles = [];
933
+ for (let i = 0; i < args.length; i++) {
934
+ const arg = args[i];
935
+ if (arg === '-i')
936
+ grepIgnoreCase = true;
937
+ else if (arg === '-n')
938
+ grepShowLineNumbers = true;
939
+ else if (arg === '-v')
940
+ grepInvertMatch = true;
941
+ else if (arg === '-r' || arg === '-R')
942
+ grepRecursive = true;
943
+ else if (arg === '-P')
944
+ grepPerlRegex = true; // Enable Perl-compatible regex (JavaScript regex)
945
+ else if (!arg.startsWith('-')) {
946
+ if (!grepPattern)
947
+ grepPattern = arg;
948
+ else
949
+ grepFiles.push(arg);
950
+ }
951
+ }
952
+ if (!grepPattern) {
953
+ return this.createResult('grep', '', 'grep: missing pattern', 1, 1);
954
+ }
955
+ // When -P is used, pattern is already JavaScript regex syntax
956
+ // When -P is not used, convert basic grep pattern to JavaScript regex
957
+ let grepRegexPattern = grepPattern;
958
+ if (!grepPerlRegex) {
959
+ // Basic grep uses BRE (Basic Regular Expression)
960
+ // In BRE, () {} + ? | need to be escaped to be special
961
+ // For simplicity, we treat the pattern as-is since JavaScript regex is close to ERE
962
+ grepRegexPattern = grepPattern;
963
+ }
964
+ const grepRegex = new RegExp(grepRegexPattern, grepIgnoreCase ? 'i' : '');
965
+ const grepResults = [];
966
+ let grepMatchFound = false;
967
+ const grepProcessFile = async (filePath) => {
968
+ const grepContent = await this.fs.read(filePath, { encoding: 'utf-8' });
969
+ const grepFileLines = grepContent.split('\n');
970
+ for (let lineNum = 0; lineNum < grepFileLines.length; lineNum++) {
971
+ const line = grepFileLines[lineNum];
972
+ const matches = grepRegex.test(line);
973
+ if (matches !== grepInvertMatch) {
974
+ grepMatchFound = true;
975
+ let output = '';
976
+ if (grepFiles.length > 1)
977
+ output += `${filePath}:`;
978
+ if (grepShowLineNumbers)
979
+ output += `${lineNum + 1}:`;
980
+ output += line;
981
+ grepResults.push(output);
982
+ }
983
+ }
984
+ };
985
+ if (grepFiles.length === 0) {
986
+ const grepInput = options?.stdin || '';
987
+ const grepInputLines = grepInput.split('\n');
988
+ for (let lineNum = 0; lineNum < grepInputLines.length; lineNum++) {
989
+ const line = grepInputLines[lineNum];
990
+ const matches = grepRegex.test(line);
991
+ if (matches !== grepInvertMatch) {
992
+ grepMatchFound = true;
993
+ let output = '';
994
+ if (grepShowLineNumbers)
995
+ output += `${lineNum + 1}:`;
996
+ output += line;
997
+ grepResults.push(output);
998
+ }
999
+ }
1000
+ }
1001
+ else {
1002
+ for (const file of grepFiles) {
1003
+ if (grepRecursive) {
1004
+ const grepFileStat = await this.fs.stat(file);
1005
+ if (grepFileStat.isDirectory()) {
1006
+ const grepDirEntries = await this.fs.list(file, { recursive: true, withFileTypes: true });
1007
+ for (const entry of grepDirEntries) {
1008
+ if (entry.isFile())
1009
+ await grepProcessFile(entry.path || `${file}/${entry.name}`);
1010
+ }
1011
+ }
1012
+ else {
1013
+ await grepProcessFile(file);
1014
+ }
1015
+ }
1016
+ else {
1017
+ await grepProcessFile(file);
1018
+ }
1019
+ }
1020
+ }
1021
+ stdout = grepResults.join('\n') + (grepResults.length ? '\n' : '');
1022
+ exitCode = grepMatchFound ? 0 : 1;
1023
+ break;
1024
+ }
1025
+ default:
1026
+ throw new Error(`Unsupported native fs command: ${cmd}`);
1027
+ }
1028
+ return this.createResult(`${cmd} ${args.join(' ')}`, stdout, stderr, exitCode, 1);
1029
+ }
1030
+ catch (error) {
1031
+ const message = error instanceof Error ? error.message : String(error);
1032
+ return this.createResult(`${cmd} ${args.join(' ')}`, '', message, 1, 1);
1033
+ }
1034
+ }
1035
+ /**
1036
+ * Execute pure computation commands natively
1037
+ */
1038
+ async executeNativeCompute(cmd, args, options) {
1039
+ let stdout = '';
1040
+ let exitCode = 0;
1041
+ switch (cmd) {
1042
+ case 'echo': {
1043
+ // Handle echo flags: -e (enable escapes), -n (no newline), -E (disable escapes)
1044
+ let enableEscapes = false;
1045
+ let addNewline = true;
1046
+ let startIdx = 0;
1047
+ // Parse flags
1048
+ for (let i = 0; i < args.length; i++) {
1049
+ if (args[i] === '-e') {
1050
+ enableEscapes = true;
1051
+ startIdx = i + 1;
1052
+ }
1053
+ else if (args[i] === '-n') {
1054
+ addNewline = false;
1055
+ startIdx = i + 1;
1056
+ }
1057
+ else if (args[i] === '-E') {
1058
+ enableEscapes = false;
1059
+ startIdx = i + 1;
1060
+ }
1061
+ else if (args[i] === '-en' || args[i] === '-ne') {
1062
+ enableEscapes = true;
1063
+ addNewline = false;
1064
+ startIdx = i + 1;
1065
+ }
1066
+ else {
1067
+ break;
1068
+ }
1069
+ }
1070
+ let output = args.slice(startIdx).join(' ');
1071
+ if (enableEscapes) {
1072
+ output = output
1073
+ .replace(/\\n/g, '\n')
1074
+ .replace(/\\t/g, '\t')
1075
+ .replace(/\\r/g, '\r')
1076
+ .replace(/\\a/g, '\x07')
1077
+ .replace(/\\b/g, '\b')
1078
+ .replace(/\\f/g, '\f')
1079
+ .replace(/\\v/g, '\v')
1080
+ .replace(/\\\\/g, '\\');
1081
+ }
1082
+ stdout = output + (addNewline ? '\n' : '');
1083
+ break;
1084
+ }
1085
+ case 'printf':
1086
+ // Simple printf implementation
1087
+ stdout = args.join(' ')
1088
+ .replace(/\\n/g, '\n')
1089
+ .replace(/\\t/g, '\t')
1090
+ .replace(/\\0/g, '\0') // Handle null characters
1091
+ .replace(/\\r/g, '\r');
1092
+ break;
1093
+ case 'pwd':
1094
+ stdout = (options?.cwd || process.cwd?.() || '/') + '\n';
1095
+ break;
1096
+ case 'date':
1097
+ stdout = new Date().toString() + '\n';
1098
+ break;
1099
+ case 'true':
1100
+ exitCode = 0;
1101
+ break;
1102
+ case 'false':
1103
+ exitCode = 1;
1104
+ break;
1105
+ case 'basename': {
1106
+ const path = args[0] || '';
1107
+ stdout = path.split('/').pop() || '';
1108
+ if (stdout)
1109
+ stdout += '\n';
1110
+ break;
1111
+ }
1112
+ case 'dirname': {
1113
+ const path = args[0] || '';
1114
+ const parts = path.split('/');
1115
+ parts.pop();
1116
+ stdout = (parts.join('/') || (path.startsWith('/') ? '/' : '.')) + '\n';
1117
+ break;
1118
+ }
1119
+ case 'wc': {
1120
+ // Count lines/words/chars from stdin or return empty
1121
+ const input = options?.stdin || '';
1122
+ const lines = input.split('\n').length - (input.endsWith('\n') ? 1 : 0);
1123
+ const words = input.split(/\s+/).filter(Boolean).length;
1124
+ const chars = input.length;
1125
+ if (args.includes('-l')) {
1126
+ stdout = `${lines}\n`;
1127
+ }
1128
+ else if (args.includes('-w')) {
1129
+ stdout = `${words}\n`;
1130
+ }
1131
+ else if (args.includes('-c')) {
1132
+ stdout = `${chars}\n`;
1133
+ }
1134
+ else {
1135
+ stdout = `${lines} ${words} ${chars}\n`;
1136
+ }
1137
+ break;
1138
+ }
1139
+ case 'sort': {
1140
+ const input = options?.stdin || '';
1141
+ const lines = input.split('\n').filter(Boolean);
1142
+ lines.sort();
1143
+ if (args.includes('-r'))
1144
+ lines.reverse();
1145
+ stdout = lines.join('\n') + (lines.length ? '\n' : '');
1146
+ break;
1147
+ }
1148
+ case 'uniq': {
1149
+ const input = options?.stdin || '';
1150
+ const lines = input.split('\n');
1151
+ const unique = lines.filter((line, i) => i === 0 || line !== lines[i - 1]);
1152
+ stdout = unique.join('\n');
1153
+ break;
1154
+ }
1155
+ case 'tr': {
1156
+ const input = options?.stdin || '';
1157
+ const set1 = args[0] || '';
1158
+ const set2 = args[1] || '';
1159
+ let result = input;
1160
+ for (let i = 0; i < set1.length && i < set2.length; i++) {
1161
+ result = result.replace(new RegExp(set1[i], 'g'), set2[i]);
1162
+ }
1163
+ stdout = result;
1164
+ break;
1165
+ }
1166
+ case 'rev': {
1167
+ const input = options?.stdin || '';
1168
+ stdout = input.split('\n').map(line => line.split('').reverse().join('')).join('\n');
1169
+ break;
1170
+ }
1171
+ case 'cut': {
1172
+ const input = options?.stdin || '';
1173
+ const delimiter = args.includes('-d') ? args[args.indexOf('-d') + 1] : '\t';
1174
+ const fieldArg = args.includes('-f') ? args[args.indexOf('-f') + 1] : '1';
1175
+ const field = parseInt(fieldArg, 10) - 1;
1176
+ stdout = input.split('\n').map(line => {
1177
+ const parts = line.split(delimiter);
1178
+ return parts[field] || '';
1179
+ }).join('\n');
1180
+ break;
1181
+ }
1182
+ // ========================================================================
1183
+ // MATH & CONTROL COMMANDS
1184
+ // ========================================================================
1185
+ case 'bc': {
1186
+ // bc receives expression from stdin (piped) or as a file/expression arg
1187
+ const input = options?.stdin || args.join(' ');
1188
+ const mathLib = args.includes('-l');
1189
+ const result = executeBc(input, { mathLib });
1190
+ stdout = result.result ? result.result + '\n' : '';
1191
+ exitCode = result.exitCode;
1192
+ if (result.stderr) {
1193
+ return this.createResult(`${cmd} ${args.join(' ')}`, stdout, result.stderr, exitCode, 1);
1194
+ }
1195
+ break;
1196
+ }
1197
+ case 'expr': {
1198
+ const result = executeExpr(args);
1199
+ stdout = result.result ? result.result + '\n' : '';
1200
+ exitCode = result.exitCode;
1201
+ if (result.stderr) {
1202
+ return this.createResult(`${cmd} ${args.join(' ')}`, stdout, result.stderr, exitCode, 1);
1203
+ }
1204
+ break;
1205
+ }
1206
+ case 'seq': {
1207
+ // Parse seq options: -s separator, -w equal-width, -f format
1208
+ const seqOptions = {};
1209
+ const numArgs = [];
1210
+ for (let i = 0; i < args.length; i++) {
1211
+ const arg = args[i];
1212
+ if (arg === '-s' && args[i + 1] !== undefined) {
1213
+ seqOptions.separator = args[++i].replace(/\\t/g, '\t').replace(/\\n/g, '\n');
1214
+ }
1215
+ else if (arg === '-w') {
1216
+ seqOptions.equalWidth = true;
1217
+ }
1218
+ else if (arg === '-f' && args[i + 1] !== undefined) {
1219
+ seqOptions.format = args[++i];
1220
+ }
1221
+ else if (!arg.startsWith('-') || /^-?\d/.test(arg)) {
1222
+ numArgs.push(parseFloat(arg));
1223
+ }
1224
+ }
1225
+ const result = executeSeq(numArgs, seqOptions);
1226
+ stdout = result.result ? result.result + '\n' : '';
1227
+ exitCode = result.exitCode;
1228
+ break;
1229
+ }
1230
+ case 'shuf': {
1231
+ // Parse shuf options
1232
+ const shufOptions = {};
1233
+ const input = options?.stdin || '';
1234
+ let inputLines = input.split('\n').filter(l => l.length > 0);
1235
+ for (let i = 0; i < args.length; i++) {
1236
+ const arg = args[i];
1237
+ if ((arg === '-n' || arg === '--head-count') && args[i + 1] !== undefined) {
1238
+ shufOptions.count = parseInt(args[++i], 10);
1239
+ }
1240
+ else if (arg.startsWith('--head-count=')) {
1241
+ shufOptions.count = parseInt(arg.slice(13), 10);
1242
+ }
1243
+ else if (arg === '-r' || arg === '--repeat') {
1244
+ shufOptions.replacement = true;
1245
+ }
1246
+ else if (arg === '-e' || arg === '--echo') {
1247
+ // Collect remaining args as echo args
1248
+ shufOptions.echoArgs = args.slice(i + 1).filter(a => !a.startsWith('-') || /^-?\d/.test(a));
1249
+ }
1250
+ else if (arg === '-i' && args[i + 1] !== undefined) {
1251
+ const range = args[++i];
1252
+ const [start, end] = range.split('-').map(Number);
1253
+ shufOptions.inputRange = { start, end };
1254
+ }
1255
+ else if (arg === '-o' && args[i + 1] !== undefined) {
1256
+ shufOptions.outputFile = args[++i];
1257
+ }
1258
+ else if (arg.startsWith('--random-source=') || arg === '--random-source') {
1259
+ shufOptions.randomSource = arg.includes('=') ? arg.split('=')[1] : args[++i];
1260
+ }
1261
+ }
1262
+ const result = executeShuf(inputLines, shufOptions);
1263
+ stdout = result.result ? result.result + '\n' : '';
1264
+ exitCode = result.exitCode;
1265
+ break;
1266
+ }
1267
+ case 'sleep': {
1268
+ if (args.length === 0) {
1269
+ return this.createResult('sleep', '', 'sleep: missing operand', 1, 1);
1270
+ }
1271
+ const result = await executeSleep(args);
1272
+ exitCode = result.exitCode;
1273
+ if (result.stderr) {
1274
+ return this.createResult(`${cmd} ${args.join(' ')}`, '', result.stderr, exitCode, 1);
1275
+ }
1276
+ break;
1277
+ }
1278
+ case 'timeout': {
1279
+ // Parse timeout options
1280
+ const timeoutOptions = { duration: '' };
1281
+ let commandStartIndex = -1;
1282
+ for (let i = 0; i < args.length; i++) {
1283
+ const arg = args[i];
1284
+ if (arg === '-k' && args[i + 1] !== undefined) {
1285
+ timeoutOptions.killAfter = args[++i];
1286
+ }
1287
+ else if (arg.startsWith('--kill-after=')) {
1288
+ timeoutOptions.killAfter = arg.slice(13);
1289
+ }
1290
+ else if (arg === '-s' && args[i + 1] !== undefined) {
1291
+ timeoutOptions.signal = args[++i];
1292
+ }
1293
+ else if (arg.startsWith('--signal=')) {
1294
+ timeoutOptions.signal = arg.slice(9);
1295
+ }
1296
+ else if (arg === '--preserve-status') {
1297
+ timeoutOptions.preserveStatus = true;
1298
+ }
1299
+ else if (arg === '--foreground') {
1300
+ timeoutOptions.foreground = true;
1301
+ }
1302
+ else if (arg === '-v' || arg === '--verbose') {
1303
+ timeoutOptions.verbose = true;
1304
+ }
1305
+ else if (!arg.startsWith('-') || /^[0-9.]/.test(arg)) {
1306
+ if (timeoutOptions.duration === '') {
1307
+ timeoutOptions.duration = arg;
1308
+ }
1309
+ else {
1310
+ commandStartIndex = i;
1311
+ break;
1312
+ }
1313
+ }
1314
+ }
1315
+ if (timeoutOptions.duration === '' || commandStartIndex < 0) {
1316
+ return this.createResult('timeout', '', 'timeout: missing operand', 125, 1);
1317
+ }
1318
+ const subCommand = args.slice(commandStartIndex).join(' ');
1319
+ // Check if the sub-command is a path to a non-existent command
1320
+ // (paths like /nonexistent/cmd are not supported natively)
1321
+ const firstWord = subCommand.trim().split(/\s+/)[0];
1322
+ if (firstWord.startsWith('/')) {
1323
+ // Full path command - not supported natively
1324
+ const notFoundResult = timeoutCommandNotFound(firstWord);
1325
+ return this.createResult(`timeout ${args.join(' ')}`, '', notFoundResult.stderr, notFoundResult.exitCode, 1);
1326
+ }
1327
+ // Execute with timeout
1328
+ const result = await executeTimeout(timeoutOptions, subCommand, async (cmd) => {
1329
+ const subResult = await this.execute(cmd, options);
1330
+ return {
1331
+ exitCode: subResult.exitCode,
1332
+ stdout: subResult.stdout,
1333
+ stderr: subResult.stderr,
1334
+ };
1335
+ });
1336
+ return this.createResult(`timeout ${args.join(' ')}`, result.stdout, result.stderr, result.exitCode, 1);
1337
+ }
1338
+ default:
1339
+ throw new Error(`Unsupported native compute command: ${cmd}`);
1340
+ }
1341
+ return this.createResult(`${cmd} ${args.join(' ')}`, stdout, '', exitCode, 1);
1342
+ }
1343
+ /**
1344
+ * Execute data processing commands (jq, yq, base64, envsubst)
1345
+ */
1346
+ async executeDataProcessing(cmd, args, fullCommand, options) {
1347
+ try {
1348
+ let stdout = '';
1349
+ const stderr = '';
1350
+ const exitCode = 0;
1351
+ switch (cmd) {
1352
+ case 'jq': {
1353
+ const { query, file, options: jqOptions } = parseJqArgs(args);
1354
+ // Get input from file or stdin
1355
+ let input;
1356
+ if (file) {
1357
+ if (this.fs) {
1358
+ input = (await this.fs.read(file, { encoding: 'utf-8' }));
1359
+ }
1360
+ else {
1361
+ throw new Error(`ENOENT: no such file: ${file}`);
1362
+ }
1363
+ }
1364
+ else if (options?.stdin) {
1365
+ input = options.stdin;
1366
+ }
1367
+ else {
1368
+ return this.createResult(fullCommand, '', 'jq: no input', 1, 1);
1369
+ }
1370
+ stdout = executeJq(query || '.', input, jqOptions);
1371
+ break;
1372
+ }
1373
+ case 'yq': {
1374
+ const { query, file, options: yqOptions } = parseYqArgs(args);
1375
+ // Get input from file or stdin
1376
+ let input;
1377
+ if (file) {
1378
+ if (this.fs) {
1379
+ input = (await this.fs.read(file, { encoding: 'utf-8' }));
1380
+ }
1381
+ else {
1382
+ throw new Error(`ENOENT: no such file: ${file}`);
1383
+ }
1384
+ }
1385
+ else if (options?.stdin) {
1386
+ input = options.stdin;
1387
+ }
1388
+ else {
1389
+ return this.createResult(fullCommand, '', 'yq: no input', 1, 1);
1390
+ }
1391
+ stdout = executeYq(query, input, yqOptions);
1392
+ break;
1393
+ }
1394
+ case 'base64': {
1395
+ const { file, options: b64Options } = parseBase64Args(args);
1396
+ // Get input from file or stdin
1397
+ let input;
1398
+ if (file) {
1399
+ if (this.fs) {
1400
+ input = (await this.fs.read(file, { encoding: 'utf-8' }));
1401
+ }
1402
+ else {
1403
+ throw new Error(`ENOENT: no such file: ${file}`);
1404
+ }
1405
+ }
1406
+ else if (options?.stdin !== undefined) {
1407
+ input = options.stdin;
1408
+ }
1409
+ else {
1410
+ // Default to empty for encode, error for decode
1411
+ if (b64Options.decode) {
1412
+ return this.createResult(fullCommand, '', 'base64: no input', 1, 1);
1413
+ }
1414
+ input = '';
1415
+ }
1416
+ stdout = executeBase64(input, b64Options);
1417
+ break;
1418
+ }
1419
+ case 'envsubst': {
1420
+ // Parse args and handle input redirect
1421
+ const { options: envOptions, inputRedirect } = parseEnvsubstArgs(args, options?.env || {});
1422
+ // Get input from redirect, stdin, or empty
1423
+ let input;
1424
+ if (inputRedirect) {
1425
+ if (this.fs) {
1426
+ input = (await this.fs.read(inputRedirect, { encoding: 'utf-8' }));
1427
+ }
1428
+ else {
1429
+ throw new Error(`ENOENT: no such file: ${inputRedirect}`);
1430
+ }
1431
+ }
1432
+ else if (options?.stdin !== undefined) {
1433
+ input = options.stdin;
1434
+ }
1435
+ else {
1436
+ input = '';
1437
+ }
1438
+ stdout = executeEnvsubst(input, envOptions);
1439
+ break;
1440
+ }
1441
+ default:
1442
+ throw new Error(`Unknown data processing command: ${cmd}`);
1443
+ }
1444
+ return this.createResult(fullCommand, stdout, stderr, exitCode, 1);
1445
+ }
1446
+ catch (error) {
1447
+ if (error instanceof JqError) {
1448
+ return this.createResult(fullCommand, '', `jq: ${error.message}`, error.exitCode, 1);
1449
+ }
1450
+ if (error instanceof Base64Error) {
1451
+ return this.createResult(fullCommand, '', `base64: ${error.message}`, 1, 1);
1452
+ }
1453
+ if (error instanceof EnvsubstError) {
1454
+ return this.createResult(fullCommand, '', `envsubst: ${error.message}`, 1, 1);
1455
+ }
1456
+ const message = error instanceof Error ? error.message : String(error);
1457
+ return this.createResult(fullCommand, '', message, 1, 1);
1458
+ }
1459
+ }
1460
+ /**
1461
+ * Execute curl command via native fetch() API
1462
+ *
1463
+ * Supports common curl flags:
1464
+ * - -X METHOD: HTTP method (GET, POST, PUT, DELETE, etc.)
1465
+ * - -H "Header: Value": Custom headers
1466
+ * - -d "data": Request body (implies POST if no -X specified)
1467
+ * - -o filename: Output to file
1468
+ * - -s: Silent mode (suppress progress)
1469
+ * - -L: Follow redirects
1470
+ * - -u user:pass: Basic authentication
1471
+ * - -I: HEAD request (headers only)
1472
+ * - --data-raw "data": Raw data without processing
1473
+ */
1474
+ async executeCurl(args) {
1475
+ let method = 'GET';
1476
+ let url = '';
1477
+ const headers = {};
1478
+ let body;
1479
+ let outputFile;
1480
+ let silent = false;
1481
+ let followRedirects = false;
1482
+ let headersOnly = false;
1483
+ let includeHeaders = false;
1484
+ for (let i = 0; i < args.length; i++) {
1485
+ const arg = args[i];
1486
+ if (arg === '-X' && args[i + 1]) {
1487
+ method = args[++i];
1488
+ }
1489
+ else if (arg === '-H' && args[i + 1]) {
1490
+ const headerValue = args[++i];
1491
+ const colonIndex = headerValue.indexOf(':');
1492
+ if (colonIndex > 0) {
1493
+ const key = headerValue.slice(0, colonIndex).trim();
1494
+ const val = headerValue.slice(colonIndex + 1).trim();
1495
+ headers[key] = val;
1496
+ }
1497
+ }
1498
+ else if ((arg === '-d' || arg === '--data' || arg === '--data-raw') && args[i + 1]) {
1499
+ body = args[++i];
1500
+ // -d implies POST if method wasn't explicitly set
1501
+ if (method === 'GET')
1502
+ method = 'POST';
1503
+ }
1504
+ else if (arg === '-o' && args[i + 1]) {
1505
+ outputFile = args[++i];
1506
+ }
1507
+ else if (arg === '-s' || arg === '--silent') {
1508
+ silent = true;
1509
+ }
1510
+ else if (arg === '-L' || arg === '--location') {
1511
+ followRedirects = true;
1512
+ }
1513
+ else if (arg === '-I' || arg === '--head') {
1514
+ headersOnly = true;
1515
+ method = 'HEAD';
1516
+ }
1517
+ else if (arg === '-i' || arg === '--include') {
1518
+ includeHeaders = true;
1519
+ }
1520
+ else if (arg === '-u' && args[i + 1]) {
1521
+ const credentials = args[++i];
1522
+ const encoded = btoa(credentials);
1523
+ headers['Authorization'] = `Basic ${encoded}`;
1524
+ }
1525
+ else if (!arg.startsWith('-') && !url) {
1526
+ url = arg;
1527
+ }
1528
+ }
1529
+ if (!url) {
1530
+ return this.createResult('curl', '', 'curl: no URL specified', 1, 1);
1531
+ }
1532
+ // Ensure URL has protocol
1533
+ if (!url.startsWith('http://') && !url.startsWith('https://')) {
1534
+ url = 'https://' + url;
1535
+ }
1536
+ try {
1537
+ const response = await fetch(url, {
1538
+ method,
1539
+ headers: Object.keys(headers).length > 0 ? headers : undefined,
1540
+ body,
1541
+ redirect: followRedirects ? 'follow' : 'manual',
1542
+ });
1543
+ let output = '';
1544
+ // Build headers string if needed
1545
+ if (headersOnly || includeHeaders) {
1546
+ const headerLines = [`HTTP/1.1 ${response.status} ${response.statusText}`];
1547
+ response.headers.forEach((value, key) => {
1548
+ headerLines.push(`${key}: ${value}`);
1549
+ });
1550
+ headerLines.push('');
1551
+ output = headerLines.join('\r\n');
1552
+ }
1553
+ // Get body content (unless HEAD request)
1554
+ if (!headersOnly) {
1555
+ const content = await response.text();
1556
+ output += content;
1557
+ }
1558
+ // Write to file if -o specified
1559
+ if (outputFile && this.fs) {
1560
+ await this.fs.write(outputFile, output);
1561
+ return this.createResult(`curl ${args.join(' ')}`, silent ? '' : '', '', 0, 1);
1562
+ }
1563
+ return this.createResult(`curl ${args.join(' ')}`, output, '', response.ok ? 0 : 1, 1);
1564
+ }
1565
+ catch (error) {
1566
+ const message = error instanceof Error ? error.message : String(error);
1567
+ return this.createResult(`curl ${args.join(' ')}`, '', `curl: ${message}`, 1, 1);
1568
+ }
1569
+ }
1570
+ /**
1571
+ * Execute wget command via native fetch() API
1572
+ *
1573
+ * Supports common wget flags:
1574
+ * - -O filename: Output to file (use "-" for stdout)
1575
+ * - -q: Quiet mode
1576
+ * - --header "Header: Value": Custom headers
1577
+ * - -S: Print server response headers
1578
+ * - --no-check-certificate: Skip SSL verification (ignored in fetch)
1579
+ */
1580
+ async executeWget(args) {
1581
+ let url = '';
1582
+ const headers = {};
1583
+ let outputFile;
1584
+ let quiet = false;
1585
+ let printHeaders = false;
1586
+ for (let i = 0; i < args.length; i++) {
1587
+ const arg = args[i];
1588
+ if (arg === '-O' && args[i + 1]) {
1589
+ outputFile = args[++i];
1590
+ }
1591
+ else if (arg === '-q' || arg === '--quiet') {
1592
+ quiet = true;
1593
+ }
1594
+ else if (arg === '--header' && args[i + 1]) {
1595
+ const headerValue = args[++i];
1596
+ const colonIndex = headerValue.indexOf(':');
1597
+ if (colonIndex > 0) {
1598
+ const key = headerValue.slice(0, colonIndex).trim();
1599
+ const val = headerValue.slice(colonIndex + 1).trim();
1600
+ headers[key] = val;
1601
+ }
1602
+ }
1603
+ else if (arg === '-S' || arg === '--server-response') {
1604
+ printHeaders = true;
1605
+ }
1606
+ else if (arg === '--no-check-certificate') {
1607
+ // Ignored - fetch handles SSL automatically
1608
+ }
1609
+ else if (!arg.startsWith('-') && !url) {
1610
+ url = arg;
1611
+ }
1612
+ }
1613
+ if (!url) {
1614
+ return this.createResult('wget', '', 'wget: missing URL', 1, 1);
1615
+ }
1616
+ // Ensure URL has protocol
1617
+ if (!url.startsWith('http://') && !url.startsWith('https://')) {
1618
+ url = 'https://' + url;
1619
+ }
1620
+ try {
1621
+ const response = await fetch(url, {
1622
+ method: 'GET',
1623
+ headers: Object.keys(headers).length > 0 ? headers : undefined,
1624
+ redirect: 'follow',
1625
+ });
1626
+ let stderr = '';
1627
+ // Print server response headers if -S
1628
+ if (printHeaders && !quiet) {
1629
+ const headerLines = [` HTTP/1.1 ${response.status} ${response.statusText}`];
1630
+ response.headers.forEach((value, key) => {
1631
+ headerLines.push(` ${key}: ${value}`);
1632
+ });
1633
+ stderr = headerLines.join('\n') + '\n';
1634
+ }
1635
+ const content = await response.text();
1636
+ // Determine output filename if not specified
1637
+ if (!outputFile) {
1638
+ // Extract filename from URL path
1639
+ const urlObj = new URL(url);
1640
+ const pathParts = urlObj.pathname.split('/');
1641
+ outputFile = pathParts[pathParts.length - 1] || 'index.html';
1642
+ }
1643
+ // Output to stdout if "-"
1644
+ if (outputFile === '-') {
1645
+ return this.createResult(`wget ${args.join(' ')}`, content, stderr, response.ok ? 0 : 1, 1);
1646
+ }
1647
+ // Write to file
1648
+ if (this.fs) {
1649
+ await this.fs.write(outputFile, content);
1650
+ const successMsg = quiet ? '' : `'${outputFile}' saved\n`;
1651
+ return this.createResult(`wget ${args.join(' ')}`, '', stderr + successMsg, 0, 1);
1652
+ }
1653
+ // No fs available, output to stdout
1654
+ return this.createResult(`wget ${args.join(' ')}`, content, stderr, response.ok ? 0 : 1, 1);
1655
+ }
1656
+ catch (error) {
1657
+ const message = error instanceof Error ? error.message : String(error);
1658
+ return this.createResult(`wget ${args.join(' ')}`, '', `wget: ${message}`, 1, 1);
1659
+ }
1660
+ }
1661
+ /**
1662
+ * Execute crypto commands via Web Crypto API (sha256sum, md5sum, uuidgen, etc.)
1663
+ */
1664
+ async executeNativeCrypto(cmd, args, options) {
1665
+ try {
1666
+ const result = await executeCryptoCommand(cmd, args, {
1667
+ fs: this.fs,
1668
+ stdin: options?.stdin,
1669
+ });
1670
+ return this.createResult(`${cmd} ${args.join(' ')}`, result.stdout, result.stderr, result.exitCode, 1);
1671
+ }
1672
+ catch (error) {
1673
+ const message = error instanceof Error ? error.message : String(error);
1674
+ return this.createResult(`${cmd} ${args.join(' ')}`, '', message, 1, 1);
1675
+ }
1676
+ }
1677
+ /**
1678
+ * Execute text processing commands (sed, awk, diff, patch, tee, xargs)
1679
+ */
1680
+ async executeTextProcessing(cmd, args, fullCommand, options) {
1681
+ try {
1682
+ const input = options?.stdin || '';
1683
+ switch (cmd) {
1684
+ case 'sed': {
1685
+ // For sed, we need to get file content if a file is specified
1686
+ const files = args.filter(a => !a.startsWith('-') && !a.startsWith('s/') && !a.startsWith("'") && !a.startsWith('"'));
1687
+ let content = input;
1688
+ if (files.length > 0 && this.fs) {
1689
+ content = await this.fs.read(files[files.length - 1], { encoding: 'utf-8' });
1690
+ }
1691
+ const result = executeSed(args, content, this.fs);
1692
+ return this.createResult(fullCommand, result.stdout, result.stderr, result.exitCode, 1);
1693
+ }
1694
+ case 'awk': {
1695
+ // For awk, get file content if specified
1696
+ let content = input;
1697
+ // Skip the first non-flag arg which is usually the program
1698
+ const nonFlagArgs = args.filter(a => !a.startsWith('-'));
1699
+ if (nonFlagArgs.length > 1 && this.fs) {
1700
+ // Last arg is file
1701
+ content = await this.fs.read(nonFlagArgs[nonFlagArgs.length - 1], { encoding: 'utf-8' });
1702
+ }
1703
+ const result = executeAwk(args, content);
1704
+ return this.createResult(fullCommand, result.stdout, result.stderr, result.exitCode, 1);
1705
+ }
1706
+ case 'diff': {
1707
+ // diff requires two file contents
1708
+ const diffFiles = args.filter(a => !a.startsWith('-'));
1709
+ if (diffFiles.length >= 2 && this.fs) {
1710
+ const file1Content = await this.fs.read(diffFiles[0], { encoding: 'utf-8' });
1711
+ const file2Content = await this.fs.read(diffFiles[1], { encoding: 'utf-8' });
1712
+ const unified = args.includes('-u') || args.includes('--unified');
1713
+ const context = args.includes('-c') || args.includes('--context');
1714
+ const result = executeDiff(file1Content, file2Content, diffFiles[0], diffFiles[1], { unified, context });
1715
+ return this.createResult(fullCommand, result.stdout, result.stderr, result.exitCode, 1);
1716
+ }
1717
+ return this.createResult(fullCommand, '', 'diff: missing operand', 1, 1);
1718
+ }
1719
+ case 'patch': {
1720
+ // patch applies a diff to a file
1721
+ const reverse = args.includes('-R') || args.includes('--reverse');
1722
+ const dryRun = args.includes('--dry-run');
1723
+ let stripLevel = 0;
1724
+ const stripArg = args.find(a => a.startsWith('-p'));
1725
+ if (stripArg) {
1726
+ stripLevel = parseInt(stripArg.slice(2), 10);
1727
+ }
1728
+ // Input is the patch content - parse it to find target file
1729
+ const patchContent = input;
1730
+ const fileMatch = patchContent.match(/^---\s+(\S+)/m);
1731
+ const newFileMatch = patchContent.match(/^\+\+\+\s+(\S+)/m);
1732
+ let targetFile = newFileMatch?.[1] || fileMatch?.[1] || '';
1733
+ // Strip prefix from target file
1734
+ if (stripLevel > 0 && targetFile) {
1735
+ const parts = targetFile.split('/');
1736
+ targetFile = parts.slice(stripLevel).join('/');
1737
+ }
1738
+ // Resolve relative path against cwd if not absolute
1739
+ const cwd = options?.cwd || '/test';
1740
+ if (!targetFile.startsWith('/') && cwd) {
1741
+ targetFile = `${cwd.replace(/\/$/, '')}/${targetFile}`;
1742
+ }
1743
+ // Read original file content
1744
+ let originalContent = '';
1745
+ if (targetFile && this.fs) {
1746
+ try {
1747
+ originalContent = await this.fs.read(targetFile, { encoding: 'utf-8' });
1748
+ }
1749
+ catch {
1750
+ // File might not exist, continue with empty
1751
+ }
1752
+ }
1753
+ const result = executePatch(originalContent, patchContent, { reverse, dryRun, stripLevel });
1754
+ // Write result back to file if not dry run and successful
1755
+ if (!dryRun && result.exitCode === 0 && result.result && targetFile && this.fs) {
1756
+ await this.fs.write(targetFile, result.result);
1757
+ }
1758
+ return this.createResult(fullCommand, result.stdout, result.stderr, result.exitCode, 1);
1759
+ }
1760
+ case 'tee': {
1761
+ const result = await executeTee(input, args, this.fs);
1762
+ return this.createResult(fullCommand, result.stdout, result.stderr, result.exitCode, 1);
1763
+ }
1764
+ case 'xargs': {
1765
+ const result = await executeXargs(input, args, async (cmd) => {
1766
+ const subResult = await this.execute(cmd, options);
1767
+ return {
1768
+ stdout: subResult.stdout,
1769
+ stderr: subResult.stderr,
1770
+ exitCode: subResult.exitCode,
1771
+ };
1772
+ });
1773
+ return this.createResult(fullCommand, result.stdout, result.stderr, result.exitCode, 1);
1774
+ }
1775
+ default:
1776
+ throw new Error(`Unsupported text processing command: ${cmd}`);
1777
+ }
1778
+ }
1779
+ catch (error) {
1780
+ const message = error instanceof Error ? error.message : String(error);
1781
+ return this.createResult(fullCommand, '', message, 1, 1);
1782
+ }
1783
+ }
1784
+ /**
1785
+ * Execute POSIX utility commands (cut, sort, tr, uniq, wc, basename, dirname, echo, printf, date, dd, od)
1786
+ */
1787
+ async executePosixUtils(cmd, args, fullCommand, options) {
1788
+ try {
1789
+ const input = options?.stdin || '';
1790
+ switch (cmd) {
1791
+ case 'cut': {
1792
+ // Parse cut options
1793
+ const cutOptions = {};
1794
+ for (let i = 0; i < args.length; i++) {
1795
+ const arg = args[i];
1796
+ if (arg === '-b' && args[i + 1]) {
1797
+ cutOptions.bytes = args[++i];
1798
+ }
1799
+ else if (arg.startsWith('-b')) {
1800
+ cutOptions.bytes = arg.slice(2);
1801
+ }
1802
+ else if (arg === '-c' && args[i + 1]) {
1803
+ cutOptions.chars = args[++i];
1804
+ }
1805
+ else if (arg.startsWith('-c')) {
1806
+ cutOptions.chars = arg.slice(2);
1807
+ }
1808
+ else if (arg === '-f' && args[i + 1]) {
1809
+ cutOptions.fields = args[++i];
1810
+ }
1811
+ else if (arg.startsWith('-f')) {
1812
+ cutOptions.fields = arg.slice(2);
1813
+ }
1814
+ else if (arg === '-d' && args[i + 1]) {
1815
+ cutOptions.delimiter = args[++i];
1816
+ }
1817
+ else if (arg.startsWith('-d')) {
1818
+ cutOptions.delimiter = arg.slice(2);
1819
+ }
1820
+ else if (arg === '--output-delimiter' && args[i + 1]) {
1821
+ cutOptions.outputDelimiter = args[++i];
1822
+ }
1823
+ else if (arg === '-s' || arg === '--only-delimited') {
1824
+ cutOptions.onlyDelimited = true;
1825
+ }
1826
+ else if (arg === '--complement') {
1827
+ cutOptions.complement = true;
1828
+ }
1829
+ }
1830
+ const stdout = executeCut(input, cutOptions);
1831
+ return this.createResult(fullCommand, stdout, '', 0, 1);
1832
+ }
1833
+ case 'sort': {
1834
+ // Parse sort options
1835
+ const sortOptions = {};
1836
+ for (let i = 0; i < args.length; i++) {
1837
+ const arg = args[i];
1838
+ if (arg === '-n' || arg === '--numeric-sort') {
1839
+ sortOptions.numeric = true;
1840
+ }
1841
+ else if (arg === '-r' || arg === '--reverse') {
1842
+ sortOptions.reverse = true;
1843
+ }
1844
+ else if (arg === '-u' || arg === '--unique') {
1845
+ sortOptions.unique = true;
1846
+ }
1847
+ else if (arg === '-f' || arg === '--ignore-case') {
1848
+ sortOptions.ignoreCase = true;
1849
+ }
1850
+ else if (arg === '-b' || arg === '--ignore-leading-blanks') {
1851
+ sortOptions.ignoreLeadingBlanks = true;
1852
+ }
1853
+ else if (arg === '-h' || arg === '--human-numeric-sort') {
1854
+ sortOptions.humanNumeric = true;
1855
+ }
1856
+ else if (arg === '-c' || arg === '--check') {
1857
+ sortOptions.check = true;
1858
+ }
1859
+ else if (arg === '-k' && args[i + 1]) {
1860
+ sortOptions.key = args[++i];
1861
+ }
1862
+ else if (arg.startsWith('-k')) {
1863
+ sortOptions.key = arg.slice(2);
1864
+ }
1865
+ else if (arg === '-t' && args[i + 1]) {
1866
+ sortOptions.separator = args[++i];
1867
+ }
1868
+ else if (arg.startsWith('-t')) {
1869
+ sortOptions.separator = arg.slice(2);
1870
+ }
1871
+ }
1872
+ const lines = input.split('\n').filter((l, i, arr) => i < arr.length - 1 || l !== '');
1873
+ const sorted = executeSort(lines, sortOptions);
1874
+ const stdout = sorted.join('\n') + (sorted.length > 0 ? '\n' : '');
1875
+ return this.createResult(fullCommand, stdout, '', 0, 1);
1876
+ }
1877
+ case 'tr': {
1878
+ // Parse tr options
1879
+ const trOptions = {};
1880
+ let set1 = '';
1881
+ let set2;
1882
+ const nonFlagArgs = [];
1883
+ for (let i = 0; i < args.length; i++) {
1884
+ const arg = args[i];
1885
+ if (arg === '-d' || arg === '--delete') {
1886
+ trOptions.delete = true;
1887
+ }
1888
+ else if (arg === '-s' || arg === '--squeeze-repeats') {
1889
+ trOptions.squeeze = true;
1890
+ }
1891
+ else if (arg === '-c' || arg === '-C' || arg === '--complement') {
1892
+ trOptions.complement = true;
1893
+ }
1894
+ else if (!arg.startsWith('-')) {
1895
+ nonFlagArgs.push(arg);
1896
+ }
1897
+ }
1898
+ set1 = nonFlagArgs[0] || '';
1899
+ set2 = nonFlagArgs[1];
1900
+ const stdout = executeTr(input, set1, set2, trOptions);
1901
+ return this.createResult(fullCommand, stdout, '', 0, 1);
1902
+ }
1903
+ case 'uniq': {
1904
+ // Parse uniq options
1905
+ const uniqOptions = {};
1906
+ for (let i = 0; i < args.length; i++) {
1907
+ const arg = args[i];
1908
+ if (arg === '-c' || arg === '--count') {
1909
+ uniqOptions.count = true;
1910
+ }
1911
+ else if (arg === '-d' || arg === '--repeated') {
1912
+ uniqOptions.repeated = true;
1913
+ }
1914
+ else if (arg === '-u' || arg === '--unique') {
1915
+ uniqOptions.unique = true;
1916
+ }
1917
+ else if (arg === '-i' || arg === '--ignore-case') {
1918
+ uniqOptions.ignoreCase = true;
1919
+ }
1920
+ else if (arg === '-f' && args[i + 1]) {
1921
+ uniqOptions.skipFields = parseInt(args[++i], 10);
1922
+ }
1923
+ else if (arg.startsWith('-f')) {
1924
+ uniqOptions.skipFields = parseInt(arg.slice(2), 10);
1925
+ }
1926
+ else if (arg === '-s' && args[i + 1]) {
1927
+ uniqOptions.skipChars = parseInt(args[++i], 10);
1928
+ }
1929
+ else if (arg.startsWith('-s')) {
1930
+ uniqOptions.skipChars = parseInt(arg.slice(2), 10);
1931
+ }
1932
+ }
1933
+ const lines = input.split('\n').filter((l, i, arr) => i < arr.length - 1 || l !== '');
1934
+ const unique = executeUniq(lines, uniqOptions);
1935
+ const stdout = unique.join('\n') + (unique.length > 0 ? '\n' : '');
1936
+ return this.createResult(fullCommand, stdout, '', 0, 1);
1937
+ }
1938
+ case 'wc': {
1939
+ // Parse wc options
1940
+ const wcOptions = {};
1941
+ let hasOptions = false;
1942
+ for (const arg of args) {
1943
+ if (arg === '-l' || arg === '--lines') {
1944
+ wcOptions.lines = true;
1945
+ hasOptions = true;
1946
+ }
1947
+ else if (arg === '-w' || arg === '--words') {
1948
+ wcOptions.words = true;
1949
+ hasOptions = true;
1950
+ }
1951
+ else if (arg === '-c' || arg === '--bytes') {
1952
+ wcOptions.bytes = true;
1953
+ hasOptions = true;
1954
+ }
1955
+ else if (arg === '-m' || arg === '--chars') {
1956
+ wcOptions.chars = true;
1957
+ hasOptions = true;
1958
+ }
1959
+ }
1960
+ const result = executeWc(input, wcOptions);
1961
+ // Format output like GNU wc
1962
+ let stdout = '';
1963
+ if (!hasOptions) {
1964
+ // Default: lines, words, bytes
1965
+ stdout = `${result.lines} ${result.words} ${result.bytes}\n`;
1966
+ }
1967
+ else {
1968
+ const parts = [];
1969
+ if (wcOptions.lines)
1970
+ parts.push(result.lines);
1971
+ if (wcOptions.words)
1972
+ parts.push(result.words);
1973
+ if (wcOptions.bytes)
1974
+ parts.push(result.bytes);
1975
+ if (wcOptions.chars)
1976
+ parts.push(result.chars);
1977
+ stdout = parts.join(' ') + '\n';
1978
+ }
1979
+ return this.createResult(fullCommand, stdout, '', 0, 1);
1980
+ }
1981
+ case 'basename': {
1982
+ const path = args.find(a => !a.startsWith('-')) || '';
1983
+ const suffix = args.filter(a => !a.startsWith('-'))[1];
1984
+ const stdout = executeBasename(path, suffix) + '\n';
1985
+ return this.createResult(fullCommand, stdout, '', 0, 1);
1986
+ }
1987
+ case 'dirname': {
1988
+ const path = args.find(a => !a.startsWith('-')) || '';
1989
+ const stdout = executeDirname(path) + '\n';
1990
+ return this.createResult(fullCommand, stdout, '', 0, 1);
1991
+ }
1992
+ case 'echo': {
1993
+ // Parse echo options
1994
+ const echoOptions = {};
1995
+ let startIdx = 0;
1996
+ for (let i = 0; i < args.length; i++) {
1997
+ if (args[i] === '-n') {
1998
+ echoOptions.noNewline = true;
1999
+ startIdx = i + 1;
2000
+ }
2001
+ else if (args[i] === '-e') {
2002
+ echoOptions.interpretEscapes = true;
2003
+ startIdx = i + 1;
2004
+ }
2005
+ else if (args[i] === '-E') {
2006
+ echoOptions.interpretEscapes = false;
2007
+ startIdx = i + 1;
2008
+ }
2009
+ else if (args[i] === '-en' || args[i] === '-ne') {
2010
+ echoOptions.noNewline = true;
2011
+ echoOptions.interpretEscapes = true;
2012
+ startIdx = i + 1;
2013
+ }
2014
+ else {
2015
+ break;
2016
+ }
2017
+ }
2018
+ const stdout = executeEcho(args.slice(startIdx), echoOptions);
2019
+ return this.createResult(fullCommand, stdout, '', 0, 1);
2020
+ }
2021
+ case 'printf': {
2022
+ if (args.length === 0) {
2023
+ return this.createResult(fullCommand, '', '', 0, 1);
2024
+ }
2025
+ const format = args[0];
2026
+ const formatArgs = args.slice(1);
2027
+ const stdout = executePrintf(format, formatArgs);
2028
+ return this.createResult(fullCommand, stdout, '', 0, 1);
2029
+ }
2030
+ case 'date': {
2031
+ // Parse date options
2032
+ const dateOptions = {};
2033
+ let format;
2034
+ for (let i = 0; i < args.length; i++) {
2035
+ const arg = args[i];
2036
+ if (arg === '-u' || arg === '--utc' || arg === '--universal') {
2037
+ dateOptions.utc = true;
2038
+ }
2039
+ else if (arg === '-d' && args[i + 1]) {
2040
+ dateOptions.date = args[++i];
2041
+ }
2042
+ else if (arg.startsWith('--date=')) {
2043
+ dateOptions.date = arg.slice(7);
2044
+ }
2045
+ else if (arg.startsWith('+')) {
2046
+ format = arg;
2047
+ }
2048
+ }
2049
+ const stdout = executeDate(format, dateOptions) + '\n';
2050
+ return this.createResult(fullCommand, stdout, '', 0, 1);
2051
+ }
2052
+ case 'dd': {
2053
+ // Parse dd options (dd uses operand=value format)
2054
+ const ddOptions = {};
2055
+ let inputFile;
2056
+ let outputFile;
2057
+ let convOptions = [];
2058
+ for (const arg of args) {
2059
+ if (arg.startsWith('bs=')) {
2060
+ ddOptions.bs = parseInt(arg.slice(3), 10);
2061
+ }
2062
+ else if (arg.startsWith('count=')) {
2063
+ ddOptions.count = parseInt(arg.slice(6), 10);
2064
+ }
2065
+ else if (arg.startsWith('skip=')) {
2066
+ ddOptions.skip = parseInt(arg.slice(5), 10);
2067
+ }
2068
+ else if (arg.startsWith('seek=')) {
2069
+ ddOptions.seek = parseInt(arg.slice(5), 10);
2070
+ }
2071
+ else if (arg.startsWith('ibs=')) {
2072
+ ddOptions.ibs = parseInt(arg.slice(4), 10);
2073
+ }
2074
+ else if (arg.startsWith('obs=')) {
2075
+ ddOptions.obs = parseInt(arg.slice(4), 10);
2076
+ }
2077
+ else if (arg.startsWith('if=')) {
2078
+ inputFile = arg.slice(3);
2079
+ }
2080
+ else if (arg.startsWith('of=')) {
2081
+ outputFile = arg.slice(3);
2082
+ }
2083
+ else if (arg.startsWith('conv=')) {
2084
+ convOptions = arg.slice(5).split(',');
2085
+ }
2086
+ }
2087
+ // Get input data from file or stdin
2088
+ let inputData;
2089
+ if (inputFile) {
2090
+ if (!this.fs) {
2091
+ return this.createResult(fullCommand, '', 'dd: no filesystem capability for if=', 1, 1);
2092
+ }
2093
+ try {
2094
+ const content = await this.fs.read(inputFile);
2095
+ inputData = typeof content === 'string' ? new TextEncoder().encode(content) : content;
2096
+ }
2097
+ catch (e) {
2098
+ return this.createResult(fullCommand, '', `dd: ${inputFile}: No such file or directory`, 1, 1);
2099
+ }
2100
+ }
2101
+ else {
2102
+ inputData = new TextEncoder().encode(input);
2103
+ }
2104
+ // Execute dd
2105
+ let outputData = executeDd(inputData, ddOptions);
2106
+ // Apply conv options
2107
+ if (convOptions.includes('ucase')) {
2108
+ const text = new TextDecoder().decode(outputData);
2109
+ outputData = new TextEncoder().encode(text.toUpperCase());
2110
+ }
2111
+ if (convOptions.includes('lcase')) {
2112
+ const text = new TextDecoder().decode(outputData);
2113
+ outputData = new TextEncoder().encode(text.toLowerCase());
2114
+ }
2115
+ // Calculate stats for stderr
2116
+ const bs = ddOptions.bs || 512;
2117
+ const recordsIn = Math.ceil(inputData.length / bs);
2118
+ const recordsOut = Math.ceil(outputData.length / bs);
2119
+ const stderr = `${recordsIn}+0 records in\n${recordsOut}+0 records out\n${outputData.length} bytes copied`;
2120
+ // Write output to file or stdout
2121
+ if (outputFile) {
2122
+ if (!this.fs) {
2123
+ return this.createResult(fullCommand, '', 'dd: no filesystem capability for of=', 1, 1);
2124
+ }
2125
+ await this.fs.write(outputFile, outputData);
2126
+ return this.createResult(fullCommand, '', stderr, 0, 1);
2127
+ }
2128
+ const stdout = new TextDecoder().decode(outputData);
2129
+ return this.createResult(fullCommand, stdout, stderr, 0, 1);
2130
+ }
2131
+ case 'od': {
2132
+ // Parse od options
2133
+ const odOptions = {};
2134
+ for (let i = 0; i < args.length; i++) {
2135
+ const arg = args[i];
2136
+ if (arg === '-A' && args[i + 1]) {
2137
+ odOptions.addressFormat = args[++i];
2138
+ }
2139
+ else if (arg.startsWith('-A')) {
2140
+ odOptions.addressFormat = arg.slice(2);
2141
+ }
2142
+ else if (arg === '-t' && args[i + 1]) {
2143
+ odOptions.format = args[++i];
2144
+ }
2145
+ else if (arg.startsWith('-t')) {
2146
+ odOptions.format = arg.slice(2);
2147
+ }
2148
+ else if (arg === '-x') {
2149
+ odOptions.format = 'x';
2150
+ }
2151
+ else if (arg === '-c') {
2152
+ odOptions.format = 'c';
2153
+ }
2154
+ else if (arg === '-d') {
2155
+ odOptions.format = 'd';
2156
+ }
2157
+ else if (arg === '-o') {
2158
+ odOptions.format = 'o';
2159
+ }
2160
+ else if (arg === '-w' && args[i + 1]) {
2161
+ odOptions.width = parseInt(args[++i], 10);
2162
+ }
2163
+ else if (arg.startsWith('-w')) {
2164
+ odOptions.width = parseInt(arg.slice(2), 10);
2165
+ }
2166
+ else if (arg === '-j' && args[i + 1]) {
2167
+ odOptions.skip = parseInt(args[++i], 10);
2168
+ }
2169
+ else if (arg.startsWith('-j')) {
2170
+ odOptions.skip = parseInt(arg.slice(2), 10);
2171
+ }
2172
+ else if (arg === '-N' && args[i + 1]) {
2173
+ odOptions.count = parseInt(args[++i], 10);
2174
+ }
2175
+ else if (arg.startsWith('-N')) {
2176
+ odOptions.count = parseInt(arg.slice(2), 10);
2177
+ }
2178
+ }
2179
+ const inputData = new TextEncoder().encode(input);
2180
+ const stdout = executeOd(inputData, odOptions);
2181
+ return this.createResult(fullCommand, stdout, '', 0, 1);
2182
+ }
2183
+ default:
2184
+ throw new Error(`Unsupported POSIX utility command: ${cmd}`);
2185
+ }
2186
+ }
2187
+ catch (error) {
2188
+ const message = error instanceof Error ? error.message : String(error);
2189
+ return this.createResult(fullCommand, '', message, 1, 1);
2190
+ }
2191
+ }
2192
+ /**
2193
+ * Execute system utility commands (yes, whoami, hostname, printenv)
2194
+ */
2195
+ async executeSystemUtilsCommands(cmd, args, fullCommand, options) {
2196
+ try {
2197
+ // Build context from execution options
2198
+ const context = {
2199
+ cwd: options?.cwd,
2200
+ env: options?.env,
2201
+ stdin: options?.stdin,
2202
+ };
2203
+ switch (cmd) {
2204
+ case 'yes': {
2205
+ // Parse yes options (there are none in standard yes)
2206
+ // Limit to 1000 lines for safety in non-streaming environment
2207
+ const result = executeYes(args, { maxLines: 1000 });
2208
+ return this.createResult(fullCommand, result.stdout, result.stderr, result.exitCode, 1);
2209
+ }
2210
+ case 'whoami': {
2211
+ const result = executeWhoami(args, context);
2212
+ return this.createResult(fullCommand, result.stdout, result.stderr, result.exitCode, 1);
2213
+ }
2214
+ case 'hostname': {
2215
+ const result = executeHostname(args, context);
2216
+ return this.createResult(fullCommand, result.stdout, result.stderr, result.exitCode, 1);
2217
+ }
2218
+ case 'printenv': {
2219
+ // Parse printenv options
2220
+ const printenvOpts = {
2221
+ null: args.includes('-0') || args.includes('--null'),
2222
+ };
2223
+ const varArgs = args.filter(a => a !== '-0' && a !== '--null');
2224
+ const result = executePrintenv(varArgs, context, printenvOpts);
2225
+ return this.createResult(fullCommand, result.stdout, result.stderr, result.exitCode, 1);
2226
+ }
2227
+ default:
2228
+ throw new Error(`Unsupported system utility command: ${cmd}`);
2229
+ }
2230
+ }
2231
+ catch (error) {
2232
+ const message = error instanceof Error ? error.message : String(error);
2233
+ return this.createResult(fullCommand, '', message, 1, 1);
2234
+ }
2235
+ }
2236
+ /**
2237
+ * Execute extended utility commands (env, id, uname, tac)
2238
+ */
2239
+ async executeExtendedUtilsCommands(cmd, args, fullCommand, options) {
2240
+ try {
2241
+ switch (cmd) {
2242
+ case 'env': {
2243
+ const envArgs = parseEnvArgs(args);
2244
+ const baseEnv = options?.env ?? {};
2245
+ const result = executeEnv(baseEnv, envArgs);
2246
+ if (result.command && result.command.length > 0) {
2247
+ // Execute the command with the modified environment
2248
+ const cmdToRun = result.command.join(' ');
2249
+ return this.execute(cmdToRun, { ...options, env: result.env });
2250
+ }
2251
+ // No command - print the environment
2252
+ const output = formatEnv(result.env);
2253
+ return this.createResult(fullCommand, output, '', 0, 1);
2254
+ }
2255
+ case 'id': {
2256
+ const idArgs = parseIdArgs(args);
2257
+ // Use worker identity (could be configurable in future)
2258
+ const output = executeId(DEFAULT_WORKER_IDENTITY, idArgs);
2259
+ return this.createResult(fullCommand, output + '\n', '', 0, 1);
2260
+ }
2261
+ case 'uname': {
2262
+ const unameArgs = parseUnameArgs(args);
2263
+ // Use worker system info (could be configurable in future)
2264
+ const output = executeUname(DEFAULT_WORKER_SYSINFO, unameArgs);
2265
+ return this.createResult(fullCommand, output + '\n', '', 0, 1);
2266
+ }
2267
+ case 'tac': {
2268
+ const { options: tacOptions, files } = parseTacArgs(args);
2269
+ // Get input - from files or stdin
2270
+ let input;
2271
+ if (files.length > 0 && this.fs) {
2272
+ // Read from files
2273
+ const contents = [];
2274
+ for (const file of files) {
2275
+ const content = await this.fs.read(file, { encoding: 'utf-8' });
2276
+ contents.push(content);
2277
+ }
2278
+ input = contents.join('');
2279
+ }
2280
+ else {
2281
+ // Use stdin
2282
+ input = options?.stdin ?? '';
2283
+ }
2284
+ const output = executeTac(input, tacOptions);
2285
+ return this.createResult(fullCommand, output, '', 0, 1);
2286
+ }
2287
+ default:
2288
+ throw new Error(`Unsupported extended utility command: ${cmd}`);
2289
+ }
2290
+ }
2291
+ catch (error) {
2292
+ const message = error instanceof Error ? error.message : String(error);
2293
+ return this.createResult(fullCommand, '', message, 1, 1);
2294
+ }
2295
+ }
2296
+ /**
2297
+ * Tier 2: Execute command via RPC service
2298
+ */
2299
+ async executeTier2(command, classification, options) {
2300
+ const serviceName = classification.capability;
2301
+ if (!serviceName) {
2302
+ throw new Error('No RPC service specified for Tier 2 execution');
2303
+ }
2304
+ const binding = this.rpcBindings[serviceName];
2305
+ if (!binding) {
2306
+ throw new Error(`RPC binding not found: ${serviceName}`);
2307
+ }
2308
+ try {
2309
+ const endpoint = typeof binding.endpoint === 'string'
2310
+ ? binding.endpoint
2311
+ : null;
2312
+ if (!endpoint) {
2313
+ // Use the binding's fetch method directly
2314
+ const fetcher = binding.endpoint;
2315
+ const response = await fetcher.fetch('/', {
2316
+ method: 'POST',
2317
+ headers: { 'Content-Type': 'application/json' },
2318
+ body: JSON.stringify({
2319
+ command,
2320
+ cwd: options?.cwd,
2321
+ env: options?.env,
2322
+ timeout: options?.timeout ?? this.defaultTimeout,
2323
+ }),
2324
+ });
2325
+ if (!response.ok) {
2326
+ const errorText = await response.text();
2327
+ return this.createResult(command, '', `RPC error: ${errorText}`, 1, 2);
2328
+ }
2329
+ const result = await response.json();
2330
+ return this.createResult(command, result.stdout, result.stderr, result.exitCode, 2);
2331
+ }
2332
+ // Make HTTP request to RPC endpoint
2333
+ const response = await fetch(`${endpoint}/execute`, {
2334
+ method: 'POST',
2335
+ headers: { 'Content-Type': 'application/json' },
2336
+ body: JSON.stringify({
2337
+ command,
2338
+ cwd: options?.cwd,
2339
+ env: options?.env,
2340
+ timeout: options?.timeout ?? this.defaultTimeout,
2341
+ }),
2342
+ });
2343
+ if (!response.ok) {
2344
+ const errorText = await response.text();
2345
+ return this.createResult(command, '', `RPC error: ${errorText}`, 1, 2);
2346
+ }
2347
+ const result = await response.json();
2348
+ return this.createResult(command, result.stdout, result.stderr, result.exitCode, 2);
2349
+ }
2350
+ catch (error) {
2351
+ const message = error instanceof Error ? error.message : String(error);
2352
+ throw new Error(`Tier 2 RPC execution failed: ${message}`);
2353
+ }
2354
+ }
2355
+ /**
2356
+ * Tier 3: Execute via worker_loaders (dynamic npm modules)
2357
+ */
2358
+ async executeTier3(command, classification, options) {
2359
+ const moduleName = classification.capability;
2360
+ if (!moduleName) {
2361
+ throw new Error('No module specified for Tier 3 execution');
2362
+ }
2363
+ const loader = this.workerLoaders[moduleName];
2364
+ if (!loader) {
2365
+ throw new Error(`Worker loader not found: ${moduleName}`);
2366
+ }
2367
+ try {
2368
+ // Load the module dynamically
2369
+ const module = await loader.load(moduleName);
2370
+ // Execute command based on module type
2371
+ // This is a simplified implementation - real implementation would
2372
+ // need to know how to invoke each module's CLI
2373
+ const result = await this.executeLoadedModule(module, command, options);
2374
+ return this.createResult(command, result.stdout, result.stderr, result.exitCode, 3);
2375
+ }
2376
+ catch (error) {
2377
+ const message = error instanceof Error ? error.message : String(error);
2378
+ throw new Error(`Tier 3 worker loader execution failed: ${message}`);
2379
+ }
2380
+ }
2381
+ /**
2382
+ * Execute a dynamically loaded module
2383
+ */
2384
+ async executeLoadedModule(module, command, _options) {
2385
+ // This is a placeholder for module-specific execution logic
2386
+ // Real implementation would handle each module type appropriately
2387
+ const cmd = this.extractCommandName(command);
2388
+ const args = this.extractArgs(command);
2389
+ // Check if module has a CLI-like interface
2390
+ const mod = module;
2391
+ // Try common patterns for CLI modules
2392
+ if (typeof mod.run === 'function') {
2393
+ const result = await mod.run(args);
2394
+ return { stdout: String(result), stderr: '', exitCode: 0 };
2395
+ }
2396
+ if (typeof mod.main === 'function') {
2397
+ const result = await mod.main(args);
2398
+ return { stdout: String(result), stderr: '', exitCode: 0 };
2399
+ }
2400
+ if (typeof mod.default === 'function') {
2401
+ const result = await mod.default(args);
2402
+ return { stdout: String(result), stderr: '', exitCode: 0 };
2403
+ }
2404
+ throw new Error(`Module ${cmd} does not have a callable interface`);
2405
+ }
2406
+ /**
2407
+ * Tier 4: Execute via Sandbox SDK
2408
+ */
2409
+ async executeTier4(command, _classification, options) {
2410
+ if (!this.sandbox) {
2411
+ throw new Error('Sandbox not configured. Tier 4 execution requires a sandbox binding.');
2412
+ }
2413
+ const result = await this.sandbox.execute(command, options);
2414
+ // Add tier info to result
2415
+ return {
2416
+ ...result,
2417
+ classification: {
2418
+ ...result.classification,
2419
+ reason: `${result.classification.reason} (Tier 4: Sandbox)`,
2420
+ },
2421
+ };
2422
+ }
2423
+ // ============================================================================
2424
+ // HELPER METHODS
2425
+ // ============================================================================
2426
+ /**
2427
+ * Extract command name from a full command string
2428
+ */
2429
+ extractCommandName(command) {
2430
+ const trimmed = command.trim();
2431
+ // Handle env vars prefix: VAR=value cmd
2432
+ const withoutEnvVars = trimmed.replace(/^(\w+=\S+\s+)+/, '');
2433
+ // Get first word
2434
+ const match = withoutEnvVars.match(/^[\w\-\.\/]+/);
2435
+ if (!match)
2436
+ return '';
2437
+ // Handle path: /usr/bin/cmd -> cmd
2438
+ const name = match[0].split('/').pop() || '';
2439
+ return name;
2440
+ }
2441
+ /**
2442
+ * Extract arguments from a full command string
2443
+ */
2444
+ extractArgs(command) {
2445
+ const trimmed = command.trim();
2446
+ // Remove env vars prefix
2447
+ const withoutEnvVars = trimmed.replace(/^(\w+=\S+\s+)+/, '');
2448
+ // Split by whitespace, respecting quotes
2449
+ const parts = this.tokenize(withoutEnvVars);
2450
+ // Skip the command name
2451
+ return parts.slice(1);
2452
+ }
2453
+ /**
2454
+ * Tokenize command respecting quotes and escape sequences
2455
+ */
2456
+ tokenize(input) {
2457
+ const tokens = [];
2458
+ let current = '';
2459
+ let inSingleQuote = false;
2460
+ let inDoubleQuote = false;
2461
+ for (let i = 0; i < input.length; i++) {
2462
+ const char = input[i];
2463
+ // Handle escape sequences in double quotes
2464
+ if (char === '\\' && inDoubleQuote && i + 1 < input.length) {
2465
+ const nextChar = input[i + 1];
2466
+ // Keep the escape sequence for later processing
2467
+ current += char + nextChar;
2468
+ i++; // Skip the escaped character
2469
+ continue;
2470
+ }
2471
+ if (char === "'" && !inDoubleQuote) {
2472
+ inSingleQuote = !inSingleQuote;
2473
+ current += char;
2474
+ }
2475
+ else if (char === '"' && !inSingleQuote) {
2476
+ inDoubleQuote = !inDoubleQuote;
2477
+ current += char;
2478
+ }
2479
+ else if (/\s/.test(char) && !inSingleQuote && !inDoubleQuote) {
2480
+ if (current) {
2481
+ tokens.push(this.stripQuotes(current));
2482
+ current = '';
2483
+ }
2484
+ }
2485
+ else {
2486
+ current += char;
2487
+ }
2488
+ }
2489
+ if (current) {
2490
+ tokens.push(this.stripQuotes(current));
2491
+ }
2492
+ return tokens;
2493
+ }
2494
+ /**
2495
+ * Strip outer quotes from a string and unescape inner quotes
2496
+ */
2497
+ stripQuotes(s) {
2498
+ if (s.startsWith('"') && s.endsWith('"')) {
2499
+ // Remove outer double quotes and unescape inner escaped quotes
2500
+ return s.slice(1, -1).replace(/\\"/g, '"');
2501
+ }
2502
+ if (s.startsWith("'") && s.endsWith("'")) {
2503
+ // Remove outer single quotes (no escaping in single quotes)
2504
+ return s.slice(1, -1);
2505
+ }
2506
+ return s;
2507
+ }
2508
+ /**
2509
+ * Check if a command can use a worker loader
2510
+ */
2511
+ matchWorkerLoader(command) {
2512
+ const cmd = this.extractCommandName(command);
2513
+ // Check if we have a loader for this command
2514
+ for (const [name, loader] of Object.entries(this.workerLoaders)) {
2515
+ if (loader.modules.includes(cmd)) {
2516
+ return name;
2517
+ }
2518
+ }
2519
+ // Check if it's a known loadable module
2520
+ if (TIER_3_LOADABLE_MODULES.has(cmd)) {
2521
+ return cmd;
2522
+ }
2523
+ return null;
2524
+ }
2525
+ /**
2526
+ * Create a BashResult with tier information
2527
+ */
2528
+ createResult(command, stdout, stderr, exitCode, tier) {
2529
+ return {
2530
+ input: command,
2531
+ command,
2532
+ valid: true,
2533
+ generated: false,
2534
+ stdout,
2535
+ stderr,
2536
+ exitCode,
2537
+ intent: {
2538
+ commands: [this.extractCommandName(command)],
2539
+ reads: [],
2540
+ writes: [],
2541
+ deletes: [],
2542
+ network: false,
2543
+ elevated: false,
2544
+ },
2545
+ classification: {
2546
+ type: 'execute',
2547
+ impact: 'none',
2548
+ reversible: true,
2549
+ reason: `Executed via Tier ${tier}`,
2550
+ },
2551
+ };
2552
+ }
2553
+ // ============================================================================
2554
+ // UTILITY METHODS
2555
+ // ============================================================================
2556
+ /**
2557
+ * Get tier capabilities summary
2558
+ */
2559
+ getCapabilities() {
2560
+ return {
2561
+ tier1: {
2562
+ available: true, // Always available for pure compute
2563
+ commands: Array.from(TIER_1_NATIVE_COMMANDS),
2564
+ },
2565
+ tier2: {
2566
+ available: Object.keys(this.rpcBindings).length > 0,
2567
+ services: Object.keys(this.rpcBindings),
2568
+ },
2569
+ tier3: {
2570
+ available: Object.keys(this.workerLoaders).length > 0,
2571
+ loaders: Object.keys(this.workerLoaders),
2572
+ },
2573
+ tier4: {
2574
+ available: this.sandbox !== undefined,
2575
+ },
2576
+ };
2577
+ }
2578
+ /**
2579
+ * Check if a specific tier is available for a command
2580
+ */
2581
+ isTierAvailable(tier, command) {
2582
+ switch (tier) {
2583
+ case 1:
2584
+ if (!command)
2585
+ return true;
2586
+ const cmd1 = this.extractCommandName(command);
2587
+ if (TIER_1_FS_COMMANDS.has(cmd1))
2588
+ return this.fs !== undefined;
2589
+ return TIER_1_NATIVE_COMMANDS.has(cmd1);
2590
+ case 2:
2591
+ if (!command)
2592
+ return Object.keys(this.rpcBindings).length > 0;
2593
+ const cmd2 = this.extractCommandName(command);
2594
+ return Object.values(this.rpcBindings).some(b => b.commands.includes(cmd2));
2595
+ case 3:
2596
+ if (!command)
2597
+ return Object.keys(this.workerLoaders).length > 0;
2598
+ return this.matchWorkerLoader(command) !== null;
2599
+ case 4:
2600
+ return this.sandbox !== undefined;
2601
+ default:
2602
+ return false;
2603
+ }
2604
+ }
2605
+ }
2606
+ // ============================================================================
2607
+ // FACTORY FUNCTIONS
2608
+ // ============================================================================
2609
+ /**
2610
+ * Create a TieredExecutor from environment bindings.
2611
+ *
2612
+ * @param env - Worker environment with bindings
2613
+ * @param options - Additional configuration options
2614
+ * @returns Configured TieredExecutor
2615
+ *
2616
+ * @example
2617
+ * ```typescript
2618
+ * // In your Worker
2619
+ * export default {
2620
+ * async fetch(request: Request, env: Env) {
2621
+ * const executor = createTieredExecutor(env, {
2622
+ * rpcBindings: {
2623
+ * jq: { endpoint: env.JQ_SERVICE, commands: ['jq'] },
2624
+ * },
2625
+ * sandbox: {
2626
+ * execute: async (cmd, opts) => containerExecutor.run(cmd, opts),
2627
+ * },
2628
+ * })
2629
+ *
2630
+ * // Commands are auto-routed to the best tier
2631
+ * const result = await executor.execute('echo hello')
2632
+ * return new Response(result.stdout)
2633
+ * }
2634
+ * }
2635
+ * ```
2636
+ */
2637
+ export function createTieredExecutor(_env, options) {
2638
+ return new TieredExecutor({
2639
+ fs: options?.fs,
2640
+ rpcBindings: options?.rpcBindings,
2641
+ workerLoaders: options?.workerLoaders,
2642
+ sandbox: options?.sandbox,
2643
+ defaultTimeout: options?.defaultTimeout,
2644
+ preferFaster: options?.preferFaster,
2645
+ });
2646
+ }
2647
+ //# sourceMappingURL=tiered-executor.js.map