@soederpop/luca 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 (358) hide show
  1. package/CLAUDE.md +71 -0
  2. package/README.md +78 -0
  3. package/bun.lock +2928 -0
  4. package/bunfig.toml +3 -0
  5. package/commands/audit-docs.ts +740 -0
  6. package/commands/build-scaffolds.ts +154 -0
  7. package/commands/generate-api-docs.ts +114 -0
  8. package/commands/update-introspection.ts +67 -0
  9. package/docs/CLI.md +335 -0
  10. package/docs/README.md +88 -0
  11. package/docs/TABLE-OF-CONTENTS.md +157 -0
  12. package/docs/apis/clients/elevenlabs.md +84 -0
  13. package/docs/apis/clients/graph.md +56 -0
  14. package/docs/apis/clients/openai.md +69 -0
  15. package/docs/apis/clients/rest.md +41 -0
  16. package/docs/apis/clients/websocket.md +107 -0
  17. package/docs/apis/features/agi/assistant.md +471 -0
  18. package/docs/apis/features/agi/assistants-manager.md +154 -0
  19. package/docs/apis/features/agi/claude-code.md +602 -0
  20. package/docs/apis/features/agi/conversation-history.md +352 -0
  21. package/docs/apis/features/agi/conversation.md +333 -0
  22. package/docs/apis/features/agi/docs-reader.md +121 -0
  23. package/docs/apis/features/agi/openai-codex.md +318 -0
  24. package/docs/apis/features/agi/openapi.md +138 -0
  25. package/docs/apis/features/agi/semantic-search.md +387 -0
  26. package/docs/apis/features/agi/skills-library.md +216 -0
  27. package/docs/apis/features/node/container-link.md +133 -0
  28. package/docs/apis/features/node/content-db.md +313 -0
  29. package/docs/apis/features/node/disk-cache.md +379 -0
  30. package/docs/apis/features/node/dns.md +651 -0
  31. package/docs/apis/features/node/docker.md +705 -0
  32. package/docs/apis/features/node/downloader.md +81 -0
  33. package/docs/apis/features/node/esbuild.md +59 -0
  34. package/docs/apis/features/node/file-manager.md +182 -0
  35. package/docs/apis/features/node/fs.md +581 -0
  36. package/docs/apis/features/node/git.md +330 -0
  37. package/docs/apis/features/node/google-auth.md +174 -0
  38. package/docs/apis/features/node/google-calendar.md +187 -0
  39. package/docs/apis/features/node/google-docs.md +151 -0
  40. package/docs/apis/features/node/google-drive.md +225 -0
  41. package/docs/apis/features/node/google-sheets.md +179 -0
  42. package/docs/apis/features/node/grep.md +290 -0
  43. package/docs/apis/features/node/helpers.md +135 -0
  44. package/docs/apis/features/node/ink.md +334 -0
  45. package/docs/apis/features/node/ipc-socket.md +260 -0
  46. package/docs/apis/features/node/json-tree.md +86 -0
  47. package/docs/apis/features/node/launcher-app-command-listener.md +145 -0
  48. package/docs/apis/features/node/networking.md +281 -0
  49. package/docs/apis/features/node/nlp.md +133 -0
  50. package/docs/apis/features/node/opener.md +97 -0
  51. package/docs/apis/features/node/os.md +118 -0
  52. package/docs/apis/features/node/package-finder.md +402 -0
  53. package/docs/apis/features/node/postgres.md +212 -0
  54. package/docs/apis/features/node/proc.md +430 -0
  55. package/docs/apis/features/node/process-manager.md +210 -0
  56. package/docs/apis/features/node/python.md +278 -0
  57. package/docs/apis/features/node/repl.md +88 -0
  58. package/docs/apis/features/node/runpod.md +673 -0
  59. package/docs/apis/features/node/secure-shell.md +169 -0
  60. package/docs/apis/features/node/semantic-search.md +401 -0
  61. package/docs/apis/features/node/sqlite.md +211 -0
  62. package/docs/apis/features/node/telegram.md +254 -0
  63. package/docs/apis/features/node/tts.md +118 -0
  64. package/docs/apis/features/node/ui.md +703 -0
  65. package/docs/apis/features/node/vault.md +64 -0
  66. package/docs/apis/features/node/vm.md +84 -0
  67. package/docs/apis/features/node/window-manager.md +337 -0
  68. package/docs/apis/features/node/yaml-tree.md +85 -0
  69. package/docs/apis/features/node/yaml.md +176 -0
  70. package/docs/apis/features/web/asset-loader.md +47 -0
  71. package/docs/apis/features/web/container-link.md +133 -0
  72. package/docs/apis/features/web/esbuild.md +59 -0
  73. package/docs/apis/features/web/helpers.md +135 -0
  74. package/docs/apis/features/web/network.md +30 -0
  75. package/docs/apis/features/web/speech.md +55 -0
  76. package/docs/apis/features/web/vault.md +64 -0
  77. package/docs/apis/features/web/vm.md +84 -0
  78. package/docs/apis/features/web/voice.md +67 -0
  79. package/docs/apis/servers/express.md +127 -0
  80. package/docs/apis/servers/mcp.md +213 -0
  81. package/docs/apis/servers/websocket.md +99 -0
  82. package/docs/documentation-audit.md +134 -0
  83. package/docs/examples/content-db.md +77 -0
  84. package/docs/examples/disk-cache.md +83 -0
  85. package/docs/examples/docker.md +101 -0
  86. package/docs/examples/downloader.md +70 -0
  87. package/docs/examples/esbuild.md +80 -0
  88. package/docs/examples/file-manager.md +82 -0
  89. package/docs/examples/fs.md +83 -0
  90. package/docs/examples/git.md +85 -0
  91. package/docs/examples/google-auth.md +88 -0
  92. package/docs/examples/google-calendar.md +94 -0
  93. package/docs/examples/google-docs.md +82 -0
  94. package/docs/examples/google-drive.md +96 -0
  95. package/docs/examples/google-sheets.md +95 -0
  96. package/docs/examples/grep.md +85 -0
  97. package/docs/examples/ink-blocks.md +75 -0
  98. package/docs/examples/ink-renderer.md +41 -0
  99. package/docs/examples/ink.md +103 -0
  100. package/docs/examples/ipc-socket.md +103 -0
  101. package/docs/examples/json-tree.md +91 -0
  102. package/docs/examples/launcher-app-command-listener.md +120 -0
  103. package/docs/examples/networking.md +58 -0
  104. package/docs/examples/nlp.md +91 -0
  105. package/docs/examples/opener.md +78 -0
  106. package/docs/examples/os.md +72 -0
  107. package/docs/examples/package-finder.md +89 -0
  108. package/docs/examples/port-exposer.md +89 -0
  109. package/docs/examples/postgres.md +91 -0
  110. package/docs/examples/proc.md +81 -0
  111. package/docs/examples/process-manager.md +79 -0
  112. package/docs/examples/python.md +91 -0
  113. package/docs/examples/repl.md +93 -0
  114. package/docs/examples/runpod.md +119 -0
  115. package/docs/examples/secure-shell.md +92 -0
  116. package/docs/examples/sqlite.md +86 -0
  117. package/docs/examples/telegram.md +77 -0
  118. package/docs/examples/tts.md +86 -0
  119. package/docs/examples/ui.md +80 -0
  120. package/docs/examples/vault.md +70 -0
  121. package/docs/examples/vm.md +86 -0
  122. package/docs/examples/window-manager.md +125 -0
  123. package/docs/examples/yaml-tree.md +93 -0
  124. package/docs/examples/yaml.md +104 -0
  125. package/docs/ideas/class-registration-refactor-possibilities.md +197 -0
  126. package/docs/ideas/container-use-api.md +9 -0
  127. package/docs/ideas/easy-auth-for-express-servers-and-luca-serve.md +0 -0
  128. package/docs/ideas/feature-stacks.md +22 -0
  129. package/docs/ideas/luca-cli-self-sufficiency-demo.md +23 -0
  130. package/docs/ideas/mcp-design.md +9 -0
  131. package/docs/ideas/web-container-debugging-feature.md +13 -0
  132. package/docs/introspection-audit.md +49 -0
  133. package/docs/introspection.md +154 -0
  134. package/docs/mcp/readme.md +162 -0
  135. package/docs/models.ts +38 -0
  136. package/docs/philosophy.md +85 -0
  137. package/docs/principles.md +7 -0
  138. package/docs/prompts/audit-codebase-for-failures-to-use-the-container.md +34 -0
  139. package/docs/prompts/mcp-test-easy-command.md +27 -0
  140. package/docs/reports/assistant-bugs.md +38 -0
  141. package/docs/reports/attach-pattern-usage.md +18 -0
  142. package/docs/reports/code-audit-results.md +391 -0
  143. package/docs/reports/introspection-audit-tasks.md +378 -0
  144. package/docs/reports/luca-mcp-improvements.md +128 -0
  145. package/docs/scaffolds/client.md +140 -0
  146. package/docs/scaffolds/command.md +106 -0
  147. package/docs/scaffolds/endpoint.md +176 -0
  148. package/docs/scaffolds/feature.md +148 -0
  149. package/docs/scaffolds/server.md +187 -0
  150. package/docs/tasks/web-container-helper-discovery.md +71 -0
  151. package/docs/todos.md +1 -0
  152. package/docs/tutorials/01-getting-started.md +106 -0
  153. package/docs/tutorials/02-container.md +210 -0
  154. package/docs/tutorials/03-scripts.md +194 -0
  155. package/docs/tutorials/04-features-overview.md +196 -0
  156. package/docs/tutorials/05-state-and-events.md +171 -0
  157. package/docs/tutorials/06-servers.md +157 -0
  158. package/docs/tutorials/07-endpoints.md +198 -0
  159. package/docs/tutorials/08-commands.md +171 -0
  160. package/docs/tutorials/09-clients.md +162 -0
  161. package/docs/tutorials/10-creating-features.md +198 -0
  162. package/docs/tutorials/11-contentbase.md +191 -0
  163. package/docs/tutorials/12-assistants.md +215 -0
  164. package/docs/tutorials/13-introspection.md +147 -0
  165. package/docs/tutorials/14-type-system.md +174 -0
  166. package/docs/tutorials/15-project-patterns.md +222 -0
  167. package/docs/tutorials/16-google-features.md +534 -0
  168. package/docs/tutorials/17-tui-blocks.md +530 -0
  169. package/docs/tutorials/18-semantic-search.md +334 -0
  170. package/index.ts +1 -0
  171. package/luca.console.ts +9 -0
  172. package/main.py +6 -0
  173. package/package.json +154 -0
  174. package/pyproject.toml +7 -0
  175. package/scripts/animations/chrome-glitch.ts +55 -0
  176. package/scripts/animations/index.ts +16 -0
  177. package/scripts/animations/neon-pulse.ts +64 -0
  178. package/scripts/animations/types.ts +6 -0
  179. package/scripts/build-web.ts +28 -0
  180. package/scripts/examples/ask-luca-expert.ts +42 -0
  181. package/scripts/examples/assistant-questions.ts +12 -0
  182. package/scripts/examples/excalidraw-expert.ts +75 -0
  183. package/scripts/examples/expert-chat.ts +0 -0
  184. package/scripts/examples/file-manager.ts +14 -0
  185. package/scripts/examples/ideas.ts +12 -0
  186. package/scripts/examples/interactive-chat.ts +20 -0
  187. package/scripts/examples/openai-tool-calls.ts +113 -0
  188. package/scripts/examples/opening-a-web-browser.ts +5 -0
  189. package/scripts/examples/telegram-bot.ts +79 -0
  190. package/scripts/examples/telegram-ink-ui.ts +302 -0
  191. package/scripts/examples/using-assistant-with-mcp.ts +560 -0
  192. package/scripts/examples/using-claude-code.ts +10 -0
  193. package/scripts/examples/using-contentdb.ts +35 -0
  194. package/scripts/examples/using-conversations.ts +35 -0
  195. package/scripts/examples/using-disk-cache.ts +10 -0
  196. package/scripts/examples/using-docker-shell.ts +75 -0
  197. package/scripts/examples/using-elevenlabs.ts +25 -0
  198. package/scripts/examples/using-google-calendar.ts +57 -0
  199. package/scripts/examples/using-google-docs.ts +74 -0
  200. package/scripts/examples/using-google-drive.ts +74 -0
  201. package/scripts/examples/using-google-sheets.ts +89 -0
  202. package/scripts/examples/using-nlp.ts +55 -0
  203. package/scripts/examples/using-ollama.ts +10 -0
  204. package/scripts/examples/using-openai-codex.ts +23 -0
  205. package/scripts/examples/using-postgres.ts +55 -0
  206. package/scripts/examples/using-runpod.ts +32 -0
  207. package/scripts/examples/using-tts.ts +40 -0
  208. package/scripts/examples/vm-loading-esm-modules.ts +16 -0
  209. package/scripts/scaffold.ts +391 -0
  210. package/scripts/scratch.ts +15 -0
  211. package/scripts/test-command-listener.ts +123 -0
  212. package/scripts/test-window-manager-lifecycle.ts +86 -0
  213. package/scripts/test-window-manager.ts +43 -0
  214. package/scripts/update-introspection-data.ts +58 -0
  215. package/src/agi/README.md +14 -0
  216. package/src/agi/container.server.ts +114 -0
  217. package/src/agi/endpoints/ask.ts +60 -0
  218. package/src/agi/endpoints/conversations/[id].ts +45 -0
  219. package/src/agi/endpoints/conversations.ts +31 -0
  220. package/src/agi/endpoints/experts.ts +37 -0
  221. package/src/agi/features/assistant.ts +767 -0
  222. package/src/agi/features/assistants-manager.ts +260 -0
  223. package/src/agi/features/claude-code.ts +1111 -0
  224. package/src/agi/features/conversation-history.ts +497 -0
  225. package/src/agi/features/conversation.ts +799 -0
  226. package/src/agi/features/openai-codex.ts +631 -0
  227. package/src/agi/features/openapi.ts +438 -0
  228. package/src/agi/features/skills-library.ts +425 -0
  229. package/src/agi/index.ts +6 -0
  230. package/src/agi/lib/token-counter.ts +122 -0
  231. package/src/browser.ts +25 -0
  232. package/src/bus.ts +100 -0
  233. package/src/cli/cli.ts +70 -0
  234. package/src/client.ts +461 -0
  235. package/src/clients/civitai/index.ts +541 -0
  236. package/src/clients/client-template.ts +41 -0
  237. package/src/clients/comfyui/index.ts +597 -0
  238. package/src/clients/elevenlabs/index.ts +291 -0
  239. package/src/clients/openai/index.ts +451 -0
  240. package/src/clients/supabase/index.ts +366 -0
  241. package/src/command.ts +164 -0
  242. package/src/commands/chat.ts +182 -0
  243. package/src/commands/console.ts +192 -0
  244. package/src/commands/describe.ts +433 -0
  245. package/src/commands/eval.ts +116 -0
  246. package/src/commands/help.ts +214 -0
  247. package/src/commands/index.ts +14 -0
  248. package/src/commands/mcp.ts +64 -0
  249. package/src/commands/prompt.ts +807 -0
  250. package/src/commands/run.ts +257 -0
  251. package/src/commands/sandbox-mcp.ts +439 -0
  252. package/src/commands/scaffold.ts +79 -0
  253. package/src/commands/serve.ts +172 -0
  254. package/src/container.ts +781 -0
  255. package/src/endpoint.ts +340 -0
  256. package/src/feature.ts +75 -0
  257. package/src/hash-object.ts +97 -0
  258. package/src/helper.ts +543 -0
  259. package/src/introspection/generated.agi.ts +23388 -0
  260. package/src/introspection/generated.node.ts +18899 -0
  261. package/src/introspection/generated.web.ts +2021 -0
  262. package/src/introspection/index.ts +256 -0
  263. package/src/introspection/scan.ts +912 -0
  264. package/src/node/container.ts +354 -0
  265. package/src/node/feature.ts +13 -0
  266. package/src/node/features/container-link.ts +558 -0
  267. package/src/node/features/content-db.ts +475 -0
  268. package/src/node/features/disk-cache.ts +382 -0
  269. package/src/node/features/dns.ts +655 -0
  270. package/src/node/features/docker.ts +912 -0
  271. package/src/node/features/downloader.ts +92 -0
  272. package/src/node/features/esbuild.ts +68 -0
  273. package/src/node/features/file-manager.ts +357 -0
  274. package/src/node/features/fs.ts +534 -0
  275. package/src/node/features/git.ts +492 -0
  276. package/src/node/features/google-auth.ts +502 -0
  277. package/src/node/features/google-calendar.ts +300 -0
  278. package/src/node/features/google-docs.ts +404 -0
  279. package/src/node/features/google-drive.ts +339 -0
  280. package/src/node/features/google-sheets.ts +279 -0
  281. package/src/node/features/grep.ts +406 -0
  282. package/src/node/features/helpers.ts +374 -0
  283. package/src/node/features/ink.ts +490 -0
  284. package/src/node/features/ipc-socket.ts +459 -0
  285. package/src/node/features/json-tree.ts +188 -0
  286. package/src/node/features/launcher-app-command-listener.ts +388 -0
  287. package/src/node/features/networking.ts +925 -0
  288. package/src/node/features/nlp.ts +211 -0
  289. package/src/node/features/opener.ts +166 -0
  290. package/src/node/features/os.ts +157 -0
  291. package/src/node/features/package-finder.ts +539 -0
  292. package/src/node/features/port-exposer.ts +342 -0
  293. package/src/node/features/postgres.ts +273 -0
  294. package/src/node/features/proc.ts +502 -0
  295. package/src/node/features/process-manager.ts +542 -0
  296. package/src/node/features/python.ts +444 -0
  297. package/src/node/features/repl.ts +194 -0
  298. package/src/node/features/runpod.ts +802 -0
  299. package/src/node/features/secure-shell.ts +248 -0
  300. package/src/node/features/semantic-search.ts +924 -0
  301. package/src/node/features/sqlite.ts +289 -0
  302. package/src/node/features/telegram.ts +342 -0
  303. package/src/node/features/tts.ts +184 -0
  304. package/src/node/features/ui.ts +857 -0
  305. package/src/node/features/vault.ts +164 -0
  306. package/src/node/features/vm.ts +312 -0
  307. package/src/node/features/window-manager.ts +804 -0
  308. package/src/node/features/yaml-tree.ts +149 -0
  309. package/src/node/features/yaml.ts +132 -0
  310. package/src/node.ts +70 -0
  311. package/src/react/index.ts +175 -0
  312. package/src/registry.ts +199 -0
  313. package/src/scaffolds/generated.ts +1613 -0
  314. package/src/scaffolds/template.ts +37 -0
  315. package/src/schemas/base.ts +255 -0
  316. package/src/server.ts +135 -0
  317. package/src/servers/express.ts +209 -0
  318. package/src/servers/mcp.ts +805 -0
  319. package/src/servers/socket.ts +120 -0
  320. package/src/state.ts +101 -0
  321. package/src/web/clients/socket.ts +82 -0
  322. package/src/web/container.ts +74 -0
  323. package/src/web/extension.ts +30 -0
  324. package/src/web/feature.ts +12 -0
  325. package/src/web/features/asset-loader.ts +64 -0
  326. package/src/web/features/container-link.ts +385 -0
  327. package/src/web/features/esbuild.ts +79 -0
  328. package/src/web/features/helpers.ts +267 -0
  329. package/src/web/features/network.ts +61 -0
  330. package/src/web/features/speech.ts +87 -0
  331. package/src/web/features/vault.ts +189 -0
  332. package/src/web/features/vm.ts +78 -0
  333. package/src/web/features/voice-recognition.ts +129 -0
  334. package/src/web/shims/isomorphic-vm.ts +149 -0
  335. package/test/bus.test.ts +134 -0
  336. package/test/clients-servers.test.ts +216 -0
  337. package/test/container-link.test.ts +274 -0
  338. package/test/features.test.ts +160 -0
  339. package/test/integration.test.ts +787 -0
  340. package/test/node-container.test.ts +121 -0
  341. package/test/rate-limit.test.ts +272 -0
  342. package/test/semantic-search.test.ts +550 -0
  343. package/test/state.test.ts +121 -0
  344. package/test-integration/assistant.test.ts +138 -0
  345. package/test-integration/assistants-manager.test.ts +123 -0
  346. package/test-integration/claude-code.test.ts +98 -0
  347. package/test-integration/conversation-history.test.ts +205 -0
  348. package/test-integration/conversation.test.ts +137 -0
  349. package/test-integration/elevenlabs.test.ts +55 -0
  350. package/test-integration/google-services.test.ts +80 -0
  351. package/test-integration/helpers.ts +89 -0
  352. package/test-integration/openai-codex.test.ts +93 -0
  353. package/test-integration/runpod.test.ts +58 -0
  354. package/test-integration/server-endpoints.test.ts +97 -0
  355. package/test-integration/skills-library.test.ts +157 -0
  356. package/test-integration/telegram.test.ts +46 -0
  357. package/tsconfig.json +58 -0
  358. package/uv.lock +8 -0
