@aigne/afs-cli 1.11.0-beta.10 → 1.11.0-beta.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.cjs +3 -2
- package/dist/cli.mjs +3 -2
- package/dist/cli.mjs.map +1 -1
- package/dist/config/afs-loader.cjs +64 -315
- package/dist/config/afs-loader.d.cts.map +1 -1
- package/dist/config/afs-loader.d.mts +2 -1
- package/dist/config/afs-loader.d.mts.map +1 -1
- package/dist/config/afs-loader.mjs +59 -310
- package/dist/config/afs-loader.mjs.map +1 -1
- package/dist/config/credential-helpers.cjs +291 -0
- package/dist/config/credential-helpers.d.mts +2 -0
- package/dist/config/credential-helpers.mjs +288 -0
- package/dist/config/credential-helpers.mjs.map +1 -0
- package/dist/config/loader.cjs +3 -1
- package/dist/config/loader.mjs +3 -2
- package/dist/config/loader.mjs.map +1 -1
- package/dist/config/program-install.cjs +276 -0
- package/dist/config/program-install.d.mts +1 -0
- package/dist/config/program-install.mjs +273 -0
- package/dist/config/program-install.mjs.map +1 -0
- package/dist/core/commands/connect.cjs +53 -0
- package/dist/core/commands/connect.d.mts +2 -0
- package/dist/core/commands/connect.mjs +55 -0
- package/dist/core/commands/connect.mjs.map +1 -0
- package/dist/core/commands/daemon.cjs +207 -0
- package/dist/core/commands/daemon.d.mts +2 -0
- package/dist/core/commands/daemon.mjs +208 -0
- package/dist/core/commands/daemon.mjs.map +1 -0
- package/dist/core/commands/explain.cjs +3 -1
- package/dist/core/commands/explain.mjs +3 -1
- package/dist/core/commands/explain.mjs.map +1 -1
- package/dist/core/commands/explore.cjs +47 -12
- package/dist/core/commands/explore.mjs +47 -12
- package/dist/core/commands/explore.mjs.map +1 -1
- package/dist/core/commands/gen-agent-md.cjs +126 -0
- package/dist/core/commands/gen-agent-md.d.mts +2 -0
- package/dist/core/commands/gen-agent-md.mjs +125 -0
- package/dist/core/commands/gen-agent-md.mjs.map +1 -0
- package/dist/core/commands/index.cjs +13 -1
- package/dist/core/commands/index.d.cts.map +1 -1
- package/dist/core/commands/index.d.mts +6 -0
- package/dist/core/commands/index.d.mts.map +1 -1
- package/dist/core/commands/index.mjs +13 -1
- package/dist/core/commands/index.mjs.map +1 -1
- package/dist/core/commands/install.cjs +91 -0
- package/dist/core/commands/install.d.mts +2 -0
- package/dist/core/commands/install.mjs +92 -0
- package/dist/core/commands/install.mjs.map +1 -0
- package/dist/core/commands/ls.cjs +14 -2
- package/dist/core/commands/ls.d.cts +2 -0
- package/dist/core/commands/ls.d.cts.map +1 -1
- package/dist/core/commands/ls.d.mts +2 -0
- package/dist/core/commands/ls.d.mts.map +1 -1
- package/dist/core/commands/ls.mjs +14 -2
- package/dist/core/commands/ls.mjs.map +1 -1
- package/dist/core/commands/mcp-bridge.cjs +201 -0
- package/dist/core/commands/mcp-bridge.d.mts +2 -0
- package/dist/core/commands/mcp-bridge.mjs +201 -0
- package/dist/core/commands/mcp-bridge.mjs.map +1 -0
- package/dist/core/commands/read.cjs +20 -7
- package/dist/core/commands/read.d.cts +2 -0
- package/dist/core/commands/read.d.cts.map +1 -1
- package/dist/core/commands/read.d.mts +2 -0
- package/dist/core/commands/read.d.mts.map +1 -1
- package/dist/core/commands/read.mjs +20 -7
- package/dist/core/commands/read.mjs.map +1 -1
- package/dist/core/commands/search.cjs +5 -1
- package/dist/core/commands/search.mjs +5 -1
- package/dist/core/commands/search.mjs.map +1 -1
- package/dist/core/commands/stat.mjs.map +1 -1
- package/dist/core/commands/types.d.cts +2 -0
- package/dist/core/commands/types.d.cts.map +1 -1
- package/dist/core/commands/types.d.mts +2 -0
- package/dist/core/commands/types.d.mts.map +1 -1
- package/dist/core/commands/types.mjs.map +1 -1
- package/dist/core/commands/vault.cjs +289 -0
- package/dist/core/commands/vault.d.mts +2 -0
- package/dist/core/commands/vault.mjs +289 -0
- package/dist/core/commands/vault.mjs.map +1 -0
- package/dist/core/commands/write.cjs +19 -6
- package/dist/core/commands/write.d.cts +2 -1
- package/dist/core/commands/write.d.cts.map +1 -1
- package/dist/core/commands/write.d.mts +2 -1
- package/dist/core/commands/write.d.mts.map +1 -1
- package/dist/core/commands/write.mjs +19 -6
- package/dist/core/commands/write.mjs.map +1 -1
- package/dist/core/executor/index.cjs +95 -19
- package/dist/core/executor/index.d.cts +4 -0
- package/dist/core/executor/index.d.cts.map +1 -1
- package/dist/core/executor/index.d.mts +4 -0
- package/dist/core/executor/index.d.mts.map +1 -1
- package/dist/core/executor/index.mjs +95 -19
- package/dist/core/executor/index.mjs.map +1 -1
- package/dist/core/formatters/index.d.mts +1 -0
- package/dist/core/formatters/install.cjs +21 -0
- package/dist/core/formatters/install.d.mts +1 -0
- package/dist/core/formatters/install.mjs +19 -0
- package/dist/core/formatters/install.mjs.map +1 -0
- package/dist/core/formatters/vault.cjs +36 -0
- package/dist/core/formatters/vault.mjs +32 -0
- package/dist/core/formatters/vault.mjs.map +1 -0
- package/dist/credential/index.d.mts +2 -1
- package/dist/credential/mcp-auth-context.cjs +27 -5
- package/dist/credential/mcp-auth-context.mjs +27 -5
- package/dist/credential/mcp-auth-context.mjs.map +1 -1
- package/dist/credential/resolver.cjs +7 -2
- package/dist/credential/resolver.mjs +7 -2
- package/dist/credential/resolver.mjs.map +1 -1
- package/dist/credential/vault-store.d.mts +1 -0
- package/dist/daemon/config-manager.cjs +279 -0
- package/dist/daemon/config-manager.mjs +279 -0
- package/dist/daemon/config-manager.mjs.map +1 -0
- package/dist/daemon/manager.cjs +164 -0
- package/dist/daemon/manager.mjs +157 -0
- package/dist/daemon/manager.mjs.map +1 -0
- package/dist/daemon/server.cjs +220 -0
- package/dist/daemon/server.mjs +220 -0
- package/dist/daemon/server.mjs.map +1 -0
- package/dist/mcp/http-transport.cjs +14 -1
- package/dist/mcp/http-transport.mjs +14 -1
- package/dist/mcp/http-transport.mjs.map +1 -1
- package/dist/mcp/server.cjs +4 -2
- package/dist/mcp/server.mjs +4 -2
- package/dist/mcp/server.mjs.map +1 -1
- package/dist/mcp/tools.cjs +62 -12
- package/dist/mcp/tools.mjs +62 -12
- package/dist/mcp/tools.mjs.map +1 -1
- package/dist/program/daemon-integration.cjs +46 -0
- package/dist/program/daemon-integration.mjs +45 -0
- package/dist/program/daemon-integration.mjs.map +1 -0
- package/dist/program/program-manager.cjs +162 -0
- package/dist/program/program-manager.mjs +162 -0
- package/dist/program/program-manager.mjs.map +1 -0
- package/dist/program/trigger-scanner.cjs +148 -0
- package/dist/program/trigger-scanner.mjs +148 -0
- package/dist/program/trigger-scanner.mjs.map +1 -0
- package/dist/providers/vault/dist/_virtual/_@oxc-project_runtime@0.108.0/helpers/decorate.cjs +11 -0
- package/dist/providers/vault/dist/_virtual/_@oxc-project_runtime@0.108.0/helpers/decorate.mjs +11 -0
- package/dist/providers/vault/dist/_virtual/_@oxc-project_runtime@0.108.0/helpers/decorate.mjs.map +1 -0
- package/dist/providers/vault/dist/encrypted-file.cjs +158 -0
- package/dist/providers/vault/dist/encrypted-file.mjs +153 -0
- package/dist/providers/vault/dist/encrypted-file.mjs.map +1 -0
- package/dist/providers/vault/dist/index.cjs +405 -0
- package/dist/providers/vault/dist/index.mjs +400 -0
- package/dist/providers/vault/dist/index.mjs.map +1 -0
- package/dist/providers/vault/dist/key-resolver.cjs +181 -0
- package/dist/providers/vault/dist/key-resolver.mjs +180 -0
- package/dist/providers/vault/dist/key-resolver.mjs.map +1 -0
- package/dist/repl.cjs +105 -14
- package/dist/repl.d.cts.map +1 -1
- package/dist/repl.d.mts.map +1 -1
- package/dist/repl.mjs +105 -14
- package/dist/repl.mjs.map +1 -1
- package/package.json +29 -22
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"write.d.mts","names":[],"sources":["../../../src/core/commands/write.ts"],"mappings":";;;;;;;UAgBiB,SAAA;EACf,IAAA;EACA,OAAA;EACA,
|
|
1
|
+
{"version":3,"file":"write.d.mts","names":[],"sources":["../../../src/core/commands/write.ts"],"mappings":";;;;;;;UAgBiB,SAAA;EACf,IAAA;EACA,OAAA;EACA,IAAA;EACA,KAAA;EACA,IAAA;AAAA;;;;iBAwBc,kBAAA,CACd,OAAA,EAAS,qBAAA,GACR,aAAA,UAAuB,SAAA"}
|
|
@@ -36,10 +36,22 @@ function createWriteCommand(options) {
|
|
|
36
36
|
type: "string",
|
|
37
37
|
description: "Content to write"
|
|
38
38
|
},
|
|
39
|
-
|
|
40
|
-
type: "
|
|
41
|
-
|
|
42
|
-
|
|
39
|
+
mode: {
|
|
40
|
+
type: "string",
|
|
41
|
+
choices: [
|
|
42
|
+
"replace",
|
|
43
|
+
"append",
|
|
44
|
+
"prepend",
|
|
45
|
+
"patch",
|
|
46
|
+
"create",
|
|
47
|
+
"update"
|
|
48
|
+
],
|
|
49
|
+
description: "Write mode",
|
|
50
|
+
default: "replace"
|
|
51
|
+
},
|
|
52
|
+
patch: {
|
|
53
|
+
type: "string",
|
|
54
|
+
description: "JSON array of patch operations (for mode=patch)"
|
|
43
55
|
},
|
|
44
56
|
meta: {
|
|
45
57
|
type: "string",
|
|
@@ -50,13 +62,14 @@ function createWriteCommand(options) {
|
|
|
50
62
|
handler: async (argv) => {
|
|
51
63
|
const metadata = parseMetaValues(argv.meta);
|
|
52
64
|
const fields = metadata ? Object.keys(metadata) : void 0;
|
|
53
|
-
if (argv.content === void 0 && !metadata) throw new Error("write requires content (use --content or provide as second argument)");
|
|
65
|
+
if (argv.content === void 0 && !metadata && argv.mode !== "patch") throw new Error("write requires content (use --content or provide as second argument)");
|
|
54
66
|
const afs = await resolveAFS(options);
|
|
55
67
|
const canonicalPath = cliPathToCanonical(argv.path);
|
|
56
68
|
const writeData = {};
|
|
57
69
|
if (argv.content !== void 0) writeData.content = argv.content;
|
|
58
70
|
if (metadata) writeData.meta = metadata;
|
|
59
|
-
|
|
71
|
+
if (argv.patch) writeData.patches = JSON.parse(argv.patch);
|
|
72
|
+
const result = await afs.write(canonicalPath, writeData, { mode: argv.mode });
|
|
60
73
|
options.onResult({
|
|
61
74
|
command: "write",
|
|
62
75
|
result,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"write.mjs","names":[],"sources":["../../../src/core/commands/write.ts"],"sourcesContent":["/**\n * write Command - Core Implementation\n *\n * Writes content to a file/node. Accepts AFS instance directly.\n * Returns AFSWriteResult directly (no custom type).\n */\n\nimport type { AFSWriteEntryPayload } from \"@aigne/afs\";\nimport type { CommandModule } from \"yargs\";\nimport { formatWriteOutput } from \"../formatters/index.js\";\nimport { cliPathToCanonical } from \"../path-utils.js\";\nimport { type CommandFactoryOptions, resolveAFS } from \"./types.js\";\n\n/**\n * Write command arguments\n */\nexport interface WriteArgs {\n path: string;\n content?: string;\n
|
|
1
|
+
{"version":3,"file":"write.mjs","names":[],"sources":["../../../src/core/commands/write.ts"],"sourcesContent":["/**\n * write Command - Core Implementation\n *\n * Writes content to a file/node. Accepts AFS instance directly.\n * Returns AFSWriteResult directly (no custom type).\n */\n\nimport type { AFSWriteEntryPayload } from \"@aigne/afs\";\nimport type { CommandModule } from \"yargs\";\nimport { formatWriteOutput } from \"../formatters/index.js\";\nimport { cliPathToCanonical } from \"../path-utils.js\";\nimport { type CommandFactoryOptions, resolveAFS } from \"./types.js\";\n\n/**\n * Write command arguments\n */\nexport interface WriteArgs {\n path: string;\n content?: string;\n mode: \"replace\" | \"append\" | \"prepend\" | \"patch\" | \"create\" | \"update\";\n patch?: string;\n meta?: string[];\n}\n\n/**\n * Parse --meta values into metadata object\n */\nfunction parseMetaValues(metaValues?: string[]): Record<string, string> | undefined {\n if (!metaValues || metaValues.length === 0) return undefined;\n\n const meta: Record<string, string> = {};\n for (const item of metaValues) {\n const idx = item.indexOf(\"=\");\n if (idx > 0) {\n const key = item.slice(0, idx);\n const value = item.slice(idx + 1);\n meta[key] = value;\n }\n }\n return Object.keys(meta).length > 0 ? meta : undefined;\n}\n\n/**\n * Create write command factory\n */\nexport function createWriteCommand(\n options: CommandFactoryOptions,\n): CommandModule<unknown, WriteArgs> {\n return {\n command: \"write <path> [content]\",\n describe: \"Write content to file\",\n builder: {\n path: {\n type: \"string\",\n demandOption: true,\n description: \"Path to write\",\n },\n content: {\n type: \"string\",\n description: \"Content to write\",\n },\n mode: {\n type: \"string\",\n choices: [\"replace\", \"append\", \"prepend\", \"patch\", \"create\", \"update\"] as const,\n description: \"Write mode\",\n default: \"replace\" as const,\n },\n patch: {\n type: \"string\",\n description: \"JSON array of patch operations (for mode=patch)\",\n },\n meta: {\n type: \"string\",\n array: true,\n description: \"Set metadata field (key=value)\",\n },\n },\n handler: async (argv) => {\n const metadata = parseMetaValues(argv.meta);\n const fields = metadata ? Object.keys(metadata) : undefined;\n\n // Content is required unless only setting metadata or using patch mode\n if (argv.content === undefined && !metadata && argv.mode !== \"patch\") {\n throw new Error(\"write requires content (use --content or provide as second argument)\");\n }\n\n const afs = await resolveAFS(options);\n const canonicalPath = cliPathToCanonical(argv.path);\n const writeData: AFSWriteEntryPayload = {};\n\n if (argv.content !== undefined) {\n writeData.content = argv.content;\n }\n if (metadata) {\n writeData.meta = metadata;\n }\n if (argv.patch) {\n writeData.patches = JSON.parse(argv.patch);\n }\n\n const result = await afs.write(canonicalPath, writeData, { mode: argv.mode });\n options.onResult({\n command: \"write\",\n result,\n format: (res, view) => formatWriteOutput(res, view, { fields }),\n });\n },\n };\n}\n"],"mappings":";;;;;;;;;AA2BA,SAAS,gBAAgB,YAA2D;AAClF,KAAI,CAAC,cAAc,WAAW,WAAW,EAAG,QAAO;CAEnD,MAAM,OAA+B,EAAE;AACvC,MAAK,MAAM,QAAQ,YAAY;EAC7B,MAAM,MAAM,KAAK,QAAQ,IAAI;AAC7B,MAAI,MAAM,GAAG;GACX,MAAM,MAAM,KAAK,MAAM,GAAG,IAAI;AAE9B,QAAK,OADS,KAAK,MAAM,MAAM,EAAE;;;AAIrC,QAAO,OAAO,KAAK,KAAK,CAAC,SAAS,IAAI,OAAO;;;;;AAM/C,SAAgB,mBACd,SACmC;AACnC,QAAO;EACL,SAAS;EACT,UAAU;EACV,SAAS;GACP,MAAM;IACJ,MAAM;IACN,cAAc;IACd,aAAa;IACd;GACD,SAAS;IACP,MAAM;IACN,aAAa;IACd;GACD,MAAM;IACJ,MAAM;IACN,SAAS;KAAC;KAAW;KAAU;KAAW;KAAS;KAAU;KAAS;IACtE,aAAa;IACb,SAAS;IACV;GACD,OAAO;IACL,MAAM;IACN,aAAa;IACd;GACD,MAAM;IACJ,MAAM;IACN,OAAO;IACP,aAAa;IACd;GACF;EACD,SAAS,OAAO,SAAS;GACvB,MAAM,WAAW,gBAAgB,KAAK,KAAK;GAC3C,MAAM,SAAS,WAAW,OAAO,KAAK,SAAS,GAAG;AAGlD,OAAI,KAAK,YAAY,UAAa,CAAC,YAAY,KAAK,SAAS,QAC3D,OAAM,IAAI,MAAM,uEAAuE;GAGzF,MAAM,MAAM,MAAM,WAAW,QAAQ;GACrC,MAAM,gBAAgB,mBAAmB,KAAK,KAAK;GACnD,MAAM,YAAkC,EAAE;AAE1C,OAAI,KAAK,YAAY,OACnB,WAAU,UAAU,KAAK;AAE3B,OAAI,SACF,WAAU,OAAO;AAEnB,OAAI,KAAK,MACP,WAAU,UAAU,KAAK,MAAM,KAAK,MAAM;GAG5C,MAAM,SAAS,MAAM,IAAI,MAAM,eAAe,WAAW,EAAE,MAAM,KAAK,MAAM,CAAC;AAC7E,WAAQ,SAAS;IACf,SAAS;IACT;IACA,SAAS,KAAK,SAAS,kBAAkB,KAAK,MAAM,EAAE,QAAQ,CAAC;IAChE,CAAC;;EAEL"}
|
|
@@ -4,6 +4,28 @@ let yargs = require("yargs");
|
|
|
4
4
|
yargs = require_rolldown_runtime.__toESM(yargs);
|
|
5
5
|
|
|
6
6
|
//#region src/core/executor/index.ts
|
|
7
|
+
/** Known command names and aliases for suggestion matching. */
|
|
8
|
+
const KNOWN_COMMANDS = [
|
|
9
|
+
"ls",
|
|
10
|
+
"list",
|
|
11
|
+
"read",
|
|
12
|
+
"cat",
|
|
13
|
+
"write",
|
|
14
|
+
"delete",
|
|
15
|
+
"rm",
|
|
16
|
+
"stat",
|
|
17
|
+
"exec",
|
|
18
|
+
"explain",
|
|
19
|
+
"search",
|
|
20
|
+
"grep",
|
|
21
|
+
"find",
|
|
22
|
+
"mount",
|
|
23
|
+
"serve",
|
|
24
|
+
"explore",
|
|
25
|
+
"service",
|
|
26
|
+
"connect",
|
|
27
|
+
"vault"
|
|
28
|
+
];
|
|
7
29
|
/**
|
|
8
30
|
* AFS Command Executor
|
|
9
31
|
*
|
|
@@ -43,6 +65,8 @@ var AFSCommandExecutor = class {
|
|
|
43
65
|
commandResult = result;
|
|
44
66
|
}
|
|
45
67
|
};
|
|
68
|
+
let failMsg;
|
|
69
|
+
let failErr;
|
|
46
70
|
let parser = (0, yargs.default)(normalizedArgs).scriptName("afs").usage("$0 <command> [options]").option("json", {
|
|
47
71
|
type: "boolean",
|
|
48
72
|
description: "Output in JSON format",
|
|
@@ -66,34 +90,42 @@ var AFSCommandExecutor = class {
|
|
|
66
90
|
type: "boolean",
|
|
67
91
|
description: "Start interactive REPL mode",
|
|
68
92
|
global: false
|
|
69
|
-
}).help(true).alias("h", "help").version(this.options.version || "unknown").alias("v", "version").demandCommand().
|
|
93
|
+
}).help(true).alias("h", "help").version(this.options.version || "unknown").alias("v", "version").demandCommand().strictCommands().exitProcess(false).fail((msg, err) => {
|
|
94
|
+
failErr = err || new Error(msg || "Unknown error");
|
|
95
|
+
failMsg = msg;
|
|
96
|
+
});
|
|
70
97
|
for (const factory of require_index.commandFactories) parser = parser.command(factory(factoryOptions));
|
|
71
98
|
try {
|
|
72
99
|
let output;
|
|
73
|
-
|
|
74
|
-
const parsed = await parser.parseAsync(normalizedArgs, {}, (e, _, o) => {
|
|
75
|
-
if (e) error = e;
|
|
100
|
+
await parser.parseAsync(normalizedArgs, {}, (_e, _, o) => {
|
|
76
101
|
output = o;
|
|
77
102
|
});
|
|
78
|
-
if (
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
103
|
+
if (failErr) {
|
|
104
|
+
const formatted$1 = await this.formatFailure(normalizedArgs, failMsg, parser);
|
|
105
|
+
return {
|
|
106
|
+
success: false,
|
|
107
|
+
command: normalizedArgs[0] || "unknown",
|
|
108
|
+
result: void 0,
|
|
109
|
+
formatted: formatted$1,
|
|
110
|
+
error: { message: failMsg || failErr.message }
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
if (output) return {
|
|
86
114
|
success: true,
|
|
87
115
|
command: "help",
|
|
88
116
|
formatted: output
|
|
89
117
|
};
|
|
90
|
-
if (
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
118
|
+
if (!commandResult) {
|
|
119
|
+
const formatted$1 = await this.formatFailure(normalizedArgs, void 0, parser);
|
|
120
|
+
return {
|
|
121
|
+
success: false,
|
|
122
|
+
command: normalizedArgs[0] || "unknown",
|
|
123
|
+
result: void 0,
|
|
124
|
+
formatted: formatted$1,
|
|
125
|
+
error: { message: `Unknown command: "${normalizedArgs[0] || ""}"` }
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
const view = outputOptions.json ? "json" : outputOptions.yaml ? "yaml" : commandResult.viewOverride ?? outputOptions.view;
|
|
97
129
|
const formatted = commandResult.format(commandResult.result, view, { path: this.extractPath(normalizedArgs) });
|
|
98
130
|
if (commandResult.error) return {
|
|
99
131
|
success: false,
|
|
@@ -120,6 +152,31 @@ var AFSCommandExecutor = class {
|
|
|
120
152
|
}
|
|
121
153
|
}
|
|
122
154
|
/**
|
|
155
|
+
* Format a friendly error message for unknown/invalid commands.
|
|
156
|
+
*/
|
|
157
|
+
async formatFailure(args, failMsg, parser) {
|
|
158
|
+
const cmd = args[0] || "";
|
|
159
|
+
const lines = [];
|
|
160
|
+
if (cmd && failMsg?.includes("Unknown command")) {
|
|
161
|
+
lines.push(`Unknown command: "${cmd}"`);
|
|
162
|
+
const suggestions = suggestCommands(cmd);
|
|
163
|
+
if (suggestions.length > 0) {
|
|
164
|
+
lines.push("");
|
|
165
|
+
lines.push(`Did you mean?`);
|
|
166
|
+
for (const s of suggestions) lines.push(` afs ${s}`);
|
|
167
|
+
}
|
|
168
|
+
} else if (failMsg) lines.push(failMsg);
|
|
169
|
+
else lines.push(`Unknown command: "${cmd}"`);
|
|
170
|
+
lines.push("");
|
|
171
|
+
try {
|
|
172
|
+
const helpText = await parser.getHelp();
|
|
173
|
+
lines.push(helpText);
|
|
174
|
+
} catch {
|
|
175
|
+
lines.push("Run \"afs --help\" to see available commands.");
|
|
176
|
+
}
|
|
177
|
+
return lines.join("\n");
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
123
180
|
* Normalize argv to an array of strings
|
|
124
181
|
*/
|
|
125
182
|
normalizeArgv(argv) {
|
|
@@ -191,6 +248,25 @@ var AFSCommandExecutor = class {
|
|
|
191
248
|
}
|
|
192
249
|
}
|
|
193
250
|
};
|
|
251
|
+
/** Levenshtein distance between two strings. */
|
|
252
|
+
function levenshtein(a, b) {
|
|
253
|
+
const m = a.length;
|
|
254
|
+
const n = b.length;
|
|
255
|
+
const dp = Array.from({ length: m + 1 }, () => Array(n + 1).fill(0));
|
|
256
|
+
for (let i = 0; i <= m; i++) dp[i][0] = i;
|
|
257
|
+
for (let j = 0; j <= n; j++) dp[0][j] = j;
|
|
258
|
+
for (let i = 1; i <= m; i++) for (let j = 1; j <= n; j++) dp[i][j] = a[i - 1] === b[j - 1] ? dp[i - 1][j - 1] : 1 + Math.min(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]);
|
|
259
|
+
return dp[m][n];
|
|
260
|
+
}
|
|
261
|
+
/** Suggest known commands similar to the given input. */
|
|
262
|
+
function suggestCommands(input) {
|
|
263
|
+
const lower = input.toLowerCase();
|
|
264
|
+
return KNOWN_COMMANDS.map((cmd) => ({
|
|
265
|
+
cmd,
|
|
266
|
+
dist: levenshtein(lower, cmd),
|
|
267
|
+
maxLen: Math.max(lower.length, cmd.length)
|
|
268
|
+
})).filter((x) => x.dist > 0 && x.dist < x.maxLen * .5).sort((a, b) => a.dist - b.dist).map((x) => x.cmd).slice(0, 3);
|
|
269
|
+
}
|
|
194
270
|
|
|
195
271
|
//#endregion
|
|
196
272
|
exports.AFSCommandExecutor = AFSCommandExecutor;
|
|
@@ -55,6 +55,10 @@ declare class AFSCommandExecutor {
|
|
|
55
55
|
* @returns Execution result with formatted output
|
|
56
56
|
*/
|
|
57
57
|
execute(argv: string | string[]): Promise<ExecuteResult>;
|
|
58
|
+
/**
|
|
59
|
+
* Format a friendly error message for unknown/invalid commands.
|
|
60
|
+
*/
|
|
61
|
+
private formatFailure;
|
|
58
62
|
/**
|
|
59
63
|
* Normalize argv to an array of strings
|
|
60
64
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.cts","names":[],"sources":["../../../src/core/executor/index.ts"],"mappings":";;;;;;UAkBiB,aAAA;EAQf;EANA,OAAA;EAUE;EARF,OAAA;EAUS;EART,MAAA;EAee;EAbf,SAAA;;EAEA,KAAA;IAaA,qCAXE,IAAA,WAeF;IAbE,OAAA;EAAA;AAAA;;;;UAOa,eAAA;
|
|
1
|
+
{"version":3,"file":"index.d.cts","names":[],"sources":["../../../src/core/executor/index.ts"],"mappings":";;;;;;UAkBiB,aAAA;EAQf;EANA,OAAA;EAUE;EARF,OAAA;EAUS;EART,MAAA;EAee;EAbf,SAAA;;EAEA,KAAA;IAaA,qCAXE,IAAA,WAeF;IAbE,OAAA;EAAA;AAAA;;;;UAOa,eAAA;EA6DiC;EA3DhD,GAAA;EA2D+C;EAzD/C,GAAA;EAyCQ;EAvCR,OAAA;AAAA;;;;;;;;;;;;;cAsCW,kBAAA;EAAA,QACH,GAAA;EAAA,QACA,OAAA;cAEI,GAAA,GAAM,GAAA,EAAK,OAAA,GAAU,eAAA;;;;;;;;;EAa3B,OAAA,CAAQ,IAAA,sBAA0B,OAAA,CAAQ,aAAA;;;;UAuJlC,aAAA;;;;UAwCN,aAAA;;;;UAoCA,QAAA;;;;UA2CA,oBAAA;;;;UA+BA,WAAA;AAAA"}
|
|
@@ -55,6 +55,10 @@ declare class AFSCommandExecutor {
|
|
|
55
55
|
* @returns Execution result with formatted output
|
|
56
56
|
*/
|
|
57
57
|
execute(argv: string | string[]): Promise<ExecuteResult>;
|
|
58
|
+
/**
|
|
59
|
+
* Format a friendly error message for unknown/invalid commands.
|
|
60
|
+
*/
|
|
61
|
+
private formatFailure;
|
|
58
62
|
/**
|
|
59
63
|
* Normalize argv to an array of strings
|
|
60
64
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../../../src/core/executor/index.ts"],"mappings":";;;;;;UAkBiB,aAAA;EAQf;EANA,OAAA;EAUE;EARF,OAAA;EAUS;EART,MAAA;EAee;EAbf,SAAA;;EAEA,KAAA;IAaA,qCAXE,IAAA,WAeF;IAbE,OAAA;EAAA;AAAA;;;;UAOa,eAAA;
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../../../src/core/executor/index.ts"],"mappings":";;;;;;UAkBiB,aAAA;EAQf;EANA,OAAA;EAUE;EARF,OAAA;EAUS;EART,MAAA;EAee;EAbf,SAAA;;EAEA,KAAA;IAaA,qCAXE,IAAA,WAeF;IAbE,OAAA;EAAA;AAAA;;;;UAOa,eAAA;EA6DiC;EA3DhD,GAAA;EA2D+C;EAzD/C,GAAA;EAyCQ;EAvCR,OAAA;AAAA;;;;;;;;;;;;;cAsCW,kBAAA;EAAA,QACH,GAAA;EAAA,QACA,OAAA;cAEI,GAAA,GAAM,GAAA,EAAK,OAAA,GAAU,eAAA;;;;;;;;;EAa3B,OAAA,CAAQ,IAAA,sBAA0B,OAAA,CAAQ,aAAA;;;;UAuJlC,aAAA;;;;UAwCN,aAAA;;;;UAoCA,QAAA;;;;UA2CA,oBAAA;;;;UA+BA,WAAA;AAAA"}
|
|
@@ -2,6 +2,28 @@ import { commandFactories } from "../commands/index.mjs";
|
|
|
2
2
|
import yargs from "yargs";
|
|
3
3
|
|
|
4
4
|
//#region src/core/executor/index.ts
|
|
5
|
+
/** Known command names and aliases for suggestion matching. */
|
|
6
|
+
const KNOWN_COMMANDS = [
|
|
7
|
+
"ls",
|
|
8
|
+
"list",
|
|
9
|
+
"read",
|
|
10
|
+
"cat",
|
|
11
|
+
"write",
|
|
12
|
+
"delete",
|
|
13
|
+
"rm",
|
|
14
|
+
"stat",
|
|
15
|
+
"exec",
|
|
16
|
+
"explain",
|
|
17
|
+
"search",
|
|
18
|
+
"grep",
|
|
19
|
+
"find",
|
|
20
|
+
"mount",
|
|
21
|
+
"serve",
|
|
22
|
+
"explore",
|
|
23
|
+
"service",
|
|
24
|
+
"connect",
|
|
25
|
+
"vault"
|
|
26
|
+
];
|
|
5
27
|
/**
|
|
6
28
|
* AFS Command Executor
|
|
7
29
|
*
|
|
@@ -41,6 +63,8 @@ var AFSCommandExecutor = class {
|
|
|
41
63
|
commandResult = result;
|
|
42
64
|
}
|
|
43
65
|
};
|
|
66
|
+
let failMsg;
|
|
67
|
+
let failErr;
|
|
44
68
|
let parser = yargs(normalizedArgs).scriptName("afs").usage("$0 <command> [options]").option("json", {
|
|
45
69
|
type: "boolean",
|
|
46
70
|
description: "Output in JSON format",
|
|
@@ -64,34 +88,42 @@ var AFSCommandExecutor = class {
|
|
|
64
88
|
type: "boolean",
|
|
65
89
|
description: "Start interactive REPL mode",
|
|
66
90
|
global: false
|
|
67
|
-
}).help(true).alias("h", "help").version(this.options.version || "unknown").alias("v", "version").demandCommand().
|
|
91
|
+
}).help(true).alias("h", "help").version(this.options.version || "unknown").alias("v", "version").demandCommand().strictCommands().exitProcess(false).fail((msg, err) => {
|
|
92
|
+
failErr = err || new Error(msg || "Unknown error");
|
|
93
|
+
failMsg = msg;
|
|
94
|
+
});
|
|
68
95
|
for (const factory of commandFactories) parser = parser.command(factory(factoryOptions));
|
|
69
96
|
try {
|
|
70
97
|
let output;
|
|
71
|
-
|
|
72
|
-
const parsed = await parser.parseAsync(normalizedArgs, {}, (e, _, o) => {
|
|
73
|
-
if (e) error = e;
|
|
98
|
+
await parser.parseAsync(normalizedArgs, {}, (_e, _, o) => {
|
|
74
99
|
output = o;
|
|
75
100
|
});
|
|
76
|
-
if (
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
101
|
+
if (failErr) {
|
|
102
|
+
const formatted$1 = await this.formatFailure(normalizedArgs, failMsg, parser);
|
|
103
|
+
return {
|
|
104
|
+
success: false,
|
|
105
|
+
command: normalizedArgs[0] || "unknown",
|
|
106
|
+
result: void 0,
|
|
107
|
+
formatted: formatted$1,
|
|
108
|
+
error: { message: failMsg || failErr.message }
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
if (output) return {
|
|
84
112
|
success: true,
|
|
85
113
|
command: "help",
|
|
86
114
|
formatted: output
|
|
87
115
|
};
|
|
88
|
-
if (
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
116
|
+
if (!commandResult) {
|
|
117
|
+
const formatted$1 = await this.formatFailure(normalizedArgs, void 0, parser);
|
|
118
|
+
return {
|
|
119
|
+
success: false,
|
|
120
|
+
command: normalizedArgs[0] || "unknown",
|
|
121
|
+
result: void 0,
|
|
122
|
+
formatted: formatted$1,
|
|
123
|
+
error: { message: `Unknown command: "${normalizedArgs[0] || ""}"` }
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
const view = outputOptions.json ? "json" : outputOptions.yaml ? "yaml" : commandResult.viewOverride ?? outputOptions.view;
|
|
95
127
|
const formatted = commandResult.format(commandResult.result, view, { path: this.extractPath(normalizedArgs) });
|
|
96
128
|
if (commandResult.error) return {
|
|
97
129
|
success: false,
|
|
@@ -118,6 +150,31 @@ var AFSCommandExecutor = class {
|
|
|
118
150
|
}
|
|
119
151
|
}
|
|
120
152
|
/**
|
|
153
|
+
* Format a friendly error message for unknown/invalid commands.
|
|
154
|
+
*/
|
|
155
|
+
async formatFailure(args, failMsg, parser) {
|
|
156
|
+
const cmd = args[0] || "";
|
|
157
|
+
const lines = [];
|
|
158
|
+
if (cmd && failMsg?.includes("Unknown command")) {
|
|
159
|
+
lines.push(`Unknown command: "${cmd}"`);
|
|
160
|
+
const suggestions = suggestCommands(cmd);
|
|
161
|
+
if (suggestions.length > 0) {
|
|
162
|
+
lines.push("");
|
|
163
|
+
lines.push(`Did you mean?`);
|
|
164
|
+
for (const s of suggestions) lines.push(` afs ${s}`);
|
|
165
|
+
}
|
|
166
|
+
} else if (failMsg) lines.push(failMsg);
|
|
167
|
+
else lines.push(`Unknown command: "${cmd}"`);
|
|
168
|
+
lines.push("");
|
|
169
|
+
try {
|
|
170
|
+
const helpText = await parser.getHelp();
|
|
171
|
+
lines.push(helpText);
|
|
172
|
+
} catch {
|
|
173
|
+
lines.push("Run \"afs --help\" to see available commands.");
|
|
174
|
+
}
|
|
175
|
+
return lines.join("\n");
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
121
178
|
* Normalize argv to an array of strings
|
|
122
179
|
*/
|
|
123
180
|
normalizeArgv(argv) {
|
|
@@ -189,6 +246,25 @@ var AFSCommandExecutor = class {
|
|
|
189
246
|
}
|
|
190
247
|
}
|
|
191
248
|
};
|
|
249
|
+
/** Levenshtein distance between two strings. */
|
|
250
|
+
function levenshtein(a, b) {
|
|
251
|
+
const m = a.length;
|
|
252
|
+
const n = b.length;
|
|
253
|
+
const dp = Array.from({ length: m + 1 }, () => Array(n + 1).fill(0));
|
|
254
|
+
for (let i = 0; i <= m; i++) dp[i][0] = i;
|
|
255
|
+
for (let j = 0; j <= n; j++) dp[0][j] = j;
|
|
256
|
+
for (let i = 1; i <= m; i++) for (let j = 1; j <= n; j++) dp[i][j] = a[i - 1] === b[j - 1] ? dp[i - 1][j - 1] : 1 + Math.min(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]);
|
|
257
|
+
return dp[m][n];
|
|
258
|
+
}
|
|
259
|
+
/** Suggest known commands similar to the given input. */
|
|
260
|
+
function suggestCommands(input) {
|
|
261
|
+
const lower = input.toLowerCase();
|
|
262
|
+
return KNOWN_COMMANDS.map((cmd) => ({
|
|
263
|
+
cmd,
|
|
264
|
+
dist: levenshtein(lower, cmd),
|
|
265
|
+
maxLen: Math.max(lower.length, cmd.length)
|
|
266
|
+
})).filter((x) => x.dist > 0 && x.dist < x.maxLen * .5).sort((a, b) => a.dist - b.dist).map((x) => x.cmd).slice(0, 3);
|
|
267
|
+
}
|
|
192
268
|
|
|
193
269
|
//#endregion
|
|
194
270
|
export { AFSCommandExecutor };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":[],"sources":["../../../src/core/executor/index.ts"],"sourcesContent":["/**\n * AFS Command Executor\n *\n * Unified command execution interface using yargs and CommandFactory pattern.\n */\n\nimport type { AFS } from \"@aigne/afs\";\nimport yargs from \"yargs\";\nimport {\n type CommandFactoryOptions,\n type CommandOutput,\n commandFactories,\n} from \"../commands/index.js\";\nimport type { ViewType } from \"../types.js\";\n\n/**\n * Result from executing a command\n */\nexport interface ExecuteResult {\n /** Whether the command executed successfully */\n success: boolean;\n /** The command that was executed (ls, read, write, etc.) */\n command: string;\n /** The raw result data from AFS */\n result?: unknown;\n /** Formatted output string */\n formatted: string;\n /** Error info if the command failed */\n error?: {\n /** Exit code (from ExitCode enum) */\n code?: number;\n /** Error message */\n message: string;\n };\n}\n\n/**\n * Options for the executor\n */\nexport interface ExecutorOptions {\n /** Whether the output is for a TTY (enables colors) */\n tty?: boolean;\n /** Current working directory (for explore command) */\n cwd?: string;\n /** Version of the AFS CLI */\n version?: string;\n}\n\n/**\n * AFS Command Executor\n *\n * Provides a unified interface for executing AFS commands using yargs.\n *\n * @example\n * ```typescript\n * const executor = new AFSCommandExecutor(afs, { tty: false });\n * const result = await executor.execute(\"afs ls /path --depth=2\");\n * console.log(result.formatted);\n * ```\n */\nexport class AFSCommandExecutor {\n private afs?: AFS;\n private options: ExecutorOptions;\n\n constructor(afs?: AFS, options?: ExecutorOptions) {\n this.afs = afs;\n this.options = options ?? {};\n }\n\n /**\n * Execute an AFS command\n *\n * @param argv - Command string or array of arguments\n * - String: \"afs ls /path --depth=2\" or \"ls /path --depth=2\"\n * - Array: [\"ls\", \"/path\", \"--depth=2\"]\n * @returns Execution result with formatted output\n */\n async execute(argv: string | string[]): Promise<ExecuteResult> {\n const normalizedArgs = this.normalizeArgv(argv);\n\n // Capture command result\n let commandResult: CommandOutput | undefined;\n\n // Determine output format from args\n const outputOptions = this.extractOutputOptions(normalizedArgs);\n\n // Create factory options\n const factoryOptions: CommandFactoryOptions = {\n afs: this.afs,\n argv: normalizedArgs,\n cwd: this.options.cwd,\n onResult: (result) => {\n commandResult = result;\n },\n };\n\n // Build yargs parser with all commands\n let parser = yargs(normalizedArgs)\n .scriptName(\"afs\")\n .usage(\"$0 <command> [options]\")\n .option(\"json\", {\n type: \"boolean\",\n description: \"Output in JSON format\",\n global: true,\n })\n .option(\"yaml\", {\n type: \"boolean\",\n description: \"Output in YAML format\",\n global: true,\n })\n .option(\"view\", {\n type: \"string\",\n choices: [\"default\", \"llm\", \"human\"],\n default: \"default\",\n description: \"Output view format\",\n global: true,\n })\n .option(\"interactive\", {\n alias: \"i\",\n type: \"boolean\",\n description: \"Start interactive REPL mode\",\n global: false,\n })\n .help(true)\n .alias(\"h\", \"help\")\n .version(this.options.version || \"unknown\")\n .alias(\"v\", \"version\")\n .demandCommand()\n .showHelpOnFail(true)\n .exitProcess(false);\n\n // Register all commands from factories\n for (const factory of commandFactories) {\n parser = parser.command(factory(factoryOptions));\n }\n\n // Parse and execute\n try {\n let output: string | undefined;\n let error: Error | undefined;\n\n const parsed = await parser.parseAsync(normalizedArgs, {}, (e, _, o) => {\n if (e) error = e;\n output = o;\n });\n\n if (error) {\n return {\n success: false,\n command: normalizedArgs[0] || \"unknown\",\n result: undefined,\n formatted: output!,\n error: { message: error.message },\n };\n }\n\n if (parsed.help) {\n return {\n success: true,\n command: \"help\",\n formatted: output!,\n };\n }\n if (parsed.version) {\n return {\n success: true,\n command: \"version\",\n formatted: output!,\n };\n }\n\n if (!commandResult) {\n throw new Error(\"Command not found\");\n }\n\n // Always use the formatter - it handles json/llm/human views\n const view: ViewType = outputOptions.json\n ? \"json\"\n : outputOptions.yaml\n ? \"yaml\"\n : outputOptions.view;\n const formatted = commandResult.format(commandResult.result, view, {\n path: this.extractPath(normalizedArgs),\n });\n\n // Check if command indicated failure\n if (commandResult.error) {\n return {\n success: false,\n command: commandResult.command,\n result: commandResult.result,\n formatted,\n error: commandResult.error,\n };\n }\n\n return {\n success: true,\n command: commandResult.command,\n result: commandResult.result,\n formatted,\n };\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n\n return {\n success: false,\n command: normalizedArgs[0] || \"unknown\",\n result: undefined,\n formatted: `ERROR: ${errorMessage}`,\n error: { message: errorMessage },\n };\n }\n }\n\n /**\n * Normalize argv to an array of strings\n */\n private normalizeArgv(argv: string | string[]): string[] {\n if (typeof argv === \"string\") {\n // Parse quoted strings properly\n return this.tokenize(argv);\n }\n\n // Filter array input\n const filtered: string[] = [];\n let foundCommand = false;\n\n for (const arg of argv) {\n // Skip node and script paths (for process.argv format)\n if (\n !foundCommand &&\n (arg.includes(\"node\") || arg.includes(\"bun\") || arg.endsWith(\".js\") || arg.endsWith(\".ts\"))\n ) {\n continue;\n }\n\n // Skip \"afs\" prefix\n if (!foundCommand && arg === \"afs\") {\n continue;\n }\n\n filtered.push(arg);\n if (!arg.startsWith(\"-\")) {\n foundCommand = true;\n }\n }\n\n return filtered;\n }\n\n /**\n * Tokenize a command string, respecting quotes\n */\n private tokenize(input: string): string[] {\n const tokens: string[] = [];\n let current = \"\";\n let inQuote = false;\n let quoteChar = \"\";\n\n for (let i = 0; i < input.length; i++) {\n const char = input[i]!;\n\n if (inQuote) {\n if (char === quoteChar) {\n inQuote = false;\n } else {\n current += char;\n }\n } else if (char === '\"' || char === \"'\") {\n inQuote = true;\n quoteChar = char;\n } else if (char === \" \" || char === \"\\t\") {\n if (current) {\n tokens.push(current);\n current = \"\";\n }\n } else {\n current += char;\n }\n }\n\n if (current) {\n tokens.push(current);\n }\n\n // Filter out \"afs\" prefix if present\n if (tokens[0] === \"afs\") {\n tokens.shift();\n }\n\n return tokens;\n }\n\n /**\n * Extract output options from args\n */\n private extractOutputOptions(args: string[]): {\n json: boolean;\n yaml: boolean;\n view: ViewType;\n } {\n let json = false;\n let yaml = false;\n let view: ViewType | undefined;\n\n for (let i = 0; i < args.length; i++) {\n const arg = args[i]!;\n if (arg === \"--json\") json = true;\n if (arg === \"--yaml\") yaml = true;\n if (arg.startsWith(\"--view=\")) {\n view = arg.slice(7) as ViewType;\n } else if (arg === \"--view\" && args[i + 1] && !args[i + 1]!.startsWith(\"-\")) {\n view = args[i + 1] as ViewType;\n }\n }\n\n // Default to human view in TTY, default otherwise\n if (!view) {\n view = this.options.tty ? \"human\" : \"default\";\n }\n\n return { json, yaml, view };\n }\n\n /**\n * Extract path from args (first non-option argument after command)\n */\n private extractPath(args: string[]): string | undefined {\n for (let i = 1; i < args.length; i++) {\n const arg = args[i]!;\n if (!arg.startsWith(\"-\")) {\n return arg;\n }\n }\n return undefined;\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["formatted"],"sources":["../../../src/core/executor/index.ts"],"sourcesContent":["/**\n * AFS Command Executor\n *\n * Unified command execution interface using yargs and CommandFactory pattern.\n */\n\nimport type { AFS } from \"@aigne/afs\";\nimport yargs from \"yargs\";\nimport {\n type CommandFactoryOptions,\n type CommandOutput,\n commandFactories,\n} from \"../commands/index.js\";\nimport type { ViewType } from \"../types.js\";\n\n/**\n * Result from executing a command\n */\nexport interface ExecuteResult {\n /** Whether the command executed successfully */\n success: boolean;\n /** The command that was executed (ls, read, write, etc.) */\n command: string;\n /** The raw result data from AFS */\n result?: unknown;\n /** Formatted output string */\n formatted: string;\n /** Error info if the command failed */\n error?: {\n /** Exit code (from ExitCode enum) */\n code?: number;\n /** Error message */\n message: string;\n };\n}\n\n/**\n * Options for the executor\n */\nexport interface ExecutorOptions {\n /** Whether the output is for a TTY (enables colors) */\n tty?: boolean;\n /** Current working directory (for explore command) */\n cwd?: string;\n /** Version of the AFS CLI */\n version?: string;\n}\n\n/** Known command names and aliases for suggestion matching. */\nconst KNOWN_COMMANDS = [\n \"ls\",\n \"list\",\n \"read\",\n \"cat\",\n \"write\",\n \"delete\",\n \"rm\",\n \"stat\",\n \"exec\",\n \"explain\",\n \"search\",\n \"grep\",\n \"find\",\n \"mount\",\n \"serve\",\n \"explore\",\n \"service\",\n \"connect\",\n \"vault\",\n];\n\n/**\n * AFS Command Executor\n *\n * Provides a unified interface for executing AFS commands using yargs.\n *\n * @example\n * ```typescript\n * const executor = new AFSCommandExecutor(afs, { tty: false });\n * const result = await executor.execute(\"afs ls /path --depth=2\");\n * console.log(result.formatted);\n * ```\n */\nexport class AFSCommandExecutor {\n private afs?: AFS;\n private options: ExecutorOptions;\n\n constructor(afs?: AFS, options?: ExecutorOptions) {\n this.afs = afs;\n this.options = options ?? {};\n }\n\n /**\n * Execute an AFS command\n *\n * @param argv - Command string or array of arguments\n * - String: \"afs ls /path --depth=2\" or \"ls /path --depth=2\"\n * - Array: [\"ls\", \"/path\", \"--depth=2\"]\n * @returns Execution result with formatted output\n */\n async execute(argv: string | string[]): Promise<ExecuteResult> {\n const normalizedArgs = this.normalizeArgv(argv);\n\n // Capture command result\n let commandResult: CommandOutput | undefined;\n\n // Determine output format from args\n const outputOptions = this.extractOutputOptions(normalizedArgs);\n\n // Create factory options\n const factoryOptions: CommandFactoryOptions = {\n afs: this.afs,\n argv: normalizedArgs,\n cwd: this.options.cwd,\n onResult: (result) => {\n commandResult = result;\n },\n };\n\n // Capture fail() info so we can format errors ourselves\n let failMsg: string | undefined;\n let failErr: Error | undefined;\n\n // Build yargs parser with all commands\n let parser = yargs(normalizedArgs)\n .scriptName(\"afs\")\n .usage(\"$0 <command> [options]\")\n .option(\"json\", {\n type: \"boolean\",\n description: \"Output in JSON format\",\n global: true,\n })\n .option(\"yaml\", {\n type: \"boolean\",\n description: \"Output in YAML format\",\n global: true,\n })\n .option(\"view\", {\n type: \"string\",\n choices: [\"default\", \"llm\", \"human\"],\n default: \"default\",\n description: \"Output view format\",\n global: true,\n })\n .option(\"interactive\", {\n alias: \"i\",\n type: \"boolean\",\n description: \"Start interactive REPL mode\",\n global: false,\n })\n .help(true)\n .alias(\"h\", \"help\")\n .version(this.options.version || \"unknown\")\n .alias(\"v\", \"version\")\n .demandCommand()\n .strictCommands()\n .exitProcess(false)\n .fail((msg, err) => {\n // Prevent yargs from writing to stderr; we handle output ourselves.\n failErr = err || new Error(msg || \"Unknown error\");\n failMsg = msg;\n });\n\n // Register all commands from factories\n for (const factory of commandFactories) {\n parser = parser.command(factory(factoryOptions));\n }\n\n // Parse and execute\n try {\n let output: string | undefined;\n\n await parser.parseAsync(normalizedArgs, {}, (_e, _, o) => {\n output = o;\n });\n\n if (failErr) {\n const formatted = await this.formatFailure(normalizedArgs, failMsg, parser);\n return {\n success: false,\n command: normalizedArgs[0] || \"unknown\",\n result: undefined,\n formatted,\n error: { message: failMsg || failErr.message },\n };\n }\n\n if (output) {\n // --help or --version produced output\n return {\n success: true,\n command: \"help\",\n formatted: output,\n };\n }\n\n if (!commandResult) {\n const formatted = await this.formatFailure(normalizedArgs, undefined, parser);\n return {\n success: false,\n command: normalizedArgs[0] || \"unknown\",\n result: undefined,\n formatted,\n error: { message: `Unknown command: \"${normalizedArgs[0] || \"\"}\"` },\n };\n }\n\n // Always use the formatter - it handles json/llm/human views\n // Explicit format flags (--json, --yaml, --view) take precedence over command viewOverride (e.g. -l)\n const view: ViewType = outputOptions.json\n ? \"json\"\n : outputOptions.yaml\n ? \"yaml\"\n : (commandResult.viewOverride ?? outputOptions.view);\n const formatted = commandResult.format(commandResult.result, view, {\n path: this.extractPath(normalizedArgs),\n });\n\n // Check if command indicated failure\n if (commandResult.error) {\n return {\n success: false,\n command: commandResult.command,\n result: commandResult.result,\n formatted,\n error: commandResult.error,\n };\n }\n\n return {\n success: true,\n command: commandResult.command,\n result: commandResult.result,\n formatted,\n };\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n\n return {\n success: false,\n command: normalizedArgs[0] || \"unknown\",\n result: undefined,\n formatted: `ERROR: ${errorMessage}`,\n error: { message: errorMessage },\n };\n }\n }\n\n /**\n * Format a friendly error message for unknown/invalid commands.\n */\n private async formatFailure(\n args: string[],\n failMsg: string | undefined,\n parser: ReturnType<typeof yargs>,\n ): Promise<string> {\n const cmd = args[0] || \"\";\n const lines: string[] = [];\n\n // Show what went wrong\n if (cmd && failMsg?.includes(\"Unknown command\")) {\n lines.push(`Unknown command: \"${cmd}\"`);\n const suggestions = suggestCommands(cmd);\n if (suggestions.length > 0) {\n lines.push(\"\");\n lines.push(`Did you mean?`);\n for (const s of suggestions) {\n lines.push(` afs ${s}`);\n }\n }\n } else if (failMsg) {\n lines.push(failMsg);\n } else {\n lines.push(`Unknown command: \"${cmd}\"`);\n }\n\n // Append help text\n lines.push(\"\");\n try {\n const helpText = await parser.getHelp();\n lines.push(helpText);\n } catch {\n lines.push('Run \"afs --help\" to see available commands.');\n }\n\n return lines.join(\"\\n\");\n }\n\n /**\n * Normalize argv to an array of strings\n */\n private normalizeArgv(argv: string | string[]): string[] {\n if (typeof argv === \"string\") {\n // Parse quoted strings properly\n return this.tokenize(argv);\n }\n\n // Filter array input\n const filtered: string[] = [];\n let foundCommand = false;\n\n for (const arg of argv) {\n // Skip node and script paths (for process.argv format)\n if (\n !foundCommand &&\n (arg.includes(\"node\") || arg.includes(\"bun\") || arg.endsWith(\".js\") || arg.endsWith(\".ts\"))\n ) {\n continue;\n }\n\n // Skip \"afs\" prefix\n if (!foundCommand && arg === \"afs\") {\n continue;\n }\n\n filtered.push(arg);\n if (!arg.startsWith(\"-\")) {\n foundCommand = true;\n }\n }\n\n return filtered;\n }\n\n /**\n * Tokenize a command string, respecting quotes\n */\n private tokenize(input: string): string[] {\n const tokens: string[] = [];\n let current = \"\";\n let inQuote = false;\n let quoteChar = \"\";\n\n for (let i = 0; i < input.length; i++) {\n const char = input[i]!;\n\n if (inQuote) {\n if (char === quoteChar) {\n inQuote = false;\n } else {\n current += char;\n }\n } else if (char === '\"' || char === \"'\") {\n inQuote = true;\n quoteChar = char;\n } else if (char === \" \" || char === \"\\t\") {\n if (current) {\n tokens.push(current);\n current = \"\";\n }\n } else {\n current += char;\n }\n }\n\n if (current) {\n tokens.push(current);\n }\n\n // Filter out \"afs\" prefix if present\n if (tokens[0] === \"afs\") {\n tokens.shift();\n }\n\n return tokens;\n }\n\n /**\n * Extract output options from args\n */\n private extractOutputOptions(args: string[]): {\n json: boolean;\n yaml: boolean;\n view: ViewType;\n } {\n let json = false;\n let yaml = false;\n let view: ViewType | undefined;\n\n for (let i = 0; i < args.length; i++) {\n const arg = args[i]!;\n if (arg === \"--json\") json = true;\n if (arg === \"--yaml\") yaml = true;\n if (arg.startsWith(\"--view=\")) {\n view = arg.slice(7) as ViewType;\n } else if (arg === \"--view\" && args[i + 1] && !args[i + 1]!.startsWith(\"-\")) {\n view = args[i + 1] as ViewType;\n }\n }\n\n // Default to human view in TTY, default otherwise\n if (!view) {\n view = this.options.tty ? \"human\" : \"default\";\n }\n\n return { json, yaml, view };\n }\n\n /**\n * Extract path from args (first non-option argument after command)\n */\n private extractPath(args: string[]): string | undefined {\n for (let i = 1; i < args.length; i++) {\n const arg = args[i]!;\n if (!arg.startsWith(\"-\")) {\n return arg;\n }\n }\n return undefined;\n }\n}\n\n/** Levenshtein distance between two strings. */\nfunction levenshtein(a: string, b: string): number {\n const m = a.length;\n const n = b.length;\n const dp: number[][] = Array.from({ length: m + 1 }, () => Array(n + 1).fill(0) as number[]);\n for (let i = 0; i <= m; i++) dp[i]![0] = i;\n for (let j = 0; j <= n; j++) dp[0]![j] = j;\n for (let i = 1; i <= m; i++) {\n for (let j = 1; j <= n; j++) {\n dp[i]![j] =\n a[i - 1] === b[j - 1]\n ? dp[i - 1]![j - 1]!\n : 1 + Math.min(dp[i - 1]![j]!, dp[i]![j - 1]!, dp[i - 1]![j - 1]!);\n }\n }\n return dp[m]![n]!;\n}\n\n/** Suggest known commands similar to the given input. */\nfunction suggestCommands(input: string): string[] {\n const lower = input.toLowerCase();\n const scored = KNOWN_COMMANDS.map((cmd) => ({\n cmd,\n dist: levenshtein(lower, cmd),\n maxLen: Math.max(lower.length, cmd.length),\n }))\n // Only suggest when edit distance < 50% of the longer string\n .filter((x) => x.dist > 0 && x.dist < x.maxLen * 0.5)\n .sort((a, b) => a.dist - b.dist);\n return scored.map((x) => x.cmd).slice(0, 3);\n}\n"],"mappings":";;;;;AAiDA,MAAM,iBAAiB;CACrB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD;;;;;;;;;;;;;AAcD,IAAa,qBAAb,MAAgC;CAC9B,AAAQ;CACR,AAAQ;CAER,YAAY,KAAW,SAA2B;AAChD,OAAK,MAAM;AACX,OAAK,UAAU,WAAW,EAAE;;;;;;;;;;CAW9B,MAAM,QAAQ,MAAiD;EAC7D,MAAM,iBAAiB,KAAK,cAAc,KAAK;EAG/C,IAAI;EAGJ,MAAM,gBAAgB,KAAK,qBAAqB,eAAe;EAG/D,MAAM,iBAAwC;GAC5C,KAAK,KAAK;GACV,MAAM;GACN,KAAK,KAAK,QAAQ;GAClB,WAAW,WAAW;AACpB,oBAAgB;;GAEnB;EAGD,IAAI;EACJ,IAAI;EAGJ,IAAI,SAAS,MAAM,eAAe,CAC/B,WAAW,MAAM,CACjB,MAAM,yBAAyB,CAC/B,OAAO,QAAQ;GACd,MAAM;GACN,aAAa;GACb,QAAQ;GACT,CAAC,CACD,OAAO,QAAQ;GACd,MAAM;GACN,aAAa;GACb,QAAQ;GACT,CAAC,CACD,OAAO,QAAQ;GACd,MAAM;GACN,SAAS;IAAC;IAAW;IAAO;IAAQ;GACpC,SAAS;GACT,aAAa;GACb,QAAQ;GACT,CAAC,CACD,OAAO,eAAe;GACrB,OAAO;GACP,MAAM;GACN,aAAa;GACb,QAAQ;GACT,CAAC,CACD,KAAK,KAAK,CACV,MAAM,KAAK,OAAO,CAClB,QAAQ,KAAK,QAAQ,WAAW,UAAU,CAC1C,MAAM,KAAK,UAAU,CACrB,eAAe,CACf,gBAAgB,CAChB,YAAY,MAAM,CAClB,MAAM,KAAK,QAAQ;AAElB,aAAU,OAAO,IAAI,MAAM,OAAO,gBAAgB;AAClD,aAAU;IACV;AAGJ,OAAK,MAAM,WAAW,iBACpB,UAAS,OAAO,QAAQ,QAAQ,eAAe,CAAC;AAIlD,MAAI;GACF,IAAI;AAEJ,SAAM,OAAO,WAAW,gBAAgB,EAAE,GAAG,IAAI,GAAG,MAAM;AACxD,aAAS;KACT;AAEF,OAAI,SAAS;IACX,MAAMA,cAAY,MAAM,KAAK,cAAc,gBAAgB,SAAS,OAAO;AAC3E,WAAO;KACL,SAAS;KACT,SAAS,eAAe,MAAM;KAC9B,QAAQ;KACR;KACA,OAAO,EAAE,SAAS,WAAW,QAAQ,SAAS;KAC/C;;AAGH,OAAI,OAEF,QAAO;IACL,SAAS;IACT,SAAS;IACT,WAAW;IACZ;AAGH,OAAI,CAAC,eAAe;IAClB,MAAMA,cAAY,MAAM,KAAK,cAAc,gBAAgB,QAAW,OAAO;AAC7E,WAAO;KACL,SAAS;KACT,SAAS,eAAe,MAAM;KAC9B,QAAQ;KACR;KACA,OAAO,EAAE,SAAS,qBAAqB,eAAe,MAAM,GAAG,IAAI;KACpE;;GAKH,MAAM,OAAiB,cAAc,OACjC,SACA,cAAc,OACZ,SACC,cAAc,gBAAgB,cAAc;GACnD,MAAM,YAAY,cAAc,OAAO,cAAc,QAAQ,MAAM,EACjE,MAAM,KAAK,YAAY,eAAe,EACvC,CAAC;AAGF,OAAI,cAAc,MAChB,QAAO;IACL,SAAS;IACT,SAAS,cAAc;IACvB,QAAQ,cAAc;IACtB;IACA,OAAO,cAAc;IACtB;AAGH,UAAO;IACL,SAAS;IACT,SAAS,cAAc;IACvB,QAAQ,cAAc;IACtB;IACD;WACM,OAAO;GACd,MAAM,eAAe,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;AAE3E,UAAO;IACL,SAAS;IACT,SAAS,eAAe,MAAM;IAC9B,QAAQ;IACR,WAAW,UAAU;IACrB,OAAO,EAAE,SAAS,cAAc;IACjC;;;;;;CAOL,MAAc,cACZ,MACA,SACA,QACiB;EACjB,MAAM,MAAM,KAAK,MAAM;EACvB,MAAM,QAAkB,EAAE;AAG1B,MAAI,OAAO,SAAS,SAAS,kBAAkB,EAAE;AAC/C,SAAM,KAAK,qBAAqB,IAAI,GAAG;GACvC,MAAM,cAAc,gBAAgB,IAAI;AACxC,OAAI,YAAY,SAAS,GAAG;AAC1B,UAAM,KAAK,GAAG;AACd,UAAM,KAAK,gBAAgB;AAC3B,SAAK,MAAM,KAAK,YACd,OAAM,KAAK,SAAS,IAAI;;aAGnB,QACT,OAAM,KAAK,QAAQ;MAEnB,OAAM,KAAK,qBAAqB,IAAI,GAAG;AAIzC,QAAM,KAAK,GAAG;AACd,MAAI;GACF,MAAM,WAAW,MAAM,OAAO,SAAS;AACvC,SAAM,KAAK,SAAS;UACd;AACN,SAAM,KAAK,gDAA8C;;AAG3D,SAAO,MAAM,KAAK,KAAK;;;;;CAMzB,AAAQ,cAAc,MAAmC;AACvD,MAAI,OAAO,SAAS,SAElB,QAAO,KAAK,SAAS,KAAK;EAI5B,MAAM,WAAqB,EAAE;EAC7B,IAAI,eAAe;AAEnB,OAAK,MAAM,OAAO,MAAM;AAEtB,OACE,CAAC,iBACA,IAAI,SAAS,OAAO,IAAI,IAAI,SAAS,MAAM,IAAI,IAAI,SAAS,MAAM,IAAI,IAAI,SAAS,MAAM,EAE1F;AAIF,OAAI,CAAC,gBAAgB,QAAQ,MAC3B;AAGF,YAAS,KAAK,IAAI;AAClB,OAAI,CAAC,IAAI,WAAW,IAAI,CACtB,gBAAe;;AAInB,SAAO;;;;;CAMT,AAAQ,SAAS,OAAyB;EACxC,MAAM,SAAmB,EAAE;EAC3B,IAAI,UAAU;EACd,IAAI,UAAU;EACd,IAAI,YAAY;AAEhB,OAAK,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;GACrC,MAAM,OAAO,MAAM;AAEnB,OAAI,QACF,KAAI,SAAS,UACX,WAAU;OAEV,YAAW;YAEJ,SAAS,QAAO,SAAS,KAAK;AACvC,cAAU;AACV,gBAAY;cACH,SAAS,OAAO,SAAS,KAClC;QAAI,SAAS;AACX,YAAO,KAAK,QAAQ;AACpB,eAAU;;SAGZ,YAAW;;AAIf,MAAI,QACF,QAAO,KAAK,QAAQ;AAItB,MAAI,OAAO,OAAO,MAChB,QAAO,OAAO;AAGhB,SAAO;;;;;CAMT,AAAQ,qBAAqB,MAI3B;EACA,IAAI,OAAO;EACX,IAAI,OAAO;EACX,IAAI;AAEJ,OAAK,IAAI,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;GACpC,MAAM,MAAM,KAAK;AACjB,OAAI,QAAQ,SAAU,QAAO;AAC7B,OAAI,QAAQ,SAAU,QAAO;AAC7B,OAAI,IAAI,WAAW,UAAU,CAC3B,QAAO,IAAI,MAAM,EAAE;YACV,QAAQ,YAAY,KAAK,IAAI,MAAM,CAAC,KAAK,IAAI,GAAI,WAAW,IAAI,CACzE,QAAO,KAAK,IAAI;;AAKpB,MAAI,CAAC,KACH,QAAO,KAAK,QAAQ,MAAM,UAAU;AAGtC,SAAO;GAAE;GAAM;GAAM;GAAM;;;;;CAM7B,AAAQ,YAAY,MAAoC;AACtD,OAAK,IAAI,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;GACpC,MAAM,MAAM,KAAK;AACjB,OAAI,CAAC,IAAI,WAAW,IAAI,CACtB,QAAO;;;;;AAQf,SAAS,YAAY,GAAW,GAAmB;CACjD,MAAM,IAAI,EAAE;CACZ,MAAM,IAAI,EAAE;CACZ,MAAM,KAAiB,MAAM,KAAK,EAAE,QAAQ,IAAI,GAAG,QAAQ,MAAM,IAAI,EAAE,CAAC,KAAK,EAAE,CAAa;AAC5F,MAAK,IAAI,IAAI,GAAG,KAAK,GAAG,IAAK,IAAG,GAAI,KAAK;AACzC,MAAK,IAAI,IAAI,GAAG,KAAK,GAAG,IAAK,IAAG,GAAI,KAAK;AACzC,MAAK,IAAI,IAAI,GAAG,KAAK,GAAG,IACtB,MAAK,IAAI,IAAI,GAAG,KAAK,GAAG,IACtB,IAAG,GAAI,KACL,EAAE,IAAI,OAAO,EAAE,IAAI,KACf,GAAG,IAAI,GAAI,IAAI,KACf,IAAI,KAAK,IAAI,GAAG,IAAI,GAAI,IAAK,GAAG,GAAI,IAAI,IAAK,GAAG,IAAI,GAAI,IAAI,GAAI;AAG1E,QAAO,GAAG,GAAI;;;AAIhB,SAAS,gBAAgB,OAAyB;CAChD,MAAM,QAAQ,MAAM,aAAa;AASjC,QARe,eAAe,KAAK,SAAS;EAC1C;EACA,MAAM,YAAY,OAAO,IAAI;EAC7B,QAAQ,KAAK,IAAI,MAAM,QAAQ,IAAI,OAAO;EAC3C,EAAE,CAEA,QAAQ,MAAM,EAAE,OAAO,KAAK,EAAE,OAAO,EAAE,SAAS,GAAI,CACpD,MAAM,GAAG,MAAM,EAAE,OAAO,EAAE,KAAK,CACpB,KAAK,MAAM,EAAE,IAAI,CAAC,MAAM,GAAG,EAAE"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { formatDeleteOutput } from "./delete.mjs";
|
|
2
2
|
import { formatExecOutput } from "./exec.mjs";
|
|
3
3
|
import { formatExplainOutput } from "./explain.mjs";
|
|
4
|
+
import "./install.mjs";
|
|
4
5
|
import { formatLsOutput } from "./ls.mjs";
|
|
5
6
|
import { formatMountListOutput } from "./mount.mjs";
|
|
6
7
|
import { formatReadOutput } from "./read.mjs";
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
|
|
2
|
+
//#region src/core/formatters/install.ts
|
|
3
|
+
function formatInstallAddOutput(result, view) {
|
|
4
|
+
if (view === "json") return JSON.stringify(result, null, 2);
|
|
5
|
+
return `Installed "${result.programName}" (${result.programId}) at ${result.mountPath}`;
|
|
6
|
+
}
|
|
7
|
+
function formatInstallListOutput(programs, view) {
|
|
8
|
+
if (view === "json") return JSON.stringify(programs, null, 2);
|
|
9
|
+
if (programs.length === 0) return "No programs installed";
|
|
10
|
+
return ["Installed programs:", ...programs.map((p) => ` ${p.id} ${p.name} ${p.entrypoint} ${p.mountPath}`)].join("\n");
|
|
11
|
+
}
|
|
12
|
+
function formatInstallRemoveOutput(result, view) {
|
|
13
|
+
if (view === "json") return JSON.stringify(result, null, 2);
|
|
14
|
+
const suffix = result.purgedData ? " (data purged)" : "";
|
|
15
|
+
return `Removed program "${result.programId}"${suffix}`;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
//#endregion
|
|
19
|
+
exports.formatInstallAddOutput = formatInstallAddOutput;
|
|
20
|
+
exports.formatInstallListOutput = formatInstallListOutput;
|
|
21
|
+
exports.formatInstallRemoveOutput = formatInstallRemoveOutput;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import "../../config/program-install.mjs";
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
//#region src/core/formatters/install.ts
|
|
2
|
+
function formatInstallAddOutput(result, view) {
|
|
3
|
+
if (view === "json") return JSON.stringify(result, null, 2);
|
|
4
|
+
return `Installed "${result.programName}" (${result.programId}) at ${result.mountPath}`;
|
|
5
|
+
}
|
|
6
|
+
function formatInstallListOutput(programs, view) {
|
|
7
|
+
if (view === "json") return JSON.stringify(programs, null, 2);
|
|
8
|
+
if (programs.length === 0) return "No programs installed";
|
|
9
|
+
return ["Installed programs:", ...programs.map((p) => ` ${p.id} ${p.name} ${p.entrypoint} ${p.mountPath}`)].join("\n");
|
|
10
|
+
}
|
|
11
|
+
function formatInstallRemoveOutput(result, view) {
|
|
12
|
+
if (view === "json") return JSON.stringify(result, null, 2);
|
|
13
|
+
const suffix = result.purgedData ? " (data purged)" : "";
|
|
14
|
+
return `Removed program "${result.programId}"${suffix}`;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
//#endregion
|
|
18
|
+
export { formatInstallAddOutput, formatInstallListOutput, formatInstallRemoveOutput };
|
|
19
|
+
//# sourceMappingURL=install.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"install.mjs","names":[],"sources":["../../../src/core/formatters/install.ts"],"sourcesContent":["/**\n * Install Command Formatters\n */\n\nimport type {\n InstalledProgram,\n InstallResult,\n RemoveResult,\n} from \"../../config/program-install.js\";\nimport type { ViewType } from \"../types.js\";\n\nexport function formatInstallAddOutput(result: InstallResult, view?: ViewType): string {\n if (view === \"json\") {\n return JSON.stringify(result, null, 2);\n }\n return `Installed \"${result.programName}\" (${result.programId}) at ${result.mountPath}`;\n}\n\nexport function formatInstallListOutput(programs: InstalledProgram[], view?: ViewType): string {\n if (view === \"json\") {\n return JSON.stringify(programs, null, 2);\n }\n if (programs.length === 0) {\n return \"No programs installed\";\n }\n const lines = programs.map((p) => ` ${p.id} ${p.name} ${p.entrypoint} ${p.mountPath}`);\n return [\"Installed programs:\", ...lines].join(\"\\n\");\n}\n\nexport function formatInstallRemoveOutput(result: RemoveResult, view?: ViewType): string {\n if (view === \"json\") {\n return JSON.stringify(result, null, 2);\n }\n const suffix = result.purgedData ? \" (data purged)\" : \"\";\n return `Removed program \"${result.programId}\"${suffix}`;\n}\n"],"mappings":";AAWA,SAAgB,uBAAuB,QAAuB,MAAyB;AACrF,KAAI,SAAS,OACX,QAAO,KAAK,UAAU,QAAQ,MAAM,EAAE;AAExC,QAAO,cAAc,OAAO,YAAY,KAAK,OAAO,UAAU,OAAO,OAAO;;AAG9E,SAAgB,wBAAwB,UAA8B,MAAyB;AAC7F,KAAI,SAAS,OACX,QAAO,KAAK,UAAU,UAAU,MAAM,EAAE;AAE1C,KAAI,SAAS,WAAW,EACtB,QAAO;AAGT,QAAO,CAAC,uBAAuB,GADjB,SAAS,KAAK,MAAM,KAAK,EAAE,GAAG,IAAI,EAAE,KAAK,IAAI,EAAE,WAAW,IAAI,EAAE,YAAY,CAClD,CAAC,KAAK,KAAK;;AAGrD,SAAgB,0BAA0B,QAAsB,MAAyB;AACvF,KAAI,SAAS,OACX,QAAO,KAAK,UAAU,QAAQ,MAAM,EAAE;CAExC,MAAM,SAAS,OAAO,aAAa,mBAAmB;AACtD,QAAO,oBAAoB,OAAO,UAAU,GAAG"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
|
|
2
|
+
//#region src/core/formatters/vault.ts
|
|
3
|
+
function formatVaultInitOutput(result, view) {
|
|
4
|
+
if (view === "json") return JSON.stringify(result, null, 2);
|
|
5
|
+
const lines = [`Vault initialized at ${result.vaultPath}`];
|
|
6
|
+
if (result.migrated && result.migrated > 0) lines.push(`Migrated ${result.migrated} credential(s) from credentials.toml`);
|
|
7
|
+
return lines.join("\n");
|
|
8
|
+
}
|
|
9
|
+
function formatVaultGetOutput(result, view) {
|
|
10
|
+
if (view === "json") return JSON.stringify(result, null, 2);
|
|
11
|
+
return result.value;
|
|
12
|
+
}
|
|
13
|
+
function formatVaultSetOutput(result, view) {
|
|
14
|
+
if (view === "json") return JSON.stringify({
|
|
15
|
+
...result,
|
|
16
|
+
success: true
|
|
17
|
+
}, null, 2);
|
|
18
|
+
return `OK ${result.group}/${result.name}`;
|
|
19
|
+
}
|
|
20
|
+
function formatVaultDeleteOutput(result, view) {
|
|
21
|
+
if (view === "json") return JSON.stringify(result, null, 2);
|
|
22
|
+
const target = result.name ? `${result.group}/${result.name}` : result.group;
|
|
23
|
+
return result.deleted ? `Deleted ${target}` : `Not found: ${target}`;
|
|
24
|
+
}
|
|
25
|
+
function formatVaultListOutput(result, view) {
|
|
26
|
+
if (view === "json") return JSON.stringify(result, null, 2);
|
|
27
|
+
if (result.secrets.length === 0) return result.group ? `No secrets in group: ${result.group}` : "Vault is empty";
|
|
28
|
+
return result.secrets.join("\n");
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
//#endregion
|
|
32
|
+
exports.formatVaultDeleteOutput = formatVaultDeleteOutput;
|
|
33
|
+
exports.formatVaultGetOutput = formatVaultGetOutput;
|
|
34
|
+
exports.formatVaultInitOutput = formatVaultInitOutput;
|
|
35
|
+
exports.formatVaultListOutput = formatVaultListOutput;
|
|
36
|
+
exports.formatVaultSetOutput = formatVaultSetOutput;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
//#region src/core/formatters/vault.ts
|
|
2
|
+
function formatVaultInitOutput(result, view) {
|
|
3
|
+
if (view === "json") return JSON.stringify(result, null, 2);
|
|
4
|
+
const lines = [`Vault initialized at ${result.vaultPath}`];
|
|
5
|
+
if (result.migrated && result.migrated > 0) lines.push(`Migrated ${result.migrated} credential(s) from credentials.toml`);
|
|
6
|
+
return lines.join("\n");
|
|
7
|
+
}
|
|
8
|
+
function formatVaultGetOutput(result, view) {
|
|
9
|
+
if (view === "json") return JSON.stringify(result, null, 2);
|
|
10
|
+
return result.value;
|
|
11
|
+
}
|
|
12
|
+
function formatVaultSetOutput(result, view) {
|
|
13
|
+
if (view === "json") return JSON.stringify({
|
|
14
|
+
...result,
|
|
15
|
+
success: true
|
|
16
|
+
}, null, 2);
|
|
17
|
+
return `OK ${result.group}/${result.name}`;
|
|
18
|
+
}
|
|
19
|
+
function formatVaultDeleteOutput(result, view) {
|
|
20
|
+
if (view === "json") return JSON.stringify(result, null, 2);
|
|
21
|
+
const target = result.name ? `${result.group}/${result.name}` : result.group;
|
|
22
|
+
return result.deleted ? `Deleted ${target}` : `Not found: ${target}`;
|
|
23
|
+
}
|
|
24
|
+
function formatVaultListOutput(result, view) {
|
|
25
|
+
if (view === "json") return JSON.stringify(result, null, 2);
|
|
26
|
+
if (result.secrets.length === 0) return result.group ? `No secrets in group: ${result.group}` : "Vault is empty";
|
|
27
|
+
return result.secrets.join("\n");
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
//#endregion
|
|
31
|
+
export { formatVaultDeleteOutput, formatVaultGetOutput, formatVaultInitOutput, formatVaultListOutput, formatVaultSetOutput };
|
|
32
|
+
//# sourceMappingURL=vault.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vault.mjs","names":[],"sources":["../../../src/core/formatters/vault.ts"],"sourcesContent":["/**\n * vault Formatter - Core Implementation\n *\n * Formats vault command output without colors.\n */\n\nimport type { ViewType } from \"../types.js\";\n\nexport interface VaultInitResult {\n success: boolean;\n vaultPath: string;\n migrated?: number;\n}\n\nexport interface VaultGetResult {\n group: string;\n name: string;\n value: string;\n}\n\nexport interface VaultSetResult {\n group: string;\n name: string;\n}\n\nexport interface VaultDeleteResult {\n group: string;\n name?: string;\n deleted: boolean;\n}\n\nexport interface VaultListResult {\n group?: string;\n secrets: string[];\n}\n\nexport function formatVaultInitOutput(result: VaultInitResult, view: ViewType): string {\n if (view === \"json\") return JSON.stringify(result, null, 2);\n const lines = [`Vault initialized at ${result.vaultPath}`];\n if (result.migrated && result.migrated > 0) {\n lines.push(`Migrated ${result.migrated} credential(s) from credentials.toml`);\n }\n return lines.join(\"\\n\");\n}\n\nexport function formatVaultGetOutput(result: VaultGetResult, view: ViewType): string {\n if (view === \"json\") return JSON.stringify(result, null, 2);\n return result.value;\n}\n\nexport function formatVaultSetOutput(result: VaultSetResult, view: ViewType): string {\n if (view === \"json\") return JSON.stringify({ ...result, success: true }, null, 2);\n return `OK ${result.group}/${result.name}`;\n}\n\nexport function formatVaultDeleteOutput(result: VaultDeleteResult, view: ViewType): string {\n if (view === \"json\") return JSON.stringify(result, null, 2);\n const target = result.name ? `${result.group}/${result.name}` : result.group;\n return result.deleted ? `Deleted ${target}` : `Not found: ${target}`;\n}\n\nexport function formatVaultListOutput(result: VaultListResult, view: ViewType): string {\n if (view === \"json\") return JSON.stringify(result, null, 2);\n if (result.secrets.length === 0) {\n return result.group ? `No secrets in group: ${result.group}` : \"Vault is empty\";\n }\n return result.secrets.join(\"\\n\");\n}\n"],"mappings":";AAoCA,SAAgB,sBAAsB,QAAyB,MAAwB;AACrF,KAAI,SAAS,OAAQ,QAAO,KAAK,UAAU,QAAQ,MAAM,EAAE;CAC3D,MAAM,QAAQ,CAAC,wBAAwB,OAAO,YAAY;AAC1D,KAAI,OAAO,YAAY,OAAO,WAAW,EACvC,OAAM,KAAK,YAAY,OAAO,SAAS,sCAAsC;AAE/E,QAAO,MAAM,KAAK,KAAK;;AAGzB,SAAgB,qBAAqB,QAAwB,MAAwB;AACnF,KAAI,SAAS,OAAQ,QAAO,KAAK,UAAU,QAAQ,MAAM,EAAE;AAC3D,QAAO,OAAO;;AAGhB,SAAgB,qBAAqB,QAAwB,MAAwB;AACnF,KAAI,SAAS,OAAQ,QAAO,KAAK,UAAU;EAAE,GAAG;EAAQ,SAAS;EAAM,EAAE,MAAM,EAAE;AACjF,QAAO,MAAM,OAAO,MAAM,GAAG,OAAO;;AAGtC,SAAgB,wBAAwB,QAA2B,MAAwB;AACzF,KAAI,SAAS,OAAQ,QAAO,KAAK,UAAU,QAAQ,MAAM,EAAE;CAC3D,MAAM,SAAS,OAAO,OAAO,GAAG,OAAO,MAAM,GAAG,OAAO,SAAS,OAAO;AACvE,QAAO,OAAO,UAAU,WAAW,WAAW,cAAc;;AAG9D,SAAgB,sBAAsB,QAAyB,MAAwB;AACrF,KAAI,SAAS,OAAQ,QAAO,KAAK,UAAU,QAAQ,MAAM,EAAE;AAC3D,KAAI,OAAO,QAAQ,WAAW,EAC5B,QAAO,OAAO,QAAQ,wBAAwB,OAAO,UAAU;AAEjE,QAAO,OAAO,QAAQ,KAAK,KAAK"}
|