cloudforge-agent 0.1.0

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Kenzo ARAI
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,125 @@
1
+ # CloudForge Agent
2
+
3
+ Lightweight agent that connects your server to [CloudForge](https://cloud-forge.me) — remote AI coding from anywhere.
4
+
5
+ CloudForge Agent runs on your server and establishes an outbound WebSocket connection to CloudForge. Your code stays on your server; CloudForge only relays terminal I/O, file operations, and Git commands.
6
+
7
+ ## Features
8
+
9
+ - **Terminal sessions** via node-pty (full PTY support)
10
+ - **File operations** — browse, read, write files remotely
11
+ - **Git integration** — status, add, commit, push, pull, diff, branch management
12
+ - **Outbound-only connection** — no firewall or port forwarding needed
13
+ - **Auto-reconnection** with exponential backoff
14
+ - **Heartbeat** with system info reporting
15
+
16
+ ## Requirements
17
+
18
+ - Node.js >= 18
19
+ - A CloudForge account and server token (get one at [cloud-forge.me](https://cloud-forge.me))
20
+
21
+ ## Installation
22
+
23
+ ### npx (quickest)
24
+
25
+ ```bash
26
+ npx cloudforge-agent --token YOUR_TOKEN
27
+ ```
28
+
29
+ ### npm global install
30
+
31
+ ```bash
32
+ npm install -g cloudforge-agent
33
+ cloudforge-agent --token YOUR_TOKEN
34
+ ```
35
+
36
+ ### From source
37
+
38
+ ```bash
39
+ git clone https://github.com/rascal-3/cloudforge-agent.git
40
+ cd cloudforge-agent
41
+ npm install
42
+ npm run build
43
+ npm start -- --token YOUR_TOKEN
44
+ ```
45
+
46
+ ### Docker
47
+
48
+ ```bash
49
+ docker run -d \
50
+ --name cloudforge-agent \
51
+ --restart unless-stopped \
52
+ -v /path/to/projects:/home/user \
53
+ cloudforge/agent:latest \
54
+ --token YOUR_TOKEN
55
+ ```
56
+
57
+ ## Usage
58
+
59
+ ```bash
60
+ cloudforge-agent --token YOUR_TOKEN [options]
61
+ ```
62
+
63
+ ### Options
64
+
65
+ | Option | Description | Default |
66
+ |--------|-------------|---------|
67
+ | `--token` | Server authentication token (required) | — |
68
+ | `--server` | CloudForge server URL | `https://cloud-forge.me` |
69
+ | `--home` | Home directory for terminal sessions | `~` |
70
+ | `--debug` | Enable debug logging | `false` |
71
+
72
+ ### Environment variables
73
+
74
+ You can also configure via environment variables or a `.env` file:
75
+
76
+ ```bash
77
+ CLOUDFORGE_TOKEN=your_token
78
+ CLOUDFORGE_SERVER=https://cloud-forge.me
79
+ CLOUDFORGE_HOME=/home/user
80
+ CLOUDFORGE_DEBUG=true
81
+ ```
82
+
83
+ ## How it works
84
+
85
+ ```
86
+ ┌─────────────────────┐ ┌─────────────────────┐
87
+ │ Your Browser │ │ Your Server │
88
+ │ (CloudForge UI) │ │ │
89
+ │ │ │ CloudForge Agent │
90
+ │ Terminal ─────────┤ ├──── node-pty │
91
+ │ File Tree ────────┤ WebSocket│──── File I/O │
92
+ │ Git Panel ────────┤◄────────►├──── Git CLI │
93
+ │ Code Editor ──────┤ │ │
94
+ └─────────────────────┘ └─────────────────────┘
95
+ ▲ │
96
+ │ CloudForge SaaS │
97
+ └── relay only ──────┘
98
+ ```
99
+
100
+ - Agent connects **outbound** to CloudForge (no inbound ports needed)
101
+ - All code stays on your server
102
+ - CloudForge relays commands between your browser and the agent
103
+
104
+ ## Supported AI Coding Tools
105
+
106
+ CloudForge works with any CLI tool running in the terminal:
107
+
108
+ - [Claude Code](https://docs.anthropic.com/en/docs/claude-code) (Anthropic)
109
+ - [Codex CLI](https://github.com/openai/codex) (OpenAI)
110
+ - [Gemini CLI](https://github.com/google/gemini-cli) (Google)
111
+ - [Aider](https://aider.chat/)
112
+ - Any other terminal-based tool
113
+
114
+ ## Development
115
+
116
+ ```bash
117
+ npm install
118
+ npm run dev # watch mode with tsx
119
+ npm run build # compile TypeScript
120
+ npm run typecheck
121
+ ```
122
+
123
+ ## License
124
+
125
+ [MIT](LICENSE)
@@ -0,0 +1,35 @@
1
+ /**
2
+ * CloudForge Agent Configuration
3
+ */
4
+ export interface AgentConfig {
5
+ token: string;
6
+ serverUrl: string;
7
+ heartbeatInterval: number;
8
+ reconnectDelay: number;
9
+ maxReconnectDelay: number;
10
+ shell: string;
11
+ homeDir: string;
12
+ debug: boolean;
13
+ }
14
+ /**
15
+ * Create agent configuration from environment and CLI options
16
+ */
17
+ export declare function createConfig(options: {
18
+ token?: string;
19
+ serverUrl?: string;
20
+ debug?: boolean;
21
+ }): AgentConfig;
22
+ /**
23
+ * Get system information for heartbeat
24
+ */
25
+ export declare function getSystemInfo(): {
26
+ os: string;
27
+ hostname: string;
28
+ platform: string;
29
+ arch: string;
30
+ nodeVersion: string;
31
+ homeDir: string;
32
+ shell: string;
33
+ };
34
+ export declare const VERSION = "0.1.0";
35
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;GAEG;AAQH,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAA;IACb,SAAS,EAAE,MAAM,CAAA;IACjB,iBAAiB,EAAE,MAAM,CAAA;IACzB,cAAc,EAAE,MAAM,CAAA;IACtB,iBAAiB,EAAE,MAAM,CAAA;IACzB,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,EAAE,MAAM,CAAA;IACf,KAAK,EAAE,OAAO,CAAA;CACf;AAiBD;;GAEG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE;IACpC,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,KAAK,CAAC,EAAE,OAAO,CAAA;CAChB,GAAG,WAAW,CAsBd;AAED;;GAEG;AACH,wBAAgB,aAAa,IAAI;IAC/B,EAAE,EAAE,MAAM,CAAA;IACV,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,EAAE,MAAM,CAAA;IAChB,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,EAAE,MAAM,CAAA;IACnB,OAAO,EAAE,MAAM,CAAA;IACf,KAAK,EAAE,MAAM,CAAA;CACd,CAUA;AAED,eAAO,MAAM,OAAO,UAAU,CAAA"}
package/dist/config.js ADDED
@@ -0,0 +1,59 @@
1
+ /**
2
+ * CloudForge Agent Configuration
3
+ */
4
+ import { config as dotenvConfig } from 'dotenv';
5
+ import os from 'os';
6
+ // Load .env file if exists
7
+ dotenvConfig();
8
+ const DEFAULT_SERVER_URL = 'https://cloud-forge.me';
9
+ const DEFAULT_HEARTBEAT_INTERVAL = 30000; // 30 seconds
10
+ const DEFAULT_RECONNECT_DELAY = 1000; // 1 second
11
+ const MAX_RECONNECT_DELAY = 30000; // 30 seconds
12
+ /**
13
+ * Get the default shell for the current platform
14
+ */
15
+ function getDefaultShell() {
16
+ if (process.platform === 'win32') {
17
+ return process.env.COMSPEC || 'cmd.exe';
18
+ }
19
+ return process.env.SHELL || '/bin/bash';
20
+ }
21
+ /**
22
+ * Create agent configuration from environment and CLI options
23
+ */
24
+ export function createConfig(options) {
25
+ const token = options.token || process.env.CLOUDFORGE_TOKEN;
26
+ if (!token) {
27
+ throw new Error('Agent token is required. Use --token flag or set CLOUDFORGE_TOKEN environment variable.');
28
+ }
29
+ // Validate token format (cf_ prefix + 32 hex chars)
30
+ if (!/^cf_[a-f0-9]{32}$/.test(token)) {
31
+ throw new Error('Invalid token format. Token should start with "cf_" followed by 32 hex characters.');
32
+ }
33
+ return {
34
+ token,
35
+ serverUrl: options.serverUrl || process.env.CLOUDFORGE_SERVER_URL || DEFAULT_SERVER_URL,
36
+ heartbeatInterval: DEFAULT_HEARTBEAT_INTERVAL,
37
+ reconnectDelay: DEFAULT_RECONNECT_DELAY,
38
+ maxReconnectDelay: MAX_RECONNECT_DELAY,
39
+ shell: getDefaultShell(),
40
+ homeDir: os.homedir(),
41
+ debug: options.debug || process.env.CLOUDFORGE_DEBUG === 'true',
42
+ };
43
+ }
44
+ /**
45
+ * Get system information for heartbeat
46
+ */
47
+ export function getSystemInfo() {
48
+ return {
49
+ os: `${os.type()} ${os.release()}`,
50
+ hostname: os.hostname(),
51
+ platform: process.platform,
52
+ arch: process.arch,
53
+ nodeVersion: process.version,
54
+ homeDir: os.homedir(),
55
+ shell: getDefaultShell(),
56
+ };
57
+ }
58
+ export const VERSION = '0.1.0';
59
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,MAAM,IAAI,YAAY,EAAE,MAAM,QAAQ,CAAA;AAC/C,OAAO,EAAE,MAAM,IAAI,CAAA;AAEnB,2BAA2B;AAC3B,YAAY,EAAE,CAAA;AAad,MAAM,kBAAkB,GAAG,wBAAwB,CAAA;AACnD,MAAM,0BAA0B,GAAG,KAAK,CAAA,CAAC,aAAa;AACtD,MAAM,uBAAuB,GAAG,IAAI,CAAA,CAAC,WAAW;AAChD,MAAM,mBAAmB,GAAG,KAAK,CAAA,CAAC,aAAa;AAE/C;;GAEG;AACH,SAAS,eAAe;IACtB,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;QACjC,OAAO,OAAO,CAAC,GAAG,CAAC,OAAO,IAAI,SAAS,CAAA;IACzC,CAAC;IACD,OAAO,OAAO,CAAC,GAAG,CAAC,KAAK,IAAI,WAAW,CAAA;AACzC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,YAAY,CAAC,OAI5B;IACC,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAA;IAE3D,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,IAAI,KAAK,CAAC,yFAAyF,CAAC,CAAA;IAC5G,CAAC;IAED,oDAAoD;IACpD,IAAI,CAAC,mBAAmB,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QACrC,MAAM,IAAI,KAAK,CAAC,oFAAoF,CAAC,CAAA;IACvG,CAAC;IAED,OAAO;QACL,KAAK;QACL,SAAS,EAAE,OAAO,CAAC,SAAS,IAAI,OAAO,CAAC,GAAG,CAAC,qBAAqB,IAAI,kBAAkB;QACvF,iBAAiB,EAAE,0BAA0B;QAC7C,cAAc,EAAE,uBAAuB;QACvC,iBAAiB,EAAE,mBAAmB;QACtC,KAAK,EAAE,eAAe,EAAE;QACxB,OAAO,EAAE,EAAE,CAAC,OAAO,EAAE;QACrB,KAAK,EAAE,OAAO,CAAC,KAAK,IAAI,OAAO,CAAC,GAAG,CAAC,gBAAgB,KAAK,MAAM;KAChE,CAAA;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,aAAa;IAS3B,OAAO;QACL,EAAE,EAAE,GAAG,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,OAAO,EAAE,EAAE;QAClC,QAAQ,EAAE,EAAE,CAAC,QAAQ,EAAE;QACvB,QAAQ,EAAE,OAAO,CAAC,QAAQ;QAC1B,IAAI,EAAE,OAAO,CAAC,IAAI;QAClB,WAAW,EAAE,OAAO,CAAC,OAAO;QAC5B,OAAO,EAAE,EAAE,CAAC,OAAO,EAAE;QACrB,KAAK,EAAE,eAAe,EAAE;KACzB,CAAA;AACH,CAAC;AAED,MAAM,CAAC,MAAM,OAAO,GAAG,OAAO,CAAA"}
@@ -0,0 +1,84 @@
1
+ /**
2
+ * CloudForge Agent File Manager
3
+ * Manages file operations for remote file access
4
+ */
5
+ import type { AgentConfig } from './config.js';
6
+ export interface FileEntry {
7
+ name: string;
8
+ path: string;
9
+ type: 'file' | 'directory' | 'symlink' | 'other';
10
+ size: number;
11
+ modified: string;
12
+ permissions: string;
13
+ }
14
+ export interface ReadFileResult {
15
+ path: string;
16
+ content: string;
17
+ encoding: 'utf8' | 'base64';
18
+ size: number;
19
+ isBinary: boolean;
20
+ }
21
+ export interface WriteFileResult {
22
+ path: string;
23
+ success: boolean;
24
+ bytesWritten: number;
25
+ }
26
+ export interface FileOperationResult {
27
+ path: string;
28
+ success: boolean;
29
+ error?: string;
30
+ }
31
+ export declare class FileManager {
32
+ private config;
33
+ private basePath;
34
+ constructor(config: AgentConfig);
35
+ /**
36
+ * Validate and resolve a path, preventing directory traversal attacks
37
+ */
38
+ private resolvePath;
39
+ /**
40
+ * Check if a file is binary based on extension
41
+ */
42
+ private isBinaryFile;
43
+ /**
44
+ * Convert file stats to permissions string
45
+ */
46
+ private formatPermissions;
47
+ /**
48
+ * Get file type from stats
49
+ */
50
+ private getFileType;
51
+ /**
52
+ * List directory contents
53
+ */
54
+ list(dirPath: string): Promise<FileEntry[]>;
55
+ /**
56
+ * Read file contents
57
+ */
58
+ read(filePath: string): Promise<ReadFileResult>;
59
+ /**
60
+ * Write file contents
61
+ */
62
+ write(filePath: string, content: string, encoding?: 'utf8' | 'base64'): Promise<WriteFileResult>;
63
+ /**
64
+ * Delete a file or directory
65
+ */
66
+ delete(targetPath: string, recursive?: boolean): Promise<FileOperationResult>;
67
+ /**
68
+ * Create a directory
69
+ */
70
+ mkdir(dirPath: string, recursive?: boolean): Promise<FileOperationResult>;
71
+ /**
72
+ * Rename/move a file or directory
73
+ */
74
+ rename(fromPath: string, toPath: string): Promise<FileOperationResult>;
75
+ /**
76
+ * Get file/directory stats
77
+ */
78
+ stat(targetPath: string): Promise<FileEntry | null>;
79
+ /**
80
+ * Check if path exists
81
+ */
82
+ exists(targetPath: string): Promise<boolean>;
83
+ }
84
+ //# sourceMappingURL=files.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"files.d.ts","sourceRoot":"","sources":["../src/files.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAOH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAgB9C,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS,GAAG,OAAO,CAAA;IAChD,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,MAAM,CAAA;IAChB,WAAW,EAAE,MAAM,CAAA;CACpB;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,CAAA;IACf,QAAQ,EAAE,MAAM,GAAG,QAAQ,CAAA;IAC3B,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,OAAO,CAAA;CAClB;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,OAAO,CAAA;IAChB,YAAY,EAAE,MAAM,CAAA;CACrB;AAED,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,OAAO,CAAA;IAChB,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED,qBAAa,WAAW;IACtB,OAAO,CAAC,MAAM,CAAa;IAC3B,OAAO,CAAC,QAAQ,CAAQ;gBAEZ,MAAM,EAAE,WAAW;IAK/B;;OAEG;IACH,OAAO,CAAC,WAAW;IAqBnB;;OAEG;IACH,OAAO,CAAC,YAAY;IAKpB;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAQzB;;OAEG;IACH,OAAO,CAAC,WAAW;IAOnB;;OAEG;IACG,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC;IAyCjD;;OAEG;IACG,IAAI,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;IAsCrD;;OAEG;IACG,KAAK,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,GAAE,MAAM,GAAG,QAAiB,GAAG,OAAO,CAAC,eAAe,CAAC;IA6B9G;;OAEG;IACG,MAAM,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,GAAE,OAAe,GAAG,OAAO,CAAC,mBAAmB,CAAC;IA2B1F;;OAEG;IACG,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,GAAE,OAAc,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAgBrF;;OAEG;IACG,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAmB5E;;OAEG;IACG,IAAI,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC;IAsBzD;;OAEG;IACG,MAAM,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;CASnD"}
package/dist/files.js ADDED
@@ -0,0 +1,285 @@
1
+ /**
2
+ * CloudForge Agent File Manager
3
+ * Manages file operations for remote file access
4
+ */
5
+ import * as fs from 'fs/promises';
6
+ import * as path from 'path';
7
+ import * as os from 'os';
8
+ import chalk from 'chalk';
9
+ // Maximum file size to read (5MB)
10
+ const MAX_FILE_SIZE = 5 * 1024 * 1024;
11
+ // Binary file extensions
12
+ const BINARY_EXTENSIONS = new Set([
13
+ '.png', '.jpg', '.jpeg', '.gif', '.webp', '.ico', '.svg',
14
+ '.pdf', '.doc', '.docx', '.xls', '.xlsx', '.ppt', '.pptx',
15
+ '.zip', '.tar', '.gz', '.rar', '.7z',
16
+ '.exe', '.dll', '.so', '.dylib',
17
+ '.mp3', '.mp4', '.avi', '.mkv', '.mov',
18
+ '.ttf', '.otf', '.woff', '.woff2',
19
+ '.pyc', '.class', '.o', '.a',
20
+ ]);
21
+ export class FileManager {
22
+ config;
23
+ basePath;
24
+ constructor(config) {
25
+ this.config = config;
26
+ this.basePath = config.homeDir;
27
+ }
28
+ /**
29
+ * Validate and resolve a path, preventing directory traversal attacks
30
+ */
31
+ resolvePath(requestedPath) {
32
+ // Expand ~ to home directory
33
+ let expanded = requestedPath;
34
+ if (expanded === '~' || expanded.startsWith('~/')) {
35
+ expanded = expanded.replace('~', os.homedir());
36
+ }
37
+ // Normalize the path
38
+ const normalized = path.normalize(expanded);
39
+ // If it's an absolute path, use it directly
40
+ // If it's relative, resolve from basePath
41
+ const resolved = path.isAbsolute(normalized)
42
+ ? normalized
43
+ : path.resolve(this.basePath, normalized);
44
+ // For security, we don't restrict to basePath - the agent runs on user's server
45
+ // User already has full access to their filesystem via terminal
46
+ return resolved;
47
+ }
48
+ /**
49
+ * Check if a file is binary based on extension
50
+ */
51
+ isBinaryFile(filePath) {
52
+ const ext = path.extname(filePath).toLowerCase();
53
+ return BINARY_EXTENSIONS.has(ext);
54
+ }
55
+ /**
56
+ * Convert file stats to permissions string
57
+ */
58
+ formatPermissions(mode) {
59
+ const perms = ['---', '--x', '-w-', '-wx', 'r--', 'r-x', 'rw-', 'rwx'];
60
+ const user = perms[(mode >> 6) & 7];
61
+ const group = perms[(mode >> 3) & 7];
62
+ const other = perms[mode & 7];
63
+ return `${user}${group}${other}`;
64
+ }
65
+ /**
66
+ * Get file type from stats
67
+ */
68
+ getFileType(stats) {
69
+ if (stats.isFile())
70
+ return 'file';
71
+ if (stats.isDirectory())
72
+ return 'directory';
73
+ if (stats.isSymbolicLink())
74
+ return 'symlink';
75
+ return 'other';
76
+ }
77
+ /**
78
+ * List directory contents
79
+ */
80
+ async list(dirPath) {
81
+ const resolvedPath = this.resolvePath(dirPath);
82
+ if (this.config.debug) {
83
+ console.log(chalk.gray(`Files list: ${resolvedPath}`));
84
+ }
85
+ const entries = await fs.readdir(resolvedPath, { withFileTypes: true });
86
+ const results = [];
87
+ for (const entry of entries) {
88
+ try {
89
+ const entryPath = path.join(resolvedPath, entry.name);
90
+ const stats = await fs.stat(entryPath);
91
+ results.push({
92
+ name: entry.name,
93
+ path: entryPath,
94
+ type: this.getFileType(stats),
95
+ size: stats.size,
96
+ modified: stats.mtime.toISOString(),
97
+ permissions: this.formatPermissions(stats.mode),
98
+ });
99
+ }
100
+ catch (err) {
101
+ // Skip entries we can't stat (permission denied, etc.)
102
+ if (this.config.debug) {
103
+ console.log(chalk.yellow(`Cannot stat: ${entry.name}`));
104
+ }
105
+ }
106
+ }
107
+ // Sort: directories first, then files, alphabetically
108
+ results.sort((a, b) => {
109
+ if (a.type === 'directory' && b.type !== 'directory')
110
+ return -1;
111
+ if (a.type !== 'directory' && b.type === 'directory')
112
+ return 1;
113
+ return a.name.localeCompare(b.name);
114
+ });
115
+ return results;
116
+ }
117
+ /**
118
+ * Read file contents
119
+ */
120
+ async read(filePath) {
121
+ const resolvedPath = this.resolvePath(filePath);
122
+ if (this.config.debug) {
123
+ console.log(chalk.gray(`File read: ${resolvedPath}`));
124
+ }
125
+ // Check file size first
126
+ const stats = await fs.stat(resolvedPath);
127
+ if (stats.size > MAX_FILE_SIZE) {
128
+ throw new Error(`File too large (${stats.size} bytes). Maximum size is ${MAX_FILE_SIZE} bytes.`);
129
+ }
130
+ const isBinary = this.isBinaryFile(resolvedPath);
131
+ if (isBinary) {
132
+ // Read as base64 for binary files
133
+ const buffer = await fs.readFile(resolvedPath);
134
+ return {
135
+ path: resolvedPath,
136
+ content: buffer.toString('base64'),
137
+ encoding: 'base64',
138
+ size: stats.size,
139
+ isBinary: true,
140
+ };
141
+ }
142
+ else {
143
+ // Read as UTF-8 for text files
144
+ const content = await fs.readFile(resolvedPath, 'utf8');
145
+ return {
146
+ path: resolvedPath,
147
+ content,
148
+ encoding: 'utf8',
149
+ size: stats.size,
150
+ isBinary: false,
151
+ };
152
+ }
153
+ }
154
+ /**
155
+ * Write file contents
156
+ */
157
+ async write(filePath, content, encoding = 'utf8') {
158
+ const resolvedPath = this.resolvePath(filePath);
159
+ if (this.config.debug) {
160
+ console.log(chalk.gray(`File write: ${resolvedPath}`));
161
+ }
162
+ // Ensure parent directory exists
163
+ const dir = path.dirname(resolvedPath);
164
+ await fs.mkdir(dir, { recursive: true });
165
+ if (encoding === 'base64') {
166
+ const buffer = Buffer.from(content, 'base64');
167
+ await fs.writeFile(resolvedPath, buffer);
168
+ return {
169
+ path: resolvedPath,
170
+ success: true,
171
+ bytesWritten: buffer.length,
172
+ };
173
+ }
174
+ else {
175
+ await fs.writeFile(resolvedPath, content, 'utf8');
176
+ return {
177
+ path: resolvedPath,
178
+ success: true,
179
+ bytesWritten: Buffer.byteLength(content, 'utf8'),
180
+ };
181
+ }
182
+ }
183
+ /**
184
+ * Delete a file or directory
185
+ */
186
+ async delete(targetPath, recursive = false) {
187
+ const resolvedPath = this.resolvePath(targetPath);
188
+ if (this.config.debug) {
189
+ console.log(chalk.gray(`File delete: ${resolvedPath}, recursive=${recursive}`));
190
+ }
191
+ try {
192
+ const stats = await fs.stat(resolvedPath);
193
+ if (stats.isDirectory()) {
194
+ if (recursive) {
195
+ await fs.rm(resolvedPath, { recursive: true, force: true });
196
+ }
197
+ else {
198
+ await fs.rmdir(resolvedPath);
199
+ }
200
+ }
201
+ else {
202
+ await fs.unlink(resolvedPath);
203
+ }
204
+ return { path: resolvedPath, success: true };
205
+ }
206
+ catch (err) {
207
+ const error = err;
208
+ return { path: resolvedPath, success: false, error: error.message };
209
+ }
210
+ }
211
+ /**
212
+ * Create a directory
213
+ */
214
+ async mkdir(dirPath, recursive = true) {
215
+ const resolvedPath = this.resolvePath(dirPath);
216
+ if (this.config.debug) {
217
+ console.log(chalk.gray(`Mkdir: ${resolvedPath}`));
218
+ }
219
+ try {
220
+ await fs.mkdir(resolvedPath, { recursive });
221
+ return { path: resolvedPath, success: true };
222
+ }
223
+ catch (err) {
224
+ const error = err;
225
+ return { path: resolvedPath, success: false, error: error.message };
226
+ }
227
+ }
228
+ /**
229
+ * Rename/move a file or directory
230
+ */
231
+ async rename(fromPath, toPath) {
232
+ const resolvedFrom = this.resolvePath(fromPath);
233
+ const resolvedTo = this.resolvePath(toPath);
234
+ if (this.config.debug) {
235
+ console.log(chalk.gray(`Rename: ${resolvedFrom} -> ${resolvedTo}`));
236
+ }
237
+ try {
238
+ // Ensure parent directory of destination exists
239
+ await fs.mkdir(path.dirname(resolvedTo), { recursive: true });
240
+ await fs.rename(resolvedFrom, resolvedTo);
241
+ return { path: resolvedTo, success: true };
242
+ }
243
+ catch (err) {
244
+ const error = err;
245
+ return { path: resolvedTo, success: false, error: error.message };
246
+ }
247
+ }
248
+ /**
249
+ * Get file/directory stats
250
+ */
251
+ async stat(targetPath) {
252
+ const resolvedPath = this.resolvePath(targetPath);
253
+ if (this.config.debug) {
254
+ console.log(chalk.gray(`Stat: ${resolvedPath}`));
255
+ }
256
+ try {
257
+ const stats = await fs.stat(resolvedPath);
258
+ return {
259
+ name: path.basename(resolvedPath),
260
+ path: resolvedPath,
261
+ type: this.getFileType(stats),
262
+ size: stats.size,
263
+ modified: stats.mtime.toISOString(),
264
+ permissions: this.formatPermissions(stats.mode),
265
+ };
266
+ }
267
+ catch {
268
+ return null;
269
+ }
270
+ }
271
+ /**
272
+ * Check if path exists
273
+ */
274
+ async exists(targetPath) {
275
+ const resolvedPath = this.resolvePath(targetPath);
276
+ try {
277
+ await fs.access(resolvedPath);
278
+ return true;
279
+ }
280
+ catch {
281
+ return false;
282
+ }
283
+ }
284
+ }
285
+ //# sourceMappingURL=files.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"files.js","sourceRoot":"","sources":["../src/files.ts"],"names":[],"mappings":"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"}