@aigne/afs-cli 1.11.0-beta.5 → 1.11.0-beta.6

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 (62) hide show
  1. package/dist/cli.cjs +41 -18
  2. package/dist/cli.mjs +42 -19
  3. package/dist/cli.mjs.map +1 -1
  4. package/dist/commands/exec.cjs +132 -14
  5. package/dist/commands/exec.mjs +129 -14
  6. package/dist/commands/exec.mjs.map +1 -1
  7. package/dist/commands/explain.cjs +1 -1
  8. package/dist/commands/explain.mjs +1 -1
  9. package/dist/commands/explain.mjs.map +1 -1
  10. package/dist/commands/index.mjs +1 -1
  11. package/dist/commands/ls.cjs +129 -30
  12. package/dist/commands/ls.mjs +129 -30
  13. package/dist/commands/ls.mjs.map +1 -1
  14. package/dist/commands/read.cjs +213 -14
  15. package/dist/commands/read.mjs +213 -14
  16. package/dist/commands/read.mjs.map +1 -1
  17. package/dist/commands/stat.cjs +116 -34
  18. package/dist/commands/stat.mjs +117 -34
  19. package/dist/commands/stat.mjs.map +1 -1
  20. package/dist/commands/write.cjs +37 -4
  21. package/dist/commands/write.mjs +38 -4
  22. package/dist/commands/write.mjs.map +1 -1
  23. package/dist/config/loader.cjs +12 -1
  24. package/dist/config/loader.mjs +12 -1
  25. package/dist/config/loader.mjs.map +1 -1
  26. package/dist/config/provider-factory.cjs +310 -3
  27. package/dist/config/provider-factory.mjs +310 -3
  28. package/dist/config/provider-factory.mjs.map +1 -1
  29. package/dist/config/uri-parser.cjs +195 -2
  30. package/dist/config/uri-parser.mjs +195 -2
  31. package/dist/config/uri-parser.mjs.map +1 -1
  32. package/dist/explorer/actions.cjs +53 -23
  33. package/dist/explorer/actions.mjs +54 -23
  34. package/dist/explorer/actions.mjs.map +1 -1
  35. package/dist/explorer/components/dialog.cjs +163 -10
  36. package/dist/explorer/components/dialog.mjs +163 -10
  37. package/dist/explorer/components/dialog.mjs.map +1 -1
  38. package/dist/explorer/components/file-list.mjs.map +1 -1
  39. package/dist/explorer/components/metadata-panel.cjs +39 -25
  40. package/dist/explorer/components/metadata-panel.mjs +39 -25
  41. package/dist/explorer/components/metadata-panel.mjs.map +1 -1
  42. package/dist/explorer/screen.cjs +23 -8
  43. package/dist/explorer/screen.mjs +24 -9
  44. package/dist/explorer/screen.mjs.map +1 -1
  45. package/dist/explorer/theme.cjs +3 -1
  46. package/dist/explorer/theme.mjs +3 -1
  47. package/dist/explorer/theme.mjs.map +1 -1
  48. package/dist/path-utils.cjs +2 -1
  49. package/dist/path-utils.mjs +1 -1
  50. package/dist/runtime.cjs +24 -0
  51. package/dist/runtime.mjs +24 -0
  52. package/dist/runtime.mjs.map +1 -1
  53. package/dist/ui/header.cjs +0 -9
  54. package/dist/ui/header.mjs +1 -9
  55. package/dist/ui/header.mjs.map +1 -1
  56. package/dist/ui/index.cjs +0 -2
  57. package/dist/ui/index.mjs +2 -3
  58. package/dist/ui/index.mjs.map +1 -1
  59. package/dist/utils/meta.cjs +51 -0
  60. package/dist/utils/meta.mjs +49 -0
  61. package/dist/utils/meta.mjs.map +1 -0
  62. package/package.json +19 -9
