@aigne/afs 1.3.0 → 1.4.0-beta.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/CHANGELOG.md +26 -0
- package/lib/cjs/afs.d.ts +17 -28
- package/lib/cjs/afs.js +132 -25
- package/lib/cjs/type.d.ts +107 -28
- package/lib/cjs/type.js +15 -0
- package/lib/dts/afs.d.ts +17 -28
- package/lib/dts/type.d.ts +107 -28
- package/lib/esm/afs.d.ts +17 -28
- package/lib/esm/afs.js +132 -25
- package/lib/esm/type.d.ts +107 -28
- package/lib/esm/type.js +14 -1
- package/package.json +3 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,31 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [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)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Bug Fixes
|
|
7
|
+
|
|
8
|
+
* **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))
|
|
9
|
+
|
|
10
|
+
## [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)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
### Bug Fixes
|
|
14
|
+
|
|
15
|
+
* bump version ([70d217c](https://github.com/AIGNE-io/aigne-framework/commit/70d217c8360dd0dda7f5f17011c4e92ec836e801))
|
|
16
|
+
|
|
17
|
+
## [1.4.0-beta](https://github.com/AIGNE-io/aigne-framework/compare/afs-v1.3.0...afs-v1.4.0-beta) (2025-12-17)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
### Features
|
|
21
|
+
|
|
22
|
+
* **afs:** support expand context into prompt template by call `$afs.xxx` ([#830](https://github.com/AIGNE-io/aigne-framework/issues/830)) ([5616acd](https://github.com/AIGNE-io/aigne-framework/commit/5616acd6ea257c91aa0b766608f45c5ce17f0345))
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
### Bug Fixes
|
|
26
|
+
|
|
27
|
+
* **afs:** read method should not throw not found error ([#835](https://github.com/AIGNE-io/aigne-framework/issues/835)) ([ebfdfc1](https://github.com/AIGNE-io/aigne-framework/commit/ebfdfc1cdba23efd23ac2ad4621e3f046990fd8b))
|
|
28
|
+
|
|
3
29
|
## [1.3.0](https://github.com/AIGNE-io/aigne-framework/compare/afs-v1.3.0-beta.3...afs-v1.3.0) (2025-12-12)
|
|
4
30
|
|
|
5
31
|
## [1.3.0-beta.3](https://github.com/AIGNE-io/aigne-framework/compare/afs-v1.3.0-beta.2...afs-v1.3.0-beta.3) (2025-12-11)
|
package/lib/cjs/afs.d.ts
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { Emitter } from "strict-event-emitter";
|
|
2
|
-
import type
|
|
2
|
+
import { type AFSContext, type AFSDeleteOptions, type AFSDeleteResult, type AFSExecOptions, type AFSExecResult, type AFSModule, type AFSReadOptions, type AFSReadResult, type AFSRenameOptions, type AFSRenameResult, type AFSRoot, type AFSRootEvents, type AFSRootListOptions, type AFSRootListResult, type AFSRootSearchOptions, type AFSRootSearchResult, type AFSWriteEntryPayload, type AFSWriteOptions, type AFSWriteResult } from "./type.js";
|
|
3
3
|
export interface AFSOptions {
|
|
4
4
|
modules?: AFSModule[];
|
|
5
|
+
context?: AFSContext;
|
|
5
6
|
}
|
|
6
7
|
export declare class AFS extends Emitter<AFSRootEvents> implements AFSRoot {
|
|
8
|
+
options: AFSOptions;
|
|
7
9
|
name: string;
|
|
8
10
|
constructor(options?: AFSOptions);
|
|
9
11
|
private modules;
|
|
@@ -14,32 +16,19 @@ export declare class AFS extends Emitter<AFSRootEvents> implements AFSRoot {
|
|
|
14
16
|
description?: string;
|
|
15
17
|
module: AFSModule;
|
|
16
18
|
}[]>;
|
|
17
|
-
list(path: string, options?:
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
message?: string;
|
|
28
|
-
}>;
|
|
29
|
-
delete(path: string, options?: AFSDeleteOptions): Promise<{
|
|
30
|
-
message?: string;
|
|
31
|
-
}>;
|
|
32
|
-
rename(oldPath: string, newPath: string, options?: AFSRenameOptions): Promise<{
|
|
33
|
-
message?: string;
|
|
34
|
-
}>;
|
|
35
|
-
search(path: string, query: string, options?: AFSSearchOptions): Promise<{
|
|
36
|
-
list: AFSEntry[];
|
|
37
|
-
message?: string;
|
|
38
|
-
}>;
|
|
19
|
+
list(path: string, options?: AFSRootListOptions): Promise<AFSRootListResult>;
|
|
20
|
+
private _list;
|
|
21
|
+
read(path: string, _options?: AFSReadOptions): Promise<AFSReadResult>;
|
|
22
|
+
write(path: string, content: AFSWriteEntryPayload, options?: AFSWriteOptions): Promise<AFSWriteResult>;
|
|
23
|
+
delete(path: string, options?: AFSDeleteOptions): Promise<AFSDeleteResult>;
|
|
24
|
+
rename(oldPath: string, newPath: string, options?: AFSRenameOptions): Promise<AFSRenameResult>;
|
|
25
|
+
search(path: string, query: string, options?: AFSRootSearchOptions): Promise<AFSRootSearchResult>;
|
|
26
|
+
private processWithPreset;
|
|
27
|
+
private _select;
|
|
28
|
+
private _search;
|
|
39
29
|
private findModules;
|
|
40
|
-
exec(path: string, args: Record<string, any>, options:
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
}>;
|
|
30
|
+
exec(path: string, args: Record<string, any>, options: AFSExecOptions): Promise<AFSExecResult>;
|
|
31
|
+
private buildSimpleListView;
|
|
32
|
+
private buildTreeView;
|
|
33
|
+
private buildMetadataSuffix;
|
|
45
34
|
}
|
package/lib/cjs/afs.js
CHANGED
|
@@ -3,12 +3,16 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.AFS = void 0;
|
|
4
4
|
const strict_event_emitter_1 = require("strict-event-emitter");
|
|
5
5
|
const ufo_1 = require("ufo");
|
|
6
|
+
const zod_1 = require("zod");
|
|
7
|
+
const type_js_1 = require("./type.js");
|
|
6
8
|
const DEFAULT_MAX_DEPTH = 1;
|
|
7
9
|
const MODULES_ROOT_DIR = "/modules";
|
|
8
10
|
class AFS extends strict_event_emitter_1.Emitter {
|
|
11
|
+
options;
|
|
9
12
|
name = "AFSRoot";
|
|
10
|
-
constructor(options) {
|
|
13
|
+
constructor(options = {}) {
|
|
11
14
|
super();
|
|
15
|
+
this.options = options;
|
|
12
16
|
for (const module of options?.modules ?? []) {
|
|
13
17
|
this.mount(module);
|
|
14
18
|
}
|
|
@@ -35,12 +39,20 @@ class AFS extends strict_event_emitter_1.Emitter {
|
|
|
35
39
|
module,
|
|
36
40
|
}));
|
|
37
41
|
}
|
|
38
|
-
async list(path, options) {
|
|
39
|
-
|
|
40
|
-
if (
|
|
41
|
-
|
|
42
|
+
async list(path, options = {}) {
|
|
43
|
+
let preset;
|
|
44
|
+
if (options.preset) {
|
|
45
|
+
preset = this.options?.context?.list?.presets?.[options.preset];
|
|
46
|
+
if (!preset)
|
|
47
|
+
throw new Error(`Preset not found: ${options.preset}`);
|
|
48
|
+
}
|
|
49
|
+
return await this.processWithPreset(path, undefined, preset, {
|
|
50
|
+
...options,
|
|
51
|
+
defaultSelect: () => this._list(path, options),
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
async _list(path, options = {}) {
|
|
42
55
|
const results = [];
|
|
43
|
-
const messages = [];
|
|
44
56
|
const matches = this.findModules(path, options);
|
|
45
57
|
for (const matched of matches) {
|
|
46
58
|
const moduleEntry = {
|
|
@@ -55,12 +67,12 @@ class AFS extends strict_event_emitter_1.Emitter {
|
|
|
55
67
|
if (!matched.module.list)
|
|
56
68
|
continue;
|
|
57
69
|
try {
|
|
58
|
-
const {
|
|
70
|
+
const { data } = await matched.module.list(matched.subpath, {
|
|
59
71
|
...options,
|
|
60
72
|
maxDepth: matched.maxDepth,
|
|
61
73
|
});
|
|
62
|
-
if (
|
|
63
|
-
results.push(...
|
|
74
|
+
if (data.length) {
|
|
75
|
+
results.push(...data.map((entry) => ({
|
|
64
76
|
...entry,
|
|
65
77
|
path: (0, ufo_1.joinURL)(matched.modulePath, entry.path),
|
|
66
78
|
})));
|
|
@@ -68,30 +80,28 @@ class AFS extends strict_event_emitter_1.Emitter {
|
|
|
68
80
|
else {
|
|
69
81
|
results.push(moduleEntry);
|
|
70
82
|
}
|
|
71
|
-
if (message)
|
|
72
|
-
messages.push(message);
|
|
73
83
|
}
|
|
74
84
|
catch (error) {
|
|
75
85
|
console.error(`Error listing from module at ${matched.modulePath}`, error);
|
|
76
86
|
}
|
|
77
87
|
}
|
|
78
|
-
return {
|
|
88
|
+
return { data: results };
|
|
79
89
|
}
|
|
80
|
-
async read(path) {
|
|
90
|
+
async read(path, _options) {
|
|
81
91
|
const modules = this.findModules(path, { exactMatch: true });
|
|
82
92
|
for (const { module, modulePath, subpath } of modules) {
|
|
83
93
|
const res = await module.read?.(subpath);
|
|
84
|
-
if (res?.
|
|
94
|
+
if (res?.data) {
|
|
85
95
|
return {
|
|
86
96
|
...res,
|
|
87
|
-
|
|
88
|
-
...res.
|
|
89
|
-
path: (0, ufo_1.joinURL)(modulePath, res.
|
|
97
|
+
data: {
|
|
98
|
+
...res.data,
|
|
99
|
+
path: (0, ufo_1.joinURL)(modulePath, res.data.path),
|
|
90
100
|
},
|
|
91
101
|
};
|
|
92
102
|
}
|
|
93
103
|
}
|
|
94
|
-
return {
|
|
104
|
+
return { data: undefined, message: "File not found" };
|
|
95
105
|
}
|
|
96
106
|
async write(path, content, options) {
|
|
97
107
|
const module = this.findModules(path, { exactMatch: true })[0];
|
|
@@ -100,9 +110,9 @@ class AFS extends strict_event_emitter_1.Emitter {
|
|
|
100
110
|
const res = await module.module.write(module.subpath, content, options);
|
|
101
111
|
return {
|
|
102
112
|
...res,
|
|
103
|
-
|
|
104
|
-
...res.
|
|
105
|
-
path: (0, ufo_1.joinURL)(module.modulePath, res.
|
|
113
|
+
data: {
|
|
114
|
+
...res.data,
|
|
115
|
+
path: (0, ufo_1.joinURL)(module.modulePath, res.data.path),
|
|
106
116
|
},
|
|
107
117
|
};
|
|
108
118
|
}
|
|
@@ -124,15 +134,61 @@ class AFS extends strict_event_emitter_1.Emitter {
|
|
|
124
134
|
}
|
|
125
135
|
return await oldModule.module.rename(oldModule.subpath, newModule.subpath, options);
|
|
126
136
|
}
|
|
127
|
-
async search(path, query, options) {
|
|
137
|
+
async search(path, query, options = {}) {
|
|
138
|
+
let preset;
|
|
139
|
+
if (options.preset) {
|
|
140
|
+
preset = this.options?.context?.search?.presets?.[options.preset];
|
|
141
|
+
if (!preset)
|
|
142
|
+
throw new Error(`Preset not found: ${options.preset}`);
|
|
143
|
+
}
|
|
144
|
+
return await this.processWithPreset(path, query, preset, {
|
|
145
|
+
...options,
|
|
146
|
+
defaultSelect: () => this._search(path, query, options),
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
async processWithPreset(path, query, preset, options) {
|
|
150
|
+
const select = options.select || preset?.select;
|
|
151
|
+
const per = options.per || preset?.per;
|
|
152
|
+
const dedupe = options.dedupe || preset?.dedupe;
|
|
153
|
+
const format = options.format || preset?.format;
|
|
154
|
+
const entries = select
|
|
155
|
+
? (await this._select(path, query, select, options)).data
|
|
156
|
+
: (await options.defaultSelect()).data;
|
|
157
|
+
const mapped = per
|
|
158
|
+
? await Promise.all(entries.map((data) => per.invoke({ data }, options).then((res) => res.data)))
|
|
159
|
+
: entries;
|
|
160
|
+
const deduped = dedupe
|
|
161
|
+
? await dedupe.invoke({ data: mapped }, options).then((res) => res.data)
|
|
162
|
+
: mapped;
|
|
163
|
+
let formatted = deduped;
|
|
164
|
+
if (format === "simple-list" || format === "tree") {
|
|
165
|
+
const valid = zod_1.z.array(type_js_1.afsEntrySchema).safeParse(deduped);
|
|
166
|
+
if (!valid.data)
|
|
167
|
+
throw new Error("Tree format requires entries to be AFSEntry objects");
|
|
168
|
+
if (format === "tree")
|
|
169
|
+
formatted = this.buildTreeView(valid.data);
|
|
170
|
+
else if (format === "simple-list")
|
|
171
|
+
formatted = this.buildSimpleListView(valid.data);
|
|
172
|
+
}
|
|
173
|
+
else if (typeof format === "object" && typeof format.invoke === "function") {
|
|
174
|
+
formatted = await format.invoke({ data: deduped }, options).then((res) => res.data);
|
|
175
|
+
}
|
|
176
|
+
return { data: formatted };
|
|
177
|
+
}
|
|
178
|
+
async _select(path, query, select, options) {
|
|
179
|
+
const { data } = await select.invoke({ path, query }, options);
|
|
180
|
+
const results = (await Promise.all(data.map((p) => this.read(p).then((res) => res.data)))).filter((i) => !!i);
|
|
181
|
+
return { data: results };
|
|
182
|
+
}
|
|
183
|
+
async _search(path, query, options) {
|
|
128
184
|
const results = [];
|
|
129
185
|
const messages = [];
|
|
130
186
|
for (const { module, modulePath, subpath } of this.findModules(path)) {
|
|
131
187
|
if (!module.search)
|
|
132
188
|
continue;
|
|
133
189
|
try {
|
|
134
|
-
const {
|
|
135
|
-
results.push(...
|
|
190
|
+
const { data, message } = await module.search(subpath, query, options);
|
|
191
|
+
results.push(...data.map((entry) => ({
|
|
136
192
|
...entry,
|
|
137
193
|
path: (0, ufo_1.joinURL)(modulePath, entry.path),
|
|
138
194
|
})));
|
|
@@ -143,7 +199,7 @@ class AFS extends strict_event_emitter_1.Emitter {
|
|
|
143
199
|
console.error(`Error searching in module at ${modulePath}`, error);
|
|
144
200
|
}
|
|
145
201
|
}
|
|
146
|
-
return {
|
|
202
|
+
return { data: results, message: messages.join("; ") };
|
|
147
203
|
}
|
|
148
204
|
findModules(path, options) {
|
|
149
205
|
const maxDepth = Math.max(options?.maxDepth ?? DEFAULT_MAX_DEPTH, 1);
|
|
@@ -179,5 +235,56 @@ class AFS extends strict_event_emitter_1.Emitter {
|
|
|
179
235
|
throw new Error(`No module found for path: ${path}`);
|
|
180
236
|
return await module.module.exec(module.subpath, args, options);
|
|
181
237
|
}
|
|
238
|
+
buildSimpleListView(entries) {
|
|
239
|
+
return entries.map((entry) => `${entry.path}${this.buildMetadataSuffix(entry)}`);
|
|
240
|
+
}
|
|
241
|
+
buildTreeView(entries) {
|
|
242
|
+
const tree = {};
|
|
243
|
+
const entryMap = new Map();
|
|
244
|
+
for (const entry of entries) {
|
|
245
|
+
entryMap.set(entry.path, entry);
|
|
246
|
+
const parts = entry.path.split("/").filter(Boolean);
|
|
247
|
+
let current = tree;
|
|
248
|
+
for (const part of parts) {
|
|
249
|
+
if (!current[part]) {
|
|
250
|
+
current[part] = {};
|
|
251
|
+
}
|
|
252
|
+
current = current[part];
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
const renderTree = (node, prefix = "", currentPath = "") => {
|
|
256
|
+
let result = "";
|
|
257
|
+
const keys = Object.keys(node);
|
|
258
|
+
keys.forEach((key, index) => {
|
|
259
|
+
const isLast = index === keys.length - 1;
|
|
260
|
+
const fullPath = currentPath ? `${currentPath}/${key}` : `/${key}`;
|
|
261
|
+
const entry = entryMap.get(fullPath);
|
|
262
|
+
result += `${prefix}${isLast ? "└── " : "├── "}${key}${entry ? this.buildMetadataSuffix(entry) : ""}`;
|
|
263
|
+
result += `\n`;
|
|
264
|
+
result += renderTree(node[key], `${prefix}${isLast ? " " : "│ "}`, fullPath);
|
|
265
|
+
});
|
|
266
|
+
return result;
|
|
267
|
+
};
|
|
268
|
+
return renderTree(tree);
|
|
269
|
+
}
|
|
270
|
+
buildMetadataSuffix(entry) {
|
|
271
|
+
// Build metadata suffix
|
|
272
|
+
const metadataParts = [];
|
|
273
|
+
// Children count
|
|
274
|
+
const childrenCount = entry?.metadata?.childrenCount;
|
|
275
|
+
if (typeof childrenCount === "number") {
|
|
276
|
+
metadataParts.push(`${childrenCount} items`);
|
|
277
|
+
}
|
|
278
|
+
// Children truncated
|
|
279
|
+
if (entry?.metadata?.childrenTruncated) {
|
|
280
|
+
metadataParts.push("truncated");
|
|
281
|
+
}
|
|
282
|
+
// Executable
|
|
283
|
+
if (entry?.metadata?.execute) {
|
|
284
|
+
metadataParts.push("executable");
|
|
285
|
+
}
|
|
286
|
+
const metadataSuffix = metadataParts.length > 0 ? ` [${metadataParts.join(", ")}]` : "";
|
|
287
|
+
return metadataSuffix;
|
|
288
|
+
}
|
|
182
289
|
}
|
|
183
290
|
exports.AFS = AFS;
|
package/lib/cjs/type.d.ts
CHANGED
|
@@ -1,60 +1,85 @@
|
|
|
1
1
|
import type { Emitter } from "strict-event-emitter";
|
|
2
|
+
import { type ZodType } from "zod";
|
|
2
3
|
export interface AFSListOptions {
|
|
3
4
|
filter?: {
|
|
4
5
|
userId?: string;
|
|
5
6
|
sessionId?: string;
|
|
6
7
|
};
|
|
7
|
-
recursive?: boolean;
|
|
8
8
|
maxDepth?: number;
|
|
9
9
|
limit?: number;
|
|
10
10
|
orderBy?: [string, "asc" | "desc"][];
|
|
11
|
+
maxChildren?: number;
|
|
12
|
+
onOverflow?: "truncate";
|
|
13
|
+
/**
|
|
14
|
+
* Whether to disable .gitignore files when listing files.
|
|
15
|
+
* @default false
|
|
16
|
+
*/
|
|
17
|
+
disableGitignore?: boolean;
|
|
18
|
+
context?: any;
|
|
19
|
+
}
|
|
20
|
+
export interface AFSListResult {
|
|
21
|
+
data: AFSEntry[];
|
|
22
|
+
message?: string;
|
|
23
|
+
context?: any;
|
|
11
24
|
}
|
|
12
25
|
export interface AFSSearchOptions {
|
|
13
26
|
limit?: number;
|
|
14
27
|
caseSensitive?: boolean;
|
|
28
|
+
context?: any;
|
|
29
|
+
}
|
|
30
|
+
export interface AFSSearchResult {
|
|
31
|
+
data: AFSEntry[];
|
|
32
|
+
message?: string;
|
|
33
|
+
}
|
|
34
|
+
export interface AFSReadOptions {
|
|
35
|
+
context?: any;
|
|
36
|
+
}
|
|
37
|
+
export interface AFSReadResult {
|
|
38
|
+
data?: AFSEntry;
|
|
39
|
+
message?: string;
|
|
15
40
|
}
|
|
16
41
|
export interface AFSDeleteOptions {
|
|
17
42
|
recursive?: boolean;
|
|
43
|
+
context?: any;
|
|
44
|
+
}
|
|
45
|
+
export interface AFSDeleteResult {
|
|
46
|
+
message?: string;
|
|
18
47
|
}
|
|
19
48
|
export interface AFSRenameOptions {
|
|
20
49
|
overwrite?: boolean;
|
|
50
|
+
context?: any;
|
|
51
|
+
}
|
|
52
|
+
export interface AFSRenameResult {
|
|
53
|
+
message?: string;
|
|
21
54
|
}
|
|
22
55
|
export interface AFSWriteOptions {
|
|
23
56
|
append?: boolean;
|
|
57
|
+
context?: any;
|
|
58
|
+
}
|
|
59
|
+
export interface AFSWriteResult {
|
|
60
|
+
data: AFSEntry;
|
|
61
|
+
message?: string;
|
|
62
|
+
context?: any;
|
|
24
63
|
}
|
|
25
64
|
export interface AFSWriteEntryPayload extends Omit<AFSEntry, "id" | "path"> {
|
|
26
65
|
}
|
|
66
|
+
export interface AFSExecOptions {
|
|
67
|
+
context: any;
|
|
68
|
+
}
|
|
69
|
+
export interface AFSExecResult {
|
|
70
|
+
data: Record<string, any>;
|
|
71
|
+
}
|
|
27
72
|
export interface AFSModule {
|
|
28
73
|
readonly name: string;
|
|
29
74
|
readonly description?: string;
|
|
30
75
|
onMount?(root: AFSRoot): void;
|
|
31
|
-
list?(path: string, options?: AFSListOptions): Promise<
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
}>;
|
|
39
|
-
write?(path: string, content: AFSWriteEntryPayload, options?: AFSWriteOptions): Promise<{
|
|
40
|
-
result: AFSEntry;
|
|
41
|
-
message?: string;
|
|
42
|
-
}>;
|
|
43
|
-
delete?(path: string, options?: AFSDeleteOptions): Promise<{
|
|
44
|
-
message?: string;
|
|
45
|
-
}>;
|
|
46
|
-
rename?(oldPath: string, newPath: string, options?: AFSRenameOptions): Promise<{
|
|
47
|
-
message?: string;
|
|
48
|
-
}>;
|
|
49
|
-
search?(path: string, query: string, options?: AFSSearchOptions): Promise<{
|
|
50
|
-
list: AFSEntry[];
|
|
51
|
-
message?: string;
|
|
52
|
-
}>;
|
|
53
|
-
exec?(path: string, args: Record<string, any>, options: {
|
|
54
|
-
context: any;
|
|
55
|
-
}): Promise<{
|
|
56
|
-
result: Record<string, any>;
|
|
57
|
-
}>;
|
|
76
|
+
list?(path: string, options?: AFSListOptions): Promise<AFSListResult>;
|
|
77
|
+
read?(path: string, options?: AFSReadOptions): Promise<AFSReadResult>;
|
|
78
|
+
write?(path: string, content: AFSWriteEntryPayload, options?: AFSWriteOptions): Promise<AFSWriteResult>;
|
|
79
|
+
delete?(path: string, options?: AFSDeleteOptions): Promise<AFSDeleteResult>;
|
|
80
|
+
rename?(oldPath: string, newPath: string, options?: AFSRenameOptions): Promise<AFSRenameResult>;
|
|
81
|
+
search?(path: string, query: string, options?: AFSSearchOptions): Promise<AFSSearchResult>;
|
|
82
|
+
exec?(path: string, args: Record<string, any>, options: AFSExecOptions): Promise<AFSExecResult>;
|
|
58
83
|
}
|
|
59
84
|
export type AFSRootEvents = {
|
|
60
85
|
agentSucceed: [{
|
|
@@ -65,7 +90,21 @@ export type AFSRootEvents = {
|
|
|
65
90
|
entry: AFSEntry;
|
|
66
91
|
}];
|
|
67
92
|
};
|
|
93
|
+
export interface AFSRootListOptions extends AFSListOptions, AFSContextPreset {
|
|
94
|
+
preset?: string;
|
|
95
|
+
}
|
|
96
|
+
export interface AFSRootListResult extends Omit<AFSListResult, "data"> {
|
|
97
|
+
data: any;
|
|
98
|
+
}
|
|
99
|
+
export interface AFSRootSearchOptions extends AFSSearchOptions, AFSContextPreset {
|
|
100
|
+
preset?: string;
|
|
101
|
+
}
|
|
102
|
+
export interface AFSRootSearchResult extends Omit<AFSSearchResult, "data"> {
|
|
103
|
+
data: any;
|
|
104
|
+
}
|
|
68
105
|
export interface AFSRoot extends Emitter<AFSRootEvents>, AFSModule {
|
|
106
|
+
list(path: string, options?: AFSRootListOptions): Promise<AFSRootListResult>;
|
|
107
|
+
search(path: string, query: string, options: AFSRootSearchOptions): Promise<AFSRootSearchResult>;
|
|
69
108
|
}
|
|
70
109
|
export interface AFSEntryMetadata extends Record<string, any> {
|
|
71
110
|
execute?: {
|
|
@@ -75,6 +114,7 @@ export interface AFSEntryMetadata extends Record<string, any> {
|
|
|
75
114
|
outputSchema?: Record<string, any>;
|
|
76
115
|
};
|
|
77
116
|
childrenCount?: number;
|
|
117
|
+
childrenTruncated?: boolean;
|
|
78
118
|
}
|
|
79
119
|
export interface AFSEntry<T = any> {
|
|
80
120
|
id: string;
|
|
@@ -89,3 +129,42 @@ export interface AFSEntry<T = any> {
|
|
|
89
129
|
linkTo?: string | null;
|
|
90
130
|
content?: T;
|
|
91
131
|
}
|
|
132
|
+
export declare const afsEntrySchema: ZodType<AFSEntry>;
|
|
133
|
+
export interface AFSContextPreset {
|
|
134
|
+
/**
|
|
135
|
+
* The view template for presenting the search results.
|
|
136
|
+
*/
|
|
137
|
+
view?: string;
|
|
138
|
+
select?: AFSContextPresetOptionAgent<{
|
|
139
|
+
path: string;
|
|
140
|
+
query?: string;
|
|
141
|
+
}, {
|
|
142
|
+
data: string[];
|
|
143
|
+
}>;
|
|
144
|
+
per?: AFSContextPresetOptionAgent<{
|
|
145
|
+
data: AFSEntry;
|
|
146
|
+
}, {
|
|
147
|
+
data: unknown;
|
|
148
|
+
}>;
|
|
149
|
+
dedupe?: AFSContextPresetOptionAgent<{
|
|
150
|
+
data: unknown[];
|
|
151
|
+
}, {
|
|
152
|
+
data: unknown;
|
|
153
|
+
}>;
|
|
154
|
+
format?: "default" | "simple-list" | "tree" | AFSContextPresetOptionAgent<{
|
|
155
|
+
data: unknown;
|
|
156
|
+
}, {
|
|
157
|
+
data: unknown;
|
|
158
|
+
}>;
|
|
159
|
+
}
|
|
160
|
+
export interface AFSContextPresetOptionAgent<I = any, O = any> {
|
|
161
|
+
invoke(input: I, options?: any): Promise<O>;
|
|
162
|
+
}
|
|
163
|
+
export interface AFSContext {
|
|
164
|
+
search?: {
|
|
165
|
+
presets?: Record<string, AFSContextPreset>;
|
|
166
|
+
};
|
|
167
|
+
list?: {
|
|
168
|
+
presets?: Record<string, AFSContextPreset>;
|
|
169
|
+
};
|
|
170
|
+
}
|
package/lib/cjs/type.js
CHANGED
|
@@ -1,2 +1,17 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.afsEntrySchema = void 0;
|
|
4
|
+
const zod_1 = require("zod");
|
|
5
|
+
exports.afsEntrySchema = zod_1.z.object({
|
|
6
|
+
id: zod_1.z.string(),
|
|
7
|
+
createdAt: zod_1.z.date().optional(),
|
|
8
|
+
updatedAt: zod_1.z.date().optional(),
|
|
9
|
+
path: zod_1.z.string(),
|
|
10
|
+
userId: zod_1.z.string().nullable().optional(),
|
|
11
|
+
sessionId: zod_1.z.string().nullable().optional(),
|
|
12
|
+
summary: zod_1.z.string().nullable().optional(),
|
|
13
|
+
description: zod_1.z.string().nullable().optional(),
|
|
14
|
+
metadata: zod_1.z.record(zod_1.z.any()).nullable().optional(),
|
|
15
|
+
linkTo: zod_1.z.string().nullable().optional(),
|
|
16
|
+
content: zod_1.z.any().optional(),
|
|
17
|
+
});
|
package/lib/dts/afs.d.ts
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { Emitter } from "strict-event-emitter";
|
|
2
|
-
import type
|
|
2
|
+
import { type AFSContext, type AFSDeleteOptions, type AFSDeleteResult, type AFSExecOptions, type AFSExecResult, type AFSModule, type AFSReadOptions, type AFSReadResult, type AFSRenameOptions, type AFSRenameResult, type AFSRoot, type AFSRootEvents, type AFSRootListOptions, type AFSRootListResult, type AFSRootSearchOptions, type AFSRootSearchResult, type AFSWriteEntryPayload, type AFSWriteOptions, type AFSWriteResult } from "./type.js";
|
|
3
3
|
export interface AFSOptions {
|
|
4
4
|
modules?: AFSModule[];
|
|
5
|
+
context?: AFSContext;
|
|
5
6
|
}
|
|
6
7
|
export declare class AFS extends Emitter<AFSRootEvents> implements AFSRoot {
|
|
8
|
+
options: AFSOptions;
|
|
7
9
|
name: string;
|
|
8
10
|
constructor(options?: AFSOptions);
|
|
9
11
|
private modules;
|
|
@@ -14,32 +16,19 @@ export declare class AFS extends Emitter<AFSRootEvents> implements AFSRoot {
|
|
|
14
16
|
description?: string;
|
|
15
17
|
module: AFSModule;
|
|
16
18
|
}[]>;
|
|
17
|
-
list(path: string, options?:
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
message?: string;
|
|
28
|
-
}>;
|
|
29
|
-
delete(path: string, options?: AFSDeleteOptions): Promise<{
|
|
30
|
-
message?: string;
|
|
31
|
-
}>;
|
|
32
|
-
rename(oldPath: string, newPath: string, options?: AFSRenameOptions): Promise<{
|
|
33
|
-
message?: string;
|
|
34
|
-
}>;
|
|
35
|
-
search(path: string, query: string, options?: AFSSearchOptions): Promise<{
|
|
36
|
-
list: AFSEntry[];
|
|
37
|
-
message?: string;
|
|
38
|
-
}>;
|
|
19
|
+
list(path: string, options?: AFSRootListOptions): Promise<AFSRootListResult>;
|
|
20
|
+
private _list;
|
|
21
|
+
read(path: string, _options?: AFSReadOptions): Promise<AFSReadResult>;
|
|
22
|
+
write(path: string, content: AFSWriteEntryPayload, options?: AFSWriteOptions): Promise<AFSWriteResult>;
|
|
23
|
+
delete(path: string, options?: AFSDeleteOptions): Promise<AFSDeleteResult>;
|
|
24
|
+
rename(oldPath: string, newPath: string, options?: AFSRenameOptions): Promise<AFSRenameResult>;
|
|
25
|
+
search(path: string, query: string, options?: AFSRootSearchOptions): Promise<AFSRootSearchResult>;
|
|
26
|
+
private processWithPreset;
|
|
27
|
+
private _select;
|
|
28
|
+
private _search;
|
|
39
29
|
private findModules;
|
|
40
|
-
exec(path: string, args: Record<string, any>, options:
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
}>;
|
|
30
|
+
exec(path: string, args: Record<string, any>, options: AFSExecOptions): Promise<AFSExecResult>;
|
|
31
|
+
private buildSimpleListView;
|
|
32
|
+
private buildTreeView;
|
|
33
|
+
private buildMetadataSuffix;
|
|
45
34
|
}
|
package/lib/dts/type.d.ts
CHANGED
|
@@ -1,60 +1,85 @@
|
|
|
1
1
|
import type { Emitter } from "strict-event-emitter";
|
|
2
|
+
import { type ZodType } from "zod";
|
|
2
3
|
export interface AFSListOptions {
|
|
3
4
|
filter?: {
|
|
4
5
|
userId?: string;
|
|
5
6
|
sessionId?: string;
|
|
6
7
|
};
|
|
7
|
-
recursive?: boolean;
|
|
8
8
|
maxDepth?: number;
|
|
9
9
|
limit?: number;
|
|
10
10
|
orderBy?: [string, "asc" | "desc"][];
|
|
11
|
+
maxChildren?: number;
|
|
12
|
+
onOverflow?: "truncate";
|
|
13
|
+
/**
|
|
14
|
+
* Whether to disable .gitignore files when listing files.
|
|
15
|
+
* @default false
|
|
16
|
+
*/
|
|
17
|
+
disableGitignore?: boolean;
|
|
18
|
+
context?: any;
|
|
19
|
+
}
|
|
20
|
+
export interface AFSListResult {
|
|
21
|
+
data: AFSEntry[];
|
|
22
|
+
message?: string;
|
|
23
|
+
context?: any;
|
|
11
24
|
}
|
|
12
25
|
export interface AFSSearchOptions {
|
|
13
26
|
limit?: number;
|
|
14
27
|
caseSensitive?: boolean;
|
|
28
|
+
context?: any;
|
|
29
|
+
}
|
|
30
|
+
export interface AFSSearchResult {
|
|
31
|
+
data: AFSEntry[];
|
|
32
|
+
message?: string;
|
|
33
|
+
}
|
|
34
|
+
export interface AFSReadOptions {
|
|
35
|
+
context?: any;
|
|
36
|
+
}
|
|
37
|
+
export interface AFSReadResult {
|
|
38
|
+
data?: AFSEntry;
|
|
39
|
+
message?: string;
|
|
15
40
|
}
|
|
16
41
|
export interface AFSDeleteOptions {
|
|
17
42
|
recursive?: boolean;
|
|
43
|
+
context?: any;
|
|
44
|
+
}
|
|
45
|
+
export interface AFSDeleteResult {
|
|
46
|
+
message?: string;
|
|
18
47
|
}
|
|
19
48
|
export interface AFSRenameOptions {
|
|
20
49
|
overwrite?: boolean;
|
|
50
|
+
context?: any;
|
|
51
|
+
}
|
|
52
|
+
export interface AFSRenameResult {
|
|
53
|
+
message?: string;
|
|
21
54
|
}
|
|
22
55
|
export interface AFSWriteOptions {
|
|
23
56
|
append?: boolean;
|
|
57
|
+
context?: any;
|
|
58
|
+
}
|
|
59
|
+
export interface AFSWriteResult {
|
|
60
|
+
data: AFSEntry;
|
|
61
|
+
message?: string;
|
|
62
|
+
context?: any;
|
|
24
63
|
}
|
|
25
64
|
export interface AFSWriteEntryPayload extends Omit<AFSEntry, "id" | "path"> {
|
|
26
65
|
}
|
|
66
|
+
export interface AFSExecOptions {
|
|
67
|
+
context: any;
|
|
68
|
+
}
|
|
69
|
+
export interface AFSExecResult {
|
|
70
|
+
data: Record<string, any>;
|
|
71
|
+
}
|
|
27
72
|
export interface AFSModule {
|
|
28
73
|
readonly name: string;
|
|
29
74
|
readonly description?: string;
|
|
30
75
|
onMount?(root: AFSRoot): void;
|
|
31
|
-
list?(path: string, options?: AFSListOptions): Promise<
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
}>;
|
|
39
|
-
write?(path: string, content: AFSWriteEntryPayload, options?: AFSWriteOptions): Promise<{
|
|
40
|
-
result: AFSEntry;
|
|
41
|
-
message?: string;
|
|
42
|
-
}>;
|
|
43
|
-
delete?(path: string, options?: AFSDeleteOptions): Promise<{
|
|
44
|
-
message?: string;
|
|
45
|
-
}>;
|
|
46
|
-
rename?(oldPath: string, newPath: string, options?: AFSRenameOptions): Promise<{
|
|
47
|
-
message?: string;
|
|
48
|
-
}>;
|
|
49
|
-
search?(path: string, query: string, options?: AFSSearchOptions): Promise<{
|
|
50
|
-
list: AFSEntry[];
|
|
51
|
-
message?: string;
|
|
52
|
-
}>;
|
|
53
|
-
exec?(path: string, args: Record<string, any>, options: {
|
|
54
|
-
context: any;
|
|
55
|
-
}): Promise<{
|
|
56
|
-
result: Record<string, any>;
|
|
57
|
-
}>;
|
|
76
|
+
list?(path: string, options?: AFSListOptions): Promise<AFSListResult>;
|
|
77
|
+
read?(path: string, options?: AFSReadOptions): Promise<AFSReadResult>;
|
|
78
|
+
write?(path: string, content: AFSWriteEntryPayload, options?: AFSWriteOptions): Promise<AFSWriteResult>;
|
|
79
|
+
delete?(path: string, options?: AFSDeleteOptions): Promise<AFSDeleteResult>;
|
|
80
|
+
rename?(oldPath: string, newPath: string, options?: AFSRenameOptions): Promise<AFSRenameResult>;
|
|
81
|
+
search?(path: string, query: string, options?: AFSSearchOptions): Promise<AFSSearchResult>;
|
|
82
|
+
exec?(path: string, args: Record<string, any>, options: AFSExecOptions): Promise<AFSExecResult>;
|
|
58
83
|
}
|
|
59
84
|
export type AFSRootEvents = {
|
|
60
85
|
agentSucceed: [{
|
|
@@ -65,7 +90,21 @@ export type AFSRootEvents = {
|
|
|
65
90
|
entry: AFSEntry;
|
|
66
91
|
}];
|
|
67
92
|
};
|
|
93
|
+
export interface AFSRootListOptions extends AFSListOptions, AFSContextPreset {
|
|
94
|
+
preset?: string;
|
|
95
|
+
}
|
|
96
|
+
export interface AFSRootListResult extends Omit<AFSListResult, "data"> {
|
|
97
|
+
data: any;
|
|
98
|
+
}
|
|
99
|
+
export interface AFSRootSearchOptions extends AFSSearchOptions, AFSContextPreset {
|
|
100
|
+
preset?: string;
|
|
101
|
+
}
|
|
102
|
+
export interface AFSRootSearchResult extends Omit<AFSSearchResult, "data"> {
|
|
103
|
+
data: any;
|
|
104
|
+
}
|
|
68
105
|
export interface AFSRoot extends Emitter<AFSRootEvents>, AFSModule {
|
|
106
|
+
list(path: string, options?: AFSRootListOptions): Promise<AFSRootListResult>;
|
|
107
|
+
search(path: string, query: string, options: AFSRootSearchOptions): Promise<AFSRootSearchResult>;
|
|
69
108
|
}
|
|
70
109
|
export interface AFSEntryMetadata extends Record<string, any> {
|
|
71
110
|
execute?: {
|
|
@@ -75,6 +114,7 @@ export interface AFSEntryMetadata extends Record<string, any> {
|
|
|
75
114
|
outputSchema?: Record<string, any>;
|
|
76
115
|
};
|
|
77
116
|
childrenCount?: number;
|
|
117
|
+
childrenTruncated?: boolean;
|
|
78
118
|
}
|
|
79
119
|
export interface AFSEntry<T = any> {
|
|
80
120
|
id: string;
|
|
@@ -89,3 +129,42 @@ export interface AFSEntry<T = any> {
|
|
|
89
129
|
linkTo?: string | null;
|
|
90
130
|
content?: T;
|
|
91
131
|
}
|
|
132
|
+
export declare const afsEntrySchema: ZodType<AFSEntry>;
|
|
133
|
+
export interface AFSContextPreset {
|
|
134
|
+
/**
|
|
135
|
+
* The view template for presenting the search results.
|
|
136
|
+
*/
|
|
137
|
+
view?: string;
|
|
138
|
+
select?: AFSContextPresetOptionAgent<{
|
|
139
|
+
path: string;
|
|
140
|
+
query?: string;
|
|
141
|
+
}, {
|
|
142
|
+
data: string[];
|
|
143
|
+
}>;
|
|
144
|
+
per?: AFSContextPresetOptionAgent<{
|
|
145
|
+
data: AFSEntry;
|
|
146
|
+
}, {
|
|
147
|
+
data: unknown;
|
|
148
|
+
}>;
|
|
149
|
+
dedupe?: AFSContextPresetOptionAgent<{
|
|
150
|
+
data: unknown[];
|
|
151
|
+
}, {
|
|
152
|
+
data: unknown;
|
|
153
|
+
}>;
|
|
154
|
+
format?: "default" | "simple-list" | "tree" | AFSContextPresetOptionAgent<{
|
|
155
|
+
data: unknown;
|
|
156
|
+
}, {
|
|
157
|
+
data: unknown;
|
|
158
|
+
}>;
|
|
159
|
+
}
|
|
160
|
+
export interface AFSContextPresetOptionAgent<I = any, O = any> {
|
|
161
|
+
invoke(input: I, options?: any): Promise<O>;
|
|
162
|
+
}
|
|
163
|
+
export interface AFSContext {
|
|
164
|
+
search?: {
|
|
165
|
+
presets?: Record<string, AFSContextPreset>;
|
|
166
|
+
};
|
|
167
|
+
list?: {
|
|
168
|
+
presets?: Record<string, AFSContextPreset>;
|
|
169
|
+
};
|
|
170
|
+
}
|
package/lib/esm/afs.d.ts
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { Emitter } from "strict-event-emitter";
|
|
2
|
-
import type
|
|
2
|
+
import { type AFSContext, type AFSDeleteOptions, type AFSDeleteResult, type AFSExecOptions, type AFSExecResult, type AFSModule, type AFSReadOptions, type AFSReadResult, type AFSRenameOptions, type AFSRenameResult, type AFSRoot, type AFSRootEvents, type AFSRootListOptions, type AFSRootListResult, type AFSRootSearchOptions, type AFSRootSearchResult, type AFSWriteEntryPayload, type AFSWriteOptions, type AFSWriteResult } from "./type.js";
|
|
3
3
|
export interface AFSOptions {
|
|
4
4
|
modules?: AFSModule[];
|
|
5
|
+
context?: AFSContext;
|
|
5
6
|
}
|
|
6
7
|
export declare class AFS extends Emitter<AFSRootEvents> implements AFSRoot {
|
|
8
|
+
options: AFSOptions;
|
|
7
9
|
name: string;
|
|
8
10
|
constructor(options?: AFSOptions);
|
|
9
11
|
private modules;
|
|
@@ -14,32 +16,19 @@ export declare class AFS extends Emitter<AFSRootEvents> implements AFSRoot {
|
|
|
14
16
|
description?: string;
|
|
15
17
|
module: AFSModule;
|
|
16
18
|
}[]>;
|
|
17
|
-
list(path: string, options?:
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
message?: string;
|
|
28
|
-
}>;
|
|
29
|
-
delete(path: string, options?: AFSDeleteOptions): Promise<{
|
|
30
|
-
message?: string;
|
|
31
|
-
}>;
|
|
32
|
-
rename(oldPath: string, newPath: string, options?: AFSRenameOptions): Promise<{
|
|
33
|
-
message?: string;
|
|
34
|
-
}>;
|
|
35
|
-
search(path: string, query: string, options?: AFSSearchOptions): Promise<{
|
|
36
|
-
list: AFSEntry[];
|
|
37
|
-
message?: string;
|
|
38
|
-
}>;
|
|
19
|
+
list(path: string, options?: AFSRootListOptions): Promise<AFSRootListResult>;
|
|
20
|
+
private _list;
|
|
21
|
+
read(path: string, _options?: AFSReadOptions): Promise<AFSReadResult>;
|
|
22
|
+
write(path: string, content: AFSWriteEntryPayload, options?: AFSWriteOptions): Promise<AFSWriteResult>;
|
|
23
|
+
delete(path: string, options?: AFSDeleteOptions): Promise<AFSDeleteResult>;
|
|
24
|
+
rename(oldPath: string, newPath: string, options?: AFSRenameOptions): Promise<AFSRenameResult>;
|
|
25
|
+
search(path: string, query: string, options?: AFSRootSearchOptions): Promise<AFSRootSearchResult>;
|
|
26
|
+
private processWithPreset;
|
|
27
|
+
private _select;
|
|
28
|
+
private _search;
|
|
39
29
|
private findModules;
|
|
40
|
-
exec(path: string, args: Record<string, any>, options:
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
}>;
|
|
30
|
+
exec(path: string, args: Record<string, any>, options: AFSExecOptions): Promise<AFSExecResult>;
|
|
31
|
+
private buildSimpleListView;
|
|
32
|
+
private buildTreeView;
|
|
33
|
+
private buildMetadataSuffix;
|
|
45
34
|
}
|
package/lib/esm/afs.js
CHANGED
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
import { Emitter } from "strict-event-emitter";
|
|
2
2
|
import { joinURL } from "ufo";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
import { afsEntrySchema, } from "./type.js";
|
|
3
5
|
const DEFAULT_MAX_DEPTH = 1;
|
|
4
6
|
const MODULES_ROOT_DIR = "/modules";
|
|
5
7
|
export class AFS extends Emitter {
|
|
8
|
+
options;
|
|
6
9
|
name = "AFSRoot";
|
|
7
|
-
constructor(options) {
|
|
10
|
+
constructor(options = {}) {
|
|
8
11
|
super();
|
|
12
|
+
this.options = options;
|
|
9
13
|
for (const module of options?.modules ?? []) {
|
|
10
14
|
this.mount(module);
|
|
11
15
|
}
|
|
@@ -32,12 +36,20 @@ export class AFS extends Emitter {
|
|
|
32
36
|
module,
|
|
33
37
|
}));
|
|
34
38
|
}
|
|
35
|
-
async list(path, options) {
|
|
36
|
-
|
|
37
|
-
if (
|
|
38
|
-
|
|
39
|
+
async list(path, options = {}) {
|
|
40
|
+
let preset;
|
|
41
|
+
if (options.preset) {
|
|
42
|
+
preset = this.options?.context?.list?.presets?.[options.preset];
|
|
43
|
+
if (!preset)
|
|
44
|
+
throw new Error(`Preset not found: ${options.preset}`);
|
|
45
|
+
}
|
|
46
|
+
return await this.processWithPreset(path, undefined, preset, {
|
|
47
|
+
...options,
|
|
48
|
+
defaultSelect: () => this._list(path, options),
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
async _list(path, options = {}) {
|
|
39
52
|
const results = [];
|
|
40
|
-
const messages = [];
|
|
41
53
|
const matches = this.findModules(path, options);
|
|
42
54
|
for (const matched of matches) {
|
|
43
55
|
const moduleEntry = {
|
|
@@ -52,12 +64,12 @@ export class AFS extends Emitter {
|
|
|
52
64
|
if (!matched.module.list)
|
|
53
65
|
continue;
|
|
54
66
|
try {
|
|
55
|
-
const {
|
|
67
|
+
const { data } = await matched.module.list(matched.subpath, {
|
|
56
68
|
...options,
|
|
57
69
|
maxDepth: matched.maxDepth,
|
|
58
70
|
});
|
|
59
|
-
if (
|
|
60
|
-
results.push(...
|
|
71
|
+
if (data.length) {
|
|
72
|
+
results.push(...data.map((entry) => ({
|
|
61
73
|
...entry,
|
|
62
74
|
path: joinURL(matched.modulePath, entry.path),
|
|
63
75
|
})));
|
|
@@ -65,30 +77,28 @@ export class AFS extends Emitter {
|
|
|
65
77
|
else {
|
|
66
78
|
results.push(moduleEntry);
|
|
67
79
|
}
|
|
68
|
-
if (message)
|
|
69
|
-
messages.push(message);
|
|
70
80
|
}
|
|
71
81
|
catch (error) {
|
|
72
82
|
console.error(`Error listing from module at ${matched.modulePath}`, error);
|
|
73
83
|
}
|
|
74
84
|
}
|
|
75
|
-
return {
|
|
85
|
+
return { data: results };
|
|
76
86
|
}
|
|
77
|
-
async read(path) {
|
|
87
|
+
async read(path, _options) {
|
|
78
88
|
const modules = this.findModules(path, { exactMatch: true });
|
|
79
89
|
for (const { module, modulePath, subpath } of modules) {
|
|
80
90
|
const res = await module.read?.(subpath);
|
|
81
|
-
if (res?.
|
|
91
|
+
if (res?.data) {
|
|
82
92
|
return {
|
|
83
93
|
...res,
|
|
84
|
-
|
|
85
|
-
...res.
|
|
86
|
-
path: joinURL(modulePath, res.
|
|
94
|
+
data: {
|
|
95
|
+
...res.data,
|
|
96
|
+
path: joinURL(modulePath, res.data.path),
|
|
87
97
|
},
|
|
88
98
|
};
|
|
89
99
|
}
|
|
90
100
|
}
|
|
91
|
-
return {
|
|
101
|
+
return { data: undefined, message: "File not found" };
|
|
92
102
|
}
|
|
93
103
|
async write(path, content, options) {
|
|
94
104
|
const module = this.findModules(path, { exactMatch: true })[0];
|
|
@@ -97,9 +107,9 @@ export class AFS extends Emitter {
|
|
|
97
107
|
const res = await module.module.write(module.subpath, content, options);
|
|
98
108
|
return {
|
|
99
109
|
...res,
|
|
100
|
-
|
|
101
|
-
...res.
|
|
102
|
-
path: joinURL(module.modulePath, res.
|
|
110
|
+
data: {
|
|
111
|
+
...res.data,
|
|
112
|
+
path: joinURL(module.modulePath, res.data.path),
|
|
103
113
|
},
|
|
104
114
|
};
|
|
105
115
|
}
|
|
@@ -121,15 +131,61 @@ export class AFS extends Emitter {
|
|
|
121
131
|
}
|
|
122
132
|
return await oldModule.module.rename(oldModule.subpath, newModule.subpath, options);
|
|
123
133
|
}
|
|
124
|
-
async search(path, query, options) {
|
|
134
|
+
async search(path, query, options = {}) {
|
|
135
|
+
let preset;
|
|
136
|
+
if (options.preset) {
|
|
137
|
+
preset = this.options?.context?.search?.presets?.[options.preset];
|
|
138
|
+
if (!preset)
|
|
139
|
+
throw new Error(`Preset not found: ${options.preset}`);
|
|
140
|
+
}
|
|
141
|
+
return await this.processWithPreset(path, query, preset, {
|
|
142
|
+
...options,
|
|
143
|
+
defaultSelect: () => this._search(path, query, options),
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
async processWithPreset(path, query, preset, options) {
|
|
147
|
+
const select = options.select || preset?.select;
|
|
148
|
+
const per = options.per || preset?.per;
|
|
149
|
+
const dedupe = options.dedupe || preset?.dedupe;
|
|
150
|
+
const format = options.format || preset?.format;
|
|
151
|
+
const entries = select
|
|
152
|
+
? (await this._select(path, query, select, options)).data
|
|
153
|
+
: (await options.defaultSelect()).data;
|
|
154
|
+
const mapped = per
|
|
155
|
+
? await Promise.all(entries.map((data) => per.invoke({ data }, options).then((res) => res.data)))
|
|
156
|
+
: entries;
|
|
157
|
+
const deduped = dedupe
|
|
158
|
+
? await dedupe.invoke({ data: mapped }, options).then((res) => res.data)
|
|
159
|
+
: mapped;
|
|
160
|
+
let formatted = deduped;
|
|
161
|
+
if (format === "simple-list" || format === "tree") {
|
|
162
|
+
const valid = z.array(afsEntrySchema).safeParse(deduped);
|
|
163
|
+
if (!valid.data)
|
|
164
|
+
throw new Error("Tree format requires entries to be AFSEntry objects");
|
|
165
|
+
if (format === "tree")
|
|
166
|
+
formatted = this.buildTreeView(valid.data);
|
|
167
|
+
else if (format === "simple-list")
|
|
168
|
+
formatted = this.buildSimpleListView(valid.data);
|
|
169
|
+
}
|
|
170
|
+
else if (typeof format === "object" && typeof format.invoke === "function") {
|
|
171
|
+
formatted = await format.invoke({ data: deduped }, options).then((res) => res.data);
|
|
172
|
+
}
|
|
173
|
+
return { data: formatted };
|
|
174
|
+
}
|
|
175
|
+
async _select(path, query, select, options) {
|
|
176
|
+
const { data } = await select.invoke({ path, query }, options);
|
|
177
|
+
const results = (await Promise.all(data.map((p) => this.read(p).then((res) => res.data)))).filter((i) => !!i);
|
|
178
|
+
return { data: results };
|
|
179
|
+
}
|
|
180
|
+
async _search(path, query, options) {
|
|
125
181
|
const results = [];
|
|
126
182
|
const messages = [];
|
|
127
183
|
for (const { module, modulePath, subpath } of this.findModules(path)) {
|
|
128
184
|
if (!module.search)
|
|
129
185
|
continue;
|
|
130
186
|
try {
|
|
131
|
-
const {
|
|
132
|
-
results.push(...
|
|
187
|
+
const { data, message } = await module.search(subpath, query, options);
|
|
188
|
+
results.push(...data.map((entry) => ({
|
|
133
189
|
...entry,
|
|
134
190
|
path: joinURL(modulePath, entry.path),
|
|
135
191
|
})));
|
|
@@ -140,7 +196,7 @@ export class AFS extends Emitter {
|
|
|
140
196
|
console.error(`Error searching in module at ${modulePath}`, error);
|
|
141
197
|
}
|
|
142
198
|
}
|
|
143
|
-
return {
|
|
199
|
+
return { data: results, message: messages.join("; ") };
|
|
144
200
|
}
|
|
145
201
|
findModules(path, options) {
|
|
146
202
|
const maxDepth = Math.max(options?.maxDepth ?? DEFAULT_MAX_DEPTH, 1);
|
|
@@ -176,4 +232,55 @@ export class AFS extends Emitter {
|
|
|
176
232
|
throw new Error(`No module found for path: ${path}`);
|
|
177
233
|
return await module.module.exec(module.subpath, args, options);
|
|
178
234
|
}
|
|
235
|
+
buildSimpleListView(entries) {
|
|
236
|
+
return entries.map((entry) => `${entry.path}${this.buildMetadataSuffix(entry)}`);
|
|
237
|
+
}
|
|
238
|
+
buildTreeView(entries) {
|
|
239
|
+
const tree = {};
|
|
240
|
+
const entryMap = new Map();
|
|
241
|
+
for (const entry of entries) {
|
|
242
|
+
entryMap.set(entry.path, entry);
|
|
243
|
+
const parts = entry.path.split("/").filter(Boolean);
|
|
244
|
+
let current = tree;
|
|
245
|
+
for (const part of parts) {
|
|
246
|
+
if (!current[part]) {
|
|
247
|
+
current[part] = {};
|
|
248
|
+
}
|
|
249
|
+
current = current[part];
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
const renderTree = (node, prefix = "", currentPath = "") => {
|
|
253
|
+
let result = "";
|
|
254
|
+
const keys = Object.keys(node);
|
|
255
|
+
keys.forEach((key, index) => {
|
|
256
|
+
const isLast = index === keys.length - 1;
|
|
257
|
+
const fullPath = currentPath ? `${currentPath}/${key}` : `/${key}`;
|
|
258
|
+
const entry = entryMap.get(fullPath);
|
|
259
|
+
result += `${prefix}${isLast ? "└── " : "├── "}${key}${entry ? this.buildMetadataSuffix(entry) : ""}`;
|
|
260
|
+
result += `\n`;
|
|
261
|
+
result += renderTree(node[key], `${prefix}${isLast ? " " : "│ "}`, fullPath);
|
|
262
|
+
});
|
|
263
|
+
return result;
|
|
264
|
+
};
|
|
265
|
+
return renderTree(tree);
|
|
266
|
+
}
|
|
267
|
+
buildMetadataSuffix(entry) {
|
|
268
|
+
// Build metadata suffix
|
|
269
|
+
const metadataParts = [];
|
|
270
|
+
// Children count
|
|
271
|
+
const childrenCount = entry?.metadata?.childrenCount;
|
|
272
|
+
if (typeof childrenCount === "number") {
|
|
273
|
+
metadataParts.push(`${childrenCount} items`);
|
|
274
|
+
}
|
|
275
|
+
// Children truncated
|
|
276
|
+
if (entry?.metadata?.childrenTruncated) {
|
|
277
|
+
metadataParts.push("truncated");
|
|
278
|
+
}
|
|
279
|
+
// Executable
|
|
280
|
+
if (entry?.metadata?.execute) {
|
|
281
|
+
metadataParts.push("executable");
|
|
282
|
+
}
|
|
283
|
+
const metadataSuffix = metadataParts.length > 0 ? ` [${metadataParts.join(", ")}]` : "";
|
|
284
|
+
return metadataSuffix;
|
|
285
|
+
}
|
|
179
286
|
}
|
package/lib/esm/type.d.ts
CHANGED
|
@@ -1,60 +1,85 @@
|
|
|
1
1
|
import type { Emitter } from "strict-event-emitter";
|
|
2
|
+
import { type ZodType } from "zod";
|
|
2
3
|
export interface AFSListOptions {
|
|
3
4
|
filter?: {
|
|
4
5
|
userId?: string;
|
|
5
6
|
sessionId?: string;
|
|
6
7
|
};
|
|
7
|
-
recursive?: boolean;
|
|
8
8
|
maxDepth?: number;
|
|
9
9
|
limit?: number;
|
|
10
10
|
orderBy?: [string, "asc" | "desc"][];
|
|
11
|
+
maxChildren?: number;
|
|
12
|
+
onOverflow?: "truncate";
|
|
13
|
+
/**
|
|
14
|
+
* Whether to disable .gitignore files when listing files.
|
|
15
|
+
* @default false
|
|
16
|
+
*/
|
|
17
|
+
disableGitignore?: boolean;
|
|
18
|
+
context?: any;
|
|
19
|
+
}
|
|
20
|
+
export interface AFSListResult {
|
|
21
|
+
data: AFSEntry[];
|
|
22
|
+
message?: string;
|
|
23
|
+
context?: any;
|
|
11
24
|
}
|
|
12
25
|
export interface AFSSearchOptions {
|
|
13
26
|
limit?: number;
|
|
14
27
|
caseSensitive?: boolean;
|
|
28
|
+
context?: any;
|
|
29
|
+
}
|
|
30
|
+
export interface AFSSearchResult {
|
|
31
|
+
data: AFSEntry[];
|
|
32
|
+
message?: string;
|
|
33
|
+
}
|
|
34
|
+
export interface AFSReadOptions {
|
|
35
|
+
context?: any;
|
|
36
|
+
}
|
|
37
|
+
export interface AFSReadResult {
|
|
38
|
+
data?: AFSEntry;
|
|
39
|
+
message?: string;
|
|
15
40
|
}
|
|
16
41
|
export interface AFSDeleteOptions {
|
|
17
42
|
recursive?: boolean;
|
|
43
|
+
context?: any;
|
|
44
|
+
}
|
|
45
|
+
export interface AFSDeleteResult {
|
|
46
|
+
message?: string;
|
|
18
47
|
}
|
|
19
48
|
export interface AFSRenameOptions {
|
|
20
49
|
overwrite?: boolean;
|
|
50
|
+
context?: any;
|
|
51
|
+
}
|
|
52
|
+
export interface AFSRenameResult {
|
|
53
|
+
message?: string;
|
|
21
54
|
}
|
|
22
55
|
export interface AFSWriteOptions {
|
|
23
56
|
append?: boolean;
|
|
57
|
+
context?: any;
|
|
58
|
+
}
|
|
59
|
+
export interface AFSWriteResult {
|
|
60
|
+
data: AFSEntry;
|
|
61
|
+
message?: string;
|
|
62
|
+
context?: any;
|
|
24
63
|
}
|
|
25
64
|
export interface AFSWriteEntryPayload extends Omit<AFSEntry, "id" | "path"> {
|
|
26
65
|
}
|
|
66
|
+
export interface AFSExecOptions {
|
|
67
|
+
context: any;
|
|
68
|
+
}
|
|
69
|
+
export interface AFSExecResult {
|
|
70
|
+
data: Record<string, any>;
|
|
71
|
+
}
|
|
27
72
|
export interface AFSModule {
|
|
28
73
|
readonly name: string;
|
|
29
74
|
readonly description?: string;
|
|
30
75
|
onMount?(root: AFSRoot): void;
|
|
31
|
-
list?(path: string, options?: AFSListOptions): Promise<
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
}>;
|
|
39
|
-
write?(path: string, content: AFSWriteEntryPayload, options?: AFSWriteOptions): Promise<{
|
|
40
|
-
result: AFSEntry;
|
|
41
|
-
message?: string;
|
|
42
|
-
}>;
|
|
43
|
-
delete?(path: string, options?: AFSDeleteOptions): Promise<{
|
|
44
|
-
message?: string;
|
|
45
|
-
}>;
|
|
46
|
-
rename?(oldPath: string, newPath: string, options?: AFSRenameOptions): Promise<{
|
|
47
|
-
message?: string;
|
|
48
|
-
}>;
|
|
49
|
-
search?(path: string, query: string, options?: AFSSearchOptions): Promise<{
|
|
50
|
-
list: AFSEntry[];
|
|
51
|
-
message?: string;
|
|
52
|
-
}>;
|
|
53
|
-
exec?(path: string, args: Record<string, any>, options: {
|
|
54
|
-
context: any;
|
|
55
|
-
}): Promise<{
|
|
56
|
-
result: Record<string, any>;
|
|
57
|
-
}>;
|
|
76
|
+
list?(path: string, options?: AFSListOptions): Promise<AFSListResult>;
|
|
77
|
+
read?(path: string, options?: AFSReadOptions): Promise<AFSReadResult>;
|
|
78
|
+
write?(path: string, content: AFSWriteEntryPayload, options?: AFSWriteOptions): Promise<AFSWriteResult>;
|
|
79
|
+
delete?(path: string, options?: AFSDeleteOptions): Promise<AFSDeleteResult>;
|
|
80
|
+
rename?(oldPath: string, newPath: string, options?: AFSRenameOptions): Promise<AFSRenameResult>;
|
|
81
|
+
search?(path: string, query: string, options?: AFSSearchOptions): Promise<AFSSearchResult>;
|
|
82
|
+
exec?(path: string, args: Record<string, any>, options: AFSExecOptions): Promise<AFSExecResult>;
|
|
58
83
|
}
|
|
59
84
|
export type AFSRootEvents = {
|
|
60
85
|
agentSucceed: [{
|
|
@@ -65,7 +90,21 @@ export type AFSRootEvents = {
|
|
|
65
90
|
entry: AFSEntry;
|
|
66
91
|
}];
|
|
67
92
|
};
|
|
93
|
+
export interface AFSRootListOptions extends AFSListOptions, AFSContextPreset {
|
|
94
|
+
preset?: string;
|
|
95
|
+
}
|
|
96
|
+
export interface AFSRootListResult extends Omit<AFSListResult, "data"> {
|
|
97
|
+
data: any;
|
|
98
|
+
}
|
|
99
|
+
export interface AFSRootSearchOptions extends AFSSearchOptions, AFSContextPreset {
|
|
100
|
+
preset?: string;
|
|
101
|
+
}
|
|
102
|
+
export interface AFSRootSearchResult extends Omit<AFSSearchResult, "data"> {
|
|
103
|
+
data: any;
|
|
104
|
+
}
|
|
68
105
|
export interface AFSRoot extends Emitter<AFSRootEvents>, AFSModule {
|
|
106
|
+
list(path: string, options?: AFSRootListOptions): Promise<AFSRootListResult>;
|
|
107
|
+
search(path: string, query: string, options: AFSRootSearchOptions): Promise<AFSRootSearchResult>;
|
|
69
108
|
}
|
|
70
109
|
export interface AFSEntryMetadata extends Record<string, any> {
|
|
71
110
|
execute?: {
|
|
@@ -75,6 +114,7 @@ export interface AFSEntryMetadata extends Record<string, any> {
|
|
|
75
114
|
outputSchema?: Record<string, any>;
|
|
76
115
|
};
|
|
77
116
|
childrenCount?: number;
|
|
117
|
+
childrenTruncated?: boolean;
|
|
78
118
|
}
|
|
79
119
|
export interface AFSEntry<T = any> {
|
|
80
120
|
id: string;
|
|
@@ -89,3 +129,42 @@ export interface AFSEntry<T = any> {
|
|
|
89
129
|
linkTo?: string | null;
|
|
90
130
|
content?: T;
|
|
91
131
|
}
|
|
132
|
+
export declare const afsEntrySchema: ZodType<AFSEntry>;
|
|
133
|
+
export interface AFSContextPreset {
|
|
134
|
+
/**
|
|
135
|
+
* The view template for presenting the search results.
|
|
136
|
+
*/
|
|
137
|
+
view?: string;
|
|
138
|
+
select?: AFSContextPresetOptionAgent<{
|
|
139
|
+
path: string;
|
|
140
|
+
query?: string;
|
|
141
|
+
}, {
|
|
142
|
+
data: string[];
|
|
143
|
+
}>;
|
|
144
|
+
per?: AFSContextPresetOptionAgent<{
|
|
145
|
+
data: AFSEntry;
|
|
146
|
+
}, {
|
|
147
|
+
data: unknown;
|
|
148
|
+
}>;
|
|
149
|
+
dedupe?: AFSContextPresetOptionAgent<{
|
|
150
|
+
data: unknown[];
|
|
151
|
+
}, {
|
|
152
|
+
data: unknown;
|
|
153
|
+
}>;
|
|
154
|
+
format?: "default" | "simple-list" | "tree" | AFSContextPresetOptionAgent<{
|
|
155
|
+
data: unknown;
|
|
156
|
+
}, {
|
|
157
|
+
data: unknown;
|
|
158
|
+
}>;
|
|
159
|
+
}
|
|
160
|
+
export interface AFSContextPresetOptionAgent<I = any, O = any> {
|
|
161
|
+
invoke(input: I, options?: any): Promise<O>;
|
|
162
|
+
}
|
|
163
|
+
export interface AFSContext {
|
|
164
|
+
search?: {
|
|
165
|
+
presets?: Record<string, AFSContextPreset>;
|
|
166
|
+
};
|
|
167
|
+
list?: {
|
|
168
|
+
presets?: Record<string, AFSContextPreset>;
|
|
169
|
+
};
|
|
170
|
+
}
|
package/lib/esm/type.js
CHANGED
|
@@ -1 +1,14 @@
|
|
|
1
|
-
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export const afsEntrySchema = z.object({
|
|
3
|
+
id: z.string(),
|
|
4
|
+
createdAt: z.date().optional(),
|
|
5
|
+
updatedAt: z.date().optional(),
|
|
6
|
+
path: z.string(),
|
|
7
|
+
userId: z.string().nullable().optional(),
|
|
8
|
+
sessionId: z.string().nullable().optional(),
|
|
9
|
+
summary: z.string().nullable().optional(),
|
|
10
|
+
description: z.string().nullable().optional(),
|
|
11
|
+
metadata: z.record(z.any()).nullable().optional(),
|
|
12
|
+
linkTo: z.string().nullable().optional(),
|
|
13
|
+
content: z.any().optional(),
|
|
14
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aigne/afs",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0-beta.2",
|
|
4
4
|
"description": "Agentic File System (AFS) is a virtual file system that supports various storage backends and provides a unified API for file operations.",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -48,7 +48,8 @@
|
|
|
48
48
|
},
|
|
49
49
|
"dependencies": {
|
|
50
50
|
"strict-event-emitter": "^0.5.1",
|
|
51
|
-
"ufo": "^1.6.1"
|
|
51
|
+
"ufo": "^1.6.1",
|
|
52
|
+
"zod": "^3.25.67"
|
|
52
53
|
},
|
|
53
54
|
"devDependencies": {
|
|
54
55
|
"@types/bun": "^1.2.22",
|