@aigne/afs-cli 1.11.0-beta.11 → 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 +21 -5
- package/dist/credential/mcp-auth-context.mjs +21 -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
package/dist/cli.cjs
CHANGED
|
@@ -25,12 +25,13 @@ async function main() {
|
|
|
25
25
|
version: require_version.VERSION
|
|
26
26
|
}).execute(args);
|
|
27
27
|
if (result.success) {
|
|
28
|
+
process.exitCode = require_errors.ExitCode.OK;
|
|
28
29
|
console.log(result.formatted);
|
|
29
|
-
process.exit(require_errors.ExitCode.OK);
|
|
30
30
|
} else {
|
|
31
|
+
process.exitCode = result.error?.code ?? require_errors.ExitCode.RUNTIME_ERROR;
|
|
31
32
|
console.error(result.formatted);
|
|
32
|
-
process.exit(result.error?.code ?? require_errors.ExitCode.RUNTIME_ERROR);
|
|
33
33
|
}
|
|
34
|
+
process.exit(process.exitCode);
|
|
34
35
|
}
|
|
35
36
|
main().catch((error) => {
|
|
36
37
|
console.error(error instanceof Error ? error.message : String(error));
|
package/dist/cli.mjs
CHANGED
|
@@ -24,12 +24,13 @@ async function main() {
|
|
|
24
24
|
version: VERSION
|
|
25
25
|
}).execute(args);
|
|
26
26
|
if (result.success) {
|
|
27
|
+
process.exitCode = ExitCode.OK;
|
|
27
28
|
console.log(result.formatted);
|
|
28
|
-
process.exit(ExitCode.OK);
|
|
29
29
|
} else {
|
|
30
|
+
process.exitCode = result.error?.code ?? ExitCode.RUNTIME_ERROR;
|
|
30
31
|
console.error(result.formatted);
|
|
31
|
-
process.exit(result.error?.code ?? ExitCode.RUNTIME_ERROR);
|
|
32
32
|
}
|
|
33
|
+
process.exit(process.exitCode);
|
|
33
34
|
}
|
|
34
35
|
main().catch((error) => {
|
|
35
36
|
console.error(error instanceof Error ? error.message : String(error));
|
package/dist/cli.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.mjs","names":[],"sources":["../src/cli.ts"],"sourcesContent":["#!/usr/bin/env node\n\n/**\n * AFS CLI - Command Line Interface\n *\n * Simple CLI that delegates to executor. AFS is lazy-loaded on demand\n * by individual commands, so mount failures don't block config commands.\n */\n\nimport \"urlpattern-polyfill\";\nimport { hideBin } from \"yargs/helpers\";\nimport { AFSCommandExecutor } from \"./core/index.js\";\nimport { ExitCode } from \"./errors.js\";\nimport { VERSION } from \"./version.js\";\n\nasync function main() {\n const args = hideBin(process.argv);\n const cwd = process.cwd();\n\n // Check for -i / --interactive before yargs parsing\n if (args.includes(\"-i\") || args.includes(\"--interactive\")) {\n const { startRepl } = await import(\"./repl.js\");\n await startRepl({ cwd, version: VERSION });\n process.exit(ExitCode.OK);\n }\n\n const executor = new AFSCommandExecutor(undefined, {\n cwd,\n tty: process.stdout.isTTY ?? false,\n version: VERSION,\n });\n\n const result = await executor.execute(args);\n\n if (result.success) {\n
|
|
1
|
+
{"version":3,"file":"cli.mjs","names":[],"sources":["../src/cli.ts"],"sourcesContent":["#!/usr/bin/env node\n\n/**\n * AFS CLI - Command Line Interface\n *\n * Simple CLI that delegates to executor. AFS is lazy-loaded on demand\n * by individual commands, so mount failures don't block config commands.\n */\n\nimport \"urlpattern-polyfill\";\nimport { hideBin } from \"yargs/helpers\";\nimport { AFSCommandExecutor } from \"./core/index.js\";\nimport { ExitCode } from \"./errors.js\";\nimport { VERSION } from \"./version.js\";\n\nasync function main() {\n const args = hideBin(process.argv);\n const cwd = process.cwd();\n\n // Check for -i / --interactive before yargs parsing\n if (args.includes(\"-i\") || args.includes(\"--interactive\")) {\n const { startRepl } = await import(\"./repl.js\");\n await startRepl({ cwd, version: VERSION });\n process.exit(ExitCode.OK);\n }\n\n const executor = new AFSCommandExecutor(undefined, {\n cwd,\n tty: process.stdout.isTTY ?? false,\n version: VERSION,\n });\n\n const result = await executor.execute(args);\n\n if (result.success) {\n process.exitCode = ExitCode.OK;\n console.log(result.formatted);\n } else {\n process.exitCode = result.error?.code ?? ExitCode.RUNTIME_ERROR;\n console.error(result.formatted);\n }\n\n // Force exit — providers may hold background resources (MCP child processes,\n // Telegram long-polling, open HTTP connections) that keep the event loop alive.\n // stdout/stderr are flushed synchronously above via console.log/console.error.\n process.exit(process.exitCode);\n}\n\nmain().catch((error) => {\n console.error(error instanceof Error ? error.message : String(error));\n process.exit(ExitCode.RUNTIME_ERROR);\n});\n"],"mappings":";;;;;;;;;AAeA,eAAe,OAAO;CACpB,MAAM,OAAO,QAAQ,QAAQ,KAAK;CAClC,MAAM,MAAM,QAAQ,KAAK;AAGzB,KAAI,KAAK,SAAS,KAAK,IAAI,KAAK,SAAS,gBAAgB,EAAE;EACzD,MAAM,EAAE,cAAc,MAAM,OAAO;AACnC,QAAM,UAAU;GAAE;GAAK,SAAS;GAAS,CAAC;AAC1C,UAAQ,KAAK,SAAS,GAAG;;CAS3B,MAAM,SAAS,MANE,IAAI,mBAAmB,QAAW;EACjD;EACA,KAAK,QAAQ,OAAO,SAAS;EAC7B,SAAS;EACV,CAAC,CAE4B,QAAQ,KAAK;AAE3C,KAAI,OAAO,SAAS;AAClB,UAAQ,WAAW,SAAS;AAC5B,UAAQ,IAAI,OAAO,UAAU;QACxB;AACL,UAAQ,WAAW,OAAO,OAAO,QAAQ,SAAS;AAClD,UAAQ,MAAM,OAAO,UAAU;;AAMjC,SAAQ,KAAK,QAAQ,SAAS;;AAGhC,MAAM,CAAC,OAAO,UAAU;AACtB,SAAQ,MAAM,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM,CAAC;AACrE,SAAQ,KAAK,SAAS,cAAc;EACpC"}
|
|
@@ -1,11 +1,28 @@
|
|
|
1
1
|
const require_rolldown_runtime = require('../_virtual/rolldown_runtime.cjs');
|
|
2
|
+
const require_credential_helpers = require('./credential-helpers.cjs');
|
|
2
3
|
const require_loader = require('./loader.cjs');
|
|
3
4
|
const require_mount_commands = require('./mount-commands.cjs');
|
|
5
|
+
let node_fs_promises = require("node:fs/promises");
|
|
6
|
+
let node_os = require("node:os");
|
|
7
|
+
let node_path = require("node:path");
|
|
4
8
|
let _aigne_afs = require("@aigne/afs");
|
|
5
9
|
let _aigne_afs_utils_uri = require("@aigne/afs/utils/uri");
|
|
6
10
|
|
|
7
11
|
//#region src/config/afs-loader.ts
|
|
8
12
|
/**
|
|
13
|
+
* AFS Loader - Lazy loading with parallel tolerant mount
|
|
14
|
+
*
|
|
15
|
+
* Provides loadAFS() for on-demand AFS creation with caching.
|
|
16
|
+
* createAFS() uses Promise.allSettled for parallel provider creation + mount,
|
|
17
|
+
* tolerating individual failures while reporting them to stderr.
|
|
18
|
+
*
|
|
19
|
+
* Integrates 4-step credential resolution:
|
|
20
|
+
* 1. Determine missing fields from provider schema
|
|
21
|
+
* 2. Silent resolution (config > env > credential store)
|
|
22
|
+
* 3. Interactive collection (provider auth() or default collect())
|
|
23
|
+
* 4. Unified persistence (sensitive → credentials.toml, non-sensitive → config options)
|
|
24
|
+
*/
|
|
25
|
+
/**
|
|
9
26
|
* Register the workspace:// scheme on a ProviderRegistry.
|
|
10
27
|
*
|
|
11
28
|
* Extracted so that both createAFS() and verifyMount() can support
|
|
@@ -27,17 +44,26 @@ function registerWorkspaceFactory(registry) {
|
|
|
27
44
|
});
|
|
28
45
|
});
|
|
29
46
|
}
|
|
30
|
-
|
|
47
|
+
const cacheMap = /* @__PURE__ */ new Map();
|
|
48
|
+
function cacheKey(cwd) {
|
|
49
|
+
const { resolve } = require("node:path");
|
|
50
|
+
return resolve(cwd);
|
|
51
|
+
}
|
|
31
52
|
/**
|
|
32
|
-
* Load AFS with
|
|
53
|
+
* Load AFS with per-cwd caching — same cwd returns same instance,
|
|
54
|
+
* different cwd creates a separate instance.
|
|
33
55
|
*/
|
|
34
56
|
async function loadAFS(cwd, options) {
|
|
57
|
+
const key = cacheKey(cwd);
|
|
58
|
+
const cached = cacheMap.get(key);
|
|
35
59
|
if (cached) return {
|
|
36
60
|
afs: cached,
|
|
37
|
-
failures: []
|
|
61
|
+
failures: [],
|
|
62
|
+
configMountPaths: [],
|
|
63
|
+
registry: new _aigne_afs.ProviderRegistry()
|
|
38
64
|
};
|
|
39
65
|
const result = await createAFS(cwd, options);
|
|
40
|
-
|
|
66
|
+
cacheMap.set(key, result.afs);
|
|
41
67
|
return result;
|
|
42
68
|
}
|
|
43
69
|
/**
|
|
@@ -64,10 +90,10 @@ async function createAFS(cwd, options) {
|
|
|
64
90
|
workspacePath: parsed.body,
|
|
65
91
|
registry,
|
|
66
92
|
createProvider: async (subMount) => {
|
|
67
|
-
const credResult = await resolveAndMergeCredentials(subMount, authContext, credentialStore, registry);
|
|
93
|
+
const credResult = await require_credential_helpers.resolveAndMergeCredentials(subMount, authContext, credentialStore, registry);
|
|
68
94
|
const provider = await registry.createProvider(subMount);
|
|
69
95
|
if (credResult) {
|
|
70
|
-
await persistCredentialResult(subMount, credResult);
|
|
96
|
+
await require_credential_helpers.persistCredentialResult(subMount, credResult);
|
|
71
97
|
const opts = subMount.options ?? {};
|
|
72
98
|
for (const key of Object.keys(credResult.sensitive)) delete opts[key];
|
|
73
99
|
subMount.options = Object.keys(opts).length > 0 ? opts : void 0;
|
|
@@ -84,9 +110,13 @@ async function createAFS(cwd, options) {
|
|
|
84
110
|
...mount.options
|
|
85
111
|
});
|
|
86
112
|
});
|
|
113
|
+
afs.createProviderFromMount = async (mount) => {
|
|
114
|
+
await require_credential_helpers.resolveAndMergeCredentials(mount, authContext, credentialStore, registry);
|
|
115
|
+
return registry.createProvider(mount);
|
|
116
|
+
};
|
|
87
117
|
afs.loadProvider = async (uri, mountPath, options$1) => {
|
|
88
118
|
(0, _aigne_afs_utils_uri.parseURI)(uri);
|
|
89
|
-
const { cleanUri: loadConfigUri, envRecord: loadEnvRecord } = extractEnvFromURI(uri);
|
|
119
|
+
const { cleanUri: loadConfigUri, envRecord: loadEnvRecord } = require_credential_helpers.extractEnvFromURI(uri);
|
|
90
120
|
const hasLoadEnv = Object.keys(loadEnvRecord).length > 0;
|
|
91
121
|
const { accessMode, auth, description, scope, ...providerOptions } = options$1 ?? {};
|
|
92
122
|
if (hasLoadEnv) providerOptions.env = {
|
|
@@ -102,7 +132,7 @@ async function createAFS(cwd, options) {
|
|
|
102
132
|
options: Object.keys(providerOptions).length > 0 ? providerOptions : void 0
|
|
103
133
|
};
|
|
104
134
|
const persistScope = scope || "cwd";
|
|
105
|
-
let credResult = await resolveAndMergeCredentials(mount, authContext, credentialStore, registry);
|
|
135
|
+
let credResult = await require_credential_helpers.resolveAndMergeCredentials(mount, authContext, credentialStore, registry);
|
|
106
136
|
try {
|
|
107
137
|
const provider = await registry.createProvider(mount);
|
|
108
138
|
await afs.mount(provider, mountPath);
|
|
@@ -117,13 +147,13 @@ async function createAFS(cwd, options) {
|
|
|
117
147
|
description: description ?? void 0,
|
|
118
148
|
options: Object.keys(retryProviderOptions).length > 0 ? retryProviderOptions : void 0
|
|
119
149
|
};
|
|
120
|
-
credResult = await resolveAndMergeCredentials(retryMount, authContext, credentialStore, registry, { forceCollect: true });
|
|
150
|
+
credResult = await require_credential_helpers.resolveAndMergeCredentials(retryMount, authContext, credentialStore, registry, { forceCollect: true });
|
|
121
151
|
const retryProvider = await registry.createProvider(retryMount);
|
|
122
152
|
await afs.mount(retryProvider, mountPath);
|
|
123
153
|
Object.assign(mount, retryMount);
|
|
124
154
|
} else throw mountError;
|
|
125
155
|
}
|
|
126
|
-
if (credResult) await persistCredentialResult(mount, credResult);
|
|
156
|
+
if (credResult) await require_credential_helpers.persistCredentialResult(mount, credResult);
|
|
127
157
|
if (hasLoadEnv && credentialStore) try {
|
|
128
158
|
const envCreds = {};
|
|
129
159
|
for (const [k, v] of Object.entries(loadEnvRecord)) envCreds[`env:${k}`] = v;
|
|
@@ -177,14 +207,14 @@ async function createAFS(cwd, options) {
|
|
|
177
207
|
};
|
|
178
208
|
if (config.registry?.enabled !== false) try {
|
|
179
209
|
const { AFSRegistry } = await import("@aigne/afs-registry");
|
|
180
|
-
const
|
|
181
|
-
await afs.mount(
|
|
182
|
-
const internalRegistry = new AFSRegistry();
|
|
183
|
-
await afs.mount(internalRegistry, "/registry/internal");
|
|
210
|
+
const registry$1 = new AFSRegistry(config.registry?.providers?.length ? { providers: config.registry.providers } : void 0);
|
|
211
|
+
await afs.mount(registry$1, "/registry");
|
|
184
212
|
} catch {}
|
|
185
213
|
if (config.mounts.length === 0) return {
|
|
186
214
|
afs,
|
|
187
|
-
failures: []
|
|
215
|
+
failures: [],
|
|
216
|
+
configMountPaths: [],
|
|
217
|
+
registry
|
|
188
218
|
};
|
|
189
219
|
const total = config.mounts.length;
|
|
190
220
|
let completed = 0;
|
|
@@ -194,7 +224,7 @@ async function createAFS(cwd, options) {
|
|
|
194
224
|
completed: 0,
|
|
195
225
|
failed: 0
|
|
196
226
|
});
|
|
197
|
-
if (credentialStore && mountSources.size > 0) await mergeStoredCredentials(config.mounts, mountSources, credentialStore);
|
|
227
|
+
if (credentialStore && mountSources.size > 0) await require_credential_helpers.mergeStoredCredentials(config.mounts, mountSources, credentialStore);
|
|
198
228
|
const results = await Promise.allSettled(config.mounts.map(async (mount) => {
|
|
199
229
|
const provider = await registry.createProvider(mount);
|
|
200
230
|
await afs.mount(provider, mount.path, { namespace: mount.namespace ?? null });
|
|
@@ -232,304 +262,23 @@ async function createAFS(cwd, options) {
|
|
|
232
262
|
for (const f of failures) console.warn(` - ${f.path}: ${f.reason}`);
|
|
233
263
|
}
|
|
234
264
|
if (succeeded.length === 0 && config.mounts.length > 0) throw new Error("All providers failed to mount");
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
*
|
|
247
|
-
* Only applies to MCP schemes (mcp://, mcp+stdio://, mcp+sse://).
|
|
248
|
-
* Non-MCP URIs are returned unchanged.
|
|
249
|
-
*/
|
|
250
|
-
function extractEnvFromURI(uri) {
|
|
251
|
-
const parsed = (0, _aigne_afs_utils_uri.parseURI)(uri);
|
|
252
|
-
const envRecord = {};
|
|
253
|
-
if (!parsed.scheme.startsWith("mcp")) return {
|
|
254
|
-
cleanUri: uri,
|
|
255
|
-
envRecord
|
|
256
|
-
};
|
|
257
|
-
const envValues = parsed.query.env;
|
|
258
|
-
if (!envValues) return {
|
|
259
|
-
cleanUri: uri,
|
|
260
|
-
envRecord
|
|
261
|
-
};
|
|
262
|
-
const envList = Array.isArray(envValues) ? envValues : [envValues];
|
|
263
|
-
for (const entry of envList) {
|
|
264
|
-
const eqIdx = entry.indexOf("=");
|
|
265
|
-
if (eqIdx > 0) envRecord[entry.slice(0, eqIdx)] = entry.slice(eqIdx + 1);
|
|
266
|
-
}
|
|
267
|
-
const queryIndex = uri.indexOf("?");
|
|
268
|
-
if (queryIndex < 0) return {
|
|
269
|
-
cleanUri: uri,
|
|
270
|
-
envRecord
|
|
271
|
-
};
|
|
272
|
-
const rawQuery = uri.slice(queryIndex + 1);
|
|
273
|
-
const params = new URLSearchParams(rawQuery);
|
|
274
|
-
params.delete("env");
|
|
275
|
-
const newQuery = params.toString();
|
|
276
|
-
const base = uri.slice(0, queryIndex);
|
|
277
|
-
return {
|
|
278
|
-
cleanUri: newQuery ? `${base}?${newQuery}` : base,
|
|
279
|
-
envRecord
|
|
280
|
-
};
|
|
281
|
-
}
|
|
282
|
-
/**
|
|
283
|
-
* Extract template variables from mount.uri using the manifest's uriTemplate
|
|
284
|
-
* and merge them into mount.options so the credential resolver sees them as "known".
|
|
285
|
-
*
|
|
286
|
-
* Example: cloudflare://d9e5fca3... + template "cloudflare://{accountId}"
|
|
287
|
-
* → mount.options.accountId = "d9e5fca3..."
|
|
288
|
-
*/
|
|
289
|
-
function mergeTemplateVarsIntoMount(mount, manifest) {
|
|
290
|
-
if (!manifest?.uriTemplate) return;
|
|
291
|
-
const { parseTemplate } = require("@aigne/afs/utils/uri-template");
|
|
292
|
-
const parsed = (0, _aigne_afs_utils_uri.parseURI)(mount.uri);
|
|
293
|
-
let templateVars;
|
|
294
|
-
try {
|
|
295
|
-
templateVars = parseTemplate(manifest.uriTemplate, parsed.body);
|
|
296
|
-
} catch {
|
|
297
|
-
return;
|
|
298
|
-
}
|
|
299
|
-
for (const [key, value] of Object.entries(templateVars)) if (value !== void 0) {
|
|
300
|
-
if (!mount.options) mount.options = {};
|
|
301
|
-
if (mount.options[key] === void 0) mount.options[key] = value;
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
/**
|
|
305
|
-
* After credential resolution, rebuild mount.uri from the template if the
|
|
306
|
-
* current URI body is empty/incomplete and resolved options can fill template vars.
|
|
307
|
-
*
|
|
308
|
-
* Example: mount.uri = "cloudflare://" (empty body), mount.options.accountId = "abc"
|
|
309
|
-
* → mount.uri = "cloudflare://abc"
|
|
310
|
-
*/
|
|
311
|
-
function rebuildURIFromTemplate(mount, manifest) {
|
|
312
|
-
if (!manifest?.uriTemplate) return;
|
|
313
|
-
const { buildURI, getTemplateVariableNames } = require("@aigne/afs/utils/uri-template");
|
|
314
|
-
const varNames = getTemplateVariableNames(manifest.uriTemplate);
|
|
315
|
-
if (varNames.length === 0) return;
|
|
316
|
-
const parsed = (0, _aigne_afs_utils_uri.parseURI)(mount.uri);
|
|
317
|
-
const { parseTemplate } = require("@aigne/afs/utils/uri-template");
|
|
318
|
-
let existingVars;
|
|
319
|
-
try {
|
|
320
|
-
existingVars = parseTemplate(manifest.uriTemplate, parsed.body);
|
|
321
|
-
} catch {
|
|
322
|
-
existingVars = {};
|
|
323
|
-
}
|
|
324
|
-
const allVars = { ...existingVars };
|
|
325
|
-
for (const name of varNames) if (!allVars[name] && mount.options?.[name] != null) allVars[name] = String(mount.options[name]);
|
|
326
|
-
try {
|
|
327
|
-
const newURI = buildURI(manifest.uriTemplate, allVars);
|
|
328
|
-
if (newURI !== mount.uri) mount.uri = newURI;
|
|
329
|
-
} catch {}
|
|
330
|
-
}
|
|
331
|
-
/**
|
|
332
|
-
* Attempt credential resolution for a mount, merging resolved values into mount.options.
|
|
333
|
-
*
|
|
334
|
-
* Returns the credential result if any fields were collected interactively,
|
|
335
|
-
* or null if no interactive collection was needed (or no schema/authContext).
|
|
336
|
-
*
|
|
337
|
-
* This function mutates mount.options and mount.auth/mount.token when credentials
|
|
338
|
-
* are resolved, so the subsequent registry.createProvider(mount) receives complete values.
|
|
339
|
-
*/
|
|
340
|
-
async function resolveAndMergeCredentials(mount, authContext, credentialStore, registry, opts) {
|
|
341
|
-
const info = await registry.getProviderInfo(mount.uri);
|
|
342
|
-
const schema = info?.schema ?? null;
|
|
343
|
-
const providerAuth = info?.auth;
|
|
344
|
-
if (!schema) return null;
|
|
345
|
-
mergeTemplateVarsIntoMount(mount, info?.manifest);
|
|
346
|
-
const { getSensitiveFields } = await import("@aigne/afs/utils/schema");
|
|
347
|
-
const sensitiveFieldsInSchema = getSensitiveFields(schema);
|
|
348
|
-
const schemaProps = schema.properties ?? {};
|
|
349
|
-
const hasEnvFields = Object.values(schemaProps).some((p) => Array.isArray(p?.env));
|
|
350
|
-
if (sensitiveFieldsInSchema.length === 0 && !hasEnvFields && !providerAuth) return null;
|
|
351
|
-
const { resolveCredentials } = await Promise.resolve().then(() => require("../credential/resolver.cjs"));
|
|
352
|
-
const result = await resolveCredentials({
|
|
353
|
-
mount,
|
|
354
|
-
schema,
|
|
355
|
-
authContext,
|
|
356
|
-
credentialStore,
|
|
357
|
-
providerAuth,
|
|
358
|
-
forceCollect: opts?.forceCollect
|
|
359
|
-
});
|
|
360
|
-
if (!result) {
|
|
361
|
-
const fieldNames = Object.keys(schema.properties ?? {});
|
|
362
|
-
const known = /* @__PURE__ */ new Set();
|
|
363
|
-
if (mount.auth !== void 0) known.add("auth");
|
|
364
|
-
if (mount.token !== void 0) known.add("token");
|
|
365
|
-
if (mount.options) for (const k of Object.keys(mount.options)) known.add(k);
|
|
366
|
-
const missing = fieldNames.filter((f) => !known.has(f));
|
|
367
|
-
const fieldList = missing.length > 0 ? missing.join(", ") : fieldNames.join(", ");
|
|
368
|
-
throw new Error(`Missing credentials: ${fieldList}. Retry with them as args, e.g. { "uri": "${mount.uri}", "path": "${mount.path}", ${missing.map((f) => `"${f}": "..."`).join(", ")} }`);
|
|
369
|
-
}
|
|
370
|
-
if (Object.keys(result.values).length > 0) {
|
|
371
|
-
if (result.values.token !== void 0 && mount.token === void 0) mount.token = String(result.values.token);
|
|
372
|
-
if (result.values.auth !== void 0 && mount.auth === void 0) mount.auth = String(result.values.auth);
|
|
373
|
-
const opts$1 = mount.options ?? {};
|
|
374
|
-
for (const [key, value] of Object.entries(result.values)) if (key !== "token" && key !== "auth" && opts$1[key] === void 0) opts$1[key] = value;
|
|
375
|
-
if (Object.keys(opts$1).length > 0) mount.options = opts$1;
|
|
376
|
-
}
|
|
377
|
-
rebuildURIFromTemplate(mount, info?.manifest);
|
|
378
|
-
return result.collected ? result : null;
|
|
379
|
-
}
|
|
380
|
-
/**
|
|
381
|
-
* Persist credential resolution result (sensitive → credentials.toml, non-sensitive → config).
|
|
382
|
-
*/
|
|
383
|
-
async function persistCredentialResult(mount, result) {
|
|
384
|
-
if (Object.keys(result.sensitive).length > 0) try {
|
|
385
|
-
const { createCredentialStore } = await Promise.resolve().then(() => require("../credential/store.cjs"));
|
|
386
|
-
await createCredentialStore().set(mount.uri, result.sensitive);
|
|
387
|
-
} catch (err) {
|
|
388
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
389
|
-
console.warn(`[mount] credential persistence failed: ${msg}`);
|
|
390
|
-
}
|
|
391
|
-
}
|
|
392
|
-
/**
|
|
393
|
-
* Load stored credentials and merge into mount options during startup.
|
|
394
|
-
*
|
|
395
|
-
* Credentials are keyed by URI (the resource identity), not mount path.
|
|
396
|
-
*/
|
|
397
|
-
async function mergeStoredCredentials(mounts, _mountSources, store) {
|
|
398
|
-
for (const mount of mounts) try {
|
|
399
|
-
const stored = await store.get(mount.uri);
|
|
400
|
-
if (stored) {
|
|
401
|
-
const opts = mount.options ?? {};
|
|
402
|
-
for (const [key, value] of Object.entries(stored)) if (key.startsWith("env:")) {
|
|
403
|
-
if (!opts.env) opts.env = {};
|
|
404
|
-
opts.env[key.slice(4)] = value;
|
|
405
|
-
} else if (opts[key] === void 0) opts[key] = value;
|
|
406
|
-
if (Object.keys(opts).length > 0) mount.options = opts;
|
|
407
|
-
}
|
|
408
|
-
} catch {}
|
|
409
|
-
}
|
|
410
|
-
/**
|
|
411
|
-
* Resolve and persist credentials for a mount configuration.
|
|
412
|
-
*
|
|
413
|
-
* Used by `mount add` CLI command to trigger credential collection
|
|
414
|
-
* at add-time rather than deferring to AFS creation.
|
|
415
|
-
*
|
|
416
|
-
* - Gets provider schema via registry
|
|
417
|
-
* - Runs 4-step credential resolution
|
|
418
|
-
* - Persists sensitive values to credentials.toml
|
|
419
|
-
* - Returns non-sensitive values for caller to update config
|
|
420
|
-
*
|
|
421
|
-
* Returns null if no schema found or no credentials needed.
|
|
422
|
-
* Throws if user cancels collection when credentials are required.
|
|
423
|
-
*/
|
|
424
|
-
async function resolveCredentialsForMount(options) {
|
|
425
|
-
const { uri, mountPath, authContext, credentialStore, extraOptions, sensitiveArgs } = options;
|
|
426
|
-
const { cleanUri: configUri, envRecord } = extractEnvFromURI(uri);
|
|
427
|
-
const hasExtractedEnv = Object.keys(envRecord).length > 0;
|
|
428
|
-
const info = await (options.registry ?? new _aigne_afs.ProviderRegistry()).getProviderInfo(uri);
|
|
429
|
-
let schema = info?.schema ?? null;
|
|
430
|
-
const providerAuth = info?.auth;
|
|
431
|
-
if (!schema && extraOptions && Object.keys(extraOptions).length > 0) {
|
|
432
|
-
const { buildAdHocSchema } = await import("@aigne/afs/utils/schema");
|
|
433
|
-
schema = buildAdHocSchema(extraOptions, sensitiveArgs ?? []);
|
|
434
|
-
}
|
|
435
|
-
const envOnlyResult = () => {
|
|
436
|
-
if (!hasExtractedEnv) return null;
|
|
437
|
-
return {
|
|
438
|
-
collected: false,
|
|
439
|
-
nonSensitive: {},
|
|
440
|
-
allValues: {},
|
|
441
|
-
persistCredentials: async () => {
|
|
442
|
-
const toStore = {};
|
|
443
|
-
for (const [key, val] of Object.entries(envRecord)) toStore[`env:${key}`] = val;
|
|
444
|
-
if (credentialStore) try {
|
|
445
|
-
await credentialStore.set(configUri, toStore);
|
|
446
|
-
} catch (err) {
|
|
447
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
448
|
-
console.warn(`[mount add] credential persistence failed: ${msg}`);
|
|
449
|
-
}
|
|
450
|
-
},
|
|
451
|
-
sensitiveFields: [],
|
|
452
|
-
configUri
|
|
453
|
-
};
|
|
454
|
-
};
|
|
455
|
-
if (!schema) return envOnlyResult();
|
|
456
|
-
const properties = schema.properties;
|
|
457
|
-
if (!properties || Object.keys(properties).length === 0) return envOnlyResult();
|
|
458
|
-
if (sensitiveArgs && sensitiveArgs.length > 0) {
|
|
459
|
-
const mergedProps = { ...properties };
|
|
460
|
-
let changed = false;
|
|
461
|
-
for (const field of sensitiveArgs) if (mergedProps[field]) {
|
|
462
|
-
mergedProps[field] = {
|
|
463
|
-
...mergedProps[field],
|
|
464
|
-
sensitive: true
|
|
465
|
-
};
|
|
466
|
-
changed = true;
|
|
467
|
-
} else if (extraOptions?.[field] !== void 0) {
|
|
468
|
-
const value = extraOptions[field];
|
|
469
|
-
mergedProps[field] = {
|
|
470
|
-
type: typeof value === "number" ? "number" : typeof value === "boolean" ? "boolean" : "string",
|
|
471
|
-
sensitive: true
|
|
472
|
-
};
|
|
473
|
-
changed = true;
|
|
474
|
-
}
|
|
475
|
-
if (changed) schema = {
|
|
476
|
-
...schema,
|
|
477
|
-
properties: mergedProps
|
|
478
|
-
};
|
|
479
|
-
}
|
|
480
|
-
const { getSensitiveFields } = await import("@aigne/afs/utils/schema");
|
|
481
|
-
const sensitiveFieldsInSchema = getSensitiveFields(schema);
|
|
482
|
-
const schemaProps = schema.properties;
|
|
483
|
-
const hasEnvFields = Object.values(schemaProps).some((p) => Array.isArray(p?.env));
|
|
484
|
-
if (sensitiveFieldsInSchema.length === 0 && !hasEnvFields && !extraOptions) return envOnlyResult();
|
|
485
|
-
const mount = {
|
|
486
|
-
uri,
|
|
487
|
-
path: mountPath
|
|
488
|
-
};
|
|
489
|
-
if (extraOptions && Object.keys(extraOptions).length > 0) mount.options = {
|
|
490
|
-
...mount.options ?? {},
|
|
491
|
-
...extraOptions
|
|
492
|
-
};
|
|
493
|
-
mergeTemplateVarsIntoMount(mount, info?.manifest);
|
|
494
|
-
const { resolveCredentials } = await Promise.resolve().then(() => require("../credential/resolver.cjs"));
|
|
495
|
-
const result = await resolveCredentials({
|
|
496
|
-
mount,
|
|
497
|
-
schema,
|
|
498
|
-
authContext,
|
|
499
|
-
credentialStore,
|
|
500
|
-
providerAuth,
|
|
501
|
-
forceCollect: options.forceCollect
|
|
502
|
-
});
|
|
503
|
-
if (!result) {
|
|
504
|
-
const fieldNames = Object.keys(properties);
|
|
505
|
-
throw new Error(`Missing credentials: ${fieldNames.join(", ")}. Retry with them as args, e.g. { "uri": "${uri}", "path": "${mountPath}", ${fieldNames.map((f) => `"${f}": "..."`).join(", ")} }`);
|
|
506
|
-
}
|
|
507
|
-
const sensitiveFieldSet = new Set(sensitiveFieldsInSchema);
|
|
508
|
-
const flatSensitive = {};
|
|
509
|
-
for (const field of sensitiveFieldsInSchema) {
|
|
510
|
-
const val = result.values[field];
|
|
511
|
-
if (val === void 0) continue;
|
|
512
|
-
if (field === "env" && typeof val === "object" && val !== null) for (const [envKey, envVal] of Object.entries(val)) flatSensitive[`env:${envKey}`] = String(envVal);
|
|
513
|
-
else flatSensitive[field] = String(val);
|
|
265
|
+
{
|
|
266
|
+
const dataDir = (0, node_path.join)(process.env[require_loader.AFS_USER_CONFIG_DIR_ENV] ?? (0, node_path.join)((0, node_os.homedir)(), require_loader.CONFIG_DIR_NAME), "data");
|
|
267
|
+
try {
|
|
268
|
+
await (0, node_fs_promises.mkdir)(dataDir, { recursive: true });
|
|
269
|
+
const dataProvider = await registry.createProvider({
|
|
270
|
+
uri: `fs://${dataDir}`,
|
|
271
|
+
path: "/.data",
|
|
272
|
+
access_mode: "readwrite"
|
|
273
|
+
});
|
|
274
|
+
await afs.mount(dataProvider, "/.data");
|
|
275
|
+
} catch {}
|
|
514
276
|
}
|
|
515
|
-
const nonSensitive = result.collected ? result.nonSensitive : extraOptions ? Object.fromEntries(Object.entries(extraOptions).filter(([k]) => !sensitiveFieldSet.has(k))) : {};
|
|
516
|
-
const persistCredentials = async () => {
|
|
517
|
-
const toStore = { ...flatSensitive };
|
|
518
|
-
for (const [key, val] of Object.entries(envRecord)) toStore[`env:${key}`] = val;
|
|
519
|
-
if (Object.keys(toStore).length > 0 && credentialStore) try {
|
|
520
|
-
await credentialStore.set(configUri, toStore);
|
|
521
|
-
} catch (err) {
|
|
522
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
523
|
-
console.warn(`[mount add] credential persistence failed: ${msg}`);
|
|
524
|
-
}
|
|
525
|
-
};
|
|
526
277
|
return {
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
sensitiveFields: sensitiveFieldsInSchema,
|
|
532
|
-
configUri: hasExtractedEnv ? configUri : void 0
|
|
278
|
+
afs,
|
|
279
|
+
failures,
|
|
280
|
+
configMountPaths: succeeded,
|
|
281
|
+
registry
|
|
533
282
|
};
|
|
534
283
|
}
|
|
535
284
|
/**
|
|
@@ -565,8 +314,8 @@ async function verifyMount(uri, mountPath, options) {
|
|
|
565
314
|
const msg = err instanceof Error ? err.message : String(err);
|
|
566
315
|
throw new Error(`Mount verification failed: could not reach provider at ${uri}. Error: ${msg}. Check your URI and credentials.`);
|
|
567
316
|
} finally {
|
|
568
|
-
|
|
569
|
-
await provider.close();
|
|
317
|
+
try {
|
|
318
|
+
await provider.close?.();
|
|
570
319
|
} catch {}
|
|
571
320
|
}
|
|
572
321
|
}
|
|
@@ -574,5 +323,5 @@ async function verifyMount(uri, mountPath, options) {
|
|
|
574
323
|
//#endregion
|
|
575
324
|
exports.createAFS = createAFS;
|
|
576
325
|
exports.loadAFS = loadAFS;
|
|
577
|
-
exports.resolveCredentialsForMount = resolveCredentialsForMount;
|
|
326
|
+
exports.resolveCredentialsForMount = require_credential_helpers.resolveCredentialsForMount;
|
|
578
327
|
exports.verifyMount = verifyMount;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"afs-loader.d.cts","names":[],"sources":["../../src/config/afs-loader.ts"],"mappings":";;;;
|
|
1
|
+
{"version":3,"file":"afs-loader.d.cts","names":[],"sources":["../../src/config/afs-loader.ts"],"mappings":";;;;UA8EiB,kBAAA;EACf,KAAA;EACA,SAAA;EACA,MAAA;AAAA;AAAA,UAiBe,gBAAA;EACf,UAAA,IAAc,KAAA,EAAO,kBAAA;;EAErB,WAAA,GAAc,WAAA;;EAEd,eAAA,GAAkB,eAAA;AAAA"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { CredentialStore } from "../credential/store.mjs";
|
|
2
|
-
import
|
|
2
|
+
import "./credential-helpers.mjs";
|
|
3
|
+
import { AFS, AuthContext } from "@aigne/afs";
|
|
3
4
|
|
|
4
5
|
//#region src/config/afs-loader.d.ts
|
|
5
6
|
interface MountProgressEvent {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"afs-loader.d.mts","names":[],"sources":["../../src/config/afs-loader.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"afs-loader.d.mts","names":[],"sources":["../../src/config/afs-loader.ts"],"mappings":";;;;;UA8EiB,kBAAA;EACf,KAAA;EACA,SAAA;EACA,MAAA;AAAA;AAAA,UAiBe,gBAAA;EACf,UAAA,IAAc,KAAA,EAAO,kBAAA;;EAErB,WAAA,GAAc,WAAA;;EAEd,eAAA,GAAkB,eAAA;AAAA"}
|