package/dist/cli.cjs CHANGED
@@ -122,13 +122,15 @@ async function main() {
122
122
  }), async (argv) => {
123
123
  const view = getViewType(argv);
124
124
  await maybeShowHeader(view);
125
- const result = await require_ls.lsCommand(await require_runtime.createRuntime(), argv.path, {
125
+ const runtime = await require_runtime.createRuntime();
126
+ const path = argv.path;
127
+ const result = await require_ls.lsCommand(runtime, path, {
126
128
  maxDepth: argv.depth,
127
129
  limit: argv.limit,
128
130
  maxChildren: argv["max-children"],
129
131
  pattern: argv.pattern
130
132
  });
131
- console.log(require_ls.formatLsOutput(result, view));
133
+ console.log(require_ls.formatLsOutput(result, view, { path }));
132
134
  }).command("stat <path>", "Get file or directory info", (yargs$2) => yargs$2.positional("path", {
133
135
  type: "string",
134
136
  demandOption: true,
@@ -158,35 +160,45 @@ async function main() {
158
160
  type: "boolean",
159
161
  default: false,
160
162
  description: "Append to file instead of overwrite"
163
+ }).option("set", {
164
+ type: "array",
165
+ string: true,
166
+ description: "Set metadata field (format: key=value), can be repeated"
161
167
  }), async (argv) => {
162
168
  const view = getViewType(argv);
163
169
  await maybeShowHeader(view);
164
170
  let content;
165
171
  if (argv.content !== void 0) content = argv.content;
172
+ else if (argv.set && argv.set.length > 0) content = void 0;
166
173
  else {
167
174
  const chunks = [];
168
175
  for await (const chunk of process.stdin) chunks.push(chunk);
169
176
  content = Buffer.concat(chunks).toString("utf-8");
170
177
  }
171
- const result = await require_write.writeCommand(await require_runtime.createRuntime(), argv.path, content, { append: argv.append });
178
+ const result = await require_write.writeCommand(await require_runtime.createRuntime(), argv.path, content, {
179
+ append: argv.append,
180
+ set: argv.set
181
+ });
172
182
  console.log(require_write.formatWriteOutput(result, view));
173
183
  if (!result.success) process.exit(require_errors.ExitCode.RUNTIME_ERROR);
174
- }).command("exec <path> [action]", "Execute operation on path", (yargs$2) => yargs$2.positional("path", {
184
+ }).command("exec <path>", "Execute an executable path (e.g., MCP tool)", (yargs$2) => yargs$2.positional("path", {
175
185
  type: "string",
176
186
  demandOption: true,
177
- description: "Path to execute on"
178
- }).positional("action", {
179
- type: "string",
180
- default: "default",
181
- description: "Action to execute"
182
- }).option("params", {
187
+ description: "Path to execute (must be executable)"
188
+ }).option("args", {
183
189
  type: "string",
184
- description: "JSON parameters for the action"
185
- }), async (argv) => {
186
- const view = getViewType(argv);
190
+ description: "JSON arguments: --args '{\"key\": \"value\"}'"
191
+ }).option("yaml", {
192
+ type: "boolean",
193
+ description: "Output in YAML format"
194
+ }).example("$0 exec /modules/mcp/tools/echo --message hello", "Execute with named param").example("$0 exec /modules/mcp/tools/query --args '{\"sql\": \"SELECT 1\"}'", "Execute with JSON args").strict(false), async (argv) => {
195
+ let view = "human";
196
+ if (argv.json) view = "json";
197
+ else if (argv.yaml) view = "yaml";
198
+ else if (argv.view) view = argv.view;
187
199
  await maybeShowHeader(view);
188
- const params = argv.params ? JSON.parse(argv.params) : {};
189
- const result = await require_exec.execCommand(await require_runtime.createRuntime(), argv.path, argv.action, params);
200
+ const args = await require_exec.parseExecArgsWithStdin(argv);
201
+ const result = await require_exec.execCommand(await require_runtime.createRuntime(), argv.path, args);
190
202
  console.log(require_exec.formatExecOutput(result, view));
191
203
  if (!result.success) process.exit(require_errors.ExitCode.RUNTIME_ERROR);
192
204
  }).command("mount", "Manage mount configurations", (yargs$2) => yargs$2.command(["list", "ls"], "List all mounts", () => {}, async (argv) => {
@@ -335,9 +347,20 @@ async function main() {
335
347
  throw error;
336
348
  }
337
349
  }
338
- main().catch((error) => {
339
- console.error("Fatal error:", error.message);
340
- process.exit(require_errors.ExitCode.RUNTIME_ERROR);
350
+ /**
351
+ * Format error message for display
352
+ */
353
+ function formatErrorForDisplay(error) {
354
+ const message = error.message;
355
+ const lines = message.split("\n");
356
+ if (lines.length > 1) return lines.map((line, i) => i === 0 ? `${require_index.colors.red("Error:")} ${line}` : ` ${line}`).join("\n");
357
+ return `${require_index.colors.red("Error:")} ${message}`;
358
+ }
359
+ main().then(() => {
360
+ process.exit(0);
361
+ }).catch((error) => {
362
+ console.error(formatErrorForDisplay(error));
363
+ process.exit(error instanceof require_errors.CLIError ? error.exitCode : require_errors.ExitCode.RUNTIME_ERROR);
341
364
  });
342
365
 
343
366
  //#endregion
package/dist/cli.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import { VERSION } from "./version.mjs";
3
- import { execCommand, formatExecOutput } from "./commands/exec.mjs";
3
+ import { execCommand, formatExecOutput, parseExecArgsWithStdin } from "./commands/exec.mjs";
4
4
  import { ConfigLoader } from "./config/loader.mjs";
5
5
  import { colors, printHeader, shouldShowHeader } from "./ui/index.mjs";
6
6
  import { formatMountListOutput, mountAddCommand, mountListCommand, mountRemoveCommand, mountValidateCommand } from "./commands/mount.mjs";
@@ -120,13 +120,15 @@ async function main() {
120
120
  }), async (argv) => {
121
121
  const view = getViewType(argv);
122
122
  await maybeShowHeader(view);
123
- const result = await lsCommand(await createRuntime(), argv.path, {
123
+ const runtime = await createRuntime();
124
+ const path = argv.path;
125
+ const result = await lsCommand(runtime, path, {
124
126
  maxDepth: argv.depth,
125
127
  limit: argv.limit,
126
128
  maxChildren: argv["max-children"],
127
129
  pattern: argv.pattern
128
130
  });
129
- console.log(formatLsOutput(result, view));
131
+ console.log(formatLsOutput(result, view, { path }));
130
132
  }).command("stat <path>", "Get file or directory info", (yargs$1) => yargs$1.positional("path", {
131
133
  type: "string",
132
134
  demandOption: true,
@@ -156,35 +158,45 @@ async function main() {
156
158
  type: "boolean",
157
159
  default: false,
158
160
  description: "Append to file instead of overwrite"
161
+ }).option("set", {
162
+ type: "array",
163
+ string: true,
164
+ description: "Set metadata field (format: key=value), can be repeated"
159
165
  }), async (argv) => {
160
166
  const view = getViewType(argv);
161
167
  await maybeShowHeader(view);
162
168
  let content;
163
169
  if (argv.content !== void 0) content = argv.content;
170
+ else if (argv.set && argv.set.length > 0) content = void 0;
164
171
  else {
165
172
  const chunks = [];
166
173
  for await (const chunk of process.stdin) chunks.push(chunk);
167
174
  content = Buffer.concat(chunks).toString("utf-8");
168
175
  }
169
- const result = await writeCommand(await createRuntime(), argv.path, content, { append: argv.append });
176
+ const result = await writeCommand(await createRuntime(), argv.path, content, {
177
+ append: argv.append,
178
+ set: argv.set
179
+ });
170
180
  console.log(formatWriteOutput(result, view));
171
181
  if (!result.success) process.exit(ExitCode.RUNTIME_ERROR);
172
- }).command("exec <path> [action]", "Execute operation on path", (yargs$1) => yargs$1.positional("path", {
182
+ }).command("exec <path>", "Execute an executable path (e.g., MCP tool)", (yargs$1) => yargs$1.positional("path", {
173
183
  type: "string",
174
184
  demandOption: true,
175
- description: "Path to execute on"
176
- }).positional("action", {
177
- type: "string",
178
- default: "default",
179
- description: "Action to execute"
180
- }).option("params", {
185
+ description: "Path to execute (must be executable)"
186
+ }).option("args", {
181
187
  type: "string",
182
- description: "JSON parameters for the action"
183
- }), async (argv) => {
184
- const view = getViewType(argv);
188
+ description: "JSON arguments: --args '{\"key\": \"value\"}'"
189
+ }).option("yaml", {
190
+ type: "boolean",
191
+ description: "Output in YAML format"
192
+ }).example("$0 exec /modules/mcp/tools/echo --message hello", "Execute with named param").example("$0 exec /modules/mcp/tools/query --args '{\"sql\": \"SELECT 1\"}'", "Execute with JSON args").strict(false), async (argv) => {
193
+ let view = "human";
194
+ if (argv.json) view = "json";
195
+ else if (argv.yaml) view = "yaml";
196
+ else if (argv.view) view = argv.view;
185
197
  await maybeShowHeader(view);
186
- const params = argv.params ? JSON.parse(argv.params) : {};
187
- const result = await execCommand(await createRuntime(), argv.path, argv.action, params);
198
+ const args = await parseExecArgsWithStdin(argv);
199
+ const result = await execCommand(await createRuntime(), argv.path, args);
188
200
  console.log(formatExecOutput(result, view));
189
201
  if (!result.success) process.exit(ExitCode.RUNTIME_ERROR);
190
202
  }).command("mount", "Manage mount configurations", (yargs$1) => yargs$1.command(["list", "ls"], "List all mounts", () => {}, async (argv) => {
@@ -333,9 +345,20 @@ async function main() {
333
345
  throw error;
334
346
  }
335
347
  }
336
- main().catch((error) => {
337
- console.error("Fatal error:", error.message);
338
- process.exit(ExitCode.RUNTIME_ERROR);
348
+ /**
349
+ * Format error message for display
350
+ */
351
+ function formatErrorForDisplay(error) {
352
+ const message = error.message;
353
+ const lines = message.split("\n");
354
+ if (lines.length > 1) return lines.map((line, i) => i === 0 ? `${colors.red("Error:")} ${line}` : ` ${line}`).join("\n");
355
+ return `${colors.red("Error:")} ${message}`;
356
+ }
357
+ main().then(() => {
358
+ process.exit(0);
359
+ }).catch((error) => {
360
+ console.error(formatErrorForDisplay(error));
361
+ process.exit(error instanceof CLIError ? error.exitCode : ExitCode.RUNTIME_ERROR);
339
362
  });
340
363
 
341
364
  //#endregion
package/dist/cli.mjs.map CHANGED
@@ -1 +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 * - afs explore [path] Interactive TUI file explorer\n *\n * Output modes (default: human):\n * - --view=human: Human friendly format with colors (default)\n * - --view=llm: LLM optimized output (token-efficient)\n * - --view=default: Machine truth (script/pipe friendly)\n * - --json: Structured JSON\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 { ConfigLoader } from \"./config/loader.js\";\nimport { CLIError, ExitCode } from \"./errors.js\";\nimport { createExplorerScreen } from \"./explorer/screen.js\";\nimport { createRuntime } from \"./runtime.js\";\nimport { colors, printHeader, shouldShowHeader } from \"./ui/index.js\";\nimport { VERSION } from \"./version.js\";\n\n// Global view type derived from args\n// Default is \"human\" for interactive use; LLMs can use --view=llm or --view=default\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 \"human\";\n}\n\n// Track if header has been shown (show only once per invocation)\nlet headerShown = false;\n\n/**\n * Show header if in human view mode and not already shown\n */\nasync function maybeShowHeader(view: ViewType): Promise<void> {\n if (view !== \"human\" || headerShown || !shouldShowHeader()) {\n return;\n }\n\n headerShown = true;\n\n // Load mount count for header\n try {\n const configLoader = new ConfigLoader();\n const config = await configLoader.load(process.cwd());\n printHeader({\n version: VERSION,\n mountCount: config.mounts.length,\n });\n } catch {\n // If config loading fails, just show header without mount count\n printHeader({\n version: VERSION,\n mountCount: 0,\n });\n }\n}\n\n// Show header for help/version in interactive mode\nasync function showHeaderIfNeeded(): Promise<void> {\n const args = process.argv.slice(2);\n const isHelp =\n args.length === 0 ||\n args.includes(\"--help\") ||\n args.includes(\"-h\") ||\n (args.length === 1 && [\"help\", \"mount\", \"explain\"].includes(args[0]!));\n\n if (isHelp && shouldShowHeader()) {\n try {\n const configLoader = new ConfigLoader();\n const config = await configLoader.load(process.cwd());\n printHeader({\n version: VERSION,\n mountCount: config.mounts.length,\n });\n } catch {\n printHeader({\n version: VERSION,\n mountCount: 0,\n });\n }\n }\n}\n\n// Run the CLI\nasync function main() {\n await showHeaderIfNeeded();\n\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 default: \"human\",\n description: \"Output format (llm for AI agents, default for scripts)\",\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 view = getViewType(argv);\n await maybeShowHeader(view);\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 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 view = getViewType(argv);\n await maybeShowHeader(view);\n const runtime = await createRuntime();\n const result = await statCommand(runtime, argv.path!);\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 view = getViewType(argv);\n await maybeShowHeader(view);\n const runtime = await createRuntime();\n const result = await readCommand(runtime, argv.path!);\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 const view = getViewType(argv);\n await maybeShowHeader(view);\n\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 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 view = getViewType(argv);\n await maybeShowHeader(view);\n\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 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 view = getViewType(argv);\n await maybeShowHeader(view);\n const result = await mountListCommand(process.cwd());\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 .option(\"token\", {\n type: \"string\",\n description: \"Bearer token for HTTP provider authorization\",\n }),\n async (argv) => {\n const view = getViewType(argv);\n await maybeShowHeader(view);\n\n const result = await mountAddCommand(process.cwd(), argv.path!, argv.uri!, {\n description: argv.description,\n token: argv.token,\n });\n\n if (view === \"json\") {\n console.log(JSON.stringify(result, null, 2));\n } else {\n if (result.success) {\n const msg =\n view === \"human\"\n ? `${colors.success(\"Added mount\")} ${colors.cyan(result.normalizedPath!)}`\n : `Added mount ${result.normalizedPath}`;\n console.log(msg);\n } else {\n const msg = view === \"human\" ? colors.error(result.message!) : result.message;\n console.error(msg);\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 view = getViewType(argv);\n await maybeShowHeader(view);\n\n const result = await mountRemoveCommand(process.cwd(), argv.path!);\n\n if (view === \"json\") {\n console.log(JSON.stringify(result, null, 2));\n } else {\n if (result.success) {\n const msg =\n view === \"human\"\n ? `${colors.success(\"Removed mount\")} ${colors.cyan(argv.path!)}`\n : `Removed mount ${argv.path}`;\n console.log(msg);\n } else {\n const msg = view === \"human\" ? colors.error(result.message!) : result.message;\n console.error(msg);\n process.exit(ExitCode.RUNTIME_ERROR);\n }\n }\n },\n )\n .command(\n \"validate\",\n \"Validate mount configuration\",\n () => {},\n async (argv) => {\n const view = getViewType(argv);\n await maybeShowHeader(view);\n\n const result = await mountValidateCommand(process.cwd());\n\n if (view === \"json\") {\n console.log(JSON.stringify(result, null, 2));\n } else {\n if (result.valid) {\n const msg =\n view === \"human\"\n ? colors.success(\"Configuration is valid\")\n : \"Configuration is valid\";\n console.log(msg);\n } else {\n const titleMsg =\n view === \"human\"\n ? colors.error(\"Configuration has errors:\")\n : \"Configuration has errors:\";\n console.error(titleMsg);\n for (const error of result.errors) {\n const errMsg =\n view === \"human\"\n ? ` ${colors.dim(\"-\")} ${colors.error(error)}`\n : ` - ${error}`;\n console.error(errMsg);\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 await maybeShowHeader(view);\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 .option(\"token\", {\n type: \"string\",\n description: \"Bearer token for authorization\",\n }),\n async (argv) => {\n const view = getViewType(argv);\n await maybeShowHeader(view);\n\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 token: argv.token,\n });\n\n console.log(formatServeOutput(result));\n\n // Keep the process running\n await new Promise(() => {});\n },\n )\n .command(\n \"explore [path]\",\n \"Interactive TUI file explorer (PC Tools style)\",\n (yargs) =>\n yargs.positional(\"path\", {\n type: \"string\",\n default: \"/\",\n description: \"Starting path to explore\",\n }),\n async (argv) => {\n const configLoader = new ConfigLoader();\n const config = await configLoader.load(process.cwd());\n const runtime = await createRuntime(process.cwd(), { configLoader });\n await createExplorerScreen({\n runtime,\n startPath: argv.path,\n version: VERSION,\n mountCount: config.mounts.length,\n });\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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"}
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 * - afs explore [path] Interactive TUI file explorer\n *\n * Output modes (default: human):\n * - --view=human: Human friendly format with colors (default)\n * - --view=llm: LLM optimized output (token-efficient)\n * - --view=default: Machine truth (script/pipe friendly)\n * - --json: Structured JSON\n */\n\nimport yargs from \"yargs\";\nimport { hideBin } from \"yargs/helpers\";\nimport {\n type ExecViewType,\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 parseExecArgsWithStdin,\n readCommand,\n serveCommand,\n statCommand,\n type ViewType,\n writeCommand,\n} from \"./commands/index.js\";\nimport { ConfigLoader } from \"./config/loader.js\";\nimport { CLIError, ExitCode } from \"./errors.js\";\nimport { createExplorerScreen } from \"./explorer/screen.js\";\nimport { createRuntime } from \"./runtime.js\";\nimport { colors, printHeader, shouldShowHeader } from \"./ui/index.js\";\nimport { VERSION } from \"./version.js\";\n\n// Global view type derived from args\n// Default is \"human\" for interactive use; LLMs can use --view=llm or --view=default\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 \"human\";\n}\n\n// Track if header has been shown (show only once per invocation)\nlet headerShown = false;\n\n/**\n * Show header if in human view mode and not already shown\n */\nasync function maybeShowHeader(view: ViewType): Promise<void> {\n if (view !== \"human\" || headerShown || !shouldShowHeader()) {\n return;\n }\n\n headerShown = true;\n\n // Load mount count for header\n try {\n const configLoader = new ConfigLoader();\n const config = await configLoader.load(process.cwd());\n printHeader({\n version: VERSION,\n mountCount: config.mounts.length,\n });\n } catch {\n // If config loading fails, just show header without mount count\n printHeader({\n version: VERSION,\n mountCount: 0,\n });\n }\n}\n\n// Show header for help/version in interactive mode\nasync function showHeaderIfNeeded(): Promise<void> {\n const args = process.argv.slice(2);\n const isHelp =\n args.length === 0 ||\n args.includes(\"--help\") ||\n args.includes(\"-h\") ||\n (args.length === 1 && [\"help\", \"mount\", \"explain\"].includes(args[0]!));\n\n if (isHelp && shouldShowHeader()) {\n try {\n const configLoader = new ConfigLoader();\n const config = await configLoader.load(process.cwd());\n printHeader({\n version: VERSION,\n mountCount: config.mounts.length,\n });\n } catch {\n printHeader({\n version: VERSION,\n mountCount: 0,\n });\n }\n }\n}\n\n// Run the CLI\nasync function main() {\n await showHeaderIfNeeded();\n\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 default: \"human\",\n description: \"Output format (llm for AI agents, default for scripts)\",\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 view = getViewType(argv);\n await maybeShowHeader(view);\n const runtime = await createRuntime();\n const path = argv.path!;\n const result = await lsCommand(runtime, path, {\n maxDepth: argv.depth,\n limit: argv.limit,\n maxChildren: argv[\"max-children\"],\n pattern: argv.pattern,\n });\n console.log(formatLsOutput(result, view, { path }));\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 view = getViewType(argv);\n await maybeShowHeader(view);\n const runtime = await createRuntime();\n const result = await statCommand(runtime, argv.path!);\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 view = getViewType(argv);\n await maybeShowHeader(view);\n const runtime = await createRuntime();\n const result = await readCommand(runtime, argv.path!);\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 .option(\"set\", {\n type: \"array\",\n string: true,\n description: \"Set metadata field (format: key=value), can be repeated\",\n }),\n async (argv) => {\n const view = getViewType(argv);\n await maybeShowHeader(view);\n\n let content: string | undefined;\n\n if (argv.content !== undefined) {\n // Use --content parameter\n content = argv.content;\n } else if (argv.set && argv.set.length > 0) {\n // If only --set is provided without content, content is optional\n content = undefined;\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 set: argv.set as string[] | undefined,\n });\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>\",\n \"Execute an executable path (e.g., MCP tool)\",\n (yargs) =>\n yargs\n .positional(\"path\", {\n type: \"string\",\n demandOption: true,\n description: \"Path to execute (must be executable)\",\n })\n .option(\"args\", {\n type: \"string\",\n description: 'JSON arguments: --args \\'{\"key\": \"value\"}\\'',\n })\n .option(\"yaml\", {\n type: \"boolean\",\n description: \"Output in YAML format\",\n })\n .example(\"$0 exec /modules/mcp/tools/echo --message hello\", \"Execute with named param\")\n .example(\n '$0 exec /modules/mcp/tools/query --args \\'{\"sql\": \"SELECT 1\"}\\'',\n \"Execute with JSON args\",\n )\n .strict(false), // Allow unknown options as exec arguments\n async (argv) => {\n // Determine output format\n let view: ExecViewType = \"human\";\n if (argv.json) view = \"json\";\n else if (argv.yaml) view = \"yaml\";\n else if (argv.view) view = argv.view as ExecViewType;\n\n await maybeShowHeader(view as ViewType);\n\n // Parse arguments from CLI options with stdin support\n const args = await parseExecArgsWithStdin(argv as Record<string, unknown>);\n\n const runtime = await createRuntime();\n const result = await execCommand(runtime, argv.path!, args);\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 view = getViewType(argv);\n await maybeShowHeader(view);\n const result = await mountListCommand(process.cwd());\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 .option(\"token\", {\n type: \"string\",\n description: \"Bearer token for HTTP provider authorization\",\n }),\n async (argv) => {\n const view = getViewType(argv);\n await maybeShowHeader(view);\n\n const result = await mountAddCommand(process.cwd(), argv.path!, argv.uri!, {\n description: argv.description,\n token: argv.token,\n });\n\n if (view === \"json\") {\n console.log(JSON.stringify(result, null, 2));\n } else {\n if (result.success) {\n const msg =\n view === \"human\"\n ? `${colors.success(\"Added mount\")} ${colors.cyan(result.normalizedPath!)}`\n : `Added mount ${result.normalizedPath}`;\n console.log(msg);\n } else {\n const msg = view === \"human\" ? colors.error(result.message!) : result.message;\n console.error(msg);\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 view = getViewType(argv);\n await maybeShowHeader(view);\n\n const result = await mountRemoveCommand(process.cwd(), argv.path!);\n\n if (view === \"json\") {\n console.log(JSON.stringify(result, null, 2));\n } else {\n if (result.success) {\n const msg =\n view === \"human\"\n ? `${colors.success(\"Removed mount\")} ${colors.cyan(argv.path!)}`\n : `Removed mount ${argv.path}`;\n console.log(msg);\n } else {\n const msg = view === \"human\" ? colors.error(result.message!) : result.message;\n console.error(msg);\n process.exit(ExitCode.RUNTIME_ERROR);\n }\n }\n },\n )\n .command(\n \"validate\",\n \"Validate mount configuration\",\n () => {},\n async (argv) => {\n const view = getViewType(argv);\n await maybeShowHeader(view);\n\n const result = await mountValidateCommand(process.cwd());\n\n if (view === \"json\") {\n console.log(JSON.stringify(result, null, 2));\n } else {\n if (result.valid) {\n const msg =\n view === \"human\"\n ? colors.success(\"Configuration is valid\")\n : \"Configuration is valid\";\n console.log(msg);\n } else {\n const titleMsg =\n view === \"human\"\n ? colors.error(\"Configuration has errors:\")\n : \"Configuration has errors:\";\n console.error(titleMsg);\n for (const error of result.errors) {\n const errMsg =\n view === \"human\"\n ? ` ${colors.dim(\"-\")} ${colors.error(error)}`\n : ` - ${error}`;\n console.error(errMsg);\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 await maybeShowHeader(view);\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 .option(\"token\", {\n type: \"string\",\n description: \"Bearer token for authorization\",\n }),\n async (argv) => {\n const view = getViewType(argv);\n await maybeShowHeader(view);\n\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 token: argv.token,\n });\n\n console.log(formatServeOutput(result));\n\n // Keep the process running\n await new Promise(() => {});\n },\n )\n .command(\n \"explore [path]\",\n \"Interactive TUI file explorer (PC Tools style)\",\n (yargs) =>\n yargs.positional(\"path\", {\n type: \"string\",\n default: \"/\",\n description: \"Starting path to explore\",\n }),\n async (argv) => {\n const configLoader = new ConfigLoader();\n const config = await configLoader.load(process.cwd());\n const runtime = await createRuntime(process.cwd(), { configLoader });\n await createExplorerScreen({\n runtime,\n startPath: argv.path,\n version: VERSION,\n mountCount: config.mounts.length,\n });\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\n/**\n * Format error message for display\n */\nfunction formatErrorForDisplay(error: Error): string {\n const message = error.message;\n\n // Format multi-line messages with proper indentation\n const lines = message.split(\"\\n\");\n if (lines.length > 1) {\n return lines\n .map((line, i) => (i === 0 ? `${colors.red(\"Error:\")} ${line}` : ` ${line}`))\n .join(\"\\n\");\n }\n\n return `${colors.red(\"Error:\")} ${message}`;\n}\n\nmain()\n .then(() => {\n // Force exit after command completes to ensure child processes (like MCP stdio)\n // don't keep the process alive. Long-running commands (serve, explore) handle\n // their own lifecycle and never reach here.\n process.exit(0);\n })\n .catch((error) => {\n console.error(formatErrorForDisplay(error));\n process.exit(error instanceof CLIError ? error.exitCode : ExitCode.RUNTIME_ERROR);\n });\n"],"mappings":"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"}
@@ -1,17 +1,110 @@
1
+ const require_rolldown_runtime = require('../_virtual/rolldown_runtime.cjs');
2
+ let yaml = require("yaml");
3
+ yaml = require_rolldown_runtime.__toESM(yaml);
1
4
 
2
5
  //#region src/commands/exec.ts
3
6
  /**
7
+ * Reserved CLI option names that should not be passed as exec arguments
8
+ */
9
+ const RESERVED_OPTIONS = new Set([
10
+ "json",
11
+ "yaml",
12
+ "view",
13
+ "help",
14
+ "h",
15
+ "version",
16
+ "V",
17
+ "_",
18
+ "$0",
19
+ "args"
20
+ ]);
21
+ /**
22
+ * Read JSON from stdin (non-blocking if TTY)
23
+ */
24
+ async function readStdin() {
25
+ if (process.stdin.isTTY) return null;
26
+ const chunks = [];
27
+ for await (const chunk of process.stdin) chunks.push(chunk);
28
+ return Buffer.concat(chunks).toString("utf-8").trim() || null;
29
+ }
30
+ /**
31
+ * Parse exec arguments with stdin support (async version)
32
+ *
33
+ * Priority: CLI flags > stdin > --args
34
+ */
35
+ async function parseExecArgsWithStdin(options) {
36
+ let result = {};
37
+ if (options.args && typeof options.args === "string") try {
38
+ const parsed = JSON.parse(options.args);
39
+ if (typeof parsed === "object" && parsed !== null) result = { ...parsed };
40
+ } catch (e) {
41
+ throw new Error(`Invalid JSON in --args: ${e.message}`);
42
+ }
43
+ const stdinContent = await readStdin();
44
+ if (stdinContent) try {
45
+ const parsed = JSON.parse(stdinContent);
46
+ if (typeof parsed === "object" && parsed !== null) result = {
47
+ ...result,
48
+ ...parsed
49
+ };
50
+ } catch (e) {
51
+ throw new Error(`Invalid JSON in stdin: ${e.message}`);
52
+ }
53
+ for (const [key, value] of Object.entries(options)) {
54
+ if (RESERVED_OPTIONS.has(key) || value === void 0 || value === null) continue;
55
+ result[key] = value;
56
+ }
57
+ return result;
58
+ }
59
+ /**
60
+ * Check if an entry is executable based on its metadata
61
+ *
62
+ * An entry is executable if:
63
+ * 1. Its `kinds` array includes "afs:executable", OR
64
+ * 2. Its `kind` field equals "afs:executable" (legacy support)
65
+ */
66
+ function isExecutable(metadata) {
67
+ if (!metadata) return false;
68
+ if (Array.isArray(metadata.kinds)) return metadata.kinds.includes("afs:executable");
69
+ return metadata.kind === "afs:executable";
70
+ }
71
+ /**
4
72
  * Execute an action on an AFS path
5
73
  *
6
- * Note: exec is not widely implemented by providers yet.
7
- * This is a placeholder for future functionality.
74
+ * This function directly executes the path without pre-checking if it's executable.
75
+ * The provider will return an appropriate error if the path is not executable.
76
+ *
77
+ * @param runtime - AFS runtime
78
+ * @param path - Path to execute
79
+ * @param args - Arguments to pass to the executable
80
+ * @returns Exec result
81
+ */
82
+ async function execCommand(runtime, path, args = {}) {
83
+ try {
84
+ const execResult = await runtime.exec(path, args);
85
+ return {
86
+ path,
87
+ success: execResult.success,
88
+ data: execResult.data,
89
+ message: execResult.error?.message,
90
+ error: execResult.error
91
+ };
92
+ } catch (error) {
93
+ const errorCode = extractErrorCode(error);
94
+ return {
95
+ path,
96
+ success: false,
97
+ message: error instanceof Error ? error.message : String(error),
98
+ error: errorCode ? { code: errorCode } : void 0
99
+ };
100
+ }
101
+ }
102
+ /**
103
+ * Extract error code from an error object
8
104
  */
9
- async function execCommand(_runtime, path, _action, _params = {}) {
10
- return {
11
- path,
12
- success: false,
13
- message: "exec operation is not yet implemented"
14
- };
105
+ function extractErrorCode(error) {
106
+ if (!error || typeof error !== "object") return void 0;
107
+ if ("code" in error && typeof error.code === "string") return error.code;
15
108
  }
16
109
  /**
17
110
  * Format exec output for different views
@@ -19,28 +112,53 @@ async function execCommand(_runtime, path, _action, _params = {}) {
19
112
  function formatExecOutput(result, view) {
20
113
  switch (view) {
21
114
  case "json": return JSON.stringify(result, null, 2);
115
+ case "yaml": return yaml.default.stringify(result);
22
116
  case "llm": return formatLlm(result);
23
117
  case "human": return formatHuman(result);
24
118
  default: return formatDefault(result);
25
119
  }
26
120
  }
27
121
  function formatDefault(result) {
28
- if (result.success) return `OK ${result.path}`;
29
- return `ERROR ${result.path} ${result.message}`;
122
+ if (result.success) {
123
+ if (result.data) return JSON.stringify(result.data);
124
+ return `OK ${result.path}`;
125
+ }
126
+ return `${result.error?.code || "ERROR"} ${result.path} ${result.message || ""}`.trim();
30
127
  }
31
128
  function formatLlm(result) {
32
129
  const lines = [];
33
130
  lines.push(`EXEC ${result.path}`);
34
131
  lines.push(`STATUS ${result.success ? "SUCCESS" : "FAILED"}`);
35
132
  if (result.data) lines.push(`DATA ${JSON.stringify(result.data)}`);
36
- if (result.message) lines.push(`MESSAGE ${result.message}`);
133
+ if (!result.success && result.error) {
134
+ if (result.error.code) lines.push(`ERROR ${result.error.code}`);
135
+ if (result.message) lines.push(`MESSAGE ${result.message}`);
136
+ if (result.error.details) lines.push(`DETAILS ${JSON.stringify(result.error.details)}`);
137
+ } else if (result.message) lines.push(`MESSAGE ${result.message}`);
37
138
  return lines.join("\n");
38
139
  }
39
140
  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}`;
141
+ if (result.success) {
142
+ const lines$1 = [`✓ Executed: ${result.path}`];
143
+ if (result.data) {
144
+ lines$1.push("");
145
+ lines$1.push(JSON.stringify(result.data, null, 2));
146
+ }
147
+ return lines$1.join("\n");
148
+ }
149
+ const lines = [`✗ Failed: ${result.path}`];
150
+ lines.push("");
151
+ if (result.error?.code) lines.push(`Error: ${result.error.code}`);
152
+ if (result.message) lines.push(`Message: ${result.message}`);
153
+ if (result.error?.details) {
154
+ lines.push("Details:");
155
+ for (const [key, value] of Object.entries(result.error.details)) lines.push(` ${key}: ${JSON.stringify(value)}`);
156
+ }
157
+ return lines.join("\n");
42
158
  }
43
159
 
44
160
  //#endregion
45
161
  exports.execCommand = execCommand;
46
- exports.formatExecOutput = formatExecOutput;
162
+ exports.formatExecOutput = formatExecOutput;
163
+ exports.isExecutable = isExecutable;
164
+ exports.parseExecArgsWithStdin = parseExecArgsWithStdin;