@aigne/afs 1.4.0-beta.1 → 1.4.0-beta.10
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/CHANGELOG.md +87 -0
- package/lib/cjs/afs.d.ts +10 -0
- package/lib/cjs/afs.js +109 -41
- package/lib/cjs/error.d.ts +13 -0
- package/lib/cjs/error.js +25 -0
- package/lib/cjs/index.d.ts +1 -0
- package/lib/cjs/index.js +1 -0
- package/lib/cjs/type.d.ts +94 -22
- package/lib/cjs/type.js +9 -1
- package/lib/dts/afs.d.ts +10 -0
- package/lib/dts/error.d.ts +13 -0
- package/lib/dts/index.d.ts +1 -0
- package/lib/dts/type.d.ts +94 -22
- package/lib/esm/afs.d.ts +10 -0
- package/lib/esm/afs.js +109 -41
- package/lib/esm/error.d.ts +13 -0
- package/lib/esm/error.js +20 -0
- package/lib/esm/index.d.ts +1 -0
- package/lib/esm/index.js +1 -0
- package/lib/esm/type.d.ts +94 -22
- package/lib/esm/type.js +8 -0
- package/package.json +5 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,92 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [1.4.0-beta.10](https://github.com/AIGNE-io/aigne-framework/compare/afs-v1.4.0-beta.9...afs-v1.4.0-beta.10) (2026-01-16)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* **afs:** improve list behavior to always include current path ([cb91f80](https://github.com/AIGNE-io/aigne-framework/commit/cb91f80c6ea3aa6e93dde26b6feeea8689fceb48))
|
|
9
|
+
|
|
10
|
+
## [1.4.0-beta.9](https://github.com/AIGNE-io/aigne-framework/compare/afs-v1.4.0-beta.8...afs-v1.4.0-beta.9) (2026-01-14)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
### Features
|
|
14
|
+
|
|
15
|
+
* **afs:** add module access control and schema validation support ([#904](https://github.com/AIGNE-io/aigne-framework/issues/904)) ([d0b279a](https://github.com/AIGNE-io/aigne-framework/commit/d0b279aac07ebe2bcc1fd4148498fc3f6bbcd561))
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
### Bug Fixes
|
|
19
|
+
|
|
20
|
+
* improve test coverage tracking and reporting ([#903](https://github.com/AIGNE-io/aigne-framework/issues/903)) ([031144e](https://github.com/AIGNE-io/aigne-framework/commit/031144e74f29e882cffe52ffda8f7a18c76ace7f))
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
### Dependencies
|
|
24
|
+
|
|
25
|
+
* The following workspace dependencies were updated
|
|
26
|
+
* dependencies
|
|
27
|
+
* @aigne/platform-helpers bumped to 0.6.7-beta.2
|
|
28
|
+
|
|
29
|
+
## [1.4.0-beta.8](https://github.com/AIGNE-io/aigne-framework/compare/afs-v1.4.0-beta.7...afs-v1.4.0-beta.8) (2026-01-12)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
### Bug Fixes
|
|
33
|
+
|
|
34
|
+
* **afs:** show gitignored files with marker instead of filtering ([c2bdea1](https://github.com/AIGNE-io/aigne-framework/commit/c2bdea155f47c9420f2fe810cdfed79ef70ef899))
|
|
35
|
+
|
|
36
|
+
## [1.4.0-beta.7](https://github.com/AIGNE-io/aigne-framework/compare/afs-v1.4.0-beta.6...afs-v1.4.0-beta.7) (2026-01-08)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
### Features
|
|
40
|
+
|
|
41
|
+
* **afs,bash:** add physical path mapping for AFS modules in bash execution ([#881](https://github.com/AIGNE-io/aigne-framework/issues/881)) ([50dbda2](https://github.com/AIGNE-io/aigne-framework/commit/50dbda224bd666d951494d2449779830d8db57fc))
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
### Bug Fixes
|
|
45
|
+
|
|
46
|
+
* bump version ([696560f](https://github.com/AIGNE-io/aigne-framework/commit/696560fa2673eddcb4d00ac0523fbbbde7273cb3))
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
### Dependencies
|
|
50
|
+
|
|
51
|
+
* The following workspace dependencies were updated
|
|
52
|
+
* dependencies
|
|
53
|
+
* @aigne/platform-helpers bumped to 0.6.7-beta.1
|
|
54
|
+
|
|
55
|
+
## [1.4.0-beta.6](https://github.com/AIGNE-io/aigne-framework/compare/afs-v1.4.0-beta.5...afs-v1.4.0-beta.6) (2026-01-06)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
### Bug Fixes
|
|
59
|
+
|
|
60
|
+
* **afs:** throw errors instead of logging in AFS module operations ([#874](https://github.com/AIGNE-io/aigne-framework/issues/874)) ([f0cc1c4](https://github.com/AIGNE-io/aigne-framework/commit/f0cc1c4056f8b95b631d595892bb12eb75da4b9f))
|
|
61
|
+
|
|
62
|
+
## [1.4.0-beta.5](https://github.com/AIGNE-io/aigne-framework/compare/afs-v1.4.0-beta.4...afs-v1.4.0-beta.5) (2025-12-31)
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
### Features
|
|
66
|
+
|
|
67
|
+
* add session compact support for AIAgent ([#863](https://github.com/AIGNE-io/aigne-framework/issues/863)) ([9010918](https://github.com/AIGNE-io/aigne-framework/commit/9010918cd3f18b02b5c60ddc9ed5c34b568d0b28))
|
|
68
|
+
|
|
69
|
+
## [1.4.0-beta.4](https://github.com/AIGNE-io/aigne-framework/compare/afs-v1.4.0-beta.3...afs-v1.4.0-beta.4) (2025-12-26)
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
### Features
|
|
73
|
+
|
|
74
|
+
* **core:** add session history support ([#858](https://github.com/AIGNE-io/aigne-framework/issues/858)) ([28a070e](https://github.com/AIGNE-io/aigne-framework/commit/28a070ed33b821d1fd344b899706d817ca992b9f))
|
|
75
|
+
|
|
76
|
+
## [1.4.0-beta.3](https://github.com/AIGNE-io/aigne-framework/compare/afs-v1.4.0-beta.2...afs-v1.4.0-beta.3) (2025-12-24)
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
### Features
|
|
80
|
+
|
|
81
|
+
* add Agent Skill support ([#787](https://github.com/AIGNE-io/aigne-framework/issues/787)) ([f04fbe7](https://github.com/AIGNE-io/aigne-framework/commit/f04fbe76ec24cf3c59c74adf92d87b0c3784a8f7))
|
|
82
|
+
|
|
83
|
+
## [1.4.0-beta.2](https://github.com/AIGNE-io/aigne-framework/compare/afs-v1.4.0-beta.1...afs-v1.4.0-beta.2) (2025-12-19)
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
### Bug Fixes
|
|
87
|
+
|
|
88
|
+
* **afs:** use simple-list instead of tree as default type ([#839](https://github.com/AIGNE-io/aigne-framework/issues/839)) ([65a9a40](https://github.com/AIGNE-io/aigne-framework/commit/65a9a4054b3bdad6f7e40357299ef3dc48f7c3e4))
|
|
89
|
+
|
|
3
90
|
## [1.4.0-beta.1](https://github.com/AIGNE-io/aigne-framework/compare/afs-v1.4.0-beta...afs-v1.4.0-beta.1) (2025-12-17)
|
|
4
91
|
|
|
5
92
|
|
package/lib/cjs/afs.d.ts
CHANGED
|
@@ -9,6 +9,11 @@ export declare class AFS extends Emitter<AFSRootEvents> implements AFSRoot {
|
|
|
9
9
|
name: string;
|
|
10
10
|
constructor(options?: AFSOptions);
|
|
11
11
|
private modules;
|
|
12
|
+
/**
|
|
13
|
+
* Check if write operations are allowed for the given module.
|
|
14
|
+
* Throws AFSReadonlyError if not allowed.
|
|
15
|
+
*/
|
|
16
|
+
private checkWritePermission;
|
|
12
17
|
mount(module: AFSModule): this;
|
|
13
18
|
listModules(): Promise<{
|
|
14
19
|
name: string;
|
|
@@ -28,5 +33,10 @@ export declare class AFS extends Emitter<AFSRootEvents> implements AFSRoot {
|
|
|
28
33
|
private _search;
|
|
29
34
|
private findModules;
|
|
30
35
|
exec(path: string, args: Record<string, any>, options: AFSExecOptions): Promise<AFSExecResult>;
|
|
36
|
+
private buildSimpleListView;
|
|
31
37
|
private buildTreeView;
|
|
38
|
+
private buildMetadataSuffix;
|
|
39
|
+
private physicalPath?;
|
|
40
|
+
initializePhysicalPath(): Promise<string>;
|
|
41
|
+
cleanupPhysicalPath(): Promise<void>;
|
|
32
42
|
}
|
package/lib/cjs/afs.js
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.AFS = void 0;
|
|
4
|
+
const index_js_1 = require("@aigne/platform-helpers/nodejs/index.js");
|
|
5
|
+
const uuid_1 = require("@aigne/uuid");
|
|
4
6
|
const strict_event_emitter_1 = require("strict-event-emitter");
|
|
5
7
|
const ufo_1 = require("ufo");
|
|
6
8
|
const zod_1 = require("zod");
|
|
9
|
+
const error_js_1 = require("./error.js");
|
|
7
10
|
const type_js_1 = require("./type.js");
|
|
8
11
|
const DEFAULT_MAX_DEPTH = 1;
|
|
9
12
|
const MODULES_ROOT_DIR = "/modules";
|
|
@@ -18,12 +21,22 @@ class AFS extends strict_event_emitter_1.Emitter {
|
|
|
18
21
|
}
|
|
19
22
|
}
|
|
20
23
|
modules = new Map();
|
|
24
|
+
/**
|
|
25
|
+
* Check if write operations are allowed for the given module.
|
|
26
|
+
* Throws AFSReadonlyError if not allowed.
|
|
27
|
+
*/
|
|
28
|
+
checkWritePermission(module, operation, path) {
|
|
29
|
+
// Module-level readonly (undefined means readonly by default)
|
|
30
|
+
if (module.accessMode !== "readwrite") {
|
|
31
|
+
throw new error_js_1.AFSReadonlyError(`Module '${module.name}' is readonly, cannot perform ${operation} to ${path}`);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
21
34
|
mount(module) {
|
|
22
|
-
|
|
23
|
-
if (
|
|
24
|
-
throw new Error(`Invalid
|
|
35
|
+
// Validate module name (should not contain '/')
|
|
36
|
+
if (module.name.includes("/")) {
|
|
37
|
+
throw new Error(`Invalid module name: ${module.name}. Module name must not contain '/'`);
|
|
25
38
|
}
|
|
26
|
-
path = (0, ufo_1.joinURL)(MODULES_ROOT_DIR,
|
|
39
|
+
const path = (0, ufo_1.joinURL)(MODULES_ROOT_DIR, module.name);
|
|
27
40
|
if (this.modules.has(path)) {
|
|
28
41
|
throw new Error(`Module already mounted at path: ${path}`);
|
|
29
42
|
}
|
|
@@ -53,14 +66,36 @@ class AFS extends strict_event_emitter_1.Emitter {
|
|
|
53
66
|
}
|
|
54
67
|
async _list(path, options = {}) {
|
|
55
68
|
const results = [];
|
|
69
|
+
// Special case: listing root "/" should return /modules directory
|
|
70
|
+
if (path === "/" && this.modules.size > 0) {
|
|
71
|
+
const maxDepth = options?.maxDepth ?? DEFAULT_MAX_DEPTH;
|
|
72
|
+
// Always include /modules directory first
|
|
73
|
+
results.push({
|
|
74
|
+
id: "modules",
|
|
75
|
+
path: MODULES_ROOT_DIR,
|
|
76
|
+
summary: "All mounted modules",
|
|
77
|
+
});
|
|
78
|
+
if (maxDepth === 1) {
|
|
79
|
+
// Only show /modules directory
|
|
80
|
+
return { data: results };
|
|
81
|
+
}
|
|
82
|
+
// For maxDepth > 1, also get children of /modules with reduced depth
|
|
83
|
+
const childrenResult = await this._list(MODULES_ROOT_DIR, {
|
|
84
|
+
...options,
|
|
85
|
+
maxDepth: maxDepth - 1,
|
|
86
|
+
});
|
|
87
|
+
results.push(...childrenResult.data);
|
|
88
|
+
return { data: results };
|
|
89
|
+
}
|
|
56
90
|
const matches = this.findModules(path, options);
|
|
57
91
|
for (const matched of matches) {
|
|
58
|
-
const moduleEntry = {
|
|
59
|
-
id: matched.module.name,
|
|
60
|
-
path: matched.remainedModulePath,
|
|
61
|
-
summary: matched.module.description,
|
|
62
|
-
};
|
|
63
92
|
if (matched.maxDepth === 0) {
|
|
93
|
+
// When maxDepth is 0, show the module entry
|
|
94
|
+
const moduleEntry = {
|
|
95
|
+
id: matched.module.name,
|
|
96
|
+
path: matched.modulePath,
|
|
97
|
+
summary: matched.module.description,
|
|
98
|
+
};
|
|
64
99
|
results.push(moduleEntry);
|
|
65
100
|
continue;
|
|
66
101
|
}
|
|
@@ -71,18 +106,16 @@ class AFS extends strict_event_emitter_1.Emitter {
|
|
|
71
106
|
...options,
|
|
72
107
|
maxDepth: matched.maxDepth,
|
|
73
108
|
});
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
results.push(moduleEntry);
|
|
82
|
-
}
|
|
109
|
+
const children = data.map((entry) => ({
|
|
110
|
+
...entry,
|
|
111
|
+
path: (0, ufo_1.joinURL)(matched.modulePath, entry.path),
|
|
112
|
+
}));
|
|
113
|
+
// Always include all nodes (including the current path itself)
|
|
114
|
+
// This ensures consistent behavior across all listing scenarios
|
|
115
|
+
results.push(...children);
|
|
83
116
|
}
|
|
84
117
|
catch (error) {
|
|
85
|
-
|
|
118
|
+
throw new Error(`Error listing from module at ${matched.modulePath}: ${error.message}`);
|
|
86
119
|
}
|
|
87
120
|
}
|
|
88
121
|
return { data: results };
|
|
@@ -107,6 +140,7 @@ class AFS extends strict_event_emitter_1.Emitter {
|
|
|
107
140
|
const module = this.findModules(path, { exactMatch: true })[0];
|
|
108
141
|
if (!module?.module.write)
|
|
109
142
|
throw new Error(`No module found for path: ${path}`);
|
|
143
|
+
this.checkWritePermission(module.module, "write", path);
|
|
110
144
|
const res = await module.module.write(module.subpath, content, options);
|
|
111
145
|
return {
|
|
112
146
|
...res,
|
|
@@ -120,6 +154,7 @@ class AFS extends strict_event_emitter_1.Emitter {
|
|
|
120
154
|
const module = this.findModules(path, { exactMatch: true })[0];
|
|
121
155
|
if (!module?.module.delete)
|
|
122
156
|
throw new Error(`No module found for path: ${path}`);
|
|
157
|
+
this.checkWritePermission(module.module, "delete", path);
|
|
123
158
|
return await module.module.delete(module.subpath, options);
|
|
124
159
|
}
|
|
125
160
|
async rename(oldPath, newPath, options) {
|
|
@@ -132,6 +167,7 @@ class AFS extends strict_event_emitter_1.Emitter {
|
|
|
132
167
|
if (!oldModule.module.rename) {
|
|
133
168
|
throw new Error(`Module does not support rename operation: ${oldModule.modulePath}`);
|
|
134
169
|
}
|
|
170
|
+
this.checkWritePermission(oldModule.module, "rename", oldPath);
|
|
135
171
|
return await oldModule.module.rename(oldModule.subpath, newModule.subpath, options);
|
|
136
172
|
}
|
|
137
173
|
async search(path, query, options = {}) {
|
|
@@ -161,12 +197,14 @@ class AFS extends strict_event_emitter_1.Emitter {
|
|
|
161
197
|
? await dedupe.invoke({ data: mapped }, options).then((res) => res.data)
|
|
162
198
|
: mapped;
|
|
163
199
|
let formatted = deduped;
|
|
164
|
-
if (format === "tree") {
|
|
200
|
+
if (format === "simple-list" || format === "tree") {
|
|
165
201
|
const valid = zod_1.z.array(type_js_1.afsEntrySchema).safeParse(deduped);
|
|
166
|
-
if (valid.data)
|
|
167
|
-
formatted = this.buildTreeView(valid.data);
|
|
168
|
-
else
|
|
202
|
+
if (!valid.data)
|
|
169
203
|
throw new Error("Tree format requires entries to be AFSEntry objects");
|
|
204
|
+
if (format === "tree")
|
|
205
|
+
formatted = this.buildTreeView(valid.data);
|
|
206
|
+
else if (format === "simple-list")
|
|
207
|
+
formatted = this.buildSimpleListView(valid.data);
|
|
170
208
|
}
|
|
171
209
|
else if (typeof format === "object" && typeof format.invoke === "function") {
|
|
172
210
|
formatted = await format.invoke({ data: deduped }, options).then((res) => res.data);
|
|
@@ -194,7 +232,7 @@ class AFS extends strict_event_emitter_1.Emitter {
|
|
|
194
232
|
messages.push(message);
|
|
195
233
|
}
|
|
196
234
|
catch (error) {
|
|
197
|
-
|
|
235
|
+
throw new Error(`Error searching in module at ${modulePath}: ${error.message}`);
|
|
198
236
|
}
|
|
199
237
|
}
|
|
200
238
|
return { data: results, message: messages.join("; ") };
|
|
@@ -233,6 +271,9 @@ class AFS extends strict_event_emitter_1.Emitter {
|
|
|
233
271
|
throw new Error(`No module found for path: ${path}`);
|
|
234
272
|
return await module.module.exec(module.subpath, args, options);
|
|
235
273
|
}
|
|
274
|
+
buildSimpleListView(entries) {
|
|
275
|
+
return entries.map((entry) => `${entry.path}${this.buildMetadataSuffix(entry)}`);
|
|
276
|
+
}
|
|
236
277
|
buildTreeView(entries) {
|
|
237
278
|
const tree = {};
|
|
238
279
|
const entryMap = new Map();
|
|
@@ -254,23 +295,7 @@ class AFS extends strict_event_emitter_1.Emitter {
|
|
|
254
295
|
const isLast = index === keys.length - 1;
|
|
255
296
|
const fullPath = currentPath ? `${currentPath}/${key}` : `/${key}`;
|
|
256
297
|
const entry = entryMap.get(fullPath);
|
|
257
|
-
|
|
258
|
-
const metadataParts = [];
|
|
259
|
-
// Children count
|
|
260
|
-
const childrenCount = entry?.metadata?.childrenCount;
|
|
261
|
-
if (typeof childrenCount === "number") {
|
|
262
|
-
metadataParts.push(`${childrenCount} items`);
|
|
263
|
-
}
|
|
264
|
-
// Children truncated
|
|
265
|
-
if (entry?.metadata?.childrenTruncated) {
|
|
266
|
-
metadataParts.push("truncated");
|
|
267
|
-
}
|
|
268
|
-
// Executable
|
|
269
|
-
if (entry?.metadata?.execute) {
|
|
270
|
-
metadataParts.push("executable");
|
|
271
|
-
}
|
|
272
|
-
const metadataSuffix = metadataParts.length > 0 ? ` [${metadataParts.join(", ")}]` : "";
|
|
273
|
-
result += `${prefix}${isLast ? "└── " : "├── "}${key}${metadataSuffix}`;
|
|
298
|
+
result += `${prefix}${isLast ? "└── " : "├── "}${key}${entry ? this.buildMetadataSuffix(entry) : ""}`;
|
|
274
299
|
result += `\n`;
|
|
275
300
|
result += renderTree(node[key], `${prefix}${isLast ? " " : "│ "}`, fullPath);
|
|
276
301
|
});
|
|
@@ -278,5 +303,48 @@ class AFS extends strict_event_emitter_1.Emitter {
|
|
|
278
303
|
};
|
|
279
304
|
return renderTree(tree);
|
|
280
305
|
}
|
|
306
|
+
buildMetadataSuffix(entry) {
|
|
307
|
+
// Build metadata suffix
|
|
308
|
+
const metadataParts = [];
|
|
309
|
+
// Children count
|
|
310
|
+
const childrenCount = entry?.metadata?.childrenCount;
|
|
311
|
+
if (typeof childrenCount === "number") {
|
|
312
|
+
metadataParts.push(`${childrenCount} items`);
|
|
313
|
+
}
|
|
314
|
+
// Children truncated
|
|
315
|
+
if (entry?.metadata?.childrenTruncated) {
|
|
316
|
+
metadataParts.push("truncated");
|
|
317
|
+
}
|
|
318
|
+
// Gitignored
|
|
319
|
+
if (entry?.metadata?.gitignored) {
|
|
320
|
+
metadataParts.push("gitignored");
|
|
321
|
+
}
|
|
322
|
+
// Executable
|
|
323
|
+
if (entry?.metadata?.execute) {
|
|
324
|
+
metadataParts.push("executable");
|
|
325
|
+
}
|
|
326
|
+
const metadataSuffix = metadataParts.length > 0 ? ` [${metadataParts.join(", ")}]` : "";
|
|
327
|
+
return metadataSuffix;
|
|
328
|
+
}
|
|
329
|
+
physicalPath;
|
|
330
|
+
async initializePhysicalPath() {
|
|
331
|
+
this.physicalPath ??= (async () => {
|
|
332
|
+
const rootDir = index_js_1.nodejs.path.join(index_js_1.nodejs.os.tmpdir(), (0, uuid_1.v7)());
|
|
333
|
+
await index_js_1.nodejs.fs.mkdir(rootDir, { recursive: true });
|
|
334
|
+
for (const [modulePath, module] of this.modules) {
|
|
335
|
+
const physicalModulePath = index_js_1.nodejs.path.join(rootDir, modulePath);
|
|
336
|
+
await index_js_1.nodejs.fs.mkdir(index_js_1.nodejs.path.dirname(physicalModulePath), { recursive: true });
|
|
337
|
+
await module.symlinkToPhysical?.(physicalModulePath);
|
|
338
|
+
}
|
|
339
|
+
return rootDir;
|
|
340
|
+
})();
|
|
341
|
+
return this.physicalPath;
|
|
342
|
+
}
|
|
343
|
+
async cleanupPhysicalPath() {
|
|
344
|
+
if (this.physicalPath) {
|
|
345
|
+
await index_js_1.nodejs.fs.rm(await this.physicalPath, { recursive: true, force: true });
|
|
346
|
+
this.physicalPath = undefined;
|
|
347
|
+
}
|
|
348
|
+
}
|
|
281
349
|
}
|
|
282
350
|
exports.AFS = AFS;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base error class for all AFS errors.
|
|
3
|
+
*/
|
|
4
|
+
export declare class AFSError extends Error {
|
|
5
|
+
readonly code: string;
|
|
6
|
+
constructor(message: string, code: string);
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Error thrown when attempting write operations on a readonly AFS or module.
|
|
10
|
+
*/
|
|
11
|
+
export declare class AFSReadonlyError extends AFSError {
|
|
12
|
+
constructor(message: string);
|
|
13
|
+
}
|
package/lib/cjs/error.js
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AFSReadonlyError = exports.AFSError = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Base error class for all AFS errors.
|
|
6
|
+
*/
|
|
7
|
+
class AFSError extends Error {
|
|
8
|
+
code;
|
|
9
|
+
constructor(message, code) {
|
|
10
|
+
super(message);
|
|
11
|
+
this.name = "AFSError";
|
|
12
|
+
this.code = code;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
exports.AFSError = AFSError;
|
|
16
|
+
/**
|
|
17
|
+
* Error thrown when attempting write operations on a readonly AFS or module.
|
|
18
|
+
*/
|
|
19
|
+
class AFSReadonlyError extends AFSError {
|
|
20
|
+
constructor(message) {
|
|
21
|
+
super(message, "AFS_READONLY");
|
|
22
|
+
this.name = "AFSReadonlyError";
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
exports.AFSReadonlyError = AFSReadonlyError;
|
package/lib/cjs/index.d.ts
CHANGED
package/lib/cjs/index.js
CHANGED
|
@@ -15,4 +15,5 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
17
|
__exportStar(require("./afs.js"), exports);
|
|
18
|
+
__exportStar(require("./error.js"), exports);
|
|
18
19
|
__exportStar(require("./type.js"), exports);
|
package/lib/cjs/type.d.ts
CHANGED
|
@@ -1,9 +1,26 @@
|
|
|
1
1
|
import type { Emitter } from "strict-event-emitter";
|
|
2
|
-
import { type ZodType } from "zod";
|
|
3
|
-
|
|
2
|
+
import { type ZodType, z } from "zod";
|
|
3
|
+
/**
|
|
4
|
+
* Access mode for AFS modules and root.
|
|
5
|
+
* - "readonly": Only read operations are allowed (list, read, search)
|
|
6
|
+
* - "readwrite": All operations are allowed
|
|
7
|
+
*/
|
|
8
|
+
export type AFSAccessMode = "readonly" | "readwrite";
|
|
9
|
+
/**
|
|
10
|
+
* Zod schema for access mode validation.
|
|
11
|
+
* Can be reused across modules that support access mode configuration.
|
|
12
|
+
*/
|
|
13
|
+
export declare const accessModeSchema: z.ZodOptional<z.ZodEnum<["readonly", "readwrite"]>>;
|
|
14
|
+
export interface AFSOperationOptions {
|
|
15
|
+
context?: any;
|
|
16
|
+
}
|
|
17
|
+
export interface AFSListOptions extends AFSOperationOptions {
|
|
4
18
|
filter?: {
|
|
19
|
+
agentId?: string;
|
|
5
20
|
userId?: string;
|
|
6
21
|
sessionId?: string;
|
|
22
|
+
before?: string;
|
|
23
|
+
after?: string;
|
|
7
24
|
};
|
|
8
25
|
maxDepth?: number;
|
|
9
26
|
limit?: number;
|
|
@@ -15,46 +32,45 @@ export interface AFSListOptions {
|
|
|
15
32
|
* @default false
|
|
16
33
|
*/
|
|
17
34
|
disableGitignore?: boolean;
|
|
18
|
-
|
|
35
|
+
/**
|
|
36
|
+
* Glob pattern to filter entries by path.
|
|
37
|
+
* Examples: "*.ts", "**\/*.js", "src/**\/*.{ts,tsx}"
|
|
38
|
+
*/
|
|
39
|
+
pattern?: string;
|
|
19
40
|
}
|
|
20
41
|
export interface AFSListResult {
|
|
21
42
|
data: AFSEntry[];
|
|
22
43
|
message?: string;
|
|
23
|
-
context?: any;
|
|
24
44
|
}
|
|
25
|
-
export interface AFSSearchOptions {
|
|
45
|
+
export interface AFSSearchOptions extends AFSOperationOptions {
|
|
26
46
|
limit?: number;
|
|
27
47
|
caseSensitive?: boolean;
|
|
28
|
-
context?: any;
|
|
29
48
|
}
|
|
30
49
|
export interface AFSSearchResult {
|
|
31
50
|
data: AFSEntry[];
|
|
32
51
|
message?: string;
|
|
33
52
|
}
|
|
34
|
-
export interface AFSReadOptions {
|
|
35
|
-
|
|
53
|
+
export interface AFSReadOptions extends AFSOperationOptions {
|
|
54
|
+
filter?: AFSListOptions["filter"];
|
|
36
55
|
}
|
|
37
56
|
export interface AFSReadResult {
|
|
38
57
|
data?: AFSEntry;
|
|
39
58
|
message?: string;
|
|
40
59
|
}
|
|
41
|
-
export interface AFSDeleteOptions {
|
|
60
|
+
export interface AFSDeleteOptions extends AFSOperationOptions {
|
|
42
61
|
recursive?: boolean;
|
|
43
|
-
context?: any;
|
|
44
62
|
}
|
|
45
63
|
export interface AFSDeleteResult {
|
|
46
64
|
message?: string;
|
|
47
65
|
}
|
|
48
|
-
export interface AFSRenameOptions {
|
|
66
|
+
export interface AFSRenameOptions extends AFSOperationOptions {
|
|
49
67
|
overwrite?: boolean;
|
|
50
|
-
context?: any;
|
|
51
68
|
}
|
|
52
69
|
export interface AFSRenameResult {
|
|
53
70
|
message?: string;
|
|
54
71
|
}
|
|
55
|
-
export interface AFSWriteOptions {
|
|
72
|
+
export interface AFSWriteOptions extends AFSOperationOptions {
|
|
56
73
|
append?: boolean;
|
|
57
|
-
context?: any;
|
|
58
74
|
}
|
|
59
75
|
export interface AFSWriteResult {
|
|
60
76
|
data: AFSEntry;
|
|
@@ -63,8 +79,7 @@ export interface AFSWriteResult {
|
|
|
63
79
|
}
|
|
64
80
|
export interface AFSWriteEntryPayload extends Omit<AFSEntry, "id" | "path"> {
|
|
65
81
|
}
|
|
66
|
-
export interface AFSExecOptions {
|
|
67
|
-
context: any;
|
|
82
|
+
export interface AFSExecOptions extends AFSOperationOptions {
|
|
68
83
|
}
|
|
69
84
|
export interface AFSExecResult {
|
|
70
85
|
data: Record<string, any>;
|
|
@@ -72,7 +87,21 @@ export interface AFSExecResult {
|
|
|
72
87
|
export interface AFSModule {
|
|
73
88
|
readonly name: string;
|
|
74
89
|
readonly description?: string;
|
|
90
|
+
/**
|
|
91
|
+
* Access mode for this module.
|
|
92
|
+
* - "readonly": Only read operations are allowed
|
|
93
|
+
* - "readwrite": All operations are allowed
|
|
94
|
+
* Default behavior is implementation-specific.
|
|
95
|
+
*/
|
|
96
|
+
readonly accessMode?: AFSAccessMode;
|
|
97
|
+
/**
|
|
98
|
+
* Enable automatic agent skill scanning for this module.
|
|
99
|
+
* When set to true, the system will scan this module for agent skills.
|
|
100
|
+
* @default false
|
|
101
|
+
*/
|
|
102
|
+
readonly agentSkills?: boolean;
|
|
75
103
|
onMount?(root: AFSRoot): void;
|
|
104
|
+
symlinkToPhysical?(path: string): Promise<void>;
|
|
76
105
|
list?(path: string, options?: AFSListOptions): Promise<AFSListResult>;
|
|
77
106
|
read?(path: string, options?: AFSReadOptions): Promise<AFSReadResult>;
|
|
78
107
|
write?(path: string, content: AFSWriteEntryPayload, options?: AFSWriteOptions): Promise<AFSWriteResult>;
|
|
@@ -81,14 +110,53 @@ export interface AFSModule {
|
|
|
81
110
|
search?(path: string, query: string, options?: AFSSearchOptions): Promise<AFSSearchResult>;
|
|
82
111
|
exec?(path: string, args: Record<string, any>, options: AFSExecOptions): Promise<AFSExecResult>;
|
|
83
112
|
}
|
|
113
|
+
/**
|
|
114
|
+
* Parameters for loading a module from configuration.
|
|
115
|
+
*/
|
|
116
|
+
export interface AFSModuleLoadParams {
|
|
117
|
+
/** Path to the configuration file */
|
|
118
|
+
filepath: string;
|
|
119
|
+
/** Parsed configuration object */
|
|
120
|
+
parsed?: object;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Interface for module classes that support schema validation and loading from configuration.
|
|
124
|
+
* This describes the static part of a module class.
|
|
125
|
+
*
|
|
126
|
+
* @example
|
|
127
|
+
* ```typescript
|
|
128
|
+
* class MyModule implements AFSModule {
|
|
129
|
+
* static schema() { return mySchema; }
|
|
130
|
+
* static async load(params: AFSModuleLoadParams) { ... }
|
|
131
|
+
* // ...
|
|
132
|
+
* }
|
|
133
|
+
*
|
|
134
|
+
* // Type check
|
|
135
|
+
* const _check: AFSModuleClass<MyModule, MyModuleOptions> = MyModule;
|
|
136
|
+
* ```
|
|
137
|
+
*/
|
|
138
|
+
export interface AFSModuleClass<T extends AFSModule = AFSModule, O extends object = object> {
|
|
139
|
+
/** Returns the Zod schema for validating module configuration */
|
|
140
|
+
schema(): ZodType<O>;
|
|
141
|
+
/** Loads a module instance from configuration file path and parsed config */
|
|
142
|
+
load(params: AFSModuleLoadParams): Promise<T>;
|
|
143
|
+
/** Constructor */
|
|
144
|
+
new (options: O): T;
|
|
145
|
+
}
|
|
84
146
|
export type AFSRootEvents = {
|
|
85
|
-
agentSucceed: [
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
147
|
+
agentSucceed: [
|
|
148
|
+
{
|
|
149
|
+
agentId?: string;
|
|
150
|
+
userId?: string;
|
|
151
|
+
sessionId?: string;
|
|
152
|
+
input: object;
|
|
153
|
+
output: object;
|
|
154
|
+
messages?: object[];
|
|
155
|
+
}
|
|
156
|
+
];
|
|
89
157
|
historyCreated: [{
|
|
90
158
|
entry: AFSEntry;
|
|
91
|
-
}];
|
|
159
|
+
}, options: AFSOperationOptions];
|
|
92
160
|
};
|
|
93
161
|
export interface AFSRootListOptions extends AFSListOptions, AFSContextPreset {
|
|
94
162
|
preset?: string;
|
|
@@ -105,6 +173,8 @@ export interface AFSRootSearchResult extends Omit<AFSSearchResult, "data"> {
|
|
|
105
173
|
export interface AFSRoot extends Emitter<AFSRootEvents>, AFSModule {
|
|
106
174
|
list(path: string, options?: AFSRootListOptions): Promise<AFSRootListResult>;
|
|
107
175
|
search(path: string, query: string, options: AFSRootSearchOptions): Promise<AFSRootSearchResult>;
|
|
176
|
+
initializePhysicalPath(): Promise<string>;
|
|
177
|
+
cleanupPhysicalPath(): Promise<void>;
|
|
108
178
|
}
|
|
109
179
|
export interface AFSEntryMetadata extends Record<string, any> {
|
|
110
180
|
execute?: {
|
|
@@ -115,12 +185,14 @@ export interface AFSEntryMetadata extends Record<string, any> {
|
|
|
115
185
|
};
|
|
116
186
|
childrenCount?: number;
|
|
117
187
|
childrenTruncated?: boolean;
|
|
188
|
+
gitignored?: boolean;
|
|
118
189
|
}
|
|
119
190
|
export interface AFSEntry<T = any> {
|
|
120
191
|
id: string;
|
|
121
192
|
createdAt?: Date;
|
|
122
193
|
updatedAt?: Date;
|
|
123
194
|
path: string;
|
|
195
|
+
agentId?: string | null;
|
|
124
196
|
userId?: string | null;
|
|
125
197
|
sessionId?: string | null;
|
|
126
198
|
summary?: string | null;
|
|
@@ -151,7 +223,7 @@ export interface AFSContextPreset {
|
|
|
151
223
|
}, {
|
|
152
224
|
data: unknown;
|
|
153
225
|
}>;
|
|
154
|
-
format?: "default" | "tree" | AFSContextPresetOptionAgent<{
|
|
226
|
+
format?: "default" | "simple-list" | "tree" | AFSContextPresetOptionAgent<{
|
|
155
227
|
data: unknown;
|
|
156
228
|
}, {
|
|
157
229
|
data: unknown;
|
package/lib/cjs/type.js
CHANGED
|
@@ -1,7 +1,15 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.afsEntrySchema = void 0;
|
|
3
|
+
exports.afsEntrySchema = exports.accessModeSchema = void 0;
|
|
4
4
|
const zod_1 = require("zod");
|
|
5
|
+
/**
|
|
6
|
+
* Zod schema for access mode validation.
|
|
7
|
+
* Can be reused across modules that support access mode configuration.
|
|
8
|
+
*/
|
|
9
|
+
exports.accessModeSchema = zod_1.z
|
|
10
|
+
.enum(["readonly", "readwrite"])
|
|
11
|
+
.describe("Access mode for this module")
|
|
12
|
+
.optional();
|
|
5
13
|
exports.afsEntrySchema = zod_1.z.object({
|
|
6
14
|
id: zod_1.z.string(),
|
|
7
15
|
createdAt: zod_1.z.date().optional(),
|
package/lib/dts/afs.d.ts
CHANGED
|
@@ -9,6 +9,11 @@ export declare class AFS extends Emitter<AFSRootEvents> implements AFSRoot {
|
|
|
9
9
|
name: string;
|
|
10
10
|
constructor(options?: AFSOptions);
|
|
11
11
|
private modules;
|
|
12
|
+
/**
|
|
13
|
+
* Check if write operations are allowed for the given module.
|
|
14
|
+
* Throws AFSReadonlyError if not allowed.
|
|
15
|
+
*/
|
|
16
|
+
private checkWritePermission;
|
|
12
17
|
mount(module: AFSModule): this;
|
|
13
18
|
listModules(): Promise<{
|
|
14
19
|
name: string;
|
|
@@ -28,5 +33,10 @@ export declare class AFS extends Emitter<AFSRootEvents> implements AFSRoot {
|
|
|
28
33
|
private _search;
|
|
29
34
|
private findModules;
|
|
30
35
|
exec(path: string, args: Record<string, any>, options: AFSExecOptions): Promise<AFSExecResult>;
|
|
36
|
+
private buildSimpleListView;
|
|
31
37
|
private buildTreeView;
|
|
38
|
+
private buildMetadataSuffix;
|
|
39
|
+
private physicalPath?;
|
|
40
|
+
initializePhysicalPath(): Promise<string>;
|
|
41
|
+
cleanupPhysicalPath(): Promise<void>;
|
|
32
42
|
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base error class for all AFS errors.
|
|
3
|
+
*/
|
|
4
|
+
export declare class AFSError extends Error {
|
|
5
|
+
readonly code: string;
|
|
6
|
+
constructor(message: string, code: string);
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Error thrown when attempting write operations on a readonly AFS or module.
|
|
10
|
+
*/
|
|
11
|
+
export declare class AFSReadonlyError extends AFSError {
|
|
12
|
+
constructor(message: string);
|
|
13
|
+
}
|
package/lib/dts/index.d.ts
CHANGED