@aigne/afs-json 1.11.0-beta.6 → 1.11.0-beta.8
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/dist/index.cjs +173 -20
- package/dist/index.d.cts +30 -29
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +30 -29
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +172 -21
- package/dist/index.mjs.map +1 -1
- package/package.json +5 -4
package/dist/index.cjs
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
1
2
|
const require_decorate = require('./_virtual/_@oxc-project_runtime@0.108.0/helpers/decorate.cjs');
|
|
3
|
+
let node_fs = require("node:fs");
|
|
2
4
|
let node_fs_promises = require("node:fs/promises");
|
|
3
5
|
let node_path = require("node:path");
|
|
4
6
|
let _aigne_afs = require("@aigne/afs");
|
|
@@ -33,10 +35,24 @@ var AFSJSON = class AFSJSON extends _aigne_afs_provider.AFSBaseProvider {
|
|
|
33
35
|
static schema() {
|
|
34
36
|
return afsJSONOptionsSchema;
|
|
35
37
|
}
|
|
36
|
-
static
|
|
38
|
+
static manifest() {
|
|
39
|
+
return {
|
|
40
|
+
name: "json",
|
|
41
|
+
description: "Mount a JSON or YAML file as a virtual filesystem",
|
|
42
|
+
uriTemplate: "json://{localPath+}",
|
|
43
|
+
category: "structured-data",
|
|
44
|
+
schema: zod.z.object({ localPath: zod.z.string() }),
|
|
45
|
+
tags: [
|
|
46
|
+
"json",
|
|
47
|
+
"yaml",
|
|
48
|
+
"structured-data"
|
|
49
|
+
]
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
static async load({ basePath, config } = {}) {
|
|
37
53
|
return new AFSJSON({
|
|
38
|
-
...await AFSJSON.schema().parseAsync(
|
|
39
|
-
cwd:
|
|
54
|
+
...await AFSJSON.schema().parseAsync(config),
|
|
55
|
+
cwd: basePath
|
|
40
56
|
});
|
|
41
57
|
}
|
|
42
58
|
name;
|
|
@@ -50,11 +66,16 @@ var AFSJSON = class AFSJSON extends _aigne_afs_provider.AFSBaseProvider {
|
|
|
50
66
|
constructor(options) {
|
|
51
67
|
super();
|
|
52
68
|
this.options = options;
|
|
69
|
+
if (options.localPath && !options.jsonPath) options.jsonPath = options.localPath;
|
|
53
70
|
(0, _aigne_afs_utils_zod.zodParse)(afsJSONOptionsSchema, options);
|
|
54
71
|
let jsonPath;
|
|
55
72
|
jsonPath = options.jsonPath.replaceAll("${CWD}", process.cwd());
|
|
56
73
|
if (jsonPath.startsWith("~/")) jsonPath = (0, node_path.join)(process.env.HOME || "", jsonPath.slice(2));
|
|
57
74
|
if (!(0, node_path.isAbsolute)(jsonPath)) jsonPath = (0, node_path.join)(options.cwd || process.cwd(), jsonPath);
|
|
75
|
+
if (!(0, node_fs.existsSync)(jsonPath)) {
|
|
76
|
+
(0, node_fs.mkdirSync)((0, node_path.dirname)(jsonPath), { recursive: true });
|
|
77
|
+
(0, node_fs.writeFileSync)(jsonPath, "{}", "utf8");
|
|
78
|
+
}
|
|
58
79
|
const ext = (0, node_path.extname)(jsonPath).toLowerCase();
|
|
59
80
|
this.fileFormat = ext === ".yaml" || ext === ".yml" ? "yaml" : "json";
|
|
60
81
|
const extensions = [
|
|
@@ -76,7 +97,7 @@ var AFSJSON = class AFSJSON extends _aigne_afs_provider.AFSBaseProvider {
|
|
|
76
97
|
/**
|
|
77
98
|
* Read metadata for a JSON node via /.meta or /path/.meta
|
|
78
99
|
* Returns stored metadata merged with computed type information
|
|
79
|
-
* Note: Meta is read-only. To write metadata, use write() with payload.
|
|
100
|
+
* Note: Meta is read-only. To write metadata, use write() with payload.meta.
|
|
80
101
|
*/
|
|
81
102
|
async readMetaHandler(ctx) {
|
|
82
103
|
await this.ensureLoaded();
|
|
@@ -104,7 +125,7 @@ var AFSJSON = class AFSJSON extends _aigne_afs_provider.AFSBaseProvider {
|
|
|
104
125
|
if (this.fileStats.birthtime) computedMeta.created = this.fileStats.birthtime;
|
|
105
126
|
if (this.fileStats.mtime) computedMeta.modified = this.fileStats.mtime;
|
|
106
127
|
return this.buildEntry((0, ufo.joinURL)(nodePath, ".meta"), {
|
|
107
|
-
|
|
128
|
+
meta: storedMeta,
|
|
108
129
|
content: computedMeta,
|
|
109
130
|
createdAt: this.fileStats.birthtime,
|
|
110
131
|
updatedAt: this.fileStats.mtime
|
|
@@ -120,12 +141,15 @@ var AFSJSON = class AFSJSON extends _aigne_afs_provider.AFSBaseProvider {
|
|
|
120
141
|
const segments = this.getPathSegments(normalizedPath);
|
|
121
142
|
const value = this.getValueAtPath(this.jsonData, segments);
|
|
122
143
|
if (value === void 0) throw new _aigne_afs.AFSNotFoundError(normalizedPath);
|
|
144
|
+
if (maxDepth === 0) return { data: [] };
|
|
145
|
+
if (!this.isDirectoryValue(value)) return { data: [] };
|
|
123
146
|
const entries = [];
|
|
124
|
-
const
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
147
|
+
const rootChildren = this.getChildren(value);
|
|
148
|
+
const queue = (rootChildren.length > maxChildren ? rootChildren.slice(0, maxChildren) : rootChildren).map((child) => ({
|
|
149
|
+
path: normalizedPath === "/" ? `/${child.key}` : `${normalizedPath}/${child.key}`,
|
|
150
|
+
value: child.value,
|
|
151
|
+
depth: 1
|
|
152
|
+
}));
|
|
129
153
|
while (queue.length > 0) {
|
|
130
154
|
const item = queue.shift();
|
|
131
155
|
if (!item) break;
|
|
@@ -170,10 +194,10 @@ var AFSJSON = class AFSJSON extends _aigne_afs_provider.AFSBaseProvider {
|
|
|
170
194
|
const normalizedPath = ctx.params.path ? `/${ctx.params.path}` : "/";
|
|
171
195
|
const segments = this.getPathSegments(normalizedPath);
|
|
172
196
|
if (payload.content !== void 0) this.setValueAtPath(this.jsonData, segments, payload.content);
|
|
173
|
-
if (payload.
|
|
197
|
+
if (payload.meta !== void 0 && typeof payload.meta === "object") {
|
|
174
198
|
const finalMeta = {
|
|
175
199
|
...this.loadMeta(normalizedPath) || {},
|
|
176
|
-
...payload.
|
|
200
|
+
...payload.meta
|
|
177
201
|
};
|
|
178
202
|
this.saveMeta(normalizedPath, finalMeta);
|
|
179
203
|
}
|
|
@@ -189,7 +213,7 @@ var AFSJSON = class AFSJSON extends _aigne_afs_provider.AFSBaseProvider {
|
|
|
189
213
|
summary: payload.summary,
|
|
190
214
|
createdAt: this.fileStats.birthtime,
|
|
191
215
|
updatedAt: this.fileStats.mtime,
|
|
192
|
-
|
|
216
|
+
meta: {
|
|
193
217
|
...storedMeta,
|
|
194
218
|
childrenCount: isDir ? children.length : void 0
|
|
195
219
|
},
|
|
@@ -265,15 +289,136 @@ var AFSJSON = class AFSJSON extends _aigne_afs_provider.AFSBaseProvider {
|
|
|
265
289
|
if (value === void 0) throw new _aigne_afs.AFSNotFoundError(normalizedPath);
|
|
266
290
|
const isDir = this.isDirectoryValue(value);
|
|
267
291
|
const children = isDir ? this.getChildren(value) : [];
|
|
268
|
-
const meta = this.loadMeta(normalizedPath);
|
|
292
|
+
const meta = { ...this.loadMeta(normalizedPath) };
|
|
293
|
+
if (isDir) meta.childrenCount = children.length;
|
|
269
294
|
return { data: {
|
|
295
|
+
id: segments.length > 0 ? segments[segments.length - 1] : "/",
|
|
270
296
|
path: normalizedPath,
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
meta: meta ?? void 0
|
|
297
|
+
createdAt: this.fileStats.birthtime,
|
|
298
|
+
updatedAt: this.fileStats.mtime,
|
|
299
|
+
meta
|
|
275
300
|
} };
|
|
276
301
|
}
|
|
302
|
+
async readCapabilitiesHandler(_ctx) {
|
|
303
|
+
await this.ensureLoaded();
|
|
304
|
+
const operations = [
|
|
305
|
+
"list",
|
|
306
|
+
"read",
|
|
307
|
+
"stat",
|
|
308
|
+
"explain",
|
|
309
|
+
"search"
|
|
310
|
+
];
|
|
311
|
+
if (this.accessMode === "readwrite") operations.push("write", "delete", "rename");
|
|
312
|
+
return {
|
|
313
|
+
id: "/.meta/.capabilities",
|
|
314
|
+
path: "/.meta/.capabilities",
|
|
315
|
+
content: {
|
|
316
|
+
schemaVersion: 1,
|
|
317
|
+
provider: this.name,
|
|
318
|
+
description: this.description || `JSON/YAML virtual filesystem (${this.fileFormat} format)`,
|
|
319
|
+
tools: [],
|
|
320
|
+
actions: [],
|
|
321
|
+
operations: this.getOperationsDeclaration()
|
|
322
|
+
},
|
|
323
|
+
meta: {
|
|
324
|
+
kind: "afs:capabilities",
|
|
325
|
+
operations
|
|
326
|
+
}
|
|
327
|
+
};
|
|
328
|
+
}
|
|
329
|
+
async explainHandler(ctx) {
|
|
330
|
+
await this.ensureLoaded();
|
|
331
|
+
const normalizedPath = (0, ufo.joinURL)("/", ctx.params.path ?? "");
|
|
332
|
+
const format = ctx.options?.format || "markdown";
|
|
333
|
+
const segments = this.getPathSegments(normalizedPath);
|
|
334
|
+
const value = this.getValueAtPath(this.jsonData, segments);
|
|
335
|
+
if (value === void 0) throw new _aigne_afs.AFSNotFoundError(normalizedPath);
|
|
336
|
+
const nodeName = segments.length > 0 ? segments[segments.length - 1] : "/";
|
|
337
|
+
const isDir = this.isDirectoryValue(value);
|
|
338
|
+
const storedMeta = this.loadMeta(normalizedPath);
|
|
339
|
+
const lines = [];
|
|
340
|
+
if (format === "markdown") {
|
|
341
|
+
lines.push(`# ${nodeName}`);
|
|
342
|
+
lines.push("");
|
|
343
|
+
lines.push(`**Path:** \`${normalizedPath}\``);
|
|
344
|
+
lines.push(`**Format:** ${this.fileFormat.toUpperCase()}`);
|
|
345
|
+
if (normalizedPath === "/") {
|
|
346
|
+
const topType = Array.isArray(this.jsonData) ? "array" : "object";
|
|
347
|
+
const children = this.getChildren(this.jsonData);
|
|
348
|
+
lines.push(`**Structure:** ${topType}`);
|
|
349
|
+
lines.push(`**Top-level keys:** ${children.length}`);
|
|
350
|
+
if (children.length > 0) {
|
|
351
|
+
lines.push("");
|
|
352
|
+
lines.push("## Keys");
|
|
353
|
+
lines.push("");
|
|
354
|
+
for (const child of children.slice(0, 30)) {
|
|
355
|
+
const childVal = child.value;
|
|
356
|
+
const childType = this.describeType(childVal);
|
|
357
|
+
lines.push(`- \`${child.key}\` — ${childType}`);
|
|
358
|
+
}
|
|
359
|
+
if (children.length > 30) lines.push(`- ... and ${children.length - 30} more`);
|
|
360
|
+
}
|
|
361
|
+
} else if (Array.isArray(value)) {
|
|
362
|
+
lines.push(`**Type:** array`);
|
|
363
|
+
lines.push(`**Elements:** ${value.length}`);
|
|
364
|
+
if (value.length > 0) {
|
|
365
|
+
const elementType = this.describeType(value[0]);
|
|
366
|
+
const isHomogeneous = value.every((v) => this.describeType(v) === elementType);
|
|
367
|
+
lines.push(`**Element type:** ${isHomogeneous ? elementType : "mixed"}`);
|
|
368
|
+
}
|
|
369
|
+
} else if (typeof value === "object" && value !== null) {
|
|
370
|
+
const children = this.getChildren(value);
|
|
371
|
+
lines.push(`**Type:** object`);
|
|
372
|
+
lines.push(`**Keys:** ${children.length}`);
|
|
373
|
+
if (children.length > 0) {
|
|
374
|
+
lines.push("");
|
|
375
|
+
lines.push("## Keys");
|
|
376
|
+
lines.push("");
|
|
377
|
+
for (const child of children.slice(0, 30)) {
|
|
378
|
+
const childType = this.describeType(child.value);
|
|
379
|
+
lines.push(`- \`${child.key}\` — ${childType}`);
|
|
380
|
+
}
|
|
381
|
+
if (children.length > 30) lines.push(`- ... and ${children.length - 30} more`);
|
|
382
|
+
}
|
|
383
|
+
} else {
|
|
384
|
+
const valType = value === null ? "null" : typeof value;
|
|
385
|
+
lines.push(`**Type:** ${valType}`);
|
|
386
|
+
const valStr = String(value);
|
|
387
|
+
if (valStr.length > 200) lines.push(`**Value:** ${valStr.slice(0, 200)}...`);
|
|
388
|
+
else lines.push(`**Value:** ${valStr}`);
|
|
389
|
+
}
|
|
390
|
+
if (storedMeta) {
|
|
391
|
+
lines.push("");
|
|
392
|
+
lines.push("## Metadata");
|
|
393
|
+
for (const [key, val] of Object.entries(storedMeta)) lines.push(`- **${key}:** ${JSON.stringify(val)}`);
|
|
394
|
+
}
|
|
395
|
+
} else {
|
|
396
|
+
lines.push(`${nodeName} (${isDir ? "directory" : "value"})`);
|
|
397
|
+
lines.push(`Path: ${normalizedPath}`);
|
|
398
|
+
lines.push(`Format: ${this.fileFormat}`);
|
|
399
|
+
if (isDir) {
|
|
400
|
+
const children = this.getChildren(value);
|
|
401
|
+
lines.push(`Children: ${children.length}`);
|
|
402
|
+
} else {
|
|
403
|
+
const valStr = String(value);
|
|
404
|
+
lines.push(`Type: ${value === null ? "null" : typeof value}`);
|
|
405
|
+
lines.push(`Value: ${valStr.length > 200 ? `${valStr.slice(0, 200)}...` : valStr}`);
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
return {
|
|
409
|
+
content: lines.join("\n"),
|
|
410
|
+
format
|
|
411
|
+
};
|
|
412
|
+
}
|
|
413
|
+
/**
|
|
414
|
+
* Get a human-readable type description for a JSON value.
|
|
415
|
+
*/
|
|
416
|
+
describeType(value) {
|
|
417
|
+
if (value === null) return "null";
|
|
418
|
+
if (Array.isArray(value)) return `array[${value.length}]`;
|
|
419
|
+
if (typeof value === "object") return `object{${Object.keys(value).filter((k) => !this.isMetaKey(k)).length} keys}`;
|
|
420
|
+
return typeof value;
|
|
421
|
+
}
|
|
277
422
|
/**
|
|
278
423
|
* Check if a key is a hidden meta key that should be filtered from listings
|
|
279
424
|
*/
|
|
@@ -484,9 +629,13 @@ var AFSJSON = class AFSJSON extends _aigne_afs_provider.AFSBaseProvider {
|
|
|
484
629
|
valueToAFSEntry(path, value) {
|
|
485
630
|
const isDir = this.isDirectoryValue(value);
|
|
486
631
|
const children = isDir ? this.getChildren(value) : [];
|
|
632
|
+
const kind = Array.isArray(value) ? "json:array" : isDir ? "json:object" : "json:value";
|
|
487
633
|
return this.buildEntry(path, {
|
|
488
634
|
content: isDir ? void 0 : value,
|
|
489
|
-
|
|
635
|
+
meta: {
|
|
636
|
+
kind,
|
|
637
|
+
childrenCount: isDir ? children.length : void 0
|
|
638
|
+
},
|
|
490
639
|
createdAt: this.fileStats.birthtime,
|
|
491
640
|
updatedAt: this.fileStats.mtime
|
|
492
641
|
});
|
|
@@ -500,6 +649,10 @@ require_decorate.__decorate([(0, _aigne_afs_provider.Delete)("/:path*")], AFSJSO
|
|
|
500
649
|
require_decorate.__decorate([(0, _aigne_afs_provider.Rename)("/:path*")], AFSJSON.prototype, "renameHandler", null);
|
|
501
650
|
require_decorate.__decorate([(0, _aigne_afs_provider.Search)("/:path*")], AFSJSON.prototype, "searchHandler", null);
|
|
502
651
|
require_decorate.__decorate([(0, _aigne_afs_provider.Stat)("/:path*")], AFSJSON.prototype, "statHandler", null);
|
|
652
|
+
require_decorate.__decorate([(0, _aigne_afs_provider.Read)("/.meta/.capabilities")], AFSJSON.prototype, "readCapabilitiesHandler", null);
|
|
653
|
+
require_decorate.__decorate([(0, _aigne_afs_provider.Explain)("/:path*")], AFSJSON.prototype, "explainHandler", null);
|
|
654
|
+
var src_default = AFSJSON;
|
|
503
655
|
|
|
504
656
|
//#endregion
|
|
505
|
-
exports.AFSJSON = AFSJSON;
|
|
657
|
+
exports.AFSJSON = AFSJSON;
|
|
658
|
+
exports.default = src_default;
|
package/dist/index.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AFSAccessMode, AFSEntry, AFSListResult, AFSModuleLoadParams, AFSSearchOptions, AFSStatResult, AFSWriteEntryPayload } from "@aigne/afs";
|
|
1
|
+
import { AFSAccessMode, AFSEntry, AFSExplainResult, AFSListResult, AFSModuleLoadParams, AFSSearchOptions, AFSStatResult, AFSWriteEntryPayload, ProviderManifest } from "@aigne/afs";
|
|
2
2
|
import { AFSBaseProvider, RouteContext } from "@aigne/afs/provider";
|
|
3
3
|
import { z } from "zod";
|
|
4
4
|
|
|
@@ -30,36 +30,27 @@ interface AFSJSONOptions {
|
|
|
30
30
|
declare class AFSJSON extends AFSBaseProvider {
|
|
31
31
|
options: AFSJSONOptions & {
|
|
32
32
|
cwd?: string;
|
|
33
|
+
localPath?: string;
|
|
34
|
+
uri?: string;
|
|
33
35
|
};
|
|
34
|
-
static schema(): z.
|
|
35
|
-
name:
|
|
36
|
-
jsonPath: z.ZodString;
|
|
37
|
-
description: z.ZodType<string | undefined, z.ZodTypeDef, string | undefined>;
|
|
38
|
-
accessMode: z.ZodType<"readonly" | "readwrite" | undefined, z.ZodTypeDef, "readonly" | "readwrite" | undefined>;
|
|
39
|
-
agentSkills: z.ZodType<boolean | undefined, z.ZodTypeDef, boolean | undefined>;
|
|
40
|
-
}, "strip", z.ZodTypeAny, {
|
|
36
|
+
static schema(): z.ZodType<{
|
|
37
|
+
name: string | undefined;
|
|
41
38
|
jsonPath: string;
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
39
|
+
description: string | undefined;
|
|
40
|
+
accessMode: "readonly" | "readwrite" | undefined;
|
|
41
|
+
agentSkills: boolean | undefined;
|
|
42
|
+
}, unknown, z.core.$ZodTypeInternals<{
|
|
43
|
+
name: string | undefined;
|
|
47
44
|
jsonPath: string;
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
jsonPath: string;
|
|
54
|
-
name?: string | undefined;
|
|
55
|
-
description?: string | undefined;
|
|
56
|
-
accessMode?: "readonly" | "readwrite" | undefined;
|
|
57
|
-
agentSkills?: boolean | undefined;
|
|
58
|
-
}, any>;
|
|
45
|
+
description: string | undefined;
|
|
46
|
+
accessMode: "readonly" | "readwrite" | undefined;
|
|
47
|
+
agentSkills: boolean | undefined;
|
|
48
|
+
}, unknown>>;
|
|
49
|
+
static manifest(): ProviderManifest;
|
|
59
50
|
static load({
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
}
|
|
51
|
+
basePath,
|
|
52
|
+
config
|
|
53
|
+
}?: AFSModuleLoadParams): Promise<AFSJSON>;
|
|
63
54
|
readonly name: string;
|
|
64
55
|
readonly description?: string;
|
|
65
56
|
readonly accessMode: AFSAccessMode;
|
|
@@ -70,11 +61,13 @@ declare class AFSJSON extends AFSBaseProvider {
|
|
|
70
61
|
private resolvedJsonPath;
|
|
71
62
|
constructor(options: AFSJSONOptions & {
|
|
72
63
|
cwd?: string;
|
|
64
|
+
localPath?: string;
|
|
65
|
+
uri?: string;
|
|
73
66
|
});
|
|
74
67
|
/**
|
|
75
68
|
* Read metadata for a JSON node via /.meta or /path/.meta
|
|
76
69
|
* Returns stored metadata merged with computed type information
|
|
77
|
-
* Note: Meta is read-only. To write metadata, use write() with payload.
|
|
70
|
+
* Note: Meta is read-only. To write metadata, use write() with payload.meta.
|
|
78
71
|
*/
|
|
79
72
|
readMetaHandler(ctx: RouteContext<{
|
|
80
73
|
path?: string;
|
|
@@ -120,6 +113,14 @@ declare class AFSJSON extends AFSBaseProvider {
|
|
|
120
113
|
statHandler(ctx: RouteContext<{
|
|
121
114
|
path?: string;
|
|
122
115
|
}>): Promise<AFSStatResult>;
|
|
116
|
+
readCapabilitiesHandler(_ctx: RouteContext): Promise<AFSEntry | undefined>;
|
|
117
|
+
explainHandler(ctx: RouteContext<{
|
|
118
|
+
path?: string;
|
|
119
|
+
}>): Promise<AFSExplainResult>;
|
|
120
|
+
/**
|
|
121
|
+
* Get a human-readable type description for a JSON value.
|
|
122
|
+
*/
|
|
123
|
+
private describeType;
|
|
123
124
|
/**
|
|
124
125
|
* Check if a key is a hidden meta key that should be filtered from listings
|
|
125
126
|
*/
|
|
@@ -179,5 +180,5 @@ declare class AFSJSON extends AFSBaseProvider {
|
|
|
179
180
|
private valueToAFSEntry;
|
|
180
181
|
}
|
|
181
182
|
//#endregion
|
|
182
|
-
export { AFSJSON, AFSJSONOptions };
|
|
183
|
+
export { AFSJSON, AFSJSON as default, AFSJSONOptions };
|
|
183
184
|
//# sourceMappingURL=index.d.cts.map
|
package/dist/index.d.cts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.cts","names":[],"sources":["../src/index.ts"],"mappings":";;;;;
|
|
1
|
+
{"version":3,"file":"index.d.cts","names":[],"sources":["../src/index.ts"],"mappings":";;;;;UAkDiB,cAAA;EACf,IAAA;EACA,QAAA;EACA,WAAA;;;;;;;EAOA,UAAA,GAAa,aAAA;EAMb;;;AAuBF;;EAvBE,WAAA;AAAA;;;;;;;cAuBW,OAAA,SAAgB,eAAA;EAkCR,OAAA,EAAS,cAAA;IAAmB,GAAA;IAAc,SAAA;IAAoB,GAAA;EAAA;EAAA,OAjC1E,MAAA,CAAA,GAAM,CAAA,CAAA,OAAA;;;;;;;;;;;;;SAIN,QAAA,CAAA,GAAY,gBAAA;EAAA,OAWN,IAAA,CAAA;IAAO,QAAA;IAAU;EAAA,IAAU,mBAAA,GAAwB,OAAA,CAAA,OAAA;EAAA,SAKvD,IAAA;EAAA,SACA,WAAA;EAAA,SACA,UAAA,EAAY,aAAA;EAAA,SACZ,WAAA;EAAA,QAED,QAAA;EAAA,QACA,SAAA;EAAA,QAIA,UAAA;EAAA,QACA,gBAAA;cAEW,OAAA,EAAS,cAAA;IAAmB,GAAA;IAAc,SAAA;IAAoB,GAAA;EAAA;EAlCtD;;;;;EA4GrB,eAAA,CAAgB,GAAA,EAAK,YAAA;IAAe,IAAA;EAAA,KAAmB,OAAA,CAAQ,QAAA;EAmE/D,WAAA,CACJ,GAAA,EAAK,YAAA;IAAe,IAAA;EAAA,KACnB,OAAA,CAAQ,aAAA;IAAkB,QAAA;EAAA;EAiFvB,WAAA,CAAY,GAAA,EAAK,YAAA;IAAe,IAAA;EAAA,KAAmB,OAAA,CAAQ,QAAA;;;;;;;;;;EAwB3D,YAAA,CACJ,GAAA,EAAK,YAAA;IAAe,IAAA;EAAA,IACpB,OAAA,EAAS,oBAAA,GACR,OAAA;IAAU,IAAA,EAAM,QAAA;EAAA;EAgDb,aAAA,CAAc,GAAA,EAAK,YAAA;IAAe,IAAA;EAAA,KAAmB,OAAA;IAAU,OAAA;EAAA;EA0B/D,aAAA,CACJ,GAAA,EAAK,YAAA;IAAe,IAAA;EAAA,IACpB,OAAA,WACC,OAAA;IAAU,OAAA;EAAA;EAiCP,aAAA,CACJ,GAAA,EAAK,YAAA;IAAe,IAAA;EAAA,IACpB,KAAA,UACA,OAAA,GAAU,gBAAA,GACT,OAAA;IAAU,IAAA,EAAM,QAAA;IAAY,OAAA;EAAA;EAuDzB,WAAA,CAAY,GAAA,EAAK,YAAA;IAAe,IAAA;EAAA,KAAmB,OAAA,CAAQ,aAAA;EAmC3D,uBAAA,CAAwB,IAAA,EAAM,YAAA,GAAe,OAAA,CAAQ,QAAA;EA0BrD,cAAA,CAAe,GAAA,EAAK,YAAA;IAAe,IAAA;EAAA,KAAmB,OAAA,CAAQ,gBAAA;EAvZ9C;;;EAAA,QAmgBd,YAAA;EA/bD;;;EAAA,QA8cC,SAAA;EA7cG;;;;;;;EAAA,QAwdH,QAAA;EA/WF;;;;;;;EAAA,QA+aE,QAAA;EA5aW;;;;EAAA,QAseL,YAAA;EAtb6C;;;EAAA,QAid7C,UAAA;EAtbQ;;;EAAA,QA6cd,eAAA;EA3cK;;;EAAA,QAodL,cAAA;EAlbN;;;EAAA,QA0cM,cAAA;EAvcL;;;EAAA,QAigBK,iBAAA;EA1cF;;;EAAA,QAqfE,gBAAA;EArfiD;;;EAAA,QA8fjD,WAAA;EA3dsB;;;EAAA,QA0etB,eAAA;AAAA"}
|
package/dist/index.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AFSAccessMode, AFSEntry, AFSListResult, AFSModuleLoadParams, AFSSearchOptions, AFSStatResult, AFSWriteEntryPayload } from "@aigne/afs";
|
|
1
|
+
import { AFSAccessMode, AFSEntry, AFSExplainResult, AFSListResult, AFSModuleLoadParams, AFSSearchOptions, AFSStatResult, AFSWriteEntryPayload, ProviderManifest } from "@aigne/afs";
|
|
2
2
|
import { AFSBaseProvider, RouteContext } from "@aigne/afs/provider";
|
|
3
3
|
import { z } from "zod";
|
|
4
4
|
|
|
@@ -30,36 +30,27 @@ interface AFSJSONOptions {
|
|
|
30
30
|
declare class AFSJSON extends AFSBaseProvider {
|
|
31
31
|
options: AFSJSONOptions & {
|
|
32
32
|
cwd?: string;
|
|
33
|
+
localPath?: string;
|
|
34
|
+
uri?: string;
|
|
33
35
|
};
|
|
34
|
-
static schema(): z.
|
|
35
|
-
name:
|
|
36
|
-
jsonPath: z.ZodString;
|
|
37
|
-
description: z.ZodType<string | undefined, z.ZodTypeDef, string | undefined>;
|
|
38
|
-
accessMode: z.ZodType<"readonly" | "readwrite" | undefined, z.ZodTypeDef, "readonly" | "readwrite" | undefined>;
|
|
39
|
-
agentSkills: z.ZodType<boolean | undefined, z.ZodTypeDef, boolean | undefined>;
|
|
40
|
-
}, "strip", z.ZodTypeAny, {
|
|
36
|
+
static schema(): z.ZodType<{
|
|
37
|
+
name: string | undefined;
|
|
41
38
|
jsonPath: string;
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
39
|
+
description: string | undefined;
|
|
40
|
+
accessMode: "readonly" | "readwrite" | undefined;
|
|
41
|
+
agentSkills: boolean | undefined;
|
|
42
|
+
}, unknown, z.core.$ZodTypeInternals<{
|
|
43
|
+
name: string | undefined;
|
|
47
44
|
jsonPath: string;
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
jsonPath: string;
|
|
54
|
-
name?: string | undefined;
|
|
55
|
-
description?: string | undefined;
|
|
56
|
-
accessMode?: "readonly" | "readwrite" | undefined;
|
|
57
|
-
agentSkills?: boolean | undefined;
|
|
58
|
-
}, any>;
|
|
45
|
+
description: string | undefined;
|
|
46
|
+
accessMode: "readonly" | "readwrite" | undefined;
|
|
47
|
+
agentSkills: boolean | undefined;
|
|
48
|
+
}, unknown>>;
|
|
49
|
+
static manifest(): ProviderManifest;
|
|
59
50
|
static load({
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
}
|
|
51
|
+
basePath,
|
|
52
|
+
config
|
|
53
|
+
}?: AFSModuleLoadParams): Promise<AFSJSON>;
|
|
63
54
|
readonly name: string;
|
|
64
55
|
readonly description?: string;
|
|
65
56
|
readonly accessMode: AFSAccessMode;
|
|
@@ -70,11 +61,13 @@ declare class AFSJSON extends AFSBaseProvider {
|
|
|
70
61
|
private resolvedJsonPath;
|
|
71
62
|
constructor(options: AFSJSONOptions & {
|
|
72
63
|
cwd?: string;
|
|
64
|
+
localPath?: string;
|
|
65
|
+
uri?: string;
|
|
73
66
|
});
|
|
74
67
|
/**
|
|
75
68
|
* Read metadata for a JSON node via /.meta or /path/.meta
|
|
76
69
|
* Returns stored metadata merged with computed type information
|
|
77
|
-
* Note: Meta is read-only. To write metadata, use write() with payload.
|
|
70
|
+
* Note: Meta is read-only. To write metadata, use write() with payload.meta.
|
|
78
71
|
*/
|
|
79
72
|
readMetaHandler(ctx: RouteContext<{
|
|
80
73
|
path?: string;
|
|
@@ -120,6 +113,14 @@ declare class AFSJSON extends AFSBaseProvider {
|
|
|
120
113
|
statHandler(ctx: RouteContext<{
|
|
121
114
|
path?: string;
|
|
122
115
|
}>): Promise<AFSStatResult>;
|
|
116
|
+
readCapabilitiesHandler(_ctx: RouteContext): Promise<AFSEntry | undefined>;
|
|
117
|
+
explainHandler(ctx: RouteContext<{
|
|
118
|
+
path?: string;
|
|
119
|
+
}>): Promise<AFSExplainResult>;
|
|
120
|
+
/**
|
|
121
|
+
* Get a human-readable type description for a JSON value.
|
|
122
|
+
*/
|
|
123
|
+
private describeType;
|
|
123
124
|
/**
|
|
124
125
|
* Check if a key is a hidden meta key that should be filtered from listings
|
|
125
126
|
*/
|
|
@@ -179,5 +180,5 @@ declare class AFSJSON extends AFSBaseProvider {
|
|
|
179
180
|
private valueToAFSEntry;
|
|
180
181
|
}
|
|
181
182
|
//#endregion
|
|
182
|
-
export { AFSJSON, AFSJSONOptions };
|
|
183
|
+
export { AFSJSON, AFSJSON as default, AFSJSONOptions };
|
|
183
184
|
//# sourceMappingURL=index.d.mts.map
|
package/dist/index.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/index.ts"],"mappings":";;;;;
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/index.ts"],"mappings":";;;;;UAkDiB,cAAA;EACf,IAAA;EACA,QAAA;EACA,WAAA;;;;;;;EAOA,UAAA,GAAa,aAAA;EAMb;;;AAuBF;;EAvBE,WAAA;AAAA;;;;;;;cAuBW,OAAA,SAAgB,eAAA;EAkCR,OAAA,EAAS,cAAA;IAAmB,GAAA;IAAc,SAAA;IAAoB,GAAA;EAAA;EAAA,OAjC1E,MAAA,CAAA,GAAM,CAAA,CAAA,OAAA;;;;;;;;;;;;;SAIN,QAAA,CAAA,GAAY,gBAAA;EAAA,OAWN,IAAA,CAAA;IAAO,QAAA;IAAU;EAAA,IAAU,mBAAA,GAAwB,OAAA,CAAA,OAAA;EAAA,SAKvD,IAAA;EAAA,SACA,WAAA;EAAA,SACA,UAAA,EAAY,aAAA;EAAA,SACZ,WAAA;EAAA,QAED,QAAA;EAAA,QACA,SAAA;EAAA,QAIA,UAAA;EAAA,QACA,gBAAA;cAEW,OAAA,EAAS,cAAA;IAAmB,GAAA;IAAc,SAAA;IAAoB,GAAA;EAAA;EAlCtD;;;;;EA4GrB,eAAA,CAAgB,GAAA,EAAK,YAAA;IAAe,IAAA;EAAA,KAAmB,OAAA,CAAQ,QAAA;EAmE/D,WAAA,CACJ,GAAA,EAAK,YAAA;IAAe,IAAA;EAAA,KACnB,OAAA,CAAQ,aAAA;IAAkB,QAAA;EAAA;EAiFvB,WAAA,CAAY,GAAA,EAAK,YAAA;IAAe,IAAA;EAAA,KAAmB,OAAA,CAAQ,QAAA;;;;;;;;;;EAwB3D,YAAA,CACJ,GAAA,EAAK,YAAA;IAAe,IAAA;EAAA,IACpB,OAAA,EAAS,oBAAA,GACR,OAAA;IAAU,IAAA,EAAM,QAAA;EAAA;EAgDb,aAAA,CAAc,GAAA,EAAK,YAAA;IAAe,IAAA;EAAA,KAAmB,OAAA;IAAU,OAAA;EAAA;EA0B/D,aAAA,CACJ,GAAA,EAAK,YAAA;IAAe,IAAA;EAAA,IACpB,OAAA,WACC,OAAA;IAAU,OAAA;EAAA;EAiCP,aAAA,CACJ,GAAA,EAAK,YAAA;IAAe,IAAA;EAAA,IACpB,KAAA,UACA,OAAA,GAAU,gBAAA,GACT,OAAA;IAAU,IAAA,EAAM,QAAA;IAAY,OAAA;EAAA;EAuDzB,WAAA,CAAY,GAAA,EAAK,YAAA;IAAe,IAAA;EAAA,KAAmB,OAAA,CAAQ,aAAA;EAmC3D,uBAAA,CAAwB,IAAA,EAAM,YAAA,GAAe,OAAA,CAAQ,QAAA;EA0BrD,cAAA,CAAe,GAAA,EAAK,YAAA;IAAe,IAAA;EAAA,KAAmB,OAAA,CAAQ,gBAAA;EAvZ9C;;;EAAA,QAmgBd,YAAA;EA/bD;;;EAAA,QA8cC,SAAA;EA7cG;;;;;;;EAAA,QAwdH,QAAA;EA/WF;;;;;;;EAAA,QA+aE,QAAA;EA5aW;;;;EAAA,QAseL,YAAA;EAtb6C;;;EAAA,QAid7C,UAAA;EAtbQ;;;EAAA,QA6cd,eAAA;EA3cK;;;EAAA,QAodL,cAAA;EAlbN;;;EAAA,QA0cM,cAAA;EAvcL;;;EAAA,QAigBK,iBAAA;EA1cF;;;EAAA,QAqfE,gBAAA;EArfiD;;;EAAA,QA8fjD,WAAA;EA3dsB;;;EAAA,QA0etB,eAAA;AAAA"}
|
package/dist/index.mjs
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { __decorate } from "./_virtual/_@oxc-project_runtime@0.108.0/helpers/decorate.mjs";
|
|
2
|
+
import { existsSync, mkdirSync, writeFileSync } from "node:fs";
|
|
2
3
|
import { readFile, stat, writeFile } from "node:fs/promises";
|
|
3
4
|
import { basename, dirname, extname, isAbsolute, join } from "node:path";
|
|
4
5
|
import { AFSNotFoundError } from "@aigne/afs";
|
|
5
|
-
import { AFSBaseProvider, Delete, List, Meta, Read, Rename, Search, Stat, Write } from "@aigne/afs/provider";
|
|
6
|
+
import { AFSBaseProvider, Delete, Explain, List, Meta, Read, Rename, Search, Stat, Write } from "@aigne/afs/provider";
|
|
6
7
|
import { camelize, optionalize, zodParse } from "@aigne/afs/utils/zod";
|
|
7
8
|
import { joinURL } from "ufo";
|
|
8
9
|
import { parse, stringify } from "yaml";
|
|
@@ -33,10 +34,24 @@ var AFSJSON = class AFSJSON extends AFSBaseProvider {
|
|
|
33
34
|
static schema() {
|
|
34
35
|
return afsJSONOptionsSchema;
|
|
35
36
|
}
|
|
36
|
-
static
|
|
37
|
+
static manifest() {
|
|
38
|
+
return {
|
|
39
|
+
name: "json",
|
|
40
|
+
description: "Mount a JSON or YAML file as a virtual filesystem",
|
|
41
|
+
uriTemplate: "json://{localPath+}",
|
|
42
|
+
category: "structured-data",
|
|
43
|
+
schema: z.object({ localPath: z.string() }),
|
|
44
|
+
tags: [
|
|
45
|
+
"json",
|
|
46
|
+
"yaml",
|
|
47
|
+
"structured-data"
|
|
48
|
+
]
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
static async load({ basePath, config } = {}) {
|
|
37
52
|
return new AFSJSON({
|
|
38
|
-
...await AFSJSON.schema().parseAsync(
|
|
39
|
-
cwd:
|
|
53
|
+
...await AFSJSON.schema().parseAsync(config),
|
|
54
|
+
cwd: basePath
|
|
40
55
|
});
|
|
41
56
|
}
|
|
42
57
|
name;
|
|
@@ -50,11 +65,16 @@ var AFSJSON = class AFSJSON extends AFSBaseProvider {
|
|
|
50
65
|
constructor(options) {
|
|
51
66
|
super();
|
|
52
67
|
this.options = options;
|
|
68
|
+
if (options.localPath && !options.jsonPath) options.jsonPath = options.localPath;
|
|
53
69
|
zodParse(afsJSONOptionsSchema, options);
|
|
54
70
|
let jsonPath;
|
|
55
71
|
jsonPath = options.jsonPath.replaceAll("${CWD}", process.cwd());
|
|
56
72
|
if (jsonPath.startsWith("~/")) jsonPath = join(process.env.HOME || "", jsonPath.slice(2));
|
|
57
73
|
if (!isAbsolute(jsonPath)) jsonPath = join(options.cwd || process.cwd(), jsonPath);
|
|
74
|
+
if (!existsSync(jsonPath)) {
|
|
75
|
+
mkdirSync(dirname(jsonPath), { recursive: true });
|
|
76
|
+
writeFileSync(jsonPath, "{}", "utf8");
|
|
77
|
+
}
|
|
58
78
|
const ext = extname(jsonPath).toLowerCase();
|
|
59
79
|
this.fileFormat = ext === ".yaml" || ext === ".yml" ? "yaml" : "json";
|
|
60
80
|
const extensions = [
|
|
@@ -76,7 +96,7 @@ var AFSJSON = class AFSJSON extends AFSBaseProvider {
|
|
|
76
96
|
/**
|
|
77
97
|
* Read metadata for a JSON node via /.meta or /path/.meta
|
|
78
98
|
* Returns stored metadata merged with computed type information
|
|
79
|
-
* Note: Meta is read-only. To write metadata, use write() with payload.
|
|
99
|
+
* Note: Meta is read-only. To write metadata, use write() with payload.meta.
|
|
80
100
|
*/
|
|
81
101
|
async readMetaHandler(ctx) {
|
|
82
102
|
await this.ensureLoaded();
|
|
@@ -104,7 +124,7 @@ var AFSJSON = class AFSJSON extends AFSBaseProvider {
|
|
|
104
124
|
if (this.fileStats.birthtime) computedMeta.created = this.fileStats.birthtime;
|
|
105
125
|
if (this.fileStats.mtime) computedMeta.modified = this.fileStats.mtime;
|
|
106
126
|
return this.buildEntry(joinURL(nodePath, ".meta"), {
|
|
107
|
-
|
|
127
|
+
meta: storedMeta,
|
|
108
128
|
content: computedMeta,
|
|
109
129
|
createdAt: this.fileStats.birthtime,
|
|
110
130
|
updatedAt: this.fileStats.mtime
|
|
@@ -120,12 +140,15 @@ var AFSJSON = class AFSJSON extends AFSBaseProvider {
|
|
|
120
140
|
const segments = this.getPathSegments(normalizedPath);
|
|
121
141
|
const value = this.getValueAtPath(this.jsonData, segments);
|
|
122
142
|
if (value === void 0) throw new AFSNotFoundError(normalizedPath);
|
|
143
|
+
if (maxDepth === 0) return { data: [] };
|
|
144
|
+
if (!this.isDirectoryValue(value)) return { data: [] };
|
|
123
145
|
const entries = [];
|
|
124
|
-
const
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
146
|
+
const rootChildren = this.getChildren(value);
|
|
147
|
+
const queue = (rootChildren.length > maxChildren ? rootChildren.slice(0, maxChildren) : rootChildren).map((child) => ({
|
|
148
|
+
path: normalizedPath === "/" ? `/${child.key}` : `${normalizedPath}/${child.key}`,
|
|
149
|
+
value: child.value,
|
|
150
|
+
depth: 1
|
|
151
|
+
}));
|
|
129
152
|
while (queue.length > 0) {
|
|
130
153
|
const item = queue.shift();
|
|
131
154
|
if (!item) break;
|
|
@@ -170,10 +193,10 @@ var AFSJSON = class AFSJSON extends AFSBaseProvider {
|
|
|
170
193
|
const normalizedPath = ctx.params.path ? `/${ctx.params.path}` : "/";
|
|
171
194
|
const segments = this.getPathSegments(normalizedPath);
|
|
172
195
|
if (payload.content !== void 0) this.setValueAtPath(this.jsonData, segments, payload.content);
|
|
173
|
-
if (payload.
|
|
196
|
+
if (payload.meta !== void 0 && typeof payload.meta === "object") {
|
|
174
197
|
const finalMeta = {
|
|
175
198
|
...this.loadMeta(normalizedPath) || {},
|
|
176
|
-
...payload.
|
|
199
|
+
...payload.meta
|
|
177
200
|
};
|
|
178
201
|
this.saveMeta(normalizedPath, finalMeta);
|
|
179
202
|
}
|
|
@@ -189,7 +212,7 @@ var AFSJSON = class AFSJSON extends AFSBaseProvider {
|
|
|
189
212
|
summary: payload.summary,
|
|
190
213
|
createdAt: this.fileStats.birthtime,
|
|
191
214
|
updatedAt: this.fileStats.mtime,
|
|
192
|
-
|
|
215
|
+
meta: {
|
|
193
216
|
...storedMeta,
|
|
194
217
|
childrenCount: isDir ? children.length : void 0
|
|
195
218
|
},
|
|
@@ -265,15 +288,136 @@ var AFSJSON = class AFSJSON extends AFSBaseProvider {
|
|
|
265
288
|
if (value === void 0) throw new AFSNotFoundError(normalizedPath);
|
|
266
289
|
const isDir = this.isDirectoryValue(value);
|
|
267
290
|
const children = isDir ? this.getChildren(value) : [];
|
|
268
|
-
const meta = this.loadMeta(normalizedPath);
|
|
291
|
+
const meta = { ...this.loadMeta(normalizedPath) };
|
|
292
|
+
if (isDir) meta.childrenCount = children.length;
|
|
269
293
|
return { data: {
|
|
294
|
+
id: segments.length > 0 ? segments[segments.length - 1] : "/",
|
|
270
295
|
path: normalizedPath,
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
meta: meta ?? void 0
|
|
296
|
+
createdAt: this.fileStats.birthtime,
|
|
297
|
+
updatedAt: this.fileStats.mtime,
|
|
298
|
+
meta
|
|
275
299
|
} };
|
|
276
300
|
}
|
|
301
|
+
async readCapabilitiesHandler(_ctx) {
|
|
302
|
+
await this.ensureLoaded();
|
|
303
|
+
const operations = [
|
|
304
|
+
"list",
|
|
305
|
+
"read",
|
|
306
|
+
"stat",
|
|
307
|
+
"explain",
|
|
308
|
+
"search"
|
|
309
|
+
];
|
|
310
|
+
if (this.accessMode === "readwrite") operations.push("write", "delete", "rename");
|
|
311
|
+
return {
|
|
312
|
+
id: "/.meta/.capabilities",
|
|
313
|
+
path: "/.meta/.capabilities",
|
|
314
|
+
content: {
|
|
315
|
+
schemaVersion: 1,
|
|
316
|
+
provider: this.name,
|
|
317
|
+
description: this.description || `JSON/YAML virtual filesystem (${this.fileFormat} format)`,
|
|
318
|
+
tools: [],
|
|
319
|
+
actions: [],
|
|
320
|
+
operations: this.getOperationsDeclaration()
|
|
321
|
+
},
|
|
322
|
+
meta: {
|
|
323
|
+
kind: "afs:capabilities",
|
|
324
|
+
operations
|
|
325
|
+
}
|
|
326
|
+
};
|
|
327
|
+
}
|
|
328
|
+
async explainHandler(ctx) {
|
|
329
|
+
await this.ensureLoaded();
|
|
330
|
+
const normalizedPath = joinURL("/", ctx.params.path ?? "");
|
|
331
|
+
const format = ctx.options?.format || "markdown";
|
|
332
|
+
const segments = this.getPathSegments(normalizedPath);
|
|
333
|
+
const value = this.getValueAtPath(this.jsonData, segments);
|
|
334
|
+
if (value === void 0) throw new AFSNotFoundError(normalizedPath);
|
|
335
|
+
const nodeName = segments.length > 0 ? segments[segments.length - 1] : "/";
|
|
336
|
+
const isDir = this.isDirectoryValue(value);
|
|
337
|
+
const storedMeta = this.loadMeta(normalizedPath);
|
|
338
|
+
const lines = [];
|
|
339
|
+
if (format === "markdown") {
|
|
340
|
+
lines.push(`# ${nodeName}`);
|
|
341
|
+
lines.push("");
|
|
342
|
+
lines.push(`**Path:** \`${normalizedPath}\``);
|
|
343
|
+
lines.push(`**Format:** ${this.fileFormat.toUpperCase()}`);
|
|
344
|
+
if (normalizedPath === "/") {
|
|
345
|
+
const topType = Array.isArray(this.jsonData) ? "array" : "object";
|
|
346
|
+
const children = this.getChildren(this.jsonData);
|
|
347
|
+
lines.push(`**Structure:** ${topType}`);
|
|
348
|
+
lines.push(`**Top-level keys:** ${children.length}`);
|
|
349
|
+
if (children.length > 0) {
|
|
350
|
+
lines.push("");
|
|
351
|
+
lines.push("## Keys");
|
|
352
|
+
lines.push("");
|
|
353
|
+
for (const child of children.slice(0, 30)) {
|
|
354
|
+
const childVal = child.value;
|
|
355
|
+
const childType = this.describeType(childVal);
|
|
356
|
+
lines.push(`- \`${child.key}\` — ${childType}`);
|
|
357
|
+
}
|
|
358
|
+
if (children.length > 30) lines.push(`- ... and ${children.length - 30} more`);
|
|
359
|
+
}
|
|
360
|
+
} else if (Array.isArray(value)) {
|
|
361
|
+
lines.push(`**Type:** array`);
|
|
362
|
+
lines.push(`**Elements:** ${value.length}`);
|
|
363
|
+
if (value.length > 0) {
|
|
364
|
+
const elementType = this.describeType(value[0]);
|
|
365
|
+
const isHomogeneous = value.every((v) => this.describeType(v) === elementType);
|
|
366
|
+
lines.push(`**Element type:** ${isHomogeneous ? elementType : "mixed"}`);
|
|
367
|
+
}
|
|
368
|
+
} else if (typeof value === "object" && value !== null) {
|
|
369
|
+
const children = this.getChildren(value);
|
|
370
|
+
lines.push(`**Type:** object`);
|
|
371
|
+
lines.push(`**Keys:** ${children.length}`);
|
|
372
|
+
if (children.length > 0) {
|
|
373
|
+
lines.push("");
|
|
374
|
+
lines.push("## Keys");
|
|
375
|
+
lines.push("");
|
|
376
|
+
for (const child of children.slice(0, 30)) {
|
|
377
|
+
const childType = this.describeType(child.value);
|
|
378
|
+
lines.push(`- \`${child.key}\` — ${childType}`);
|
|
379
|
+
}
|
|
380
|
+
if (children.length > 30) lines.push(`- ... and ${children.length - 30} more`);
|
|
381
|
+
}
|
|
382
|
+
} else {
|
|
383
|
+
const valType = value === null ? "null" : typeof value;
|
|
384
|
+
lines.push(`**Type:** ${valType}`);
|
|
385
|
+
const valStr = String(value);
|
|
386
|
+
if (valStr.length > 200) lines.push(`**Value:** ${valStr.slice(0, 200)}...`);
|
|
387
|
+
else lines.push(`**Value:** ${valStr}`);
|
|
388
|
+
}
|
|
389
|
+
if (storedMeta) {
|
|
390
|
+
lines.push("");
|
|
391
|
+
lines.push("## Metadata");
|
|
392
|
+
for (const [key, val] of Object.entries(storedMeta)) lines.push(`- **${key}:** ${JSON.stringify(val)}`);
|
|
393
|
+
}
|
|
394
|
+
} else {
|
|
395
|
+
lines.push(`${nodeName} (${isDir ? "directory" : "value"})`);
|
|
396
|
+
lines.push(`Path: ${normalizedPath}`);
|
|
397
|
+
lines.push(`Format: ${this.fileFormat}`);
|
|
398
|
+
if (isDir) {
|
|
399
|
+
const children = this.getChildren(value);
|
|
400
|
+
lines.push(`Children: ${children.length}`);
|
|
401
|
+
} else {
|
|
402
|
+
const valStr = String(value);
|
|
403
|
+
lines.push(`Type: ${value === null ? "null" : typeof value}`);
|
|
404
|
+
lines.push(`Value: ${valStr.length > 200 ? `${valStr.slice(0, 200)}...` : valStr}`);
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
return {
|
|
408
|
+
content: lines.join("\n"),
|
|
409
|
+
format
|
|
410
|
+
};
|
|
411
|
+
}
|
|
412
|
+
/**
|
|
413
|
+
* Get a human-readable type description for a JSON value.
|
|
414
|
+
*/
|
|
415
|
+
describeType(value) {
|
|
416
|
+
if (value === null) return "null";
|
|
417
|
+
if (Array.isArray(value)) return `array[${value.length}]`;
|
|
418
|
+
if (typeof value === "object") return `object{${Object.keys(value).filter((k) => !this.isMetaKey(k)).length} keys}`;
|
|
419
|
+
return typeof value;
|
|
420
|
+
}
|
|
277
421
|
/**
|
|
278
422
|
* Check if a key is a hidden meta key that should be filtered from listings
|
|
279
423
|
*/
|
|
@@ -484,9 +628,13 @@ var AFSJSON = class AFSJSON extends AFSBaseProvider {
|
|
|
484
628
|
valueToAFSEntry(path, value) {
|
|
485
629
|
const isDir = this.isDirectoryValue(value);
|
|
486
630
|
const children = isDir ? this.getChildren(value) : [];
|
|
631
|
+
const kind = Array.isArray(value) ? "json:array" : isDir ? "json:object" : "json:value";
|
|
487
632
|
return this.buildEntry(path, {
|
|
488
633
|
content: isDir ? void 0 : value,
|
|
489
|
-
|
|
634
|
+
meta: {
|
|
635
|
+
kind,
|
|
636
|
+
childrenCount: isDir ? children.length : void 0
|
|
637
|
+
},
|
|
490
638
|
createdAt: this.fileStats.birthtime,
|
|
491
639
|
updatedAt: this.fileStats.mtime
|
|
492
640
|
});
|
|
@@ -500,7 +648,10 @@ __decorate([Delete("/:path*")], AFSJSON.prototype, "deleteHandler", null);
|
|
|
500
648
|
__decorate([Rename("/:path*")], AFSJSON.prototype, "renameHandler", null);
|
|
501
649
|
__decorate([Search("/:path*")], AFSJSON.prototype, "searchHandler", null);
|
|
502
650
|
__decorate([Stat("/:path*")], AFSJSON.prototype, "statHandler", null);
|
|
651
|
+
__decorate([Read("/.meta/.capabilities")], AFSJSON.prototype, "readCapabilitiesHandler", null);
|
|
652
|
+
__decorate([Explain("/:path*")], AFSJSON.prototype, "explainHandler", null);
|
|
653
|
+
var src_default = AFSJSON;
|
|
503
654
|
|
|
504
655
|
//#endregion
|
|
505
|
-
export { AFSJSON };
|
|
656
|
+
export { AFSJSON, src_default as default };
|
|
506
657
|
//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":["afs","meta","parseYAML","stringifyYAML"],"sources":["../src/index.ts"],"sourcesContent":["import { readFile, stat, writeFile } from \"node:fs/promises\";\nimport { basename, dirname, extname, isAbsolute, join } from \"node:path\";\nimport {\n type AFSAccessMode,\n type AFSDeleteOptions,\n type AFSEntry,\n type AFSEntryMetadata,\n type AFSListResult,\n type AFSModuleClass,\n type AFSModuleLoadParams,\n AFSNotFoundError,\n type AFSRenameOptions,\n type AFSSearchOptions,\n type AFSStatResult,\n type AFSWriteEntryPayload,\n} from \"@aigne/afs\";\nimport {\n AFSBaseProvider,\n Delete,\n List,\n Meta,\n Read,\n Rename,\n type RouteContext,\n Search,\n Stat,\n Write,\n} from \"@aigne/afs/provider\";\nimport { camelize, optionalize, zodParse } from \"@aigne/afs/utils/zod\";\nimport { joinURL } from \"ufo\";\nimport { parse as parseYAML, stringify as stringifyYAML } from \"yaml\";\nimport { z } from \"zod\";\n\nconst LIST_MAX_LIMIT = 1000;\n\n/** Hidden key for storing AFS metadata (mirrors FS provider's .afs directory) */\nconst AFS_KEY = \".afs\";\n\n/** Subkey for storing metadata (mirrors FS provider's meta.yaml file) */\nconst META_KEY = \"meta\";\n\n/** Subkey for storing child node metadata (mirrors FS provider's .nodes directory) */\nconst NODES_KEY = \".nodes\";\n\nexport interface AFSJSONOptions {\n name?: string;\n jsonPath: string;\n description?: string;\n /**\n * Access mode for this module.\n * - \"readonly\": Only read operations are allowed\n * - \"readwrite\": All operations are allowed (default, unless agentSkills is enabled)\n * @default \"readwrite\" (or \"readonly\" when agentSkills is true)\n */\n accessMode?: AFSAccessMode;\n /**\n * Enable automatic agent skill scanning for this module.\n * When enabled, defaults accessMode to \"readonly\" if not explicitly set.\n * @default false\n */\n agentSkills?: boolean;\n}\n\nconst afsJSONOptionsSchema = camelize(\n z.object({\n name: optionalize(z.string()),\n jsonPath: z.string().describe(\"The path to the JSON/YAML file to mount\"),\n description: optionalize(z.string().describe(\"A description of the JSON module\")),\n accessMode: optionalize(\n z.enum([\"readonly\", \"readwrite\"]).describe(\"Access mode for this module\"),\n ),\n agentSkills: optionalize(\n z.boolean().describe(\"Enable automatic agent skill scanning for this module\"),\n ),\n }),\n);\n\n/**\n * AFS module for mounting JSON/YAML files as virtual file systems.\n *\n * JSON/YAML objects are treated as directories, and properties/array items as files.\n * Supports nested structures and path-based access to data values.\n */\nexport class AFSJSON extends AFSBaseProvider {\n static schema() {\n return afsJSONOptionsSchema;\n }\n\n static async load({ filepath, parsed }: AFSModuleLoadParams) {\n const valid = await AFSJSON.schema().parseAsync(parsed);\n return new AFSJSON({ ...valid, cwd: dirname(filepath) });\n }\n\n readonly name: string;\n readonly description?: string;\n readonly accessMode: AFSAccessMode;\n readonly agentSkills?: boolean;\n\n private jsonData: any = null;\n private fileStats: {\n birthtime?: Date;\n mtime?: Date;\n } = {};\n private fileFormat: \"json\" | \"yaml\" = \"json\";\n private resolvedJsonPath: string;\n\n constructor(public options: AFSJSONOptions & { cwd?: string }) {\n super();\n zodParse(afsJSONOptionsSchema, options);\n\n let jsonPath: string;\n\n jsonPath = options.jsonPath.replaceAll(\"${CWD}\", process.cwd());\n if (jsonPath.startsWith(\"~/\")) {\n jsonPath = join(process.env.HOME || \"\", jsonPath.slice(2));\n }\n if (!isAbsolute(jsonPath)) {\n jsonPath = join(options.cwd || process.cwd(), jsonPath);\n }\n\n // Detect file format based on extension for writing\n const ext = extname(jsonPath).toLowerCase();\n this.fileFormat = ext === \".yaml\" || ext === \".yml\" ? \"yaml\" : \"json\";\n\n // Extract name without extension\n const extensions = [\".json\", \".yaml\", \".yml\"];\n let name = basename(jsonPath);\n for (const e of extensions) {\n if (name.endsWith(e)) {\n name = name.slice(0, -e.length);\n break;\n }\n }\n\n this.name = options.name || name || \"json\";\n this.description = options.description;\n this.agentSkills = options.agentSkills;\n // Default to \"readwrite\", but \"readonly\" if agentSkills is enabled\n this.accessMode = options.accessMode ?? (options.agentSkills ? \"readonly\" : \"readwrite\");\n this.resolvedJsonPath = jsonPath;\n }\n\n // ========== Meta Handlers ==========\n // Meta is read-only introspection. Metadata writes are handled by @Write via payload.metadata.\n //\n // Meta storage strategy (mirrors FS provider's .afs directory):\n // - For objects (directories): metadata stored in `.afs.meta` key within the object\n // - For primitives (files): metadata stored in parent's `.afs[\".nodes\"][key].meta` structure\n //\n // Example JSON structure:\n // {\n // \"database\": {\n // \"host\": \"localhost\",\n // \".afs\": {\n // \"meta\": { \"description\": \"Database config\" }, // object's own meta\n // \".nodes\": {\n // \"host\": { \"meta\": { \"description\": \"DB hostname\" } } // primitive's meta\n // }\n // }\n // }\n // }\n\n /**\n * Read metadata for a JSON node via /.meta or /path/.meta\n * Returns stored metadata merged with computed type information\n * Note: Meta is read-only. To write metadata, use write() with payload.metadata.\n */\n @Meta(\"/:path*\")\n async readMetaHandler(ctx: RouteContext<{ path?: string }>): Promise<AFSEntry | undefined> {\n await this.ensureLoaded();\n\n const nodePath = joinURL(\"/\", ctx.params.path ?? \"\");\n const segments = this.getPathSegments(nodePath);\n const value = this.getValueAtPath(this.jsonData, segments);\n\n if (value === undefined) {\n throw new AFSNotFoundError(nodePath);\n }\n\n const isDir = this.isDirectoryValue(value);\n const children = isDir ? this.getChildren(value) : [];\n\n // Determine the JSON type\n let type: string;\n if (Array.isArray(value)) {\n type = \"array\";\n } else if (value === null) {\n type = \"null\";\n } else if (typeof value === \"object\") {\n type = \"object\";\n } else {\n type = typeof value;\n }\n\n // Load stored user-defined metadata\n const storedMeta = this.loadMeta(nodePath) || {};\n\n // Build computed metadata (type info, etc.)\n const computedMeta: Record<string, unknown> = {\n type,\n path: nodePath,\n };\n\n if (isDir) {\n computedMeta.childrenCount = children.length;\n if (Array.isArray(value)) {\n computedMeta.length = value.length;\n } else {\n // Filter out internal keys from keys list\n computedMeta.keys = Object.keys(value).filter((k) => !this.isMetaKey(k));\n }\n } else {\n computedMeta.value = value;\n }\n\n if (this.fileStats.birthtime) {\n computedMeta.created = this.fileStats.birthtime;\n }\n if (this.fileStats.mtime) {\n computedMeta.modified = this.fileStats.mtime;\n }\n\n return this.buildEntry(joinURL(nodePath, \".meta\"), {\n // User-defined metadata goes in metadata field (for conformance)\n metadata: storedMeta as AFSEntryMetadata,\n // Computed type info goes in content (JSON-specific)\n content: computedMeta,\n createdAt: this.fileStats.birthtime,\n updatedAt: this.fileStats.mtime,\n });\n }\n\n // ========== Route Handlers ==========\n\n @List(\"/:path*\", { handleDepth: true })\n async listHandler(\n ctx: RouteContext<{ path?: string }>,\n ): Promise<AFSListResult & { noExpand?: string[] }> {\n await this.ensureLoaded();\n\n const normalizedPath = ctx.params.path ? `/${ctx.params.path}` : \"/\";\n const options = ctx.options as { limit?: number; maxChildren?: number; maxDepth?: number };\n const limit = Math.min(options?.limit || LIST_MAX_LIMIT, LIST_MAX_LIMIT);\n const maxChildren =\n typeof options?.maxChildren === \"number\" ? options.maxChildren : Number.MAX_SAFE_INTEGER;\n const maxDepth = options?.maxDepth ?? 1;\n\n const segments = this.getPathSegments(normalizedPath);\n const value = this.getValueAtPath(this.jsonData, segments);\n\n if (value === undefined) {\n throw new AFSNotFoundError(normalizedPath);\n }\n\n const entries: AFSEntry[] = [];\n\n interface QueueItem {\n path: string;\n value: any;\n depth: number;\n }\n\n const queue: QueueItem[] = [{ path: normalizedPath, value, depth: 0 }];\n\n while (queue.length > 0) {\n const item = queue.shift();\n if (!item) break;\n\n const { path: itemPath, value: itemValue, depth } = item;\n\n const entry = this.valueToAFSEntry(itemPath, itemValue);\n entries.push(entry);\n\n if (entries.length >= limit) {\n break;\n }\n\n // Process children if within depth limit\n if (this.isDirectoryValue(itemValue) && depth < maxDepth) {\n const children = this.getChildren(itemValue);\n const childrenToProcess =\n children.length > maxChildren ? children.slice(0, maxChildren) : children;\n\n for (const child of childrenToProcess) {\n const childPath = itemPath === \"/\" ? `/${child.key}` : `${itemPath}/${child.key}`;\n queue.push({\n path: childPath,\n value: child.value,\n depth: depth + 1,\n });\n }\n }\n }\n\n return { data: entries };\n }\n\n @Read(\"/:path*\")\n async readHandler(ctx: RouteContext<{ path?: string }>): Promise<AFSEntry | undefined> {\n await this.ensureLoaded();\n\n const normalizedPath = ctx.params.path ? `/${ctx.params.path}` : \"/\";\n const segments = this.getPathSegments(normalizedPath);\n const value = this.getValueAtPath(this.jsonData, segments);\n\n if (value === undefined) {\n throw new AFSNotFoundError(normalizedPath);\n }\n\n return this.valueToAFSEntry(normalizedPath, value);\n }\n\n /**\n * Write handler - supports writing content and/or metadata\n *\n * | payload | behavior |\n * |---------|----------|\n * | { content } | write content only |\n * | { metadata } | write metadata only (to .afs storage) |\n * | { content, metadata } | write both |\n */\n @Write(\"/:path*\")\n async writeHandler(\n ctx: RouteContext<{ path?: string }>,\n payload: AFSWriteEntryPayload,\n ): Promise<{ data: AFSEntry }> {\n await this.ensureLoaded();\n\n const normalizedPath = ctx.params.path ? `/${ctx.params.path}` : \"/\";\n const segments = this.getPathSegments(normalizedPath);\n\n // Write content if provided\n if (payload.content !== undefined) {\n this.setValueAtPath(this.jsonData, segments, payload.content);\n }\n\n // Write metadata if provided (merge with existing)\n if (payload.metadata !== undefined && typeof payload.metadata === \"object\") {\n const existingMeta = this.loadMeta(normalizedPath) || {};\n const finalMeta = { ...existingMeta, ...payload.metadata };\n this.saveMeta(normalizedPath, finalMeta);\n }\n\n // Save back to file\n await this.saveToFile();\n\n const newValue = this.getValueAtPath(this.jsonData, segments);\n const isDir = this.isDirectoryValue(newValue);\n const children = isDir ? this.getChildren(newValue) : [];\n\n // Load stored metadata for response\n const storedMeta = this.loadMeta(normalizedPath) || {};\n\n const writtenEntry: AFSEntry = {\n id: normalizedPath,\n path: normalizedPath,\n content: payload.content !== undefined ? payload.content : newValue,\n summary: payload.summary,\n createdAt: this.fileStats.birthtime,\n updatedAt: this.fileStats.mtime,\n metadata: {\n ...storedMeta,\n childrenCount: isDir ? children.length : undefined,\n } as AFSEntryMetadata,\n userId: payload.userId,\n sessionId: payload.sessionId,\n linkTo: payload.linkTo,\n };\n\n return { data: writtenEntry };\n }\n\n @Delete(\"/:path*\")\n async deleteHandler(ctx: RouteContext<{ path?: string }>): Promise<{ message: string }> {\n await this.ensureLoaded();\n\n const normalizedPath = ctx.params.path ? `/${ctx.params.path}` : \"/\";\n const options = ctx.options as AFSDeleteOptions | undefined;\n const segments = this.getPathSegments(normalizedPath);\n const value = this.getValueAtPath(this.jsonData, segments);\n\n if (value === undefined) {\n throw new AFSNotFoundError(normalizedPath);\n }\n\n const hasChildren = this.isDirectoryValue(value) && this.getChildren(value).length > 0;\n if (hasChildren && !options?.recursive) {\n throw new Error(\n `Cannot delete directory '${normalizedPath}' without recursive option. Set recursive: true to delete directories.`,\n );\n }\n\n this.deleteValueAtPath(this.jsonData, segments);\n await this.saveToFile();\n\n return { message: `Successfully deleted: ${normalizedPath}` };\n }\n\n @Rename(\"/:path*\")\n async renameHandler(\n ctx: RouteContext<{ path?: string }>,\n newPath: string,\n ): Promise<{ message: string }> {\n await this.ensureLoaded();\n\n const normalizedOldPath = ctx.params.path ? `/${ctx.params.path}` : \"/\";\n const normalizedNewPath = this.normalizePath(newPath);\n const options = ctx.options as AFSRenameOptions | undefined;\n\n const oldSegments = this.getPathSegments(normalizedOldPath);\n const newSegments = this.getPathSegments(normalizedNewPath);\n\n const oldValue = this.getValueAtPath(this.jsonData, oldSegments);\n if (oldValue === undefined) {\n throw new AFSNotFoundError(normalizedOldPath);\n }\n\n const existingNewValue = this.getValueAtPath(this.jsonData, newSegments);\n if (existingNewValue !== undefined && !options?.overwrite) {\n throw new Error(\n `Destination '${normalizedNewPath}' already exists. Set overwrite: true to replace it.`,\n );\n }\n\n // Copy to new location and delete old\n this.setValueAtPath(this.jsonData, newSegments, oldValue);\n this.deleteValueAtPath(this.jsonData, oldSegments);\n await this.saveToFile();\n\n return {\n message: `Successfully renamed '${normalizedOldPath}' to '${normalizedNewPath}'`,\n };\n }\n\n @Search(\"/:path*\")\n async searchHandler(\n ctx: RouteContext<{ path?: string }>,\n query: string,\n options?: AFSSearchOptions,\n ): Promise<{ data: AFSEntry[]; message?: string }> {\n await this.ensureLoaded();\n\n const normalizedPath = ctx.params.path ? `/${ctx.params.path}` : \"/\";\n const limit = Math.min(options?.limit || LIST_MAX_LIMIT, LIST_MAX_LIMIT);\n const caseSensitive = options?.caseSensitive ?? false;\n\n const segments = this.getPathSegments(normalizedPath);\n const rootValue = this.getValueAtPath(this.jsonData, segments);\n\n if (rootValue === undefined) {\n throw new AFSNotFoundError(normalizedPath);\n }\n\n const entries: AFSEntry[] = [];\n const searchQuery = caseSensitive ? query : query.toLowerCase();\n\n const searchInValue = (valuePath: string, value: any): void => {\n if (entries.length >= limit) return;\n\n let matched = false;\n\n // Search in the value itself\n if (!this.isDirectoryValue(value)) {\n const valueStr = typeof value === \"string\" ? value : JSON.stringify(value);\n const searchValue = caseSensitive ? valueStr : valueStr.toLowerCase();\n if (searchValue.includes(searchQuery)) {\n matched = true;\n }\n }\n\n if (matched) {\n entries.push(this.valueToAFSEntry(valuePath, value));\n }\n\n // Recursively search children\n if (this.isDirectoryValue(value)) {\n const children = this.getChildren(value);\n for (const child of children) {\n if (entries.length >= limit) break;\n const childPath = valuePath === \"/\" ? `/${child.key}` : `${valuePath}/${child.key}`;\n searchInValue(childPath, child.value);\n }\n }\n };\n\n searchInValue(normalizedPath, rootValue);\n\n return {\n data: entries,\n message: entries.length >= limit ? `Results truncated to limit ${limit}` : undefined,\n };\n }\n\n @Stat(\"/:path*\")\n async statHandler(ctx: RouteContext<{ path?: string }>): Promise<AFSStatResult> {\n await this.ensureLoaded();\n\n const normalizedPath = ctx.params.path ? `/${ctx.params.path}` : \"/\";\n const segments = this.getPathSegments(normalizedPath);\n const value = this.getValueAtPath(this.jsonData, segments);\n\n if (value === undefined) {\n throw new AFSNotFoundError(normalizedPath);\n }\n\n const isDir = this.isDirectoryValue(value);\n const children = isDir ? this.getChildren(value) : [];\n const meta = this.loadMeta(normalizedPath);\n\n return {\n data: {\n path: normalizedPath,\n childrenCount: isDir ? children.length : undefined,\n created: this.fileStats.birthtime,\n modified: this.fileStats.mtime,\n meta: meta ?? undefined,\n },\n };\n }\n\n // ========== Private Helper Methods ==========\n\n /**\n * Check if a key is a hidden meta key that should be filtered from listings\n */\n private isMetaKey(key: string): boolean {\n return key === AFS_KEY;\n }\n\n /**\n * Load metadata for a node.\n *\n * Storage location depends on node type (mirrors FS provider's .afs structure):\n * - Objects: `.afs.meta` key within the object itself\n * - Primitives: parent's `.afs[\".nodes\"][key].meta`\n */\n private loadMeta(nodePath: string): Record<string, unknown> | null {\n const segments = this.getPathSegments(nodePath);\n const value = this.getValueAtPath(this.jsonData, segments);\n\n if (value === undefined) {\n return null;\n }\n\n if (this.isDirectoryValue(value) && !Array.isArray(value)) {\n // Object: meta is in value[\".afs\"].meta\n const afs = value[AFS_KEY];\n if (afs && typeof afs === \"object\" && !Array.isArray(afs)) {\n const meta = afs[META_KEY];\n if (meta && typeof meta === \"object\" && !Array.isArray(meta)) {\n return meta as Record<string, unknown>;\n }\n }\n return null;\n }\n\n // Primitive or array: meta is in parent's .afs[\".nodes\"][key].meta\n if (segments.length === 0) {\n // Root is always an object, handled above\n return null;\n }\n\n const parentSegments = segments.slice(0, -1);\n const nodeKey = segments[segments.length - 1]!;\n const parentValue = this.getValueAtPath(this.jsonData, parentSegments);\n\n if (!parentValue || Array.isArray(parentValue) || typeof parentValue !== \"object\") {\n return null;\n }\n\n const afs = parentValue[AFS_KEY];\n if (!afs || typeof afs !== \"object\" || Array.isArray(afs)) {\n return null;\n }\n\n const nodes = afs[NODES_KEY];\n if (!nodes || typeof nodes !== \"object\" || Array.isArray(nodes)) {\n return null;\n }\n\n const nodeEntry = nodes[nodeKey];\n if (!nodeEntry || typeof nodeEntry !== \"object\" || Array.isArray(nodeEntry)) {\n return null;\n }\n\n const meta = nodeEntry[META_KEY];\n if (!meta || typeof meta !== \"object\" || Array.isArray(meta)) {\n return null;\n }\n\n return meta as Record<string, unknown>;\n }\n\n /**\n * Save metadata for a node.\n *\n * Storage location depends on node type (mirrors FS provider's .afs structure):\n * - Objects: `.afs.meta` key within the object itself\n * - Primitives: parent's `.afs[\".nodes\"][key].meta`\n */\n private saveMeta(nodePath: string, meta: Record<string, unknown>): void {\n const segments = this.getPathSegments(nodePath);\n const value = this.getValueAtPath(this.jsonData, segments);\n\n if (value === undefined) {\n throw new AFSNotFoundError(nodePath);\n }\n\n if (this.isDirectoryValue(value) && !Array.isArray(value)) {\n // Object: store in value[\".afs\"].meta\n if (!value[AFS_KEY]) {\n value[AFS_KEY] = {};\n }\n // Store in .meta key\n value[AFS_KEY][META_KEY] = meta;\n return;\n }\n\n // Primitive or array: store in parent's .afs[\".nodes\"][key].meta\n if (segments.length === 0) {\n throw new Error(\"Cannot save meta for root when root is not an object\");\n }\n\n const parentSegments = segments.slice(0, -1);\n const nodeKey = segments[segments.length - 1]!;\n const parentValue = this.getValueAtPath(this.jsonData, parentSegments);\n\n if (!parentValue || typeof parentValue !== \"object\") {\n throw new Error(`Parent path is not an object`);\n }\n\n if (Array.isArray(parentValue)) {\n throw new Error(`Cannot save meta for array elements`);\n }\n\n // Ensure .afs exists\n if (!parentValue[AFS_KEY]) {\n parentValue[AFS_KEY] = {};\n }\n\n // Ensure .afs[\".nodes\"] exists\n if (!parentValue[AFS_KEY][NODES_KEY]) {\n parentValue[AFS_KEY][NODES_KEY] = {};\n }\n\n // Ensure .afs[\".nodes\"][nodeKey] exists\n if (!parentValue[AFS_KEY][NODES_KEY][nodeKey]) {\n parentValue[AFS_KEY][NODES_KEY][nodeKey] = {};\n }\n\n // Store the meta in .meta key\n parentValue[AFS_KEY][NODES_KEY][nodeKey][META_KEY] = meta;\n }\n\n /**\n * Load JSON/YAML data from file. Called lazily on first access.\n * Uses YAML parser which can handle both JSON and YAML formats.\n */\n private async ensureLoaded(): Promise<void> {\n if (this.jsonData !== null) return;\n\n try {\n const stats = await stat(this.resolvedJsonPath);\n this.fileStats = {\n birthtime: stats.birthtime,\n mtime: stats.mtime,\n };\n\n const content = await readFile(this.resolvedJsonPath, \"utf8\");\n\n // YAML parser can handle both JSON and YAML formats\n this.jsonData = parseYAML(content);\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") {\n // File doesn't exist yet, start with empty object\n this.jsonData = {};\n } else {\n throw error;\n }\n }\n }\n\n /**\n * Save JSON/YAML data back to file. Only called in readwrite mode.\n */\n private async saveToFile(): Promise<void> {\n let content: string;\n\n // Serialize based on file format\n if (this.fileFormat === \"yaml\") {\n content = stringifyYAML(this.jsonData);\n } else {\n content = JSON.stringify(this.jsonData, null, 2);\n }\n\n await writeFile(this.resolvedJsonPath, content, \"utf8\");\n\n // Update file stats\n const stats = await stat(this.resolvedJsonPath);\n this.fileStats = {\n birthtime: this.fileStats.birthtime || stats.birthtime,\n mtime: stats.mtime,\n };\n }\n\n /**\n * Get path segments from normalized path\n */\n private getPathSegments(path: string): string[] {\n const normalized = this.normalizePath(path);\n if (normalized === \"/\") return [];\n return normalized.slice(1).split(\"/\");\n }\n\n /**\n * Navigate to a value in the JSON structure using path segments\n */\n private getValueAtPath(data: any, segments: string[]): any {\n let current = data;\n for (const segment of segments) {\n if (current == null) return undefined;\n\n // Handle array indices\n if (Array.isArray(current)) {\n const index = Number.parseInt(segment, 10);\n if (Number.isNaN(index) || index < 0 || index >= current.length) {\n return undefined;\n }\n current = current[index];\n } else if (typeof current === \"object\") {\n current = current[segment as keyof typeof current];\n } else {\n return undefined;\n }\n }\n return current;\n }\n\n /**\n * Set a value in the JSON structure at the given path\n */\n private setValueAtPath(data: any, segments: string[], value: any): void {\n if (segments.length === 0) {\n throw new Error(\"Cannot set value at root path\");\n }\n\n let current = data;\n for (let i = 0; i < segments.length - 1; i++) {\n const segment = segments[i]!;\n const nextSegment = segments[i + 1]!;\n\n if (Array.isArray(current)) {\n const index = Number.parseInt(segment, 10);\n if (Number.isNaN(index) || index < 0) {\n throw new Error(`Invalid array index: ${segment}`);\n }\n\n // Extend array if necessary\n while (current.length <= index) {\n current.push(null);\n }\n\n if (current[index] == null) {\n // Determine if next level should be array or object\n const isNextArray = !Number.isNaN(Number.parseInt(nextSegment, 10));\n current[index] = isNextArray ? [] : {};\n }\n current = current[index];\n } else if (typeof current === \"object\") {\n if (current[segment] == null) {\n // Determine if next level should be array or object\n const isNextArray = !Number.isNaN(Number.parseInt(nextSegment, 10));\n current[segment] = isNextArray ? [] : {};\n }\n current = current[segment];\n } else {\n throw new Error(\n `Cannot set property on non-object at ${segments.slice(0, i + 1).join(\"/\")}`,\n );\n }\n }\n\n const lastSegment = segments[segments.length - 1]!;\n if (Array.isArray(current)) {\n const index = Number.parseInt(lastSegment, 10);\n if (Number.isNaN(index) || index < 0) {\n throw new Error(`Invalid array index: ${lastSegment}`);\n }\n current[index] = value;\n } else if (typeof current === \"object\") {\n current[lastSegment] = value;\n } else {\n throw new Error(\"Cannot set property on non-object\");\n }\n }\n\n /**\n * Delete a value from the JSON structure at the given path\n */\n private deleteValueAtPath(data: any, segments: string[]): boolean {\n if (segments.length === 0) {\n throw new Error(\"Cannot delete root path\");\n }\n\n let current = data;\n for (let i = 0; i < segments.length - 1; i++) {\n const segment = segments[i]!;\n\n if (Array.isArray(current)) {\n const index = Number.parseInt(segment, 10);\n if (Number.isNaN(index) || index < 0 || index >= current.length) {\n return false;\n }\n current = current[index];\n } else if (typeof current === \"object\") {\n if (!(segment in current)) return false;\n current = current[segment];\n } else {\n return false;\n }\n }\n\n const lastSegment = segments[segments.length - 1]!;\n if (Array.isArray(current)) {\n const index = Number.parseInt(lastSegment, 10);\n if (Number.isNaN(index) || index < 0 || index >= current.length) {\n return false;\n }\n current.splice(index, 1);\n return true;\n }\n if (typeof current === \"object\") {\n if (!(lastSegment in current)) return false;\n delete current[lastSegment];\n return true;\n }\n return false;\n }\n\n /**\n * Check if a value is a \"directory\" (object or array with children)\n */\n private isDirectoryValue(value: any): boolean {\n if (Array.isArray(value)) return true;\n if (typeof value === \"object\" && value !== null) return true;\n return false;\n }\n\n /**\n * Get children of a directory value (filters out .afs meta key)\n */\n private getChildren(value: any): Array<{ key: string; value: any }> {\n if (Array.isArray(value)) {\n return value.map((item, index) => ({ key: String(index), value: item }));\n }\n if (typeof value === \"object\" && value !== null) {\n return Object.entries(value)\n .filter(([key]) => !this.isMetaKey(key))\n .map(([key, val]) => ({ key, value: val }));\n }\n return [];\n }\n\n /**\n * Convert a JSON value to an AFSEntry\n */\n private valueToAFSEntry(path: string, value: any): AFSEntry {\n const isDir = this.isDirectoryValue(value);\n const children = isDir ? this.getChildren(value) : [];\n\n return this.buildEntry(path, {\n content: isDir ? undefined : value,\n metadata: {\n childrenCount: isDir ? children.length : undefined,\n },\n createdAt: this.fileStats.birthtime,\n updatedAt: this.fileStats.mtime,\n });\n }\n}\n\nconst _typeCheck: AFSModuleClass<AFSJSON, AFSJSONOptions> = AFSJSON;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["afs","meta","parseYAML","stringifyYAML"],"sources":["../src/index.ts"],"sourcesContent":["import { existsSync, mkdirSync, writeFileSync } from \"node:fs\";\nimport { readFile, stat, writeFile } from \"node:fs/promises\";\nimport { basename, dirname, extname, isAbsolute, join } from \"node:path\";\nimport {\n type AFSAccessMode,\n type AFSDeleteOptions,\n type AFSEntry,\n type AFSEntryMetadata,\n type AFSExplainOptions,\n type AFSExplainResult,\n type AFSListResult,\n type AFSModuleClass,\n type AFSModuleLoadParams,\n AFSNotFoundError,\n type AFSRenameOptions,\n type AFSSearchOptions,\n type AFSStatResult,\n type AFSWriteEntryPayload,\n type CapabilitiesManifest,\n type ProviderManifest,\n} from \"@aigne/afs\";\nimport {\n AFSBaseProvider,\n Delete,\n Explain,\n List,\n Meta,\n Read,\n Rename,\n type RouteContext,\n Search,\n Stat,\n Write,\n} from \"@aigne/afs/provider\";\nimport { camelize, optionalize, zodParse } from \"@aigne/afs/utils/zod\";\nimport { joinURL } from \"ufo\";\nimport { parse as parseYAML, stringify as stringifyYAML } from \"yaml\";\nimport { z } from \"zod\";\n\nconst LIST_MAX_LIMIT = 1000;\n\n/** Hidden key for storing AFS metadata (mirrors FS provider's .afs directory) */\nconst AFS_KEY = \".afs\";\n\n/** Subkey for storing metadata (mirrors FS provider's meta.yaml file) */\nconst META_KEY = \"meta\";\n\n/** Subkey for storing child node metadata (mirrors FS provider's .nodes directory) */\nconst NODES_KEY = \".nodes\";\n\nexport interface AFSJSONOptions {\n name?: string;\n jsonPath: string;\n description?: string;\n /**\n * Access mode for this module.\n * - \"readonly\": Only read operations are allowed\n * - \"readwrite\": All operations are allowed (default, unless agentSkills is enabled)\n * @default \"readwrite\" (or \"readonly\" when agentSkills is true)\n */\n accessMode?: AFSAccessMode;\n /**\n * Enable automatic agent skill scanning for this module.\n * When enabled, defaults accessMode to \"readonly\" if not explicitly set.\n * @default false\n */\n agentSkills?: boolean;\n}\n\nconst afsJSONOptionsSchema = camelize(\n z.object({\n name: optionalize(z.string()),\n jsonPath: z.string().describe(\"The path to the JSON/YAML file to mount\"),\n description: optionalize(z.string().describe(\"A description of the JSON module\")),\n accessMode: optionalize(\n z.enum([\"readonly\", \"readwrite\"]).describe(\"Access mode for this module\"),\n ),\n agentSkills: optionalize(\n z.boolean().describe(\"Enable automatic agent skill scanning for this module\"),\n ),\n }),\n);\n\n/**\n * AFS module for mounting JSON/YAML files as virtual file systems.\n *\n * JSON/YAML objects are treated as directories, and properties/array items as files.\n * Supports nested structures and path-based access to data values.\n */\nexport class AFSJSON extends AFSBaseProvider {\n static schema() {\n return afsJSONOptionsSchema;\n }\n\n static manifest(): ProviderManifest {\n return {\n name: \"json\",\n description: \"Mount a JSON or YAML file as a virtual filesystem\",\n uriTemplate: \"json://{localPath+}\",\n category: \"structured-data\",\n schema: z.object({ localPath: z.string() }),\n tags: [\"json\", \"yaml\", \"structured-data\"],\n };\n }\n\n static async load({ basePath, config }: AFSModuleLoadParams = {}) {\n const valid = await AFSJSON.schema().parseAsync(config);\n return new AFSJSON({ ...valid, cwd: basePath });\n }\n\n readonly name: string;\n readonly description?: string;\n readonly accessMode: AFSAccessMode;\n readonly agentSkills?: boolean;\n\n private jsonData: any = null;\n private fileStats: {\n birthtime?: Date;\n mtime?: Date;\n } = {};\n private fileFormat: \"json\" | \"yaml\" = \"json\";\n private resolvedJsonPath: string;\n\n constructor(public options: AFSJSONOptions & { cwd?: string; localPath?: string; uri?: string }) {\n super();\n\n // Normalize registry-passed template vars: localPath → jsonPath\n if ((options as any).localPath && !options.jsonPath) {\n options.jsonPath = (options as any).localPath;\n }\n\n zodParse(afsJSONOptionsSchema, options);\n\n let jsonPath: string;\n\n jsonPath = options.jsonPath.replaceAll(\"${CWD}\", process.cwd());\n if (jsonPath.startsWith(\"~/\")) {\n jsonPath = join(process.env.HOME || \"\", jsonPath.slice(2));\n }\n if (!isAbsolute(jsonPath)) {\n jsonPath = join(options.cwd || process.cwd(), jsonPath);\n }\n\n // Auto-create JSON file if it doesn't exist\n if (!existsSync(jsonPath)) {\n mkdirSync(dirname(jsonPath), { recursive: true });\n writeFileSync(jsonPath, \"{}\", \"utf8\");\n }\n\n // Detect file format based on extension for writing\n const ext = extname(jsonPath).toLowerCase();\n this.fileFormat = ext === \".yaml\" || ext === \".yml\" ? \"yaml\" : \"json\";\n\n // Extract name without extension\n const extensions = [\".json\", \".yaml\", \".yml\"];\n let name = basename(jsonPath);\n for (const e of extensions) {\n if (name.endsWith(e)) {\n name = name.slice(0, -e.length);\n break;\n }\n }\n\n this.name = options.name || name || \"json\";\n this.description = options.description;\n this.agentSkills = options.agentSkills;\n // Default to \"readwrite\", but \"readonly\" if agentSkills is enabled\n this.accessMode = options.accessMode ?? (options.agentSkills ? \"readonly\" : \"readwrite\");\n this.resolvedJsonPath = jsonPath;\n }\n\n // ========== Meta Handlers ==========\n // Meta is read-only introspection. Metadata writes are handled by @Write via payload.meta.\n //\n // Meta storage strategy (mirrors FS provider's .afs directory):\n // - For objects (directories): metadata stored in `.afs.meta` key within the object\n // - For primitives (files): metadata stored in parent's `.afs[\".nodes\"][key].meta` structure\n //\n // Example JSON structure:\n // {\n // \"database\": {\n // \"host\": \"localhost\",\n // \".afs\": {\n // \"meta\": { \"description\": \"Database config\" }, // object's own meta\n // \".nodes\": {\n // \"host\": { \"meta\": { \"description\": \"DB hostname\" } } // primitive's meta\n // }\n // }\n // }\n // }\n\n /**\n * Read metadata for a JSON node via /.meta or /path/.meta\n * Returns stored metadata merged with computed type information\n * Note: Meta is read-only. To write metadata, use write() with payload.meta.\n */\n @Meta(\"/:path*\")\n async readMetaHandler(ctx: RouteContext<{ path?: string }>): Promise<AFSEntry | undefined> {\n await this.ensureLoaded();\n\n const nodePath = joinURL(\"/\", ctx.params.path ?? \"\");\n const segments = this.getPathSegments(nodePath);\n const value = this.getValueAtPath(this.jsonData, segments);\n\n if (value === undefined) {\n throw new AFSNotFoundError(nodePath);\n }\n\n const isDir = this.isDirectoryValue(value);\n const children = isDir ? this.getChildren(value) : [];\n\n // Determine the JSON type\n let type: string;\n if (Array.isArray(value)) {\n type = \"array\";\n } else if (value === null) {\n type = \"null\";\n } else if (typeof value === \"object\") {\n type = \"object\";\n } else {\n type = typeof value;\n }\n\n // Load stored user-defined metadata\n const storedMeta = this.loadMeta(nodePath) || {};\n\n // Build computed metadata (type info, etc.)\n const computedMeta: Record<string, unknown> = {\n type,\n path: nodePath,\n };\n\n if (isDir) {\n computedMeta.childrenCount = children.length;\n if (Array.isArray(value)) {\n computedMeta.length = value.length;\n } else {\n // Filter out internal keys from keys list\n computedMeta.keys = Object.keys(value).filter((k) => !this.isMetaKey(k));\n }\n } else {\n computedMeta.value = value;\n }\n\n if (this.fileStats.birthtime) {\n computedMeta.created = this.fileStats.birthtime;\n }\n if (this.fileStats.mtime) {\n computedMeta.modified = this.fileStats.mtime;\n }\n\n return this.buildEntry(joinURL(nodePath, \".meta\"), {\n // User-defined metadata goes in metadata field (for conformance)\n meta: storedMeta as AFSEntryMetadata,\n // Computed type info goes in content (JSON-specific)\n content: computedMeta,\n createdAt: this.fileStats.birthtime,\n updatedAt: this.fileStats.mtime,\n });\n }\n\n // ========== Route Handlers ==========\n\n @List(\"/:path*\", { handleDepth: true })\n async listHandler(\n ctx: RouteContext<{ path?: string }>,\n ): Promise<AFSListResult & { noExpand?: string[] }> {\n await this.ensureLoaded();\n\n const normalizedPath = ctx.params.path ? `/${ctx.params.path}` : \"/\";\n const options = ctx.options as { limit?: number; maxChildren?: number; maxDepth?: number };\n const limit = Math.min(options?.limit || LIST_MAX_LIMIT, LIST_MAX_LIMIT);\n const maxChildren =\n typeof options?.maxChildren === \"number\" ? options.maxChildren : Number.MAX_SAFE_INTEGER;\n const maxDepth = options?.maxDepth ?? 1;\n\n const segments = this.getPathSegments(normalizedPath);\n const value = this.getValueAtPath(this.jsonData, segments);\n\n if (value === undefined) {\n throw new AFSNotFoundError(normalizedPath);\n }\n\n // Note: list() returns only children, never the path itself (per new semantics)\n // maxDepth=0 means no children, maxDepth=1 means immediate children only, etc.\n if (maxDepth === 0) {\n return { data: [] };\n }\n\n // If the value is not a directory, it has no children\n if (!this.isDirectoryValue(value)) {\n return { data: [] };\n }\n\n const entries: AFSEntry[] = [];\n\n interface QueueItem {\n path: string;\n value: any;\n depth: number;\n }\n\n // Start with immediate children at depth 1 (not the path itself at depth 0)\n const rootChildren = this.getChildren(value);\n const rootChildrenToProcess =\n rootChildren.length > maxChildren ? rootChildren.slice(0, maxChildren) : rootChildren;\n\n const queue: QueueItem[] = rootChildrenToProcess.map((child) => ({\n path: normalizedPath === \"/\" ? `/${child.key}` : `${normalizedPath}/${child.key}`,\n value: child.value,\n depth: 1,\n }));\n\n while (queue.length > 0) {\n const item = queue.shift();\n if (!item) break;\n\n const { path: itemPath, value: itemValue, depth } = item;\n\n const entry = this.valueToAFSEntry(itemPath, itemValue);\n entries.push(entry);\n\n if (entries.length >= limit) {\n break;\n }\n\n // Process children if within depth limit\n if (this.isDirectoryValue(itemValue) && depth < maxDepth) {\n const children = this.getChildren(itemValue);\n const childrenToProcess =\n children.length > maxChildren ? children.slice(0, maxChildren) : children;\n\n for (const child of childrenToProcess) {\n const childPath = itemPath === \"/\" ? `/${child.key}` : `${itemPath}/${child.key}`;\n queue.push({\n path: childPath,\n value: child.value,\n depth: depth + 1,\n });\n }\n }\n }\n\n return { data: entries };\n }\n\n @Read(\"/:path*\")\n async readHandler(ctx: RouteContext<{ path?: string }>): Promise<AFSEntry | undefined> {\n await this.ensureLoaded();\n\n const normalizedPath = ctx.params.path ? `/${ctx.params.path}` : \"/\";\n const segments = this.getPathSegments(normalizedPath);\n const value = this.getValueAtPath(this.jsonData, segments);\n\n if (value === undefined) {\n throw new AFSNotFoundError(normalizedPath);\n }\n\n return this.valueToAFSEntry(normalizedPath, value);\n }\n\n /**\n * Write handler - supports writing content and/or metadata\n *\n * | payload | behavior |\n * |---------|----------|\n * | { content } | write content only |\n * | { metadata } | write metadata only (to .afs storage) |\n * | { content, metadata } | write both |\n */\n @Write(\"/:path*\")\n async writeHandler(\n ctx: RouteContext<{ path?: string }>,\n payload: AFSWriteEntryPayload,\n ): Promise<{ data: AFSEntry }> {\n await this.ensureLoaded();\n\n const normalizedPath = ctx.params.path ? `/${ctx.params.path}` : \"/\";\n const segments = this.getPathSegments(normalizedPath);\n\n // Write content if provided\n if (payload.content !== undefined) {\n this.setValueAtPath(this.jsonData, segments, payload.content);\n }\n\n // Write metadata if provided (merge with existing)\n if (payload.meta !== undefined && typeof payload.meta === \"object\") {\n const existingMeta = this.loadMeta(normalizedPath) || {};\n const finalMeta = { ...existingMeta, ...payload.meta };\n this.saveMeta(normalizedPath, finalMeta);\n }\n\n // Save back to file\n await this.saveToFile();\n\n const newValue = this.getValueAtPath(this.jsonData, segments);\n const isDir = this.isDirectoryValue(newValue);\n const children = isDir ? this.getChildren(newValue) : [];\n\n // Load stored metadata for response\n const storedMeta = this.loadMeta(normalizedPath) || {};\n\n const writtenEntry: AFSEntry = {\n id: normalizedPath,\n path: normalizedPath,\n content: payload.content !== undefined ? payload.content : newValue,\n summary: payload.summary,\n createdAt: this.fileStats.birthtime,\n updatedAt: this.fileStats.mtime,\n meta: {\n ...storedMeta,\n childrenCount: isDir ? children.length : undefined,\n } as AFSEntryMetadata,\n userId: payload.userId,\n sessionId: payload.sessionId,\n linkTo: payload.linkTo,\n };\n\n return { data: writtenEntry };\n }\n\n @Delete(\"/:path*\")\n async deleteHandler(ctx: RouteContext<{ path?: string }>): Promise<{ message: string }> {\n await this.ensureLoaded();\n\n const normalizedPath = ctx.params.path ? `/${ctx.params.path}` : \"/\";\n const options = ctx.options as AFSDeleteOptions | undefined;\n const segments = this.getPathSegments(normalizedPath);\n const value = this.getValueAtPath(this.jsonData, segments);\n\n if (value === undefined) {\n throw new AFSNotFoundError(normalizedPath);\n }\n\n const hasChildren = this.isDirectoryValue(value) && this.getChildren(value).length > 0;\n if (hasChildren && !options?.recursive) {\n throw new Error(\n `Cannot delete directory '${normalizedPath}' without recursive option. Set recursive: true to delete directories.`,\n );\n }\n\n this.deleteValueAtPath(this.jsonData, segments);\n await this.saveToFile();\n\n return { message: `Successfully deleted: ${normalizedPath}` };\n }\n\n @Rename(\"/:path*\")\n async renameHandler(\n ctx: RouteContext<{ path?: string }>,\n newPath: string,\n ): Promise<{ message: string }> {\n await this.ensureLoaded();\n\n const normalizedOldPath = ctx.params.path ? `/${ctx.params.path}` : \"/\";\n const normalizedNewPath = this.normalizePath(newPath);\n const options = ctx.options as AFSRenameOptions | undefined;\n\n const oldSegments = this.getPathSegments(normalizedOldPath);\n const newSegments = this.getPathSegments(normalizedNewPath);\n\n const oldValue = this.getValueAtPath(this.jsonData, oldSegments);\n if (oldValue === undefined) {\n throw new AFSNotFoundError(normalizedOldPath);\n }\n\n const existingNewValue = this.getValueAtPath(this.jsonData, newSegments);\n if (existingNewValue !== undefined && !options?.overwrite) {\n throw new Error(\n `Destination '${normalizedNewPath}' already exists. Set overwrite: true to replace it.`,\n );\n }\n\n // Copy to new location and delete old\n this.setValueAtPath(this.jsonData, newSegments, oldValue);\n this.deleteValueAtPath(this.jsonData, oldSegments);\n await this.saveToFile();\n\n return {\n message: `Successfully renamed '${normalizedOldPath}' to '${normalizedNewPath}'`,\n };\n }\n\n @Search(\"/:path*\")\n async searchHandler(\n ctx: RouteContext<{ path?: string }>,\n query: string,\n options?: AFSSearchOptions,\n ): Promise<{ data: AFSEntry[]; message?: string }> {\n await this.ensureLoaded();\n\n const normalizedPath = ctx.params.path ? `/${ctx.params.path}` : \"/\";\n const limit = Math.min(options?.limit || LIST_MAX_LIMIT, LIST_MAX_LIMIT);\n const caseSensitive = options?.caseSensitive ?? false;\n\n const segments = this.getPathSegments(normalizedPath);\n const rootValue = this.getValueAtPath(this.jsonData, segments);\n\n if (rootValue === undefined) {\n throw new AFSNotFoundError(normalizedPath);\n }\n\n const entries: AFSEntry[] = [];\n const searchQuery = caseSensitive ? query : query.toLowerCase();\n\n const searchInValue = (valuePath: string, value: any): void => {\n if (entries.length >= limit) return;\n\n let matched = false;\n\n // Search in the value itself\n if (!this.isDirectoryValue(value)) {\n const valueStr = typeof value === \"string\" ? value : JSON.stringify(value);\n const searchValue = caseSensitive ? valueStr : valueStr.toLowerCase();\n if (searchValue.includes(searchQuery)) {\n matched = true;\n }\n }\n\n if (matched) {\n entries.push(this.valueToAFSEntry(valuePath, value));\n }\n\n // Recursively search children\n if (this.isDirectoryValue(value)) {\n const children = this.getChildren(value);\n for (const child of children) {\n if (entries.length >= limit) break;\n const childPath = valuePath === \"/\" ? `/${child.key}` : `${valuePath}/${child.key}`;\n searchInValue(childPath, child.value);\n }\n }\n };\n\n searchInValue(normalizedPath, rootValue);\n\n return {\n data: entries,\n message: entries.length >= limit ? `Results truncated to limit ${limit}` : undefined,\n };\n }\n\n @Stat(\"/:path*\")\n async statHandler(ctx: RouteContext<{ path?: string }>): Promise<AFSStatResult> {\n await this.ensureLoaded();\n\n const normalizedPath = ctx.params.path ? `/${ctx.params.path}` : \"/\";\n const segments = this.getPathSegments(normalizedPath);\n const value = this.getValueAtPath(this.jsonData, segments);\n\n if (value === undefined) {\n throw new AFSNotFoundError(normalizedPath);\n }\n\n const isDir = this.isDirectoryValue(value);\n const children = isDir ? this.getChildren(value) : [];\n const loadedMeta = this.loadMeta(normalizedPath);\n const meta: Record<string, unknown> = { ...loadedMeta };\n if (isDir) {\n meta.childrenCount = children.length;\n }\n\n const id = segments.length > 0 ? (segments[segments.length - 1] as string) : \"/\";\n\n return {\n data: {\n id,\n path: normalizedPath,\n createdAt: this.fileStats.birthtime,\n updatedAt: this.fileStats.mtime,\n meta,\n },\n };\n }\n\n // ========== Explain & Capabilities ==========\n\n @Read(\"/.meta/.capabilities\")\n async readCapabilitiesHandler(_ctx: RouteContext): Promise<AFSEntry | undefined> {\n await this.ensureLoaded();\n\n const operations = [\"list\", \"read\", \"stat\", \"explain\", \"search\"];\n if (this.accessMode === \"readwrite\") {\n operations.push(\"write\", \"delete\", \"rename\");\n }\n\n const manifest: CapabilitiesManifest = {\n schemaVersion: 1,\n provider: this.name,\n description: this.description || `JSON/YAML virtual filesystem (${this.fileFormat} format)`,\n tools: [],\n actions: [],\n operations: this.getOperationsDeclaration(),\n };\n\n return {\n id: \"/.meta/.capabilities\",\n path: \"/.meta/.capabilities\",\n content: manifest,\n meta: { kind: \"afs:capabilities\", operations },\n };\n }\n\n @Explain(\"/:path*\")\n async explainHandler(ctx: RouteContext<{ path?: string }>): Promise<AFSExplainResult> {\n await this.ensureLoaded();\n\n const normalizedPath = joinURL(\"/\", ctx.params.path ?? \"\");\n const format = (ctx.options as AFSExplainOptions)?.format || \"markdown\";\n const segments = this.getPathSegments(normalizedPath);\n const value = this.getValueAtPath(this.jsonData, segments);\n\n if (value === undefined) {\n throw new AFSNotFoundError(normalizedPath);\n }\n\n const nodeName = segments.length > 0 ? segments[segments.length - 1]! : \"/\";\n const isDir = this.isDirectoryValue(value);\n const storedMeta = this.loadMeta(normalizedPath);\n const lines: string[] = [];\n\n if (format === \"markdown\") {\n lines.push(`# ${nodeName}`);\n lines.push(\"\");\n lines.push(`**Path:** \\`${normalizedPath}\\``);\n lines.push(`**Format:** ${this.fileFormat.toUpperCase()}`);\n\n if (normalizedPath === \"/\") {\n // Root: describe file path, format, top-level structure\n const topType = Array.isArray(this.jsonData) ? \"array\" : \"object\";\n const children = this.getChildren(this.jsonData);\n lines.push(`**Structure:** ${topType}`);\n lines.push(`**Top-level keys:** ${children.length}`);\n if (children.length > 0) {\n lines.push(\"\");\n lines.push(\"## Keys\");\n lines.push(\"\");\n for (const child of children.slice(0, 30)) {\n const childVal = child.value;\n const childType = this.describeType(childVal);\n lines.push(`- \\`${child.key}\\` — ${childType}`);\n }\n if (children.length > 30) {\n lines.push(`- ... and ${children.length - 30} more`);\n }\n }\n } else if (Array.isArray(value)) {\n // Array node\n lines.push(`**Type:** array`);\n lines.push(`**Elements:** ${value.length}`);\n if (value.length > 0) {\n const elementType = this.describeType(value[0]);\n const isHomogeneous = value.every((v: unknown) => this.describeType(v) === elementType);\n lines.push(`**Element type:** ${isHomogeneous ? elementType : \"mixed\"}`);\n }\n } else if (typeof value === \"object\" && value !== null) {\n // Object node\n const children = this.getChildren(value);\n lines.push(`**Type:** object`);\n lines.push(`**Keys:** ${children.length}`);\n if (children.length > 0) {\n lines.push(\"\");\n lines.push(\"## Keys\");\n lines.push(\"\");\n for (const child of children.slice(0, 30)) {\n const childType = this.describeType(child.value);\n lines.push(`- \\`${child.key}\\` — ${childType}`);\n }\n if (children.length > 30) {\n lines.push(`- ... and ${children.length - 30} more`);\n }\n }\n } else {\n // Primitive node\n const valType = value === null ? \"null\" : typeof value;\n lines.push(`**Type:** ${valType}`);\n const valStr = String(value);\n if (valStr.length > 200) {\n lines.push(`**Value:** ${valStr.slice(0, 200)}...`);\n } else {\n lines.push(`**Value:** ${valStr}`);\n }\n }\n\n if (storedMeta) {\n lines.push(\"\");\n lines.push(\"## Metadata\");\n for (const [key, val] of Object.entries(storedMeta)) {\n lines.push(`- **${key}:** ${JSON.stringify(val)}`);\n }\n }\n } else {\n // text format\n lines.push(`${nodeName} (${isDir ? \"directory\" : \"value\"})`);\n lines.push(`Path: ${normalizedPath}`);\n lines.push(`Format: ${this.fileFormat}`);\n if (isDir) {\n const children = this.getChildren(value);\n lines.push(`Children: ${children.length}`);\n } else {\n const valStr = String(value);\n lines.push(`Type: ${value === null ? \"null\" : typeof value}`);\n lines.push(`Value: ${valStr.length > 200 ? `${valStr.slice(0, 200)}...` : valStr}`);\n }\n }\n\n return { content: lines.join(\"\\n\"), format };\n }\n\n /**\n * Get a human-readable type description for a JSON value.\n */\n private describeType(value: unknown): string {\n if (value === null) return \"null\";\n if (Array.isArray(value)) return `array[${value.length}]`;\n if (typeof value === \"object\") {\n const keys = Object.keys(value).filter((k) => !this.isMetaKey(k));\n return `object{${keys.length} keys}`;\n }\n return typeof value;\n }\n\n // ========== Private Helper Methods ==========\n\n /**\n * Check if a key is a hidden meta key that should be filtered from listings\n */\n private isMetaKey(key: string): boolean {\n return key === AFS_KEY;\n }\n\n /**\n * Load metadata for a node.\n *\n * Storage location depends on node type (mirrors FS provider's .afs structure):\n * - Objects: `.afs.meta` key within the object itself\n * - Primitives: parent's `.afs[\".nodes\"][key].meta`\n */\n private loadMeta(nodePath: string): Record<string, unknown> | null {\n const segments = this.getPathSegments(nodePath);\n const value = this.getValueAtPath(this.jsonData, segments);\n\n if (value === undefined) {\n return null;\n }\n\n if (this.isDirectoryValue(value) && !Array.isArray(value)) {\n // Object: meta is in value[\".afs\"].meta\n const afs = value[AFS_KEY];\n if (afs && typeof afs === \"object\" && !Array.isArray(afs)) {\n const meta = afs[META_KEY];\n if (meta && typeof meta === \"object\" && !Array.isArray(meta)) {\n return meta as Record<string, unknown>;\n }\n }\n return null;\n }\n\n // Primitive or array: meta is in parent's .afs[\".nodes\"][key].meta\n if (segments.length === 0) {\n // Root is always an object, handled above\n return null;\n }\n\n const parentSegments = segments.slice(0, -1);\n const nodeKey = segments[segments.length - 1]!;\n const parentValue = this.getValueAtPath(this.jsonData, parentSegments);\n\n if (!parentValue || Array.isArray(parentValue) || typeof parentValue !== \"object\") {\n return null;\n }\n\n const afs = parentValue[AFS_KEY];\n if (!afs || typeof afs !== \"object\" || Array.isArray(afs)) {\n return null;\n }\n\n const nodes = afs[NODES_KEY];\n if (!nodes || typeof nodes !== \"object\" || Array.isArray(nodes)) {\n return null;\n }\n\n const nodeEntry = nodes[nodeKey];\n if (!nodeEntry || typeof nodeEntry !== \"object\" || Array.isArray(nodeEntry)) {\n return null;\n }\n\n const meta = nodeEntry[META_KEY];\n if (!meta || typeof meta !== \"object\" || Array.isArray(meta)) {\n return null;\n }\n\n return meta as Record<string, unknown>;\n }\n\n /**\n * Save metadata for a node.\n *\n * Storage location depends on node type (mirrors FS provider's .afs structure):\n * - Objects: `.afs.meta` key within the object itself\n * - Primitives: parent's `.afs[\".nodes\"][key].meta`\n */\n private saveMeta(nodePath: string, meta: Record<string, unknown>): void {\n const segments = this.getPathSegments(nodePath);\n const value = this.getValueAtPath(this.jsonData, segments);\n\n if (value === undefined) {\n throw new AFSNotFoundError(nodePath);\n }\n\n if (this.isDirectoryValue(value) && !Array.isArray(value)) {\n // Object: store in value[\".afs\"].meta\n if (!value[AFS_KEY]) {\n value[AFS_KEY] = {};\n }\n // Store in .meta key\n value[AFS_KEY][META_KEY] = meta;\n return;\n }\n\n // Primitive or array: store in parent's .afs[\".nodes\"][key].meta\n if (segments.length === 0) {\n throw new Error(\"Cannot save meta for root when root is not an object\");\n }\n\n const parentSegments = segments.slice(0, -1);\n const nodeKey = segments[segments.length - 1]!;\n const parentValue = this.getValueAtPath(this.jsonData, parentSegments);\n\n if (!parentValue || typeof parentValue !== \"object\") {\n throw new Error(`Parent path is not an object`);\n }\n\n if (Array.isArray(parentValue)) {\n throw new Error(`Cannot save meta for array elements`);\n }\n\n // Ensure .afs exists\n if (!parentValue[AFS_KEY]) {\n parentValue[AFS_KEY] = {};\n }\n\n // Ensure .afs[\".nodes\"] exists\n if (!parentValue[AFS_KEY][NODES_KEY]) {\n parentValue[AFS_KEY][NODES_KEY] = {};\n }\n\n // Ensure .afs[\".nodes\"][nodeKey] exists\n if (!parentValue[AFS_KEY][NODES_KEY][nodeKey]) {\n parentValue[AFS_KEY][NODES_KEY][nodeKey] = {};\n }\n\n // Store the meta in .meta key\n parentValue[AFS_KEY][NODES_KEY][nodeKey][META_KEY] = meta;\n }\n\n /**\n * Load JSON/YAML data from file. Called lazily on first access.\n * Uses YAML parser which can handle both JSON and YAML formats.\n */\n private async ensureLoaded(): Promise<void> {\n if (this.jsonData !== null) return;\n\n try {\n const stats = await stat(this.resolvedJsonPath);\n this.fileStats = {\n birthtime: stats.birthtime,\n mtime: stats.mtime,\n };\n\n const content = await readFile(this.resolvedJsonPath, \"utf8\");\n\n // YAML parser can handle both JSON and YAML formats\n this.jsonData = parseYAML(content);\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") {\n // File doesn't exist yet, start with empty object\n this.jsonData = {};\n } else {\n throw error;\n }\n }\n }\n\n /**\n * Save JSON/YAML data back to file. Only called in readwrite mode.\n */\n private async saveToFile(): Promise<void> {\n let content: string;\n\n // Serialize based on file format\n if (this.fileFormat === \"yaml\") {\n content = stringifyYAML(this.jsonData);\n } else {\n content = JSON.stringify(this.jsonData, null, 2);\n }\n\n await writeFile(this.resolvedJsonPath, content, \"utf8\");\n\n // Update file stats\n const stats = await stat(this.resolvedJsonPath);\n this.fileStats = {\n birthtime: this.fileStats.birthtime || stats.birthtime,\n mtime: stats.mtime,\n };\n }\n\n /**\n * Get path segments from normalized path\n */\n private getPathSegments(path: string): string[] {\n const normalized = this.normalizePath(path);\n if (normalized === \"/\") return [];\n return normalized.slice(1).split(\"/\");\n }\n\n /**\n * Navigate to a value in the JSON structure using path segments\n */\n private getValueAtPath(data: any, segments: string[]): any {\n let current = data;\n for (const segment of segments) {\n if (current == null) return undefined;\n\n // Handle array indices\n if (Array.isArray(current)) {\n const index = Number.parseInt(segment, 10);\n if (Number.isNaN(index) || index < 0 || index >= current.length) {\n return undefined;\n }\n current = current[index];\n } else if (typeof current === \"object\") {\n current = current[segment as keyof typeof current];\n } else {\n return undefined;\n }\n }\n return current;\n }\n\n /**\n * Set a value in the JSON structure at the given path\n */\n private setValueAtPath(data: any, segments: string[], value: any): void {\n if (segments.length === 0) {\n throw new Error(\"Cannot set value at root path\");\n }\n\n let current = data;\n for (let i = 0; i < segments.length - 1; i++) {\n const segment = segments[i]!;\n const nextSegment = segments[i + 1]!;\n\n if (Array.isArray(current)) {\n const index = Number.parseInt(segment, 10);\n if (Number.isNaN(index) || index < 0) {\n throw new Error(`Invalid array index: ${segment}`);\n }\n\n // Extend array if necessary\n while (current.length <= index) {\n current.push(null);\n }\n\n if (current[index] == null) {\n // Determine if next level should be array or object\n const isNextArray = !Number.isNaN(Number.parseInt(nextSegment, 10));\n current[index] = isNextArray ? [] : {};\n }\n current = current[index];\n } else if (typeof current === \"object\") {\n if (current[segment] == null) {\n // Determine if next level should be array or object\n const isNextArray = !Number.isNaN(Number.parseInt(nextSegment, 10));\n current[segment] = isNextArray ? [] : {};\n }\n current = current[segment];\n } else {\n throw new Error(\n `Cannot set property on non-object at ${segments.slice(0, i + 1).join(\"/\")}`,\n );\n }\n }\n\n const lastSegment = segments[segments.length - 1]!;\n if (Array.isArray(current)) {\n const index = Number.parseInt(lastSegment, 10);\n if (Number.isNaN(index) || index < 0) {\n throw new Error(`Invalid array index: ${lastSegment}`);\n }\n current[index] = value;\n } else if (typeof current === \"object\") {\n current[lastSegment] = value;\n } else {\n throw new Error(\"Cannot set property on non-object\");\n }\n }\n\n /**\n * Delete a value from the JSON structure at the given path\n */\n private deleteValueAtPath(data: any, segments: string[]): boolean {\n if (segments.length === 0) {\n throw new Error(\"Cannot delete root path\");\n }\n\n let current = data;\n for (let i = 0; i < segments.length - 1; i++) {\n const segment = segments[i]!;\n\n if (Array.isArray(current)) {\n const index = Number.parseInt(segment, 10);\n if (Number.isNaN(index) || index < 0 || index >= current.length) {\n return false;\n }\n current = current[index];\n } else if (typeof current === \"object\") {\n if (!(segment in current)) return false;\n current = current[segment];\n } else {\n return false;\n }\n }\n\n const lastSegment = segments[segments.length - 1]!;\n if (Array.isArray(current)) {\n const index = Number.parseInt(lastSegment, 10);\n if (Number.isNaN(index) || index < 0 || index >= current.length) {\n return false;\n }\n current.splice(index, 1);\n return true;\n }\n if (typeof current === \"object\") {\n if (!(lastSegment in current)) return false;\n delete current[lastSegment];\n return true;\n }\n return false;\n }\n\n /**\n * Check if a value is a \"directory\" (object or array with children)\n */\n private isDirectoryValue(value: any): boolean {\n if (Array.isArray(value)) return true;\n if (typeof value === \"object\" && value !== null) return true;\n return false;\n }\n\n /**\n * Get children of a directory value (filters out .afs meta key)\n */\n private getChildren(value: any): Array<{ key: string; value: any }> {\n if (Array.isArray(value)) {\n return value.map((item, index) => ({ key: String(index), value: item }));\n }\n if (typeof value === \"object\" && value !== null) {\n return Object.entries(value)\n .filter(([key]) => !this.isMetaKey(key))\n .map(([key, val]) => ({ key, value: val }));\n }\n return [];\n }\n\n /**\n * Convert a JSON value to an AFSEntry\n */\n private valueToAFSEntry(path: string, value: any): AFSEntry {\n const isDir = this.isDirectoryValue(value);\n const children = isDir ? this.getChildren(value) : [];\n const kind = Array.isArray(value) ? \"json:array\" : isDir ? \"json:object\" : \"json:value\";\n\n return this.buildEntry(path, {\n content: isDir ? undefined : value,\n meta: {\n kind,\n childrenCount: isDir ? children.length : undefined,\n },\n createdAt: this.fileStats.birthtime,\n updatedAt: this.fileStats.mtime,\n });\n }\n}\n\nconst _typeCheck: AFSModuleClass<AFSJSON, AFSJSONOptions> = AFSJSON;\n\nexport default AFSJSON;\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aigne/afs-json",
|
|
3
|
-
"version": "1.11.0-beta.
|
|
3
|
+
"version": "1.11.0-beta.8",
|
|
4
4
|
"description": "AIGNE AFS module for JSON and YAML file storage",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"publishConfig": {
|
|
@@ -35,8 +35,8 @@
|
|
|
35
35
|
"dependencies": {
|
|
36
36
|
"ufo": "^1.6.3",
|
|
37
37
|
"yaml": "^2.8.1",
|
|
38
|
-
"zod": "^
|
|
39
|
-
"@aigne/afs": "^1.11.0-beta.
|
|
38
|
+
"zod": "^4.0.0",
|
|
39
|
+
"@aigne/afs": "^1.11.0-beta.8"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
42
|
"@types/bun": "^1.3.6",
|
|
@@ -45,7 +45,8 @@
|
|
|
45
45
|
"tsdown": "0.20.0-beta.3",
|
|
46
46
|
"typescript": "5.9.2",
|
|
47
47
|
"@aigne/scripts": "0.0.0",
|
|
48
|
-
"@aigne/typescript-config": "0.0.0"
|
|
48
|
+
"@aigne/typescript-config": "0.0.0",
|
|
49
|
+
"@aigne/afs-testing": "1.11.0-beta.8"
|
|
49
50
|
},
|
|
50
51
|
"scripts": {
|
|
51
52
|
"build": "tsdown",
|