@tencentcloudadp/cli 0.1.4 → 0.1.5
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/README.md +3 -3
- package/bin/adp.js +3 -2
- package/dist/cli.js +1929 -441
- package/dist/cli.js.map +1 -1
- package/package.json +2 -1
- package/skills/adp/SKILL.md +3 -2
- package/skills/adp/configuration/SKILL.md +3 -0
- package/skills/adp/create/SKILL.md +39 -7
- package/skills/adp/evals/evals.json +14 -0
- package/skills/adp/gotchas/SKILL.md +8 -4
- package/skills/adp/references/app-modes.md +2 -1
- package/skills/adp/references/auth.md +3 -3
- package/skills/adp/references/credentials.md +46 -8
- package/skills/adp/references/mcp.md +78 -0
- package/skills/adp/references/pitfalls.md +6 -0
package/dist/cli.js
CHANGED
|
@@ -153,12 +153,12 @@ var CommandRegistry = class {
|
|
|
153
153
|
};
|
|
154
154
|
}
|
|
155
155
|
schemaHint(tokens) {
|
|
156
|
-
const
|
|
156
|
+
const path18 = [];
|
|
157
157
|
for (const token of tokens) {
|
|
158
|
-
if (!this.knownTokensAt(
|
|
159
|
-
|
|
158
|
+
if (!this.knownTokensAt(path18).has(token)) break;
|
|
159
|
+
path18.push(token);
|
|
160
160
|
}
|
|
161
|
-
return
|
|
161
|
+
return path18.length > 0 ? `Run: adp schema --command "${path18.join(" ")}" --format json` : "Run: adp schema --compact --format json";
|
|
162
162
|
}
|
|
163
163
|
/**
|
|
164
164
|
* Resolves argv's command tokens against the real command tree, returning a
|
|
@@ -191,26 +191,26 @@ var CommandRegistry = class {
|
|
|
191
191
|
return void 0;
|
|
192
192
|
}
|
|
193
193
|
/** True when `path` is a group, i.e. something must follow it. */
|
|
194
|
-
isGroupPath(
|
|
195
|
-
const prefix =
|
|
194
|
+
isGroupPath(path18) {
|
|
195
|
+
const prefix = path18.join(" ");
|
|
196
196
|
return this.commands.some((definition) => {
|
|
197
197
|
const parts = literalTokens(definition.command);
|
|
198
|
-
return parts.length >
|
|
198
|
+
return parts.length > path18.length && parts.slice(0, path18.length).join(" ") === prefix;
|
|
199
199
|
});
|
|
200
200
|
}
|
|
201
201
|
/** Every valid next token at a command path: leaf names and group names. */
|
|
202
|
-
knownTokensAt(
|
|
203
|
-
const prefix =
|
|
202
|
+
knownTokensAt(path18) {
|
|
203
|
+
const prefix = path18.join(" ");
|
|
204
204
|
const tokens = /* @__PURE__ */ new Set();
|
|
205
205
|
for (const definition of this.commands) {
|
|
206
206
|
const parts = literalTokens(definition.command);
|
|
207
|
-
if (parts.length <=
|
|
207
|
+
if (parts.length <= path18.length) {
|
|
208
208
|
continue;
|
|
209
209
|
}
|
|
210
|
-
if (parts.slice(0,
|
|
210
|
+
if (parts.slice(0, path18.length).join(" ") !== prefix) {
|
|
211
211
|
continue;
|
|
212
212
|
}
|
|
213
|
-
const next = parts[
|
|
213
|
+
const next = parts[path18.length];
|
|
214
214
|
if (next !== void 0) {
|
|
215
215
|
tokens.add(next);
|
|
216
216
|
}
|
|
@@ -583,7 +583,7 @@ function fitsRegisteredCommand(command, definitions) {
|
|
|
583
583
|
}
|
|
584
584
|
|
|
585
585
|
// src/infrastructure/logging/logger.ts
|
|
586
|
-
var SECRET_RE = /secret[_-]?id|secret[_-]?key|secret[_-]?token|tmp[_-]?secret|app[_-]?key|x-cos-security-token|TENCENTCLOUD_/gi;
|
|
586
|
+
var SECRET_RE = /secret[_-]?id|secret[_-]?key|secret[_-]?token|tmp[_-]?secret|app[_-]?key|tool[_-]?key|x-cos-security-token|TENCENTCLOUD_/gi;
|
|
587
587
|
var SECRET_ID_RE = /\bAKID[0-9A-Za-z]+\b/g;
|
|
588
588
|
function redact(value) {
|
|
589
589
|
return value.replace(SECRET_ID_RE, "[redacted-secret-id]").replace(SECRET_RE, "[redacted]");
|
|
@@ -1145,24 +1145,11 @@ function assertNumericId(value, name, listCommand) {
|
|
|
1145
1145
|
}
|
|
1146
1146
|
return trimmed;
|
|
1147
1147
|
}
|
|
1148
|
-
function
|
|
1148
|
+
function assertLocalPath(input) {
|
|
1149
1149
|
if (!input || hasControlChars(input)) {
|
|
1150
1150
|
throw usageError("Invalid local path", "Pass a filesystem path without control characters");
|
|
1151
1151
|
}
|
|
1152
|
-
|
|
1153
|
-
return normalize(resolve(cwd, input));
|
|
1154
|
-
}
|
|
1155
|
-
function pathFromNode() {
|
|
1156
|
-
const posixJoin = (left, right) => {
|
|
1157
|
-
if (right.startsWith("/") || /^[A-Za-z]:[\\/]/.test(right)) {
|
|
1158
|
-
return right;
|
|
1159
|
-
}
|
|
1160
|
-
return `${left.replace(/[/\\]+$/, "")}/${right.replace(/^[/\\]+/, "")}`;
|
|
1161
|
-
};
|
|
1162
|
-
return {
|
|
1163
|
-
resolve: (...parts) => parts.reduce((acc, part) => posixJoin(acc, part)),
|
|
1164
|
-
normalize: (p) => p.replace(/\\/g, "/").replace(/\/{2,}/g, "/")
|
|
1165
|
-
};
|
|
1152
|
+
return input;
|
|
1166
1153
|
}
|
|
1167
1154
|
|
|
1168
1155
|
// src/interfaces/cli/core/id-flags.ts
|
|
@@ -1890,13 +1877,15 @@ ${input.error ? `<p class="err">${escapeHtml(input.error)}</p>` : ""}
|
|
|
1890
1877
|
|
|
1891
1878
|
// src/infrastructure/child-process/detached-login.ts
|
|
1892
1879
|
import { spawn } from "child_process";
|
|
1880
|
+
import { win32 } from "path";
|
|
1893
1881
|
var DETACHED_LOGIN_ENV = "ADP_WEB_LOGIN_IPC";
|
|
1894
1882
|
async function launchDetachedLogin(input) {
|
|
1895
|
-
const entry = process.argv[1];
|
|
1883
|
+
const entry = input.entry ?? process.argv[1];
|
|
1896
1884
|
if (!entry) {
|
|
1897
1885
|
throw new DomainError("Cannot locate the adp entry script", "upstream", "DetachFailed");
|
|
1898
1886
|
}
|
|
1899
|
-
const child = spawn(process.execPath, [...process.execArgv, entry, ...input.args], {
|
|
1887
|
+
const child = (input.spawnImpl ?? spawn)(input.execPath ?? process.execPath, [...input.execArgv ?? process.execArgv, entry, ...input.args], {
|
|
1888
|
+
shell: false,
|
|
1900
1889
|
detached: true,
|
|
1901
1890
|
stdio: ["ignore", "ignore", "ignore", "ipc"],
|
|
1902
1891
|
env: { ...input.env, [DETACHED_LOGIN_ENV]: "1" },
|
|
@@ -1909,9 +1898,10 @@ async function launchDetachedLogin(input) {
|
|
|
1909
1898
|
}, input.handshakeTimeoutMs ?? 15e3);
|
|
1910
1899
|
child.once("message", (message) => {
|
|
1911
1900
|
clearTimeout(timer);
|
|
1912
|
-
const parsed = message;
|
|
1913
|
-
if (parsed.type !== "auth_url" || !parsed.url || !parsed.expiresAt) {
|
|
1914
|
-
|
|
1901
|
+
const parsed = message && typeof message === "object" ? message : {};
|
|
1902
|
+
if (parsed.type !== "auth_url" || typeof parsed.url !== "string" || typeof parsed.expiresAt !== "string" || !parsed.url || !parsed.expiresAt) {
|
|
1903
|
+
child.kill();
|
|
1904
|
+
reject(new DomainError(typeof parsed.error === "string" ? parsed.error : "The login server failed to start", "upstream", "DetachFailed"));
|
|
1915
1905
|
return;
|
|
1916
1906
|
}
|
|
1917
1907
|
child.disconnect();
|
|
@@ -1928,10 +1918,27 @@ async function launchDetachedLogin(input) {
|
|
|
1928
1918
|
});
|
|
1929
1919
|
});
|
|
1930
1920
|
}
|
|
1931
|
-
function openInBrowser(url) {
|
|
1932
|
-
|
|
1921
|
+
function openInBrowser(url, options = {}) {
|
|
1922
|
+
let target;
|
|
1923
|
+
try {
|
|
1924
|
+
target = new URL(url);
|
|
1925
|
+
} catch {
|
|
1926
|
+
throw new DomainError("Browser URL must be an absolute HTTP(S) URL", "usage", "InvalidBrowserUrl");
|
|
1927
|
+
}
|
|
1928
|
+
if (!["http:", "https:"].includes(target.protocol) || [...url].some((char) => char.charCodeAt(0) < 32)) {
|
|
1929
|
+
throw new DomainError("Browser URL must use HTTP(S) without control characters", "usage", "InvalidBrowserUrl");
|
|
1930
|
+
}
|
|
1931
|
+
const platform = options.platform ?? process.platform;
|
|
1932
|
+
const env = options.env ?? process.env;
|
|
1933
|
+
const systemRoot = Object.entries(env).find(([key]) => key.toLowerCase() === "systemroot")?.[1] ?? "C:\\Windows";
|
|
1934
|
+
const [command, args] = platform === "darwin" ? ["open", [target.href]] : platform === "win32" ? [win32.join(systemRoot, "System32", "rundll32.exe"), [`${win32.join(systemRoot, "System32", "url.dll")},FileProtocolHandler`, target.href]] : ["xdg-open", [target.href]];
|
|
1933
1935
|
try {
|
|
1934
|
-
const child = spawn(command, args, {
|
|
1936
|
+
const child = (options.spawnImpl ?? spawn)(command, args, {
|
|
1937
|
+
detached: true,
|
|
1938
|
+
stdio: "ignore",
|
|
1939
|
+
windowsHide: true,
|
|
1940
|
+
shell: false
|
|
1941
|
+
});
|
|
1935
1942
|
child.on("error", () => void 0);
|
|
1936
1943
|
child.unref();
|
|
1937
1944
|
} catch {
|
|
@@ -2007,27 +2014,51 @@ async function resolveIdentity(deps, input) {
|
|
|
2007
2014
|
}
|
|
2008
2015
|
|
|
2009
2016
|
// src/infrastructure/fs/profile-file-store.ts
|
|
2010
|
-
import {
|
|
2011
|
-
|
|
2017
|
+
import { readFile, readdir, rm } from "fs/promises";
|
|
2018
|
+
|
|
2019
|
+
// src/infrastructure/fs/private-file.ts
|
|
2020
|
+
import { chmod, mkdir, writeFile } from "fs/promises";
|
|
2012
2021
|
import path from "path";
|
|
2022
|
+
async function writePrivateFile(filePath, contents, options = {}) {
|
|
2023
|
+
const fs = { mkdir, writeFile, chmod, ...options.fs };
|
|
2024
|
+
const posix = (options.platform ?? process.platform) !== "win32";
|
|
2025
|
+
await fs.mkdir(path.dirname(filePath), { recursive: true });
|
|
2026
|
+
if (posix) {
|
|
2027
|
+
try {
|
|
2028
|
+
await fs.chmod(filePath, 384);
|
|
2029
|
+
} catch (error) {
|
|
2030
|
+
if (error.code !== "ENOENT") {
|
|
2031
|
+
throw error;
|
|
2032
|
+
}
|
|
2033
|
+
}
|
|
2034
|
+
}
|
|
2035
|
+
await fs.writeFile(filePath, contents, { encoding: "utf8", ...posix ? { mode: 384 } : {} });
|
|
2036
|
+
if (posix) {
|
|
2037
|
+
await fs.chmod(filePath, 384);
|
|
2038
|
+
}
|
|
2039
|
+
}
|
|
2040
|
+
|
|
2041
|
+
// src/infrastructure/fs/profile-file-store.ts
|
|
2042
|
+
import { homedir } from "os";
|
|
2043
|
+
import path2 from "path";
|
|
2013
2044
|
function adpProfilesDir(home = homedir()) {
|
|
2014
|
-
return
|
|
2045
|
+
return path2.join(home, ".adp", "profiles");
|
|
2015
2046
|
}
|
|
2016
2047
|
function adpActiveProfilePath(home = homedir()) {
|
|
2017
|
-
return
|
|
2048
|
+
return path2.join(home, ".adp", "active");
|
|
2018
2049
|
}
|
|
2019
2050
|
function profileFileName(name) {
|
|
2020
|
-
if (!name || name
|
|
2051
|
+
if (!name || name.startsWith(".") || /[<>:"/\\|?*]/u.test(name) || [...name].some((character) => character.charCodeAt(0) < 32) || /[. ]$/u.test(name) || /^(?:con|prn|aux|nul|conin\$|conout\$|com[1-9¹²³]|lpt[1-9¹²³]) *(?:\.|$)/iu.test(name)) {
|
|
2021
2052
|
throw new Error(`Invalid profile name: ${name}`);
|
|
2022
2053
|
}
|
|
2023
2054
|
return `${name}.json`;
|
|
2024
2055
|
}
|
|
2025
|
-
function createProfileStore(dir = adpProfilesDir(), activePath = adpActiveProfilePath()) {
|
|
2056
|
+
function createProfileStore(dir = adpProfilesDir(), activePath = adpActiveProfilePath(), privateFileOptions = {}) {
|
|
2026
2057
|
return {
|
|
2027
2058
|
async load(name) {
|
|
2028
2059
|
let text13;
|
|
2029
2060
|
try {
|
|
2030
|
-
text13 = await readFile(
|
|
2061
|
+
text13 = await readFile(path2.join(dir, profileFileName(name)), "utf8");
|
|
2031
2062
|
} catch (error) {
|
|
2032
2063
|
if (error.code === "ENOENT") {
|
|
2033
2064
|
return void 0;
|
|
@@ -2037,17 +2068,12 @@ function createProfileStore(dir = adpProfilesDir(), activePath = adpActiveProfil
|
|
|
2037
2068
|
return parseProfile(name, text13);
|
|
2038
2069
|
},
|
|
2039
2070
|
async save(profile) {
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
`, {
|
|
2044
|
-
encoding: "utf8",
|
|
2045
|
-
mode: 384
|
|
2046
|
-
});
|
|
2047
|
-
await chmod(target, 384);
|
|
2071
|
+
const target = path2.join(dir, profileFileName(profile.name));
|
|
2072
|
+
await writePrivateFile(target, `${JSON.stringify(profile, null, 2)}
|
|
2073
|
+
`, privateFileOptions);
|
|
2048
2074
|
},
|
|
2049
2075
|
async remove(name) {
|
|
2050
|
-
await rm(
|
|
2076
|
+
await rm(path2.join(dir, profileFileName(name)), { force: true });
|
|
2051
2077
|
},
|
|
2052
2078
|
async list() {
|
|
2053
2079
|
let entries;
|
|
@@ -2082,15 +2108,13 @@ function createProfileStore(dir = adpProfilesDir(), activePath = adpActiveProfil
|
|
|
2082
2108
|
}
|
|
2083
2109
|
throw error;
|
|
2084
2110
|
}
|
|
2085
|
-
const name = text13.
|
|
2086
|
-
return name.length > 0 ? name : void 0;
|
|
2111
|
+
const name = text13.replace(/[\r\n]+$/u, "");
|
|
2112
|
+
return name.trim().length > 0 ? name : void 0;
|
|
2087
2113
|
},
|
|
2088
2114
|
async setActive(name) {
|
|
2089
2115
|
profileFileName(name);
|
|
2090
|
-
await
|
|
2091
|
-
|
|
2092
|
-
`, { encoding: "utf8", mode: 384 });
|
|
2093
|
-
await chmod(activePath, 384);
|
|
2116
|
+
await writePrivateFile(activePath, `${name}
|
|
2117
|
+
`, privateFileOptions);
|
|
2094
2118
|
}
|
|
2095
2119
|
};
|
|
2096
2120
|
}
|
|
@@ -2401,7 +2425,7 @@ function mapSdkError(error) {
|
|
|
2401
2425
|
if (/SecretIdNotFound/i.test(blob)) {
|
|
2402
2426
|
return new DomainError(message, "auth", code, {
|
|
2403
2427
|
...options,
|
|
2404
|
-
hint: "This SecretId
|
|
2428
|
+
hint: "This SecretId was not found on the host that received it. SaveDoc, RetryDocParse, and workflow canvas use the same LKE 2023-11-30 actions on every site: public cloud calls lke.tencentcloudapi.com, and an independent or custom profile sends them to its ADP host. Log in with the site that issued the key.",
|
|
2405
2429
|
retryable: false
|
|
2406
2430
|
});
|
|
2407
2431
|
}
|
|
@@ -3096,11 +3120,11 @@ function mergePluginBindings(spec) {
|
|
|
3096
3120
|
byId.set(tool.pluginId, { pluginId: tool.pluginId });
|
|
3097
3121
|
}
|
|
3098
3122
|
}
|
|
3099
|
-
for (const
|
|
3100
|
-
byId.set(
|
|
3123
|
+
for (const pluginId3 of spec.pluginIds) {
|
|
3124
|
+
byId.set(pluginId3, { pluginId: pluginId3 });
|
|
3101
3125
|
}
|
|
3102
|
-
for (const
|
|
3103
|
-
byId.set(
|
|
3126
|
+
for (const pluginId3 of spec.connectorIds ?? []) {
|
|
3127
|
+
byId.set(pluginId3, { pluginId: pluginId3 });
|
|
3104
3128
|
}
|
|
3105
3129
|
for (const plugin of spec.plugins ?? []) {
|
|
3106
3130
|
byId.set(plugin.pluginId, plugin);
|
|
@@ -3208,7 +3232,9 @@ function toSummary5(raw) {
|
|
|
3208
3232
|
return {
|
|
3209
3233
|
agentId: String(raw.AgentId ?? raw.agentId ?? ""),
|
|
3210
3234
|
name: optionalString3(raw.Name ?? raw.name ?? profile.Name) ?? "",
|
|
3211
|
-
description: optionalString3(raw.Description ?? raw.description ?? profile.Description)
|
|
3235
|
+
description: optionalString3(raw.Description ?? raw.description ?? profile.Description),
|
|
3236
|
+
role: roleOf(raw.Role ?? profile.Role),
|
|
3237
|
+
parentAgentId: optionalString3(raw.ParentAgentId ?? profile.ParentAgentId)
|
|
3212
3238
|
};
|
|
3213
3239
|
}
|
|
3214
3240
|
function toDetail3(response, fallbackId) {
|
|
@@ -3255,9 +3281,14 @@ function toDetail3(response, fallbackId) {
|
|
|
3255
3281
|
agentId: String(response.AgentId ?? agent.AgentId ?? fallbackId),
|
|
3256
3282
|
name: optionalString3(profile.Name),
|
|
3257
3283
|
description: optionalString3(profile.Description),
|
|
3284
|
+
role: roleOf(profile.Role),
|
|
3285
|
+
parentAgentId: optionalString3(profile.ParentAgentId),
|
|
3258
3286
|
spec
|
|
3259
3287
|
};
|
|
3260
3288
|
}
|
|
3289
|
+
function roleOf(value) {
|
|
3290
|
+
return typeof value === "number" ? value : void 0;
|
|
3291
|
+
}
|
|
3261
3292
|
function optionalString3(value) {
|
|
3262
3293
|
return typeof value === "string" ? value : void 0;
|
|
3263
3294
|
}
|
|
@@ -3463,14 +3494,14 @@ function isApiCreate(input) {
|
|
|
3463
3494
|
return "spec" in input;
|
|
3464
3495
|
}
|
|
3465
3496
|
function createPluginGateway(client) {
|
|
3466
|
-
async function describeRaw(
|
|
3497
|
+
async function describeRaw(pluginId3, spaceId) {
|
|
3467
3498
|
const response = await callSdk(
|
|
3468
|
-
() => client.request("DescribePlugin", compact({ PluginId:
|
|
3499
|
+
() => client.request("DescribePlugin", compact({ PluginId: pluginId3, SpaceId: spaceId }))
|
|
3469
3500
|
);
|
|
3470
3501
|
return asRecord2(response.Plugin ?? response);
|
|
3471
3502
|
}
|
|
3472
|
-
async function describePlugin2(
|
|
3473
|
-
return toSummary7(await describeRaw(
|
|
3503
|
+
async function describePlugin2(pluginId3, spaceId) {
|
|
3504
|
+
return toSummary7(await describeRaw(pluginId3, spaceId));
|
|
3474
3505
|
}
|
|
3475
3506
|
return {
|
|
3476
3507
|
async list(input) {
|
|
@@ -4540,6 +4571,376 @@ function createPluginAccessGateway(client) {
|
|
|
4540
4571
|
};
|
|
4541
4572
|
}
|
|
4542
4573
|
|
|
4574
|
+
// src/infrastructure/tencent/tool-key-gateway.ts
|
|
4575
|
+
function asText(value) {
|
|
4576
|
+
if (typeof value === "string" && value) {
|
|
4577
|
+
return value;
|
|
4578
|
+
}
|
|
4579
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
4580
|
+
return String(value);
|
|
4581
|
+
}
|
|
4582
|
+
return void 0;
|
|
4583
|
+
}
|
|
4584
|
+
function toRecord(raw) {
|
|
4585
|
+
const record = asRecord2(raw);
|
|
4586
|
+
const apiKeyId = asText(record.ApiKeyId);
|
|
4587
|
+
if (!apiKeyId) {
|
|
4588
|
+
return void 0;
|
|
4589
|
+
}
|
|
4590
|
+
const status = Number(record.Status);
|
|
4591
|
+
return {
|
|
4592
|
+
apiKeyId,
|
|
4593
|
+
apiKey: asText(record.ApiKey) ?? "",
|
|
4594
|
+
description: asText(record.Description) ?? "",
|
|
4595
|
+
...Number.isFinite(status) ? { status } : {},
|
|
4596
|
+
...asText(record.CreateTime) ? { createTime: asText(record.CreateTime) } : {},
|
|
4597
|
+
...asText(record.LastAccessTime) ? { lastAccessTime: asText(record.LastAccessTime) } : {}
|
|
4598
|
+
};
|
|
4599
|
+
}
|
|
4600
|
+
function createToolKeyGateway(client) {
|
|
4601
|
+
return {
|
|
4602
|
+
async create() {
|
|
4603
|
+
const response = await callSdk(() => client.request("CreateApiKey", {}));
|
|
4604
|
+
return { apiKey: String(response.ApiKey ?? ""), apiKeyId: String(response.ApiKeyId ?? "") };
|
|
4605
|
+
},
|
|
4606
|
+
async list() {
|
|
4607
|
+
const response = await callSdk(() => client.request("DescribeApiKeyList", {}));
|
|
4608
|
+
const items = Array.isArray(response.ApiKeyList) ? response.ApiKeyList : [];
|
|
4609
|
+
return items.map(toRecord).filter((item) => item !== void 0);
|
|
4610
|
+
},
|
|
4611
|
+
async update(input) {
|
|
4612
|
+
await callSdk(
|
|
4613
|
+
() => client.request("ModifyApiKey", { ApiKeyId: input.apiKeyId, Description: input.description })
|
|
4614
|
+
);
|
|
4615
|
+
},
|
|
4616
|
+
async setStatus(input) {
|
|
4617
|
+
await callSdk(
|
|
4618
|
+
() => client.request("ModifyApiKeyStatus", { ApiKeyId: input.apiKeyId, Status: input.status })
|
|
4619
|
+
);
|
|
4620
|
+
},
|
|
4621
|
+
async delete(input) {
|
|
4622
|
+
await callSdk(() => client.request("DeleteApiKey", { ApiKeyId: input.apiKeyId }));
|
|
4623
|
+
}
|
|
4624
|
+
};
|
|
4625
|
+
}
|
|
4626
|
+
|
|
4627
|
+
// src/domain/plugin/mcp-url.ts
|
|
4628
|
+
var PLUGIN_MCP_URL_PREFIX = "https://adp.cloud.tencent.com/";
|
|
4629
|
+
var PLUGIN_ID = /^[A-Za-z0-9][A-Za-z0-9_-]{0,127}$/;
|
|
4630
|
+
function pluginMcpUrl(pluginId3) {
|
|
4631
|
+
if (!PLUGIN_ID.test(pluginId3)) {
|
|
4632
|
+
throw usageError(
|
|
4633
|
+
"Invalid plugin-id for an MCP URL",
|
|
4634
|
+
"Pass the plugin id from adp plugin list. It must be one path segment, without slashes."
|
|
4635
|
+
);
|
|
4636
|
+
}
|
|
4637
|
+
return `${PLUGIN_MCP_URL_PREFIX}plugin/mcp/${pluginId3}/mcp`;
|
|
4638
|
+
}
|
|
4639
|
+
function assertPluginMcpUrl(url) {
|
|
4640
|
+
let parsed;
|
|
4641
|
+
try {
|
|
4642
|
+
parsed = new URL(url);
|
|
4643
|
+
} catch {
|
|
4644
|
+
throw mcpUrlRejected();
|
|
4645
|
+
}
|
|
4646
|
+
const allowed = new URL(PLUGIN_MCP_URL_PREFIX);
|
|
4647
|
+
if (parsed.origin !== allowed.origin || parsed.username || parsed.password || parsed.search || parsed.hash) {
|
|
4648
|
+
throw mcpUrlRejected();
|
|
4649
|
+
}
|
|
4650
|
+
if (!/^\/plugin\/mcp\/[A-Za-z0-9][A-Za-z0-9_-]{0,127}\/mcp$/.test(parsed.pathname)) {
|
|
4651
|
+
throw mcpUrlRejected();
|
|
4652
|
+
}
|
|
4653
|
+
}
|
|
4654
|
+
function mcpUrlRejected() {
|
|
4655
|
+
return new DomainError(
|
|
4656
|
+
"Refusing to send a tool key to a URL outside the plugin MCP allowlist",
|
|
4657
|
+
"usage",
|
|
4658
|
+
"McpUrlNotAllowed",
|
|
4659
|
+
{
|
|
4660
|
+
hint: "Calls only go to https://adp.cloud.tencent.com/plugin/mcp/<pluginId>/mcp",
|
|
4661
|
+
retryable: false
|
|
4662
|
+
}
|
|
4663
|
+
);
|
|
4664
|
+
}
|
|
4665
|
+
|
|
4666
|
+
// src/infrastructure/mcp/plugin-mcp-client.ts
|
|
4667
|
+
var PROTOCOL_VERSION = "2024-11-05";
|
|
4668
|
+
var CLIENT_INFO = { name: "adp-cli", version: "0.0.0" };
|
|
4669
|
+
var ERROR_BODY_PREVIEW = 400;
|
|
4670
|
+
function createPluginMcpGateway(options = {}) {
|
|
4671
|
+
const fetchImpl = options.fetchImpl ?? fetch;
|
|
4672
|
+
async function open(input) {
|
|
4673
|
+
const url = pluginMcpUrl(input.pluginId);
|
|
4674
|
+
assertPluginMcpUrl(url);
|
|
4675
|
+
const session = createSession({ url, apiKey: input.apiKey, fetchImpl, timeoutMs: input.timeoutMs });
|
|
4676
|
+
await session.initialize();
|
|
4677
|
+
return session;
|
|
4678
|
+
}
|
|
4679
|
+
return {
|
|
4680
|
+
async listTools(input) {
|
|
4681
|
+
const session = await open(input);
|
|
4682
|
+
return readTools(await session.sendRequest("tools/list", {}));
|
|
4683
|
+
},
|
|
4684
|
+
async callTool(input) {
|
|
4685
|
+
const session = await open(input);
|
|
4686
|
+
return unwrapToolPayload(
|
|
4687
|
+
await session.sendRequest("tools/call", { name: input.toolName, arguments: input.arguments }),
|
|
4688
|
+
input.apiKey
|
|
4689
|
+
);
|
|
4690
|
+
}
|
|
4691
|
+
};
|
|
4692
|
+
}
|
|
4693
|
+
function createSession(options) {
|
|
4694
|
+
let sessionId = "";
|
|
4695
|
+
let nextId = 1;
|
|
4696
|
+
async function post(payload) {
|
|
4697
|
+
assertPluginMcpUrl(options.url);
|
|
4698
|
+
const headers = {
|
|
4699
|
+
"Content-Type": "application/json",
|
|
4700
|
+
Accept: "application/json, text/event-stream",
|
|
4701
|
+
Authorization: `Bearer ${options.apiKey}`
|
|
4702
|
+
};
|
|
4703
|
+
if (sessionId) {
|
|
4704
|
+
headers["Mcp-Session-Id"] = sessionId;
|
|
4705
|
+
}
|
|
4706
|
+
const controller = new AbortController();
|
|
4707
|
+
const timer = setTimeout(() => controller.abort(), options.timeoutMs);
|
|
4708
|
+
let response;
|
|
4709
|
+
try {
|
|
4710
|
+
response = await options.fetchImpl(options.url, {
|
|
4711
|
+
method: "POST",
|
|
4712
|
+
headers,
|
|
4713
|
+
body: JSON.stringify(payload),
|
|
4714
|
+
signal: controller.signal,
|
|
4715
|
+
redirect: "error"
|
|
4716
|
+
});
|
|
4717
|
+
} catch (cause) {
|
|
4718
|
+
const aborted = cause instanceof Error && cause.name === "AbortError";
|
|
4719
|
+
throw new DomainError(
|
|
4720
|
+
aborted ? `MCP request timed out after ${options.timeoutMs}ms` : "MCP request failed",
|
|
4721
|
+
"upstream",
|
|
4722
|
+
aborted ? "Timeout" : "McpTransport",
|
|
4723
|
+
{ retryable: true, cause }
|
|
4724
|
+
);
|
|
4725
|
+
} finally {
|
|
4726
|
+
clearTimeout(timer);
|
|
4727
|
+
}
|
|
4728
|
+
const seen = response.headers.get("Mcp-Session-Id");
|
|
4729
|
+
if (seen) {
|
|
4730
|
+
sessionId = seen;
|
|
4731
|
+
}
|
|
4732
|
+
const body = await response.text();
|
|
4733
|
+
if (response.status === 401 || response.status === 403) {
|
|
4734
|
+
throw new DomainError(`MCP plugin rejected the tool key (HTTP ${response.status})`, "auth", "ToolKeyRejected", {
|
|
4735
|
+
hint: "The key in ADP_API_KEY, --api-key-env, or ~/.adp/tool-key was rejected. Create a new one with adp plugin key create.",
|
|
4736
|
+
retryable: false,
|
|
4737
|
+
nextActions: [
|
|
4738
|
+
{ command: "adp plugin key create --format json", reason: "issue a new tool key and save it" }
|
|
4739
|
+
]
|
|
4740
|
+
});
|
|
4741
|
+
}
|
|
4742
|
+
if (response.status >= 400) {
|
|
4743
|
+
throw new DomainError(
|
|
4744
|
+
`MCP request failed (HTTP ${response.status}): ${scrub(body, options.apiKey) || "(empty)"}`,
|
|
4745
|
+
"upstream",
|
|
4746
|
+
"McpTransport",
|
|
4747
|
+
{ retryable: response.status >= 500 }
|
|
4748
|
+
);
|
|
4749
|
+
}
|
|
4750
|
+
return { status: response.status, body };
|
|
4751
|
+
}
|
|
4752
|
+
function unwrap(raw) {
|
|
4753
|
+
if (!raw || typeof raw !== "object") {
|
|
4754
|
+
return raw;
|
|
4755
|
+
}
|
|
4756
|
+
const frame = raw;
|
|
4757
|
+
if (frame.error) {
|
|
4758
|
+
throw new DomainError(
|
|
4759
|
+
`MCP error: ${scrub(JSON.stringify(frame.error), options.apiKey)}`,
|
|
4760
|
+
"upstream",
|
|
4761
|
+
"McpServerError",
|
|
4762
|
+
{ retryable: false }
|
|
4763
|
+
);
|
|
4764
|
+
}
|
|
4765
|
+
return frame.result ?? raw;
|
|
4766
|
+
}
|
|
4767
|
+
async function sendRequest(method, params) {
|
|
4768
|
+
const id = nextId;
|
|
4769
|
+
nextId += 1;
|
|
4770
|
+
const { body } = await post({ jsonrpc: "2.0", id, method, params });
|
|
4771
|
+
if (!body.trim()) {
|
|
4772
|
+
throw new DomainError("MCP response was empty", "upstream", "McpProtocol", { retryable: true });
|
|
4773
|
+
}
|
|
4774
|
+
return unwrap(parseMcpBody(body));
|
|
4775
|
+
}
|
|
4776
|
+
return {
|
|
4777
|
+
async initialize() {
|
|
4778
|
+
await sendRequest("initialize", {
|
|
4779
|
+
protocolVersion: PROTOCOL_VERSION,
|
|
4780
|
+
capabilities: {},
|
|
4781
|
+
clientInfo: CLIENT_INFO
|
|
4782
|
+
});
|
|
4783
|
+
await post({ jsonrpc: "2.0", method: "notifications/initialized", params: {} });
|
|
4784
|
+
},
|
|
4785
|
+
sendRequest
|
|
4786
|
+
};
|
|
4787
|
+
}
|
|
4788
|
+
function parseMcpBody(body) {
|
|
4789
|
+
try {
|
|
4790
|
+
return JSON.parse(body);
|
|
4791
|
+
} catch {
|
|
4792
|
+
}
|
|
4793
|
+
let lastData = [];
|
|
4794
|
+
for (const chunk of body.split("\n\n")) {
|
|
4795
|
+
const dataLines = chunk.split(/\r?\n/).filter((line) => line.startsWith("data:")).map((line) => line.slice(5).trimStart());
|
|
4796
|
+
if (dataLines.length > 0) {
|
|
4797
|
+
lastData = dataLines;
|
|
4798
|
+
}
|
|
4799
|
+
}
|
|
4800
|
+
if (lastData.length === 0) {
|
|
4801
|
+
throw new DomainError("MCP response was neither JSON nor SSE", "upstream", "McpProtocol", { retryable: true });
|
|
4802
|
+
}
|
|
4803
|
+
try {
|
|
4804
|
+
return JSON.parse(lastData.join("\n").trim());
|
|
4805
|
+
} catch (cause) {
|
|
4806
|
+
throw new DomainError("MCP response frame is not valid JSON", "upstream", "McpProtocol", {
|
|
4807
|
+
retryable: true,
|
|
4808
|
+
cause
|
|
4809
|
+
});
|
|
4810
|
+
}
|
|
4811
|
+
}
|
|
4812
|
+
function unwrapToolPayload(result, secret = "") {
|
|
4813
|
+
if (!result || typeof result !== "object") {
|
|
4814
|
+
return result;
|
|
4815
|
+
}
|
|
4816
|
+
const payload = result;
|
|
4817
|
+
if (payload.isError) {
|
|
4818
|
+
const parts = [];
|
|
4819
|
+
if (Array.isArray(payload.content)) {
|
|
4820
|
+
for (const item of payload.content) {
|
|
4821
|
+
const text13 = item ?? {};
|
|
4822
|
+
if (text13.type === "text") {
|
|
4823
|
+
parts.push(String(text13.text ?? ""));
|
|
4824
|
+
}
|
|
4825
|
+
}
|
|
4826
|
+
}
|
|
4827
|
+
const message = scrub(parts.join("\n").trim(), secret);
|
|
4828
|
+
throw new DomainError(`MCP tool failed: ${message || "(no text)"}`, "upstream", "McpToolError", { retryable: false });
|
|
4829
|
+
}
|
|
4830
|
+
if (Array.isArray(payload.content)) {
|
|
4831
|
+
for (const item of payload.content) {
|
|
4832
|
+
const text13 = item ?? {};
|
|
4833
|
+
if (text13.type !== "text") {
|
|
4834
|
+
continue;
|
|
4835
|
+
}
|
|
4836
|
+
const raw = String(text13.text ?? "");
|
|
4837
|
+
try {
|
|
4838
|
+
return JSON.parse(raw);
|
|
4839
|
+
} catch {
|
|
4840
|
+
return raw;
|
|
4841
|
+
}
|
|
4842
|
+
}
|
|
4843
|
+
}
|
|
4844
|
+
return result;
|
|
4845
|
+
}
|
|
4846
|
+
function readTools(result) {
|
|
4847
|
+
const record = result && typeof result === "object" ? result : {};
|
|
4848
|
+
const tools = Array.isArray(record.tools) ? record.tools : [];
|
|
4849
|
+
return tools.flatMap((item) => {
|
|
4850
|
+
if (!item || typeof item !== "object") {
|
|
4851
|
+
return [];
|
|
4852
|
+
}
|
|
4853
|
+
const tool = item;
|
|
4854
|
+
if (typeof tool.name !== "string" || !tool.name) {
|
|
4855
|
+
return [];
|
|
4856
|
+
}
|
|
4857
|
+
const inputSchema = tool.inputSchema && typeof tool.inputSchema === "object" && !Array.isArray(tool.inputSchema) ? tool.inputSchema : void 0;
|
|
4858
|
+
return [
|
|
4859
|
+
{
|
|
4860
|
+
name: tool.name,
|
|
4861
|
+
...typeof tool.description === "string" ? { description: tool.description } : {},
|
|
4862
|
+
...inputSchema ? { inputSchema } : {}
|
|
4863
|
+
}
|
|
4864
|
+
];
|
|
4865
|
+
});
|
|
4866
|
+
}
|
|
4867
|
+
function scrub(text13, secret) {
|
|
4868
|
+
let out = text13;
|
|
4869
|
+
const trimmed = secret.trim();
|
|
4870
|
+
if (trimmed.length >= 4) {
|
|
4871
|
+
out = out.split(trimmed).join("[redacted]");
|
|
4872
|
+
}
|
|
4873
|
+
return out.replace(/Bearer\s+\S+/gi, "Bearer [redacted]").slice(0, ERROR_BODY_PREVIEW);
|
|
4874
|
+
}
|
|
4875
|
+
|
|
4876
|
+
// src/infrastructure/fs/tool-key-file-store.ts
|
|
4877
|
+
import { readFile as readFile2, rm as rm2 } from "fs/promises";
|
|
4878
|
+
import { homedir as homedir2 } from "os";
|
|
4879
|
+
import path3 from "path";
|
|
4880
|
+
|
|
4881
|
+
// src/infrastructure/fs/ini-credentials.ts
|
|
4882
|
+
function parseIni(text13) {
|
|
4883
|
+
const result = {};
|
|
4884
|
+
for (const rawLine of text13.split(/\r?\n/)) {
|
|
4885
|
+
const line = rawLine.trim();
|
|
4886
|
+
if (!line || line.startsWith("#") || line.startsWith(";") || line.startsWith("[")) {
|
|
4887
|
+
continue;
|
|
4888
|
+
}
|
|
4889
|
+
const eq = line.indexOf("=");
|
|
4890
|
+
if (eq < 0) {
|
|
4891
|
+
continue;
|
|
4892
|
+
}
|
|
4893
|
+
const key = line.slice(0, eq).trim().toLowerCase();
|
|
4894
|
+
const value = line.slice(eq + 1).trim();
|
|
4895
|
+
if (key) {
|
|
4896
|
+
result[key] = value;
|
|
4897
|
+
}
|
|
4898
|
+
}
|
|
4899
|
+
return result;
|
|
4900
|
+
}
|
|
4901
|
+
function renderIni(section, entries) {
|
|
4902
|
+
const body = entries.filter((entry) => entry[1] !== void 0 && entry[1] !== "").map(([key, value]) => `${key} = ${value}`);
|
|
4903
|
+
return [`[${section}]`, ...body, ""].join("\n");
|
|
4904
|
+
}
|
|
4905
|
+
|
|
4906
|
+
// src/infrastructure/fs/tool-key-file-store.ts
|
|
4907
|
+
function adpToolKeyPath(home = homedir2()) {
|
|
4908
|
+
return path3.join(home, ".adp", "tool-key");
|
|
4909
|
+
}
|
|
4910
|
+
function createToolKeyFileStore(filePath, privateFileOptions = {}) {
|
|
4911
|
+
return {
|
|
4912
|
+
async load() {
|
|
4913
|
+
try {
|
|
4914
|
+
const parsed = parseIni(await readFile2(filePath, "utf8"));
|
|
4915
|
+
const value = (parsed.tool_key ?? parsed.api_key ?? "").trim();
|
|
4916
|
+
if (!value) {
|
|
4917
|
+
return void 0;
|
|
4918
|
+
}
|
|
4919
|
+
const apiKeyId = (parsed.api_key_id ?? "").trim();
|
|
4920
|
+
return { value, ...apiKeyId ? { apiKeyId } : {} };
|
|
4921
|
+
} catch (error) {
|
|
4922
|
+
if (error.code === "ENOENT") {
|
|
4923
|
+
return void 0;
|
|
4924
|
+
}
|
|
4925
|
+
throw error;
|
|
4926
|
+
}
|
|
4927
|
+
},
|
|
4928
|
+
async save(input) {
|
|
4929
|
+
await writePrivateFile(
|
|
4930
|
+
filePath,
|
|
4931
|
+
renderIni("default", [
|
|
4932
|
+
["tool_key", input.value],
|
|
4933
|
+
["api_key_id", input.apiKeyId]
|
|
4934
|
+
]),
|
|
4935
|
+
privateFileOptions
|
|
4936
|
+
);
|
|
4937
|
+
},
|
|
4938
|
+
async clear() {
|
|
4939
|
+
await rm2(filePath, { force: true });
|
|
4940
|
+
}
|
|
4941
|
+
};
|
|
4942
|
+
}
|
|
4943
|
+
|
|
4543
4944
|
// src/infrastructure/tencent/skill-gateway.ts
|
|
4544
4945
|
var CREATE_TYPE_FILE_UPLOAD = 1;
|
|
4545
4946
|
function createSkillGateway(client) {
|
|
@@ -5060,7 +5461,7 @@ var DEFAULT_TIMEOUT_MS = 18e4;
|
|
|
5060
5461
|
function createSseChatGateway(client, options = {}) {
|
|
5061
5462
|
const chatUrl = options.chatUrl ?? DEFAULT_ADP_CHAT_SSE_URL;
|
|
5062
5463
|
const fetchImpl = options.fetchImpl ?? fetch;
|
|
5063
|
-
const
|
|
5464
|
+
const timeoutMs2 = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
5064
5465
|
return {
|
|
5065
5466
|
async createSession(input) {
|
|
5066
5467
|
if (input.conversationId && !isValidConversationId(input.conversationId)) {
|
|
@@ -5094,13 +5495,13 @@ function createSseChatGateway(client, options = {}) {
|
|
|
5094
5495
|
};
|
|
5095
5496
|
},
|
|
5096
5497
|
async sendMessage(session, input, onEvent) {
|
|
5097
|
-
await postSseChat(fetchImpl, chatUrl, session, input, onEvent,
|
|
5498
|
+
await postSseChat(fetchImpl, chatUrl, session, input, onEvent, timeoutMs2);
|
|
5098
5499
|
},
|
|
5099
5500
|
async close() {
|
|
5100
5501
|
}
|
|
5101
5502
|
};
|
|
5102
5503
|
}
|
|
5103
|
-
async function postSseChat(fetchImpl, chatUrl, session, input, onEvent,
|
|
5504
|
+
async function postSseChat(fetchImpl, chatUrl, session, input, onEvent, timeoutMs2) {
|
|
5104
5505
|
const body = buildChatRequest({
|
|
5105
5506
|
conversationId: session.conversationId,
|
|
5106
5507
|
appKey: session.appKey,
|
|
@@ -5110,7 +5511,7 @@ async function postSseChat(fetchImpl, chatUrl, session, input, onEvent, timeoutM
|
|
|
5110
5511
|
attachments: input.attachments
|
|
5111
5512
|
});
|
|
5112
5513
|
const controller = new AbortController();
|
|
5113
|
-
const timer = setTimeout(() => controller.abort(),
|
|
5514
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs2);
|
|
5114
5515
|
let response;
|
|
5115
5516
|
try {
|
|
5116
5517
|
response = await fetchImpl(chatUrl, {
|
|
@@ -5148,7 +5549,7 @@ async function postSseChat(fetchImpl, chatUrl, session, input, onEvent, timeoutM
|
|
|
5148
5549
|
await readSseStream(stream, onEvent, seen);
|
|
5149
5550
|
} catch (error) {
|
|
5150
5551
|
if (isAbortError(error)) {
|
|
5151
|
-
throw chatTimeoutError(
|
|
5552
|
+
throw chatTimeoutError(timeoutMs2, seen);
|
|
5152
5553
|
}
|
|
5153
5554
|
if (error instanceof DomainError) {
|
|
5154
5555
|
throw error;
|
|
@@ -5162,8 +5563,8 @@ async function postSseChat(fetchImpl, chatUrl, session, input, onEvent, timeoutM
|
|
|
5162
5563
|
}
|
|
5163
5564
|
}
|
|
5164
5565
|
var MISSING_TOOL = /(mcp__[\w.-]*?(\w+)) not found/;
|
|
5165
|
-
function chatTimeoutError(
|
|
5166
|
-
const seconds2 = Math.round(
|
|
5566
|
+
function chatTimeoutError(timeoutMs2, seen) {
|
|
5567
|
+
const seconds2 = Math.round(timeoutMs2 / 1e3);
|
|
5167
5568
|
if (seen.missingTool) {
|
|
5168
5569
|
return new DomainError(
|
|
5169
5570
|
`Chat timed out after ${seconds2}s; the agent's tool ${seen.missingTool} was not found by the runtime`,
|
|
@@ -5573,12 +5974,12 @@ function toTask2(raw) {
|
|
|
5573
5974
|
}
|
|
5574
5975
|
function toMcpApp(raw) {
|
|
5575
5976
|
const mcp = {};
|
|
5576
|
-
const
|
|
5977
|
+
const pluginId3 = optionalString8(raw.PluginId);
|
|
5577
5978
|
const resourceUri = optionalString8(raw.ResourceUri);
|
|
5578
5979
|
const threadId = optionalString8(raw.ThreadId);
|
|
5579
5980
|
const toolResult = optionalString8(raw.ToolResult);
|
|
5580
|
-
if (
|
|
5581
|
-
mcp.pluginId =
|
|
5981
|
+
if (pluginId3) {
|
|
5982
|
+
mcp.pluginId = pluginId3;
|
|
5582
5983
|
}
|
|
5583
5984
|
if (resourceUri) {
|
|
5584
5985
|
mcp.resourceUri = resourceUri;
|
|
@@ -6705,8 +7106,8 @@ function hmacSha1Hex(key, value) {
|
|
|
6705
7106
|
}
|
|
6706
7107
|
|
|
6707
7108
|
// src/infrastructure/fs/local-document-reader.ts
|
|
6708
|
-
import { readFile as
|
|
6709
|
-
import
|
|
7109
|
+
import { readFile as readFile3 } from "fs/promises";
|
|
7110
|
+
import path4 from "path";
|
|
6710
7111
|
|
|
6711
7112
|
// src/domain/knowledge/doc.ts
|
|
6712
7113
|
var DOC_ENABLE_SCOPE_BOTH = 4;
|
|
@@ -6769,7 +7170,7 @@ function createFsLocalDocumentReader() {
|
|
|
6769
7170
|
async read(absolutePath) {
|
|
6770
7171
|
let bytes;
|
|
6771
7172
|
try {
|
|
6772
|
-
bytes = await
|
|
7173
|
+
bytes = await readFile3(absolutePath);
|
|
6773
7174
|
} catch (error) {
|
|
6774
7175
|
const code = error.code;
|
|
6775
7176
|
throw usageError(
|
|
@@ -6777,7 +7178,7 @@ function createFsLocalDocumentReader() {
|
|
|
6777
7178
|
code === "ENOENT" ? "Check --file points at an existing document" : "Check file permissions"
|
|
6778
7179
|
);
|
|
6779
7180
|
}
|
|
6780
|
-
const fileName =
|
|
7181
|
+
const fileName = path4.basename(absolutePath);
|
|
6781
7182
|
return {
|
|
6782
7183
|
fileName,
|
|
6783
7184
|
fileType: fileTypeFromName(fileName),
|
|
@@ -6788,38 +7189,11 @@ function createFsLocalDocumentReader() {
|
|
|
6788
7189
|
}
|
|
6789
7190
|
|
|
6790
7191
|
// src/infrastructure/fs/credential-file-store.ts
|
|
6791
|
-
import { homedir as
|
|
6792
|
-
import {
|
|
6793
|
-
import
|
|
6794
|
-
|
|
6795
|
-
|
|
6796
|
-
function parseIni(text13) {
|
|
6797
|
-
const result = {};
|
|
6798
|
-
for (const rawLine of text13.split(/\r?\n/)) {
|
|
6799
|
-
const line = rawLine.trim();
|
|
6800
|
-
if (!line || line.startsWith("#") || line.startsWith(";") || line.startsWith("[")) {
|
|
6801
|
-
continue;
|
|
6802
|
-
}
|
|
6803
|
-
const eq = line.indexOf("=");
|
|
6804
|
-
if (eq < 0) {
|
|
6805
|
-
continue;
|
|
6806
|
-
}
|
|
6807
|
-
const key = line.slice(0, eq).trim().toLowerCase();
|
|
6808
|
-
const value = line.slice(eq + 1).trim();
|
|
6809
|
-
if (key) {
|
|
6810
|
-
result[key] = value;
|
|
6811
|
-
}
|
|
6812
|
-
}
|
|
6813
|
-
return result;
|
|
6814
|
-
}
|
|
6815
|
-
function renderIni(section, entries) {
|
|
6816
|
-
const body = entries.filter((entry) => entry[1] !== void 0 && entry[1] !== "").map(([key, value]) => `${key} = ${value}`);
|
|
6817
|
-
return [`[${section}]`, ...body, ""].join("\n");
|
|
6818
|
-
}
|
|
6819
|
-
|
|
6820
|
-
// src/infrastructure/fs/credential-file-store.ts
|
|
6821
|
-
function tencentCloudCredentialsPath(home = homedir2()) {
|
|
6822
|
-
return path3.join(home, ".tencentcloud", "credentials");
|
|
7192
|
+
import { homedir as homedir3 } from "os";
|
|
7193
|
+
import { readFile as readFile4, rm as rm3 } from "fs/promises";
|
|
7194
|
+
import path5 from "path";
|
|
7195
|
+
function tencentCloudCredentialsPath(home = homedir3()) {
|
|
7196
|
+
return path5.join(home, ".tencentcloud", "credentials");
|
|
6823
7197
|
}
|
|
6824
7198
|
function createEnvCredentialReader(env = process.env) {
|
|
6825
7199
|
return {
|
|
@@ -6833,11 +7207,11 @@ function createEnvCredentialReader(env = process.env) {
|
|
|
6833
7207
|
}
|
|
6834
7208
|
};
|
|
6835
7209
|
}
|
|
6836
|
-
function createCredentialFileStore(filePath, source2) {
|
|
7210
|
+
function createCredentialFileStore(filePath, source2, privateFileOptions = {}) {
|
|
6837
7211
|
return {
|
|
6838
7212
|
async load() {
|
|
6839
7213
|
try {
|
|
6840
|
-
const text13 = await
|
|
7214
|
+
const text13 = await readFile4(filePath, "utf8");
|
|
6841
7215
|
const parsed = parseIni(text13);
|
|
6842
7216
|
const secretId = parsed.secret_id ?? parsed.secretid;
|
|
6843
7217
|
const secretKey = parsed.secret_key ?? parsed.secretkey;
|
|
@@ -6853,26 +7227,30 @@ function createCredentialFileStore(filePath, source2) {
|
|
|
6853
7227
|
}
|
|
6854
7228
|
},
|
|
6855
7229
|
async save(input) {
|
|
6856
|
-
await mkdir2(path3.dirname(filePath), { recursive: true });
|
|
6857
7230
|
const body = renderIni("default", [
|
|
6858
7231
|
["secret_id", input.secretId],
|
|
6859
7232
|
["secret_key", input.secretKey],
|
|
6860
7233
|
["token", input.token]
|
|
6861
7234
|
]);
|
|
6862
|
-
await
|
|
6863
|
-
await chmod2(filePath, 384);
|
|
7235
|
+
await writePrivateFile(filePath, body, privateFileOptions);
|
|
6864
7236
|
},
|
|
6865
7237
|
async clear() {
|
|
6866
|
-
await
|
|
7238
|
+
await rm3(filePath, { force: true });
|
|
6867
7239
|
}
|
|
6868
7240
|
};
|
|
6869
7241
|
}
|
|
6870
7242
|
|
|
6871
7243
|
// src/infrastructure/fs/jsonc-config-store.ts
|
|
6872
|
-
import { mkdir as
|
|
6873
|
-
import
|
|
7244
|
+
import { mkdir as mkdir2, readFile as readFile5, writeFile as writeFile2 } from "fs/promises";
|
|
7245
|
+
import path7 from "path";
|
|
6874
7246
|
import { parse as parseJsonc } from "jsonc-parser";
|
|
6875
7247
|
|
|
7248
|
+
// src/infrastructure/fs/local-path.ts
|
|
7249
|
+
import path6 from "path";
|
|
7250
|
+
function canonicalizeLocalPath(input, cwd, paths = path6) {
|
|
7251
|
+
return paths.resolve(cwd, assertLocalPath(input));
|
|
7252
|
+
}
|
|
7253
|
+
|
|
6876
7254
|
// src/domain/project-config/env-overlay.ts
|
|
6877
7255
|
function mergeEnvOverlay(base, overlay) {
|
|
6878
7256
|
return {
|
|
@@ -7263,27 +7641,27 @@ function createJsoncConfigStore() {
|
|
|
7263
7641
|
return {
|
|
7264
7642
|
async load(options) {
|
|
7265
7643
|
const cwd = options.cwd;
|
|
7266
|
-
const configPath =
|
|
7644
|
+
const configPath = canonicalizeLocalPath(options.configPath ?? "adp.jsonc", cwd);
|
|
7267
7645
|
const { config: base, warnings } = await readConfigFile(configPath);
|
|
7268
7646
|
const extra = warnings.length > 0 ? { warnings } : {};
|
|
7269
7647
|
if (!options.envName) {
|
|
7270
7648
|
return { config: base, configPath, ...extra };
|
|
7271
7649
|
}
|
|
7272
|
-
const overlayPath =
|
|
7650
|
+
const overlayPath = canonicalizeLocalPath(`adp.env.${options.envName}.jsonc`, cwd);
|
|
7273
7651
|
const overlay = await readOptionalConfig(overlayPath);
|
|
7274
7652
|
return { config: overlay ? mergeEnvOverlay(base, overlay) : base, configPath, ...extra };
|
|
7275
7653
|
},
|
|
7276
7654
|
async write(configPath, config2) {
|
|
7277
|
-
await
|
|
7655
|
+
await mkdir2(path7.dirname(configPath), { recursive: true });
|
|
7278
7656
|
const body = `${JSON.stringify(adpConfigToFile(config2), null, 2)}
|
|
7279
7657
|
`;
|
|
7280
|
-
await
|
|
7658
|
+
await writeFile2(configPath, body, "utf8");
|
|
7281
7659
|
},
|
|
7282
7660
|
async writeSidecar(cwd, relativePath, contents, options) {
|
|
7283
7661
|
const resolved2 = canonicalizeLocalPath(relativePath, cwd);
|
|
7284
|
-
await
|
|
7662
|
+
await mkdir2(path7.dirname(resolved2), { recursive: true });
|
|
7285
7663
|
try {
|
|
7286
|
-
await
|
|
7664
|
+
await writeFile2(resolved2, contents, { encoding: "utf8", flag: options?.overwrite === false ? "wx" : "w" });
|
|
7287
7665
|
} catch (error) {
|
|
7288
7666
|
if (error.code === "EEXIST") {
|
|
7289
7667
|
return false;
|
|
@@ -7295,7 +7673,7 @@ function createJsoncConfigStore() {
|
|
|
7295
7673
|
async readInstructions(cwd, relativePath) {
|
|
7296
7674
|
const resolved2 = canonicalizeLocalPath(relativePath, cwd);
|
|
7297
7675
|
try {
|
|
7298
|
-
return await
|
|
7676
|
+
return await readFile5(resolved2, "utf8");
|
|
7299
7677
|
} catch {
|
|
7300
7678
|
throw new DomainError(`instructions file not found: ${relativePath} (resolved to ${resolved2})`, "usage", "InstructionsFileMissing", {
|
|
7301
7679
|
hint: `Create ${resolved2} with the agent's system prompt, or replace agent.instructions_file with inline agent.instructions in adp.jsonc`,
|
|
@@ -7322,7 +7700,7 @@ function unknownConfigFields(parsed) {
|
|
|
7322
7700
|
async function readConfigFile(configPath) {
|
|
7323
7701
|
let text13;
|
|
7324
7702
|
try {
|
|
7325
|
-
text13 = await
|
|
7703
|
+
text13 = await readFile5(configPath, "utf8");
|
|
7326
7704
|
} catch {
|
|
7327
7705
|
throw new DomainError(`Config not found: ${configPath}`, "usage", "UsageError", {
|
|
7328
7706
|
hint: "Run: adp init or pass --config path/to/adp.jsonc",
|
|
@@ -7356,7 +7734,7 @@ async function readConfigFile(configPath) {
|
|
|
7356
7734
|
async function readOptionalConfig(configPath) {
|
|
7357
7735
|
let text13;
|
|
7358
7736
|
try {
|
|
7359
|
-
text13 = await
|
|
7737
|
+
text13 = await readFile5(configPath, "utf8");
|
|
7360
7738
|
} catch (error) {
|
|
7361
7739
|
if (error.code === "ENOENT") {
|
|
7362
7740
|
return void 0;
|
|
@@ -7375,8 +7753,8 @@ async function readOptionalConfig(configPath) {
|
|
|
7375
7753
|
}
|
|
7376
7754
|
|
|
7377
7755
|
// src/infrastructure/fs/companion-skill-pack.ts
|
|
7378
|
-
import { cp, readFile as
|
|
7379
|
-
import
|
|
7756
|
+
import { cp, readFile as readFile6, stat } from "fs/promises";
|
|
7757
|
+
import path9 from "path";
|
|
7380
7758
|
import { existsSync as existsSync2 } from "fs";
|
|
7381
7759
|
|
|
7382
7760
|
// src/domain/companion-skills/companion-skill.ts
|
|
@@ -7412,13 +7790,13 @@ function parseAgentKinds(value) {
|
|
|
7412
7790
|
|
|
7413
7791
|
// src/infrastructure/fs/package-root.ts
|
|
7414
7792
|
import { existsSync, readFileSync } from "fs";
|
|
7415
|
-
import
|
|
7793
|
+
import path8 from "path";
|
|
7416
7794
|
import { fileURLToPath } from "url";
|
|
7417
7795
|
var CLI_PACKAGE_NAME = "@tencentcloudadp/cli";
|
|
7418
|
-
function resolvePackageRoot(startDir =
|
|
7796
|
+
function resolvePackageRoot(startDir = path8.dirname(fileURLToPath(import.meta.url))) {
|
|
7419
7797
|
let dir = startDir;
|
|
7420
7798
|
for (let i = 0; i < 10; i += 1) {
|
|
7421
|
-
const pkgPath =
|
|
7799
|
+
const pkgPath = path8.join(dir, "package.json");
|
|
7422
7800
|
if (existsSync(pkgPath)) {
|
|
7423
7801
|
try {
|
|
7424
7802
|
const pkg = JSON.parse(readFileSync(pkgPath, "utf8"));
|
|
@@ -7428,7 +7806,7 @@ function resolvePackageRoot(startDir = path5.dirname(fileURLToPath(import.meta.u
|
|
|
7428
7806
|
} catch {
|
|
7429
7807
|
}
|
|
7430
7808
|
}
|
|
7431
|
-
const parent =
|
|
7809
|
+
const parent = path8.dirname(dir);
|
|
7432
7810
|
if (parent === dir) {
|
|
7433
7811
|
break;
|
|
7434
7812
|
}
|
|
@@ -7439,9 +7817,9 @@ function resolvePackageRoot(startDir = path5.dirname(fileURLToPath(import.meta.u
|
|
|
7439
7817
|
"Run adp from the installed npm package or the adp-cli repository"
|
|
7440
7818
|
);
|
|
7441
7819
|
}
|
|
7442
|
-
function readCliPackageIdentity(startDir =
|
|
7820
|
+
function readCliPackageIdentity(startDir = path8.dirname(fileURLToPath(import.meta.url))) {
|
|
7443
7821
|
const root = resolvePackageRoot(startDir);
|
|
7444
|
-
const pkgPath =
|
|
7822
|
+
const pkgPath = path8.join(root, "package.json");
|
|
7445
7823
|
const pkg = JSON.parse(readFileSync(pkgPath, "utf8"));
|
|
7446
7824
|
if (typeof pkg.version !== "string" || pkg.version.trim().length === 0) {
|
|
7447
7825
|
throw usageError(
|
|
@@ -7455,12 +7833,12 @@ function readCliPackageIdentity(startDir = path5.dirname(fileURLToPath(import.me
|
|
|
7455
7833
|
// src/infrastructure/fs/companion-skill-pack.ts
|
|
7456
7834
|
function createFsCompanionSkillPack(options = {}) {
|
|
7457
7835
|
const packageRoot = options.packageRoot ?? resolvePackageRoot();
|
|
7458
|
-
const skillsRoot =
|
|
7836
|
+
const skillsRoot = path9.join(packageRoot, "skills");
|
|
7459
7837
|
return {
|
|
7460
7838
|
async listSkillIds() {
|
|
7461
7839
|
const ids4 = [];
|
|
7462
7840
|
for (const name of COMPANION_SKILL_IDS) {
|
|
7463
|
-
if (existsSync2(
|
|
7841
|
+
if (existsSync2(path9.join(skillsRoot, name, "SKILL.md"))) {
|
|
7464
7842
|
ids4.push(name);
|
|
7465
7843
|
}
|
|
7466
7844
|
}
|
|
@@ -7473,18 +7851,18 @@ function createFsCompanionSkillPack(options = {}) {
|
|
|
7473
7851
|
return ids4;
|
|
7474
7852
|
},
|
|
7475
7853
|
async skillSourceDir(skillId) {
|
|
7476
|
-
const dir =
|
|
7477
|
-
const skillFile =
|
|
7854
|
+
const dir = path9.join(skillsRoot, skillId);
|
|
7855
|
+
const skillFile = path9.join(dir, "SKILL.md");
|
|
7478
7856
|
if (!existsSync2(skillFile)) {
|
|
7479
7857
|
throw usageError(`Companion skill not found: ${skillId}`, `Looked for ${skillFile}`);
|
|
7480
7858
|
}
|
|
7481
7859
|
return dir;
|
|
7482
7860
|
},
|
|
7483
7861
|
async readDescription(sourceDir) {
|
|
7484
|
-
const file =
|
|
7862
|
+
const file = path9.join(sourceDir, "SKILL.md");
|
|
7485
7863
|
let raw;
|
|
7486
7864
|
try {
|
|
7487
|
-
raw = await
|
|
7865
|
+
raw = await readFile6(file, "utf8");
|
|
7488
7866
|
} catch {
|
|
7489
7867
|
return "";
|
|
7490
7868
|
}
|
|
@@ -7499,11 +7877,11 @@ function createFsCompanionSkillPack(options = {}) {
|
|
|
7499
7877
|
}
|
|
7500
7878
|
},
|
|
7501
7879
|
joinPath(...parts) {
|
|
7502
|
-
return
|
|
7880
|
+
return path9.join(...parts);
|
|
7503
7881
|
},
|
|
7504
7882
|
async copySkill(sourceDir, destDir, dryRun) {
|
|
7505
|
-
const skillId =
|
|
7506
|
-
if (
|
|
7883
|
+
const skillId = path9.basename(sourceDir);
|
|
7884
|
+
if (path9.resolve(sourceDir) === path9.resolve(destDir)) {
|
|
7507
7885
|
return { skillId, destDir, copied: false };
|
|
7508
7886
|
}
|
|
7509
7887
|
if (dryRun) {
|
|
@@ -7534,12 +7912,12 @@ function parseFrontmatterDescription(raw) {
|
|
|
7534
7912
|
|
|
7535
7913
|
// src/infrastructure/fs/config-schema-locator.ts
|
|
7536
7914
|
import { existsSync as existsSync3 } from "fs";
|
|
7537
|
-
import
|
|
7915
|
+
import path10 from "path";
|
|
7538
7916
|
function createFsConfigSchemaLocator(options = {}) {
|
|
7539
7917
|
return {
|
|
7540
7918
|
async resolvePath() {
|
|
7541
7919
|
const root = options.packageRoot ?? resolvePackageRoot();
|
|
7542
|
-
const schemaPath =
|
|
7920
|
+
const schemaPath = path10.join(root, "config-schema.json");
|
|
7543
7921
|
if (!existsSync3(schemaPath)) {
|
|
7544
7922
|
throw usageError(
|
|
7545
7923
|
`config-schema.json not found at ${schemaPath}`,
|
|
@@ -7559,7 +7937,7 @@ var NETWORK_HINT = `Check network access to ${NPM_REGISTRY_ORIGIN}`;
|
|
|
7559
7937
|
function createNpmRegistryGateway(options = {}) {
|
|
7560
7938
|
const origin = options.origin?.trim() || NPM_REGISTRY_ORIGIN;
|
|
7561
7939
|
const fetchImpl = options.fetchImpl ?? fetch;
|
|
7562
|
-
const
|
|
7940
|
+
const timeoutMs2 = options.timeoutMs ?? DEFAULT_TIMEOUT_MS2;
|
|
7563
7941
|
return {
|
|
7564
7942
|
async getRelease(request) {
|
|
7565
7943
|
const packageName = request.packageName.trim();
|
|
@@ -7573,7 +7951,7 @@ function createNpmRegistryGateway(options = {}) {
|
|
|
7573
7951
|
response = await fetchImpl(url, {
|
|
7574
7952
|
method: "GET",
|
|
7575
7953
|
headers: { accept: "application/json", "user-agent": NPM_USER_AGENT },
|
|
7576
|
-
signal: AbortSignal.timeout(
|
|
7954
|
+
signal: AbortSignal.timeout(timeoutMs2)
|
|
7577
7955
|
});
|
|
7578
7956
|
} catch (error) {
|
|
7579
7957
|
throw registryError(
|
|
@@ -7625,12 +8003,83 @@ function trimTrailingSlash(origin) {
|
|
|
7625
8003
|
|
|
7626
8004
|
// src/infrastructure/child-process/spawn-command-runner.ts
|
|
7627
8005
|
import { spawn as spawn2 } from "child_process";
|
|
7628
|
-
|
|
7629
|
-
|
|
7630
|
-
|
|
7631
|
-
|
|
7632
|
-
|
|
7633
|
-
|
|
8006
|
+
|
|
8007
|
+
// src/infrastructure/child-process/windows-command.ts
|
|
8008
|
+
import { statSync } from "fs";
|
|
8009
|
+
import { win32 as win322 } from "path";
|
|
8010
|
+
function isFile(path18) {
|
|
8011
|
+
try {
|
|
8012
|
+
return statSync(path18).isFile();
|
|
8013
|
+
} catch {
|
|
8014
|
+
return false;
|
|
8015
|
+
}
|
|
8016
|
+
}
|
|
8017
|
+
function envValue(env, name) {
|
|
8018
|
+
const key = Object.keys(env).find((key2) => key2.toLowerCase() === name.toLowerCase());
|
|
8019
|
+
return key === void 0 ? void 0 : env[key];
|
|
8020
|
+
}
|
|
8021
|
+
function windowsCommand(command, args, options = {}) {
|
|
8022
|
+
const env = options.env ?? process.env;
|
|
8023
|
+
const fileExists = options.isFile ?? isFile;
|
|
8024
|
+
const cwd = options.cwd ?? process.cwd();
|
|
8025
|
+
const extensions = [".exe", ".com", ".cmd", ".bat"];
|
|
8026
|
+
const configured = (envValue(env, "PATHEXT") ?? ".COM;.EXE;.BAT;.CMD").split(";").map((ext) => ext.toLowerCase()).filter((ext) => extensions.includes(ext));
|
|
8027
|
+
const suffixes = win322.extname(command) ? [""] : configured;
|
|
8028
|
+
const dirs = /[\\/]/.test(command) ? [""] : [cwd, ...(envValue(env, "PATH") ?? "").split(";")];
|
|
8029
|
+
let resolved2;
|
|
8030
|
+
for (const dir of dirs) {
|
|
8031
|
+
for (const suffix of suffixes) {
|
|
8032
|
+
const candidate = win322.resolve(cwd, dir.replace(/^"|"$/g, ""), command + suffix);
|
|
8033
|
+
if (fileExists(candidate)) {
|
|
8034
|
+
resolved2 = candidate;
|
|
8035
|
+
break;
|
|
8036
|
+
}
|
|
8037
|
+
}
|
|
8038
|
+
if (resolved2) break;
|
|
8039
|
+
}
|
|
8040
|
+
const executable = resolved2 ?? command;
|
|
8041
|
+
if (!/\.(cmd|bat)$/i.test(executable)) {
|
|
8042
|
+
return { command: executable, args: [...args], windowsVerbatimArguments: false };
|
|
8043
|
+
}
|
|
8044
|
+
const manager = win322.basename(executable).replace(/\.(cmd|bat)$/i, "").toLowerCase();
|
|
8045
|
+
if (resolved2 && ["npm", "pnpm", "yarn"].includes(manager)) {
|
|
8046
|
+
const root = win322.dirname(executable);
|
|
8047
|
+
const entries = manager === "npm" ? ["node_modules/npm/bin/npm-cli.js"] : manager === "pnpm" ? ["node_modules/pnpm/bin/pnpm.cjs", "node_modules/pnpm/bin/pnpm.js"] : ["node_modules/yarn/bin/yarn.js"];
|
|
8048
|
+
entries.push(`node_modules/corepack/dist/${manager}.js`);
|
|
8049
|
+
const entry = entries.map((path18) => win322.join(root, path18)).find(fileExists);
|
|
8050
|
+
if (entry) {
|
|
8051
|
+
return { command: options.execPath ?? process.execPath, args: [entry, ...args], windowsVerbatimArguments: false };
|
|
8052
|
+
}
|
|
8053
|
+
}
|
|
8054
|
+
const quote = (value) => {
|
|
8055
|
+
if ([...value].some((char) => char.charCodeAt(0) < 32) || /["%!?^&|<>()]/.test(value) || value.endsWith("\\")) {
|
|
8056
|
+
throw new Error("Unsupported character in Windows batch command; use a Node.js entry or executable instead");
|
|
8057
|
+
}
|
|
8058
|
+
return `"${value}"`;
|
|
8059
|
+
};
|
|
8060
|
+
const line = `"${[executable, ...args].map(quote).join(" ")}"`;
|
|
8061
|
+
if (line.length > 8e3) throw new Error("Windows batch command is too long");
|
|
8062
|
+
if (!resolved2) throw Object.assign(new Error(`Executable not found: ${command}`), { code: "ENOENT" });
|
|
8063
|
+
return {
|
|
8064
|
+
command: win322.join(envValue(env, "SystemRoot") ?? "C:\\Windows", "System32", "cmd.exe"),
|
|
8065
|
+
args: ["/d", "/s", "/v:off", "/c", line],
|
|
8066
|
+
windowsVerbatimArguments: true
|
|
8067
|
+
};
|
|
8068
|
+
}
|
|
8069
|
+
|
|
8070
|
+
// src/infrastructure/child-process/spawn-command-runner.ts
|
|
8071
|
+
function createSpawnCommandRunner(options = {}) {
|
|
8072
|
+
const stdio = options.stdio ?? "inherit";
|
|
8073
|
+
return (request) => new Promise((resolve, reject) => {
|
|
8074
|
+
const invocation = (options.platform ?? process.platform) === "win32" ? windowsCommand(request.command, request.args, options.windows) : { command: request.command, args: request.args, windowsVerbatimArguments: false };
|
|
8075
|
+
const child = (options.spawnImpl ?? spawn2)(invocation.command, invocation.args, {
|
|
8076
|
+
stdio,
|
|
8077
|
+
shell: false,
|
|
8078
|
+
windowsVerbatimArguments: invocation.windowsVerbatimArguments,
|
|
8079
|
+
...options.windows?.env ? { env: options.windows.env } : {}
|
|
8080
|
+
});
|
|
8081
|
+
child.on("error", reject);
|
|
8082
|
+
child.on("close", (code, signal) => {
|
|
7634
8083
|
if (code === null) {
|
|
7635
8084
|
reject(new Error(`${request.command} exited via signal ${signal ?? "unknown"}`));
|
|
7636
8085
|
return;
|
|
@@ -7641,17 +8090,17 @@ function createSpawnCommandRunner(options = {}) {
|
|
|
7641
8090
|
}
|
|
7642
8091
|
|
|
7643
8092
|
// src/infrastructure/fs/update-check-store.ts
|
|
7644
|
-
import { homedir as
|
|
7645
|
-
import {
|
|
7646
|
-
import
|
|
7647
|
-
function adpUpdateCheckPath(home =
|
|
7648
|
-
return
|
|
8093
|
+
import { homedir as homedir4 } from "os";
|
|
8094
|
+
import { readFile as readFile7 } from "fs/promises";
|
|
8095
|
+
import path11 from "path";
|
|
8096
|
+
function adpUpdateCheckPath(home = homedir4()) {
|
|
8097
|
+
return path11.join(home, ".adp", "update-check.json");
|
|
7649
8098
|
}
|
|
7650
|
-
function createUpdateCheckStore(filePath = adpUpdateCheckPath()) {
|
|
8099
|
+
function createUpdateCheckStore(filePath = adpUpdateCheckPath(), privateFileOptions = {}) {
|
|
7651
8100
|
return {
|
|
7652
8101
|
async load() {
|
|
7653
8102
|
try {
|
|
7654
|
-
const record = JSON.parse(await
|
|
8103
|
+
const record = JSON.parse(await readFile7(filePath, "utf8"));
|
|
7655
8104
|
if (typeof record?.latestVersion !== "string" || record.latestVersion.length === 0) {
|
|
7656
8105
|
return void 0;
|
|
7657
8106
|
}
|
|
@@ -7672,23 +8121,16 @@ function createUpdateCheckStore(filePath = adpUpdateCheckPath()) {
|
|
|
7672
8121
|
}
|
|
7673
8122
|
},
|
|
7674
8123
|
async save(record) {
|
|
7675
|
-
|
|
7676
|
-
|
|
7677
|
-
await writeFile4(filePath, `${JSON.stringify(record, null, 2)}
|
|
7678
|
-
`, {
|
|
7679
|
-
encoding: "utf8",
|
|
7680
|
-
mode: 384
|
|
7681
|
-
});
|
|
7682
|
-
} catch {
|
|
7683
|
-
}
|
|
8124
|
+
await writePrivateFile(filePath, `${JSON.stringify(record, null, 2)}
|
|
8125
|
+
`, privateFileOptions);
|
|
7684
8126
|
}
|
|
7685
8127
|
};
|
|
7686
8128
|
}
|
|
7687
8129
|
|
|
7688
8130
|
// src/infrastructure/fs/install-source-probe.ts
|
|
7689
|
-
import { homedir as
|
|
7690
|
-
import { readFile as
|
|
7691
|
-
import
|
|
8131
|
+
import { homedir as homedir5 } from "os";
|
|
8132
|
+
import { readFile as readFile8, realpath, writeFile as writeFile3 } from "fs/promises";
|
|
8133
|
+
import path12 from "path";
|
|
7692
8134
|
|
|
7693
8135
|
// src/domain/update/install-source.ts
|
|
7694
8136
|
var INSTALL_SOURCES = ["npm", "workbuddy"];
|
|
@@ -7724,7 +8166,7 @@ function createInstallSourceProbe(options) {
|
|
|
7724
8166
|
return fromEnv;
|
|
7725
8167
|
}
|
|
7726
8168
|
const resolved2 = await realpath(root).catch(() => root);
|
|
7727
|
-
const prefix = workbuddyConnectorPrefix(options.env, options.homeDir ??
|
|
8169
|
+
const prefix = workbuddyConnectorPrefix(options.env, options.homeDir ?? homedir5());
|
|
7728
8170
|
const resolvedPrefix = await realpath(prefix).catch(() => prefix);
|
|
7729
8171
|
return isWithin(resolved2, resolvedPrefix, platform) ? "workbuddy" : "npm";
|
|
7730
8172
|
} catch {
|
|
@@ -7732,8 +8174,8 @@ function createInstallSourceProbe(options) {
|
|
|
7732
8174
|
}
|
|
7733
8175
|
},
|
|
7734
8176
|
async mark(source2) {
|
|
7735
|
-
const filePath =
|
|
7736
|
-
await
|
|
8177
|
+
const filePath = path12.join(packageRoot(), INSTALL_SOURCE_MARKER);
|
|
8178
|
+
await writeFile3(
|
|
7737
8179
|
filePath,
|
|
7738
8180
|
`${JSON.stringify({ source: source2, markedAt: (/* @__PURE__ */ new Date()).toISOString() }, null, 2)}
|
|
7739
8181
|
`,
|
|
@@ -7745,23 +8187,23 @@ function createInstallSourceProbe(options) {
|
|
|
7745
8187
|
}
|
|
7746
8188
|
async function readMarker(root) {
|
|
7747
8189
|
try {
|
|
7748
|
-
const parsed = JSON.parse(await
|
|
8190
|
+
const parsed = JSON.parse(await readFile8(path12.join(root, INSTALL_SOURCE_MARKER), "utf8"));
|
|
7749
8191
|
return isInstallSource(parsed.source) ? parsed.source : void 0;
|
|
7750
8192
|
} catch {
|
|
7751
8193
|
return void 0;
|
|
7752
8194
|
}
|
|
7753
8195
|
}
|
|
7754
8196
|
function workbuddyConnectorPrefix(env, homeDir) {
|
|
7755
|
-
const configDir = env.WORKBUDDY_CONFIG_DIR?.trim() || env.CODEBUDDY_CONFIG_DIR?.trim() ||
|
|
7756
|
-
return
|
|
8197
|
+
const configDir = env.WORKBUDDY_CONFIG_DIR?.trim() || env.CODEBUDDY_CONFIG_DIR?.trim() || path12.join(homeDir, ".workbuddy");
|
|
8198
|
+
return path12.join(configDir, "binaries", "node", "cli-connector-packages");
|
|
7757
8199
|
}
|
|
7758
8200
|
function isWithin(target, prefix, platform) {
|
|
7759
8201
|
const normalize = (value) => {
|
|
7760
|
-
const resolved2 =
|
|
8202
|
+
const resolved2 = path12.resolve(value);
|
|
7761
8203
|
return platform === "win32" ? resolved2.toLowerCase() : resolved2;
|
|
7762
8204
|
};
|
|
7763
|
-
const relative =
|
|
7764
|
-
return relative.length > 0 && !relative.startsWith("..") && !
|
|
8205
|
+
const relative = path12.relative(normalize(prefix), normalize(target));
|
|
8206
|
+
return relative.length > 0 && !relative.startsWith("..") && !path12.isAbsolute(relative);
|
|
7765
8207
|
}
|
|
7766
8208
|
|
|
7767
8209
|
// src/infrastructure/tencent/workflow-gateway.ts
|
|
@@ -8274,10 +8716,10 @@ function createMemoryGateway(clients) {
|
|
|
8274
8716
|
];
|
|
8275
8717
|
const patch = {};
|
|
8276
8718
|
const paths = [];
|
|
8277
|
-
for (const [key, field,
|
|
8719
|
+
for (const [key, field, path18] of fields) {
|
|
8278
8720
|
if (input.patch[key] !== void 0 && (rich || key === "type" || key === "content")) {
|
|
8279
8721
|
patch[field] = input.patch[key];
|
|
8280
|
-
paths.push(`entry_patch.${branch}.${
|
|
8722
|
+
paths.push(`entry_patch.${branch}.${path18}`);
|
|
8281
8723
|
}
|
|
8282
8724
|
}
|
|
8283
8725
|
await request("ModifyMemoryEntry", {
|
|
@@ -9499,8 +9941,8 @@ function createKbShareGateway(client) {
|
|
|
9499
9941
|
}
|
|
9500
9942
|
|
|
9501
9943
|
// src/infrastructure/tencent/volume-gateway.ts
|
|
9502
|
-
import { mkdir as
|
|
9503
|
-
import
|
|
9944
|
+
import { mkdir as mkdir3, readFile as readFile9, writeFile as writeFile4 } from "fs/promises";
|
|
9945
|
+
import path13 from "path";
|
|
9504
9946
|
|
|
9505
9947
|
// src/domain/volume/volume.ts
|
|
9506
9948
|
var VOLUME_STATUS_LABELS = { 1: "creating", 2: "ready", 3: "failed", 4: "deleting" };
|
|
@@ -9511,14 +9953,14 @@ function normalizeVolumePath(input, options = {}) {
|
|
|
9511
9953
|
if (segments.some((segment) => segment === "..")) {
|
|
9512
9954
|
throw new DomainError("Volume paths cannot contain '..'", "usage", "UsageError");
|
|
9513
9955
|
}
|
|
9514
|
-
const
|
|
9515
|
-
if (!
|
|
9956
|
+
const path18 = segments.join("/");
|
|
9957
|
+
if (!path18 && !options.allowRoot) {
|
|
9516
9958
|
throw new DomainError("Pass a path inside the volume, e.g. docs/report.pdf", "usage", "UsageError");
|
|
9517
9959
|
}
|
|
9518
|
-
return
|
|
9960
|
+
return path18;
|
|
9519
9961
|
}
|
|
9520
|
-
function baseName(
|
|
9521
|
-
return
|
|
9962
|
+
function baseName(path18) {
|
|
9963
|
+
return path18.slice(path18.lastIndexOf("/") + 1);
|
|
9522
9964
|
}
|
|
9523
9965
|
|
|
9524
9966
|
// src/infrastructure/tencent/volume-gateway.ts
|
|
@@ -9658,7 +10100,7 @@ function createVolumeGateway(client, options = {}) {
|
|
|
9658
10100
|
await request("DeleteFileVolumeEntry", { ...ref3(input), RelativePath: input.path, ExpectedType: ENTRY_TYPES[input.type] });
|
|
9659
10101
|
},
|
|
9660
10102
|
async upload(input) {
|
|
9661
|
-
const body = await
|
|
10103
|
+
const body = await readFile9(input.localPath).catch((error) => {
|
|
9662
10104
|
throw new DomainError(`Cannot read ${input.localPath}`, "usage", "LocalFileUnreadable", {
|
|
9663
10105
|
hint: error.code === "ENOENT" ? "Check the --file path" : error.message
|
|
9664
10106
|
});
|
|
@@ -9681,8 +10123,8 @@ function createVolumeGateway(client, options = {}) {
|
|
|
9681
10123
|
throw await transferError(response, "download");
|
|
9682
10124
|
}
|
|
9683
10125
|
const bytes = new Uint8Array(await response.arrayBuffer());
|
|
9684
|
-
await
|
|
9685
|
-
await
|
|
10126
|
+
await mkdir3(path13.dirname(input.localPath), { recursive: true });
|
|
10127
|
+
await writeFile4(input.localPath, bytes);
|
|
9686
10128
|
return { bytes: bytes.byteLength };
|
|
9687
10129
|
},
|
|
9688
10130
|
async previewUrl(input) {
|
|
@@ -10071,8 +10513,8 @@ function positive3(value) {
|
|
|
10071
10513
|
}
|
|
10072
10514
|
|
|
10073
10515
|
// src/infrastructure/cos/package-downloader.ts
|
|
10074
|
-
import { mkdir as
|
|
10075
|
-
import
|
|
10516
|
+
import { mkdir as mkdir4, readFile as readFile10, writeFile as writeFile5 } from "fs/promises";
|
|
10517
|
+
import path14 from "path";
|
|
10076
10518
|
function createPackageDownloader(options = {}) {
|
|
10077
10519
|
const fetchImpl = options.fetchImpl ?? globalThis.fetch;
|
|
10078
10520
|
return {
|
|
@@ -10085,12 +10527,12 @@ function createPackageDownloader(options = {}) {
|
|
|
10085
10527
|
});
|
|
10086
10528
|
}
|
|
10087
10529
|
const bytes = new Uint8Array(await response.arrayBuffer());
|
|
10088
|
-
await
|
|
10089
|
-
await
|
|
10530
|
+
await mkdir4(path14.dirname(absolutePath), { recursive: true });
|
|
10531
|
+
await writeFile5(absolutePath, bytes);
|
|
10090
10532
|
return { bytes: bytes.byteLength };
|
|
10091
10533
|
},
|
|
10092
10534
|
async upload(url, absolutePath) {
|
|
10093
|
-
const body = await
|
|
10535
|
+
const body = await readFile10(absolutePath).catch((error) => {
|
|
10094
10536
|
throw new DomainError(`Cannot read package file ${absolutePath}`, "usage", "PackageFileUnreadable", {
|
|
10095
10537
|
hint: error.code === "ENOENT" ? "Check the --file path" : error.message
|
|
10096
10538
|
});
|
|
@@ -10201,7 +10643,7 @@ var PAGE_NOT_EXIST = "Generic.PageNotExist";
|
|
|
10201
10643
|
function createTencentDocsPortal(options = {}) {
|
|
10202
10644
|
const origin = options.origin ?? DOCS_PORTAL_ORIGIN;
|
|
10203
10645
|
const fetchImpl = options.fetchImpl ?? fetch;
|
|
10204
|
-
const
|
|
10646
|
+
const timeoutMs2 = options.timeoutMs ?? DEFAULT_DOCS_TIMEOUT_MS;
|
|
10205
10647
|
return {
|
|
10206
10648
|
async search(input) {
|
|
10207
10649
|
if (!input.keyword.trim()) {
|
|
@@ -10212,7 +10654,7 @@ function createTencentDocsPortal(options = {}) {
|
|
|
10212
10654
|
url.searchParams.set("keyword", input.keyword.trim());
|
|
10213
10655
|
url.searchParams.set("page", "1");
|
|
10214
10656
|
url.searchParams.set("pagesize", String(pagesize));
|
|
10215
|
-
const payload = await requestJson(fetchImpl, url, { method: "GET" },
|
|
10657
|
+
const payload = await requestJson(fetchImpl, url, { method: "GET" }, timeoutMs2, origin);
|
|
10216
10658
|
return parseSearchHits(payload, origin);
|
|
10217
10659
|
},
|
|
10218
10660
|
async listPages(input) {
|
|
@@ -10225,7 +10667,7 @@ function createTencentDocsPortal(options = {}) {
|
|
|
10225
10667
|
isPreview: false
|
|
10226
10668
|
}
|
|
10227
10669
|
};
|
|
10228
|
-
const payload = await postCgi(fetchImpl, origin, LIST_MENU_ACTION, body,
|
|
10670
|
+
const payload = await postCgi(fetchImpl, origin, LIST_MENU_ACTION, body, timeoutMs2);
|
|
10229
10671
|
const nodes = extractMenuNodes(payload);
|
|
10230
10672
|
const pages = flattenMenu(nodes, productId);
|
|
10231
10673
|
if (!input.docType) {
|
|
@@ -10249,12 +10691,12 @@ function createTencentDocsPortal(options = {}) {
|
|
|
10249
10691
|
catId: Number(productId) || productId
|
|
10250
10692
|
}
|
|
10251
10693
|
};
|
|
10252
|
-
const payload = await postCgi(fetchImpl, origin, GET_DOC_ACTION, body,
|
|
10694
|
+
const payload = await postCgi(fetchImpl, origin, GET_DOC_ACTION, body, timeoutMs2);
|
|
10253
10695
|
return parseDocContent(payload, documentId, productId);
|
|
10254
10696
|
}
|
|
10255
10697
|
};
|
|
10256
10698
|
}
|
|
10257
|
-
async function postCgi(fetchImpl, origin, action, body,
|
|
10699
|
+
async function postCgi(fetchImpl, origin, action, body, timeoutMs2) {
|
|
10258
10700
|
const url = new URL(`${DOCS_CGI_PREFIX}/${action}`, origin);
|
|
10259
10701
|
return requestJson(
|
|
10260
10702
|
fetchImpl,
|
|
@@ -10264,11 +10706,11 @@ async function postCgi(fetchImpl, origin, action, body, timeoutMs) {
|
|
|
10264
10706
|
headers: { "content-type": "application/json" },
|
|
10265
10707
|
body: JSON.stringify(body)
|
|
10266
10708
|
},
|
|
10267
|
-
|
|
10709
|
+
timeoutMs2,
|
|
10268
10710
|
origin
|
|
10269
10711
|
);
|
|
10270
10712
|
}
|
|
10271
|
-
async function requestJson(fetchImpl, url, init,
|
|
10713
|
+
async function requestJson(fetchImpl, url, init, timeoutMs2, origin) {
|
|
10272
10714
|
const referer = productDocsUrl(DEFAULT_DOCS_PRODUCT_ID);
|
|
10273
10715
|
let response;
|
|
10274
10716
|
try {
|
|
@@ -10280,7 +10722,7 @@ async function requestJson(fetchImpl, url, init, timeoutMs, origin) {
|
|
|
10280
10722
|
referer,
|
|
10281
10723
|
...init.headers
|
|
10282
10724
|
},
|
|
10283
|
-
signal: AbortSignal.timeout(
|
|
10725
|
+
signal: AbortSignal.timeout(timeoutMs2)
|
|
10284
10726
|
});
|
|
10285
10727
|
} catch (error) {
|
|
10286
10728
|
throw portalError(
|
|
@@ -10564,7 +11006,7 @@ function normalizedChoiceName(value) {
|
|
|
10564
11006
|
|
|
10565
11007
|
// src/interfaces/cli/prompter.ts
|
|
10566
11008
|
var PROMPT_TIMEOUT_MS = 6e4;
|
|
10567
|
-
async function readSecret(message,
|
|
11009
|
+
async function readSecret(message, timeoutMs2) {
|
|
10568
11010
|
const stdin = process.stdin;
|
|
10569
11011
|
process.stdout.write(message);
|
|
10570
11012
|
if (!stdin.isTTY) {
|
|
@@ -10583,7 +11025,7 @@ async function readSecret(message, timeoutMs) {
|
|
|
10583
11025
|
process.stdout.write("\n");
|
|
10584
11026
|
resolve(result);
|
|
10585
11027
|
};
|
|
10586
|
-
const timer = setTimeout(() => finish(value),
|
|
11028
|
+
const timer = setTimeout(() => finish(value), timeoutMs2);
|
|
10587
11029
|
const onData = (chunk) => {
|
|
10588
11030
|
for (const char of chunk.toString("utf8")) {
|
|
10589
11031
|
if (char === "\r" || char === "\n") {
|
|
@@ -10607,9 +11049,9 @@ async function readSecret(message, timeoutMs) {
|
|
|
10607
11049
|
stdin.on("data", onData);
|
|
10608
11050
|
});
|
|
10609
11051
|
}
|
|
10610
|
-
async function readLine(message,
|
|
11052
|
+
async function readLine(message, timeoutMs2) {
|
|
10611
11053
|
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
10612
|
-
const timer = setTimeout(() => rl.close(),
|
|
11054
|
+
const timer = setTimeout(() => rl.close(), timeoutMs2);
|
|
10613
11055
|
try {
|
|
10614
11056
|
return await rl.question(message);
|
|
10615
11057
|
} catch (error) {
|
|
@@ -10727,6 +11169,8 @@ async function createProductionDeps(env = process.env) {
|
|
|
10727
11169
|
launchDetachedLogin,
|
|
10728
11170
|
openBrowser: openInBrowser,
|
|
10729
11171
|
env,
|
|
11172
|
+
toolKeyStore: createToolKeyFileStore(adpToolKeyPath()),
|
|
11173
|
+
pluginMcp: createPluginMcpGateway(),
|
|
10730
11174
|
resolveIdentity: (flags) => resolveIdentityFor(flags),
|
|
10731
11175
|
async resolveGateways(flags) {
|
|
10732
11176
|
const identity = await resolveIdentityFor(flags);
|
|
@@ -10748,6 +11192,7 @@ async function createProductionDeps(env = process.env) {
|
|
|
10748
11192
|
release: createReleaseGateway(client),
|
|
10749
11193
|
plugin: createPluginGateway(client),
|
|
10750
11194
|
pluginAccess: createPluginAccessGateway(client),
|
|
11195
|
+
toolKey: createToolKeyGateway(lke),
|
|
10751
11196
|
skillLifecycle: createSkillLifecycleGateway(client),
|
|
10752
11197
|
workflowRunControl: createWorkflowRunControlGateway(client),
|
|
10753
11198
|
agentTool: createAgentToolGateway(client),
|
|
@@ -10782,25 +11227,13 @@ async function createProductionDeps(env = process.env) {
|
|
|
10782
11227
|
usage: createUsageGateway(client),
|
|
10783
11228
|
objectStore: createPlatformObjectStore(),
|
|
10784
11229
|
packageDownloader: createPackageDownloader(),
|
|
10785
|
-
knowledge:
|
|
10786
|
-
"adp kb doc is not supported by the independent-site profile",
|
|
10787
|
-
"Knowledge document transport uses the public-cloud LKE and platform COS planes"
|
|
10788
|
-
) : createKnowledgeGateway({ adp: client, lke }),
|
|
11230
|
+
knowledge: createKnowledgeGateway({ adp: client, lke }),
|
|
10789
11231
|
kb: createKbGateway(client),
|
|
10790
11232
|
channel: createChannelGateway(client)
|
|
10791
11233
|
};
|
|
10792
11234
|
}
|
|
10793
11235
|
};
|
|
10794
11236
|
}
|
|
10795
|
-
function unsupportedGateway(message, hint) {
|
|
10796
|
-
return new Proxy({}, {
|
|
10797
|
-
get() {
|
|
10798
|
-
return async () => {
|
|
10799
|
-
throw usageError(message, hint);
|
|
10800
|
-
};
|
|
10801
|
-
}
|
|
10802
|
-
});
|
|
10803
|
-
}
|
|
10804
11237
|
function canPrompt(deps) {
|
|
10805
11238
|
return deps.stdinIsTTY && !deps.agentName;
|
|
10806
11239
|
}
|
|
@@ -11364,7 +11797,7 @@ function registerIdentityCommands(registry, ctx) {
|
|
|
11364
11797
|
}
|
|
11365
11798
|
|
|
11366
11799
|
// src/interfaces/cli/commands/init.ts
|
|
11367
|
-
import
|
|
11800
|
+
import path15 from "path";
|
|
11368
11801
|
|
|
11369
11802
|
// src/domain/project-config/adp-config.ts
|
|
11370
11803
|
var APP_MODES = {
|
|
@@ -11682,7 +12115,7 @@ function registerInitCommand(registry, ctx) {
|
|
|
11682
12115
|
plugins: []
|
|
11683
12116
|
}
|
|
11684
12117
|
};
|
|
11685
|
-
const configPath =
|
|
12118
|
+
const configPath = path15.resolve(ctx.flags.cwd, ctx.flags.config ?? "adp.jsonc");
|
|
11686
12119
|
const createRemote = Boolean(args["create-remote"]);
|
|
11687
12120
|
const gateways = createRemote && !ctx.flags.dryRun ? await ctx.deps.resolveGateways(ctx.flags) : void 0;
|
|
11688
12121
|
const previewModels = createRemote && ctx.flags.dryRun && config2.appMode === APP_MODES.claw && modelId === PLACEHOLDER_MODEL_ID ? await ctx.deps.resolveGateways(ctx.flags).then((resolved2) => resolved2.model).catch(() => void 0) : void 0;
|
|
@@ -13646,7 +14079,7 @@ function registerSpaceCommands(registry, ctx) {
|
|
|
13646
14079
|
}
|
|
13647
14080
|
|
|
13648
14081
|
// src/infrastructure/fs/app-package-reader.ts
|
|
13649
|
-
import { readFile as
|
|
14082
|
+
import { readFile as readFile11 } from "fs/promises";
|
|
13650
14083
|
import { inflateRawSync } from "zlib";
|
|
13651
14084
|
var END_OF_CENTRAL_DIRECTORY = 101010256;
|
|
13652
14085
|
var CENTRAL_FILE_HEADER = 33639248;
|
|
@@ -13727,7 +14160,7 @@ function createAppPackageReader() {
|
|
|
13727
14160
|
}
|
|
13728
14161
|
async function readInventory(file) {
|
|
13729
14162
|
try {
|
|
13730
|
-
const zip = await
|
|
14163
|
+
const zip = await readFile11(file);
|
|
13731
14164
|
const entries = listEntries(zip);
|
|
13732
14165
|
if (entries.length === 0 && zip.length > 0 && !looksLikeZip(zip)) {
|
|
13733
14166
|
return EMPTY_INVENTORY;
|
|
@@ -15430,28 +15863,126 @@ function afterAppCreate(payload) {
|
|
|
15430
15863
|
};
|
|
15431
15864
|
}
|
|
15432
15865
|
|
|
15866
|
+
// src/interfaces/cli/commands/agent/index.ts
|
|
15867
|
+
import { readFile as readFile12 } from "fs/promises";
|
|
15868
|
+
import path16 from "path";
|
|
15869
|
+
|
|
15433
15870
|
// src/application/agent/agent-use-cases.ts
|
|
15871
|
+
var CLAW_AGENT_LIMIT = 20;
|
|
15434
15872
|
async function listAgents(gateway, input) {
|
|
15435
15873
|
return collectPages(
|
|
15436
15874
|
(page3, pageSize) => gateway.list({ appId: input.appId, limit: pageSize, page: page3 }),
|
|
15437
15875
|
{ limit: input.limit, page: input.page, firstPage: 0 }
|
|
15438
15876
|
);
|
|
15439
15877
|
}
|
|
15440
|
-
function
|
|
15878
|
+
function specForAgentCreate(config2, projectInstructions, overrides) {
|
|
15879
|
+
const subViaFlags = overrides.subAgent === true || overrides.role === 1;
|
|
15880
|
+
const role = subViaFlags ? 1 : overrides.role ?? config2?.agent.profile.role ?? 0;
|
|
15881
|
+
if (role !== 0 && role !== 1) {
|
|
15882
|
+
throw usageError(
|
|
15883
|
+
`Agent role must be 0 (main) or 1 (sub-agent); got ${role}`,
|
|
15884
|
+
"Pass --role 0 or --role 1 (or --sub-agent)"
|
|
15885
|
+
);
|
|
15886
|
+
}
|
|
15887
|
+
if (subViaFlags && !overrides.name?.trim()) {
|
|
15888
|
+
throw usageError(
|
|
15889
|
+
"A Claw sub-agent needs --name",
|
|
15890
|
+
"Pass --name. adp.jsonc agent.profile.name is the main agent and is not reused for --role 1"
|
|
15891
|
+
);
|
|
15892
|
+
}
|
|
15893
|
+
const name = (overrides.name ?? config2?.agent.profile.name ?? "").trim();
|
|
15894
|
+
if (!name) {
|
|
15895
|
+
throw usageError("Agent name is required", "Pass --name, or set agent.profile.name in adp.jsonc");
|
|
15896
|
+
}
|
|
15897
|
+
const description = overrides.description !== void 0 ? overrides.description : subViaFlags ? name : config2?.agent.profile.description;
|
|
15898
|
+
const configuredModel = overrides.modelId ?? config2?.agent.model.modelId ?? "";
|
|
15899
|
+
const modelId = configuredModel === PLACEHOLDER_MODEL_ID ? "" : configuredModel;
|
|
15900
|
+
return {
|
|
15901
|
+
profile: {
|
|
15902
|
+
name,
|
|
15903
|
+
description,
|
|
15904
|
+
iconUrl: subViaFlags ? void 0 : config2?.agent.profile.iconUrl,
|
|
15905
|
+
role
|
|
15906
|
+
},
|
|
15907
|
+
instructions: instructionsForCreate(name, description, subViaFlags, config2, projectInstructions, overrides.instructions),
|
|
15908
|
+
model: {
|
|
15909
|
+
modelId,
|
|
15910
|
+
...subViaFlags ? {} : {
|
|
15911
|
+
alias: config2?.agent.model.alias,
|
|
15912
|
+
contextWordsLimit: config2?.agent.model.contextWordsLimit,
|
|
15913
|
+
instructionsWordsLimit: config2?.agent.model.instructionsWordsLimit
|
|
15914
|
+
}
|
|
15915
|
+
},
|
|
15916
|
+
skillIds: overrides.skillIds ?? (subViaFlags ? [] : config2?.agent.skillIds ?? []),
|
|
15917
|
+
pluginIds: subViaFlags ? [] : config2?.agent.pluginIds ?? [],
|
|
15918
|
+
connectorIds: subViaFlags ? void 0 : config2?.agent.connectorIds,
|
|
15919
|
+
tools: subViaFlags ? [{ ...KNOWLEDGE_RETRIEVAL_TOOL }] : config2?.agent.tools ?? [],
|
|
15920
|
+
plugins: subViaFlags ? void 0 : config2?.agent.plugins,
|
|
15921
|
+
maxReasoningRound: subViaFlags ? void 0 : config2?.agent.maxReasoningRound
|
|
15922
|
+
};
|
|
15923
|
+
}
|
|
15924
|
+
function instructionsForCreate(name, description, subViaFlags, config2, projectInstructions, explicit) {
|
|
15925
|
+
if (explicit !== void 0) {
|
|
15926
|
+
return explicit;
|
|
15927
|
+
}
|
|
15928
|
+
if (subViaFlags) {
|
|
15929
|
+
return defaultSubAgentInstructions(name, description);
|
|
15930
|
+
}
|
|
15931
|
+
if (projectInstructions !== void 0) {
|
|
15932
|
+
return projectInstructions;
|
|
15933
|
+
}
|
|
15934
|
+
if (config2?.agent.instructions) {
|
|
15935
|
+
return config2.agent.instructions;
|
|
15936
|
+
}
|
|
15937
|
+
if (!config2) {
|
|
15938
|
+
return defaultSubAgentInstructions(name, description);
|
|
15939
|
+
}
|
|
15940
|
+
return "";
|
|
15941
|
+
}
|
|
15942
|
+
function defaultSubAgentInstructions(name, description) {
|
|
15943
|
+
if (description && description !== name) {
|
|
15944
|
+
return `You are ${name}. ${description}`;
|
|
15945
|
+
}
|
|
15946
|
+
return `You are ${name}.`;
|
|
15947
|
+
}
|
|
15948
|
+
function shellWord4(value) {
|
|
15949
|
+
return /^[\w@%+=:,./-]+$/.test(value) ? value : `'${value.replace(/'/g, "'\\''")}'`;
|
|
15950
|
+
}
|
|
15951
|
+
function subAgentCreateCommand(appId3, name) {
|
|
15952
|
+
const shown = name?.trim() ? name.trim() : "sub-agent";
|
|
15953
|
+
return `adp agent create --app-id ${appId3} --role 1 --name ${shellWord4(shown)} --dry-run --format json`;
|
|
15954
|
+
}
|
|
15955
|
+
function agentAlreadyExists(appId3, agentId, name) {
|
|
15441
15956
|
return new DomainError(
|
|
15442
|
-
`App ${appId3} already has agent ${agentId}
|
|
15957
|
+
`App ${appId3} already has main agent ${agentId}. CreateAgent with role 0 returns that agent instead of creating another one`,
|
|
15443
15958
|
"conflict",
|
|
15444
15959
|
"AgentAlreadyExists",
|
|
15445
15960
|
{
|
|
15446
|
-
hint: "A Claw app (app_mode 4) has
|
|
15961
|
+
hint: "A Claw app (app_mode 4) has one main agent (role 0) and up to 19 sub-agents (role 1). Edit the main agent with adp agent update, or pass --role 1 (or --sub-agent) on adp agent create to add a sub-agent",
|
|
15447
15962
|
nextActions: [
|
|
15448
15963
|
{
|
|
15449
15964
|
command: `adp agent update --app-id ${appId3} --agent-id ${agentId} --format json`,
|
|
15450
|
-
reason: "edit the existing agent
|
|
15965
|
+
reason: "edit the existing main agent (role 0) instead of creating another one"
|
|
15451
15966
|
},
|
|
15452
15967
|
{
|
|
15453
|
-
command:
|
|
15454
|
-
reason: "
|
|
15968
|
+
command: subAgentCreateCommand(appId3, name),
|
|
15969
|
+
reason: "add a Claw sub-agent (role 1); set --description to when the main agent should delegate, and --instructions for how the sub-agent works"
|
|
15970
|
+
}
|
|
15971
|
+
]
|
|
15972
|
+
}
|
|
15973
|
+
);
|
|
15974
|
+
}
|
|
15975
|
+
function agentLimitReached(appId3) {
|
|
15976
|
+
return new DomainError(
|
|
15977
|
+
`App ${appId3} already has ${CLAW_AGENT_LIMIT} agents. A Claw app allows 1 main agent and 19 sub-agents`,
|
|
15978
|
+
"conflict",
|
|
15979
|
+
"AgentLimitExceeded",
|
|
15980
|
+
{
|
|
15981
|
+
hint: "Delete a sub-agent before creating another. Keep the main agent (role 0).",
|
|
15982
|
+
nextActions: [
|
|
15983
|
+
{
|
|
15984
|
+
command: `adp agent list --app-id ${appId3} --format json`,
|
|
15985
|
+
reason: "list agents and their roles before deleting a sub-agent"
|
|
15455
15986
|
}
|
|
15456
15987
|
]
|
|
15457
15988
|
}
|
|
@@ -15472,7 +16003,7 @@ async function describeAgent(gateway, input) {
|
|
|
15472
16003
|
throw error;
|
|
15473
16004
|
}
|
|
15474
16005
|
}
|
|
15475
|
-
async function createAgent(gateway, input, apps2) {
|
|
16006
|
+
async function createAgent(gateway, input, apps2, models) {
|
|
15476
16007
|
const app = await apps2.describe({ appId: input.appId });
|
|
15477
16008
|
if (app.appMode !== void 0 && app.appMode !== APP_MODES.claw) {
|
|
15478
16009
|
throw usageError(
|
|
@@ -15480,26 +16011,110 @@ async function createAgent(gateway, input, apps2) {
|
|
|
15480
16011
|
app.appMode === APP_MODES.standard ? "A Standard app has no extra agents: edit its settings in adp.jsonc and run adp deploy" : "Edit the existing agents with adp agent update, or create a Claw app (adp init --app-mode 4) for a separate agent"
|
|
15481
16012
|
);
|
|
15482
16013
|
}
|
|
16014
|
+
const role = input.spec.profile?.role ?? 0;
|
|
16015
|
+
if (role !== 0 && role !== 1) {
|
|
16016
|
+
throw usageError(
|
|
16017
|
+
`Agent role must be 0 (main) or 1 (sub-agent); got ${role}`,
|
|
16018
|
+
"Pass --role 0 or --role 1 (or --sub-agent)"
|
|
16019
|
+
);
|
|
16020
|
+
}
|
|
15483
16021
|
const before = await gateway.list({ appId: input.appId, limit: 100, page: 0 });
|
|
16022
|
+
const main2 = before.items.find((agent) => (agent.role ?? 0) === 0);
|
|
16023
|
+
if (role === 0 && main2) {
|
|
16024
|
+
throw agentAlreadyExists(input.appId, main2.agentId, input.spec.profile?.name);
|
|
16025
|
+
}
|
|
16026
|
+
if (before.items.length >= CLAW_AGENT_LIMIT) {
|
|
16027
|
+
throw agentLimitReached(input.appId);
|
|
16028
|
+
}
|
|
16029
|
+
const spec = await withInheritedModel(gateway, models, {
|
|
16030
|
+
appId: input.appId,
|
|
16031
|
+
spaceId: input.spaceId,
|
|
16032
|
+
spec: input.spec,
|
|
16033
|
+
agents: before.items
|
|
16034
|
+
});
|
|
15484
16035
|
if (input.dryRun) {
|
|
15485
|
-
|
|
15486
|
-
|
|
15487
|
-
throw agentAlreadyExists(input.appId, existing.agentId);
|
|
16036
|
+
if (role === 1) {
|
|
16037
|
+
return { dryRun: true, appId: input.appId, role: 1, name: spec.profile.name, modelId: spec.model.modelId };
|
|
15488
16038
|
}
|
|
15489
16039
|
return { dryRun: true, appId: input.appId };
|
|
15490
16040
|
}
|
|
15491
|
-
const created = await gateway.create(input);
|
|
16041
|
+
const created = await gateway.create({ appId: input.appId, spec });
|
|
15492
16042
|
if (before.items.some((agent) => agent.agentId === created.agentId)) {
|
|
15493
|
-
throw agentAlreadyExists(input.appId, created.agentId);
|
|
16043
|
+
throw agentAlreadyExists(input.appId, created.agentId, spec.profile.name);
|
|
16044
|
+
}
|
|
16045
|
+
if (role === 1) {
|
|
16046
|
+
return { dryRun: false, ...created, role: 1, name: spec.profile.name, modelId: spec.model.modelId };
|
|
15494
16047
|
}
|
|
15495
16048
|
return { dryRun: false, ...created };
|
|
15496
16049
|
}
|
|
16050
|
+
async function withInheritedModel(gateway, models, input) {
|
|
16051
|
+
const current = input.spec.model.modelId;
|
|
16052
|
+
if (current && current !== PLACEHOLDER_MODEL_ID) {
|
|
16053
|
+
return input.spec;
|
|
16054
|
+
}
|
|
16055
|
+
const main2 = input.agents.find((agent) => (agent.role ?? 0) === 0);
|
|
16056
|
+
if (main2) {
|
|
16057
|
+
try {
|
|
16058
|
+
const detail = await gateway.describe({ appId: input.appId, agentId: main2.agentId });
|
|
16059
|
+
const modelId = detail.spec?.model.modelId;
|
|
16060
|
+
if (modelId && modelId !== PLACEHOLDER_MODEL_ID) {
|
|
16061
|
+
return { ...input.spec, model: { ...input.spec.model, modelId } };
|
|
16062
|
+
}
|
|
16063
|
+
} catch {
|
|
16064
|
+
}
|
|
16065
|
+
}
|
|
16066
|
+
if (models && input.spaceId) {
|
|
16067
|
+
try {
|
|
16068
|
+
const listed = await models.list({ limit: 1, page: 0, scene: MODEL_SCENE_CLAW, spaceId: input.spaceId });
|
|
16069
|
+
const modelId = listed.items[0]?.modelId;
|
|
16070
|
+
if (modelId) {
|
|
16071
|
+
return { ...input.spec, model: { ...input.spec.model, modelId } };
|
|
16072
|
+
}
|
|
16073
|
+
} catch {
|
|
16074
|
+
}
|
|
16075
|
+
}
|
|
16076
|
+
return { ...input.spec, model: { ...input.spec.model, modelId: "Auto/auto" } };
|
|
16077
|
+
}
|
|
16078
|
+
function hasPatch(patch) {
|
|
16079
|
+
return Boolean(patch && Object.values(patch).some((value) => value !== void 0));
|
|
16080
|
+
}
|
|
16081
|
+
function applyAgentPatch(spec, patch) {
|
|
16082
|
+
return {
|
|
16083
|
+
...spec,
|
|
16084
|
+
profile: {
|
|
16085
|
+
...spec.profile,
|
|
16086
|
+
...patch.name !== void 0 ? { name: patch.name } : {},
|
|
16087
|
+
...patch.description !== void 0 ? { description: patch.description } : {}
|
|
16088
|
+
},
|
|
16089
|
+
...patch.instructions !== void 0 ? { instructions: patch.instructions } : {},
|
|
16090
|
+
model: patch.modelId !== void 0 ? { ...spec.model, modelId: patch.modelId } : spec.model
|
|
16091
|
+
};
|
|
16092
|
+
}
|
|
15497
16093
|
async function modifyAgent(gateway, input) {
|
|
16094
|
+
const patching = hasPatch(input.patch);
|
|
16095
|
+
let spec = input.spec;
|
|
16096
|
+
if (patching || !spec) {
|
|
16097
|
+
if (!patching) {
|
|
16098
|
+
throw usageError(
|
|
16099
|
+
"Agent update needs adp.jsonc or a field to change",
|
|
16100
|
+
"Pass --name, --description, --instructions, --instructions-file, or --model-id"
|
|
16101
|
+
);
|
|
16102
|
+
}
|
|
16103
|
+
const current = await describeAgent(gateway, { appId: input.appId, agentId: input.agentId });
|
|
16104
|
+
if (!current.spec) {
|
|
16105
|
+
throw usageError(
|
|
16106
|
+
`Agent ${input.agentId} has no config to update`,
|
|
16107
|
+
"Run adp agent get and pass --name, --description, --instructions, or --model-id"
|
|
16108
|
+
);
|
|
16109
|
+
}
|
|
16110
|
+
spec = applyAgentPatch(current.spec, input.patch ?? {});
|
|
16111
|
+
}
|
|
16112
|
+
const patched = patching ? { name: spec.profile.name, description: spec.profile.description, modelId: spec.model.modelId } : {};
|
|
15498
16113
|
if (input.dryRun) {
|
|
15499
|
-
return { dryRun: true, agentId: input.agentId };
|
|
16114
|
+
return { dryRun: true, agentId: input.agentId, ...patched };
|
|
15500
16115
|
}
|
|
15501
|
-
await gateway.modify({
|
|
15502
|
-
return { dryRun: false, agentId: input.agentId };
|
|
16116
|
+
await gateway.modify({ appId: input.appId, agentId: input.agentId, spec, updateMask: defaultUpdateMask() });
|
|
16117
|
+
return { dryRun: false, agentId: input.agentId, ...patched };
|
|
15503
16118
|
}
|
|
15504
16119
|
async function deleteAgent(gateway, input) {
|
|
15505
16120
|
await assertExisting([input.agentId], async (agentId) => (await describeAgent(gateway, { appId: input.appId, agentId })).agentId, {
|
|
@@ -15570,28 +16185,82 @@ function registerAgentCommands(registry, ctx) {
|
|
|
15570
16185
|
registry.define(
|
|
15571
16186
|
createCommand({
|
|
15572
16187
|
command: "agent create",
|
|
15573
|
-
describe: "Create
|
|
16188
|
+
describe: "Create a Claw agent (role 0 main, or role 1 sub-agent)",
|
|
15574
16189
|
effects: "non_idempotent",
|
|
15575
16190
|
outputKind: "data",
|
|
15576
16191
|
examples: [
|
|
15577
16192
|
"adp agent create --app-id app-1 --format json",
|
|
15578
|
-
"adp agent create --app-id app-1 --dry-run"
|
|
16193
|
+
"adp agent create --app-id app-1 --dry-run",
|
|
16194
|
+
"adp agent create --app-id app-1 --role 1 --name ray\u7684\u6D4B\u8BD5agent --description delegates-ray-tests --dry-run --format json",
|
|
16195
|
+
"adp agent create --app-id app-1 --sub-agent --name ray\u7684\u6D4B\u8BD5agent --instructions You-are-ray --model-id m1 --dry-run --format json"
|
|
16196
|
+
],
|
|
16197
|
+
flags: [
|
|
16198
|
+
{ name: "app-id", type: "string", describe: "App ID (default: adp.jsonc app_id)" },
|
|
16199
|
+
{
|
|
16200
|
+
name: "name",
|
|
16201
|
+
type: "string",
|
|
16202
|
+
describe: "Agent name. Overrides adp.jsonc agent.profile.name. Required when adp.jsonc is absent, and required with --role 1 or --sub-agent"
|
|
16203
|
+
},
|
|
16204
|
+
{
|
|
16205
|
+
name: "description",
|
|
16206
|
+
type: "string",
|
|
16207
|
+
describe: "Routing description: the main agent uses it to decide when to delegate. Overrides adp.jsonc agent.profile.description"
|
|
16208
|
+
},
|
|
16209
|
+
{
|
|
16210
|
+
name: "role",
|
|
16211
|
+
type: "number",
|
|
16212
|
+
describe: "0 = main agent (default), 1 = Claw sub-agent. A second role 0 fails with AgentAlreadyExists; role 1 adds a sub-agent (up to 19)"
|
|
16213
|
+
},
|
|
16214
|
+
{
|
|
16215
|
+
name: "sub-agent",
|
|
16216
|
+
type: "boolean",
|
|
16217
|
+
describe: "Create a Claw sub-agent (same as --role 1). Does not copy the main agent's instructions.md, skill_ids, or plugin_ids"
|
|
16218
|
+
},
|
|
16219
|
+
{
|
|
16220
|
+
name: "instructions",
|
|
16221
|
+
type: "string",
|
|
16222
|
+
describe: "System prompt. With --role 1 this is the sub-agent prompt; instructions.md is not copied unless you pass it here or via --instructions-file"
|
|
16223
|
+
},
|
|
16224
|
+
{
|
|
16225
|
+
name: "instructions-file",
|
|
16226
|
+
type: "string",
|
|
16227
|
+
describe: "Read the system prompt from this file instead of --instructions or instructions.md"
|
|
16228
|
+
},
|
|
16229
|
+
{
|
|
16230
|
+
name: "model-id",
|
|
16231
|
+
type: "string",
|
|
16232
|
+
describe: "Model ID. Default: a real adp.jsonc agent.model.model_id, else the main agent's model, else the first ModelScene=18 model, else Auto/auto"
|
|
16233
|
+
},
|
|
16234
|
+
{
|
|
16235
|
+
name: "skill-id",
|
|
16236
|
+
type: "string",
|
|
16237
|
+
list: true,
|
|
16238
|
+
describe: "Skill ID to mount (repeatable). With --role 1, defaults to none instead of copying the main agent"
|
|
16239
|
+
}
|
|
15579
16240
|
],
|
|
15580
|
-
flags: [{ name: "app-id", type: "string", describe: "App ID (default: adp.jsonc app_id)" }],
|
|
15581
16241
|
async handler(args) {
|
|
15582
|
-
const
|
|
16242
|
+
const instructionsFlag = await readInstructionsFlag(ctx, args);
|
|
16243
|
+
const overrides = readCreateOverrides(args, instructionsFlag);
|
|
16244
|
+
const loaded = await tryLoadConfig(ctx.deps.configStore, {
|
|
15583
16245
|
cwd: ctx.flags.cwd,
|
|
15584
16246
|
configPath: ctx.flags.config,
|
|
15585
16247
|
envName: ctx.flags.env
|
|
15586
16248
|
});
|
|
15587
|
-
const
|
|
16249
|
+
const projectInstructions = loaded && !overrides.subAgent && !instructionsFlag.explicit ? await resolveInstructions(ctx.deps.configStore, ctx.flags.cwd, loaded.config) : void 0;
|
|
16250
|
+
const spec = specForAgentCreate(loaded?.config, projectInstructions, overrides);
|
|
15588
16251
|
const gateways = await ctx.deps.resolveGateways(ctx.flags);
|
|
15589
16252
|
return mutationPayload(
|
|
15590
|
-
await createAgent(
|
|
15591
|
-
|
|
15592
|
-
|
|
15593
|
-
|
|
15594
|
-
|
|
16253
|
+
await createAgent(
|
|
16254
|
+
gateways.agent,
|
|
16255
|
+
{
|
|
16256
|
+
appId: await agentAppId(ctx, args),
|
|
16257
|
+
spec,
|
|
16258
|
+
dryRun: ctx.flags.dryRun,
|
|
16259
|
+
spaceId: loaded?.config.spaceId
|
|
16260
|
+
},
|
|
16261
|
+
gateways.app,
|
|
16262
|
+
gateways.model
|
|
16263
|
+
),
|
|
15595
16264
|
"create",
|
|
15596
16265
|
"agent"
|
|
15597
16266
|
);
|
|
@@ -15601,28 +16270,50 @@ function registerAgentCommands(registry, ctx) {
|
|
|
15601
16270
|
registry.define(
|
|
15602
16271
|
createCommand({
|
|
15603
16272
|
command: "agent update",
|
|
15604
|
-
describe: "Modify an agent from
|
|
16273
|
+
describe: "Modify an agent from adp.jsonc, or patch fields passed as flags",
|
|
15605
16274
|
effects: "idempotent",
|
|
15606
16275
|
outputKind: "data",
|
|
15607
16276
|
examples: [
|
|
15608
16277
|
"adp agent update --app-id app-1 --agent-id agt-1 --format json",
|
|
15609
|
-
"adp agent update --app-id app-1 --agent-id agt-1 --dry-run"
|
|
16278
|
+
"adp agent update --app-id app-1 --agent-id agt-1 --dry-run",
|
|
16279
|
+
"adp agent update --app-id app-1 --agent-id agt-1 --name ray\u7684\u6D4B\u8BD5agent --description delegates-ray-tests --dry-run --format json"
|
|
15610
16280
|
],
|
|
15611
16281
|
flags: [
|
|
15612
16282
|
{ name: "app-id", type: "string", describe: "App ID (default: adp.jsonc app_id)" },
|
|
15613
|
-
{ name: "agent-id", type: "string", describe: "Agent ID (default: adp.jsonc agent_id when the app is the bound one)" }
|
|
16283
|
+
{ name: "agent-id", type: "string", describe: "Agent ID (default: adp.jsonc agent_id when the app is the bound one)" },
|
|
16284
|
+
{ name: "name", type: "string", describe: "New agent name. With any field flag, other fields stay as they are on the agent" },
|
|
16285
|
+
{ name: "description", type: "string", describe: "New routing description. With any field flag, other fields stay as they are on the agent" },
|
|
16286
|
+
{ name: "instructions", type: "string", describe: "New system prompt" },
|
|
16287
|
+
{ name: "instructions-file", type: "string", describe: "Read the new system prompt from this file" },
|
|
16288
|
+
{ name: "model-id", type: "string", describe: "New model ID" }
|
|
15614
16289
|
],
|
|
15615
16290
|
async handler(args) {
|
|
15616
|
-
const
|
|
16291
|
+
const instructionsFlag = await readInstructionsFlag(ctx, args);
|
|
16292
|
+
const patch = readUpdatePatch(args, instructionsFlag);
|
|
16293
|
+
const loaded = await tryLoadConfig(ctx.deps.configStore, {
|
|
15617
16294
|
cwd: ctx.flags.cwd,
|
|
15618
16295
|
configPath: ctx.flags.config,
|
|
15619
16296
|
envName: ctx.flags.env
|
|
15620
16297
|
});
|
|
15621
|
-
const instructions = await resolveInstructions(ctx.deps.configStore, ctx.flags.cwd, loaded.config);
|
|
15622
16298
|
const gateways = await ctx.deps.resolveGateways(ctx.flags);
|
|
16299
|
+
const ids4 = await agentIds(ctx, args, "agent update modifies one agent");
|
|
16300
|
+
if (patch) {
|
|
16301
|
+
return mutationPayload(
|
|
16302
|
+
await modifyAgent(gateways.agent, { ...ids4, patch, dryRun: ctx.flags.dryRun }),
|
|
16303
|
+
"update",
|
|
16304
|
+
"agent"
|
|
16305
|
+
);
|
|
16306
|
+
}
|
|
16307
|
+
if (!loaded) {
|
|
16308
|
+
throw usageError(
|
|
16309
|
+
"Agent update needs adp.jsonc or a field to change",
|
|
16310
|
+
"Pass --name, --description, --instructions, --instructions-file, or --model-id"
|
|
16311
|
+
);
|
|
16312
|
+
}
|
|
16313
|
+
const instructions = await resolveInstructions(ctx.deps.configStore, ctx.flags.cwd, loaded.config);
|
|
15623
16314
|
return mutationPayload(
|
|
15624
16315
|
await modifyAgent(gateways.agent, {
|
|
15625
|
-
...
|
|
16316
|
+
...ids4,
|
|
15626
16317
|
spec: toAgentSpec(loaded.config, instructions),
|
|
15627
16318
|
dryRun: ctx.flags.dryRun
|
|
15628
16319
|
}),
|
|
@@ -15663,6 +16354,72 @@ function registerAgentCommands(registry, ctx) {
|
|
|
15663
16354
|
})
|
|
15664
16355
|
);
|
|
15665
16356
|
}
|
|
16357
|
+
async function readInstructionsFlag(ctx, args) {
|
|
16358
|
+
const inline = typeof args.instructions === "string" ? args.instructions : void 0;
|
|
16359
|
+
const file = typeof args["instructions-file"] === "string" ? args["instructions-file"] : void 0;
|
|
16360
|
+
if (inline !== void 0 && file !== void 0) {
|
|
16361
|
+
throw usageError("Pass only one of --instructions and --instructions-file", "One system prompt is enough");
|
|
16362
|
+
}
|
|
16363
|
+
if (file !== void 0) {
|
|
16364
|
+
const filePath = path16.resolve(ctx.flags.cwd, file);
|
|
16365
|
+
try {
|
|
16366
|
+
return { text: await readFile12(filePath, "utf8"), explicit: true };
|
|
16367
|
+
} catch {
|
|
16368
|
+
throw usageError(`Cannot read --instructions-file ${file}`, "Pass a path to a text file, or use --instructions");
|
|
16369
|
+
}
|
|
16370
|
+
}
|
|
16371
|
+
if (inline !== void 0) {
|
|
16372
|
+
return { text: inline, explicit: true };
|
|
16373
|
+
}
|
|
16374
|
+
return { explicit: false };
|
|
16375
|
+
}
|
|
16376
|
+
function readCreateOverrides(args, instructions) {
|
|
16377
|
+
const subFlag = args["sub-agent"] === true;
|
|
16378
|
+
let role;
|
|
16379
|
+
if (args.role !== void 0) {
|
|
16380
|
+
const parsed = typeof args.role === "number" ? args.role : Number(args.role);
|
|
16381
|
+
if (parsed !== 0 && parsed !== 1) {
|
|
16382
|
+
throw usageError("`--role` must be 0 (main agent) or 1 (sub-agent)", "Pass --role 0, --role 1, or --sub-agent");
|
|
16383
|
+
}
|
|
16384
|
+
role = parsed;
|
|
16385
|
+
}
|
|
16386
|
+
if (subFlag && role === 0) {
|
|
16387
|
+
throw usageError("`--sub-agent` is role 1", "Drop --role 0, or drop --sub-agent");
|
|
16388
|
+
}
|
|
16389
|
+
const subAgent = subFlag || role === 1;
|
|
16390
|
+
return {
|
|
16391
|
+
name: optionalText3(args.name),
|
|
16392
|
+
description: optionalText3(args.description),
|
|
16393
|
+
role: subAgent ? 1 : role,
|
|
16394
|
+
subAgent,
|
|
16395
|
+
instructions: instructions.explicit ? instructions.text ?? "" : void 0,
|
|
16396
|
+
modelId: optionalText3(args["model-id"]),
|
|
16397
|
+
skillIds: args["skill-id"] === void 0 ? void 0 : stringList2(args["skill-id"])
|
|
16398
|
+
};
|
|
16399
|
+
}
|
|
16400
|
+
function readUpdatePatch(args, instructions) {
|
|
16401
|
+
const patch = {};
|
|
16402
|
+
if (typeof args.name === "string") {
|
|
16403
|
+
patch.name = args.name;
|
|
16404
|
+
}
|
|
16405
|
+
if (typeof args.description === "string") {
|
|
16406
|
+
patch.description = args.description;
|
|
16407
|
+
}
|
|
16408
|
+
if (instructions.explicit) {
|
|
16409
|
+
patch.instructions = instructions.text ?? "";
|
|
16410
|
+
}
|
|
16411
|
+
if (typeof args["model-id"] === "string") {
|
|
16412
|
+
patch.modelId = args["model-id"];
|
|
16413
|
+
}
|
|
16414
|
+
return Object.values(patch).some((value) => value !== void 0) ? patch : void 0;
|
|
16415
|
+
}
|
|
16416
|
+
function optionalText3(value) {
|
|
16417
|
+
return typeof value === "string" ? value : void 0;
|
|
16418
|
+
}
|
|
16419
|
+
function stringList2(value) {
|
|
16420
|
+
const raw = Array.isArray(value) ? value : value === void 0 || value === null ? [] : [value];
|
|
16421
|
+
return raw.flatMap((item) => String(item).split(",")).map((item) => item.trim()).filter((item) => item.length > 0);
|
|
16422
|
+
}
|
|
15666
16423
|
|
|
15667
16424
|
// src/application/agent/agent-tool-use-cases.ts
|
|
15668
16425
|
function explainAgentToolError(error) {
|
|
@@ -17386,7 +18143,7 @@ async function modifyPlugin(gateway, input) {
|
|
|
17386
18143
|
async function deletePlugin(gateway, input) {
|
|
17387
18144
|
const scope = input.spaceId;
|
|
17388
18145
|
if (scope) {
|
|
17389
|
-
await assertExisting([input.pluginId], async (
|
|
18146
|
+
await assertExisting([input.pluginId], async (pluginId3) => (await gateway.describe({ pluginId: pluginId3, spaceId: scope })).pluginId, {
|
|
17390
18147
|
code: "PluginNotFound",
|
|
17391
18148
|
noun: "plugin",
|
|
17392
18149
|
listCommand: `adp plugin list --space-id ${scope} --fields pluginId,name --format json`
|
|
@@ -17402,7 +18159,7 @@ async function deletePlugin(gateway, input) {
|
|
|
17402
18159
|
throw error;
|
|
17403
18160
|
}
|
|
17404
18161
|
const spaceId = input.spaceId;
|
|
17405
|
-
const missing = spaceId ? await missingIds([input.pluginId], async (
|
|
18162
|
+
const missing = spaceId ? await missingIds([input.pluginId], async (pluginId3) => (await gateway.describe({ pluginId: pluginId3, spaceId })).pluginId).catch(() => []) : [input.pluginId];
|
|
17406
18163
|
if (missing.length === 0) {
|
|
17407
18164
|
throw error;
|
|
17408
18165
|
}
|
|
@@ -17419,8 +18176,8 @@ async function deletePlugin(gateway, input) {
|
|
|
17419
18176
|
}
|
|
17420
18177
|
|
|
17421
18178
|
// src/infrastructure/fs/plugin-spec-file.ts
|
|
17422
|
-
import { readFile as
|
|
17423
|
-
import
|
|
18179
|
+
import { readFile as readFile13 } from "fs/promises";
|
|
18180
|
+
import path17 from "path";
|
|
17424
18181
|
import { parse as parseJsonc2 } from "jsonc-parser";
|
|
17425
18182
|
import { z as z2 } from "zod";
|
|
17426
18183
|
var paramTypeSchema = z2.enum(Object.keys(PARAM_TYPES));
|
|
@@ -17544,10 +18301,10 @@ function parsePluginSpec(text13, sourcePath, env = process.env) {
|
|
|
17544
18301
|
};
|
|
17545
18302
|
}
|
|
17546
18303
|
async function loadPluginSpec(cwd, relativePath) {
|
|
17547
|
-
const resolved2 =
|
|
18304
|
+
const resolved2 = path17.resolve(cwd, relativePath);
|
|
17548
18305
|
let text13;
|
|
17549
18306
|
try {
|
|
17550
|
-
text13 = await
|
|
18307
|
+
text13 = await readFile13(resolved2, "utf8");
|
|
17551
18308
|
} catch {
|
|
17552
18309
|
throw usageError(
|
|
17553
18310
|
`Plugin spec not found: ${resolved2}`,
|
|
@@ -17603,22 +18360,28 @@ function registerPluginCommands(registry, ctx) {
|
|
|
17603
18360
|
async handler(args) {
|
|
17604
18361
|
const spaceId = await resolveSpaceId(ctx, args, "plugin get reads the plugin in a space");
|
|
17605
18362
|
const gateways = await ctx.deps.resolveGateways(ctx.flags);
|
|
17606
|
-
const
|
|
17607
|
-
const plugin = await describePlugin(gateways.plugin, { pluginId:
|
|
17608
|
-
const
|
|
18363
|
+
const pluginId3 = assertResourceId(String(args["plugin-id"]), "plugin-id");
|
|
18364
|
+
const plugin = await describePlugin(gateways.plugin, { pluginId: pluginId3, spaceId: assertResourceId(spaceId, "space-id") });
|
|
18365
|
+
const tool = plugin.tools?.[0];
|
|
18366
|
+
const toolId = tool?.toolId;
|
|
18367
|
+
const mcpCall = plugin.pluginKind === PLUGIN_KIND_MCP && toolId ? {
|
|
18368
|
+
command: mcpCallCommand(pluginId3, { toolId, name: tool?.name }),
|
|
18369
|
+
reason: "preview a direct MCP call; adp plugin key create saves the tool key that call reads"
|
|
18370
|
+
} : void 0;
|
|
17609
18371
|
return {
|
|
17610
18372
|
result: plugin,
|
|
17611
18373
|
nextActions: toolId ? [
|
|
17612
18374
|
{
|
|
17613
|
-
command: `adp agent tool bind --plugin-id ${
|
|
17614
|
-
reason: `bind ${
|
|
18375
|
+
command: `adp agent tool bind --plugin-id ${pluginId3} --tool-id ${toolId} --format json`,
|
|
18376
|
+
reason: `bind ${tool?.name ?? "the first tool"} to an agent (pick another toolId from tools[] for a different tool); also add {"plugin_id":"${pluginId3}","tool_id":"${toolId}"} to agent.tools in adp.jsonc, or the next adp deploy removes it`,
|
|
17615
18377
|
needs_input: { flag: "agent-id", question: "Agent ID to bind the tool to (adp agent list)" }
|
|
17616
18378
|
},
|
|
17617
18379
|
{
|
|
17618
18380
|
command: "adp deploy --dry-run --format json",
|
|
17619
|
-
reason: `the project-file route: add {"plugin_id":"${
|
|
18381
|
+
reason: `the project-file route: add {"plugin_id":"${pluginId3}","tool_id":"${toolId}"} to agent.tools in adp.jsonc, then preview the release`,
|
|
17620
18382
|
needs_edit: { file: "adp.jsonc" }
|
|
17621
|
-
}
|
|
18383
|
+
},
|
|
18384
|
+
...mcpCall ? [mcpCall] : []
|
|
17622
18385
|
] : void 0
|
|
17623
18386
|
};
|
|
17624
18387
|
}
|
|
@@ -17830,17 +18593,24 @@ function registerPluginCommands(registry, ctx) {
|
|
|
17830
18593
|
})
|
|
17831
18594
|
);
|
|
17832
18595
|
}
|
|
18596
|
+
function mcpCallCommand(pluginId3, tool) {
|
|
18597
|
+
const name = tool.name?.trim();
|
|
18598
|
+
if (name && /^[A-Za-z0-9_-]+$/.test(name)) {
|
|
18599
|
+
return `adp plugin tool call --plugin-id ${pluginId3} --tool-name ${name} --dry-run --format json`;
|
|
18600
|
+
}
|
|
18601
|
+
return `adp plugin tool call --plugin-id ${pluginId3} --tool-id ${tool.toolId} --dry-run --format json`;
|
|
18602
|
+
}
|
|
17833
18603
|
function afterPluginCreate(payload, spaceId) {
|
|
17834
|
-
const
|
|
17835
|
-
if (payload.result.dryRun || !
|
|
18604
|
+
const pluginId3 = payload.result.pluginId;
|
|
18605
|
+
if (payload.result.dryRun || !pluginId3) {
|
|
17836
18606
|
return payload;
|
|
17837
18607
|
}
|
|
17838
18608
|
return {
|
|
17839
18609
|
...payload,
|
|
17840
18610
|
nextActions: [
|
|
17841
|
-
{ command: `adp plugin get --plugin-id ${
|
|
18611
|
+
{ command: `adp plugin get --plugin-id ${pluginId3} --space-id ${spaceId} --format json`, reason: "list the plugin's tool IDs" },
|
|
17842
18612
|
{
|
|
17843
|
-
command: `adp agent tool bind --plugin-id ${
|
|
18613
|
+
command: `adp agent tool bind --plugin-id ${pluginId3} --format json`,
|
|
17844
18614
|
reason: "bind one of those tools to an agent's draft, then adp deploy",
|
|
17845
18615
|
needs_input: { flag: "tool-id", question: "Tool ID from adp plugin get" }
|
|
17846
18616
|
}
|
|
@@ -17986,76 +18756,481 @@ function strings6(value) {
|
|
|
17986
18756
|
function pluginId(args) {
|
|
17987
18757
|
return assertResourceId(String(args["plugin-id"]), "plugin-id");
|
|
17988
18758
|
}
|
|
17989
|
-
function registerPluginAccessCommands(registry, ctx) {
|
|
18759
|
+
function registerPluginAccessCommands(registry, ctx) {
|
|
18760
|
+
registry.define(
|
|
18761
|
+
createCommand({
|
|
18762
|
+
command: "plugin share get",
|
|
18763
|
+
describe: "Show who may use a plugin across spaces (active config, or --pending for the one awaiting approval)",
|
|
18764
|
+
effects: "read_only",
|
|
18765
|
+
outputKind: "data",
|
|
18766
|
+
flags: [pluginIdFlag, { name: "pending", type: "boolean", describe: "Show the config awaiting approval" }],
|
|
18767
|
+
examples: ["adp plugin share get --plugin-id plg-1 --format json"],
|
|
18768
|
+
async handler(args) {
|
|
18769
|
+
const gateways = await ctx.deps.resolveGateways(ctx.flags);
|
|
18770
|
+
if (args.pending === true) {
|
|
18771
|
+
return { result: await describePendingPluginShare(gateways.pluginAccess, { pluginId: pluginId(args) }) };
|
|
18772
|
+
}
|
|
18773
|
+
return { result: await describePluginShare(gateways.pluginAccess, { pluginId: pluginId(args), pending: false }) };
|
|
18774
|
+
}
|
|
18775
|
+
})
|
|
18776
|
+
);
|
|
18777
|
+
registry.define(
|
|
18778
|
+
createCommand({
|
|
18779
|
+
command: "plugin share set",
|
|
18780
|
+
describe: "Change plugin or credential share scope; may need approval, and is blocked while apps use what it removes",
|
|
18781
|
+
effects: "idempotent",
|
|
18782
|
+
outputKind: "data",
|
|
18783
|
+
flags: [
|
|
18784
|
+
pluginIdFlag,
|
|
18785
|
+
{ name: "scope", type: "string", describe: "Plugin scope: none | all | spaces" },
|
|
18786
|
+
{ name: "space", type: "string", describe: "Target space ID for --scope spaces (repeatable)" },
|
|
18787
|
+
{ name: "credential", type: "string", describe: "<credential-id>=none|all|spaces:<id>,<id> (repeatable)" },
|
|
18788
|
+
{ name: "remark", type: "string", describe: "Note for the approver" },
|
|
18789
|
+
{ name: "force", type: "boolean", describe: "Admin only: apply even though referrers lose access" },
|
|
18790
|
+
{ name: "confirm-name", type: "string", describe: "Plugin name, required with --force" }
|
|
18791
|
+
],
|
|
18792
|
+
examples: [
|
|
18793
|
+
"adp plugin share set --plugin-id plg-1 --scope spaces --space sp-2 --yes",
|
|
18794
|
+
"adp plugin share set --plugin-id plg-1 --credential cred-1=all --yes --format json"
|
|
18795
|
+
],
|
|
18796
|
+
async handler(args) {
|
|
18797
|
+
const id = pluginId(args);
|
|
18798
|
+
let plugin;
|
|
18799
|
+
if (args.scope !== void 0) {
|
|
18800
|
+
const scope = String(args.scope);
|
|
18801
|
+
if (!SCOPES.includes(scope)) {
|
|
18802
|
+
throw usageError(`--scope must be one of ${SCOPES.join(", ")}`);
|
|
18803
|
+
}
|
|
18804
|
+
plugin = { scope, spaceIds: [...new Set(strings6(args.space).map((s) => assertResourceId(s, "space")))] };
|
|
18805
|
+
} else if (args.space !== void 0) {
|
|
18806
|
+
throw usageError("--space needs --scope spaces");
|
|
18807
|
+
}
|
|
18808
|
+
const credentials = strings6(args.credential).map(parseCredentialShare);
|
|
18809
|
+
await requireYes(ctx, `change share settings of plugin ${id}`);
|
|
18810
|
+
if (ctx.flags.dryRun) {
|
|
18811
|
+
return { result: { dryRun: true, pluginId: id, plugin, credentials }, message: `Would change share settings of plugin ${id}.` };
|
|
18812
|
+
}
|
|
18813
|
+
const gateways = await ctx.deps.resolveGateways(ctx.flags);
|
|
18814
|
+
const result = await setPluginShare(gateways.pluginAccess, {
|
|
18815
|
+
pluginId: id,
|
|
18816
|
+
plugin,
|
|
18817
|
+
credentials,
|
|
18818
|
+
remark: typeof args.remark === "string" ? args.remark : void 0,
|
|
18819
|
+
force: args.force === true,
|
|
18820
|
+
confirmedName: typeof args["confirm-name"] === "string" ? args["confirm-name"] : void 0
|
|
18821
|
+
});
|
|
18822
|
+
return {
|
|
18823
|
+
result,
|
|
18824
|
+
message: result.status === "pending_approval" ? `Submitted for approval: plugin ${id}.` : `Share settings applied: plugin ${id}.`,
|
|
18825
|
+
nextActions: [
|
|
18826
|
+
{
|
|
18827
|
+
command: `adp plugin share get --plugin-id ${id}${result.status === "pending_approval" ? " --pending" : ""}`,
|
|
18828
|
+
reason: result.status === "pending_approval" ? "Review the config awaiting approval" : "Confirm the active config"
|
|
18829
|
+
}
|
|
18830
|
+
]
|
|
18831
|
+
};
|
|
18832
|
+
}
|
|
18833
|
+
})
|
|
18834
|
+
);
|
|
18835
|
+
registry.define(
|
|
18836
|
+
createCommand({
|
|
18837
|
+
command: "plugin share approval",
|
|
18838
|
+
describe: "Show a plugin share approval (scope and credential changes)",
|
|
18839
|
+
effects: "read_only",
|
|
18840
|
+
outputKind: "data",
|
|
18841
|
+
flags: [pluginIdFlag, { name: "approval-id", type: "string", describe: "Approval ID", required: true }],
|
|
18842
|
+
examples: ["adp plugin share approval --plugin-id plg-1 --approval-id 2096851869377474240 --format json"],
|
|
18843
|
+
async handler(args) {
|
|
18844
|
+
const gateways = await ctx.deps.resolveGateways(ctx.flags);
|
|
18845
|
+
return {
|
|
18846
|
+
result: await describePluginShareApproval(gateways.pluginAccess, {
|
|
18847
|
+
pluginId: pluginId(args),
|
|
18848
|
+
approvalId: assertResourceId(String(args["approval-id"]), "approval-id")
|
|
18849
|
+
})
|
|
18850
|
+
};
|
|
18851
|
+
}
|
|
18852
|
+
})
|
|
18853
|
+
);
|
|
18854
|
+
registry.define(
|
|
18855
|
+
createCommand({
|
|
18856
|
+
command: "plugin tool get",
|
|
18857
|
+
describe: "Show one plugin tool with its input/output schema",
|
|
18858
|
+
effects: "read_only",
|
|
18859
|
+
outputKind: "data",
|
|
18860
|
+
flags: [
|
|
18861
|
+
pluginIdFlag,
|
|
18862
|
+
{ name: "tool-id", type: "string", describe: "Tool ID (see adp plugin get)", required: true },
|
|
18863
|
+
{ name: "space-id", type: "string", describe: "Space ID (defaults to adp.jsonc)" }
|
|
18864
|
+
],
|
|
18865
|
+
examples: ["adp plugin tool get --plugin-id plg-1 --tool-id tool-1 --format json"],
|
|
18866
|
+
async handler(args) {
|
|
18867
|
+
const spaceId = await optionalSpaceId(ctx, args);
|
|
18868
|
+
const gateways = await ctx.deps.resolveGateways(ctx.flags);
|
|
18869
|
+
const id = pluginId(args);
|
|
18870
|
+
const toolId = assertResourceId(String(args["tool-id"]), "tool-id");
|
|
18871
|
+
const tool = await describePluginTool(gateways.pluginAccess, {
|
|
18872
|
+
pluginId: id,
|
|
18873
|
+
toolId,
|
|
18874
|
+
...spaceId ? { spaceId: assertResourceId(spaceId, "space-id") } : {}
|
|
18875
|
+
});
|
|
18876
|
+
const toolName = tool.name.trim();
|
|
18877
|
+
return {
|
|
18878
|
+
result: tool,
|
|
18879
|
+
nextActions: [
|
|
18880
|
+
{
|
|
18881
|
+
command: /^[A-Za-z0-9_-]+$/.test(toolName) ? `adp plugin tool call --plugin-id ${id} --tool-name ${toolName} --dry-run --format json` : `adp plugin tool call --plugin-id ${id} --tool-id ${toolId} --dry-run --format json`,
|
|
18882
|
+
reason: "preview a direct MCP call when this plugin is pluginKind=2; adp plugin key create saves the tool key"
|
|
18883
|
+
}
|
|
18884
|
+
]
|
|
18885
|
+
};
|
|
18886
|
+
}
|
|
18887
|
+
})
|
|
18888
|
+
);
|
|
18889
|
+
registry.define(
|
|
18890
|
+
createCommand({
|
|
18891
|
+
command: "plugin auth check",
|
|
18892
|
+
describe: "Check whether the caller has authorized OAuth plugins",
|
|
18893
|
+
effects: "read_only",
|
|
18894
|
+
outputKind: "data",
|
|
18895
|
+
flags: [
|
|
18896
|
+
{ name: "plugin-id", type: "string", describe: "Plugin ID (repeatable)", required: true, list: true },
|
|
18897
|
+
{ name: "credential-id", type: "string", describe: "OAuth credential ID, paired by position with --plugin-id" }
|
|
18898
|
+
],
|
|
18899
|
+
examples: ["adp plugin auth check --plugin-id plg-1 --credential-id cred-1 --format json"],
|
|
18900
|
+
async handler(args) {
|
|
18901
|
+
const pluginIds = strings6(args["plugin-id"]).map((id) => assertResourceId(id, "plugin-id"));
|
|
18902
|
+
const credentialIds = strings6(args["credential-id"]);
|
|
18903
|
+
const gateways = await ctx.deps.resolveGateways(ctx.flags);
|
|
18904
|
+
const items = await checkPluginAuth(gateways.pluginAccess, {
|
|
18905
|
+
items: pluginIds.map((id, i) => ({ pluginId: id, ...credentialIds[i] ? { credentialId: credentialIds[i] } : {} }))
|
|
18906
|
+
});
|
|
18907
|
+
return { result: { items } };
|
|
18908
|
+
}
|
|
18909
|
+
})
|
|
18910
|
+
);
|
|
18911
|
+
registry.define(
|
|
18912
|
+
createCommand({
|
|
18913
|
+
command: "plugin oauth-url",
|
|
18914
|
+
describe: "Create an OAuth consent link for an OAuth plugin credential; open it in a browser",
|
|
18915
|
+
effects: "non_idempotent",
|
|
18916
|
+
outputKind: "data",
|
|
18917
|
+
flags: [pluginIdFlag, { name: "credential-id", type: "string", describe: "OAuth credential ID", required: true }],
|
|
18918
|
+
examples: ["adp plugin oauth-url --plugin-id plg-1 --credential-id cred-1"],
|
|
18919
|
+
async handler(args) {
|
|
18920
|
+
const input = { pluginId: pluginId(args), credentialId: assertResourceId(String(args["credential-id"]), "credential-id") };
|
|
18921
|
+
if (ctx.flags.dryRun) {
|
|
18922
|
+
return { result: { dryRun: true, ...input }, message: `Would create an OAuth consent link for credential ${input.credentialId}.` };
|
|
18923
|
+
}
|
|
18924
|
+
const gateways = await ctx.deps.resolveGateways(ctx.flags);
|
|
18925
|
+
const { url } = await pluginOAuthUrl(gateways.pluginAccess, input);
|
|
18926
|
+
return { result: { url }, message: url };
|
|
18927
|
+
}
|
|
18928
|
+
})
|
|
18929
|
+
);
|
|
18930
|
+
}
|
|
18931
|
+
|
|
18932
|
+
// src/domain/plugin/tool-key.ts
|
|
18933
|
+
function maskToolKey(value) {
|
|
18934
|
+
if (value.includes("*")) {
|
|
18935
|
+
return value;
|
|
18936
|
+
}
|
|
18937
|
+
if (value.length <= 8) {
|
|
18938
|
+
return "****";
|
|
18939
|
+
}
|
|
18940
|
+
return `${value.slice(0, 4)}****${value.slice(-4)}`;
|
|
18941
|
+
}
|
|
18942
|
+
|
|
18943
|
+
// src/application/plugin/tool-key-use-cases.ts
|
|
18944
|
+
var CREATE_COMMAND = {
|
|
18945
|
+
command: "adp plugin key create --format json",
|
|
18946
|
+
reason: "create a tool key and save it for adp plugin tool call"
|
|
18947
|
+
};
|
|
18948
|
+
var LIST_COMMAND = {
|
|
18949
|
+
command: "adp plugin key list --format json",
|
|
18950
|
+
reason: "list tool key ids; the plaintext is only returned when a key is created"
|
|
18951
|
+
};
|
|
18952
|
+
function toolKeyLimitReached(error) {
|
|
18953
|
+
const message = error instanceof Error ? error.message : "";
|
|
18954
|
+
if (!message.includes("4509400")) {
|
|
18955
|
+
return void 0;
|
|
18956
|
+
}
|
|
18957
|
+
return new DomainError("This account already has the maximum of 2 tool keys (4509400)", "conflict", "ToolKeyLimitReached", {
|
|
18958
|
+
hint: "An existing key's plaintext cannot be read back. Run adp plugin key list. A lastAccessTime of 0 has never been used. After you confirm which key to drop, disable it, then delete it, and create again. Or set a plaintext you already hold as ADP_API_KEY.",
|
|
18959
|
+
retryable: false,
|
|
18960
|
+
requestId: error instanceof DomainError ? error.requestId : void 0,
|
|
18961
|
+
cause: error,
|
|
18962
|
+
nextActions: [
|
|
18963
|
+
{
|
|
18964
|
+
command: "adp plugin key list --format json",
|
|
18965
|
+
reason: "see key ids and lastAccessTime; 0 means unused. Confirm with the user before disabling one"
|
|
18966
|
+
},
|
|
18967
|
+
{
|
|
18968
|
+
command: "adp plugin key disable --format json",
|
|
18969
|
+
reason: "disable the confirmed key first; delete rejects a key that is still enabled",
|
|
18970
|
+
needs_input: { flag: "key-id", question: "Tool key ID from adp plugin key list" }
|
|
18971
|
+
},
|
|
18972
|
+
{
|
|
18973
|
+
command: "adp plugin key delete --yes --format json",
|
|
18974
|
+
reason: "after disable succeeds, pass the same --key-id, then adp plugin key create",
|
|
18975
|
+
needs_input: { flag: "key-id", question: "Tool key ID from adp plugin key list" }
|
|
18976
|
+
}
|
|
18977
|
+
]
|
|
18978
|
+
});
|
|
18979
|
+
}
|
|
18980
|
+
function toolKeyNotDisabled(error, apiKeyId) {
|
|
18981
|
+
const message = error instanceof Error ? error.message : "";
|
|
18982
|
+
if (!message.includes("4509404")) {
|
|
18983
|
+
return void 0;
|
|
18984
|
+
}
|
|
18985
|
+
return new DomainError(`Tool key ${apiKeyId} must be disabled before it can be deleted (4509404)`, "conflict", "ToolKeyNotDisabled", {
|
|
18986
|
+
hint: "Disable the key, then delete it. Disabling stops clients that use this key.",
|
|
18987
|
+
retryable: false,
|
|
18988
|
+
requestId: error instanceof DomainError ? error.requestId : void 0,
|
|
18989
|
+
cause: error,
|
|
18990
|
+
nextActions: [
|
|
18991
|
+
{
|
|
18992
|
+
command: `adp plugin key disable --key-id ${apiKeyId} --format json`,
|
|
18993
|
+
reason: "disable the key; DeleteApiKey rejects a key that is still enabled"
|
|
18994
|
+
},
|
|
18995
|
+
{
|
|
18996
|
+
command: `adp plugin key delete --key-id ${apiKeyId} --yes --format json`,
|
|
18997
|
+
reason: "delete the key after it is disabled"
|
|
18998
|
+
}
|
|
18999
|
+
]
|
|
19000
|
+
});
|
|
19001
|
+
}
|
|
19002
|
+
function toolKeyMissingError() {
|
|
19003
|
+
return new DomainError("MCP plugin calls need an ADP API Key (tool key)", "auth", "ToolKeyMissing", {
|
|
19004
|
+
hint: "Create one with adp plugin key create (it is saved to ~/.adp/tool-key), set ADP_API_KEY, or pass --api-key-env. Do not put the secret on the command line.",
|
|
19005
|
+
retryable: false,
|
|
19006
|
+
nextActions: [CREATE_COMMAND, LIST_COMMAND]
|
|
19007
|
+
});
|
|
19008
|
+
}
|
|
19009
|
+
async function resolveToolKey(input) {
|
|
19010
|
+
if (input.envName) {
|
|
19011
|
+
const value = (input.env[input.envName] ?? "").trim();
|
|
19012
|
+
if (!value) {
|
|
19013
|
+
throw new DomainError(`Environment variable ${input.envName} is empty`, "usage", "UsageError", {
|
|
19014
|
+
hint: "Export the ADP API Key in that variable, or omit --api-key-env to use ADP_API_KEY or ~/.adp/tool-key",
|
|
19015
|
+
retryable: false
|
|
19016
|
+
});
|
|
19017
|
+
}
|
|
19018
|
+
return { value, source: "api-key-env", envName: input.envName };
|
|
19019
|
+
}
|
|
19020
|
+
const fromEnv = (input.env.ADP_API_KEY ?? "").trim();
|
|
19021
|
+
if (fromEnv) {
|
|
19022
|
+
return { value: fromEnv, source: "env", envName: "ADP_API_KEY" };
|
|
19023
|
+
}
|
|
19024
|
+
const stored = await input.store.load();
|
|
19025
|
+
if (!stored?.value.trim()) {
|
|
19026
|
+
return void 0;
|
|
19027
|
+
}
|
|
19028
|
+
return { value: stored.value.trim(), source: "file", ...stored.apiKeyId ? { apiKeyId: stored.apiKeyId } : {} };
|
|
19029
|
+
}
|
|
19030
|
+
function viewOf(record) {
|
|
19031
|
+
return {
|
|
19032
|
+
apiKeyId: record.apiKeyId,
|
|
19033
|
+
apiKey: maskToolKey(record.apiKey),
|
|
19034
|
+
masked: true,
|
|
19035
|
+
description: record.description,
|
|
19036
|
+
...record.status !== void 0 ? { status: record.status, enabled: record.status === 1 } : {},
|
|
19037
|
+
...record.createTime ? { createTime: record.createTime } : {},
|
|
19038
|
+
...record.lastAccessTime ? { lastAccessTime: record.lastAccessTime } : {}
|
|
19039
|
+
};
|
|
19040
|
+
}
|
|
19041
|
+
async function listToolKeys(gateway) {
|
|
19042
|
+
const records20 = await gateway.list();
|
|
19043
|
+
return records20.map(viewOf);
|
|
19044
|
+
}
|
|
19045
|
+
async function requireKey(gateway, apiKeyId) {
|
|
19046
|
+
const found = (await listToolKeys(gateway)).find((item) => item.apiKeyId === apiKeyId);
|
|
19047
|
+
if (!found) {
|
|
19048
|
+
throw new DomainError(`No tool key with ID ${apiKeyId}`, "not_found", "ToolKeyNotFound", {
|
|
19049
|
+
hint: "List ids with adp plugin key list. The plaintext cannot be recovered from the list.",
|
|
19050
|
+
retryable: false,
|
|
19051
|
+
nextActions: [LIST_COMMAND]
|
|
19052
|
+
});
|
|
19053
|
+
}
|
|
19054
|
+
return found;
|
|
19055
|
+
}
|
|
19056
|
+
async function createToolKey(gateway, store, input) {
|
|
19057
|
+
const description = input.description?.trim() || void 0;
|
|
19058
|
+
if (input.dryRun) {
|
|
19059
|
+
return { dryRun: true, save: input.save, ...description ? { description } : {} };
|
|
19060
|
+
}
|
|
19061
|
+
let created;
|
|
19062
|
+
try {
|
|
19063
|
+
created = await gateway.create();
|
|
19064
|
+
} catch (error) {
|
|
19065
|
+
const limit = toolKeyLimitReached(error);
|
|
19066
|
+
if (limit) {
|
|
19067
|
+
throw limit;
|
|
19068
|
+
}
|
|
19069
|
+
throw error;
|
|
19070
|
+
}
|
|
19071
|
+
if (!created.apiKey || !created.apiKeyId) {
|
|
19072
|
+
throw new DomainError("CreateApiKey did not return a tool key", "upstream", "ToolKeyNotCreated", {
|
|
19073
|
+
hint: "Nothing was saved locally. Retry adp plugin key create.",
|
|
19074
|
+
retryable: true,
|
|
19075
|
+
nextActions: [CREATE_COMMAND]
|
|
19076
|
+
});
|
|
19077
|
+
}
|
|
19078
|
+
if (input.save) {
|
|
19079
|
+
await store.save({ value: created.apiKey, apiKeyId: created.apiKeyId });
|
|
19080
|
+
}
|
|
19081
|
+
if (description) {
|
|
19082
|
+
try {
|
|
19083
|
+
await gateway.update({ apiKeyId: created.apiKeyId, description });
|
|
19084
|
+
} catch (error) {
|
|
19085
|
+
throw new DomainError(
|
|
19086
|
+
input.save ? `Tool key ${created.apiKeyId} was saved locally, but the description was not updated` : `Tool key ${created.apiKeyId} was created, but the description was not updated. Plaintext: ${created.apiKey}`,
|
|
19087
|
+
"upstream",
|
|
19088
|
+
"ToolKeyDescriptionFailed",
|
|
19089
|
+
{
|
|
19090
|
+
cause: error,
|
|
19091
|
+
hint: input.save ? "The key is in ~/.adp/tool-key. Set the description with adp plugin key update." : "This is the only time the plaintext is available.",
|
|
19092
|
+
retryable: false,
|
|
19093
|
+
nextActions: [
|
|
19094
|
+
{
|
|
19095
|
+
command: `adp plugin key update --key-id ${created.apiKeyId} --format json`,
|
|
19096
|
+
reason: "retry the description",
|
|
19097
|
+
needs_input: { flag: "description", question: "Description for this tool key" }
|
|
19098
|
+
}
|
|
19099
|
+
]
|
|
19100
|
+
}
|
|
19101
|
+
);
|
|
19102
|
+
}
|
|
19103
|
+
}
|
|
19104
|
+
return {
|
|
19105
|
+
dryRun: false,
|
|
19106
|
+
apiKeyId: created.apiKeyId,
|
|
19107
|
+
apiKey: input.reveal ? created.apiKey : maskToolKey(created.apiKey),
|
|
19108
|
+
masked: !input.reveal,
|
|
19109
|
+
saved: input.save,
|
|
19110
|
+
...description ? { description } : {},
|
|
19111
|
+
...input.keepSecret ? { secret: created.apiKey } : {}
|
|
19112
|
+
};
|
|
19113
|
+
}
|
|
19114
|
+
async function setToolKeyStatus(gateway, input) {
|
|
19115
|
+
await requireKey(gateway, input.apiKeyId);
|
|
19116
|
+
if (!input.dryRun) {
|
|
19117
|
+
await gateway.setStatus({ apiKeyId: input.apiKeyId, status: input.status });
|
|
19118
|
+
}
|
|
19119
|
+
return { dryRun: input.dryRun, apiKeyId: input.apiKeyId, status: input.status, enabled: input.status === 1 };
|
|
19120
|
+
}
|
|
19121
|
+
async function updateToolKey(gateway, input) {
|
|
19122
|
+
await requireKey(gateway, input.apiKeyId);
|
|
19123
|
+
if (!input.dryRun) {
|
|
19124
|
+
await gateway.update({ apiKeyId: input.apiKeyId, description: input.description });
|
|
19125
|
+
}
|
|
19126
|
+
return { dryRun: input.dryRun, apiKeyId: input.apiKeyId, description: input.description };
|
|
19127
|
+
}
|
|
19128
|
+
async function deleteToolKey(gateway, store, input) {
|
|
19129
|
+
await requireKey(gateway, input.apiKeyId);
|
|
19130
|
+
if (input.dryRun) {
|
|
19131
|
+
return { dryRun: true, apiKeyId: input.apiKeyId, localKeyCleared: false };
|
|
19132
|
+
}
|
|
19133
|
+
try {
|
|
19134
|
+
await gateway.delete({ apiKeyId: input.apiKeyId });
|
|
19135
|
+
} catch (error) {
|
|
19136
|
+
const notDisabled = toolKeyNotDisabled(error, input.apiKeyId);
|
|
19137
|
+
if (notDisabled) {
|
|
19138
|
+
throw notDisabled;
|
|
19139
|
+
}
|
|
19140
|
+
throw error;
|
|
19141
|
+
}
|
|
19142
|
+
const stored = await store.load();
|
|
19143
|
+
const localKeyCleared = stored?.apiKeyId === input.apiKeyId;
|
|
19144
|
+
if (localKeyCleared) {
|
|
19145
|
+
await store.clear();
|
|
19146
|
+
}
|
|
19147
|
+
return { dryRun: false, apiKeyId: input.apiKeyId, localKeyCleared };
|
|
19148
|
+
}
|
|
19149
|
+
|
|
19150
|
+
// src/interfaces/cli/commands/plugin/key.ts
|
|
19151
|
+
var keyIdFlag = { name: "key-id", type: "string", describe: "Tool key ID (adp plugin key list)", required: true };
|
|
19152
|
+
var revealFlag4 = {
|
|
19153
|
+
name: "reveal",
|
|
19154
|
+
type: "boolean",
|
|
19155
|
+
describe: "Print the plaintext tool key. Otherwise it is masked. The plaintext is only available at creation."
|
|
19156
|
+
};
|
|
19157
|
+
function storeOf(ctx) {
|
|
19158
|
+
return ctx.deps.toolKeyStore ?? createToolKeyFileStore(adpToolKeyPath());
|
|
19159
|
+
}
|
|
19160
|
+
function savedNote(saved) {
|
|
19161
|
+
return saved ? " Saved to ~/.adp/tool-key for later adp plugin tool call." : "";
|
|
19162
|
+
}
|
|
19163
|
+
function registerPluginKeyCommands(registry, ctx) {
|
|
17990
19164
|
registry.define(
|
|
17991
19165
|
createCommand({
|
|
17992
|
-
command: "plugin
|
|
17993
|
-
describe: "
|
|
19166
|
+
command: "plugin key list",
|
|
19167
|
+
describe: "List ADP API keys (tool keys). Values are masked; plaintext exists only at creation.",
|
|
17994
19168
|
effects: "read_only",
|
|
17995
19169
|
outputKind: "data",
|
|
17996
|
-
flags: [
|
|
17997
|
-
examples: ["adp plugin
|
|
17998
|
-
async handler(
|
|
19170
|
+
flags: [],
|
|
19171
|
+
examples: ["adp plugin key list --format json"],
|
|
19172
|
+
async handler() {
|
|
17999
19173
|
const gateways = await ctx.deps.resolveGateways(ctx.flags);
|
|
18000
|
-
|
|
18001
|
-
|
|
18002
|
-
|
|
18003
|
-
|
|
19174
|
+
const items = await listToolKeys(gateways.toolKey);
|
|
19175
|
+
return applyListShape(
|
|
19176
|
+
ctx,
|
|
19177
|
+
sliceResult(items, { limit: ctx.flags.limit, page: ctx.flags.page }),
|
|
19178
|
+
"adp plugin key list"
|
|
19179
|
+
);
|
|
18004
19180
|
}
|
|
18005
19181
|
})
|
|
18006
19182
|
);
|
|
18007
19183
|
registry.define(
|
|
18008
19184
|
createCommand({
|
|
18009
|
-
command: "plugin
|
|
18010
|
-
describe: "
|
|
18011
|
-
effects: "
|
|
19185
|
+
command: "plugin key create",
|
|
19186
|
+
describe: "Create an ADP API key (tool key) and save it to ~/.adp/tool-key so adp plugin tool call can use it",
|
|
19187
|
+
effects: "non_idempotent",
|
|
18012
19188
|
outputKind: "data",
|
|
18013
19189
|
flags: [
|
|
18014
|
-
|
|
18015
|
-
|
|
18016
|
-
{
|
|
18017
|
-
|
|
18018
|
-
|
|
18019
|
-
|
|
18020
|
-
|
|
19190
|
+
{ name: "description", type: "string", describe: "Note stored on the key (ModifyApiKey)" },
|
|
19191
|
+
revealFlag4,
|
|
19192
|
+
{
|
|
19193
|
+
name: "save",
|
|
19194
|
+
type: "boolean",
|
|
19195
|
+
default: true,
|
|
19196
|
+
describe: "Save the new key to ~/.adp/tool-key (mode 0600). Pass --no-save to skip; then --reveal is required, because the plaintext is returned only once."
|
|
19197
|
+
}
|
|
18021
19198
|
],
|
|
18022
19199
|
examples: [
|
|
18023
|
-
"adp plugin
|
|
18024
|
-
"adp plugin
|
|
19200
|
+
"adp plugin key create --format json",
|
|
19201
|
+
"adp plugin key create --description kling --reveal --format json",
|
|
19202
|
+
"adp plugin key create --no-save --reveal --format json"
|
|
18025
19203
|
],
|
|
18026
19204
|
async handler(args) {
|
|
18027
|
-
const
|
|
18028
|
-
|
|
18029
|
-
if (
|
|
18030
|
-
|
|
18031
|
-
|
|
18032
|
-
|
|
18033
|
-
|
|
18034
|
-
plugin = { scope, spaceIds: [...new Set(strings6(args.space).map((s) => assertResourceId(s, "space")))] };
|
|
18035
|
-
} else if (args.space !== void 0) {
|
|
18036
|
-
throw usageError("--space needs --scope spaces");
|
|
19205
|
+
const save = args.save !== false;
|
|
19206
|
+
const reveal = args.reveal === true;
|
|
19207
|
+
if (!save && !reveal) {
|
|
19208
|
+
throw usageError(
|
|
19209
|
+
"Refusing to create a tool key that cannot be recovered",
|
|
19210
|
+
"The plaintext is returned only once. Omit --no-save to store it in ~/.adp/tool-key, or pass --reveal to print it."
|
|
19211
|
+
);
|
|
18037
19212
|
}
|
|
18038
|
-
const
|
|
18039
|
-
|
|
18040
|
-
|
|
18041
|
-
|
|
19213
|
+
const description = typeof args.description === "string" ? args.description : void 0;
|
|
19214
|
+
const created = await createToolKey(
|
|
19215
|
+
(await ctx.deps.resolveGateways(ctx.flags)).toolKey,
|
|
19216
|
+
storeOf(ctx),
|
|
19217
|
+
{ description, reveal, save, dryRun: ctx.flags.dryRun }
|
|
19218
|
+
);
|
|
19219
|
+
if (created.dryRun) {
|
|
19220
|
+
return {
|
|
19221
|
+
result: created,
|
|
19222
|
+
message: save ? "Would create a tool key and save it to ~/.adp/tool-key." : "Would create a tool key and print it. Nothing is saved."
|
|
19223
|
+
};
|
|
18042
19224
|
}
|
|
18043
|
-
const
|
|
18044
|
-
const result = await setPluginShare(gateways.pluginAccess, {
|
|
18045
|
-
pluginId: id,
|
|
18046
|
-
plugin,
|
|
18047
|
-
credentials,
|
|
18048
|
-
remark: typeof args.remark === "string" ? args.remark : void 0,
|
|
18049
|
-
force: args.force === true,
|
|
18050
|
-
confirmedName: typeof args["confirm-name"] === "string" ? args["confirm-name"] : void 0
|
|
18051
|
-
});
|
|
19225
|
+
const { secret: _secret, ...result } = created;
|
|
18052
19226
|
return {
|
|
18053
19227
|
result,
|
|
18054
|
-
message:
|
|
19228
|
+
message: `Created tool key ${result.apiKey}.${savedNote(result.saved)}`,
|
|
18055
19229
|
nextActions: [
|
|
19230
|
+
{ command: "adp plugin key list --format json", reason: "confirm the new key id; the list stays masked" },
|
|
18056
19231
|
{
|
|
18057
|
-
command:
|
|
18058
|
-
reason:
|
|
19232
|
+
command: "adp plugin list --fields pluginId,name,pluginKind --format json",
|
|
19233
|
+
reason: "pick a pluginKind=2 plugin, then adp plugin tool call"
|
|
18059
19234
|
}
|
|
18060
19235
|
]
|
|
18061
19236
|
};
|
|
@@ -18064,86 +19239,397 @@ function registerPluginAccessCommands(registry, ctx) {
|
|
|
18064
19239
|
);
|
|
18065
19240
|
registry.define(
|
|
18066
19241
|
createCommand({
|
|
18067
|
-
command: "plugin
|
|
18068
|
-
describe: "
|
|
18069
|
-
effects: "
|
|
19242
|
+
command: "plugin key update",
|
|
19243
|
+
describe: "Change an ADP API key's description",
|
|
19244
|
+
effects: "idempotent",
|
|
18070
19245
|
outputKind: "data",
|
|
18071
|
-
flags: [
|
|
18072
|
-
|
|
19246
|
+
flags: [
|
|
19247
|
+
keyIdFlag,
|
|
19248
|
+
{ name: "description", type: "string", describe: "New note", required: true }
|
|
19249
|
+
],
|
|
19250
|
+
examples: ["adp plugin key update --key-id key-1 --description kling --format json"],
|
|
18073
19251
|
async handler(args) {
|
|
19252
|
+
const apiKeyId = assertResourceId(String(args["key-id"]), "key-id");
|
|
19253
|
+
const description = String(args.description ?? "").trim();
|
|
19254
|
+
if (!description) {
|
|
19255
|
+
throw usageError("Missing --description", "Pass the note to store on this tool key");
|
|
19256
|
+
}
|
|
18074
19257
|
const gateways = await ctx.deps.resolveGateways(ctx.flags);
|
|
19258
|
+
const result = await updateToolKey(gateways.toolKey, { apiKeyId, description, dryRun: ctx.flags.dryRun });
|
|
18075
19259
|
return {
|
|
18076
|
-
result
|
|
18077
|
-
|
|
18078
|
-
approvalId: assertResourceId(String(args["approval-id"]), "approval-id")
|
|
18079
|
-
})
|
|
19260
|
+
result,
|
|
19261
|
+
message: ctx.flags.dryRun ? `Would update the description of tool key ${apiKeyId}.` : `Updated tool key ${apiKeyId}.`
|
|
18080
19262
|
};
|
|
18081
19263
|
}
|
|
18082
19264
|
})
|
|
18083
19265
|
);
|
|
19266
|
+
for (const enabled of [true, false]) {
|
|
19267
|
+
const verb = enabled ? "enable" : "disable";
|
|
19268
|
+
const status = enabled ? 1 : 2;
|
|
19269
|
+
registry.define(
|
|
19270
|
+
createCommand({
|
|
19271
|
+
command: `plugin key ${verb}`,
|
|
19272
|
+
describe: enabled ? "Enable an ADP API key (status 1). A disabled key cannot call MCP plugins." : "Disable an ADP API key (status 2). Delete requires the key to be disabled first.",
|
|
19273
|
+
effects: "idempotent",
|
|
19274
|
+
outputKind: "data",
|
|
19275
|
+
flags: [keyIdFlag],
|
|
19276
|
+
examples: [`adp plugin key ${verb} --key-id key-1 --format json`],
|
|
19277
|
+
async handler(args) {
|
|
19278
|
+
const apiKeyId = assertResourceId(String(args["key-id"]), "key-id");
|
|
19279
|
+
const gateways = await ctx.deps.resolveGateways(ctx.flags);
|
|
19280
|
+
const result = await setToolKeyStatus(gateways.toolKey, { apiKeyId, status, dryRun: ctx.flags.dryRun });
|
|
19281
|
+
if (ctx.flags.dryRun) {
|
|
19282
|
+
return { result, message: `Would ${verb} tool key ${apiKeyId}.` };
|
|
19283
|
+
}
|
|
19284
|
+
return { result, message: `${enabled ? "Enabled" : "Disabled"} tool key ${apiKeyId}.` };
|
|
19285
|
+
}
|
|
19286
|
+
})
|
|
19287
|
+
);
|
|
19288
|
+
}
|
|
18084
19289
|
registry.define(
|
|
18085
19290
|
createCommand({
|
|
18086
|
-
command: "plugin
|
|
18087
|
-
describe: "
|
|
18088
|
-
effects: "
|
|
19291
|
+
command: "plugin key delete",
|
|
19292
|
+
describe: "Delete an ADP API key. Clients using it stop working. A matching ~/.adp/tool-key is removed.",
|
|
19293
|
+
effects: "non_idempotent",
|
|
18089
19294
|
outputKind: "data",
|
|
18090
|
-
flags: [
|
|
18091
|
-
|
|
18092
|
-
{ name: "tool-id", type: "string", describe: "Tool ID (see adp plugin get)", required: true },
|
|
18093
|
-
{ name: "space-id", type: "string", describe: "Space ID (defaults to adp.jsonc)" }
|
|
18094
|
-
],
|
|
18095
|
-
examples: ["adp plugin tool get --plugin-id plg-1 --tool-id tool-1 --format json"],
|
|
19295
|
+
flags: [keyIdFlag],
|
|
19296
|
+
examples: ["adp plugin key delete --key-id key-1 --yes"],
|
|
18096
19297
|
async handler(args) {
|
|
18097
|
-
const
|
|
19298
|
+
const apiKeyId = assertResourceId(String(args["key-id"]), "key-id");
|
|
19299
|
+
await requireYes(ctx, `delete tool key ${apiKeyId}`);
|
|
18098
19300
|
const gateways = await ctx.deps.resolveGateways(ctx.flags);
|
|
19301
|
+
const result = await deleteToolKey(gateways.toolKey, storeOf(ctx), { apiKeyId, dryRun: ctx.flags.dryRun });
|
|
18099
19302
|
return {
|
|
18100
|
-
result
|
|
18101
|
-
|
|
18102
|
-
toolId: assertResourceId(String(args["tool-id"]), "tool-id"),
|
|
18103
|
-
...spaceId ? { spaceId: assertResourceId(spaceId, "space-id") } : {}
|
|
18104
|
-
})
|
|
19303
|
+
result,
|
|
19304
|
+
message: ctx.flags.dryRun ? `Would delete tool key ${apiKeyId}.` : `Deleted tool key ${apiKeyId}.`
|
|
18105
19305
|
};
|
|
18106
19306
|
}
|
|
18107
19307
|
})
|
|
18108
19308
|
);
|
|
19309
|
+
}
|
|
19310
|
+
|
|
19311
|
+
// src/application/plugin/plugin-mcp-use-cases.ts
|
|
19312
|
+
async function prepareToolKey(gateway, store, input) {
|
|
19313
|
+
const existing = await resolveToolKey({ env: input.env, envName: input.envName, store });
|
|
19314
|
+
if (existing) {
|
|
19315
|
+
return {
|
|
19316
|
+
value: existing.value,
|
|
19317
|
+
source: existing.source,
|
|
19318
|
+
...existing.apiKeyId ? { apiKeyId: existing.apiKeyId } : {},
|
|
19319
|
+
created: false,
|
|
19320
|
+
wouldCreate: false,
|
|
19321
|
+
hasKey: true
|
|
19322
|
+
};
|
|
19323
|
+
}
|
|
19324
|
+
if (!input.autoCreate) {
|
|
19325
|
+
if (input.dryRun) {
|
|
19326
|
+
return { created: false, wouldCreate: false, hasKey: false };
|
|
19327
|
+
}
|
|
19328
|
+
throw toolKeyMissingError();
|
|
19329
|
+
}
|
|
19330
|
+
if (input.dryRun) {
|
|
19331
|
+
return { created: false, wouldCreate: true, hasKey: false };
|
|
19332
|
+
}
|
|
19333
|
+
if (!gateway) {
|
|
19334
|
+
throw new DomainError("Creating a tool key needs cloud credentials", "auth", "ToolKeyMissing", {
|
|
19335
|
+
hint: "Run adp auth status, then retry with --auto-create-key, or create a key with adp plugin key create.",
|
|
19336
|
+
retryable: false,
|
|
19337
|
+
nextActions: [
|
|
19338
|
+
{ command: "adp auth status --format json", reason: "check the CAM credential used to call CreateApiKey" },
|
|
19339
|
+
{ command: "adp plugin key create --format json", reason: "create and save a tool key" }
|
|
19340
|
+
]
|
|
19341
|
+
});
|
|
19342
|
+
}
|
|
19343
|
+
const created = await createToolKey(gateway, store, { reveal: false, save: true, dryRun: false, keepSecret: true });
|
|
19344
|
+
if (created.dryRun || !created.secret) {
|
|
19345
|
+
throw new DomainError("CreateApiKey did not return a tool key", "upstream", "ToolKeyNotCreated", { retryable: true });
|
|
19346
|
+
}
|
|
19347
|
+
return { value: created.secret, source: "created", apiKeyId: created.apiKeyId, created: true, wouldCreate: false, hasKey: true };
|
|
19348
|
+
}
|
|
19349
|
+
async function resolveToolName(tools, input) {
|
|
19350
|
+
const name = input.toolName?.trim() || void 0;
|
|
19351
|
+
if (!input.toolId) {
|
|
19352
|
+
if (!name) {
|
|
19353
|
+
throw new DomainError("Pass --tool-name or --tool-id", "usage", "UsageError", {
|
|
19354
|
+
hint: "Tool names are on adp plugin get. --tool-id is resolved to that name.",
|
|
19355
|
+
retryable: false,
|
|
19356
|
+
nextActions: [
|
|
19357
|
+
{
|
|
19358
|
+
command: "adp plugin list --fields pluginId,name,pluginKind --format json",
|
|
19359
|
+
reason: "find a pluginKind=2 plugin, then read its tools"
|
|
19360
|
+
}
|
|
19361
|
+
]
|
|
19362
|
+
});
|
|
19363
|
+
}
|
|
19364
|
+
return name;
|
|
19365
|
+
}
|
|
19366
|
+
if (!tools) {
|
|
19367
|
+
throw new DomainError("--tool-id needs cloud credentials to look up the tool name", "auth", "AuthFailure", {
|
|
19368
|
+
hint: "Pass --tool-name to skip the lookup, or run adp auth status and retry.",
|
|
19369
|
+
retryable: false,
|
|
19370
|
+
nextActions: [{ command: "adp auth status --format json", reason: "check the CAM credential used to describe the tool" }]
|
|
19371
|
+
});
|
|
19372
|
+
}
|
|
19373
|
+
const detail = await describePluginTool(tools, {
|
|
19374
|
+
pluginId: input.pluginId,
|
|
19375
|
+
toolId: input.toolId,
|
|
19376
|
+
...input.spaceId ? { spaceId: input.spaceId } : {}
|
|
19377
|
+
});
|
|
19378
|
+
if (name && detail.name !== name) {
|
|
19379
|
+
throw new DomainError(
|
|
19380
|
+
`--tool-name ${name} does not match tool ${input.toolId} (${detail.name})`,
|
|
19381
|
+
"usage",
|
|
19382
|
+
"UsageError",
|
|
19383
|
+
{ hint: "Omit one of the two flags, or pass the name adp plugin tool get prints.", retryable: false }
|
|
19384
|
+
);
|
|
19385
|
+
}
|
|
19386
|
+
if (!detail.name) {
|
|
19387
|
+
throw new DomainError(`Tool ${input.toolId} has no name`, "not_found", "PluginToolNotFound", { retryable: false });
|
|
19388
|
+
}
|
|
19389
|
+
return detail.name;
|
|
19390
|
+
}
|
|
19391
|
+
async function callPluginMcpTool(deps, input) {
|
|
19392
|
+
const url = pluginMcpUrl(input.pluginId);
|
|
19393
|
+
const toolName = await resolveToolName(deps.tools, input);
|
|
19394
|
+
const key = await prepareToolKey(deps.toolKeys, deps.store, input);
|
|
19395
|
+
const base = {
|
|
19396
|
+
dryRun: input.dryRun,
|
|
19397
|
+
url,
|
|
19398
|
+
pluginId: input.pluginId,
|
|
19399
|
+
toolName,
|
|
19400
|
+
...input.toolId ? { toolId: input.toolId } : {},
|
|
19401
|
+
arguments: input.arguments,
|
|
19402
|
+
...key.source ? { apiKeySource: key.source } : {},
|
|
19403
|
+
...key.apiKeyId ? { apiKeyId: key.apiKeyId } : {},
|
|
19404
|
+
apiKeyCreated: key.created,
|
|
19405
|
+
wouldCreateKey: key.wouldCreate,
|
|
19406
|
+
hasKey: key.hasKey
|
|
19407
|
+
};
|
|
19408
|
+
if (input.dryRun || !key.value) {
|
|
19409
|
+
return base;
|
|
19410
|
+
}
|
|
19411
|
+
const output = await deps.mcp.callTool({
|
|
19412
|
+
pluginId: input.pluginId,
|
|
19413
|
+
apiKey: key.value,
|
|
19414
|
+
toolName,
|
|
19415
|
+
arguments: input.arguments,
|
|
19416
|
+
timeoutMs: input.timeoutMs
|
|
19417
|
+
});
|
|
19418
|
+
return { ...base, output };
|
|
19419
|
+
}
|
|
19420
|
+
async function listPluginMcpTools(deps, input) {
|
|
19421
|
+
const url = pluginMcpUrl(input.pluginId);
|
|
19422
|
+
const key = await prepareToolKey(deps.toolKeys, deps.store, input);
|
|
19423
|
+
const base = {
|
|
19424
|
+
dryRun: input.dryRun,
|
|
19425
|
+
url,
|
|
19426
|
+
pluginId: input.pluginId,
|
|
19427
|
+
...key.source ? { apiKeySource: key.source } : {},
|
|
19428
|
+
...key.apiKeyId ? { apiKeyId: key.apiKeyId } : {},
|
|
19429
|
+
apiKeyCreated: key.created,
|
|
19430
|
+
wouldCreateKey: key.wouldCreate,
|
|
19431
|
+
hasKey: key.hasKey
|
|
19432
|
+
};
|
|
19433
|
+
if (input.dryRun || !key.value) {
|
|
19434
|
+
return base;
|
|
19435
|
+
}
|
|
19436
|
+
const tools = await deps.mcp.listTools({ pluginId: input.pluginId, apiKey: key.value, timeoutMs: input.timeoutMs });
|
|
19437
|
+
return { ...base, tools };
|
|
19438
|
+
}
|
|
19439
|
+
|
|
19440
|
+
// src/interfaces/cli/commands/plugin/tool-call.ts
|
|
19441
|
+
var ENV_NAME = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
19442
|
+
var DEFAULT_TIMEOUT_MS3 = 6e4;
|
|
19443
|
+
var MAX_TIMEOUT_MS = 6e5;
|
|
19444
|
+
var pluginIdFlag2 = {
|
|
19445
|
+
name: "plugin-id",
|
|
19446
|
+
type: "string",
|
|
19447
|
+
describe: "Plugin ID. The call goes to https://adp.cloud.tencent.com/plugin/mcp/<pluginId>/mcp",
|
|
19448
|
+
required: true
|
|
19449
|
+
};
|
|
19450
|
+
var apiKeyEnvFlag = {
|
|
19451
|
+
name: "api-key-env",
|
|
19452
|
+
type: "string",
|
|
19453
|
+
describe: "Environment variable holding the ADP API Key. Default: ADP_API_KEY, then ~/.adp/tool-key. The secret is never a flag."
|
|
19454
|
+
};
|
|
19455
|
+
var autoCreateFlag = {
|
|
19456
|
+
name: "auto-create-key",
|
|
19457
|
+
type: "boolean",
|
|
19458
|
+
describe: "When no tool key is available, create one, save it to ~/.adp/tool-key, and use it. The plaintext is not printed."
|
|
19459
|
+
};
|
|
19460
|
+
var timeoutFlag = {
|
|
19461
|
+
name: "timeout-ms",
|
|
19462
|
+
type: "number",
|
|
19463
|
+
default: DEFAULT_TIMEOUT_MS3,
|
|
19464
|
+
describe: "MCP HTTP timeout in milliseconds"
|
|
19465
|
+
};
|
|
19466
|
+
function dryRunMessage(result, preview, done) {
|
|
19467
|
+
if (!result.dryRun) {
|
|
19468
|
+
return done;
|
|
19469
|
+
}
|
|
19470
|
+
if (result.wouldCreateKey) {
|
|
19471
|
+
return `Would create a tool key and ${preview}.`;
|
|
19472
|
+
}
|
|
19473
|
+
if (!result.hasKey) {
|
|
19474
|
+
return `Would ${preview}. No tool key is loaded; create one or pass --auto-create-key before the real call.`;
|
|
19475
|
+
}
|
|
19476
|
+
return `Would ${preview}.`;
|
|
19477
|
+
}
|
|
19478
|
+
function keyNeeded(result) {
|
|
19479
|
+
if (!result.dryRun || result.hasKey || result.wouldCreateKey) {
|
|
19480
|
+
return void 0;
|
|
19481
|
+
}
|
|
19482
|
+
return [
|
|
19483
|
+
{
|
|
19484
|
+
command: "adp plugin key create --format json",
|
|
19485
|
+
reason: "save a tool key before the real call, or rerun with --auto-create-key"
|
|
19486
|
+
}
|
|
19487
|
+
];
|
|
19488
|
+
}
|
|
19489
|
+
function storeOf2(ctx) {
|
|
19490
|
+
return ctx.deps.toolKeyStore ?? createToolKeyFileStore(adpToolKeyPath());
|
|
19491
|
+
}
|
|
19492
|
+
function mcpOf(ctx) {
|
|
19493
|
+
return ctx.deps.pluginMcp ?? createPluginMcpGateway();
|
|
19494
|
+
}
|
|
19495
|
+
function envName(value) {
|
|
19496
|
+
if (typeof value !== "string" || !value.trim()) {
|
|
19497
|
+
return void 0;
|
|
19498
|
+
}
|
|
19499
|
+
const name = value.trim();
|
|
19500
|
+
if (!ENV_NAME.test(name)) {
|
|
19501
|
+
throw usageError("--api-key-env must be an environment variable name", "Example: --api-key-env ADP_API_KEY");
|
|
19502
|
+
}
|
|
19503
|
+
return name;
|
|
19504
|
+
}
|
|
19505
|
+
function timeoutMs(value) {
|
|
19506
|
+
const parsed = value === void 0 ? DEFAULT_TIMEOUT_MS3 : Number(value);
|
|
19507
|
+
if (!Number.isInteger(parsed) || parsed < 1 || parsed > MAX_TIMEOUT_MS) {
|
|
19508
|
+
throw usageError("--timeout-ms must be an integer from 1 to 600000");
|
|
19509
|
+
}
|
|
19510
|
+
return parsed;
|
|
19511
|
+
}
|
|
19512
|
+
function toolArguments(args) {
|
|
19513
|
+
const input = args.input;
|
|
19514
|
+
const alias = args.args;
|
|
19515
|
+
if (typeof input === "string" && typeof alias === "string" && input !== alias) {
|
|
19516
|
+
throw usageError("Pass only one of --input or --args", "Both are the JSON object sent as the tool arguments");
|
|
19517
|
+
}
|
|
19518
|
+
const raw = typeof input === "string" ? input : typeof alias === "string" ? alias : void 0;
|
|
19519
|
+
if (raw === void 0 || !raw.trim()) {
|
|
19520
|
+
return {};
|
|
19521
|
+
}
|
|
19522
|
+
let parsed;
|
|
19523
|
+
try {
|
|
19524
|
+
parsed = JSON.parse(raw);
|
|
19525
|
+
} catch {
|
|
19526
|
+
throw usageError("--input must be a JSON object", `Example: --input '{"prompt":"a cat"}'`);
|
|
19527
|
+
}
|
|
19528
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
19529
|
+
throw usageError("--input must be a JSON object", "Arrays and scalars are rejected. Pass {} for no arguments.");
|
|
19530
|
+
}
|
|
19531
|
+
return parsed;
|
|
19532
|
+
}
|
|
19533
|
+
function pluginId2(args) {
|
|
19534
|
+
return assertResourceId(String(args["plugin-id"]), "plugin-id");
|
|
19535
|
+
}
|
|
19536
|
+
function registerPluginToolCallCommands(registry, ctx) {
|
|
18109
19537
|
registry.define(
|
|
18110
19538
|
createCommand({
|
|
18111
|
-
command: "plugin
|
|
18112
|
-
describe: "
|
|
19539
|
+
command: "plugin tool list",
|
|
19540
|
+
describe: "List tools on a platform MCP plugin over Streamable HTTP (not the catalog from plugin get)",
|
|
18113
19541
|
effects: "read_only",
|
|
18114
19542
|
outputKind: "data",
|
|
18115
|
-
flags: [
|
|
18116
|
-
|
|
18117
|
-
|
|
18118
|
-
|
|
18119
|
-
|
|
18120
|
-
|
|
18121
|
-
const
|
|
18122
|
-
const
|
|
18123
|
-
const gateways = await ctx.deps.resolveGateways(ctx.flags);
|
|
18124
|
-
const
|
|
18125
|
-
|
|
18126
|
-
|
|
18127
|
-
|
|
19543
|
+
flags: [pluginIdFlag2, apiKeyEnvFlag, autoCreateFlag, timeoutFlag],
|
|
19544
|
+
examples: ["adp plugin tool list --plugin-id plg-1 --format json"],
|
|
19545
|
+
async handler(args) {
|
|
19546
|
+
const id = pluginId2(args);
|
|
19547
|
+
const name = envName(args["api-key-env"]);
|
|
19548
|
+
const store = storeOf2(ctx);
|
|
19549
|
+
const autoCreate = args["auto-create-key"] === true;
|
|
19550
|
+
const existing = await resolveToolKey({ env: ctx.deps.env, envName: name, store });
|
|
19551
|
+
const gateways = autoCreate && !existing && !ctx.flags.dryRun ? await ctx.deps.resolveGateways(ctx.flags) : void 0;
|
|
19552
|
+
const result = await listPluginMcpTools(
|
|
19553
|
+
{ mcp: mcpOf(ctx), store, ...gateways ? { toolKeys: gateways.toolKey } : {} },
|
|
19554
|
+
{
|
|
19555
|
+
pluginId: id,
|
|
19556
|
+
env: ctx.deps.env,
|
|
19557
|
+
...name ? { envName: name } : {},
|
|
19558
|
+
autoCreate,
|
|
19559
|
+
timeoutMs: timeoutMs(args["timeout-ms"]),
|
|
19560
|
+
dryRun: ctx.flags.dryRun
|
|
19561
|
+
}
|
|
19562
|
+
);
|
|
19563
|
+
return {
|
|
19564
|
+
result,
|
|
19565
|
+
message: dryRunMessage(result, `list tools at ${result.url}`, `Listed tools at ${result.url}.`),
|
|
19566
|
+
nextActions: keyNeeded(result)
|
|
19567
|
+
};
|
|
18128
19568
|
}
|
|
18129
19569
|
})
|
|
18130
19570
|
);
|
|
18131
19571
|
registry.define(
|
|
18132
19572
|
createCommand({
|
|
18133
|
-
command: "plugin
|
|
18134
|
-
describe: "
|
|
19573
|
+
command: "plugin tool call",
|
|
19574
|
+
describe: "Call one tool on a platform MCP plugin (pluginKind=2). Auth is a tool key, not a command-line secret.",
|
|
18135
19575
|
effects: "non_idempotent",
|
|
18136
19576
|
outputKind: "data",
|
|
18137
|
-
flags: [
|
|
18138
|
-
|
|
19577
|
+
flags: [
|
|
19578
|
+
pluginIdFlag2,
|
|
19579
|
+
{ name: "tool-name", type: "string", describe: "Tool name, such as SubmitKlingTextToVideoJob. Required unless --tool-id is set." },
|
|
19580
|
+
{ name: "tool-id", type: "string", describe: "Tool ID from adp plugin get. Resolved to the tool name when --tool-name is omitted." },
|
|
19581
|
+
{ name: "input", type: "string", describe: "JSON object of tool arguments. Default {}." },
|
|
19582
|
+
{ name: "args", type: "string", describe: "Alias of --input" },
|
|
19583
|
+
{ name: "space-id", type: "string", describe: "Space ID used only to resolve --tool-id (defaults to adp.jsonc)" },
|
|
19584
|
+
apiKeyEnvFlag,
|
|
19585
|
+
autoCreateFlag,
|
|
19586
|
+
timeoutFlag
|
|
19587
|
+
],
|
|
19588
|
+
examples: [
|
|
19589
|
+
"adp plugin tool call --plugin-id plg-1 --tool-name SubmitJob --input '{}' --format json",
|
|
19590
|
+
"adp plugin tool call --plugin-id plg-1 --tool-id tool-1 --dry-run --format json",
|
|
19591
|
+
"adp plugin tool call --plugin-id plg-1 --tool-name SubmitJob --auto-create-key --format json"
|
|
19592
|
+
],
|
|
18139
19593
|
async handler(args) {
|
|
18140
|
-
const
|
|
18141
|
-
|
|
18142
|
-
|
|
18143
|
-
|
|
18144
|
-
const
|
|
18145
|
-
const
|
|
18146
|
-
|
|
19594
|
+
const id = pluginId2(args);
|
|
19595
|
+
const toolName = typeof args["tool-name"] === "string" && args["tool-name"].trim() ? args["tool-name"].trim() : void 0;
|
|
19596
|
+
const toolId = typeof args["tool-id"] === "string" && args["tool-id"].trim() ? assertResourceId(args["tool-id"].trim(), "tool-id") : void 0;
|
|
19597
|
+
const name = envName(args["api-key-env"]);
|
|
19598
|
+
const store = storeOf2(ctx);
|
|
19599
|
+
const autoCreate = args["auto-create-key"] === true;
|
|
19600
|
+
const spaceId = await optionalSpaceId(ctx, args);
|
|
19601
|
+
const existing = await resolveToolKey({ env: ctx.deps.env, envName: name, store });
|
|
19602
|
+
const needCloud = Boolean(toolId) || autoCreate && !existing && !ctx.flags.dryRun;
|
|
19603
|
+
const gateways = needCloud ? await ctx.deps.resolveGateways(ctx.flags) : void 0;
|
|
19604
|
+
const result = await callPluginMcpTool(
|
|
19605
|
+
{
|
|
19606
|
+
mcp: mcpOf(ctx),
|
|
19607
|
+
store,
|
|
19608
|
+
...gateways ? { tools: gateways.pluginAccess, toolKeys: gateways.toolKey } : {}
|
|
19609
|
+
},
|
|
19610
|
+
{
|
|
19611
|
+
pluginId: id,
|
|
19612
|
+
...toolName ? { toolName } : {},
|
|
19613
|
+
...toolId ? { toolId } : {},
|
|
19614
|
+
...spaceId ? { spaceId: assertResourceId(spaceId, "space-id") } : {},
|
|
19615
|
+
arguments: toolArguments(args),
|
|
19616
|
+
env: ctx.deps.env,
|
|
19617
|
+
...name ? { envName: name } : {},
|
|
19618
|
+
autoCreate,
|
|
19619
|
+
timeoutMs: timeoutMs(args["timeout-ms"]),
|
|
19620
|
+
dryRun: ctx.flags.dryRun
|
|
19621
|
+
}
|
|
19622
|
+
);
|
|
19623
|
+
return {
|
|
19624
|
+
result,
|
|
19625
|
+
message: dryRunMessage(result, `call ${result.toolName} at ${result.url}`, `Called ${result.toolName}.`),
|
|
19626
|
+
nextActions: keyNeeded(result) ?? (!result.dryRun && result.toolName.startsWith("Submit") ? [
|
|
19627
|
+
{
|
|
19628
|
+
command: `adp plugin get --plugin-id ${id} --format json`,
|
|
19629
|
+
reason: "find the matching Query tool and call it with the task id in output"
|
|
19630
|
+
}
|
|
19631
|
+
] : void 0)
|
|
19632
|
+
};
|
|
18147
19633
|
}
|
|
18148
19634
|
})
|
|
18149
19635
|
);
|
|
@@ -18685,7 +20171,7 @@ function registerEnvCommands(registry, ctx) {
|
|
|
18685
20171
|
}
|
|
18686
20172
|
|
|
18687
20173
|
// src/interfaces/cli/commands/skills-install.ts
|
|
18688
|
-
import { homedir as
|
|
20174
|
+
import { homedir as homedir6 } from "os";
|
|
18689
20175
|
|
|
18690
20176
|
// src/application/companion-skills/discover-companion-skills.ts
|
|
18691
20177
|
async function discoverCompanionSkills(pack, input) {
|
|
@@ -18830,7 +20316,7 @@ function registerCompanionSkillCommands(registry, ctx) {
|
|
|
18830
20316
|
await requireYes(ctx, `install companion skills (${scope})`);
|
|
18831
20317
|
}
|
|
18832
20318
|
const result = await installCompanionSkills(ctx.deps.companionSkills, {
|
|
18833
|
-
homeDir:
|
|
20319
|
+
homeDir: homedir6(),
|
|
18834
20320
|
cwd: ctx.flags.cwd,
|
|
18835
20321
|
scope,
|
|
18836
20322
|
agents: typeof args.agent === "string" ? args.agent : void 0,
|
|
@@ -18862,7 +20348,7 @@ function registerCompanionSkillCommands(registry, ctx) {
|
|
|
18862
20348
|
],
|
|
18863
20349
|
async handler() {
|
|
18864
20350
|
const result = await discoverCompanionSkills(ctx.deps.companionSkills, {
|
|
18865
|
-
homeDir:
|
|
20351
|
+
homeDir: homedir6(),
|
|
18866
20352
|
cwd: ctx.flags.cwd
|
|
18867
20353
|
});
|
|
18868
20354
|
if (isManagedInstall(await detectInstallSource(ctx.deps))) {
|
|
@@ -22071,7 +23557,7 @@ async function modifyChannel(deps, input) {
|
|
|
22071
23557
|
if (paths.length === 0) {
|
|
22072
23558
|
throw usageError("Nothing to update", `Pass --description or --spec-json. Updatable paths: ${allowed.join(", ")}`);
|
|
22073
23559
|
}
|
|
22074
|
-
const rejected = paths.filter((
|
|
23560
|
+
const rejected = paths.filter((path18) => !allowed.includes(path18));
|
|
22075
23561
|
if (rejected.length > 0) {
|
|
22076
23562
|
throw usageError(
|
|
22077
23563
|
`ModifyChannel cannot change ${rejected.join(", ")}`,
|
|
@@ -22357,7 +23843,7 @@ function registerModelCommands(registry, ctx) {
|
|
|
22357
23843
|
}
|
|
22358
23844
|
|
|
22359
23845
|
// src/interfaces/cli/commands/workflow/index.ts
|
|
22360
|
-
import { readFile as
|
|
23846
|
+
import { readFile as readFile15 } from "fs/promises";
|
|
22361
23847
|
|
|
22362
23848
|
// src/domain/workflow/canvas.ts
|
|
22363
23849
|
var WORKFLOW_NODE_TYPES = [
|
|
@@ -22615,17 +24101,17 @@ function checkReferences(nodes, problems) {
|
|
|
22615
24101
|
const ref3 = isRecord(value.Reference) ? value.Reference : !root && "JsonPath" in value && text4(value.NodeID) ? value : void 0;
|
|
22616
24102
|
if (ref3 && text4(ref3.NodeID)) {
|
|
22617
24103
|
const target = byId.get(text4(ref3.NodeID));
|
|
22618
|
-
const
|
|
24104
|
+
const path18 = text4(ref3.JsonPath);
|
|
22619
24105
|
if (!target) {
|
|
22620
24106
|
problems.push(
|
|
22621
24107
|
`node ${id}: "${here}" references node "${text4(ref3.NodeID)}", which does not exist; point Reference.NodeID at one of ${[...byId.keys()].join(", ")}`
|
|
22622
24108
|
);
|
|
22623
24109
|
} else {
|
|
22624
|
-
const field = /^Output\.([^.[\]]+)/.exec(
|
|
24110
|
+
const field = /^Output\.([^.[\]]+)/.exec(path18)?.[1];
|
|
22625
24111
|
const declared = declaredOutputs(target);
|
|
22626
24112
|
if (field && declared && !declared.includes(field)) {
|
|
22627
24113
|
problems.push(
|
|
22628
|
-
`node ${id}: "${here}" reads ${text4(ref3.NodeID)}.${
|
|
24114
|
+
`node ${id}: "${here}" reads ${text4(ref3.NodeID)}.${path18}, but ${text4(ref3.NodeID)} (${text4(target.NodeType)}) declares only ${declared.map((name) => `Output.${name}`).join(", ")}; rename the reference or the ${text4(target.NodeType) === "PARAMETER_EXTRACTOR" ? "parameter" : "output"}`
|
|
22629
24115
|
);
|
|
22630
24116
|
}
|
|
22631
24117
|
}
|
|
@@ -22883,18 +24369,18 @@ var COMPARISON_OPERATORS = /* @__PURE__ */ new Set([
|
|
|
22883
24369
|
"NOT_SET"
|
|
22884
24370
|
]);
|
|
22885
24371
|
var NUMERIC_OPERATORS = /* @__PURE__ */ new Set(["LT", "LE", "GT", "GE"]);
|
|
22886
|
-
function checkLogical(logical,
|
|
24372
|
+
function checkLogical(logical, path18, fixes, problems) {
|
|
22887
24373
|
const compound = Array.isArray(logical.Compound) ? logical.Compound.filter(isRecord) : [];
|
|
22888
24374
|
const combined = logical.LogicalOperator === "AND" || logical.LogicalOperator === "OR";
|
|
22889
24375
|
if (combined) {
|
|
22890
24376
|
if (compound.length === 0) {
|
|
22891
|
-
problems.push(`${
|
|
24377
|
+
problems.push(`${path18}: LogicalOperator ${text4(logical.LogicalOperator)} needs conditions in Compound[]`);
|
|
22892
24378
|
}
|
|
22893
24379
|
if ("Comparison" in logical) {
|
|
22894
24380
|
delete logical.Comparison;
|
|
22895
|
-
fixes.push(`removed ${
|
|
24381
|
+
fixes.push(`removed ${path18}.Comparison (an ${text4(logical.LogicalOperator)} group uses Compound only)`);
|
|
22896
24382
|
}
|
|
22897
|
-
compound.forEach((child, index) => checkLogical(child, `${
|
|
24383
|
+
compound.forEach((child, index) => checkLogical(child, `${path18}.Compound[${index}]`, fixes, problems));
|
|
22898
24384
|
return;
|
|
22899
24385
|
}
|
|
22900
24386
|
const comparison = isRecord(logical.Comparison) ? logical.Comparison : void 0;
|
|
@@ -22904,10 +24390,10 @@ function checkLogical(logical, path14, fixes, problems) {
|
|
|
22904
24390
|
const operator = text4(comparison.Operator);
|
|
22905
24391
|
if (!COMPARISON_OPERATORS.has(operator)) {
|
|
22906
24392
|
problems.push(
|
|
22907
|
-
`${
|
|
24393
|
+
`${path18}.Comparison: Operator "${operator || "none"}" is not supported; use one of ${[...COMPARISON_OPERATORS].join(", ")}`
|
|
22908
24394
|
);
|
|
22909
24395
|
} else if (NUMERIC_OPERATORS.has(operator) && !["INT", "FLOAT"].includes(text4(comparison.LeftType))) {
|
|
22910
|
-
problems.push(`${
|
|
24396
|
+
problems.push(`${path18}.Comparison: ${operator} compares numbers; LeftType must be INT or FLOAT, got ${text4(comparison.LeftType) || "none"}`);
|
|
22911
24397
|
}
|
|
22912
24398
|
}
|
|
22913
24399
|
function dynamicCard(node) {
|
|
@@ -23049,9 +24535,9 @@ function rewriteEndReferences(node, fixes) {
|
|
|
23049
24535
|
const value = isRecord(property.Value) ? property.Value : void 0;
|
|
23050
24536
|
if (value?.InputType === "INPUT_REF" && isRecord(value.InputRef)) {
|
|
23051
24537
|
const ref3 = value.InputRef;
|
|
23052
|
-
const
|
|
23053
|
-
property.Value = { InputType: "REFERENCE_OUTPUT", Reference: { NodeID: text4(ref3.NodeID), JsonPath:
|
|
23054
|
-
fixes.push(`END ${text4(node.NodeID)}: output ${text4(property.Title)} INPUT_REF -> REFERENCE_OUTPUT ${
|
|
24538
|
+
const path18 = text4(ref3.JsonPath) || `Output.${text4(ref3.Name)}`;
|
|
24539
|
+
property.Value = { InputType: "REFERENCE_OUTPUT", Reference: { NodeID: text4(ref3.NodeID), JsonPath: path18 } };
|
|
24540
|
+
fixes.push(`END ${text4(node.NodeID)}: output ${text4(property.Title)} INPUT_REF -> REFERENCE_OUTPUT ${path18}`);
|
|
23055
24541
|
}
|
|
23056
24542
|
visit(property.Properties);
|
|
23057
24543
|
}
|
|
@@ -23254,7 +24740,7 @@ function recheckAction(input) {
|
|
|
23254
24740
|
};
|
|
23255
24741
|
}
|
|
23256
24742
|
return {
|
|
23257
|
-
command: rerunOf(input, "dry-run") ?? `adp workflow deploy --app-id ${input.appId}${workflow} --canvas-file ${
|
|
24743
|
+
command: rerunOf(input, "dry-run") ?? `adp workflow deploy --app-id ${input.appId}${workflow} --canvas-file ${shellWord5(input.canvasFile)}${input.bind === false ? " --no-bind" : input.bind ? " --bind" : ""} --dry-run --format json`,
|
|
23258
24744
|
reason: `after editing ${input.canvasFile} to fix the problems above, re-run this local check (no cloud write)`,
|
|
23259
24745
|
needs_edit: { file: input.canvasFile }
|
|
23260
24746
|
};
|
|
@@ -23347,7 +24833,7 @@ function platformRejectionActions(input, canvas, errors) {
|
|
|
23347
24833
|
const workflow = input.workflowId ? ` --workflow-id ${input.workflowId}` : "";
|
|
23348
24834
|
actions.push(
|
|
23349
24835
|
input.canvasFile ? {
|
|
23350
|
-
command: rerunOf(input, "yes") ?? `adp workflow deploy --app-id ${input.appId}${workflow} --canvas-file ${
|
|
24836
|
+
command: rerunOf(input, "yes") ?? `adp workflow deploy --app-id ${input.appId}${workflow} --canvas-file ${shellWord5(input.canvasFile)}${input.bind === false ? " --no-bind" : input.bind ? " --bind" : ""} --yes --format json`,
|
|
23351
24837
|
reason: `after editing ${named ? `node ${named}` : "the canvas"} in ${input.canvasFile} as the platform message says, deploy again; this writes the workflow draft (the local --dry-run check already passes)`,
|
|
23352
24838
|
needs_edit: { file: input.canvasFile }
|
|
23353
24839
|
} : recheckAction(input)
|
|
@@ -23357,7 +24843,7 @@ function platformRejectionActions(input, canvas, errors) {
|
|
|
23357
24843
|
function rerunOf(input, mode2) {
|
|
23358
24844
|
return input.rerun?.(mode2);
|
|
23359
24845
|
}
|
|
23360
|
-
function
|
|
24846
|
+
function shellWord5(value) {
|
|
23361
24847
|
return /^[\w@%+=:,./-]+$/.test(value) ? value : `'${value.replace(/'/g, "'\\''")}'`;
|
|
23362
24848
|
}
|
|
23363
24849
|
async function withShellCleanup(error, gateway, appId3, workflowId2, name) {
|
|
@@ -23587,13 +25073,13 @@ function signatureExpiry2(url) {
|
|
|
23587
25073
|
}
|
|
23588
25074
|
|
|
23589
25075
|
// src/infrastructure/fs/workflow-canvas-extractor.ts
|
|
23590
|
-
import { readFile as
|
|
25076
|
+
import { readFile as readFile14, writeFile as writeFile6 } from "fs/promises";
|
|
23591
25077
|
import { basename, dirname, join } from "path";
|
|
23592
25078
|
var CANVAS_ENTRY = /(?:^|\/)([^/]+_workflow\.json)$/;
|
|
23593
25079
|
function createWorkflowCanvasExtractor() {
|
|
23594
25080
|
return {
|
|
23595
25081
|
async extractCanvases(zipPath) {
|
|
23596
|
-
const zip = await
|
|
25082
|
+
const zip = await readFile14(zipPath);
|
|
23597
25083
|
const written = [];
|
|
23598
25084
|
for (const entry of listEntries(zip)) {
|
|
23599
25085
|
const match = CANVAS_ENTRY.exec(entry.name);
|
|
@@ -23602,7 +25088,7 @@ function createWorkflowCanvasExtractor() {
|
|
|
23602
25088
|
continue;
|
|
23603
25089
|
}
|
|
23604
25090
|
const target = join(dirname(zipPath), basename(match[1]));
|
|
23605
|
-
await
|
|
25091
|
+
await writeFile6(target, body);
|
|
23606
25092
|
written.push(target);
|
|
23607
25093
|
}
|
|
23608
25094
|
return written;
|
|
@@ -23913,7 +25399,7 @@ function parseTimeout(args) {
|
|
|
23913
25399
|
}
|
|
23914
25400
|
return timeout * 1e3;
|
|
23915
25401
|
}
|
|
23916
|
-
function
|
|
25402
|
+
function shellWord6(value) {
|
|
23917
25403
|
return /^[\w@%+=:,./-]+$/.test(value) ? value : `'${value.replace(/'/g, "'\\''")}'`;
|
|
23918
25404
|
}
|
|
23919
25405
|
function waitingActions(appId3, workflowRunId, question, options = []) {
|
|
@@ -23934,7 +25420,7 @@ function waitingActions(appId3, workflowRunId, question, options = []) {
|
|
|
23934
25420
|
}
|
|
23935
25421
|
return [
|
|
23936
25422
|
{
|
|
23937
|
-
command: `adp workflow run resume --app-id ${appId3} --run-id ${workflowRunId} --query ${
|
|
25423
|
+
command: `adp workflow run resume --app-id ${appId3} --run-id ${workflowRunId} --query ${shellWord6(options[0])} --format json`,
|
|
23938
25424
|
reason: `${ask}options: ${options.join(" / ")}; this picks the first, change --query to choose another`
|
|
23939
25425
|
},
|
|
23940
25426
|
get
|
|
@@ -23985,7 +25471,7 @@ function registerWorkflowRunCommands(registry, ctx) {
|
|
|
23985
25471
|
message: `Would start a workflow run of app ${id}.`
|
|
23986
25472
|
};
|
|
23987
25473
|
}
|
|
23988
|
-
const
|
|
25474
|
+
const timeoutMs2 = parseTimeout(args);
|
|
23989
25475
|
const gateways = await ctx.deps.resolveGateways(ctx.flags);
|
|
23990
25476
|
const result = await runWorkflow(
|
|
23991
25477
|
{ runs: gateways.workflowRun, latestMessage: (ref3) => gateways.workflowRunControl.latestMessage(ref3) },
|
|
@@ -23996,7 +25482,7 @@ function registerWorkflowRunCommands(registry, ctx) {
|
|
|
23996
25482
|
variables,
|
|
23997
25483
|
visitorId: typeof args["visitor-id"] === "string" ? args["visitor-id"] : void 0,
|
|
23998
25484
|
wait: args.wait !== false,
|
|
23999
|
-
timeoutMs
|
|
25485
|
+
timeoutMs: timeoutMs2
|
|
24000
25486
|
}
|
|
24001
25487
|
);
|
|
24002
25488
|
if (result.status === "submitted") {
|
|
@@ -24168,7 +25654,7 @@ function registerWorkflowRunCommands(registry, ctx) {
|
|
|
24168
25654
|
if (ctx.flags.dryRun) {
|
|
24169
25655
|
return { result: { dryRun: true, ...input }, message: `Would resume workflow run ${input.workflowRunId}.` };
|
|
24170
25656
|
}
|
|
24171
|
-
const
|
|
25657
|
+
const timeoutMs2 = parseTimeout(args);
|
|
24172
25658
|
const gateways = await ctx.deps.resolveGateways(ctx.flags);
|
|
24173
25659
|
if (args.wait !== false) {
|
|
24174
25660
|
return waitedOutput(
|
|
@@ -24176,7 +25662,7 @@ function registerWorkflowRunCommands(registry, ctx) {
|
|
|
24176
25662
|
gateways.workflowRunControl,
|
|
24177
25663
|
await resumeWorkflowRunAndWait(
|
|
24178
25664
|
{ runs: gateways.workflowRun, control: gateways.workflowRunControl },
|
|
24179
|
-
{ ...input, timeoutMs }
|
|
25665
|
+
{ ...input, timeoutMs: timeoutMs2 }
|
|
24180
25666
|
)
|
|
24181
25667
|
)
|
|
24182
25668
|
);
|
|
@@ -24217,22 +25703,22 @@ function registerWorkflowRunCommands(registry, ctx) {
|
|
|
24217
25703
|
}
|
|
24218
25704
|
|
|
24219
25705
|
// src/interfaces/cli/commands/workflow/index.ts
|
|
24220
|
-
async function readCanvas(
|
|
25706
|
+
async function readCanvas(path18) {
|
|
24221
25707
|
let raw;
|
|
24222
25708
|
try {
|
|
24223
|
-
raw = await
|
|
25709
|
+
raw = await readFile15(path18, "utf8");
|
|
24224
25710
|
} catch {
|
|
24225
|
-
throw usageError(`Cannot read canvas file ${
|
|
25711
|
+
throw usageError(`Cannot read canvas file ${path18}`, "Pass a readable JSON file via --canvas-file");
|
|
24226
25712
|
}
|
|
24227
25713
|
try {
|
|
24228
25714
|
const parsed = JSON.parse(raw);
|
|
24229
25715
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
24230
|
-
throw usageError(`Canvas file ${
|
|
25716
|
+
throw usageError(`Canvas file ${path18} must contain a JSON object`, "Pass a workflow canvas object");
|
|
24231
25717
|
}
|
|
24232
25718
|
return parsed;
|
|
24233
25719
|
} catch (error) {
|
|
24234
25720
|
if (error instanceof SyntaxError) {
|
|
24235
|
-
throw usageError(`Canvas file ${
|
|
25721
|
+
throw usageError(`Canvas file ${path18} is not valid JSON`, "Fix the canvas JSON and retry");
|
|
24236
25722
|
}
|
|
24237
25723
|
throw error;
|
|
24238
25724
|
}
|
|
@@ -25272,7 +26758,7 @@ function registerMemoryCommands(registry, ctx) {
|
|
|
25272
26758
|
examples: ["adp memory export --space-id sp-1 --store-id rms_abc --output ./memory.csv"],
|
|
25273
26759
|
async handler(args) {
|
|
25274
26760
|
const ref3 = await storeRef(ctx, args);
|
|
25275
|
-
const output =
|
|
26761
|
+
const output = typeof args.output === "string" ? canonicalizeLocalPath(args.output, ctx.flags.cwd) : void 0;
|
|
25276
26762
|
if (ctx.flags.dryRun) {
|
|
25277
26763
|
return { result: { dryRun: true, ...ref3, output }, message: `Would export memory store ${ref3.storeId}.` };
|
|
25278
26764
|
}
|
|
@@ -25491,11 +26977,11 @@ async function credentialRef(ctx, args) {
|
|
|
25491
26977
|
};
|
|
25492
26978
|
}
|
|
25493
26979
|
async function readToken(ctx, args, required3) {
|
|
25494
|
-
const
|
|
25495
|
-
if (
|
|
25496
|
-
const value = ctx.deps.env[
|
|
26980
|
+
const envName2 = text6(args, "token-env");
|
|
26981
|
+
if (envName2) {
|
|
26982
|
+
const value = ctx.deps.env[envName2]?.trim();
|
|
25497
26983
|
if (!value) {
|
|
25498
|
-
throw new DomainError(`Environment variable ${
|
|
26984
|
+
throw new DomainError(`Environment variable ${envName2} is empty or unset`, "usage", "UsageError");
|
|
25499
26985
|
}
|
|
25500
26986
|
return value;
|
|
25501
26987
|
}
|
|
@@ -25773,7 +27259,7 @@ ${auth.authorizationUrl}`);
|
|
|
25773
27259
|
}
|
|
25774
27260
|
|
|
25775
27261
|
// src/interfaces/cli/commands/timer/index.ts
|
|
25776
|
-
import { readFile as
|
|
27262
|
+
import { readFile as readFile16 } from "fs/promises";
|
|
25777
27263
|
|
|
25778
27264
|
// src/application/timer/timer-use-cases.ts
|
|
25779
27265
|
var RUN_POLL_MS = 3e3;
|
|
@@ -25905,7 +27391,7 @@ async function prompt(args) {
|
|
|
25905
27391
|
return inline;
|
|
25906
27392
|
}
|
|
25907
27393
|
try {
|
|
25908
|
-
const content = (await
|
|
27394
|
+
const content = (await readFile16(file, "utf8")).trim();
|
|
25909
27395
|
if (!content) {
|
|
25910
27396
|
throw new Error("empty");
|
|
25911
27397
|
}
|
|
@@ -26934,49 +28420,49 @@ async function deleteVolume(gateway, input) {
|
|
|
26934
28420
|
return { volumeId: volume.volumeId, name: volume.name, deleted: true, referenceApps: volume.referenceApps };
|
|
26935
28421
|
}
|
|
26936
28422
|
function listVolumeEntries(gateway, input) {
|
|
26937
|
-
const
|
|
26938
|
-
return guard10(gateway.listEntries({ ...input, path:
|
|
28423
|
+
const path18 = normalizeVolumePath(input.path, { allowRoot: true });
|
|
28424
|
+
return guard10(gateway.listEntries({ ...input, path: path18 }), { ...input, path: path18 });
|
|
26939
28425
|
}
|
|
26940
28426
|
function makeVolumeDirectory(gateway, input) {
|
|
26941
|
-
const
|
|
26942
|
-
return guard10(gateway.mkdir({ ...input, path:
|
|
28427
|
+
const path18 = normalizeVolumePath(input.path);
|
|
28428
|
+
return guard10(gateway.mkdir({ ...input, path: path18 }), { ...input, path: path18 });
|
|
26943
28429
|
}
|
|
26944
28430
|
async function renameVolumeFile(gateway, input) {
|
|
26945
|
-
const
|
|
28431
|
+
const path18 = normalizeVolumePath(input.path);
|
|
26946
28432
|
const name = input.name.trim();
|
|
26947
28433
|
if (!name || name.includes("/") || name === "." || name === "..") {
|
|
26948
28434
|
throw new DomainError("--name is a single file name; files cannot move between directories", "usage", "UsageError");
|
|
26949
28435
|
}
|
|
26950
|
-
const renamed = await guard10(gateway.rename({ ...input, path:
|
|
28436
|
+
const renamed = await guard10(gateway.rename({ ...input, path: path18, name }), { ...input, path: path18, operation: "rename" });
|
|
26951
28437
|
if (renamed.sizeBytes > 0) {
|
|
26952
28438
|
return renamed;
|
|
26953
28439
|
}
|
|
26954
|
-
const finalPath = renamed.path || [...
|
|
28440
|
+
const finalPath = renamed.path || [...path18.split("/").slice(0, -1), name].join("/");
|
|
26955
28441
|
const parent = finalPath.split("/").slice(0, -1).join("/");
|
|
26956
28442
|
const listing = await gateway.listEntries({ spaceId: input.spaceId, volumeId: input.volumeId, path: parent, query: baseName(finalPath), limit: 50 }).catch(() => void 0);
|
|
26957
28443
|
const entry = listing?.items.find((item) => item.path === finalPath);
|
|
26958
28444
|
return { path: finalPath, sizeBytes: entry?.sizeBytes ?? renamed.sizeBytes };
|
|
26959
28445
|
}
|
|
26960
28446
|
async function deleteVolumeEntry(gateway, input) {
|
|
26961
|
-
const
|
|
28447
|
+
const path18 = normalizeVolumePath(input.path);
|
|
26962
28448
|
const type = input.recursive ? "directory" : "file";
|
|
26963
|
-
await guard10(gateway.deleteEntry({ ...input, path:
|
|
26964
|
-
return { volumeId: input.volumeId, path:
|
|
28449
|
+
await guard10(gateway.deleteEntry({ ...input, path: path18, type }), { ...input, path: path18, operation: "delete" });
|
|
28450
|
+
return { volumeId: input.volumeId, path: path18, type, deleted: true };
|
|
26965
28451
|
}
|
|
26966
28452
|
function uploadToVolume(gateway, input) {
|
|
26967
28453
|
const local = baseName(input.localPath.replace(/\\/g, "/"));
|
|
26968
28454
|
const raw = input.to === void 0 || input.to === "" ? local : input.to.endsWith("/") ? `${input.to}${local}` : input.to;
|
|
26969
|
-
const
|
|
26970
|
-
return guard10(gateway.upload({ ...input, path:
|
|
28455
|
+
const path18 = normalizeVolumePath(raw);
|
|
28456
|
+
return guard10(gateway.upload({ ...input, path: path18 }), { ...input, path: path18 });
|
|
26971
28457
|
}
|
|
26972
28458
|
async function downloadFromVolume(gateway, input) {
|
|
26973
|
-
const
|
|
26974
|
-
const result = await guard10(gateway.download({ ...input, path:
|
|
26975
|
-
return { volumeId: input.volumeId, path:
|
|
28459
|
+
const path18 = normalizeVolumePath(input.path);
|
|
28460
|
+
const result = await guard10(gateway.download({ ...input, path: path18 }), { ...input, path: path18 });
|
|
28461
|
+
return { volumeId: input.volumeId, path: path18, output: input.localPath, ...result };
|
|
26976
28462
|
}
|
|
26977
28463
|
function volumePreviewUrl(gateway, input) {
|
|
26978
|
-
const
|
|
26979
|
-
return guard10(gateway.previewUrl({ ...input, path:
|
|
28464
|
+
const path18 = normalizeVolumePath(input.path);
|
|
28465
|
+
return guard10(gateway.previewUrl({ ...input, path: path18 }), { ...input, path: path18 });
|
|
26980
28466
|
}
|
|
26981
28467
|
|
|
26982
28468
|
// src/interfaces/cli/commands/volume/index.ts
|
|
@@ -27103,14 +28589,14 @@ function registerVolumeCommands(registry, ctx) {
|
|
|
27103
28589
|
examples: ["adp volume ls --space-id sp-1 --volume-id v-1 --path docs --format json"],
|
|
27104
28590
|
async handler(args) {
|
|
27105
28591
|
const target = await ref2(ctx, args);
|
|
27106
|
-
const
|
|
28592
|
+
const path18 = text10(args.path) ?? "";
|
|
27107
28593
|
const query = text10(args.query);
|
|
27108
28594
|
const gateways = await ctx.deps.resolveGateways(ctx.flags);
|
|
27109
|
-
const page3 = await listVolumeEntries(gateways.volume, { ...target, path:
|
|
28595
|
+
const page3 = await listVolumeEntries(gateways.volume, { ...target, path: path18, query, limit: ctx.flags.limit, page: ctx.flags.page });
|
|
27110
28596
|
return applyListShape(
|
|
27111
28597
|
ctx,
|
|
27112
28598
|
pageResult(page3, { limit: ctx.flags.limit, page: ctx.flags.page }),
|
|
27113
|
-
`adp volume ls --space-id ${target.spaceId} --volume-id ${target.volumeId}${
|
|
28599
|
+
`adp volume ls --space-id ${target.spaceId} --volume-id ${target.volumeId}${path18 ? ` --path ${JSON.stringify(path18)}` : ""}`
|
|
27114
28600
|
);
|
|
27115
28601
|
}
|
|
27116
28602
|
})
|
|
@@ -27937,7 +29423,7 @@ function registerSynonymCommands(registry, ctx) {
|
|
|
27937
29423
|
examples: ["adp synonym export --app-id app-1 --output ./synonyms.xlsx"],
|
|
27938
29424
|
async handler(args) {
|
|
27939
29425
|
const appId3 = await resolveAppId(ctx, args, WHY_APP7);
|
|
27940
|
-
const output =
|
|
29426
|
+
const output = typeof args.output === "string" ? canonicalizeLocalPath(args.output, ctx.flags.cwd) : void 0;
|
|
27941
29427
|
const input = { appId: appId3, query: text11(args, "query"), categoryId: categoryId(args), unreleasedOnly: args.unreleased === true };
|
|
27942
29428
|
if (ctx.flags.dryRun) {
|
|
27943
29429
|
return { result: { dryRun: true, ...input, output }, message: "Would export synonyms." };
|
|
@@ -28166,7 +29652,7 @@ function registerUnsatisfiedCommands(registry, ctx) {
|
|
|
28166
29652
|
examples: ["adp unsatisfied export --app-id app-1 --status pending --output ./unsatisfied.xlsx"],
|
|
28167
29653
|
async handler(args) {
|
|
28168
29654
|
const appId3 = await resolveAppId(ctx, args, WHY_APP8);
|
|
28169
|
-
const output =
|
|
29655
|
+
const output = typeof args.output === "string" ? canonicalizeLocalPath(args.output, ctx.flags.cwd) : void 0;
|
|
28170
29656
|
const input = { appId: appId3, ...filters5(args), replyIds: list4(args, "reply-id").map((id) => assertResourceId(id, "reply-id")) };
|
|
28171
29657
|
if (ctx.flags.dryRun) {
|
|
28172
29658
|
return { result: { dryRun: true, ...input, output }, message: "Would export unsatisfied replies." };
|
|
@@ -29009,6 +30495,8 @@ async function runCli(options) {
|
|
|
29009
30495
|
registerAppOpsCommands(registry, ctx);
|
|
29010
30496
|
registerPluginCommands(registry, ctx);
|
|
29011
30497
|
registerPluginAccessCommands(registry, ctx);
|
|
30498
|
+
registerPluginKeyCommands(registry, ctx);
|
|
30499
|
+
registerPluginToolCallCommands(registry, ctx);
|
|
29012
30500
|
registerSkillCommands(registry, ctx);
|
|
29013
30501
|
registerSkillLifecycleCommands(registry, ctx);
|
|
29014
30502
|
registerEnvCommands(registry, ctx);
|