agentfs-sdk 0.2.0-pre.2 → 0.2.0-pre.3

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.
@@ -17,10 +17,15 @@ export declare class Filesystem {
17
17
  private db;
18
18
  private initialized;
19
19
  private rootIno;
20
+ private chunkSize;
20
21
  constructor(db: Database);
22
+ /**
23
+ * Get the configured chunk size
24
+ */
25
+ getChunkSize(): number;
21
26
  private initialize;
22
27
  /**
23
- * Ensure root directory exists
28
+ * Ensure config and root directory exist, returns the chunk_size
24
29
  */
25
30
  private ensureRoot;
26
31
  /**
@@ -57,7 +62,7 @@ export declare class Filesystem {
57
62
  private getLinkCount;
58
63
  writeFile(path: string, content: string | Buffer): Promise<void>;
59
64
  private updateFileContent;
60
- readFile(path: string): Promise<string>;
65
+ readFile(path: string, encoding?: BufferEncoding): Promise<Buffer | string>;
61
66
  readdir(path: string): Promise<string[]>;
62
67
  deleteFile(path: string): Promise<void>;
63
68
  stat(path: string): Promise<Stats>;
@@ -9,12 +9,20 @@ const S_IFLNK = 0o120000; // Symbolic link
9
9
  // Default permissions
10
10
  const DEFAULT_FILE_MODE = S_IFREG | 0o644; // Regular file, rw-r--r--
11
11
  const DEFAULT_DIR_MODE = S_IFDIR | 0o755; // Directory, rwxr-xr-x
12
+ const DEFAULT_CHUNK_SIZE = 4096;
12
13
  class Filesystem {
13
14
  constructor(db) {
14
15
  this.rootIno = 1;
16
+ this.chunkSize = DEFAULT_CHUNK_SIZE;
15
17
  this.db = db;
16
18
  this.initialized = this.initialize();
17
19
  }
20
+ /**
21
+ * Get the configured chunk size
22
+ */
23
+ getChunkSize() {
24
+ return this.chunkSize;
25
+ }
18
26
  async initialize() {
19
27
  // Ensure database is connected
20
28
  try {
@@ -26,6 +34,13 @@ class Filesystem {
26
34
  throw error;
27
35
  }
28
36
  }
37
+ // Create the config table
38
+ await this.db.exec(`
39
+ CREATE TABLE IF NOT EXISTS fs_config (
40
+ key TEXT PRIMARY KEY,
41
+ value TEXT NOT NULL
42
+ )
43
+ `);
29
44
  // Create the inode table
30
45
  await this.db.exec(`
31
46
  CREATE TABLE IF NOT EXISTS fs_inode (
@@ -54,20 +69,14 @@ class Filesystem {
54
69
  CREATE INDEX IF NOT EXISTS idx_fs_dentry_parent
55
70
  ON fs_dentry(parent_ino, name)
56
71
  `);
57
- // Create the data blocks table
72
+ // Create the data chunks table
58
73
  await this.db.exec(`
59
74
  CREATE TABLE IF NOT EXISTS fs_data (
60
- id INTEGER PRIMARY KEY AUTOINCREMENT,
61
75
  ino INTEGER NOT NULL,
62
- offset INTEGER NOT NULL,
63
- size INTEGER NOT NULL,
64
- data BLOB NOT NULL
76
+ chunk_index INTEGER NOT NULL,
77
+ data BLOB NOT NULL,
78
+ PRIMARY KEY (ino, chunk_index)
65
79
  )
66
- `);
67
- // Create index for efficient data block lookups
68
- await this.db.exec(`
69
- CREATE INDEX IF NOT EXISTS idx_fs_data_ino_offset
70
- ON fs_data(ino, offset)
71
80
  `);
72
81
  // Create the symlink table
73
82
  await this.db.exec(`
@@ -76,13 +85,28 @@ class Filesystem {
76
85
  target TEXT NOT NULL
77
86
  )
78
87
  `);
79
- // Create root directory if it doesn't exist
80
- await this.ensureRoot();
88
+ // Initialize config and root directory, and get chunk_size
89
+ this.chunkSize = await this.ensureRoot();
81
90
  }
82
91
  /**
83
- * Ensure root directory exists
92
+ * Ensure config and root directory exist, returns the chunk_size
84
93
  */
85
94
  async ensureRoot() {
95
+ // Ensure chunk_size config exists and get its value
96
+ const configStmt = this.db.prepare("SELECT value FROM fs_config WHERE key = 'chunk_size'");
97
+ const config = await configStmt.get();
98
+ let chunkSize;
99
+ if (!config) {
100
+ const insertConfigStmt = this.db.prepare(`
101
+ INSERT INTO fs_config (key, value) VALUES ('chunk_size', ?)
102
+ `);
103
+ await insertConfigStmt.run(DEFAULT_CHUNK_SIZE.toString());
104
+ chunkSize = DEFAULT_CHUNK_SIZE;
105
+ }
106
+ else {
107
+ chunkSize = parseInt(config.value, 10) || DEFAULT_CHUNK_SIZE;
108
+ }
109
+ // Ensure root directory exists
86
110
  const stmt = this.db.prepare('SELECT ino FROM fs_inode WHERE ino = ?');
87
111
  const root = await stmt.get(this.rootIno);
88
112
  if (!root) {
@@ -93,6 +117,7 @@ class Filesystem {
93
117
  `);
94
118
  await insertStmt.run(this.rootIno, DEFAULT_DIR_MODE, now, now, now);
95
119
  }
120
+ return chunkSize;
96
121
  }
97
122
  /**
98
123
  * Normalize a path
@@ -240,15 +265,22 @@ class Filesystem {
240
265
  async updateFileContent(ino, content) {
241
266
  const buffer = typeof content === 'string' ? Buffer.from(content, 'utf-8') : content;
242
267
  const now = Math.floor(Date.now() / 1000);
243
- // Delete existing data blocks
268
+ // Delete existing data chunks
244
269
  const deleteStmt = this.db.prepare('DELETE FROM fs_data WHERE ino = ?');
245
270
  await deleteStmt.run(ino);
246
- // Write data in chunks (for now, single chunk, but can be extended)
247
- const stmt = this.db.prepare(`
248
- INSERT INTO fs_data (ino, offset, size, data)
249
- VALUES (?, ?, ?, ?)
250
- `);
251
- await stmt.run(ino, 0, buffer.length, buffer);
271
+ // Write data in chunks
272
+ if (buffer.length > 0) {
273
+ const stmt = this.db.prepare(`
274
+ INSERT INTO fs_data (ino, chunk_index, data)
275
+ VALUES (?, ?, ?)
276
+ `);
277
+ let chunkIndex = 0;
278
+ for (let offset = 0; offset < buffer.length; offset += this.chunkSize) {
279
+ const chunk = buffer.subarray(offset, Math.min(offset + this.chunkSize, buffer.length));
280
+ await stmt.run(ino, chunkIndex, chunk);
281
+ chunkIndex++;
282
+ }
283
+ }
252
284
  // Update inode size and mtime
253
285
  const updateStmt = this.db.prepare(`
254
286
  UPDATE fs_inode
@@ -257,30 +289,36 @@ class Filesystem {
257
289
  `);
258
290
  await updateStmt.run(buffer.length, now, ino);
259
291
  }
260
- async readFile(path) {
292
+ async readFile(path, encoding) {
261
293
  await this.initialized;
262
294
  const ino = await this.resolvePath(path);
263
295
  if (ino === null) {
264
296
  throw new Error(`ENOENT: no such file or directory, open '${path}'`);
265
297
  }
266
- // Get all data blocks
298
+ // Get all data chunks
267
299
  const stmt = this.db.prepare(`
268
300
  SELECT data FROM fs_data
269
301
  WHERE ino = ?
270
- ORDER BY offset ASC
302
+ ORDER BY chunk_index ASC
271
303
  `);
272
304
  const rows = await stmt.all(ino);
305
+ let combined;
273
306
  if (rows.length === 0) {
274
- return '';
307
+ combined = Buffer.alloc(0);
308
+ }
309
+ else {
310
+ // Concatenate all chunks
311
+ const buffers = rows.map(row => row.data);
312
+ combined = Buffer.concat(buffers);
275
313
  }
276
- // Concatenate all chunks
277
- const buffers = rows.map(row => row.data);
278
- const combined = Buffer.concat(buffers);
279
314
  // Update atime
280
315
  const now = Math.floor(Date.now() / 1000);
281
316
  const updateStmt = this.db.prepare('UPDATE fs_inode SET atime = ? WHERE ino = ?');
282
317
  await updateStmt.run(now, ino);
283
- return combined.toString('utf-8');
318
+ if (encoding) {
319
+ return combined.toString(encoding);
320
+ }
321
+ return combined;
284
322
  }
285
323
  async readdir(path) {
286
324
  await this.initialized;
@@ -316,9 +354,12 @@ class Filesystem {
316
354
  // Check if this was the last link to the inode
317
355
  const linkCount = await this.getLinkCount(ino);
318
356
  if (linkCount === 0) {
319
- // Delete the inode and all associated data (CASCADE will handle data blocks)
320
- const deleteStmt = this.db.prepare('DELETE FROM fs_inode WHERE ino = ?');
321
- await deleteStmt.run(ino);
357
+ // Delete the inode
358
+ const deleteInodeStmt = this.db.prepare('DELETE FROM fs_inode WHERE ino = ?');
359
+ await deleteInodeStmt.run(ino);
360
+ // Delete all data chunks
361
+ const deleteDataStmt = this.db.prepare('DELETE FROM fs_data WHERE ino = ?');
362
+ await deleteDataStmt.run(ino);
322
363
  }
323
364
  }
324
365
  async stat(path) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentfs-sdk",
3
- "version": "0.2.0-pre.2",
3
+ "version": "0.2.0-pre.3",
4
4
  "description": "AgentFS SDK",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",