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

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 (318) hide show
  1. package/dist/cli.cjs +25 -328
  2. package/dist/cli.d.cts +2 -1
  3. package/dist/cli.d.mts +2 -1
  4. package/dist/cli.mjs +26 -328
  5. package/dist/cli.mjs.map +1 -1
  6. package/dist/config/afs-loader.cjs +123 -0
  7. package/dist/config/afs-loader.d.cts +14 -0
  8. package/dist/config/afs-loader.d.cts.map +1 -0
  9. package/dist/config/afs-loader.d.mts +14 -0
  10. package/dist/config/afs-loader.d.mts.map +1 -0
  11. package/dist/config/afs-loader.mjs +122 -0
  12. package/dist/config/afs-loader.mjs.map +1 -0
  13. package/dist/config/loader.cjs +14 -3
  14. package/dist/config/loader.mjs +14 -3
  15. package/dist/config/loader.mjs.map +1 -1
  16. package/dist/{commands/mount.cjs → config/mount-commands.cjs} +13 -49
  17. package/dist/config/mount-commands.d.cts +20 -0
  18. package/dist/config/mount-commands.d.cts.map +1 -0
  19. package/dist/config/mount-commands.d.mts +20 -0
  20. package/dist/config/mount-commands.d.mts.map +1 -0
  21. package/dist/{commands/mount.mjs → config/mount-commands.mjs} +14 -49
  22. package/dist/config/mount-commands.mjs.map +1 -0
  23. package/dist/config/schema.cjs +9 -1
  24. package/dist/config/schema.mjs +9 -1
  25. package/dist/config/schema.mjs.map +1 -1
  26. package/dist/core/commands/delete.cjs +41 -0
  27. package/dist/core/commands/delete.d.cts +18 -0
  28. package/dist/core/commands/delete.d.cts.map +1 -0
  29. package/dist/core/commands/delete.d.mts +18 -0
  30. package/dist/core/commands/delete.d.mts.map +1 -0
  31. package/dist/core/commands/delete.mjs +42 -0
  32. package/dist/core/commands/delete.mjs.map +1 -0
  33. package/dist/core/commands/exec.cjs +95 -0
  34. package/dist/core/commands/exec.d.cts +26 -0
  35. package/dist/core/commands/exec.d.cts.map +1 -0
  36. package/dist/core/commands/exec.d.mts +26 -0
  37. package/dist/core/commands/exec.d.mts.map +1 -0
  38. package/dist/core/commands/exec.mjs +96 -0
  39. package/dist/core/commands/exec.mjs.map +1 -0
  40. package/dist/core/commands/explain.cjs +254 -0
  41. package/dist/core/commands/explain.d.cts +25 -0
  42. package/dist/core/commands/explain.d.cts.map +1 -0
  43. package/dist/core/commands/explain.d.mts +25 -0
  44. package/dist/core/commands/explain.d.mts.map +1 -0
  45. package/dist/core/commands/explain.mjs +255 -0
  46. package/dist/core/commands/explain.mjs.map +1 -0
  47. package/dist/core/commands/explore.cjs +30 -0
  48. package/dist/core/commands/explore.d.mts +2 -0
  49. package/dist/core/commands/explore.mjs +31 -0
  50. package/dist/core/commands/explore.mjs.map +1 -0
  51. package/dist/core/commands/index.cjs +36 -0
  52. package/dist/core/commands/index.d.cts +21 -0
  53. package/dist/core/commands/index.d.cts.map +1 -0
  54. package/dist/core/commands/index.d.mts +24 -0
  55. package/dist/core/commands/index.d.mts.map +1 -0
  56. package/dist/core/commands/index.mjs +37 -0
  57. package/dist/core/commands/index.mjs.map +1 -0
  58. package/dist/core/commands/ls.cjs +57 -0
  59. package/dist/core/commands/ls.d.cts +21 -0
  60. package/dist/core/commands/ls.d.cts.map +1 -0
  61. package/dist/core/commands/ls.d.mts +21 -0
  62. package/dist/core/commands/ls.d.mts.map +1 -0
  63. package/dist/core/commands/ls.mjs +58 -0
  64. package/dist/core/commands/ls.mjs.map +1 -0
  65. package/dist/core/commands/mount.cjs +139 -0
  66. package/dist/core/commands/mount.d.cts +33 -0
  67. package/dist/core/commands/mount.d.cts.map +1 -0
  68. package/dist/core/commands/mount.d.mts +33 -0
  69. package/dist/core/commands/mount.d.mts.map +1 -0
  70. package/dist/core/commands/mount.mjs +140 -0
  71. package/dist/core/commands/mount.mjs.map +1 -0
  72. package/dist/core/commands/read.cjs +48 -0
  73. package/dist/core/commands/read.d.cts +17 -0
  74. package/dist/core/commands/read.d.cts.map +1 -0
  75. package/dist/core/commands/read.d.mts +17 -0
  76. package/dist/core/commands/read.d.mts.map +1 -0
  77. package/dist/core/commands/read.mjs +49 -0
  78. package/dist/core/commands/read.mjs.map +1 -0
  79. package/dist/core/commands/search.cjs +40 -0
  80. package/dist/core/commands/search.d.mts +2 -0
  81. package/dist/core/commands/search.mjs +41 -0
  82. package/dist/core/commands/search.mjs.map +1 -0
  83. package/dist/core/commands/serve.cjs +242 -0
  84. package/dist/core/commands/serve.d.mts +2 -0
  85. package/dist/core/commands/serve.mjs +242 -0
  86. package/dist/core/commands/serve.mjs.map +1 -0
  87. package/dist/core/commands/stat.cjs +53 -0
  88. package/dist/core/commands/stat.d.cts +17 -0
  89. package/dist/core/commands/stat.d.cts.map +1 -0
  90. package/dist/core/commands/stat.d.mts +17 -0
  91. package/dist/core/commands/stat.d.mts.map +1 -0
  92. package/dist/core/commands/stat.mjs +54 -0
  93. package/dist/core/commands/stat.mjs.map +1 -0
  94. package/dist/core/commands/types.cjs +13 -0
  95. package/dist/core/commands/types.d.cts +54 -0
  96. package/dist/core/commands/types.d.cts.map +1 -0
  97. package/dist/core/commands/types.d.mts +54 -0
  98. package/dist/core/commands/types.d.mts.map +1 -0
  99. package/dist/core/commands/types.mjs +14 -0
  100. package/dist/core/commands/types.mjs.map +1 -0
  101. package/dist/core/commands/write.cjs +70 -0
  102. package/dist/core/commands/write.d.cts +20 -0
  103. package/dist/core/commands/write.d.cts.map +1 -0
  104. package/dist/core/commands/write.d.mts +20 -0
  105. package/dist/core/commands/write.d.mts.map +1 -0
  106. package/dist/core/commands/write.mjs +71 -0
  107. package/dist/core/commands/write.mjs.map +1 -0
  108. package/dist/core/executor/index.cjs +196 -0
  109. package/dist/core/executor/index.d.cts +77 -0
  110. package/dist/core/executor/index.d.cts.map +1 -0
  111. package/dist/core/executor/index.d.mts +77 -0
  112. package/dist/core/executor/index.d.mts.map +1 -0
  113. package/dist/core/executor/index.mjs +195 -0
  114. package/dist/core/executor/index.mjs.map +1 -0
  115. package/dist/core/formatters/delete.cjs +37 -0
  116. package/dist/core/formatters/delete.d.cts +18 -0
  117. package/dist/core/formatters/delete.d.cts.map +1 -0
  118. package/dist/core/formatters/delete.d.mts +18 -0
  119. package/dist/core/formatters/delete.d.mts.map +1 -0
  120. package/dist/core/formatters/delete.mjs +37 -0
  121. package/dist/core/formatters/delete.mjs.map +1 -0
  122. package/dist/core/formatters/exec.cjs +60 -0
  123. package/dist/core/formatters/exec.d.cts +18 -0
  124. package/dist/core/formatters/exec.d.cts.map +1 -0
  125. package/dist/core/formatters/exec.d.mts +18 -0
  126. package/dist/core/formatters/exec.d.mts.map +1 -0
  127. package/dist/core/formatters/exec.mjs +60 -0
  128. package/dist/core/formatters/exec.mjs.map +1 -0
  129. package/dist/core/formatters/explain.cjs +97 -0
  130. package/dist/core/formatters/explain.d.cts +11 -0
  131. package/dist/core/formatters/explain.d.cts.map +1 -0
  132. package/dist/core/formatters/explain.d.mts +11 -0
  133. package/dist/core/formatters/explain.d.mts.map +1 -0
  134. package/dist/core/formatters/explain.mjs +96 -0
  135. package/dist/core/formatters/explain.mjs.map +1 -0
  136. package/dist/core/formatters/index.d.mts +9 -0
  137. package/dist/core/formatters/ls.cjs +179 -0
  138. package/dist/core/formatters/ls.d.cts +20 -0
  139. package/dist/core/formatters/ls.d.cts.map +1 -0
  140. package/dist/core/formatters/ls.d.mts +20 -0
  141. package/dist/core/formatters/ls.d.mts.map +1 -0
  142. package/dist/core/formatters/ls.mjs +179 -0
  143. package/dist/core/formatters/ls.mjs.map +1 -0
  144. package/dist/core/formatters/mount.cjs +55 -0
  145. package/dist/core/formatters/mount.d.cts +15 -0
  146. package/dist/core/formatters/mount.d.cts.map +1 -0
  147. package/dist/core/formatters/mount.d.mts +15 -0
  148. package/dist/core/formatters/mount.d.mts.map +1 -0
  149. package/dist/core/formatters/mount.mjs +55 -0
  150. package/dist/core/formatters/mount.mjs.map +1 -0
  151. package/dist/core/formatters/read.cjs +100 -0
  152. package/dist/core/formatters/read.d.cts +22 -0
  153. package/dist/core/formatters/read.d.cts.map +1 -0
  154. package/dist/core/formatters/read.d.mts +22 -0
  155. package/dist/core/formatters/read.d.mts.map +1 -0
  156. package/dist/core/formatters/read.mjs +100 -0
  157. package/dist/core/formatters/read.mjs.map +1 -0
  158. package/dist/core/formatters/search.cjs +44 -0
  159. package/dist/core/formatters/search.d.mts +1 -0
  160. package/dist/core/formatters/search.mjs +44 -0
  161. package/dist/core/formatters/search.mjs.map +1 -0
  162. package/dist/core/formatters/stat.cjs +155 -0
  163. package/dist/core/formatters/stat.d.cts +15 -0
  164. package/dist/core/formatters/stat.d.cts.map +1 -0
  165. package/dist/core/formatters/stat.d.mts +15 -0
  166. package/dist/core/formatters/stat.d.mts.map +1 -0
  167. package/dist/core/formatters/stat.mjs +155 -0
  168. package/dist/core/formatters/stat.mjs.map +1 -0
  169. package/dist/core/formatters/write.cjs +51 -0
  170. package/dist/core/formatters/write.d.cts +22 -0
  171. package/dist/core/formatters/write.d.cts.map +1 -0
  172. package/dist/core/formatters/write.d.mts +22 -0
  173. package/dist/core/formatters/write.d.mts.map +1 -0
  174. package/dist/core/formatters/write.mjs +51 -0
  175. package/dist/core/formatters/write.mjs.map +1 -0
  176. package/dist/core/helpers/exec-args.cjs +142 -0
  177. package/dist/core/helpers/exec-args.d.cts +46 -0
  178. package/dist/core/helpers/exec-args.d.cts.map +1 -0
  179. package/dist/core/helpers/exec-args.d.mts +46 -0
  180. package/dist/core/helpers/exec-args.d.mts.map +1 -0
  181. package/dist/core/helpers/exec-args.mjs +139 -0
  182. package/dist/core/helpers/exec-args.mjs.map +1 -0
  183. package/dist/core/helpers/stdin.cjs +41 -0
  184. package/dist/core/helpers/stdin.d.cts +15 -0
  185. package/dist/core/helpers/stdin.d.cts.map +1 -0
  186. package/dist/core/helpers/stdin.d.mts +15 -0
  187. package/dist/core/helpers/stdin.d.mts.map +1 -0
  188. package/dist/core/helpers/stdin.mjs +41 -0
  189. package/dist/core/helpers/stdin.mjs.map +1 -0
  190. package/dist/core/index.cjs +49 -0
  191. package/dist/core/index.d.cts +24 -0
  192. package/dist/core/index.d.mts +25 -0
  193. package/dist/core/index.mjs +24 -0
  194. package/dist/core/path-utils.cjs +1 -0
  195. package/dist/core/path-utils.mjs +3 -0
  196. package/dist/core/types.d.cts +24 -0
  197. package/dist/core/types.d.cts.map +1 -0
  198. package/dist/core/types.d.mts +24 -0
  199. package/dist/core/types.d.mts.map +1 -0
  200. package/dist/errors.cjs +0 -11
  201. package/dist/errors.mjs +1 -11
  202. package/dist/errors.mjs.map +1 -1
  203. package/dist/explorer/actions.cjs +113 -48
  204. package/dist/explorer/actions.mjs +113 -48
  205. package/dist/explorer/actions.mjs.map +1 -1
  206. package/dist/explorer/components/dialog.cjs +287 -10
  207. package/dist/explorer/components/dialog.mjs +287 -10
  208. package/dist/explorer/components/dialog.mjs.map +1 -1
  209. package/dist/explorer/components/file-list.mjs.map +1 -1
  210. package/dist/explorer/components/metadata-panel.cjs +121 -24
  211. package/dist/explorer/components/metadata-panel.mjs +121 -24
  212. package/dist/explorer/components/metadata-panel.mjs.map +1 -1
  213. package/dist/explorer/screen.cjs +72 -21
  214. package/dist/explorer/screen.d.cts +23 -0
  215. package/dist/explorer/screen.d.cts.map +1 -0
  216. package/dist/explorer/screen.d.mts +23 -0
  217. package/dist/explorer/screen.d.mts.map +1 -0
  218. package/dist/explorer/screen.mjs +73 -22
  219. package/dist/explorer/screen.mjs.map +1 -1
  220. package/dist/explorer/theme.cjs +4 -2
  221. package/dist/explorer/theme.mjs +4 -2
  222. package/dist/explorer/theme.mjs.map +1 -1
  223. package/dist/index.cjs +7 -1
  224. package/dist/index.d.cts +4 -1
  225. package/dist/index.d.mts +4 -1
  226. package/dist/index.mjs +4 -1
  227. package/dist/mcp/http-transport.cjs +68 -0
  228. package/dist/mcp/http-transport.mjs +68 -0
  229. package/dist/mcp/http-transport.mjs.map +1 -0
  230. package/dist/mcp/prompts.cjs +48 -0
  231. package/dist/mcp/prompts.mjs +48 -0
  232. package/dist/mcp/prompts.mjs.map +1 -0
  233. package/dist/mcp/resources.cjs +25 -0
  234. package/dist/mcp/resources.mjs +25 -0
  235. package/dist/mcp/resources.mjs.map +1 -0
  236. package/dist/mcp/server.cjs +30 -0
  237. package/dist/mcp/server.mjs +30 -0
  238. package/dist/mcp/server.mjs.map +1 -0
  239. package/dist/mcp/tools.cjs +196 -0
  240. package/dist/mcp/tools.mjs +196 -0
  241. package/dist/mcp/tools.mjs.map +1 -0
  242. package/dist/node_modules/.pnpm/urlpattern-polyfill@10.1.0/node_modules/urlpattern-polyfill/dist/index.d.cts +10 -0
  243. package/dist/node_modules/.pnpm/urlpattern-polyfill@10.1.0/node_modules/urlpattern-polyfill/dist/index.d.cts.map +1 -0
  244. package/dist/node_modules/.pnpm/urlpattern-polyfill@10.1.0/node_modules/urlpattern-polyfill/dist/index.d.mts +10 -0
  245. package/dist/node_modules/.pnpm/urlpattern-polyfill@10.1.0/node_modules/urlpattern-polyfill/dist/index.d.mts.map +1 -0
  246. package/dist/node_modules/.pnpm/urlpattern-polyfill@10.1.0/node_modules/urlpattern-polyfill/dist/types.d.cts +46 -0
  247. package/dist/node_modules/.pnpm/urlpattern-polyfill@10.1.0/node_modules/urlpattern-polyfill/dist/types.d.cts.map +1 -0
  248. package/dist/node_modules/.pnpm/urlpattern-polyfill@10.1.0/node_modules/urlpattern-polyfill/dist/types.d.mts +46 -0
  249. package/dist/node_modules/.pnpm/urlpattern-polyfill@10.1.0/node_modules/urlpattern-polyfill/dist/types.d.mts.map +1 -0
  250. package/dist/node_modules/.pnpm/urlpattern-polyfill@10.1.0/node_modules/urlpattern-polyfill/dist/urlpattern.cjs +902 -0
  251. package/dist/node_modules/.pnpm/urlpattern-polyfill@10.1.0/node_modules/urlpattern-polyfill/dist/urlpattern.mjs +902 -0
  252. package/dist/node_modules/.pnpm/urlpattern-polyfill@10.1.0/node_modules/urlpattern-polyfill/dist/urlpattern.mjs.map +1 -0
  253. package/dist/node_modules/.pnpm/urlpattern-polyfill@10.1.0/node_modules/urlpattern-polyfill/index.cjs +6 -0
  254. package/dist/node_modules/.pnpm/urlpattern-polyfill@10.1.0/node_modules/urlpattern-polyfill/index.mjs +8 -0
  255. package/dist/node_modules/.pnpm/urlpattern-polyfill@10.1.0/node_modules/urlpattern-polyfill/index.mjs.map +1 -0
  256. package/dist/path-utils.cjs +2 -1
  257. package/dist/path-utils.d.cts +50 -0
  258. package/dist/path-utils.d.cts.map +1 -0
  259. package/dist/path-utils.d.mts +50 -0
  260. package/dist/path-utils.d.mts.map +1 -0
  261. package/dist/path-utils.mjs +1 -1
  262. package/dist/repl.cjs +485 -0
  263. package/dist/repl.d.cts +15 -0
  264. package/dist/repl.d.cts.map +1 -0
  265. package/dist/repl.d.mts +16 -0
  266. package/dist/repl.d.mts.map +1 -0
  267. package/dist/repl.mjs +485 -0
  268. package/dist/repl.mjs.map +1 -0
  269. package/dist/serve.cjs +146 -0
  270. package/dist/serve.d.cts +41 -0
  271. package/dist/serve.d.cts.map +1 -0
  272. package/dist/serve.d.mts +41 -0
  273. package/dist/serve.d.mts.map +1 -0
  274. package/dist/serve.mjs +146 -0
  275. package/dist/serve.mjs.map +1 -0
  276. package/dist/ui/header.cjs +1 -49
  277. package/dist/ui/header.mjs +1 -47
  278. package/dist/ui/header.mjs.map +1 -1
  279. package/dist/ui/index.cjs +2 -11
  280. package/dist/ui/index.mjs +2 -8
  281. package/dist/ui/index.mjs.map +1 -1
  282. package/dist/ui/terminal.cjs +1 -10
  283. package/dist/ui/terminal.mjs +1 -8
  284. package/dist/ui/terminal.mjs.map +1 -1
  285. package/package.json +32 -9
  286. package/dist/commands/exec.cjs +0 -46
  287. package/dist/commands/exec.mjs +0 -45
  288. package/dist/commands/exec.mjs.map +0 -1
  289. package/dist/commands/explain.cjs +0 -244
  290. package/dist/commands/explain.mjs +0 -242
  291. package/dist/commands/explain.mjs.map +0 -1
  292. package/dist/commands/index.cjs +0 -8
  293. package/dist/commands/index.mjs +0 -10
  294. package/dist/commands/ls.cjs +0 -143
  295. package/dist/commands/ls.mjs +0 -143
  296. package/dist/commands/ls.mjs.map +0 -1
  297. package/dist/commands/mount.mjs.map +0 -1
  298. package/dist/commands/read.cjs +0 -65
  299. package/dist/commands/read.mjs +0 -64
  300. package/dist/commands/read.mjs.map +0 -1
  301. package/dist/commands/serve.cjs +0 -144
  302. package/dist/commands/serve.mjs +0 -143
  303. package/dist/commands/serve.mjs.map +0 -1
  304. package/dist/commands/stat.cjs +0 -113
  305. package/dist/commands/stat.mjs +0 -112
  306. package/dist/commands/stat.mjs.map +0 -1
  307. package/dist/commands/write.cjs +0 -52
  308. package/dist/commands/write.mjs +0 -51
  309. package/dist/commands/write.mjs.map +0 -1
  310. package/dist/config/provider-factory.cjs +0 -93
  311. package/dist/config/provider-factory.mjs +0 -94
  312. package/dist/config/provider-factory.mjs.map +0 -1
  313. package/dist/config/uri-parser.cjs +0 -92
  314. package/dist/config/uri-parser.mjs +0 -92
  315. package/dist/config/uri-parser.mjs.map +0 -1
  316. package/dist/runtime.cjs +0 -96
  317. package/dist/runtime.mjs +0 -96
  318. package/dist/runtime.mjs.map +0 -1
