@aigne/afs-cli 1.11.0-beta.1 → 1.11.0-beta.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. package/README.md +63 -9
  2. package/dist/_virtual/rolldown_runtime.cjs +29 -0
  3. package/dist/cli.cjs +251 -0
  4. package/dist/cli.d.cts +1 -0
  5. package/dist/cli.mjs +241 -19
  6. package/dist/cli.mjs.map +1 -0
  7. package/dist/commands/exec.cjs +46 -0
  8. package/dist/commands/exec.mjs +45 -0
  9. package/dist/commands/exec.mjs.map +1 -0
  10. package/dist/commands/explain.cjs +244 -0
  11. package/dist/commands/explain.mjs +242 -0
  12. package/dist/commands/explain.mjs.map +1 -0
  13. package/dist/commands/index.cjs +8 -0
  14. package/dist/commands/index.mjs +10 -0
  15. package/dist/commands/ls.cjs +141 -0
  16. package/dist/commands/ls.mjs +140 -0
  17. package/dist/commands/ls.mjs.map +1 -0
  18. package/dist/commands/mount.cjs +170 -0
  19. package/dist/commands/mount.mjs +166 -0
  20. package/dist/commands/mount.mjs.map +1 -0
  21. package/dist/commands/read.cjs +65 -0
  22. package/dist/commands/read.mjs +64 -0
  23. package/dist/commands/read.mjs.map +1 -0
  24. package/dist/commands/serve.cjs +141 -0
  25. package/dist/commands/serve.mjs +140 -0
  26. package/dist/commands/serve.mjs.map +1 -0
  27. package/dist/commands/stat.cjs +113 -0
  28. package/dist/commands/stat.mjs +112 -0
  29. package/dist/commands/stat.mjs.map +1 -0
  30. package/dist/commands/write.cjs +52 -0
  31. package/dist/commands/write.mjs +51 -0
  32. package/dist/commands/write.mjs.map +1 -0
  33. package/dist/config/env.cjs +46 -0
  34. package/dist/config/env.mjs +46 -0
  35. package/dist/config/env.mjs.map +1 -0
  36. package/dist/config/loader.cjs +171 -0
  37. package/dist/config/loader.mjs +169 -0
  38. package/dist/config/loader.mjs.map +1 -0
  39. package/dist/config/provider-factory.cjs +92 -0
  40. package/dist/config/provider-factory.mjs +93 -0
  41. package/dist/config/provider-factory.mjs.map +1 -0
  42. package/dist/config/schema.cjs +36 -0
  43. package/dist/config/schema.mjs +36 -0
  44. package/dist/config/schema.mjs.map +1 -0
  45. package/dist/config/uri-parser.cjs +92 -0
  46. package/dist/config/uri-parser.mjs +92 -0
  47. package/dist/config/uri-parser.mjs.map +1 -0
  48. package/dist/errors.cjs +29 -0
  49. package/dist/errors.mjs +28 -0
  50. package/dist/errors.mjs.map +1 -0
  51. package/dist/index.cjs +3 -0
  52. package/dist/index.d.cts +2 -0
  53. package/dist/index.d.mts +1 -3
  54. package/dist/index.mjs +1 -1
  55. package/dist/runtime.cjs +82 -0
  56. package/dist/runtime.mjs +82 -0
  57. package/dist/runtime.mjs.map +1 -0
  58. package/dist/version.cjs +9 -0
  59. package/dist/version.d.cts +5 -0
  60. package/dist/version.d.cts.map +1 -0
  61. package/dist/version.d.mts +5 -0
  62. package/dist/version.d.mts.map +1 -0
  63. package/dist/version.mjs +9 -0
  64. package/dist/version.mjs.map +1 -0
  65. package/package.json +52 -11
  66. package/.turbo/turbo-build.log +0 -18
  67. package/.turbo/turbo-check-types.log +0 -4
  68. package/dist/version--p6A8sKX.mjs +0 -5
  69. package/src/cli.test.ts +0 -8
  70. package/src/cli.ts +0 -29
  71. package/src/index.ts +0 -7
  72. package/src/version.ts +0 -1
  73. package/tsconfig.json +0 -16
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.mjs","names":["yargs"],"sources":["../src/cli.ts"],"sourcesContent":["#!/usr/bin/env node\n\n/**\n * AFS CLI - Command Line Interface\n *\n * Commands:\n * - afs mount list|ls List mount configurations\n * - afs mount add <path> <uri> Add a mount\n * - afs mount remove|rm <path> Remove a mount\n * - afs mount validate Validate mount configuration\n * - afs list|ls [path] List directory\n * - afs stat <path> Get file/directory info\n * - afs read <path> Read file content\n * - afs write <path> Write file content (--content or stdin)\n * - afs exec <path> <action> Execute operation\n * - afs serve Start HTTP server to expose AFS\n *\n * Output modes:\n * - Default: Machine Truth (LLM/script friendly)\n * - --json: Structured JSON\n * - --view=llm: LLM optimized output\n * - --view=human: Human friendly format\n */\n\nimport yargs from \"yargs\";\nimport { hideBin } from \"yargs/helpers\";\nimport {\n execCommand,\n explainCommand,\n explainPathCommand,\n formatExecOutput,\n formatExplainOutput,\n formatLsOutput,\n formatMountListOutput,\n formatPathExplainOutput,\n formatReadOutput,\n formatServeOutput,\n formatStatOutput,\n formatWriteOutput,\n lsCommand,\n mountAddCommand,\n mountListCommand,\n mountRemoveCommand,\n mountValidateCommand,\n readCommand,\n serveCommand,\n statCommand,\n type ViewType,\n writeCommand,\n} from \"./commands/index.js\";\nimport { CLIError, ExitCode } from \"./errors.js\";\nimport { createRuntime } from \"./runtime.js\";\nimport { VERSION } from \"./version.js\";\n\n// Global view type derived from args\nfunction getViewType(argv: { json?: boolean; view?: string }): ViewType {\n if (argv.json) return \"json\";\n if (argv.view) return argv.view as ViewType;\n return \"default\";\n}\n\n// Run the CLI\nasync function main() {\n const cli = yargs(hideBin(process.argv))\n .scriptName(\"afs\")\n .version(VERSION)\n .alias(\"version\", \"V\")\n .help(\"help\")\n .alias(\"help\", \"h\")\n .usage(\"$0 <command> [options]\")\n .option(\"json\", {\n type: \"boolean\",\n description: \"Output in JSON format\",\n global: true,\n })\n .option(\"view\", {\n type: \"string\",\n choices: [\"default\", \"llm\", \"human\"],\n description: \"Output view format\",\n global: true,\n })\n .command(\n [\"list [path]\", \"ls [path]\"],\n \"List directory contents\",\n (yargs) =>\n yargs\n .positional(\"path\", {\n type: \"string\",\n default: \"/\",\n description: \"Path to list\",\n })\n .option(\"depth\", {\n type: \"number\",\n default: 1,\n description: \"Maximum depth to list\",\n })\n .option(\"limit\", {\n alias: \"n\",\n type: \"number\",\n description: \"Maximum number of entries to return\",\n })\n .option(\"max-children\", {\n type: \"number\",\n description: \"Maximum children per directory\",\n })\n .option(\"pattern\", {\n alias: \"p\",\n type: \"string\",\n description: \"Glob pattern to filter entries (e.g., *.ts, **/*.js)\",\n }),\n async (argv) => {\n const runtime = await createRuntime();\n const result = await lsCommand(runtime, argv.path!, {\n maxDepth: argv.depth,\n limit: argv.limit,\n maxChildren: argv[\"max-children\"],\n pattern: argv.pattern,\n });\n const view = getViewType(argv);\n console.log(formatLsOutput(result, view));\n },\n )\n .command(\n \"stat <path>\",\n \"Get file or directory info\",\n (yargs) =>\n yargs.positional(\"path\", {\n type: \"string\",\n demandOption: true,\n description: \"Path to stat\",\n }),\n async (argv) => {\n const runtime = await createRuntime();\n const result = await statCommand(runtime, argv.path!);\n const view = getViewType(argv);\n console.log(formatStatOutput(result, view));\n },\n )\n .command(\n \"read <path>\",\n \"Read file content\",\n (yargs) =>\n yargs.positional(\"path\", {\n type: \"string\",\n demandOption: true,\n description: \"Path to read\",\n }),\n async (argv) => {\n const runtime = await createRuntime();\n const result = await readCommand(runtime, argv.path!);\n const view = getViewType(argv);\n console.log(formatReadOutput(result, view));\n },\n )\n .command(\n \"write <path>\",\n \"Write content to file (from --content or stdin)\",\n (yargs) =>\n yargs\n .positional(\"path\", {\n type: \"string\",\n demandOption: true,\n description: \"Path to write\",\n })\n .option(\"content\", {\n type: \"string\",\n description: \"Content to write (if not provided, reads from stdin)\",\n })\n .option(\"append\", {\n type: \"boolean\",\n default: false,\n description: \"Append to file instead of overwrite\",\n }),\n async (argv) => {\n let content: string;\n\n if (argv.content !== undefined) {\n // Use --content parameter\n content = argv.content;\n } else {\n // Read content from stdin\n const chunks: Buffer[] = [];\n for await (const chunk of process.stdin) {\n chunks.push(chunk);\n }\n content = Buffer.concat(chunks).toString(\"utf-8\");\n }\n\n const runtime = await createRuntime();\n const result = await writeCommand(runtime, argv.path!, content, {\n append: argv.append,\n });\n const view = getViewType(argv);\n console.log(formatWriteOutput(result, view));\n\n if (!result.success) {\n process.exit(ExitCode.RUNTIME_ERROR);\n }\n },\n )\n .command(\n \"exec <path> [action]\",\n \"Execute operation on path\",\n (yargs) =>\n yargs\n .positional(\"path\", {\n type: \"string\",\n demandOption: true,\n description: \"Path to execute on\",\n })\n .positional(\"action\", {\n type: \"string\",\n default: \"default\",\n description: \"Action to execute\",\n })\n .option(\"params\", {\n type: \"string\",\n description: \"JSON parameters for the action\",\n }),\n async (argv) => {\n const params = argv.params ? JSON.parse(argv.params) : {};\n\n const runtime = await createRuntime();\n const result = await execCommand(runtime, argv.path!, argv.action!, params);\n const view = getViewType(argv);\n console.log(formatExecOutput(result, view));\n\n if (!result.success) {\n process.exit(ExitCode.RUNTIME_ERROR);\n }\n },\n )\n .command(\n \"mount\",\n \"Manage mount configurations\",\n (yargs) =>\n yargs\n .command(\n [\"list\", \"ls\"],\n \"List all mounts\",\n () => {},\n async (argv) => {\n const result = await mountListCommand(process.cwd());\n const view = getViewType(argv);\n console.log(formatMountListOutput(result.mounts, view));\n },\n )\n .command(\n \"add <path> <uri>\",\n \"Add a new mount (path=virtual path, uri=data source)\",\n (yargs) =>\n yargs\n .positional(\"path\", {\n type: \"string\",\n demandOption: true,\n description: \"Virtual path in AFS namespace (e.g., /src, /data)\",\n })\n .positional(\"uri\", {\n type: \"string\",\n demandOption: true,\n description: \"Data source URI: fs:///local/path, git://repo, sqlite:///db.sqlite\",\n })\n .option(\"description\", {\n type: \"string\",\n description: \"Human-readable description for this mount\",\n }),\n async (argv) => {\n const result = await mountAddCommand(process.cwd(), argv.path!, argv.uri!, {\n description: argv.description,\n });\n const view = getViewType(argv);\n\n if (view === \"json\") {\n console.log(JSON.stringify(result, null, 2));\n } else {\n if (result.success) {\n console.log(`Added mount ${argv.path}`);\n } else {\n console.error(result.message);\n process.exit(ExitCode.RUNTIME_ERROR);\n }\n }\n },\n )\n .command(\n [\"remove <path>\", \"rm <path>\"],\n \"Remove a mount\",\n (yargs) =>\n yargs.positional(\"path\", {\n type: \"string\",\n demandOption: true,\n description: \"Virtual path to remove (e.g., /src)\",\n }),\n async (argv) => {\n const result = await mountRemoveCommand(process.cwd(), argv.path!);\n const view = getViewType(argv);\n\n if (view === \"json\") {\n console.log(JSON.stringify(result, null, 2));\n } else {\n if (result.success) {\n console.log(`Removed mount ${argv.path}`);\n } else {\n console.error(result.message);\n process.exit(ExitCode.RUNTIME_ERROR);\n }\n }\n },\n )\n .command(\n \"validate\",\n \"Validate mount configuration\",\n () => {},\n async (argv) => {\n const result = await mountValidateCommand(process.cwd());\n const view = getViewType(argv);\n\n if (view === \"json\") {\n console.log(JSON.stringify(result, null, 2));\n } else {\n if (result.valid) {\n console.log(\"Configuration is valid\");\n } else {\n console.error(\"Configuration has errors:\");\n for (const error of result.errors) {\n console.error(` - ${error}`);\n }\n process.exit(ExitCode.RUNTIME_ERROR);\n }\n }\n },\n )\n .demandCommand(1, \"Please specify a mount subcommand\"),\n () => {},\n )\n .command(\n \"explain [topic]\",\n \"Explain AFS concepts or AFS object\",\n (yargs) =>\n yargs.positional(\"topic\", {\n type: \"string\",\n description: \"Topic (mount, path, uri) or AFS path (e.g., /modules/src)\",\n }),\n async (argv) => {\n const view = getViewType(argv);\n const topic = argv.topic;\n\n // If topic starts with /, treat as object path\n if (topic?.startsWith(\"/\")) {\n const runtime = await createRuntime();\n const result = await explainPathCommand(runtime, topic);\n console.log(formatPathExplainOutput(result, view));\n } else {\n const result = await explainCommand(process.cwd(), topic);\n console.log(formatExplainOutput(result, view));\n }\n },\n )\n .command(\n \"serve\",\n \"Start HTTP server to expose AFS providers\",\n (yargs) =>\n yargs\n .option(\"host\", {\n type: \"string\",\n default: \"localhost\",\n description: \"Host address to listen on\",\n })\n .option(\"port\", {\n type: \"number\",\n default: 3000,\n description: \"Port to listen on\",\n })\n .option(\"path\", {\n type: \"string\",\n default: \"/afs\",\n description: \"Base path for the server\",\n })\n .option(\"readonly\", {\n type: \"boolean\",\n default: false,\n description: \"Run in readonly mode (disable write operations)\",\n })\n .option(\"cors\", {\n type: \"boolean\",\n default: false,\n description: \"Enable CORS support\",\n })\n .option(\"max-body\", {\n type: \"number\",\n description: \"Maximum request body size in bytes (default: 10MB)\",\n }),\n async (argv) => {\n const result = await serveCommand({\n host: argv.host,\n port: argv.port,\n path: argv.path,\n readonly: argv.readonly,\n cors: argv.cors,\n maxBodySize: argv[\"max-body\"],\n });\n\n console.log(formatServeOutput(result));\n\n // Keep the process running\n await new Promise(() => {});\n },\n )\n .demandCommand(1, \"Please specify a command\")\n .strict();\n\n try {\n await cli.parse();\n } catch (error) {\n if (error instanceof CLIError) {\n console.error(error.message);\n process.exit(error.exitCode);\n }\n throw error;\n }\n}\n\nmain().catch((error) => {\n console.error(\"Fatal error:\", error.message);\n process.exit(ExitCode.RUNTIME_ERROR);\n});\n"],"mappings":"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"}
@@ -0,0 +1,46 @@
1
+
2
+ //#region src/commands/exec.ts
3
+ /**
4
+ * Execute an action on an AFS path
5
+ *
6
+ * Note: exec is not widely implemented by providers yet.
7
+ * This is a placeholder for future functionality.
8
+ */
9
+ async function execCommand(_runtime, path, _action, _params = {}) {
10
+ return {
11
+ path,
12
+ success: false,
13
+ message: "exec operation is not yet implemented"
14
+ };
15
+ }
16
+ /**
17
+ * Format exec output for different views
18
+ */
19
+ function formatExecOutput(result, view) {
20
+ switch (view) {
21
+ case "json": return JSON.stringify(result, null, 2);
22
+ case "llm": return formatLlm(result);
23
+ case "human": return formatHuman(result);
24
+ default: return formatDefault(result);
25
+ }
26
+ }
27
+ function formatDefault(result) {
28
+ if (result.success) return `OK ${result.path}`;
29
+ return `ERROR ${result.path} ${result.message}`;
30
+ }
31
+ function formatLlm(result) {
32
+ const lines = [];
33
+ lines.push(`EXEC ${result.path}`);
34
+ lines.push(`STATUS ${result.success ? "SUCCESS" : "FAILED"}`);
35
+ if (result.data) lines.push(`DATA ${JSON.stringify(result.data)}`);
36
+ if (result.message) lines.push(`MESSAGE ${result.message}`);
37
+ return lines.join("\n");
38
+ }
39
+ function formatHuman(result) {
40
+ if (result.success) return `Executed on ${result.path}\n${result.data ? JSON.stringify(result.data, null, 2) : ""}`;
41
+ return `Failed to execute on ${result.path}: ${result.message}`;
42
+ }
43
+
44
+ //#endregion
45
+ exports.execCommand = execCommand;
46
+ exports.formatExecOutput = formatExecOutput;
@@ -0,0 +1,45 @@
1
+ //#region src/commands/exec.ts
2
+ /**
3
+ * Execute an action on an AFS path
4
+ *
5
+ * Note: exec is not widely implemented by providers yet.
6
+ * This is a placeholder for future functionality.
7
+ */
8
+ async function execCommand(_runtime, path, _action, _params = {}) {
9
+ return {
10
+ path,
11
+ success: false,
12
+ message: "exec operation is not yet implemented"
13
+ };
14
+ }
15
+ /**
16
+ * Format exec output for different views
17
+ */
18
+ function formatExecOutput(result, view) {
19
+ switch (view) {
20
+ case "json": return JSON.stringify(result, null, 2);
21
+ case "llm": return formatLlm(result);
22
+ case "human": return formatHuman(result);
23
+ default: return formatDefault(result);
24
+ }
25
+ }
26
+ function formatDefault(result) {
27
+ if (result.success) return `OK ${result.path}`;
28
+ return `ERROR ${result.path} ${result.message}`;
29
+ }
30
+ function formatLlm(result) {
31
+ const lines = [];
32
+ lines.push(`EXEC ${result.path}`);
33
+ lines.push(`STATUS ${result.success ? "SUCCESS" : "FAILED"}`);
34
+ if (result.data) lines.push(`DATA ${JSON.stringify(result.data)}`);
35
+ if (result.message) lines.push(`MESSAGE ${result.message}`);
36
+ return lines.join("\n");
37
+ }
38
+ function formatHuman(result) {
39
+ if (result.success) return `Executed on ${result.path}\n${result.data ? JSON.stringify(result.data, null, 2) : ""}`;
40
+ return `Failed to execute on ${result.path}: ${result.message}`;
41
+ }
42
+
43
+ //#endregion
44
+ export { execCommand, formatExecOutput };
45
+ //# sourceMappingURL=exec.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"exec.mjs","names":[],"sources":["../../src/commands/exec.ts"],"sourcesContent":["import type { AFSRuntime } from \"../runtime.js\";\nimport type { ViewType } from \"./ls.js\";\n\nexport interface ExecResult {\n path: string;\n success: boolean;\n data?: Record<string, unknown>;\n message?: string;\n}\n\n/**\n * Execute an action on an AFS path\n *\n * Note: exec is not widely implemented by providers yet.\n * This is a placeholder for future functionality.\n */\nexport async function execCommand(\n _runtime: AFSRuntime,\n path: string,\n _action: string,\n _params: Record<string, unknown> = {},\n): Promise<ExecResult> {\n // exec is not yet implemented in the runtime\n // This is a placeholder that returns an error\n\n return {\n path,\n success: false,\n message: \"exec operation is not yet implemented\",\n };\n}\n\n/**\n * Format exec output for different views\n */\nexport function formatExecOutput(result: ExecResult, view: ViewType): string {\n switch (view) {\n case \"json\":\n return JSON.stringify(result, null, 2);\n case \"llm\":\n return formatLlm(result);\n case \"human\":\n return formatHuman(result);\n default:\n return formatDefault(result);\n }\n}\n\nfunction formatDefault(result: ExecResult): string {\n if (result.success) {\n return `OK ${result.path}`;\n }\n return `ERROR ${result.path} ${result.message}`;\n}\n\nfunction formatLlm(result: ExecResult): string {\n const lines: string[] = [];\n\n lines.push(`EXEC ${result.path}`);\n lines.push(`STATUS ${result.success ? \"SUCCESS\" : \"FAILED\"}`);\n\n if (result.data) {\n lines.push(`DATA ${JSON.stringify(result.data)}`);\n }\n\n if (result.message) {\n lines.push(`MESSAGE ${result.message}`);\n }\n\n return lines.join(\"\\n\");\n}\n\nfunction formatHuman(result: ExecResult): string {\n if (result.success) {\n return `Executed on ${result.path}\\n${result.data ? JSON.stringify(result.data, null, 2) : \"\"}`;\n }\n return `Failed to execute on ${result.path}: ${result.message}`;\n}\n"],"mappings":";;;;;;;AAgBA,eAAsB,YACpB,UACA,MACA,SACA,UAAmC,EAAE,EAChB;AAIrB,QAAO;EACL;EACA,SAAS;EACT,SAAS;EACV;;;;;AAMH,SAAgB,iBAAiB,QAAoB,MAAwB;AAC3E,SAAQ,MAAR;EACE,KAAK,OACH,QAAO,KAAK,UAAU,QAAQ,MAAM,EAAE;EACxC,KAAK,MACH,QAAO,UAAU,OAAO;EAC1B,KAAK,QACH,QAAO,YAAY,OAAO;EAC5B,QACE,QAAO,cAAc,OAAO;;;AAIlC,SAAS,cAAc,QAA4B;AACjD,KAAI,OAAO,QACT,QAAO,MAAM,OAAO;AAEtB,QAAO,SAAS,OAAO,KAAK,GAAG,OAAO;;AAGxC,SAAS,UAAU,QAA4B;CAC7C,MAAM,QAAkB,EAAE;AAE1B,OAAM,KAAK,QAAQ,OAAO,OAAO;AACjC,OAAM,KAAK,UAAU,OAAO,UAAU,YAAY,WAAW;AAE7D,KAAI,OAAO,KACT,OAAM,KAAK,QAAQ,KAAK,UAAU,OAAO,KAAK,GAAG;AAGnD,KAAI,OAAO,QACT,OAAM,KAAK,WAAW,OAAO,UAAU;AAGzC,QAAO,MAAM,KAAK,KAAK;;AAGzB,SAAS,YAAY,QAA4B;AAC/C,KAAI,OAAO,QACT,QAAO,eAAe,OAAO,KAAK,IAAI,OAAO,OAAO,KAAK,UAAU,OAAO,MAAM,MAAM,EAAE,GAAG;AAE7F,QAAO,wBAAwB,OAAO,KAAK,IAAI,OAAO"}
@@ -0,0 +1,244 @@
1
+ const require_mount = require('./mount.cjs');
2
+
3
+ //#region src/commands/explain.ts
4
+ /**
5
+ * Explain AFS concepts or current configuration
6
+ */
7
+ async function explainCommand(cwd, topic) {
8
+ switch (topic) {
9
+ case "mount":
10
+ case "mounts": return explainMounts(cwd);
11
+ case "path":
12
+ case "paths": return explainPaths();
13
+ case "uri": return explainUri();
14
+ default: return explainOverview();
15
+ }
16
+ }
17
+ /**
18
+ * Explain an AFS object at a given path
19
+ */
20
+ async function explainPathCommand(runtime, path) {
21
+ const entry = (await runtime.read(path)).data;
22
+ if (!entry) return {
23
+ path,
24
+ type: "unknown"
25
+ };
26
+ const metadata = entry.metadata || {};
27
+ const entryType = metadata.type || "file";
28
+ const result = {
29
+ path: entry.path,
30
+ type: entryType,
31
+ description: metadata.description,
32
+ metadata: {}
33
+ };
34
+ if (metadata.provider) result.metadata.provider = String(metadata.provider);
35
+ if (metadata.permissions) {
36
+ const perms = metadata.permissions;
37
+ result.metadata.permissions = Array.isArray(perms) ? perms.join(", ") : String(perms);
38
+ }
39
+ if (entryType === "exec") {
40
+ if (metadata.inputs) result.inputs = Array.isArray(metadata.inputs) ? metadata.inputs : [String(metadata.inputs)];
41
+ if (metadata.outputs) result.outputs = Array.isArray(metadata.outputs) ? metadata.outputs : [String(metadata.outputs)];
42
+ if (metadata.errors) result.errors = Array.isArray(metadata.errors) ? metadata.errors : [String(metadata.errors)];
43
+ if (metadata.sideEffects) result.sideEffects = Array.isArray(metadata.sideEffects) ? metadata.sideEffects : [String(metadata.sideEffects)];
44
+ }
45
+ if (Object.keys(result.metadata).length === 0) delete result.metadata;
46
+ return result;
47
+ }
48
+ function explainOverview() {
49
+ return {
50
+ topic: "AFS Overview",
51
+ explanation: `AFS (Abstract File System) is a virtual filesystem that unifies different data sources into a single namespace.
52
+
53
+ Core Concepts:
54
+ - mount: Mount a data source to a virtual path
55
+ - path: Virtual path, e.g., /src, /data
56
+ - uri: Data source address, e.g., fs://, git://, sqlite://
57
+
58
+ Data Flow:
59
+ User Path -> AFS -> /modules/{name} -> Provider -> Actual Data`,
60
+ examples: [
61
+ "afs mount add /src fs:///path/to/source",
62
+ "afs ls /modules/src",
63
+ "afs read /modules/src/file.txt"
64
+ ]
65
+ };
66
+ }
67
+ async function explainMounts(cwd) {
68
+ const result = await require_mount.mountListCommand(cwd);
69
+ if (result.mounts.length === 0) return {
70
+ topic: "Mounts",
71
+ explanation: `No mounts configured.
72
+
73
+ Use mount add to add a mount:
74
+ afs mount add <path> <uri>
75
+
76
+ path: Virtual path for accessing data in AFS
77
+ uri: Data source URI specifying the data origin`,
78
+ examples: ["afs mount add /src fs:///Users/me/project", "afs mount add /data sqlite:///data.db"]
79
+ };
80
+ return {
81
+ topic: "Mounts",
82
+ explanation: `Current mount configuration:
83
+
84
+ ${result.mounts.map((m) => ` ${m.path} → ${m.uri}${m.description ? ` (${m.description})` : ""}`).join("\n")}
85
+
86
+ After mounting, data is accessed via /modules/{name}:
87
+ path="/src" -> /modules/src`,
88
+ examples: result.mounts.map((m) => {
89
+ return `afs ls /modules/${m.path.slice(1).replace(/\//g, "-") || "root"}`;
90
+ })
91
+ };
92
+ }
93
+ function explainPaths() {
94
+ return {
95
+ topic: "Paths",
96
+ explanation: `AFS Path Structure:
97
+
98
+ / Root directory
99
+ /modules All mounted modules
100
+ /modules/{name} Specific module, name derived from mount path
101
+
102
+ Path Mapping:
103
+ config: path="/src" -> access: /modules/src
104
+ config: path="/data" -> access: /modules/data
105
+
106
+ Note: The path configured by user is transformed to /modules/{name}`
107
+ };
108
+ }
109
+ function explainUri() {
110
+ return {
111
+ topic: "URI",
112
+ explanation: `AFS URI Schemes and Objects:
113
+
114
+ fs:// Local Filesystem Provider
115
+ Format: fs:///absolute/path or fs://./relative/path
116
+ Objects:
117
+ - directory: folder entries, supports list
118
+ - file: file entries, supports read/write
119
+ Operations: list, read, write, delete
120
+
121
+ git:// Git Repository Provider
122
+ Format: git:///local/repo or git://github.com/user/repo?branch=main
123
+ Objects:
124
+ - directory: tree entries
125
+ - file: blob entries, read-only
126
+ Operations: list, read
127
+
128
+ sqlite:// SQLite Database Provider
129
+ Format: sqlite:///path/to/db.sqlite
130
+ Objects:
131
+ - directory: database root, tables list
132
+ - exec: table entries, supports query operations
133
+ Operations: list, read, exec (SQL queries)
134
+
135
+ json:// JSON Data Provider
136
+ Format: json:///path/to/data.json
137
+ Objects:
138
+ - directory: object/array entries
139
+ - file: primitive values
140
+ Operations: list, read, write`,
141
+ examples: [
142
+ "afs mount add /src fs:///Users/me/project",
143
+ "afs mount add /repo git://github.com/user/repo",
144
+ "afs mount add /db sqlite:///data.sqlite"
145
+ ]
146
+ };
147
+ }
148
+ /**
149
+ * Format explain output for different views
150
+ */
151
+ function formatExplainOutput(result, view) {
152
+ switch (view) {
153
+ case "json": return JSON.stringify(result, null, 2);
154
+ case "llm": return formatLlm(result);
155
+ default: return formatDefault(result);
156
+ }
157
+ }
158
+ function formatDefault(result) {
159
+ let output = `${result.topic}\n${"=".repeat(result.topic.length)}\n\n${result.explanation}`;
160
+ if (result.examples && result.examples.length > 0) output += `\n\nExamples:\n${result.examples.map((e) => ` $ ${e}`).join("\n")}`;
161
+ return output;
162
+ }
163
+ function formatLlm(result) {
164
+ const lines = [
165
+ `TOPIC ${result.topic}`,
166
+ "",
167
+ result.explanation
168
+ ];
169
+ if (result.examples && result.examples.length > 0) {
170
+ lines.push("", "EXAMPLES");
171
+ for (const example of result.examples) lines.push(`CMD ${example}`);
172
+ }
173
+ return lines.join("\n");
174
+ }
175
+ /**
176
+ * Format object explain output for different views
177
+ */
178
+ function formatPathExplainOutput(result, view) {
179
+ switch (view) {
180
+ case "json": return JSON.stringify(result, null, 2);
181
+ case "llm": return formatPathLlm(result);
182
+ default: return formatPathDefault(result);
183
+ }
184
+ }
185
+ function formatPathDefault(result) {
186
+ const lines = [];
187
+ lines.push(`PATH ${result.path}`);
188
+ lines.push("");
189
+ lines.push("TYPE");
190
+ lines.push(result.type);
191
+ if (result.description) {
192
+ lines.push("");
193
+ lines.push("DESCRIPTION");
194
+ lines.push(result.description);
195
+ }
196
+ if (result.inputs && result.inputs.length > 0) {
197
+ lines.push("");
198
+ lines.push("INPUTS");
199
+ for (const input of result.inputs) lines.push(`- ${input}`);
200
+ }
201
+ if (result.outputs && result.outputs.length > 0) {
202
+ lines.push("");
203
+ lines.push("OUTPUTS");
204
+ for (const output of result.outputs) lines.push(`- ${output}`);
205
+ }
206
+ if (result.errors && result.errors.length > 0) {
207
+ lines.push("");
208
+ lines.push("ERRORS");
209
+ for (const error of result.errors) lines.push(`- ${error}`);
210
+ }
211
+ if (result.sideEffects && result.sideEffects.length > 0) {
212
+ lines.push("");
213
+ lines.push("SIDE EFFECTS");
214
+ for (const effect of result.sideEffects) lines.push(`- ${effect}`);
215
+ } else {
216
+ lines.push("");
217
+ lines.push("SIDE EFFECTS");
218
+ lines.push("- none");
219
+ }
220
+ if (result.metadata && Object.keys(result.metadata).length > 0) {
221
+ lines.push("");
222
+ lines.push("METADATA");
223
+ for (const [key, value] of Object.entries(result.metadata)) lines.push(`- ${key}: ${value}`);
224
+ }
225
+ return lines.join("\n");
226
+ }
227
+ function formatPathLlm(result) {
228
+ const lines = [];
229
+ lines.push(`PATH ${result.path}`);
230
+ lines.push(`TYPE ${result.type.toUpperCase()}`);
231
+ if (result.description) lines.push(`DESC ${result.description}`);
232
+ if (result.inputs && result.inputs.length > 0) lines.push(`INPUTS ${result.inputs.join(", ")}`);
233
+ if (result.outputs && result.outputs.length > 0) lines.push(`OUTPUTS ${result.outputs.join(", ")}`);
234
+ if (result.errors && result.errors.length > 0) lines.push(`ERRORS ${result.errors.join(", ")}`);
235
+ lines.push(`SIDE_EFFECTS ${result.sideEffects?.join(", ") || "none"}`);
236
+ if (result.metadata) for (const [key, value] of Object.entries(result.metadata)) lines.push(`${key.toUpperCase()} ${value}`);
237
+ return lines.join("\n");
238
+ }
239
+
240
+ //#endregion
241
+ exports.explainCommand = explainCommand;
242
+ exports.explainPathCommand = explainPathCommand;
243
+ exports.formatExplainOutput = formatExplainOutput;
244
+ exports.formatPathExplainOutput = formatPathExplainOutput;
@@ -0,0 +1,242 @@
1
+ import { mountListCommand } from "./mount.mjs";
2
+
3
+ //#region src/commands/explain.ts
4
+ /**
5
+ * Explain AFS concepts or current configuration
6
+ */
7
+ async function explainCommand(cwd, topic) {
8
+ switch (topic) {
9
+ case "mount":
10
+ case "mounts": return explainMounts(cwd);
11
+ case "path":
12
+ case "paths": return explainPaths();
13
+ case "uri": return explainUri();
14
+ default: return explainOverview();
15
+ }
16
+ }
17
+ /**
18
+ * Explain an AFS object at a given path
19
+ */
20
+ async function explainPathCommand(runtime, path) {
21
+ const entry = (await runtime.read(path)).data;
22
+ if (!entry) return {
23
+ path,
24
+ type: "unknown"
25
+ };
26
+ const metadata = entry.metadata || {};
27
+ const entryType = metadata.type || "file";
28
+ const result = {
29
+ path: entry.path,
30
+ type: entryType,
31
+ description: metadata.description,
32
+ metadata: {}
33
+ };
34
+ if (metadata.provider) result.metadata.provider = String(metadata.provider);
35
+ if (metadata.permissions) {
36
+ const perms = metadata.permissions;
37
+ result.metadata.permissions = Array.isArray(perms) ? perms.join(", ") : String(perms);
38
+ }
39
+ if (entryType === "exec") {
40
+ if (metadata.inputs) result.inputs = Array.isArray(metadata.inputs) ? metadata.inputs : [String(metadata.inputs)];
41
+ if (metadata.outputs) result.outputs = Array.isArray(metadata.outputs) ? metadata.outputs : [String(metadata.outputs)];
42
+ if (metadata.errors) result.errors = Array.isArray(metadata.errors) ? metadata.errors : [String(metadata.errors)];
43
+ if (metadata.sideEffects) result.sideEffects = Array.isArray(metadata.sideEffects) ? metadata.sideEffects : [String(metadata.sideEffects)];
44
+ }
45
+ if (Object.keys(result.metadata).length === 0) delete result.metadata;
46
+ return result;
47
+ }
48
+ function explainOverview() {
49
+ return {
50
+ topic: "AFS Overview",
51
+ explanation: `AFS (Abstract File System) is a virtual filesystem that unifies different data sources into a single namespace.
52
+
53
+ Core Concepts:
54
+ - mount: Mount a data source to a virtual path
55
+ - path: Virtual path, e.g., /src, /data
56
+ - uri: Data source address, e.g., fs://, git://, sqlite://
57
+
58
+ Data Flow:
59
+ User Path -> AFS -> /modules/{name} -> Provider -> Actual Data`,
60
+ examples: [
61
+ "afs mount add /src fs:///path/to/source",
62
+ "afs ls /modules/src",
63
+ "afs read /modules/src/file.txt"
64
+ ]
65
+ };
66
+ }
67
+ async function explainMounts(cwd) {
68
+ const result = await mountListCommand(cwd);
69
+ if (result.mounts.length === 0) return {
70
+ topic: "Mounts",
71
+ explanation: `No mounts configured.
72
+
73
+ Use mount add to add a mount:
74
+ afs mount add <path> <uri>
75
+
76
+ path: Virtual path for accessing data in AFS
77
+ uri: Data source URI specifying the data origin`,
78
+ examples: ["afs mount add /src fs:///Users/me/project", "afs mount add /data sqlite:///data.db"]
79
+ };
80
+ return {
81
+ topic: "Mounts",
82
+ explanation: `Current mount configuration:
83
+
84
+ ${result.mounts.map((m) => ` ${m.path} → ${m.uri}${m.description ? ` (${m.description})` : ""}`).join("\n")}
85
+
86
+ After mounting, data is accessed via /modules/{name}:
87
+ path="/src" -> /modules/src`,
88
+ examples: result.mounts.map((m) => {
89
+ return `afs ls /modules/${m.path.slice(1).replace(/\//g, "-") || "root"}`;
90
+ })
91
+ };
92
+ }
93
+ function explainPaths() {
94
+ return {
95
+ topic: "Paths",
96
+ explanation: `AFS Path Structure:
97
+
98
+ / Root directory
99
+ /modules All mounted modules
100
+ /modules/{name} Specific module, name derived from mount path
101
+
102
+ Path Mapping:
103
+ config: path="/src" -> access: /modules/src
104
+ config: path="/data" -> access: /modules/data
105
+
106
+ Note: The path configured by user is transformed to /modules/{name}`
107
+ };
108
+ }
109
+ function explainUri() {
110
+ return {
111
+ topic: "URI",
112
+ explanation: `AFS URI Schemes and Objects:
113
+
114
+ fs:// Local Filesystem Provider
115
+ Format: fs:///absolute/path or fs://./relative/path
116
+ Objects:
117
+ - directory: folder entries, supports list
118
+ - file: file entries, supports read/write
119
+ Operations: list, read, write, delete
120
+
121
+ git:// Git Repository Provider
122
+ Format: git:///local/repo or git://github.com/user/repo?branch=main
123
+ Objects:
124
+ - directory: tree entries
125
+ - file: blob entries, read-only
126
+ Operations: list, read
127
+
128
+ sqlite:// SQLite Database Provider
129
+ Format: sqlite:///path/to/db.sqlite
130
+ Objects:
131
+ - directory: database root, tables list
132
+ - exec: table entries, supports query operations
133
+ Operations: list, read, exec (SQL queries)
134
+
135
+ json:// JSON Data Provider
136
+ Format: json:///path/to/data.json
137
+ Objects:
138
+ - directory: object/array entries
139
+ - file: primitive values
140
+ Operations: list, read, write`,
141
+ examples: [
142
+ "afs mount add /src fs:///Users/me/project",
143
+ "afs mount add /repo git://github.com/user/repo",
144
+ "afs mount add /db sqlite:///data.sqlite"
145
+ ]
146
+ };
147
+ }
148
+ /**
149
+ * Format explain output for different views
150
+ */
151
+ function formatExplainOutput(result, view) {
152
+ switch (view) {
153
+ case "json": return JSON.stringify(result, null, 2);
154
+ case "llm": return formatLlm(result);
155
+ default: return formatDefault(result);
156
+ }
157
+ }
158
+ function formatDefault(result) {
159
+ let output = `${result.topic}\n${"=".repeat(result.topic.length)}\n\n${result.explanation}`;
160
+ if (result.examples && result.examples.length > 0) output += `\n\nExamples:\n${result.examples.map((e) => ` $ ${e}`).join("\n")}`;
161
+ return output;
162
+ }
163
+ function formatLlm(result) {
164
+ const lines = [
165
+ `TOPIC ${result.topic}`,
166
+ "",
167
+ result.explanation
168
+ ];
169
+ if (result.examples && result.examples.length > 0) {
170
+ lines.push("", "EXAMPLES");
171
+ for (const example of result.examples) lines.push(`CMD ${example}`);
172
+ }
173
+ return lines.join("\n");
174
+ }
175
+ /**
176
+ * Format object explain output for different views
177
+ */
178
+ function formatPathExplainOutput(result, view) {
179
+ switch (view) {
180
+ case "json": return JSON.stringify(result, null, 2);
181
+ case "llm": return formatPathLlm(result);
182
+ default: return formatPathDefault(result);
183
+ }
184
+ }
185
+ function formatPathDefault(result) {
186
+ const lines = [];
187
+ lines.push(`PATH ${result.path}`);
188
+ lines.push("");
189
+ lines.push("TYPE");
190
+ lines.push(result.type);
191
+ if (result.description) {
192
+ lines.push("");
193
+ lines.push("DESCRIPTION");
194
+ lines.push(result.description);
195
+ }
196
+ if (result.inputs && result.inputs.length > 0) {
197
+ lines.push("");
198
+ lines.push("INPUTS");
199
+ for (const input of result.inputs) lines.push(`- ${input}`);
200
+ }
201
+ if (result.outputs && result.outputs.length > 0) {
202
+ lines.push("");
203
+ lines.push("OUTPUTS");
204
+ for (const output of result.outputs) lines.push(`- ${output}`);
205
+ }
206
+ if (result.errors && result.errors.length > 0) {
207
+ lines.push("");
208
+ lines.push("ERRORS");
209
+ for (const error of result.errors) lines.push(`- ${error}`);
210
+ }
211
+ if (result.sideEffects && result.sideEffects.length > 0) {
212
+ lines.push("");
213
+ lines.push("SIDE EFFECTS");
214
+ for (const effect of result.sideEffects) lines.push(`- ${effect}`);
215
+ } else {
216
+ lines.push("");
217
+ lines.push("SIDE EFFECTS");
218
+ lines.push("- none");
219
+ }
220
+ if (result.metadata && Object.keys(result.metadata).length > 0) {
221
+ lines.push("");
222
+ lines.push("METADATA");
223
+ for (const [key, value] of Object.entries(result.metadata)) lines.push(`- ${key}: ${value}`);
224
+ }
225
+ return lines.join("\n");
226
+ }
227
+ function formatPathLlm(result) {
228
+ const lines = [];
229
+ lines.push(`PATH ${result.path}`);
230
+ lines.push(`TYPE ${result.type.toUpperCase()}`);
231
+ if (result.description) lines.push(`DESC ${result.description}`);
232
+ if (result.inputs && result.inputs.length > 0) lines.push(`INPUTS ${result.inputs.join(", ")}`);
233
+ if (result.outputs && result.outputs.length > 0) lines.push(`OUTPUTS ${result.outputs.join(", ")}`);
234
+ if (result.errors && result.errors.length > 0) lines.push(`ERRORS ${result.errors.join(", ")}`);
235
+ lines.push(`SIDE_EFFECTS ${result.sideEffects?.join(", ") || "none"}`);
236
+ if (result.metadata) for (const [key, value] of Object.entries(result.metadata)) lines.push(`${key.toUpperCase()} ${value}`);
237
+ return lines.join("\n");
238
+ }
239
+
240
+ //#endregion
241
+ export { explainCommand, explainPathCommand, formatExplainOutput, formatPathExplainOutput };
242
+ //# sourceMappingURL=explain.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"explain.mjs","names":[],"sources":["../../src/commands/explain.ts"],"sourcesContent":["import type { AFSRuntime } from \"../runtime.js\";\nimport type { ViewType } from \"./ls.js\";\nimport { mountListCommand } from \"./mount.js\";\n\nexport interface ExplainResult {\n topic: string;\n explanation: string;\n examples?: string[];\n}\n\nexport interface PathExplainResult {\n path: string;\n type: string;\n description?: string;\n inputs?: string[];\n outputs?: string[];\n errors?: string[];\n sideEffects?: string[];\n metadata?: Record<string, string>;\n}\n\n/**\n * Explain AFS concepts or current configuration\n */\nexport async function explainCommand(cwd: string, topic?: string): Promise<ExplainResult> {\n switch (topic) {\n case \"mount\":\n case \"mounts\":\n return explainMounts(cwd);\n case \"path\":\n case \"paths\":\n return explainPaths();\n case \"uri\":\n return explainUri();\n default:\n return explainOverview();\n }\n}\n\n/**\n * Explain an AFS object at a given path\n */\nexport async function explainPathCommand(\n runtime: AFSRuntime,\n path: string,\n): Promise<PathExplainResult> {\n const readResult = await runtime.read(path);\n const entry = readResult.data;\n\n if (!entry) {\n return {\n path,\n type: \"unknown\",\n };\n }\n\n const metadata = entry.metadata || {};\n const entryType = (metadata.type as string) || \"file\";\n\n const result: PathExplainResult = {\n path: entry.path,\n type: entryType,\n description: metadata.description as string | undefined,\n metadata: {},\n };\n\n // Add metadata\n if (metadata.provider) {\n result.metadata!.provider = String(metadata.provider);\n }\n if (metadata.permissions) {\n const perms = metadata.permissions;\n result.metadata!.permissions = Array.isArray(perms) ? perms.join(\", \") : String(perms);\n }\n\n // For exec type, try to get schema info\n if (entryType === \"exec\") {\n if (metadata.inputs) {\n result.inputs = Array.isArray(metadata.inputs)\n ? (metadata.inputs as string[])\n : [String(metadata.inputs)];\n }\n if (metadata.outputs) {\n result.outputs = Array.isArray(metadata.outputs)\n ? (metadata.outputs as string[])\n : [String(metadata.outputs)];\n }\n if (metadata.errors) {\n result.errors = Array.isArray(metadata.errors)\n ? (metadata.errors as string[])\n : [String(metadata.errors)];\n }\n if (metadata.sideEffects) {\n result.sideEffects = Array.isArray(metadata.sideEffects)\n ? (metadata.sideEffects as string[])\n : [String(metadata.sideEffects)];\n }\n }\n\n // Clean up empty metadata\n if (Object.keys(result.metadata!).length === 0) {\n delete result.metadata;\n }\n\n return result;\n}\n\nfunction explainOverview(): ExplainResult {\n return {\n topic: \"AFS Overview\",\n explanation: `AFS (Abstract File System) is a virtual filesystem that unifies different data sources into a single namespace.\n\nCore Concepts:\n- mount: Mount a data source to a virtual path\n- path: Virtual path, e.g., /src, /data\n- uri: Data source address, e.g., fs://, git://, sqlite://\n\nData Flow:\n User Path -> AFS -> /modules/{name} -> Provider -> Actual Data`,\n examples: [\n \"afs mount add /src fs:///path/to/source\",\n \"afs ls /modules/src\",\n \"afs read /modules/src/file.txt\",\n ],\n };\n}\n\nasync function explainMounts(cwd: string): Promise<ExplainResult> {\n const result = await mountListCommand(cwd);\n\n if (result.mounts.length === 0) {\n return {\n topic: \"Mounts\",\n explanation: `No mounts configured.\n\nUse mount add to add a mount:\n afs mount add <path> <uri>\n\npath: Virtual path for accessing data in AFS\nuri: Data source URI specifying the data origin`,\n examples: [\n \"afs mount add /src fs:///Users/me/project\",\n \"afs mount add /data sqlite:///data.db\",\n ],\n };\n }\n\n const mountList = result.mounts\n .map((m) => ` ${m.path} → ${m.uri}${m.description ? ` (${m.description})` : \"\"}`)\n .join(\"\\n\");\n\n return {\n topic: \"Mounts\",\n explanation: `Current mount configuration:\n\n${mountList}\n\nAfter mounting, data is accessed via /modules/{name}:\n path=\"/src\" -> /modules/src`,\n examples: result.mounts.map((m) => {\n const name = m.path.slice(1).replace(/\\//g, \"-\") || \"root\";\n return `afs ls /modules/${name}`;\n }),\n };\n}\n\nfunction explainPaths(): ExplainResult {\n return {\n topic: \"Paths\",\n explanation: `AFS Path Structure:\n\n/ Root directory\n/modules All mounted modules\n/modules/{name} Specific module, name derived from mount path\n\nPath Mapping:\n config: path=\"/src\" -> access: /modules/src\n config: path=\"/data\" -> access: /modules/data\n\nNote: The path configured by user is transformed to /modules/{name}`,\n };\n}\n\nfunction explainUri(): ExplainResult {\n return {\n topic: \"URI\",\n explanation: `AFS URI Schemes and Objects:\n\nfs:// Local Filesystem Provider\n Format: fs:///absolute/path or fs://./relative/path\n Objects:\n - directory: folder entries, supports list\n - file: file entries, supports read/write\n Operations: list, read, write, delete\n\ngit:// Git Repository Provider\n Format: git:///local/repo or git://github.com/user/repo?branch=main\n Objects:\n - directory: tree entries\n - file: blob entries, read-only\n Operations: list, read\n\nsqlite:// SQLite Database Provider\n Format: sqlite:///path/to/db.sqlite\n Objects:\n - directory: database root, tables list\n - exec: table entries, supports query operations\n Operations: list, read, exec (SQL queries)\n\njson:// JSON Data Provider\n Format: json:///path/to/data.json\n Objects:\n - directory: object/array entries\n - file: primitive values\n Operations: list, read, write`,\n examples: [\n \"afs mount add /src fs:///Users/me/project\",\n \"afs mount add /repo git://github.com/user/repo\",\n \"afs mount add /db sqlite:///data.sqlite\",\n ],\n };\n}\n\n/**\n * Format explain output for different views\n */\nexport function formatExplainOutput(result: ExplainResult, view: ViewType): string {\n switch (view) {\n case \"json\":\n return JSON.stringify(result, null, 2);\n case \"llm\":\n return formatLlm(result);\n default:\n return formatDefault(result);\n }\n}\n\nfunction formatDefault(result: ExplainResult): string {\n let output = `${result.topic}\\n${\"=\".repeat(result.topic.length)}\\n\\n${result.explanation}`;\n\n if (result.examples && result.examples.length > 0) {\n output += `\\n\\nExamples:\\n${result.examples.map((e) => ` $ ${e}`).join(\"\\n\")}`;\n }\n\n return output;\n}\n\nfunction formatLlm(result: ExplainResult): string {\n const lines = [`TOPIC ${result.topic}`, \"\", result.explanation];\n\n if (result.examples && result.examples.length > 0) {\n lines.push(\"\", \"EXAMPLES\");\n for (const example of result.examples) {\n lines.push(`CMD ${example}`);\n }\n }\n\n return lines.join(\"\\n\");\n}\n\n/**\n * Format object explain output for different views\n */\nexport function formatPathExplainOutput(result: PathExplainResult, view: ViewType): string {\n switch (view) {\n case \"json\":\n return JSON.stringify(result, null, 2);\n case \"llm\":\n return formatPathLlm(result);\n default:\n return formatPathDefault(result);\n }\n}\n\nfunction formatPathDefault(result: PathExplainResult): string {\n const lines: string[] = [];\n\n lines.push(`PATH ${result.path}`);\n lines.push(\"\");\n lines.push(\"TYPE\");\n lines.push(result.type);\n\n if (result.description) {\n lines.push(\"\");\n lines.push(\"DESCRIPTION\");\n lines.push(result.description);\n }\n\n if (result.inputs && result.inputs.length > 0) {\n lines.push(\"\");\n lines.push(\"INPUTS\");\n for (const input of result.inputs) {\n lines.push(`- ${input}`);\n }\n }\n\n if (result.outputs && result.outputs.length > 0) {\n lines.push(\"\");\n lines.push(\"OUTPUTS\");\n for (const output of result.outputs) {\n lines.push(`- ${output}`);\n }\n }\n\n if (result.errors && result.errors.length > 0) {\n lines.push(\"\");\n lines.push(\"ERRORS\");\n for (const error of result.errors) {\n lines.push(`- ${error}`);\n }\n }\n\n if (result.sideEffects && result.sideEffects.length > 0) {\n lines.push(\"\");\n lines.push(\"SIDE EFFECTS\");\n for (const effect of result.sideEffects) {\n lines.push(`- ${effect}`);\n }\n } else {\n lines.push(\"\");\n lines.push(\"SIDE EFFECTS\");\n lines.push(\"- none\");\n }\n\n if (result.metadata && Object.keys(result.metadata).length > 0) {\n lines.push(\"\");\n lines.push(\"METADATA\");\n for (const [key, value] of Object.entries(result.metadata)) {\n lines.push(`- ${key}: ${value}`);\n }\n }\n\n return lines.join(\"\\n\");\n}\n\nfunction formatPathLlm(result: PathExplainResult): string {\n const lines: string[] = [];\n\n lines.push(`PATH ${result.path}`);\n lines.push(`TYPE ${result.type.toUpperCase()}`);\n\n if (result.description) {\n lines.push(`DESC ${result.description}`);\n }\n\n if (result.inputs && result.inputs.length > 0) {\n lines.push(`INPUTS ${result.inputs.join(\", \")}`);\n }\n\n if (result.outputs && result.outputs.length > 0) {\n lines.push(`OUTPUTS ${result.outputs.join(\", \")}`);\n }\n\n if (result.errors && result.errors.length > 0) {\n lines.push(`ERRORS ${result.errors.join(\", \")}`);\n }\n\n lines.push(`SIDE_EFFECTS ${result.sideEffects?.join(\", \") || \"none\"}`);\n\n if (result.metadata) {\n for (const [key, value] of Object.entries(result.metadata)) {\n lines.push(`${key.toUpperCase()} ${value}`);\n }\n }\n\n return lines.join(\"\\n\");\n}\n"],"mappings":"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"}