@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.
- package/CLAUDE.md +71 -0
- package/README.md +78 -0
- package/bun.lock +2928 -0
- package/bunfig.toml +3 -0
- package/commands/audit-docs.ts +740 -0
- package/commands/build-scaffolds.ts +154 -0
- package/commands/generate-api-docs.ts +114 -0
- package/commands/update-introspection.ts +67 -0
- package/docs/CLI.md +335 -0
- package/docs/README.md +88 -0
- package/docs/TABLE-OF-CONTENTS.md +157 -0
- package/docs/apis/clients/elevenlabs.md +84 -0
- package/docs/apis/clients/graph.md +56 -0
- package/docs/apis/clients/openai.md +69 -0
- package/docs/apis/clients/rest.md +41 -0
- package/docs/apis/clients/websocket.md +107 -0
- package/docs/apis/features/agi/assistant.md +471 -0
- package/docs/apis/features/agi/assistants-manager.md +154 -0
- package/docs/apis/features/agi/claude-code.md +602 -0
- package/docs/apis/features/agi/conversation-history.md +352 -0
- package/docs/apis/features/agi/conversation.md +333 -0
- package/docs/apis/features/agi/docs-reader.md +121 -0
- package/docs/apis/features/agi/openai-codex.md +318 -0
- package/docs/apis/features/agi/openapi.md +138 -0
- package/docs/apis/features/agi/semantic-search.md +387 -0
- package/docs/apis/features/agi/skills-library.md +216 -0
- package/docs/apis/features/node/container-link.md +133 -0
- package/docs/apis/features/node/content-db.md +313 -0
- package/docs/apis/features/node/disk-cache.md +379 -0
- package/docs/apis/features/node/dns.md +651 -0
- package/docs/apis/features/node/docker.md +705 -0
- package/docs/apis/features/node/downloader.md +81 -0
- package/docs/apis/features/node/esbuild.md +59 -0
- package/docs/apis/features/node/file-manager.md +182 -0
- package/docs/apis/features/node/fs.md +581 -0
- package/docs/apis/features/node/git.md +330 -0
- package/docs/apis/features/node/google-auth.md +174 -0
- package/docs/apis/features/node/google-calendar.md +187 -0
- package/docs/apis/features/node/google-docs.md +151 -0
- package/docs/apis/features/node/google-drive.md +225 -0
- package/docs/apis/features/node/google-sheets.md +179 -0
- package/docs/apis/features/node/grep.md +290 -0
- package/docs/apis/features/node/helpers.md +135 -0
- package/docs/apis/features/node/ink.md +334 -0
- package/docs/apis/features/node/ipc-socket.md +260 -0
- package/docs/apis/features/node/json-tree.md +86 -0
- package/docs/apis/features/node/launcher-app-command-listener.md +145 -0
- package/docs/apis/features/node/networking.md +281 -0
- package/docs/apis/features/node/nlp.md +133 -0
- package/docs/apis/features/node/opener.md +97 -0
- package/docs/apis/features/node/os.md +118 -0
- package/docs/apis/features/node/package-finder.md +402 -0
- package/docs/apis/features/node/postgres.md +212 -0
- package/docs/apis/features/node/proc.md +430 -0
- package/docs/apis/features/node/process-manager.md +210 -0
- package/docs/apis/features/node/python.md +278 -0
- package/docs/apis/features/node/repl.md +88 -0
- package/docs/apis/features/node/runpod.md +673 -0
- package/docs/apis/features/node/secure-shell.md +169 -0
- package/docs/apis/features/node/semantic-search.md +401 -0
- package/docs/apis/features/node/sqlite.md +211 -0
- package/docs/apis/features/node/telegram.md +254 -0
- package/docs/apis/features/node/tts.md +118 -0
- package/docs/apis/features/node/ui.md +703 -0
- package/docs/apis/features/node/vault.md +64 -0
- package/docs/apis/features/node/vm.md +84 -0
- package/docs/apis/features/node/window-manager.md +337 -0
- package/docs/apis/features/node/yaml-tree.md +85 -0
- package/docs/apis/features/node/yaml.md +176 -0
- package/docs/apis/features/web/asset-loader.md +47 -0
- package/docs/apis/features/web/container-link.md +133 -0
- package/docs/apis/features/web/esbuild.md +59 -0
- package/docs/apis/features/web/helpers.md +135 -0
- package/docs/apis/features/web/network.md +30 -0
- package/docs/apis/features/web/speech.md +55 -0
- package/docs/apis/features/web/vault.md +64 -0
- package/docs/apis/features/web/vm.md +84 -0
- package/docs/apis/features/web/voice.md +67 -0
- package/docs/apis/servers/express.md +127 -0
- package/docs/apis/servers/mcp.md +213 -0
- package/docs/apis/servers/websocket.md +99 -0
- package/docs/documentation-audit.md +134 -0
- package/docs/examples/content-db.md +77 -0
- package/docs/examples/disk-cache.md +83 -0
- package/docs/examples/docker.md +101 -0
- package/docs/examples/downloader.md +70 -0
- package/docs/examples/esbuild.md +80 -0
- package/docs/examples/file-manager.md +82 -0
- package/docs/examples/fs.md +83 -0
- package/docs/examples/git.md +85 -0
- package/docs/examples/google-auth.md +88 -0
- package/docs/examples/google-calendar.md +94 -0
- package/docs/examples/google-docs.md +82 -0
- package/docs/examples/google-drive.md +96 -0
- package/docs/examples/google-sheets.md +95 -0
- package/docs/examples/grep.md +85 -0
- package/docs/examples/ink-blocks.md +75 -0
- package/docs/examples/ink-renderer.md +41 -0
- package/docs/examples/ink.md +103 -0
- package/docs/examples/ipc-socket.md +103 -0
- package/docs/examples/json-tree.md +91 -0
- package/docs/examples/launcher-app-command-listener.md +120 -0
- package/docs/examples/networking.md +58 -0
- package/docs/examples/nlp.md +91 -0
- package/docs/examples/opener.md +78 -0
- package/docs/examples/os.md +72 -0
- package/docs/examples/package-finder.md +89 -0
- package/docs/examples/port-exposer.md +89 -0
- package/docs/examples/postgres.md +91 -0
- package/docs/examples/proc.md +81 -0
- package/docs/examples/process-manager.md +79 -0
- package/docs/examples/python.md +91 -0
- package/docs/examples/repl.md +93 -0
- package/docs/examples/runpod.md +119 -0
- package/docs/examples/secure-shell.md +92 -0
- package/docs/examples/sqlite.md +86 -0
- package/docs/examples/telegram.md +77 -0
- package/docs/examples/tts.md +86 -0
- package/docs/examples/ui.md +80 -0
- package/docs/examples/vault.md +70 -0
- package/docs/examples/vm.md +86 -0
- package/docs/examples/window-manager.md +125 -0
- package/docs/examples/yaml-tree.md +93 -0
- package/docs/examples/yaml.md +104 -0
- package/docs/ideas/class-registration-refactor-possibilities.md +197 -0
- package/docs/ideas/container-use-api.md +9 -0
- package/docs/ideas/easy-auth-for-express-servers-and-luca-serve.md +0 -0
- package/docs/ideas/feature-stacks.md +22 -0
- package/docs/ideas/luca-cli-self-sufficiency-demo.md +23 -0
- package/docs/ideas/mcp-design.md +9 -0
- package/docs/ideas/web-container-debugging-feature.md +13 -0
- package/docs/introspection-audit.md +49 -0
- package/docs/introspection.md +154 -0
- package/docs/mcp/readme.md +162 -0
- package/docs/models.ts +38 -0
- package/docs/philosophy.md +85 -0
- package/docs/principles.md +7 -0
- package/docs/prompts/audit-codebase-for-failures-to-use-the-container.md +34 -0
- package/docs/prompts/mcp-test-easy-command.md +27 -0
- package/docs/reports/assistant-bugs.md +38 -0
- package/docs/reports/attach-pattern-usage.md +18 -0
- package/docs/reports/code-audit-results.md +391 -0
- package/docs/reports/introspection-audit-tasks.md +378 -0
- package/docs/reports/luca-mcp-improvements.md +128 -0
- package/docs/scaffolds/client.md +140 -0
- package/docs/scaffolds/command.md +106 -0
- package/docs/scaffolds/endpoint.md +176 -0
- package/docs/scaffolds/feature.md +148 -0
- package/docs/scaffolds/server.md +187 -0
- package/docs/tasks/web-container-helper-discovery.md +71 -0
- package/docs/todos.md +1 -0
- package/docs/tutorials/01-getting-started.md +106 -0
- package/docs/tutorials/02-container.md +210 -0
- package/docs/tutorials/03-scripts.md +194 -0
- package/docs/tutorials/04-features-overview.md +196 -0
- package/docs/tutorials/05-state-and-events.md +171 -0
- package/docs/tutorials/06-servers.md +157 -0
- package/docs/tutorials/07-endpoints.md +198 -0
- package/docs/tutorials/08-commands.md +171 -0
- package/docs/tutorials/09-clients.md +162 -0
- package/docs/tutorials/10-creating-features.md +198 -0
- package/docs/tutorials/11-contentbase.md +191 -0
- package/docs/tutorials/12-assistants.md +215 -0
- package/docs/tutorials/13-introspection.md +147 -0
- package/docs/tutorials/14-type-system.md +174 -0
- package/docs/tutorials/15-project-patterns.md +222 -0
- package/docs/tutorials/16-google-features.md +534 -0
- package/docs/tutorials/17-tui-blocks.md +530 -0
- package/docs/tutorials/18-semantic-search.md +334 -0
- package/index.ts +1 -0
- package/luca.console.ts +9 -0
- package/main.py +6 -0
- package/package.json +154 -0
- package/pyproject.toml +7 -0
- package/scripts/animations/chrome-glitch.ts +55 -0
- package/scripts/animations/index.ts +16 -0
- package/scripts/animations/neon-pulse.ts +64 -0
- package/scripts/animations/types.ts +6 -0
- package/scripts/build-web.ts +28 -0
- package/scripts/examples/ask-luca-expert.ts +42 -0
- package/scripts/examples/assistant-questions.ts +12 -0
- package/scripts/examples/excalidraw-expert.ts +75 -0
- package/scripts/examples/expert-chat.ts +0 -0
- package/scripts/examples/file-manager.ts +14 -0
- package/scripts/examples/ideas.ts +12 -0
- package/scripts/examples/interactive-chat.ts +20 -0
- package/scripts/examples/openai-tool-calls.ts +113 -0
- package/scripts/examples/opening-a-web-browser.ts +5 -0
- package/scripts/examples/telegram-bot.ts +79 -0
- package/scripts/examples/telegram-ink-ui.ts +302 -0
- package/scripts/examples/using-assistant-with-mcp.ts +560 -0
- package/scripts/examples/using-claude-code.ts +10 -0
- package/scripts/examples/using-contentdb.ts +35 -0
- package/scripts/examples/using-conversations.ts +35 -0
- package/scripts/examples/using-disk-cache.ts +10 -0
- package/scripts/examples/using-docker-shell.ts +75 -0
- package/scripts/examples/using-elevenlabs.ts +25 -0
- package/scripts/examples/using-google-calendar.ts +57 -0
- package/scripts/examples/using-google-docs.ts +74 -0
- package/scripts/examples/using-google-drive.ts +74 -0
- package/scripts/examples/using-google-sheets.ts +89 -0
- package/scripts/examples/using-nlp.ts +55 -0
- package/scripts/examples/using-ollama.ts +10 -0
- package/scripts/examples/using-openai-codex.ts +23 -0
- package/scripts/examples/using-postgres.ts +55 -0
- package/scripts/examples/using-runpod.ts +32 -0
- package/scripts/examples/using-tts.ts +40 -0
- package/scripts/examples/vm-loading-esm-modules.ts +16 -0
- package/scripts/scaffold.ts +391 -0
- package/scripts/scratch.ts +15 -0
- package/scripts/test-command-listener.ts +123 -0
- package/scripts/test-window-manager-lifecycle.ts +86 -0
- package/scripts/test-window-manager.ts +43 -0
- package/scripts/update-introspection-data.ts +58 -0
- package/src/agi/README.md +14 -0
- package/src/agi/container.server.ts +114 -0
- package/src/agi/endpoints/ask.ts +60 -0
- package/src/agi/endpoints/conversations/[id].ts +45 -0
- package/src/agi/endpoints/conversations.ts +31 -0
- package/src/agi/endpoints/experts.ts +37 -0
- package/src/agi/features/assistant.ts +767 -0
- package/src/agi/features/assistants-manager.ts +260 -0
- package/src/agi/features/claude-code.ts +1111 -0
- package/src/agi/features/conversation-history.ts +497 -0
- package/src/agi/features/conversation.ts +799 -0
- package/src/agi/features/openai-codex.ts +631 -0
- package/src/agi/features/openapi.ts +438 -0
- package/src/agi/features/skills-library.ts +425 -0
- package/src/agi/index.ts +6 -0
- package/src/agi/lib/token-counter.ts +122 -0
- package/src/browser.ts +25 -0
- package/src/bus.ts +100 -0
- package/src/cli/cli.ts +70 -0
- package/src/client.ts +461 -0
- package/src/clients/civitai/index.ts +541 -0
- package/src/clients/client-template.ts +41 -0
- package/src/clients/comfyui/index.ts +597 -0
- package/src/clients/elevenlabs/index.ts +291 -0
- package/src/clients/openai/index.ts +451 -0
- package/src/clients/supabase/index.ts +366 -0
- package/src/command.ts +164 -0
- package/src/commands/chat.ts +182 -0
- package/src/commands/console.ts +192 -0
- package/src/commands/describe.ts +433 -0
- package/src/commands/eval.ts +116 -0
- package/src/commands/help.ts +214 -0
- package/src/commands/index.ts +14 -0
- package/src/commands/mcp.ts +64 -0
- package/src/commands/prompt.ts +807 -0
- package/src/commands/run.ts +257 -0
- package/src/commands/sandbox-mcp.ts +439 -0
- package/src/commands/scaffold.ts +79 -0
- package/src/commands/serve.ts +172 -0
- package/src/container.ts +781 -0
- package/src/endpoint.ts +340 -0
- package/src/feature.ts +75 -0
- package/src/hash-object.ts +97 -0
- package/src/helper.ts +543 -0
- package/src/introspection/generated.agi.ts +23388 -0
- package/src/introspection/generated.node.ts +18899 -0
- package/src/introspection/generated.web.ts +2021 -0
- package/src/introspection/index.ts +256 -0
- package/src/introspection/scan.ts +912 -0
- package/src/node/container.ts +354 -0
- package/src/node/feature.ts +13 -0
- package/src/node/features/container-link.ts +558 -0
- package/src/node/features/content-db.ts +475 -0
- package/src/node/features/disk-cache.ts +382 -0
- package/src/node/features/dns.ts +655 -0
- package/src/node/features/docker.ts +912 -0
- package/src/node/features/downloader.ts +92 -0
- package/src/node/features/esbuild.ts +68 -0
- package/src/node/features/file-manager.ts +357 -0
- package/src/node/features/fs.ts +534 -0
- package/src/node/features/git.ts +492 -0
- package/src/node/features/google-auth.ts +502 -0
- package/src/node/features/google-calendar.ts +300 -0
- package/src/node/features/google-docs.ts +404 -0
- package/src/node/features/google-drive.ts +339 -0
- package/src/node/features/google-sheets.ts +279 -0
- package/src/node/features/grep.ts +406 -0
- package/src/node/features/helpers.ts +374 -0
- package/src/node/features/ink.ts +490 -0
- package/src/node/features/ipc-socket.ts +459 -0
- package/src/node/features/json-tree.ts +188 -0
- package/src/node/features/launcher-app-command-listener.ts +388 -0
- package/src/node/features/networking.ts +925 -0
- package/src/node/features/nlp.ts +211 -0
- package/src/node/features/opener.ts +166 -0
- package/src/node/features/os.ts +157 -0
- package/src/node/features/package-finder.ts +539 -0
- package/src/node/features/port-exposer.ts +342 -0
- package/src/node/features/postgres.ts +273 -0
- package/src/node/features/proc.ts +502 -0
- package/src/node/features/process-manager.ts +542 -0
- package/src/node/features/python.ts +444 -0
- package/src/node/features/repl.ts +194 -0
- package/src/node/features/runpod.ts +802 -0
- package/src/node/features/secure-shell.ts +248 -0
- package/src/node/features/semantic-search.ts +924 -0
- package/src/node/features/sqlite.ts +289 -0
- package/src/node/features/telegram.ts +342 -0
- package/src/node/features/tts.ts +184 -0
- package/src/node/features/ui.ts +857 -0
- package/src/node/features/vault.ts +164 -0
- package/src/node/features/vm.ts +312 -0
- package/src/node/features/window-manager.ts +804 -0
- package/src/node/features/yaml-tree.ts +149 -0
- package/src/node/features/yaml.ts +132 -0
- package/src/node.ts +70 -0
- package/src/react/index.ts +175 -0
- package/src/registry.ts +199 -0
- package/src/scaffolds/generated.ts +1613 -0
- package/src/scaffolds/template.ts +37 -0
- package/src/schemas/base.ts +255 -0
- package/src/server.ts +135 -0
- package/src/servers/express.ts +209 -0
- package/src/servers/mcp.ts +805 -0
- package/src/servers/socket.ts +120 -0
- package/src/state.ts +101 -0
- package/src/web/clients/socket.ts +82 -0
- package/src/web/container.ts +74 -0
- package/src/web/extension.ts +30 -0
- package/src/web/feature.ts +12 -0
- package/src/web/features/asset-loader.ts +64 -0
- package/src/web/features/container-link.ts +385 -0
- package/src/web/features/esbuild.ts +79 -0
- package/src/web/features/helpers.ts +267 -0
- package/src/web/features/network.ts +61 -0
- package/src/web/features/speech.ts +87 -0
- package/src/web/features/vault.ts +189 -0
- package/src/web/features/vm.ts +78 -0
- package/src/web/features/voice-recognition.ts +129 -0
- package/src/web/shims/isomorphic-vm.ts +149 -0
- package/test/bus.test.ts +134 -0
- package/test/clients-servers.test.ts +216 -0
- package/test/container-link.test.ts +274 -0
- package/test/features.test.ts +160 -0
- package/test/integration.test.ts +787 -0
- package/test/node-container.test.ts +121 -0
- package/test/rate-limit.test.ts +272 -0
- package/test/semantic-search.test.ts +550 -0
- package/test/state.test.ts +121 -0
- package/test-integration/assistant.test.ts +138 -0
- package/test-integration/assistants-manager.test.ts +123 -0
- package/test-integration/claude-code.test.ts +98 -0
- package/test-integration/conversation-history.test.ts +205 -0
- package/test-integration/conversation.test.ts +137 -0
- package/test-integration/elevenlabs.test.ts +55 -0
- package/test-integration/google-services.test.ts +80 -0
- package/test-integration/helpers.ts +89 -0
- package/test-integration/openai-codex.test.ts +93 -0
- package/test-integration/runpod.test.ts +58 -0
- package/test-integration/server-endpoints.test.ts +97 -0
- package/test-integration/skills-library.test.ts +157 -0
- package/test-integration/telegram.test.ts +46 -0
- package/tsconfig.json +58 -0
- 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);
|