@@ -0,0 +1,534 @@
1
+ import { features, Feature } from "../feature.js";
2
+ import { FeatureStateSchema, FeatureOptionsSchema } from '../../schemas/base.js'
3
+ import {
4
+ mkdirSync,
5
+ writeFileSync,
6
+ appendFileSync,
7
+ readdirSync,
8
+ statSync,
9
+ readFileSync,
10
+ } from "fs";
11
+ import { join, resolve, dirname } from "path";
12
+ import { readFile, stat, unlink, mkdir, writeFile, appendFile, readdir } from "fs/promises";
13
+ import { native as rimraf } from 'rimraf'
14
+
15
+ type WalkOptions = {
16
+ directories?: boolean;
17
+ files?: boolean;
18
+ exclude?: string | string[];
19
+ include?: string | string[];
20
+ };
21
+
22
+ /**
23
+ * The FS feature provides methods for interacting with the file system, relative to the
24
+ * container's cwd.
25
+ *
26
+ * @extends Feature
27
+ *
28
+ * @example
29
+ * ```typescript
30
+ * const fs = container.feature('fs')
31
+ * const content = fs.readFile('package.json')
32
+ * const exists = fs.exists('tsconfig.json')
33
+ * await fs.ensureFileAsync('output/result.json', '{}')
34
+ * ```
35
+ */
36
+ export class FS extends Feature {
37
+ static override shortcut = "features.fs" as const
38
+ static override stateSchema = FeatureStateSchema
39
+ static override optionsSchema = FeatureOptionsSchema
40
+
41
+ /**
42
+ * Asynchronously reads a file and returns its contents as a Buffer.
43
+ *
44
+ * @param {string} path - The file path relative to the container's working directory
45
+ * @returns {Promise<Buffer>} A promise that resolves to the file contents as a Buffer
46
+ * @throws {Error} Throws an error if the file doesn't exist or cannot be read
47
+ *
48
+ * @example
49
+ * ```typescript
50
+ * const fs = container.feature('fs')
51
+ * const buffer = await fs.readFileAsync('data.txt')
52
+ * console.log(buffer.toString())
53
+ * ```
54
+ */
55
+ async readFileAsync(path: string) {
56
+ return await readFile(this.container.paths.resolve(path))
57
+ }
58
+
59
+ /**
60
+ * Asynchronously reads the contents of a directory.
61
+ *
62
+ * @param {string} path - The directory path relative to the container's working directory
63
+ * @returns {Promise<string[]>} A promise that resolves to an array of file and directory names
64
+ * @throws {Error} Throws an error if the directory doesn't exist or cannot be read
65
+ *
66
+ * @example
67
+ * ```typescript
68
+ * const fs = container.feature('fs')
69
+ * const entries = await fs.readdir('src')
70
+ * console.log(entries) // ['index.ts', 'utils.ts', 'components']
71
+ * ```
72
+ */
73
+ async readdir(path: string) {
74
+ return await readdir(this.container.paths.resolve(path))
75
+ }
76
+
77
+ /**
78
+ * Recursively walks a directory and returns an array of relative path names for each file and directory.
79
+ *
80
+ * @param {string} basePath - The base directory path to start walking from
81
+ * @param {WalkOptions} options - Options to configure the walk behavior
82
+ * @param {boolean} [options.directories=true] - Whether to include directories in results
83
+ * @param {boolean} [options.files=true] - Whether to include files in results
84
+ * @param {string | string[]} [options.exclude=[]] - Patterns to exclude from results
85
+ * @param {string | string[]} [options.include=[]] - Patterns to include in results
86
+ * @returns {{ directories: string[], files: string[] }} Object containing arrays of directory and file paths
87
+ *
88
+ * @example
89
+ * ```typescript
90
+ * const result = fs.walk('src', { files: true, directories: false })
91
+ * console.log(result.files) // ['src/index.ts', 'src/utils.ts', 'src/components/Button.tsx']
92
+ * ```
93
+ */
94
+ walk(basePath: string, options: WalkOptions = {}) {
95
+ const {
96
+ directories = true,
97
+ files = true,
98
+ exclude = [],
99
+ include = [],
100
+ } = options;
101
+
102
+ const walk = (baseDir: string) => {
103
+ const results = {
104
+ directories: [] as string[],
105
+ files: [] as string[],
106
+ };
107
+
108
+ const entries = readdirSync(baseDir, { withFileTypes: true });
109
+
110
+ for (const entry of entries) {
111
+ const name = entry.name;
112
+ const path = join(baseDir, name);
113
+ const isDir = entry.isDirectory();
114
+
115
+ if (isDir && directories) {
116
+ results.directories.push(path);
117
+ }
118
+
119
+ if (!isDir && files) {
120
+ results.files.push(path);
121
+ }
122
+
123
+ if (isDir) {
124
+ const subResults = walk(path);
125
+ results.files.push(...subResults.files);
126
+ results.directories.push(...subResults.directories);
127
+ }
128
+ }
129
+
130
+ return results;
131
+ };
132
+
133
+ return walk(this.container.paths.resolve(basePath));
134
+ }
135
+
136
+ /**
137
+ * Asynchronously and recursively walks a directory and returns an array of relative path names.
138
+ *
139
+ * @param {string} baseDir - The base directory path to start walking from
140
+ * @param {WalkOptions} options - Options to configure the walk behavior
141
+ * @param {boolean} [options.directories=true] - Whether to include directories in results
142
+ * @param {boolean} [options.files=true] - Whether to include files in results
143
+ * @param {string | string[]} [options.exclude=[]] - Patterns to exclude from results
144
+ * @param {string | string[]} [options.include=[]] - Patterns to include in results
145
+ * @returns {Promise<{ directories: string[], files: string[] }>} Promise resolving to object with directory and file paths
146
+ * @throws {Error} Throws an error if the directory cannot be accessed
147
+ *
148
+ * @example
149
+ * ```typescript
150
+ * const result = await fs.walkAsync('src', { exclude: ['node_modules'] })
151
+ * console.log(`Found ${result.files.length} files and ${result.directories.length} directories`)
152
+ * ```
153
+ */
154
+ async walkAsync(baseDir: string, options: WalkOptions = {}) {
155
+ const {
156
+ directories = true,
157
+ files = true,
158
+ exclude = [],
159
+ include = [],
160
+ } = options;
161
+
162
+ const walk = async (baseDir: string) => {
163
+ const results = {
164
+ directories: [] as string[],
165
+ files: [] as string[],
166
+ };
167
+
168
+ const entries = await readdir(baseDir, { withFileTypes: true });
169
+
170
+ for (const entry of entries) {
171
+ const name = entry.name;
172
+ const path = join(baseDir, name);
173
+ const isDir = entry.isDirectory();
174
+
175
+ if (isDir && directories) {
176
+ results.directories.push(path);
177
+ }
178
+
179
+ if (!isDir && files) {
180
+ results.files.push(path);
181
+ }
182
+
183
+ if (isDir) {
184
+ const subResults = await walk(path);
185
+ results.files.push(...subResults.files);
186
+ results.directories.push(...subResults.directories);
187
+ }
188
+ }
189
+
190
+ return results;
191
+ };
192
+
193
+ return walk(this.container.paths.resolve(baseDir));
194
+ }
195
+
196
+ /**
197
+ * Asynchronously ensures a file exists with the specified content, creating directories as needed.
198
+ *
199
+ * @param {string} path - The file path where the file should be created
200
+ * @param {string} content - The content to write to the file
201
+ * @param {boolean} [overwrite=false] - Whether to overwrite the file if it already exists
202
+ * @returns {Promise<string>} A promise that resolves to the absolute file path
203
+ * @throws {Error} Throws an error if the file cannot be created or written
204
+ *
205
+ * @example
206
+ * ```typescript
207
+ * await fs.ensureFileAsync('config/settings.json', '{}', true)
208
+ * // Creates config directory and settings.json file with '{}' content
209
+ * ```
210
+ */
211
+ async ensureFileAsync(path: string, content: string, overwrite = false) {
212
+ path = this.container.paths.resolve(path);
213
+
214
+ if (this.exists(path) && !overwrite) {
215
+ return path;
216
+ }
217
+
218
+ const { dir } = this.container.paths.parse(path);
219
+ await mkdir(dir, { recursive: true });
220
+ await writeFile(path, content);
221
+ return path;
222
+ }
223
+
224
+ /**
225
+ * Asynchronously writes content to a file.
226
+ *
227
+ * @param {string} path - The file path where content should be written
228
+ * @param {Buffer | string} content - The content to write to the file
229
+ * @returns {Promise<void>} A promise that resolves when the file is written
230
+ * @throws {Error} Throws an error if the file cannot be written
231
+ *
232
+ * @example
233
+ * ```typescript
234
+ * await fs.writeFileAsync('output.txt', 'Hello World')
235
+ * await fs.writeFileAsync('data.bin', Buffer.from([1, 2, 3, 4]))
236
+ * ```
237
+ */
238
+ async writeFileAsync(path:string, content: Buffer | string) {
239
+ return writeFile(this.container.paths.resolve(path), content)
240
+ }
241
+
242
+ /**
243
+ * Synchronously appends content to a file.
244
+ *
245
+ * @param {string} path - The file path to append to
246
+ * @param {Buffer | string} content - The content to append
247
+ *
248
+ * @example
249
+ * ```typescript
250
+ * fs.appendFile('log.txt', 'New line\n')
251
+ * ```
252
+ */
253
+ appendFile(path: string, content: Buffer | string) {
254
+ appendFileSync(this.container.paths.resolve(path), content)
255
+ }
256
+
257
+ /**
258
+ * Asynchronously appends content to a file.
259
+ *
260
+ * @param {string} path - The file path to append to
261
+ * @param {Buffer | string} content - The content to append
262
+ * @returns {Promise<void>} A promise that resolves when the content is appended
263
+ *
264
+ * @example
265
+ * ```typescript
266
+ * await fs.appendFileAsync('log.txt', 'New line\n')
267
+ * ```
268
+ */
269
+ async appendFileAsync(path: string, content: Buffer | string) {
270
+ return appendFile(this.container.paths.resolve(path), content)
271
+ }
272
+
273
+ /**
274
+ * Synchronously ensures a directory exists, creating parent directories as needed.
275
+ *
276
+ * @param {string} path - The directory path to create
277
+ * @returns {string} The resolved directory path
278
+ * @throws {Error} Throws an error if the directory cannot be created
279
+ *
280
+ * @example
281
+ * ```typescript
282
+ * fs.ensureFolder('logs/debug')
283
+ * // Creates logs and logs/debug directories if they don't exist
284
+ * ```
285
+ */
286
+ ensureFolder(path: string) {
287
+ mkdirSync(this.container.paths.resolve(path), { recursive: true });
288
+ return path;
289
+ }
290
+
291
+ /**
292
+ * Synchronously ensures a file exists with the specified content, creating directories as needed.
293
+ *
294
+ * @param {string} path - The file path where the file should be created
295
+ * @param {string} content - The content to write to the file
296
+ * @param {boolean} [overwrite=false] - Whether to overwrite the file if it already exists
297
+ * @returns {string} The resolved file path
298
+ * @throws {Error} Throws an error if the file cannot be created or written
299
+ *
300
+ * @example
301
+ * ```typescript
302
+ * fs.ensureFile('logs/app.log', '', false)
303
+ * // Creates logs directory and app.log file if they don't exist
304
+ * ```
305
+ */
306
+ ensureFile(path: string, content: string, overwrite = false) {
307
+ path = this.container.paths.resolve(path);
308
+
309
+ if (this.exists(path) && !overwrite) {
310
+ return path;
311
+ }
312
+
313
+ const { dir } = this.container.paths.parse(path);
314
+ mkdirSync(dir, { recursive: true });
315
+ writeFileSync(path, content);
316
+ return path;
317
+ }
318
+
319
+ /**
320
+ * Synchronously finds a file by walking up the directory tree from the current working directory.
321
+ *
322
+ * @param {string} fileName - The name of the file to search for
323
+ * @param {object} [options={}] - Options for the search
324
+ * @param {string} [options.cwd] - The directory to start searching from (defaults to container.cwd)
325
+ * @returns {string | null} The absolute path to the found file, or null if not found
326
+ *
327
+ * @example
328
+ * ```typescript
329
+ * const packageJson = fs.findUp('package.json')
330
+ * if (packageJson) {
331
+ * console.log(`Found package.json at: ${packageJson}`)
332
+ * }
333
+ * ```
334
+ */
335
+ findUp(fileName: string, options: { cwd?: string } = {}): string | null {
336
+ const { cwd = this.container.cwd } = options;
337
+ let startAt = cwd;
338
+
339
+ // walk up the tree until we find the fileName exists
340
+ if (this.exists(join(startAt, fileName))) {
341
+ return resolve(startAt, fileName);
342
+ }
343
+
344
+ // walk up the tree until we find the fileName exists
345
+ while (startAt !== dirname(startAt)) {
346
+ startAt = dirname(startAt);
347
+ if (this.exists(join(startAt, fileName))) {
348
+ return resolve(startAt, fileName);
349
+ }
350
+ }
351
+
352
+ return null;
353
+ }
354
+
355
+ /**
356
+ * Asynchronously checks if a file or directory exists.
357
+ *
358
+ * @param {string} path - The path to check for existence
359
+ * @returns {Promise<boolean>} A promise that resolves to true if the path exists, false otherwise
360
+ *
361
+ * @example
362
+ * ```typescript
363
+ * if (await fs.existsAsync('config.json')) {
364
+ * console.log('Config file exists!')
365
+ * }
366
+ * ```
367
+ */
368
+ async existsAsync(path: string) {
369
+ const { container } = this;
370
+ const filePath = container.paths.resolve(path);
371
+ const exists = await stat(filePath)
372
+ .then(() => true)
373
+ .catch((e) => false);
374
+
375
+ return exists
376
+ }
377
+
378
+ /**
379
+ * Synchronously checks if a file or directory exists.
380
+ *
381
+ * @param {string} path - The path to check for existence
382
+ * @returns {boolean} True if the path exists, false otherwise
383
+ *
384
+ * @example
385
+ * ```typescript
386
+ * if (fs.exists('config.json')) {
387
+ * console.log('Config file exists!')
388
+ * }
389
+ * ```
390
+ */
391
+ exists(path: string): boolean {
392
+ const { container } = this;
393
+ const filePath = container.paths.resolve(path);
394
+
395
+ try {
396
+ statSync(filePath);
397
+ return true;
398
+ } catch (error) {
399
+ return false;
400
+ }
401
+ }
402
+
403
+ /**
404
+ * Asynchronously removes a file.
405
+ *
406
+ * @param {string} path - The path of the file to remove
407
+ * @returns {Promise<void>} A promise that resolves when the file is removed
408
+ * @throws {Error} Throws an error if the file cannot be removed or doesn't exist
409
+ *
410
+ * @example
411
+ * ```typescript
412
+ * await fs.rm('temp/cache.tmp')
413
+ * ```
414
+ */
415
+ async rm(path: string) {
416
+ return await unlink(this.container.paths.resolve(path));
417
+ }
418
+
419
+ /**
420
+ * Synchronously reads and parses a JSON file.
421
+ *
422
+ * @param {string} path - The path to the JSON file
423
+ * @returns {any} The parsed JSON content
424
+ * @throws {Error} Throws an error if the file doesn't exist, cannot be read, or contains invalid JSON
425
+ *
426
+ * @example
427
+ * ```typescript
428
+ * const config = fs.readJson('config.json')
429
+ * console.log(config.version)
430
+ * ```
431
+ */
432
+ readJson(path: string) {
433
+ const { container } = this;
434
+ const filePath = container.paths.resolve(path);
435
+ return JSON.parse(readFileSync(filePath).toString());
436
+ }
437
+
438
+ /**
439
+ * Synchronously reads a file and returns its contents as a string.
440
+ *
441
+ * @param {string} path - The path to the file
442
+ * @returns {string} The file contents as a string
443
+ * @throws {Error} Throws an error if the file doesn't exist or cannot be read
444
+ *
445
+ * @example
446
+ * ```typescript
447
+ * const content = fs.readFile('README.md')
448
+ * console.log(content)
449
+ * ```
450
+ */
451
+ readFile(path: string) {
452
+ const { container } = this;
453
+ const filePath = container.paths.resolve(path);
454
+ return readFileSync(filePath).toString();
455
+ }
456
+
457
+ /**
458
+ * Asynchronously removes a directory and all its contents.
459
+ *
460
+ * @param {string} dirPath - The path of the directory to remove
461
+ * @returns {Promise<void>} A promise that resolves when the directory is removed
462
+ * @throws {Error} Throws an error if the directory cannot be removed
463
+ *
464
+ * @example
465
+ * ```typescript
466
+ * await fs.rmdir('temp/cache')
467
+ * // Removes the cache directory and all its contents
468
+ * ```
469
+ */
470
+ async rmdir(dirPath: string) {
471
+ await rimraf(this.container.paths.resolve(dirPath));
472
+ }
473
+
474
+ /**
475
+ * Asynchronously finds a file by walking up the directory tree.
476
+ *
477
+ * @param {string} fileName - The name of the file to search for
478
+ * @param {object} [options={}] - Options for the search
479
+ * @param {string} [options.cwd] - The directory to start searching from (defaults to container.cwd)
480
+ * @param {boolean} [options.multiple=false] - Whether to find multiple instances of the file
481
+ * @returns {Promise<string | string[] | null>} The path(s) to the found file(s), or null if not found
482
+ * @throws {Error} Throws an error if the search encounters filesystem issues
483
+ *
484
+ * @example
485
+ * ```typescript
486
+ * const packageJson = await fs.findUpAsync('package.json')
487
+ * const allPackageJsons = await fs.findUpAsync('package.json', { multiple: true })
488
+ * ```
489
+ */
490
+ async findUpAsync(
491
+ fileName: string,
492
+ options: { cwd?: string; multiple?: boolean } = {}
493
+ ): Promise<string | string[] | null> {
494
+ const { cwd = this.container.cwd, multiple = false } = options;
495
+ let startAt = cwd;
496
+ const foundFiles = [];
497
+
498
+ const fileExistsInDir = async (dir: string, file: string) => {
499
+ try {
500
+ await stat(join(dir, file));
501
+ return true;
502
+ } catch (error) {
503
+ return false;
504
+ }
505
+ };
506
+
507
+ if (await fileExistsInDir(startAt, fileName)) {
508
+ if (multiple) {
509
+ foundFiles.push(resolve(startAt, fileName));
510
+ } else {
511
+ return resolve(startAt, fileName);
512
+ }
513
+ }
514
+
515
+ while (startAt !== dirname(startAt)) {
516
+ startAt = dirname(startAt);
517
+ if (await fileExistsInDir(startAt, fileName)) {
518
+ if (multiple) {
519
+ foundFiles.push(resolve(startAt, fileName));
520
+ } else {
521
+ return resolve(startAt, fileName);
522
+ }
523
+ }
524
+ }
525
+
526
+ if (multiple && foundFiles.length > 0) {
527
+ return foundFiles;
528
+ }
529
+
530
+ return null;
531
+ }
532
+ }
533
+
534
+ export default features.register("fs", FS);