@@ -10,7 +10,7 @@ function formatMetadata(entry, metadata) {
10
10
  const prefix = icon ? `${icon} ` : "";
11
11
  lines.push(`${prefix}${entry.name}`);
12
12
  lines.push("");
13
- lines.push(`Type: ${entry.type}`);
13
+ lines.push(`Path: ${entry.path}`);
14
14
  if (entry.size !== void 0 || metadata?.size !== void 0) {
15
15
  const size = metadata?.size ?? entry.size;
16
16
  lines.push(`Size: ${formatSize(size)}`);
@@ -29,20 +29,131 @@ function formatMetadata(entry, metadata) {
29
29
  const display = hash.length > 20 ? `${hash.slice(0, 20)}...` : hash;
30
30
  lines.push(`Hash: ${display}`);
31
31
  }
32
- if (entry.description || metadata?.description) {
33
- lines.push("");
34
- lines.push("Description:");
35
- const wrapped = wrapText(metadata?.description ?? entry.description, 25);
36
- lines.push(...wrapped);
32
+ if (metadata?.mountPath) lines.push(`Mount: ${metadata.mountPath}`);
33
+ if (metadata?.uri) lines.push(`URI: ${metadata.uri}`);
34
+ const kinds = entry.kinds && entry.kinds.length > 0 ? entry.kinds : metadata?.extra?.kinds;
35
+ const kind = entry.kind ?? metadata?.extra?.kind;
36
+ if (kinds && kinds.length > 0) lines.push(`Kinds: ${kinds.join(" → ")}`);
37
+ else if (kind) lines.push(`Kind: ${kind}`);
38
+ if (metadata?.extra && Object.keys(metadata.extra).length > 0) {
39
+ const builtInFields = new Set([
40
+ "size",
41
+ "mimeType",
42
+ "childrenCount",
43
+ "hash",
44
+ "provider",
45
+ "mountPath",
46
+ "uri",
47
+ "permissions",
48
+ "kind",
49
+ "kinds"
50
+ ]);
51
+ for (const [key, value] of Object.entries(metadata.extra)) {
52
+ if (builtInFields.has(key) || value === void 0) continue;
53
+ if (key === "inputSchema" && typeof value === "object" && value !== null) {
54
+ const schema = value;
55
+ if (schema.properties && typeof schema.properties === "object") {
56
+ lines.push("");
57
+ lines.push("InputSchema:");
58
+ const props = schema.properties;
59
+ for (const [propName, propSchema] of Object.entries(props)) {
60
+ const ps = propSchema;
61
+ const type = ps.type || "any";
62
+ const desc = ps.description ? ` - ${ps.description}` : "";
63
+ const req = Array.isArray(schema.required) && schema.required.includes(propName) ? "*" : "";
64
+ lines.push(` • ${propName}${req}: ${type}${desc}`);
65
+ }
66
+ continue;
67
+ }
68
+ }
69
+ const displayKey = key.charAt(0).toUpperCase() + key.slice(1);
70
+ const displayValue = formatValue(value);
71
+ if (displayValue.includes("\n")) {
72
+ lines.push("");
73
+ lines.push(`${displayKey}:`);
74
+ for (const line of displayValue.split("\n")) lines.push(` ${line}`);
75
+ } else lines.push(`${displayKey}: ${displayValue}`);
76
+ }
37
77
  }
38
- if (metadata?.mountPath) {
78
+ const actions = metadata?.actions ?? entry.actions;
79
+ lines.push("");
80
+ lines.push("─────── Actions ───────");
81
+ if (actions && actions.length > 0) {
82
+ for (let i = 0; i < actions.length; i++) {
83
+ const action = actions[i];
84
+ if (action) lines.push(`[${i + 1}] ${action.name}`);
85
+ }
39
86
  lines.push("");
40
- lines.push(`Mount: ${metadata.mountPath}`);
41
- }
42
- if (metadata?.uri) lines.push(`URI: ${metadata.uri}`);
87
+ lines.push("(F4 to execute)");
88
+ } else lines.push("(none)");
43
89
  return lines;
44
90
  }
45
91
  /**
92
+ * Format a value for display
93
+ */
94
+ function formatValue(value) {
95
+ if (value === null || value === void 0) return "";
96
+ if (typeof value === "string") return value;
97
+ if (typeof value === "number" || typeof value === "boolean") return String(value);
98
+ if (Array.isArray(value)) {
99
+ if (value.length === 0) return "[]";
100
+ if (value.every((v) => typeof v === "string" || typeof v === "number")) return value.join(", ");
101
+ if (value.every((v) => typeof v === "object" && v !== null && "name" in v)) return formatNamedItems(value);
102
+ try {
103
+ return JSON.stringify(value, null, 2);
104
+ } catch {
105
+ return "[unable to display]";
106
+ }
107
+ }
108
+ if (typeof value === "object") {
109
+ const obj = value;
110
+ if (isSchemaProperties(obj)) return formatSchemaProperties(obj);
111
+ try {
112
+ return JSON.stringify(value, null, 2);
113
+ } catch {
114
+ return "[unable to display]";
115
+ }
116
+ }
117
+ return String(value);
118
+ }
119
+ /**
120
+ * Check if object looks like JSON Schema properties
121
+ */
122
+ function isSchemaProperties(obj) {
123
+ const values = Object.values(obj);
124
+ if (values.length === 0) return false;
125
+ return values.every((v) => typeof v === "object" && v !== null && ("type" in v || "$ref" in v));
126
+ }
127
+ /**
128
+ * Format JSON Schema properties object
129
+ */
130
+ function formatSchemaProperties(props) {
131
+ const lines = [];
132
+ for (const [name, schema] of Object.entries(props)) {
133
+ const s = schema;
134
+ const type = s.type || s.$ref || "any";
135
+ const desc = s.description ? ` - ${s.description}` : "";
136
+ lines.push(`• ${name}: ${type}${desc}`);
137
+ }
138
+ return lines.join("\n");
139
+ }
140
+ /**
141
+ * Format array of named items (columns, fields, etc.)
142
+ */
143
+ function formatNamedItems(items) {
144
+ const lines = [];
145
+ for (const item of items) {
146
+ const type = item.type ? `: ${item.type}` : "";
147
+ const desc = item.description ? ` - ${item.description}` : "";
148
+ const flags = [];
149
+ if (item.primaryKey) flags.push("PK");
150
+ if (item.nullable) flags.push("nullable");
151
+ const flagsStr = flags.length > 0 ? ` (${flags.join(", ")})` : "";
152
+ lines.push(`• ${item.name}${type}${flagsStr}${desc}`);
153
+ }
154
+ return lines.join("\n");
155
+ }
156
+ /**
46
157
  * Format date and time
47
158
  */
48
159
  function formatDateTime(date) {
@@ -55,20 +166,6 @@ function formatDateTime(date) {
55
166
  });
56
167
  }
57
168
  /**
58
- * Word wrap text
59
- */
60
- function wrapText(text, maxWidth) {
61
- const words = text.split(/\s+/);
62
- const lines = [];
63
- let current = "";
64
- for (const word of words) if (current.length + word.length + 1 > maxWidth) {
65
- if (current) lines.push(current);
66
- current = word;
67
- } else current = current ? `${current} ${word}` : word;
68
- if (current) lines.push(current);
69
- return lines;
70
- }
71
- /**
72
169
  * Create metadata panel component
73
170
  */
74
171
  function createMetadataPanel(blessed, options) {
@@ -1 +1 @@
1
- {"version":3,"file":"metadata-panel.mjs","names":[],"sources":["../../../src/explorer/components/metadata-panel.ts"],"sourcesContent":["/**\n * AFS Explorer Metadata Panel Component\n *\n * Right panel showing detailed metadata for selected entry.\n */\n\nimport type Blessed from \"blessed\";\nimport { Colors, formatSize, Icons } from \"../theme.js\";\nimport type { EntryMetadata, ExplorerEntry } from \"../types.js\";\n\nexport interface MetadataPanelOptions {\n parent: Blessed.Widgets.Node;\n width: string | number;\n height: string | number;\n top?: string | number;\n right?: string | number;\n}\n\n/**\n * Format metadata for display\n */\nexport function formatMetadata(entry: ExplorerEntry, metadata?: EntryMetadata): string[] {\n const lines: string[] = [];\n\n // Entry name with type indicator (only show icon for non-files)\n const icon = entry.type !== \"file\" ? Icons[entry.type] : \"\";\n const prefix = icon ? `${icon} ` : \"\";\n lines.push(`${prefix}${entry.name}`);\n lines.push(\"\");\n\n // Type\n lines.push(`Type: ${entry.type}`);\n\n // Size\n if (entry.size !== undefined || metadata?.size !== undefined) {\n const size = metadata?.size ?? entry.size;\n lines.push(`Size: ${formatSize(size!)}`);\n }\n\n // Children count\n if (entry.childrenCount !== undefined || metadata?.childrenCount !== undefined) {\n const count = metadata?.childrenCount ?? entry.childrenCount;\n lines.push(`Items: ${count}`);\n }\n\n // Modified date\n if (entry.modified || metadata?.modified) {\n const date = metadata?.modified ?? entry.modified;\n lines.push(`Modified: ${formatDateTime(date!)}`);\n }\n\n // Provider\n if (entry.provider || metadata?.provider) {\n lines.push(`Provider: ${metadata?.provider ?? entry.provider}`);\n }\n\n // Hash\n if (entry.hash || metadata?.hash) {\n const hash = metadata?.hash ?? entry.hash;\n // Truncate long hashes\n const display = hash!.length > 20 ? `${hash!.slice(0, 20)}...` : hash;\n lines.push(`Hash: ${display}`);\n }\n\n // Description\n if (entry.description || metadata?.description) {\n lines.push(\"\");\n lines.push(\"Description:\");\n const desc = metadata?.description ?? entry.description;\n // Word wrap description\n const wrapped = wrapText(desc!, 25);\n lines.push(...wrapped);\n }\n\n // Mount path\n if (metadata?.mountPath) {\n lines.push(\"\");\n lines.push(`Mount: ${metadata.mountPath}`);\n }\n\n // URI\n if (metadata?.uri) {\n lines.push(`URI: ${metadata.uri}`);\n }\n\n return lines;\n}\n\n/**\n * Format date and time\n */\nfunction formatDateTime(date: Date): string {\n return date.toLocaleString(\"en\", {\n year: \"numeric\",\n month: \"short\",\n day: \"numeric\",\n hour: \"2-digit\",\n minute: \"2-digit\",\n });\n}\n\n/**\n * Word wrap text\n */\nfunction wrapText(text: string, maxWidth: number): string[] {\n const words = text.split(/\\s+/);\n const lines: string[] = [];\n let current = \"\";\n\n for (const word of words) {\n if (current.length + word.length + 1 > maxWidth) {\n if (current) lines.push(current);\n current = word;\n } else {\n current = current ? `${current} ${word}` : word;\n }\n }\n if (current) lines.push(current);\n\n return lines;\n}\n\n/**\n * Create metadata panel component\n */\nexport function createMetadataPanel(blessed: typeof Blessed, options: MetadataPanelOptions) {\n const { parent, width, height, top = 0, right = 0 } = options;\n\n // Create box for metadata panel\n const panel = blessed.box({\n parent,\n top,\n right,\n width,\n height,\n tags: true,\n scrollable: true,\n alwaysScroll: true,\n style: {\n fg: Colors.fg.normal,\n bg: Colors.bg.main,\n },\n border: {\n type: \"line\",\n },\n label: \" Details \",\n });\n\n let currentEntry: ExplorerEntry | undefined;\n let _currentMetadata: EntryMetadata | undefined;\n\n return {\n element: panel,\n\n /**\n * Update panel with entry info\n */\n update(entry: ExplorerEntry, metadata?: EntryMetadata): void {\n currentEntry = entry;\n _currentMetadata = metadata;\n\n if (entry.type === \"up\") {\n panel.setContent(\" Parent directory\");\n (panel.screen as Blessed.Widgets.Screen)?.render();\n return;\n }\n\n const lines = formatMetadata(entry, metadata);\n panel.setContent(lines.map((l) => ` ${l}`).join(\"\\n\"));\n (panel.screen as Blessed.Widgets.Screen)?.render();\n },\n\n /**\n * Clear the panel\n */\n clear(): void {\n currentEntry = undefined;\n _currentMetadata = undefined;\n panel.setContent(\"\");\n (panel.screen as Blessed.Widgets.Screen)?.render();\n },\n\n /**\n * Get current entry\n */\n getCurrentEntry(): ExplorerEntry | undefined {\n return currentEntry;\n },\n\n /**\n * Destroy the component\n */\n destroy(): void {\n panel.destroy();\n },\n };\n}\n\nexport type MetadataPanel = ReturnType<typeof createMetadataPanel>;\n"],"mappings":"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"}
1
+ {"version":3,"file":"metadata-panel.mjs","names":[],"sources":["../../../src/explorer/components/metadata-panel.ts"],"sourcesContent":["/**\n * AFS Explorer Metadata Panel Component\n *\n * Right panel showing detailed metadata for selected entry.\n */\n\nimport type Blessed from \"blessed\";\nimport { Colors, formatSize, Icons } from \"../theme.js\";\nimport type { EntryMetadata, ExplorerEntry } from \"../types.js\";\n\nexport interface MetadataPanelOptions {\n parent: Blessed.Widgets.Node;\n width: string | number;\n height: string | number;\n top?: string | number;\n right?: string | number;\n}\n\n/**\n * Format metadata for display\n */\nexport function formatMetadata(entry: ExplorerEntry, metadata?: EntryMetadata): string[] {\n const lines: string[] = [];\n\n // Entry name with type indicator (only show icon for non-files)\n const icon = entry.type !== \"file\" ? Icons[entry.type] : \"\";\n const prefix = icon ? `${icon} ` : \"\";\n lines.push(`${prefix}${entry.name}`);\n lines.push(\"\");\n\n // Path\n lines.push(`Path: ${entry.path}`);\n\n // Size\n if (entry.size !== undefined || metadata?.size !== undefined) {\n const size = metadata?.size ?? entry.size;\n lines.push(`Size: ${formatSize(size!)}`);\n }\n\n // Children count\n if (entry.childrenCount !== undefined || metadata?.childrenCount !== undefined) {\n const count = metadata?.childrenCount ?? entry.childrenCount;\n lines.push(`Items: ${count}`);\n }\n\n // Modified date\n if (entry.modified || metadata?.modified) {\n const date = metadata?.modified ?? entry.modified;\n lines.push(`Modified: ${formatDateTime(date!)}`);\n }\n\n // Provider\n if (entry.provider || metadata?.provider) {\n lines.push(`Provider: ${metadata?.provider ?? entry.provider}`);\n }\n\n // Hash\n if (entry.hash || metadata?.hash) {\n const hash = metadata?.hash ?? entry.hash;\n // Truncate long hashes\n const display = hash!.length > 20 ? `${hash!.slice(0, 20)}...` : hash;\n lines.push(`Hash: ${display}`);\n }\n\n // Mount path\n if (metadata?.mountPath) {\n lines.push(`Mount: ${metadata.mountPath}`);\n }\n\n // URI\n if (metadata?.uri) {\n lines.push(`URI: ${metadata.uri}`);\n }\n\n // Kind/Kinds information (show one or the other, avoid redundancy)\n // Prefer entry.kinds/kind, fallback to metadata.extra.kinds/kind\n const kinds =\n entry.kinds && entry.kinds.length > 0\n ? entry.kinds\n : (metadata?.extra?.kinds as string[] | undefined);\n const kind = entry.kind ?? (metadata?.extra?.kind as string | undefined);\n\n if (kinds && kinds.length > 0) {\n lines.push(`Kinds: ${kinds.join(\" → \")}`);\n } else if (kind) {\n lines.push(`Kind: ${kind}`);\n }\n\n // Display all meta fields from extra (flat, same level as other fields)\n if (metadata?.extra && Object.keys(metadata.extra).length > 0) {\n // Filter out built-in fields that are already displayed above\n const builtInFields = new Set([\n \"size\",\n \"mimeType\",\n \"childrenCount\",\n \"hash\",\n \"provider\",\n \"mountPath\",\n \"uri\",\n \"permissions\",\n \"kind\",\n \"kinds\",\n ]);\n\n for (const [key, value] of Object.entries(metadata.extra)) {\n if (builtInFields.has(key) || value === undefined) continue;\n\n // Special handling for inputSchema - show properties nicely\n if (key === \"inputSchema\" && typeof value === \"object\" && value !== null) {\n const schema = value as Record<string, unknown>;\n if (schema.properties && typeof schema.properties === \"object\") {\n lines.push(\"\");\n lines.push(\"InputSchema:\");\n const props = schema.properties as Record<string, unknown>;\n for (const [propName, propSchema] of Object.entries(props)) {\n const ps = propSchema as Record<string, unknown>;\n const type = ps.type || \"any\";\n const desc = ps.description ? ` - ${ps.description}` : \"\";\n const req =\n Array.isArray(schema.required) && schema.required.includes(propName) ? \"*\" : \"\";\n lines.push(` • ${propName}${req}: ${type}${desc}`);\n }\n continue;\n }\n }\n\n // Capitalize first letter of key for display\n const displayKey = key.charAt(0).toUpperCase() + key.slice(1);\n const displayValue = formatValue(value);\n\n if (displayValue.includes(\"\\n\")) {\n lines.push(\"\");\n lines.push(`${displayKey}:`);\n for (const line of displayValue.split(\"\\n\")) {\n lines.push(` ${line}`);\n }\n } else {\n lines.push(`${displayKey}: ${displayValue}`);\n }\n }\n }\n\n // Actions section (prefer metadata.actions from stat, fallback to entry.actions)\n const actions = metadata?.actions ?? entry.actions;\n lines.push(\"\");\n lines.push(\"─────── Actions ───────\");\n if (actions && actions.length > 0) {\n for (let i = 0; i < actions.length; i++) {\n const action = actions[i];\n if (action) {\n lines.push(`[${i + 1}] ${action.name}`);\n }\n }\n lines.push(\"\");\n lines.push(\"(F4 to execute)\");\n } else {\n lines.push(\"(none)\");\n }\n\n return lines;\n}\n\n/**\n * Format a value for display\n */\nfunction formatValue(value: unknown): string {\n if (value === null || value === undefined) {\n return \"\";\n }\n if (typeof value === \"string\") {\n return value;\n }\n if (typeof value === \"number\" || typeof value === \"boolean\") {\n return String(value);\n }\n if (Array.isArray(value)) {\n if (value.length === 0) return \"[]\";\n // Simple arrays of primitives\n if (value.every((v) => typeof v === \"string\" || typeof v === \"number\")) {\n return value.join(\", \");\n }\n // Arrays of objects with name/type (like columns, fields, properties)\n if (value.every((v) => typeof v === \"object\" && v !== null && \"name\" in v)) {\n return formatNamedItems(\n value as Array<{ name: string; type?: string; description?: string }>,\n );\n }\n try {\n return JSON.stringify(value, null, 2);\n } catch {\n return \"[unable to display]\";\n }\n }\n if (typeof value === \"object\") {\n // Check if it's a JSON Schema properties object\n const obj = value as Record<string, unknown>;\n if (isSchemaProperties(obj)) {\n return formatSchemaProperties(obj);\n }\n try {\n return JSON.stringify(value, null, 2);\n } catch {\n return \"[unable to display]\";\n }\n }\n return String(value);\n}\n\n/**\n * Check if object looks like JSON Schema properties\n */\nfunction isSchemaProperties(obj: Record<string, unknown>): boolean {\n const values = Object.values(obj);\n if (values.length === 0) return false;\n // Check if values look like schema definitions (have type property)\n return values.every((v) => typeof v === \"object\" && v !== null && (\"type\" in v || \"$ref\" in v));\n}\n\n/**\n * Format JSON Schema properties object\n */\nfunction formatSchemaProperties(props: Record<string, unknown>): string {\n const lines: string[] = [];\n for (const [name, schema] of Object.entries(props)) {\n const s = schema as Record<string, unknown>;\n const type = s.type || s.$ref || \"any\";\n const desc = s.description ? ` - ${s.description}` : \"\";\n lines.push(`• ${name}: ${type}${desc}`);\n }\n return lines.join(\"\\n\");\n}\n\n/**\n * Format array of named items (columns, fields, etc.)\n */\nfunction formatNamedItems(\n items: Array<{\n name: string;\n type?: string;\n description?: string;\n nullable?: boolean;\n primaryKey?: boolean;\n }>,\n): string {\n const lines: string[] = [];\n for (const item of items) {\n const type = item.type ? `: ${item.type}` : \"\";\n const desc = item.description ? ` - ${item.description}` : \"\";\n // Add flags for nullable and primaryKey\n const flags: string[] = [];\n if (item.primaryKey) flags.push(\"PK\");\n if (item.nullable) flags.push(\"nullable\");\n const flagsStr = flags.length > 0 ? ` (${flags.join(\", \")})` : \"\";\n lines.push(`• ${item.name}${type}${flagsStr}${desc}`);\n }\n return lines.join(\"\\n\");\n}\n\n/**\n * Format date and time\n */\nfunction formatDateTime(date: Date): string {\n return date.toLocaleString(\"en\", {\n year: \"numeric\",\n month: \"short\",\n day: \"numeric\",\n hour: \"2-digit\",\n minute: \"2-digit\",\n });\n}\n\n/**\n * Create metadata panel component\n */\nexport function createMetadataPanel(blessed: typeof Blessed, options: MetadataPanelOptions) {\n const { parent, width, height, top = 0, right = 0 } = options;\n\n // Create box for metadata panel\n const panel = blessed.box({\n parent,\n top,\n right,\n width,\n height,\n tags: true,\n scrollable: true,\n alwaysScroll: true,\n style: {\n fg: Colors.fg.normal,\n bg: Colors.bg.main,\n },\n border: {\n type: \"line\",\n },\n label: \" Details \",\n });\n\n let currentEntry: ExplorerEntry | undefined;\n let _currentMetadata: EntryMetadata | undefined;\n\n return {\n element: panel,\n\n /**\n * Update panel with entry info\n */\n update(entry: ExplorerEntry, metadata?: EntryMetadata): void {\n currentEntry = entry;\n _currentMetadata = metadata;\n\n if (entry.type === \"up\") {\n panel.setContent(\" Parent directory\");\n (panel.screen as Blessed.Widgets.Screen)?.render();\n return;\n }\n\n const lines = formatMetadata(entry, metadata);\n panel.setContent(lines.map((l) => ` ${l}`).join(\"\\n\"));\n (panel.screen as Blessed.Widgets.Screen)?.render();\n },\n\n /**\n * Clear the panel\n */\n clear(): void {\n currentEntry = undefined;\n _currentMetadata = undefined;\n panel.setContent(\"\");\n (panel.screen as Blessed.Widgets.Screen)?.render();\n },\n\n /**\n * Get current entry\n */\n getCurrentEntry(): ExplorerEntry | undefined {\n return currentEntry;\n },\n\n /**\n * Destroy the component\n */\n destroy(): void {\n panel.destroy();\n },\n };\n}\n\nexport type MetadataPanel = ReturnType<typeof createMetadataPanel>;\n"],"mappings":"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"}
@@ -14,24 +14,23 @@ blessed = require_rolldown_runtime.__toESM(blessed);
14
14
 
15
15
  //#region src/explorer/screen.ts
16
16
  /**
17
- * AFS Explorer Screen
18
- *
19
- * Main screen controller that manages all UI components and user interaction.
20
- */
21
- /**
22
17
  * Create and run the explorer screen
23
18
  */
24
19
  async function createExplorerScreen(options) {
25
- const { runtime, startPath = "/", version, mountCount } = options;
20
+ const { afs, startPath = "/", version } = options;
21
+ const isRemote = !!(options.input || options.output);
26
22
  const store = require_state.createStore(require_actions.createInitialState(startPath));
27
23
  const registry = require_keybindings.createDefaultRegistry();
28
- const screen = blessed.default.screen({
24
+ const screenOpts = {
29
25
  smartCSR: true,
30
26
  title: "AFS Explorer",
31
- terminal: "xterm",
27
+ terminal: options.terminal || "xterm",
32
28
  fullUnicode: true,
33
29
  warnings: false
34
- });
30
+ };
31
+ if (options.input) screenOpts.input = options.input;
32
+ if (options.output) screenOpts.output = options.output;
33
+ const screen = blessed.default.screen(screenOpts);
35
34
  require_status_bar.createStatusBar(blessed.default, {
36
35
  parent: screen,
37
36
  store,
@@ -60,12 +59,13 @@ async function createExplorerScreen(options) {
60
59
  bottom: 0
61
60
  });
62
61
  const dialogs = require_dialog.createDialogManager(blessed.default, { parent: screen });
62
+ const mountCount = afs.getMounts().length;
63
63
  async function loadPath(path) {
64
64
  store.setState({
65
65
  loading: true,
66
66
  error: void 0
67
67
  });
68
- const result = await require_actions.loadDirectory(runtime, path);
68
+ const result = await require_actions.loadDirectory(afs, path);
69
69
  store.setState({
70
70
  currentPath: path,
71
71
  entries: result.entries,
@@ -79,7 +79,7 @@ async function createExplorerScreen(options) {
79
79
  async function updateMetadata() {
80
80
  const selected = require_actions.navigation.getSelected(store.getState());
81
81
  if (selected) {
82
- const metadata = await require_actions.loadMetadata(runtime, selected);
82
+ const metadata = await require_actions.loadMetadata(afs, selected);
83
83
  metadataPanel.update(selected, metadata);
84
84
  } else metadataPanel.clear();
85
85
  }
@@ -99,7 +99,7 @@ async function createExplorerScreen(options) {
99
99
  if (!selected || selected.type === "up") return;
100
100
  if (selected.type === "file") {
101
101
  dialogs.showLoading("Loading file");
102
- const result = await require_actions.readFileContent(runtime, selected.path);
102
+ const result = await require_actions.readFileContent(afs, selected.path);
103
103
  if (result.error) dialogs.showError("View Error", result.error);
104
104
  else dialogs.showFileView(selected.path, result.content);
105
105
  } else if (selected.type === "directory") await loadPath(selected.path);
@@ -108,16 +108,61 @@ async function createExplorerScreen(options) {
108
108
  const selected = require_actions.navigation.getSelected(store.getState());
109
109
  if (!selected || selected.type === "up") return;
110
110
  dialogs.showLoading("Getting explain info");
111
- const result = await require_actions.getExplain(runtime, selected.path);
111
+ const result = await require_actions.getExplain(afs, selected.path);
112
112
  if (result.error) dialogs.showError("Explain Error", result.error);
113
113
  else dialogs.showExplain(selected.path, result.content);
114
114
  }
115
+ async function runAction(item) {
116
+ if (item.inputSchema) dialogs.showParamsInput(item.path, item.inputSchema, async (params) => {
117
+ dialogs.showLoading("Executing action");
118
+ const result = await require_actions.executeAction(afs, item.path, item.name, params);
119
+ dialogs.showActionResult(item.name, result.success, result.message, result.data);
120
+ });
121
+ else {
122
+ dialogs.showLoading("Executing action");
123
+ const result = await require_actions.executeAction(afs, item.path, item.name);
124
+ dialogs.showActionResult(item.name, result.success, result.message, result.data);
125
+ }
126
+ }
115
127
  async function handleExec() {
116
128
  const selected = require_actions.navigation.getSelected(store.getState());
117
129
  if (!selected || selected.type === "up") return;
118
- dialogs.showLoading("Executing action");
119
- const result = await require_actions.executeAction(runtime, selected.path, "default");
120
- dialogs.showActionResult("default", result.success, result.message, result.data);
130
+ const metadata = await require_actions.loadMetadata(afs, selected);
131
+ const actionItems = [];
132
+ const actions = metadata?.actions ?? selected.actions;
133
+ if (actions && actions.length > 0) for (const action of actions) {
134
+ let inputSchema = action.inputSchema;
135
+ if (!inputSchema) try {
136
+ const actionPath = `${selected.path}/.actions/${action.name}`;
137
+ inputSchema = (await afs.stat(actionPath)).data?.meta?.inputSchema;
138
+ } catch {}
139
+ actionItems.push({
140
+ name: action.name,
141
+ path: `${selected.path}/.actions/${action.name}`,
142
+ description: action.description,
143
+ inputSchema
144
+ });
145
+ }
146
+ if (selected.type === "exec") {
147
+ const inputSchema = metadata?.extra?.inputSchema;
148
+ actionItems.push({
149
+ name: "Execute",
150
+ path: selected.path,
151
+ description: "Execute this node directly",
152
+ inputSchema
153
+ });
154
+ }
155
+ if (actionItems.length === 0) {
156
+ dialogs.showError("No Actions", `${selected.name} has no available actions`);
157
+ return;
158
+ }
159
+ if (actionItems.length === 1) {
160
+ await runAction(actionItems[0]);
161
+ return;
162
+ }
163
+ dialogs.showActionPicker(selected.path, actionItems, async (item) => {
164
+ await runAction(item);
165
+ });
121
166
  }
122
167
  async function handleRefresh() {
123
168
  await loadPath(store.getState().currentPath);
@@ -129,13 +174,19 @@ async function createExplorerScreen(options) {
129
174
  exec: handleExec,
130
175
  refresh: handleRefresh,
131
176
  quit: () => {
132
- dialogs.showConfirm("Are you sure you want to quit?", () => {
133
- screen.destroy();
134
- require_index.printLogo();
177
+ dialogs.showConfirm("Are you sure you want to quit?", async () => {
178
+ if (isRemote || options.onExit) {
179
+ screen.destroy();
180
+ options.onExit?.();
181
+ return;
182
+ }
183
+ const logo = require_index.colors.brightCyan("▄▀█ █▀▀ █▀\n█▀█ █▀░ ▄█\n");
184
+ const tagline = require_index.colors.dim("Agentic File System");
135
185
  const versionPart = require_index.colors.green(`v${version}`);
136
186
  const mountPart = require_index.colors.yellow(`${mountCount} ${mountCount === 1 ? "mount" : "mounts"}`);
137
- console.log(`${versionPart} ${require_index.colors.dim("•")} ${mountPart}`);
138
- console.log(require_index.colors.dim("\nThanks for using AFS Explorer!\n"));
187
+ const farewell = `\n${logo}${tagline}\n\n${`${versionPart} ${require_index.colors.dim("•")} ${mountPart}`}\n${require_index.colors.dim("Thanks for using AFS Explorer!")}\n`;
188
+ screen.destroy();
189
+ process.stdout.write(farewell);
139
190
  process.exit(0);
140
191
  });
141
192
  },
@@ -0,0 +1,23 @@
1
+ import { AFS } from "@aigne/afs";
2
+
3
+ //#region src/explorer/screen.d.ts
4
+ interface ExplorerScreenOptions {
5
+ afs: AFS;
6
+ startPath?: string;
7
+ version: string;
8
+ /** Custom input stream (for remote/WebSocket sessions). */
9
+ input?: NodeJS.ReadableStream;
10
+ /** Custom output stream (for remote/WebSocket sessions). */
11
+ output?: NodeJS.WritableStream;
12
+ /** Terminal type override. */
13
+ terminal?: string;
14
+ /** Called when the screen is destroyed (instead of process.exit). */
15
+ onExit?: () => void;
16
+ }
17
+ /**
18
+ * Create and run the explorer screen
19
+ */
20
+ declare function createExplorerScreen(options: ExplorerScreenOptions): Promise<void>;
21
+ //#endregion
22
+ export { createExplorerScreen };
23
+ //# sourceMappingURL=screen.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"screen.d.cts","names":[],"sources":["../../src/explorer/screen.ts"],"mappings":";;;UA6BiB,qBAAA;EACf,GAAA,EAAK,GAAA;EACL,SAAA;EACA,OAAA;EAI8B;EAF9B,KAAA,GAAQ,MAAA,CAAO,cAAA;EAJV;EAML,MAAA,GAAS,MAAA,CAAO,cAAA;EAJhB;EAMA,QAAA;EAJQ;EAMR,MAAA;AAAA;;;;iBAMoB,oBAAA,CAAqB,OAAA,EAAS,qBAAA,GAAwB,OAAA"}
@@ -0,0 +1,23 @@
1
+ import { AFS } from "@aigne/afs";
2
+
3
+ //#region src/explorer/screen.d.ts
4
+ interface ExplorerScreenOptions {
5
+ afs: AFS;
6
+ startPath?: string;
7
+ version: string;
8
+ /** Custom input stream (for remote/WebSocket sessions). */
9
+ input?: NodeJS.ReadableStream;
10
+ /** Custom output stream (for remote/WebSocket sessions). */
11
+ output?: NodeJS.WritableStream;
12
+ /** Terminal type override. */
13
+ terminal?: string;
14
+ /** Called when the screen is destroyed (instead of process.exit). */
15
+ onExit?: () => void;
16
+ }
17
+ /**
18
+ * Create and run the explorer screen
19
+ */
20
+ declare function createExplorerScreen(options: ExplorerScreenOptions): Promise<void>;
21
+ //#endregion
22
+ export { createExplorerScreen };
23
+ //# sourceMappingURL=screen.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"screen.d.mts","names":[],"sources":["../../src/explorer/screen.ts"],"mappings":";;;UA6BiB,qBAAA;EACf,GAAA,EAAK,GAAA;EACL,SAAA;EACA,OAAA;EAI8B;EAF9B,KAAA,GAAQ,MAAA,CAAO,cAAA;EAJV;EAML,MAAA,GAAS,MAAA,CAAO,cAAA;EAJhB;EAMA,QAAA;EAJQ;EAMR,MAAA;AAAA;;;;iBAMoB,oBAAA,CAAqB,OAAA,EAAS,qBAAA,GAAwB,OAAA"}
@@ -1,4 +1,4 @@
1
- import { colors, printLogo } from "../ui/index.mjs";
1
+ import { colors } from "../ui/index.mjs";
2
2
  import { createInitialState, executeAction, getExplain, loadDirectory, loadMetadata, navigation, readFileContent } from "./actions.mjs";
3
3
  import { createDefaultRegistry } from "./keybindings.mjs";
4
4
  import { createDialogManager } from "./components/dialog.mjs";
@@ -12,24 +12,23 @@ import blessed from "blessed";
12
12
 
13
13
  //#region src/explorer/screen.ts
14
14
  /**
15
- * AFS Explorer Screen
16
- *
17
- * Main screen controller that manages all UI components and user interaction.
18
- */
19
- /**
20
15
  * Create and run the explorer screen
21
16
  */
22
17
  async function createExplorerScreen(options) {
23
- const { runtime, startPath = "/", version, mountCount } = options;
18
+ const { afs, startPath = "/", version } = options;
19
+ const isRemote = !!(options.input || options.output);
24
20
  const store = createStore(createInitialState(startPath));
25
21
  const registry = createDefaultRegistry();
26
- const screen = blessed.screen({
22
+ const screenOpts = {
27
23
  smartCSR: true,
28
24
  title: "AFS Explorer",
29
- terminal: "xterm",
25
+ terminal: options.terminal || "xterm",
30
26
  fullUnicode: true,
31
27
  warnings: false
32
- });
28
+ };
29
+ if (options.input) screenOpts.input = options.input;
30
+ if (options.output) screenOpts.output = options.output;
31
+ const screen = blessed.screen(screenOpts);
33
32
  createStatusBar(blessed, {
34
33
  parent: screen,
35
34
  store,
@@ -58,12 +57,13 @@ async function createExplorerScreen(options) {
58
57
  bottom: 0
59
58
  });
60
59
  const dialogs = createDialogManager(blessed, { parent: screen });
60
+ const mountCount = afs.getMounts().length;
61
61
  async function loadPath(path) {
62
62
  store.setState({
63
63
  loading: true,
64
64
  error: void 0
65
65
  });
66
- const result = await loadDirectory(runtime, path);
66
+ const result = await loadDirectory(afs, path);
67
67
  store.setState({
68
68
  currentPath: path,
69
69
  entries: result.entries,
@@ -77,7 +77,7 @@ async function createExplorerScreen(options) {
77
77
  async function updateMetadata() {
78
78
  const selected = navigation.getSelected(store.getState());
79
79
  if (selected) {
80
- const metadata = await loadMetadata(runtime, selected);
80
+ const metadata = await loadMetadata(afs, selected);
81
81
  metadataPanel.update(selected, metadata);
82
82
  } else metadataPanel.clear();
83
83
  }
@@ -97,7 +97,7 @@ async function createExplorerScreen(options) {
97
97
  if (!selected || selected.type === "up") return;
98
98
  if (selected.type === "file") {
99
99
  dialogs.showLoading("Loading file");
100
- const result = await readFileContent(runtime, selected.path);
100
+ const result = await readFileContent(afs, selected.path);
101
101
  if (result.error) dialogs.showError("View Error", result.error);
102
102
  else dialogs.showFileView(selected.path, result.content);
103
103
  } else if (selected.type === "directory") await loadPath(selected.path);
@@ -106,16 +106,61 @@ async function createExplorerScreen(options) {
106
106
  const selected = navigation.getSelected(store.getState());
107
107
  if (!selected || selected.type === "up") return;
108
108
  dialogs.showLoading("Getting explain info");
109
- const result = await getExplain(runtime, selected.path);
109
+ const result = await getExplain(afs, selected.path);
110
110
  if (result.error) dialogs.showError("Explain Error", result.error);
111
111
  else dialogs.showExplain(selected.path, result.content);
112
112
  }
113
+ async function runAction(item) {
114
+ if (item.inputSchema) dialogs.showParamsInput(item.path, item.inputSchema, async (params) => {
115
+ dialogs.showLoading("Executing action");
116
+ const result = await executeAction(afs, item.path, item.name, params);
117
+ dialogs.showActionResult(item.name, result.success, result.message, result.data);
118
+ });
119
+ else {
120
+ dialogs.showLoading("Executing action");
121
+ const result = await executeAction(afs, item.path, item.name);
122
+ dialogs.showActionResult(item.name, result.success, result.message, result.data);
123
+ }
124
+ }
113
125
  async function handleExec() {
114
126
  const selected = navigation.getSelected(store.getState());
115
127
  if (!selected || selected.type === "up") return;
116
- dialogs.showLoading("Executing action");
117
- const result = await executeAction(runtime, selected.path, "default");
118
- dialogs.showActionResult("default", result.success, result.message, result.data);
128
+ const metadata = await loadMetadata(afs, selected);
129
+ const actionItems = [];
130
+ const actions = metadata?.actions ?? selected.actions;
131
+ if (actions && actions.length > 0) for (const action of actions) {
132
+ let inputSchema = action.inputSchema;
133
+ if (!inputSchema) try {
134
+ const actionPath = `${selected.path}/.actions/${action.name}`;
135
+ inputSchema = (await afs.stat(actionPath)).data?.meta?.inputSchema;
136
+ } catch {}
137
+ actionItems.push({
138
+ name: action.name,
139
+ path: `${selected.path}/.actions/${action.name}`,
140
+ description: action.description,
141
+ inputSchema
142
+ });
143
+ }
144
+ if (selected.type === "exec") {
145
+ const inputSchema = metadata?.extra?.inputSchema;
146
+ actionItems.push({
147
+ name: "Execute",
148
+ path: selected.path,
149
+ description: "Execute this node directly",
150
+ inputSchema
151
+ });
152
+ }
153
+ if (actionItems.length === 0) {
154
+ dialogs.showError("No Actions", `${selected.name} has no available actions`);
155
+ return;
156
+ }
157
+ if (actionItems.length === 1) {
158
+ await runAction(actionItems[0]);
159
+ return;
160
+ }
161
+ dialogs.showActionPicker(selected.path, actionItems, async (item) => {
162
+ await runAction(item);
163
+ });
119
164
  }
120
165
  async function handleRefresh() {
121
166
  await loadPath(store.getState().currentPath);
@@ -127,13 +172,19 @@ async function createExplorerScreen(options) {
127
172
  exec: handleExec,
128
173
  refresh: handleRefresh,
129
174
  quit: () => {
130
- dialogs.showConfirm("Are you sure you want to quit?", () => {
131
- screen.destroy();
132
- printLogo();
175
+ dialogs.showConfirm("Are you sure you want to quit?", async () => {
176
+ if (isRemote || options.onExit) {
177
+ screen.destroy();
178
+ options.onExit?.();
179
+ return;
180
+ }
181
+ const logo = colors.brightCyan("▄▀█ █▀▀ █▀\n█▀█ █▀░ ▄█\n");
182
+ const tagline = colors.dim("Agentic File System");
133
183
  const versionPart = colors.green(`v${version}`);
134
184
  const mountPart = colors.yellow(`${mountCount} ${mountCount === 1 ? "mount" : "mounts"}`);
135
- console.log(`${versionPart} ${colors.dim("•")} ${mountPart}`);
136
- console.log(colors.dim("\nThanks for using AFS Explorer!\n"));
185
+ const farewell = `\n${logo}${tagline}\n\n${`${versionPart} ${colors.dim("•")} ${mountPart}`}\n${colors.dim("Thanks for using AFS Explorer!")}\n`;
186
+ screen.destroy();
187
+ process.stdout.write(farewell);
137
188
  process.exit(0);
138
189
  });
139
190
  },