@dam-agents/cli 0.2.4-rc1 → 0.2.5-rc1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin.js +1377 -428
- package/package.json +2 -2
package/dist/bin.js
CHANGED
|
@@ -10879,6 +10879,15 @@ var TermsStaleAtTransportError = class extends Error {
|
|
|
10879
10879
|
host;
|
|
10880
10880
|
kind = "terms-stale";
|
|
10881
10881
|
};
|
|
10882
|
+
var ForbiddenAtTransportError = class extends Error {
|
|
10883
|
+
constructor(detail) {
|
|
10884
|
+
super(detail || "access denied");
|
|
10885
|
+
this.detail = detail;
|
|
10886
|
+
this.name = "ForbiddenAtTransportError";
|
|
10887
|
+
}
|
|
10888
|
+
detail;
|
|
10889
|
+
kind = "forbidden";
|
|
10890
|
+
};
|
|
10882
10891
|
function buildAuthHeaders(deps) {
|
|
10883
10892
|
return async () => {
|
|
10884
10893
|
const result = await deps.tokenProvider.getValidAccessToken(deps.host);
|
|
@@ -10891,20 +10900,26 @@ function buildAuthHeaders(deps) {
|
|
|
10891
10900
|
throw new Error(e2.reason ?? e2.kind);
|
|
10892
10901
|
};
|
|
10893
10902
|
}
|
|
10894
|
-
function
|
|
10903
|
+
function wrapFetchWithServerGates(host, baseFetch) {
|
|
10895
10904
|
const inner = baseFetch ?? fetch;
|
|
10896
10905
|
return (async (input, init) => {
|
|
10897
10906
|
const response = await inner(input, init);
|
|
10898
|
-
if (response.status
|
|
10907
|
+
if ([401, 403, 412].includes(response.status)) {
|
|
10899
10908
|
const clone3 = response.clone();
|
|
10909
|
+
let body;
|
|
10900
10910
|
try {
|
|
10901
|
-
|
|
10902
|
-
|
|
10903
|
-
|
|
10904
|
-
|
|
10905
|
-
|
|
10906
|
-
|
|
10907
|
-
|
|
10911
|
+
body = await clone3.json();
|
|
10912
|
+
} catch {
|
|
10913
|
+
return response;
|
|
10914
|
+
}
|
|
10915
|
+
if (body.error === "terms_stale")
|
|
10916
|
+
throw new TermsStaleAtTransportError(host);
|
|
10917
|
+
if (body.error === "unauthorized")
|
|
10918
|
+
throw new AuthRequiredAtTransportError(`session expired for ${host}`);
|
|
10919
|
+
if (body.error === "forbidden")
|
|
10920
|
+
throw new ForbiddenAtTransportError(
|
|
10921
|
+
typeof body.message === "string" ? body.message : ""
|
|
10922
|
+
);
|
|
10908
10923
|
}
|
|
10909
10924
|
return response;
|
|
10910
10925
|
});
|
|
@@ -10914,7 +10929,7 @@ function createTrpcClient(deps) {
|
|
|
10914
10929
|
links: [
|
|
10915
10930
|
httpBatchLink({
|
|
10916
10931
|
url: `${deps.host.replace(/\/+$/, "")}/api/trpc`,
|
|
10917
|
-
fetch:
|
|
10932
|
+
fetch: wrapFetchWithServerGates(deps.host, deps.fetch),
|
|
10918
10933
|
headers: buildAuthHeaders(deps)
|
|
10919
10934
|
})
|
|
10920
10935
|
]
|
|
@@ -10926,7 +10941,7 @@ function createAgentTrpcClient(deps) {
|
|
|
10926
10941
|
links: [
|
|
10927
10942
|
httpBatchLink({
|
|
10928
10943
|
url: base,
|
|
10929
|
-
fetch:
|
|
10944
|
+
fetch: wrapFetchWithServerGates(deps.host, deps.fetch),
|
|
10930
10945
|
headers: buildAuthHeaders(deps)
|
|
10931
10946
|
})
|
|
10932
10947
|
]
|
|
@@ -28765,7 +28780,7 @@ var secretTestAnthropicInputSchema = external_exports.object({
|
|
|
28765
28780
|
envName: external_exports.enum(["ANTHROPIC_API_KEY", "CLAUDE_CODE_OAUTH_TOKEN"])
|
|
28766
28781
|
});
|
|
28767
28782
|
|
|
28768
|
-
// ../api-server-api/src/modules/
|
|
28783
|
+
// ../api-server-api/src/modules/connections/providers.ts
|
|
28769
28784
|
var DEFAULT_ENV_PLACEHOLDER = "dummy-placeholder";
|
|
28770
28785
|
var IBM_LITELLM_HOST = "ete-litellm.ai-models.vpc.res.ibm.com";
|
|
28771
28786
|
var IBM_LITELLM_BASE_URL = `https://${IBM_LITELLM_HOST}`;
|
|
@@ -28809,7 +28824,8 @@ var PROVIDERS = {
|
|
|
28809
28824
|
{
|
|
28810
28825
|
key: "oauth",
|
|
28811
28826
|
label: "OAuth Token",
|
|
28812
|
-
|
|
28827
|
+
templateId: "anthropic-oauth",
|
|
28828
|
+
tokenPrefix: "sk-ant-oat",
|
|
28813
28829
|
defaultEnvMappings: [
|
|
28814
28830
|
{
|
|
28815
28831
|
envName: "CLAUDE_CODE_OAUTH_TOKEN",
|
|
@@ -28820,7 +28836,9 @@ var PROVIDERS = {
|
|
|
28820
28836
|
{
|
|
28821
28837
|
key: "api-key",
|
|
28822
28838
|
label: "API Key",
|
|
28823
|
-
|
|
28839
|
+
templateId: "anthropic",
|
|
28840
|
+
tokenPrefix: "sk-ant-api",
|
|
28841
|
+
isDefault: true,
|
|
28824
28842
|
defaultEnvMappings: [
|
|
28825
28843
|
{
|
|
28826
28844
|
envName: "ANTHROPIC_API_KEY",
|
|
@@ -28839,6 +28857,7 @@ var PROVIDERS = {
|
|
|
28839
28857
|
{
|
|
28840
28858
|
key: "api-key",
|
|
28841
28859
|
label: "API Token",
|
|
28860
|
+
templateId: "ibm-litellm",
|
|
28842
28861
|
defaultEnvMappings: ibmLitellmEnvMappings()
|
|
28843
28862
|
}
|
|
28844
28863
|
]
|
|
@@ -28847,14 +28866,13 @@ var PROVIDERS = {
|
|
|
28847
28866
|
id: "openai",
|
|
28848
28867
|
displayName: "OpenAI",
|
|
28849
28868
|
hostPattern: "api.openai.com",
|
|
28850
|
-
//
|
|
28851
|
-
// status pages and other host endpoints from getting a spurious
|
|
28852
|
-
// Authorization header.
|
|
28869
|
+
// Scope injection to /v1/* so other host endpoints don't get a stray Authorization header.
|
|
28853
28870
|
pathPattern: "/v1/*",
|
|
28854
28871
|
modes: [
|
|
28855
28872
|
{
|
|
28856
28873
|
key: "api-key",
|
|
28857
28874
|
label: "API Key",
|
|
28875
|
+
templateId: "openai",
|
|
28858
28876
|
defaultEnvMappings: [
|
|
28859
28877
|
{ envName: "OPENAI_API_KEY", placeholder: DEFAULT_ENV_PLACEHOLDER }
|
|
28860
28878
|
]
|
|
@@ -28869,8 +28887,9 @@ var PROVIDERS = {
|
|
|
28869
28887
|
{
|
|
28870
28888
|
key: "api-key",
|
|
28871
28889
|
label: "API Key",
|
|
28890
|
+
templateId: "bob",
|
|
28872
28891
|
defaultEnvMappings: bobEnvMappings(),
|
|
28873
|
-
//
|
|
28892
|
+
// `Apikey` prefix; `Bearer` would trigger JWT auth.
|
|
28874
28893
|
injection: {
|
|
28875
28894
|
headerName: "Authorization",
|
|
28876
28895
|
valueFormat: "Apikey {value}"
|
|
@@ -28885,6 +28904,29 @@ var PROVIDERS = {
|
|
|
28885
28904
|
var PROVIDER_PRESET_TYPES = Object.keys(
|
|
28886
28905
|
PROVIDERS
|
|
28887
28906
|
);
|
|
28907
|
+
function isProviderPresetType(type) {
|
|
28908
|
+
return type in PROVIDERS;
|
|
28909
|
+
}
|
|
28910
|
+
var TEMPLATE_TO_PROVIDER = new Map(
|
|
28911
|
+
PROVIDER_PRESET_TYPES.flatMap(
|
|
28912
|
+
(type) => PROVIDERS[type].modes.map(
|
|
28913
|
+
(mode) => [mode.templateId, type]
|
|
28914
|
+
)
|
|
28915
|
+
)
|
|
28916
|
+
);
|
|
28917
|
+
var PROVIDER_TEMPLATE_IDS = new Set(
|
|
28918
|
+
TEMPLATE_TO_PROVIDER.keys()
|
|
28919
|
+
);
|
|
28920
|
+
function providerTypeForTemplateId(templateId) {
|
|
28921
|
+
return TEMPLATE_TO_PROVIDER.get(templateId) ?? null;
|
|
28922
|
+
}
|
|
28923
|
+
function templateIdForProvider(type, value) {
|
|
28924
|
+
const modes = PROVIDERS[type].modes;
|
|
28925
|
+
const matched = modes.find(
|
|
28926
|
+
(mode) => mode.tokenPrefix !== void 0 && value.startsWith(mode.tokenPrefix)
|
|
28927
|
+
);
|
|
28928
|
+
return (matched ?? modes.find((mode) => mode.isDefault) ?? modes[0]).templateId;
|
|
28929
|
+
}
|
|
28888
28930
|
|
|
28889
28931
|
// ../agent-runtime-api/src/modules/files/schemas.ts
|
|
28890
28932
|
var pathSchema = external_exports.string().min(1);
|
|
@@ -29192,7 +29234,11 @@ var templateInput = external_exports.object({
|
|
|
29192
29234
|
// Marks a config input the form packs into `configInputs` rather than the typed auth fields.
|
|
29193
29235
|
configInput: external_exports.boolean().optional(),
|
|
29194
29236
|
label: external_exports.string().optional(),
|
|
29195
|
-
hint: external_exports.string().optional()
|
|
29237
|
+
hint: external_exports.string().optional(),
|
|
29238
|
+
// Validation a config input declares, surfaced so clients can validate before submit (the server enforces the same).
|
|
29239
|
+
pattern: external_exports.string().optional(),
|
|
29240
|
+
patternHint: external_exports.string().optional(),
|
|
29241
|
+
enumValues: external_exports.array(external_exports.string()).optional()
|
|
29196
29242
|
});
|
|
29197
29243
|
var connectionTemplateView = external_exports.object({
|
|
29198
29244
|
id: external_exports.string(),
|
|
@@ -29219,6 +29265,10 @@ var agentConnections = external_exports.object({
|
|
|
29219
29265
|
var connectionIdInputSchema = external_exports.object({
|
|
29220
29266
|
id: external_exports.string().min(1)
|
|
29221
29267
|
});
|
|
29268
|
+
var connectionUpdateInputSchema = external_exports.object({
|
|
29269
|
+
id: external_exports.string().min(1),
|
|
29270
|
+
value: external_exports.string().min(1)
|
|
29271
|
+
});
|
|
29222
29272
|
var connectionStartOAuthInputSchema = external_exports.object({
|
|
29223
29273
|
connectionId: external_exports.string().min(1),
|
|
29224
29274
|
returnTo: external_exports.string().regex(
|
|
@@ -29680,10 +29730,16 @@ function classifyTrpcError(e2) {
|
|
|
29680
29730
|
let cursor = e2;
|
|
29681
29731
|
for (let depth = 0; cursor && depth < 8; depth++) {
|
|
29682
29732
|
if (cursor instanceof TermsStaleAtTransportError) throw cursor;
|
|
29733
|
+
if (cursor instanceof ForbiddenAtTransportError) throw cursor;
|
|
29683
29734
|
if (cursor instanceof AuthRequiredAtTransportError)
|
|
29684
29735
|
return err2({ kind: "auth-required", reason: cursor.message });
|
|
29685
29736
|
cursor = cursor.cause;
|
|
29686
29737
|
}
|
|
29738
|
+
if (e2 instanceof TRPCClientError) {
|
|
29739
|
+
const serverCode = e2.data?.code;
|
|
29740
|
+
if (serverCode)
|
|
29741
|
+
return err2({ kind: "transport", reason: e2.message, serverCode });
|
|
29742
|
+
}
|
|
29687
29743
|
return err2({
|
|
29688
29744
|
kind: "transport",
|
|
29689
29745
|
reason: e2 instanceof Error ? e2.message : typeof e2 === "string" ? e2 : "unknown transport failure"
|
|
@@ -29883,68 +29939,46 @@ function sleep2(ms) {
|
|
|
29883
29939
|
return new Promise((r) => setTimeout(r, ms));
|
|
29884
29940
|
}
|
|
29885
29941
|
|
|
29886
|
-
// src/modules/
|
|
29887
|
-
var
|
|
29888
|
-
|
|
29889
|
-
|
|
29890
|
-
|
|
29891
|
-
|
|
29892
|
-
|
|
29893
|
-
|
|
29894
|
-
|
|
29895
|
-
|
|
29896
|
-
var EXIT_SCHEDULE_NOT_FOUND = 9;
|
|
29897
|
-
var EXIT_SIGINT = 130;
|
|
29942
|
+
// src/modules/auth/infrastructure/auth-env-reader.ts
|
|
29943
|
+
var DAM_TOKEN_ENV_VAR = "DAM_TOKEN";
|
|
29944
|
+
function createProcessAuthEnvReader(env = process.env) {
|
|
29945
|
+
return {
|
|
29946
|
+
damToken() {
|
|
29947
|
+
const v2 = env[DAM_TOKEN_ENV_VAR];
|
|
29948
|
+
return v2 && v2.length > 0 ? v2 : void 0;
|
|
29949
|
+
}
|
|
29950
|
+
};
|
|
29951
|
+
}
|
|
29898
29952
|
|
|
29899
|
-
// src/modules/
|
|
29953
|
+
// src/modules/shared/auth-message.ts
|
|
29954
|
+
function formatAuthRejection(reason, env = process.env) {
|
|
29955
|
+
const hint = env[DAM_TOKEN_ENV_VAR] ? "DAM_TOKEN was rejected \u2014 check it is valid and unexpired" : "run `dam auth login` first";
|
|
29956
|
+
return `error: not authenticated: ${reason}
|
|
29957
|
+
hint: ${hint}
|
|
29958
|
+
`;
|
|
29959
|
+
}
|
|
29960
|
+
|
|
29961
|
+
// src/modules/shared/trpc/print.ts
|
|
29900
29962
|
function formatTransportError(reason, host) {
|
|
29901
29963
|
return `cannot reach server \`${host}\`: ${reason}`;
|
|
29902
29964
|
}
|
|
29903
|
-
function
|
|
29904
|
-
return error51.kind === "not-found" || error51.kind === "ambiguous" ? EXIT_AGENT_NOT_RESOLVED : EXIT_RUNTIME_FAILURE;
|
|
29905
|
-
}
|
|
29906
|
-
function printServiceError(error51, host) {
|
|
29965
|
+
function printServiceError(error51, host, env = process.env) {
|
|
29907
29966
|
if (error51.kind === "auth-required") {
|
|
29908
|
-
process.stderr.write(
|
|
29967
|
+
process.stderr.write(formatAuthRejection(error51.reason, env));
|
|
29968
|
+
return;
|
|
29969
|
+
}
|
|
29970
|
+
if (error51.serverCode) {
|
|
29971
|
+
process.stderr.write(`error: ${error51.reason}
|
|
29909
29972
|
`);
|
|
29910
|
-
process.stderr.write("hint: run `dam auth login` first\n");
|
|
29911
29973
|
return;
|
|
29912
29974
|
}
|
|
29913
29975
|
process.stderr.write(`error: ${formatTransportError(error51.reason, host)}
|
|
29914
29976
|
`);
|
|
29915
29977
|
}
|
|
29916
|
-
function
|
|
29917
|
-
|
|
29918
|
-
|
|
29919
|
-
|
|
29920
|
-
process.stderr.write(`error: no agent with id \`${error51.ref}\`
|
|
29921
|
-
`);
|
|
29922
|
-
} else {
|
|
29923
|
-
process.stderr.write(`error: no agent named "${error51.ref}"
|
|
29924
|
-
`);
|
|
29925
|
-
}
|
|
29926
|
-
return;
|
|
29927
|
-
case "ambiguous":
|
|
29928
|
-
process.stderr.write(`error: multiple agents named "${error51.ref}":
|
|
29929
|
-
`);
|
|
29930
|
-
for (const m of error51.matches) {
|
|
29931
|
-
process.stderr.write(` - \`${m.id}\`
|
|
29932
|
-
`);
|
|
29933
|
-
}
|
|
29934
|
-
process.stderr.write("hint: specify by id instead\n");
|
|
29935
|
-
return;
|
|
29936
|
-
case "auth-required":
|
|
29937
|
-
process.stderr.write(`error: not authenticated: ${error51.reason}
|
|
29938
|
-
`);
|
|
29939
|
-
process.stderr.write("hint: run `dam auth login` first\n");
|
|
29940
|
-
return;
|
|
29941
|
-
case "transport":
|
|
29942
|
-
process.stderr.write(
|
|
29943
|
-
`error: ${formatTransportError(error51.reason, host)}
|
|
29944
|
-
`
|
|
29945
|
-
);
|
|
29946
|
-
return;
|
|
29947
|
-
}
|
|
29978
|
+
function printTrpcError(e2, host) {
|
|
29979
|
+
const r = classifyTrpcError(e2);
|
|
29980
|
+
if (r.ok) return;
|
|
29981
|
+
printServiceError(r.error, host);
|
|
29948
29982
|
}
|
|
29949
29983
|
|
|
29950
29984
|
// src/modules/agent/commands/create-helpers.ts
|
|
@@ -29972,6 +30006,19 @@ function validateAgentName(name) {
|
|
|
29972
30006
|
return ok2(void 0);
|
|
29973
30007
|
}
|
|
29974
30008
|
|
|
30009
|
+
// src/modules/shared/exit-codes.ts
|
|
30010
|
+
var EXIT_SUCCESS = 0;
|
|
30011
|
+
var EXIT_RUNTIME_FAILURE = 1;
|
|
30012
|
+
var EXIT_INVALID_INPUT = 2;
|
|
30013
|
+
var EXIT_BELOW_FLOOR = 3;
|
|
30014
|
+
var EXIT_AUTH_STATUS_NO_VALID = 4;
|
|
30015
|
+
var EXIT_AGENT_NOT_RESOLVED = 5;
|
|
30016
|
+
var EXIT_RULE_NOT_FOUND = 6;
|
|
30017
|
+
var EXIT_AGENT_NOT_REACHABLE = 7;
|
|
30018
|
+
var EXIT_APPROVAL_NOT_ACTIONABLE = 8;
|
|
30019
|
+
var EXIT_SCHEDULE_NOT_FOUND = 9;
|
|
30020
|
+
var EXIT_SIGINT = 130;
|
|
30021
|
+
|
|
29975
30022
|
// src/modules/agent/commands/create.ts
|
|
29976
30023
|
var DEFAULT_TIMEOUT_SECONDS = 120;
|
|
29977
30024
|
function buildCreateCommand(deps) {
|
|
@@ -30099,11 +30146,7 @@ async function runCreate(name, opts, deps) {
|
|
|
30099
30146
|
}
|
|
30100
30147
|
const classified = classifyTrpcError(e2);
|
|
30101
30148
|
if (!classified.ok && classified.error.kind === "auth-required") {
|
|
30102
|
-
|
|
30103
|
-
`error: not authenticated: ${classified.error.reason}
|
|
30104
|
-
hint: run \`dam auth login\` first
|
|
30105
|
-
`
|
|
30106
|
-
);
|
|
30149
|
+
printServiceError(classified.error, host);
|
|
30107
30150
|
process.exit(EXIT_RUNTIME_FAILURE);
|
|
30108
30151
|
}
|
|
30109
30152
|
process.stderr.write(`error: failed to create agent: ${errorReason(e2)}
|
|
@@ -31149,6 +31192,17 @@ ${c2}
|
|
|
31149
31192
|
}
|
|
31150
31193
|
} }).prompt();
|
|
31151
31194
|
|
|
31195
|
+
// src/modules/shared/prompt-secret.ts
|
|
31196
|
+
function promptSecret(message) {
|
|
31197
|
+
return Ce({
|
|
31198
|
+
message,
|
|
31199
|
+
validate(v2) {
|
|
31200
|
+
if (!v2 || v2.trim() === "") return "Required";
|
|
31201
|
+
return void 0;
|
|
31202
|
+
}
|
|
31203
|
+
});
|
|
31204
|
+
}
|
|
31205
|
+
|
|
31152
31206
|
// src/modules/agent/lib/group-github-pats.ts
|
|
31153
31207
|
var API_HOST = "api.github.com";
|
|
31154
31208
|
var GIT_HOST = "github.com";
|
|
@@ -31178,8 +31232,119 @@ function groupGithubPats(secrets) {
|
|
|
31178
31232
|
return pairs;
|
|
31179
31233
|
}
|
|
31180
31234
|
|
|
31235
|
+
// src/modules/connection/services/connection-service.ts
|
|
31236
|
+
function createConnectionService(deps) {
|
|
31237
|
+
const readIds = async (agentId) => {
|
|
31238
|
+
const res = await deps.trpc.connections.getAgentConnections.query({
|
|
31239
|
+
agentId
|
|
31240
|
+
});
|
|
31241
|
+
return res.connections.map((c2) => c2.connectionId);
|
|
31242
|
+
};
|
|
31243
|
+
return {
|
|
31244
|
+
async list() {
|
|
31245
|
+
return trpcCall(() => deps.trpc.connections.list.query());
|
|
31246
|
+
},
|
|
31247
|
+
async listTemplates() {
|
|
31248
|
+
return trpcCall(() => deps.trpc.connections.listTemplates.query());
|
|
31249
|
+
},
|
|
31250
|
+
async createConnection(input) {
|
|
31251
|
+
return trpcCall(() => deps.trpc.connections.create.mutate(input));
|
|
31252
|
+
},
|
|
31253
|
+
async update(id, value) {
|
|
31254
|
+
return trpcCall(async () => {
|
|
31255
|
+
await deps.trpc.connections.update.mutate({ id, value });
|
|
31256
|
+
});
|
|
31257
|
+
},
|
|
31258
|
+
async startOAuth(connectionId) {
|
|
31259
|
+
return trpcCall(
|
|
31260
|
+
() => deps.trpc.connections.startOAuth.mutate({ connectionId })
|
|
31261
|
+
);
|
|
31262
|
+
},
|
|
31263
|
+
async discoverMcp(url2) {
|
|
31264
|
+
return trpcCall(() => deps.trpc.connections.discoverMcp.mutate({ url: url2 }));
|
|
31265
|
+
},
|
|
31266
|
+
async getConnection(id) {
|
|
31267
|
+
return trpcCall(() => deps.trpc.connections.get.query({ id }));
|
|
31268
|
+
},
|
|
31269
|
+
async agentConnectionIds(agentId) {
|
|
31270
|
+
return trpcCall(() => readIds(agentId));
|
|
31271
|
+
},
|
|
31272
|
+
async grant(agentId, add) {
|
|
31273
|
+
return trpcCall(async () => {
|
|
31274
|
+
const current = await readIds(agentId);
|
|
31275
|
+
const next = Array.from(/* @__PURE__ */ new Set([...current, ...add]));
|
|
31276
|
+
await deps.trpc.connections.setAgentConnections.mutate({
|
|
31277
|
+
agentId,
|
|
31278
|
+
connectionIds: next
|
|
31279
|
+
});
|
|
31280
|
+
return next;
|
|
31281
|
+
});
|
|
31282
|
+
},
|
|
31283
|
+
async revoke(agentId, remove) {
|
|
31284
|
+
return trpcCall(async () => {
|
|
31285
|
+
const drop = new Set(remove);
|
|
31286
|
+
const current = await readIds(agentId);
|
|
31287
|
+
const next = current.filter((id) => !drop.has(id));
|
|
31288
|
+
await deps.trpc.connections.setAgentConnections.mutate({
|
|
31289
|
+
agentId,
|
|
31290
|
+
connectionIds: next
|
|
31291
|
+
});
|
|
31292
|
+
return next;
|
|
31293
|
+
});
|
|
31294
|
+
},
|
|
31295
|
+
async disconnect(id) {
|
|
31296
|
+
return trpcCall(async () => {
|
|
31297
|
+
await deps.trpc.connections.delete.mutate({ id });
|
|
31298
|
+
});
|
|
31299
|
+
}
|
|
31300
|
+
};
|
|
31301
|
+
}
|
|
31302
|
+
|
|
31303
|
+
// src/modules/connection/domain/config-inputs.ts
|
|
31304
|
+
function configInputsOf(template) {
|
|
31305
|
+
return template.inputs.filter((i) => i.configInput);
|
|
31306
|
+
}
|
|
31307
|
+
function validateConfigInputValue(input, value) {
|
|
31308
|
+
const trimmed = value.trim();
|
|
31309
|
+
if (trimmed === "") return void 0;
|
|
31310
|
+
const label = input.label ?? input.name;
|
|
31311
|
+
if (input.enumValues && !input.enumValues.includes(trimmed)) {
|
|
31312
|
+
const opts = input.enumValues.map((v2) => `\`${v2}\``).join(", ");
|
|
31313
|
+
return `${label}: must be one of ${opts}`;
|
|
31314
|
+
}
|
|
31315
|
+
if (input.pattern && !new RegExp(`^(?:${input.pattern})$`).test(trimmed)) {
|
|
31316
|
+
const expected = input.patternHint ?? `value matching ${input.pattern}`;
|
|
31317
|
+
return `${label}: expected ${expected}`;
|
|
31318
|
+
}
|
|
31319
|
+
return void 0;
|
|
31320
|
+
}
|
|
31321
|
+
function resolveConfigInputFlags(template, rawFlags) {
|
|
31322
|
+
const byName2 = new Map(configInputsOf(template).map((i) => [i.name, i]));
|
|
31323
|
+
const out = {};
|
|
31324
|
+
for (const raw of rawFlags) {
|
|
31325
|
+
const eq = raw.indexOf("=");
|
|
31326
|
+
if (eq < 0) return err2({ kind: "missing-equals", input: raw });
|
|
31327
|
+
const key = raw.slice(0, eq);
|
|
31328
|
+
const value = raw.slice(eq + 1).trim();
|
|
31329
|
+
const input = byName2.get(key);
|
|
31330
|
+
if (!input) {
|
|
31331
|
+
return err2({ kind: "unknown-key", key, validKeys: [...byName2.keys()] });
|
|
31332
|
+
}
|
|
31333
|
+
if (value === "") {
|
|
31334
|
+
delete out[key];
|
|
31335
|
+
continue;
|
|
31336
|
+
}
|
|
31337
|
+
const message = validateConfigInputValue(input, value);
|
|
31338
|
+
if (message) return err2({ kind: "invalid-value", key, message });
|
|
31339
|
+
out[key] = value;
|
|
31340
|
+
}
|
|
31341
|
+
return ok2(out);
|
|
31342
|
+
}
|
|
31343
|
+
|
|
31181
31344
|
// src/modules/agent/commands/create-interactive.ts
|
|
31182
31345
|
var WAIT_TIMEOUT_SECONDS = 120;
|
|
31346
|
+
var GITHUB_PAT_TEMPLATE_ID = "github-pat";
|
|
31347
|
+
var CONNECTION_NAME_RE = /^[a-z0-9]+(-[a-z0-9]+)*$/;
|
|
31183
31348
|
var ROLLBACK_CODES = /* @__PURE__ */ new Set([
|
|
31184
31349
|
"CONFLICT",
|
|
31185
31350
|
"BAD_REQUEST",
|
|
@@ -31200,7 +31365,7 @@ function classifyFailure(e2) {
|
|
|
31200
31365
|
}
|
|
31201
31366
|
async function deleteCreated(trpc, cleanup) {
|
|
31202
31367
|
let orphanAgent = null;
|
|
31203
|
-
const
|
|
31368
|
+
const orphanConnections = [];
|
|
31204
31369
|
if (cleanup.agentId) {
|
|
31205
31370
|
try {
|
|
31206
31371
|
await trpc.agents.delete.mutate({ id: cleanup.agentId });
|
|
@@ -31208,26 +31373,26 @@ async function deleteCreated(trpc, cleanup) {
|
|
|
31208
31373
|
orphanAgent = cleanup.agentId;
|
|
31209
31374
|
}
|
|
31210
31375
|
}
|
|
31211
|
-
for (const id of cleanup.
|
|
31376
|
+
for (const id of cleanup.newConnectionIds) {
|
|
31212
31377
|
try {
|
|
31213
|
-
await trpc.
|
|
31378
|
+
await trpc.connections.delete.mutate({ id });
|
|
31214
31379
|
} catch {
|
|
31215
|
-
|
|
31380
|
+
orphanConnections.push(id);
|
|
31216
31381
|
}
|
|
31217
31382
|
}
|
|
31218
|
-
return { orphanAgent,
|
|
31383
|
+
return { orphanAgent, orphanConnections };
|
|
31219
31384
|
}
|
|
31220
|
-
function formatOrphans(orphanAgent,
|
|
31221
|
-
if (!orphanAgent &&
|
|
31385
|
+
function formatOrphans(orphanAgent, orphanConnections) {
|
|
31386
|
+
if (!orphanAgent && orphanConnections.length === 0) return null;
|
|
31222
31387
|
const lines = ["Cleanup partially failed. Manual cleanup needed:"];
|
|
31223
31388
|
if (orphanAgent) {
|
|
31224
31389
|
lines.push(
|
|
31225
31390
|
` Agent: ${orphanAgent} (delete via web UI or \`dam agent delete\`)`
|
|
31226
31391
|
);
|
|
31227
31392
|
}
|
|
31228
|
-
if (
|
|
31393
|
+
if (orphanConnections.length > 0) {
|
|
31229
31394
|
lines.push(
|
|
31230
|
-
`
|
|
31395
|
+
` Connections: ${orphanConnections.join(", ")} (delete via \`dam connection disconnect\`)`
|
|
31231
31396
|
);
|
|
31232
31397
|
}
|
|
31233
31398
|
return lines.join("\n");
|
|
@@ -31296,7 +31461,7 @@ hint: run \`dam auth login\` first`
|
|
|
31296
31461
|
});
|
|
31297
31462
|
if (q(templateId)) return cancelAndExit();
|
|
31298
31463
|
const trpc = deps.createTrpcClient(host);
|
|
31299
|
-
const cleanup = {
|
|
31464
|
+
const cleanup = { newConnectionIds: [], agentId: null };
|
|
31300
31465
|
const provider = await pickProvider(trpc, cleanup);
|
|
31301
31466
|
const githubPat = await pickGithubPat(trpc, cleanup);
|
|
31302
31467
|
const spin = ft();
|
|
@@ -31319,19 +31484,39 @@ hint: run \`dam auth login\` first`
|
|
|
31319
31484
|
await handleStage1Failure(trpc, cleanup, e2);
|
|
31320
31485
|
process.exit(EXIT_RUNTIME_FAILURE);
|
|
31321
31486
|
}
|
|
31322
|
-
spin.message("Granting
|
|
31323
|
-
const
|
|
31324
|
-
|
|
31487
|
+
spin.message("Granting credentials...");
|
|
31488
|
+
const connectionIds = [];
|
|
31489
|
+
const secretIds = [];
|
|
31490
|
+
if (provider.routing.kind === "connection") {
|
|
31491
|
+
connectionIds.push(provider.routing.id);
|
|
31492
|
+
} else {
|
|
31493
|
+
secretIds.push(provider.routing.id);
|
|
31494
|
+
}
|
|
31495
|
+
if (githubPat) {
|
|
31496
|
+
if (githubPat.source === "connection") {
|
|
31497
|
+
connectionIds.push(githubPat.connectionId);
|
|
31498
|
+
} else {
|
|
31499
|
+
secretIds.push(githubPat.apiSecretId, githubPat.gitSecretId);
|
|
31500
|
+
}
|
|
31501
|
+
}
|
|
31325
31502
|
try {
|
|
31326
|
-
await withRetry(
|
|
31327
|
-
()
|
|
31328
|
-
|
|
31329
|
-
|
|
31330
|
-
|
|
31331
|
-
|
|
31503
|
+
await withRetry(async () => {
|
|
31504
|
+
if (connectionIds.length > 0) {
|
|
31505
|
+
await trpc.connections.setAgentConnections.mutate({
|
|
31506
|
+
agentId: cleanup.agentId,
|
|
31507
|
+
connectionIds
|
|
31508
|
+
});
|
|
31509
|
+
}
|
|
31510
|
+
if (secretIds.length > 0) {
|
|
31511
|
+
await trpc.secrets.setAgentAccess.mutate({
|
|
31512
|
+
agentId: cleanup.agentId,
|
|
31513
|
+
secretIds
|
|
31514
|
+
});
|
|
31515
|
+
}
|
|
31516
|
+
});
|
|
31332
31517
|
} catch (e2) {
|
|
31333
31518
|
spin.stop("Grant failed");
|
|
31334
|
-
R2.error(`Failed to grant
|
|
31519
|
+
R2.error(`Failed to grant credentials: ${errorReason2(e2)}`);
|
|
31335
31520
|
R2.warn(
|
|
31336
31521
|
`Agent ${name} was created but the credential grant did not land. Configure access via the web UI, or run \`dam agent delete ${name}\` to start over.`
|
|
31337
31522
|
);
|
|
@@ -31403,9 +31588,9 @@ async function cancelAndCleanup(trpc, cleanup) {
|
|
|
31403
31588
|
process.exit(0);
|
|
31404
31589
|
}
|
|
31405
31590
|
async function flushCleanup(trpc, cleanup) {
|
|
31406
|
-
if (cleanup.agentId === null && cleanup.
|
|
31407
|
-
const { orphanAgent,
|
|
31408
|
-
const summary = formatOrphans(orphanAgent,
|
|
31591
|
+
if (cleanup.agentId === null && cleanup.newConnectionIds.length === 0) return;
|
|
31592
|
+
const { orphanAgent, orphanConnections } = await deleteCreated(trpc, cleanup);
|
|
31593
|
+
const summary = formatOrphans(orphanAgent, orphanConnections);
|
|
31409
31594
|
if (summary) R2.warn(summary);
|
|
31410
31595
|
}
|
|
31411
31596
|
async function handleStage1Failure(trpc, cleanup, originalError) {
|
|
@@ -31418,8 +31603,8 @@ async function handleStage1Failure(trpc, cleanup, originalError) {
|
|
|
31418
31603
|
R2.error(`Failed to create agent: ${reason}`);
|
|
31419
31604
|
const lines = [];
|
|
31420
31605
|
if (cleanup.agentId) lines.push(` Agent: ${cleanup.agentId}`);
|
|
31421
|
-
if (cleanup.
|
|
31422
|
-
lines.push(`
|
|
31606
|
+
if (cleanup.newConnectionIds.length > 0) {
|
|
31607
|
+
lines.push(` Connections: ${cleanup.newConnectionIds.join(", ")}`);
|
|
31423
31608
|
}
|
|
31424
31609
|
if (lines.length > 0) {
|
|
31425
31610
|
R2.warn(
|
|
@@ -31430,229 +31615,304 @@ async function handleStage1Failure(trpc, cleanup, originalError) {
|
|
|
31430
31615
|
);
|
|
31431
31616
|
}
|
|
31432
31617
|
}
|
|
31433
|
-
async function
|
|
31434
|
-
let list;
|
|
31618
|
+
async function listCredentials(trpc, cleanup) {
|
|
31435
31619
|
try {
|
|
31436
|
-
|
|
31620
|
+
return {
|
|
31621
|
+
conns: await trpc.connections.list.query(),
|
|
31622
|
+
secrets: await trpc.secrets.list.query(),
|
|
31623
|
+
templates: await trpc.connections.listTemplates.query()
|
|
31624
|
+
};
|
|
31437
31625
|
} catch (e2) {
|
|
31438
|
-
me(`failed to list
|
|
31626
|
+
me(`failed to list credentials: ${errorReason2(e2)}`);
|
|
31439
31627
|
await flushCleanup(trpc, cleanup);
|
|
31440
31628
|
process.exit(EXIT_RUNTIME_FAILURE);
|
|
31441
31629
|
}
|
|
31442
|
-
|
|
31443
|
-
|
|
31630
|
+
}
|
|
31631
|
+
async function pickProvider(trpc, cleanup) {
|
|
31632
|
+
const { conns, secrets, templates } = await listCredentials(trpc, cleanup);
|
|
31633
|
+
const existingConns = providerConns(conns);
|
|
31634
|
+
const existingSecrets = secrets.filter(
|
|
31635
|
+
(s) => isProviderPresetType(s.type)
|
|
31444
31636
|
).map((s) => ({ id: s.id, name: s.name, type: s.type }));
|
|
31445
|
-
if (
|
|
31637
|
+
if (existingConns.length === 0 && existingSecrets.length === 0) {
|
|
31446
31638
|
R2.info("No model providers configured yet \u2014 let's add one.");
|
|
31447
|
-
return addOrReplaceProvider(trpc, cleanup,
|
|
31639
|
+
return addOrReplaceProvider(trpc, cleanup, existingConns, templates);
|
|
31448
31640
|
}
|
|
31449
31641
|
const NEW = "__new__";
|
|
31450
31642
|
const picked = await Ee({
|
|
31451
31643
|
message: "Model provider",
|
|
31452
31644
|
options: [
|
|
31453
|
-
...
|
|
31645
|
+
...existingConns.map((c2) => ({
|
|
31646
|
+
value: `conn:${c2.id}`,
|
|
31647
|
+
label: `${c2.name} (${c2.type})`
|
|
31648
|
+
})),
|
|
31649
|
+
...existingSecrets.map((s) => ({
|
|
31650
|
+
value: `secret:${s.id}`,
|
|
31651
|
+
label: `${s.name} (${s.type}) (legacy)`
|
|
31652
|
+
})),
|
|
31454
31653
|
{ value: NEW, label: "Add new..." }
|
|
31455
31654
|
]
|
|
31456
31655
|
});
|
|
31457
31656
|
if (q(picked)) return cancelAndCleanup(trpc, cleanup);
|
|
31458
|
-
if (picked === NEW)
|
|
31459
|
-
|
|
31460
|
-
|
|
31461
|
-
|
|
31462
|
-
|
|
31463
|
-
|
|
31657
|
+
if (picked === NEW) {
|
|
31658
|
+
return addOrReplaceProvider(trpc, cleanup, existingConns, templates);
|
|
31659
|
+
}
|
|
31660
|
+
if (picked.startsWith("conn:")) {
|
|
31661
|
+
const found2 = existingConns.find((c2) => `conn:${c2.id}` === picked);
|
|
31662
|
+
return {
|
|
31663
|
+
routing: { kind: "connection", id: found2.id },
|
|
31664
|
+
name: found2.name,
|
|
31665
|
+
type: found2.type
|
|
31666
|
+
};
|
|
31464
31667
|
}
|
|
31668
|
+
const found = existingSecrets.find((s) => `secret:${s.id}` === picked);
|
|
31465
31669
|
return {
|
|
31466
|
-
|
|
31670
|
+
routing: { kind: "secret", id: found.id },
|
|
31467
31671
|
name: found.name,
|
|
31468
|
-
type: found.type
|
|
31469
|
-
createdNew: false
|
|
31672
|
+
type: found.type
|
|
31470
31673
|
};
|
|
31471
31674
|
}
|
|
31472
|
-
|
|
31675
|
+
function providerConns(conns) {
|
|
31676
|
+
return conns.filter((c2) => PROVIDER_TEMPLATE_IDS.has(c2.templateId)).map((c2) => {
|
|
31677
|
+
const type = providerTypeForTemplateId(c2.templateId);
|
|
31678
|
+
return type ? { id: c2.id, name: c2.name, templateId: c2.templateId, type } : null;
|
|
31679
|
+
}).filter((c2) => c2 !== null);
|
|
31680
|
+
}
|
|
31681
|
+
async function addOrReplaceProvider(trpc, cleanup, existingConns, templates) {
|
|
31473
31682
|
while (true) {
|
|
31474
31683
|
const type = await Ee({
|
|
31475
31684
|
message: "Provider type",
|
|
31476
|
-
options:
|
|
31477
|
-
|
|
31478
|
-
|
|
31479
|
-
|
|
31480
|
-
]
|
|
31685
|
+
options: PROVIDER_PRESET_TYPES.map((t) => ({
|
|
31686
|
+
value: t,
|
|
31687
|
+
label: PROVIDERS[t].displayName
|
|
31688
|
+
}))
|
|
31481
31689
|
});
|
|
31482
31690
|
if (q(type)) return cancelAndCleanup(trpc, cleanup);
|
|
31483
|
-
const existingOfType =
|
|
31691
|
+
const existingOfType = existingConns.find((c2) => c2.type === type);
|
|
31484
31692
|
if (existingOfType) {
|
|
31485
31693
|
const replace = await ue({
|
|
31486
|
-
message: `A ${PROVIDERS[type].displayName}
|
|
31694
|
+
message: `A ${PROVIDERS[type].displayName} connection already exists. Replace its credential?`,
|
|
31487
31695
|
initialValue: false
|
|
31488
31696
|
});
|
|
31489
31697
|
if (q(replace)) return cancelAndCleanup(trpc, cleanup);
|
|
31490
31698
|
if (!replace) {
|
|
31491
31699
|
return {
|
|
31492
|
-
|
|
31700
|
+
routing: { kind: "connection", id: existingOfType.id },
|
|
31493
31701
|
name: existingOfType.name,
|
|
31494
|
-
type
|
|
31495
|
-
createdNew: false
|
|
31702
|
+
type
|
|
31496
31703
|
};
|
|
31497
31704
|
}
|
|
31498
|
-
const
|
|
31499
|
-
|
|
31500
|
-
validate(v2) {
|
|
31501
|
-
if (!v2 || v2.trim() === "") return "Required";
|
|
31502
|
-
return void 0;
|
|
31503
|
-
}
|
|
31504
|
-
});
|
|
31505
|
-
if (q(apiKey2)) return cancelAndCleanup(trpc, cleanup);
|
|
31506
|
-
const updateInput = await parseOrExit(
|
|
31507
|
-
secretUpdateInputSchema,
|
|
31508
|
-
{ id: existingOfType.id, value: apiKey2 },
|
|
31509
|
-
EXIT_INVALID_INPUT,
|
|
31510
|
-
() => flushCleanup(trpc, cleanup)
|
|
31705
|
+
const value2 = await promptSecret(
|
|
31706
|
+
`New ${PROVIDERS[type].displayName} credential`
|
|
31511
31707
|
);
|
|
31708
|
+
if (q(value2)) return cancelAndCleanup(trpc, cleanup);
|
|
31709
|
+
const templateId2 = templateIdForProvider(type, value2);
|
|
31710
|
+
if (templateId2 !== existingOfType.templateId) {
|
|
31711
|
+
const have = existingOfType.templateId === "anthropic-oauth" ? "an OAuth token" : "an API key";
|
|
31712
|
+
const got = templateId2 === "anthropic-oauth" ? "an OAuth token" : "an API key";
|
|
31713
|
+
R2.error(
|
|
31714
|
+
`This connection expects ${have}, but that looks like ${got}. Paste a matching credential, or disconnect it and add a new one to switch.`
|
|
31715
|
+
);
|
|
31716
|
+
continue;
|
|
31717
|
+
}
|
|
31512
31718
|
try {
|
|
31513
|
-
await trpc.
|
|
31719
|
+
await trpc.connections.update.mutate({
|
|
31720
|
+
id: existingOfType.id,
|
|
31721
|
+
value: value2
|
|
31722
|
+
});
|
|
31514
31723
|
return {
|
|
31515
|
-
|
|
31724
|
+
routing: { kind: "connection", id: existingOfType.id },
|
|
31516
31725
|
name: existingOfType.name,
|
|
31517
|
-
type
|
|
31518
|
-
createdNew: false
|
|
31726
|
+
type
|
|
31519
31727
|
};
|
|
31520
31728
|
} catch (e2) {
|
|
31521
|
-
R2.error(`Failed to replace
|
|
31729
|
+
R2.error(`Failed to replace credential: ${errorReason2(e2)}`);
|
|
31522
31730
|
continue;
|
|
31523
31731
|
}
|
|
31524
31732
|
}
|
|
31525
|
-
const
|
|
31526
|
-
|
|
31527
|
-
|
|
31528
|
-
|
|
31529
|
-
|
|
31530
|
-
|
|
31531
|
-
|
|
31532
|
-
|
|
31533
|
-
|
|
31534
|
-
|
|
31535
|
-
|
|
31536
|
-
|
|
31537
|
-
|
|
31538
|
-
|
|
31733
|
+
const value = await promptSecret(
|
|
31734
|
+
`${PROVIDERS[type].displayName} credential`
|
|
31735
|
+
);
|
|
31736
|
+
if (q(value)) return cancelAndCleanup(trpc, cleanup);
|
|
31737
|
+
const templateId = templateIdForProvider(type, value);
|
|
31738
|
+
const template = templates.find((t) => t.id === templateId);
|
|
31739
|
+
const configInputs = template ? await promptConfigInputs(trpc, cleanup, template) : {};
|
|
31740
|
+
const created = await createProviderConnection(
|
|
31741
|
+
trpc,
|
|
31742
|
+
cleanup,
|
|
31743
|
+
type,
|
|
31744
|
+
templateId,
|
|
31745
|
+
value,
|
|
31746
|
+
configInputs
|
|
31539
31747
|
);
|
|
31748
|
+
if (created) return created;
|
|
31749
|
+
}
|
|
31750
|
+
}
|
|
31751
|
+
async function promptConfigInputs(trpc, cleanup, template) {
|
|
31752
|
+
const inputs = configInputsOf(template);
|
|
31753
|
+
if (inputs.length === 0) return {};
|
|
31754
|
+
Se("Optional configuration \u2014 press Enter to skip each.");
|
|
31755
|
+
const out = {};
|
|
31756
|
+
for (const input of inputs) {
|
|
31757
|
+
const label = input.label ?? input.name;
|
|
31758
|
+
if (input.enumValues) {
|
|
31759
|
+
const SKIP = "__skip__";
|
|
31760
|
+
const choice = await Ee({
|
|
31761
|
+
message: input.hint ? `${label} \u2014 ${input.hint}` : label,
|
|
31762
|
+
options: [
|
|
31763
|
+
...input.enumValues.map((v2) => ({ value: v2, label: v2 })),
|
|
31764
|
+
{ value: SKIP, label: "Skip" }
|
|
31765
|
+
],
|
|
31766
|
+
initialValue: SKIP
|
|
31767
|
+
});
|
|
31768
|
+
if (q(choice)) return cancelAndCleanup(trpc, cleanup);
|
|
31769
|
+
if (choice !== SKIP) out[input.name] = choice;
|
|
31770
|
+
continue;
|
|
31771
|
+
}
|
|
31772
|
+
const answer = await Re({
|
|
31773
|
+
message: input.hint ? `${label} \u2014 ${input.hint}` : label,
|
|
31774
|
+
validate: (v2) => validateConfigInputValue(input, v2 ?? "")
|
|
31775
|
+
});
|
|
31776
|
+
if (q(answer)) return cancelAndCleanup(trpc, cleanup);
|
|
31777
|
+
const trimmed = answer.trim();
|
|
31778
|
+
if (trimmed) out[input.name] = trimmed;
|
|
31779
|
+
}
|
|
31780
|
+
return out;
|
|
31781
|
+
}
|
|
31782
|
+
async function createConnectionWithRename(trpc, cleanup, params) {
|
|
31783
|
+
let name = params.name;
|
|
31784
|
+
const hasConfig = params.configInputs && Object.keys(params.configInputs).length > 0;
|
|
31785
|
+
while (true) {
|
|
31540
31786
|
try {
|
|
31541
|
-
const created = await trpc.
|
|
31542
|
-
|
|
31543
|
-
|
|
31544
|
-
|
|
31545
|
-
|
|
31546
|
-
|
|
31547
|
-
|
|
31548
|
-
|
|
31787
|
+
const created = await trpc.connections.create.mutate({
|
|
31788
|
+
templateId: params.templateId,
|
|
31789
|
+
name,
|
|
31790
|
+
authKind: "header",
|
|
31791
|
+
value: params.value,
|
|
31792
|
+
...hasConfig ? { configInputs: params.configInputs } : {}
|
|
31793
|
+
});
|
|
31794
|
+
cleanup.newConnectionIds.push(created.id);
|
|
31795
|
+
return { id: created.id, name };
|
|
31549
31796
|
} catch (e2) {
|
|
31550
|
-
|
|
31797
|
+
if (trpcCode(e2) === "CONFLICT") {
|
|
31798
|
+
const renamed = await Re({
|
|
31799
|
+
message: `A connection named "${name}" already exists. Choose a different name`,
|
|
31800
|
+
validate(v2) {
|
|
31801
|
+
if (!v2 || !CONNECTION_NAME_RE.test(v2)) {
|
|
31802
|
+
return `lowercase letters, digits, and single hyphens (e.g. ${params.nameExample})`;
|
|
31803
|
+
}
|
|
31804
|
+
return void 0;
|
|
31805
|
+
}
|
|
31806
|
+
});
|
|
31807
|
+
if (q(renamed)) return cancelAndCleanup(trpc, cleanup);
|
|
31808
|
+
name = renamed;
|
|
31809
|
+
continue;
|
|
31810
|
+
}
|
|
31811
|
+
R2.error(`Failed to create connection: ${errorReason2(e2)}`);
|
|
31812
|
+
return null;
|
|
31551
31813
|
}
|
|
31552
31814
|
}
|
|
31553
31815
|
}
|
|
31816
|
+
async function createProviderConnection(trpc, cleanup, type, templateId, value, configInputs) {
|
|
31817
|
+
const created = await createConnectionWithRename(trpc, cleanup, {
|
|
31818
|
+
templateId,
|
|
31819
|
+
name: templateId,
|
|
31820
|
+
value,
|
|
31821
|
+
nameExample: "my-anthropic",
|
|
31822
|
+
configInputs
|
|
31823
|
+
});
|
|
31824
|
+
if (!created) return null;
|
|
31825
|
+
return {
|
|
31826
|
+
routing: { kind: "connection", id: created.id },
|
|
31827
|
+
name: created.name,
|
|
31828
|
+
type
|
|
31829
|
+
};
|
|
31830
|
+
}
|
|
31831
|
+
var DEFAULT_GITHUB_PAT_NAME = GITHUB_PAT_TEMPLATE_ID;
|
|
31554
31832
|
async function pickGithubPat(trpc, cleanup) {
|
|
31555
|
-
|
|
31556
|
-
|
|
31557
|
-
|
|
31558
|
-
|
|
31559
|
-
me(`failed to list secrets: ${errorReason2(e2)}`);
|
|
31560
|
-
await flushCleanup(trpc, cleanup);
|
|
31561
|
-
process.exit(EXIT_RUNTIME_FAILURE);
|
|
31562
|
-
}
|
|
31563
|
-
const pairs = groupGithubPats(list);
|
|
31564
|
-
if (pairs.length === 0) {
|
|
31833
|
+
const { conns, secrets } = await listCredentials(trpc, cleanup);
|
|
31834
|
+
const patConns = conns.filter((c2) => c2.templateId === GITHUB_PAT_TEMPLATE_ID);
|
|
31835
|
+
const pairs = groupGithubPats(secrets);
|
|
31836
|
+
if (patConns.length === 0 && pairs.length === 0) {
|
|
31565
31837
|
R2.info("No GitHub PAT configured yet.");
|
|
31566
31838
|
const add = await ue({ message: "Add one?", initialValue: true });
|
|
31567
31839
|
if (q(add)) return cancelAndCleanup(trpc, cleanup);
|
|
31568
31840
|
if (!add) return null;
|
|
31569
|
-
return addOrReplaceGithubPat(trpc, cleanup,
|
|
31841
|
+
return addOrReplaceGithubPat(trpc, cleanup, patConns);
|
|
31570
31842
|
}
|
|
31571
31843
|
const NEW = "__new__";
|
|
31572
31844
|
const SKIP = "__skip__";
|
|
31573
31845
|
const picked = await Ee({
|
|
31574
31846
|
message: "GitHub PAT",
|
|
31575
31847
|
options: [
|
|
31576
|
-
...
|
|
31848
|
+
...patConns.map((c2) => ({ value: `conn:${c2.id}`, label: c2.name })),
|
|
31849
|
+
...pairs.map((p2) => ({
|
|
31850
|
+
value: `secret:${p2.name}`,
|
|
31851
|
+
label: `${p2.name} (legacy)`
|
|
31852
|
+
})),
|
|
31577
31853
|
{ value: NEW, label: "Add new..." },
|
|
31578
31854
|
{ value: SKIP, label: "Skip" }
|
|
31579
31855
|
]
|
|
31580
31856
|
});
|
|
31581
31857
|
if (q(picked)) return cancelAndCleanup(trpc, cleanup);
|
|
31582
31858
|
if (picked === SKIP) return null;
|
|
31583
|
-
if (picked === NEW) return addOrReplaceGithubPat(trpc, cleanup,
|
|
31584
|
-
|
|
31585
|
-
|
|
31586
|
-
|
|
31587
|
-
await flushCleanup(trpc, cleanup);
|
|
31588
|
-
process.exit(EXIT_RUNTIME_FAILURE);
|
|
31859
|
+
if (picked === NEW) return addOrReplaceGithubPat(trpc, cleanup, patConns);
|
|
31860
|
+
if (picked.startsWith("conn:")) {
|
|
31861
|
+
const found2 = patConns.find((c2) => `conn:${c2.id}` === picked);
|
|
31862
|
+
return { source: "connection", connectionId: found2.id, name: found2.name };
|
|
31589
31863
|
}
|
|
31590
|
-
|
|
31864
|
+
const found = pairs.find((p2) => `secret:${p2.name}` === picked);
|
|
31865
|
+
return {
|
|
31866
|
+
source: "secret",
|
|
31867
|
+
apiSecretId: found.apiSecretId,
|
|
31868
|
+
gitSecretId: found.gitSecretId,
|
|
31869
|
+
name: found.name
|
|
31870
|
+
};
|
|
31591
31871
|
}
|
|
31592
|
-
var DEFAULT_GITHUB_PAT_NAME = "GitHub";
|
|
31593
31872
|
async function addOrReplaceGithubPat(trpc, cleanup, existing) {
|
|
31594
|
-
const collide = existing.find((
|
|
31873
|
+
const collide = existing.find((c2) => c2.name === DEFAULT_GITHUB_PAT_NAME);
|
|
31595
31874
|
while (true) {
|
|
31596
31875
|
if (collide) {
|
|
31597
31876
|
const replace = await ue({
|
|
31598
|
-
message: `A GitHub PAT named "${DEFAULT_GITHUB_PAT_NAME}" already exists. Replace its token?`,
|
|
31877
|
+
message: `A GitHub PAT connection named "${DEFAULT_GITHUB_PAT_NAME}" already exists. Replace its token?`,
|
|
31599
31878
|
initialValue: false
|
|
31600
31879
|
});
|
|
31601
31880
|
if (q(replace)) return cancelAndCleanup(trpc, cleanup);
|
|
31602
31881
|
if (!replace) {
|
|
31603
|
-
return {
|
|
31882
|
+
return {
|
|
31883
|
+
source: "connection",
|
|
31884
|
+
connectionId: collide.id,
|
|
31885
|
+
name: collide.name
|
|
31886
|
+
};
|
|
31604
31887
|
}
|
|
31605
|
-
const token2 = await
|
|
31606
|
-
message: "New GitHub personal access token",
|
|
31607
|
-
validate(v2) {
|
|
31608
|
-
if (!v2 || v2.trim() === "") return "Required";
|
|
31609
|
-
return void 0;
|
|
31610
|
-
}
|
|
31611
|
-
});
|
|
31888
|
+
const token2 = await promptSecret("New GitHub personal access token");
|
|
31612
31889
|
if (q(token2)) return cancelAndCleanup(trpc, cleanup);
|
|
31613
|
-
const updateInput = await parseOrExit(
|
|
31614
|
-
secretUpdateGithubPatInputSchema,
|
|
31615
|
-
{
|
|
31616
|
-
apiSecretId: collide.apiSecretId,
|
|
31617
|
-
gitSecretId: collide.gitSecretId,
|
|
31618
|
-
token: token2
|
|
31619
|
-
},
|
|
31620
|
-
EXIT_INVALID_INPUT,
|
|
31621
|
-
() => flushCleanup(trpc, cleanup)
|
|
31622
|
-
);
|
|
31623
31890
|
try {
|
|
31624
|
-
await trpc.
|
|
31625
|
-
return {
|
|
31891
|
+
await trpc.connections.update.mutate({ id: collide.id, value: token2 });
|
|
31892
|
+
return {
|
|
31893
|
+
source: "connection",
|
|
31894
|
+
connectionId: collide.id,
|
|
31895
|
+
name: collide.name
|
|
31896
|
+
};
|
|
31626
31897
|
} catch (e2) {
|
|
31627
31898
|
R2.error(`Failed to replace GitHub PAT: ${errorReason2(e2)}`);
|
|
31628
31899
|
continue;
|
|
31629
31900
|
}
|
|
31630
31901
|
}
|
|
31631
|
-
const token = await
|
|
31632
|
-
message: "GitHub personal access token",
|
|
31633
|
-
validate(v2) {
|
|
31634
|
-
if (!v2 || v2.trim() === "") return "Required";
|
|
31635
|
-
return void 0;
|
|
31636
|
-
}
|
|
31637
|
-
});
|
|
31902
|
+
const token = await promptSecret("GitHub personal access token");
|
|
31638
31903
|
if (q(token)) return cancelAndCleanup(trpc, cleanup);
|
|
31639
|
-
const
|
|
31640
|
-
|
|
31641
|
-
|
|
31642
|
-
|
|
31643
|
-
|
|
31644
|
-
);
|
|
31645
|
-
|
|
31646
|
-
const created = await trpc.secrets.createGithubPat.mutate(createInput);
|
|
31647
|
-
cleanup.newSecretIds.push(created.apiSecretId, created.gitSecretId);
|
|
31904
|
+
const created = await createConnectionWithRename(trpc, cleanup, {
|
|
31905
|
+
templateId: GITHUB_PAT_TEMPLATE_ID,
|
|
31906
|
+
name: DEFAULT_GITHUB_PAT_NAME,
|
|
31907
|
+
value: token,
|
|
31908
|
+
nameExample: "my-github"
|
|
31909
|
+
});
|
|
31910
|
+
if (created) {
|
|
31648
31911
|
return {
|
|
31649
|
-
|
|
31650
|
-
|
|
31651
|
-
|
|
31652
|
-
createdNew: true
|
|
31912
|
+
source: "connection",
|
|
31913
|
+
connectionId: created.id,
|
|
31914
|
+
name: created.name
|
|
31653
31915
|
};
|
|
31654
|
-
} catch (e2) {
|
|
31655
|
-
R2.error(`Failed to create GitHub PAT: ${errorReason2(e2)}`);
|
|
31656
31916
|
}
|
|
31657
31917
|
}
|
|
31658
31918
|
}
|
|
@@ -31701,6 +31961,37 @@ function createAgentResolver(deps) {
|
|
|
31701
31961
|
};
|
|
31702
31962
|
}
|
|
31703
31963
|
|
|
31964
|
+
// src/modules/agent/commands/errors.ts
|
|
31965
|
+
function exitCodeForResolveError(error51) {
|
|
31966
|
+
return error51.kind === "not-found" || error51.kind === "ambiguous" ? EXIT_AGENT_NOT_RESOLVED : EXIT_RUNTIME_FAILURE;
|
|
31967
|
+
}
|
|
31968
|
+
function printResolveError(error51, host) {
|
|
31969
|
+
switch (error51.kind) {
|
|
31970
|
+
case "not-found":
|
|
31971
|
+
if (error51.via === "id") {
|
|
31972
|
+
process.stderr.write(`error: no agent with id \`${error51.ref}\`
|
|
31973
|
+
`);
|
|
31974
|
+
} else {
|
|
31975
|
+
process.stderr.write(`error: no agent named "${error51.ref}"
|
|
31976
|
+
`);
|
|
31977
|
+
}
|
|
31978
|
+
return;
|
|
31979
|
+
case "ambiguous":
|
|
31980
|
+
process.stderr.write(`error: multiple agents named "${error51.ref}":
|
|
31981
|
+
`);
|
|
31982
|
+
for (const m of error51.matches) {
|
|
31983
|
+
process.stderr.write(` - \`${m.id}\`
|
|
31984
|
+
`);
|
|
31985
|
+
}
|
|
31986
|
+
process.stderr.write("hint: specify by id instead\n");
|
|
31987
|
+
return;
|
|
31988
|
+
case "auth-required":
|
|
31989
|
+
case "transport":
|
|
31990
|
+
printServiceError(error51, host);
|
|
31991
|
+
return;
|
|
31992
|
+
}
|
|
31993
|
+
}
|
|
31994
|
+
|
|
31704
31995
|
// src/modules/shared/prompt.ts
|
|
31705
31996
|
import { createInterface as createInterface2 } from "readline/promises";
|
|
31706
31997
|
var DEFAULT_PROMPT_TIMEOUT_MS = 3e4;
|
|
@@ -32136,6 +32427,24 @@ function createAgentService(deps) {
|
|
|
32136
32427
|
} catch (e2) {
|
|
32137
32428
|
return notFoundOnMutate(e2, id);
|
|
32138
32429
|
}
|
|
32430
|
+
},
|
|
32431
|
+
async updateAllowedUserEmails(id, emails) {
|
|
32432
|
+
try {
|
|
32433
|
+
return ok2(
|
|
32434
|
+
await deps.trpc.agents.update.mutate({
|
|
32435
|
+
id,
|
|
32436
|
+
allowedUserEmails: [...emails]
|
|
32437
|
+
})
|
|
32438
|
+
);
|
|
32439
|
+
} catch (e2) {
|
|
32440
|
+
if (e2?.data?.code === "BAD_REQUEST") {
|
|
32441
|
+
return err2({
|
|
32442
|
+
kind: "invalid-input",
|
|
32443
|
+
message: e2 instanceof Error ? e2.message : String(e2)
|
|
32444
|
+
});
|
|
32445
|
+
}
|
|
32446
|
+
return notFoundOnMutate(e2, id);
|
|
32447
|
+
}
|
|
32139
32448
|
}
|
|
32140
32449
|
};
|
|
32141
32450
|
}
|
|
@@ -32299,6 +32608,20 @@ function buildDenyCommand(deps) {
|
|
|
32299
32608
|
);
|
|
32300
32609
|
}
|
|
32301
32610
|
|
|
32611
|
+
// src/modules/agent/domain/allowed-users.ts
|
|
32612
|
+
function mergeAllowedUserEmails(current, opts) {
|
|
32613
|
+
const removeSet = new Set((opts.remove ?? []).map((e2) => e2.toLowerCase()));
|
|
32614
|
+
const seen = /* @__PURE__ */ new Set();
|
|
32615
|
+
const result = [];
|
|
32616
|
+
for (const email3 of [...current, ...opts.add ?? []]) {
|
|
32617
|
+
const key = email3.toLowerCase();
|
|
32618
|
+
if (removeSet.has(key) || seen.has(key)) continue;
|
|
32619
|
+
seen.add(key);
|
|
32620
|
+
result.push(email3);
|
|
32621
|
+
}
|
|
32622
|
+
return result;
|
|
32623
|
+
}
|
|
32624
|
+
|
|
32302
32625
|
// src/modules/shared/relative-time.ts
|
|
32303
32626
|
var MINUTE_MS = 6e4;
|
|
32304
32627
|
var HOUR_MS = 36e5;
|
|
@@ -32819,10 +33142,7 @@ function buildTokenCreateCommand(deps) {
|
|
|
32819
33142
|
`);
|
|
32820
33143
|
}
|
|
32821
33144
|
} catch (err3) {
|
|
32822
|
-
|
|
32823
|
-
`error: ${err3 instanceof Error ? err3.message : String(err3)}
|
|
32824
|
-
`
|
|
32825
|
-
);
|
|
33145
|
+
printTrpcError(err3, resolved.value.server);
|
|
32826
33146
|
process.exit(EXIT_RUNTIME_FAILURE);
|
|
32827
33147
|
}
|
|
32828
33148
|
}
|
|
@@ -32863,10 +33183,7 @@ function buildTokenListCommand(deps) {
|
|
|
32863
33183
|
);
|
|
32864
33184
|
}
|
|
32865
33185
|
} catch (err3) {
|
|
32866
|
-
|
|
32867
|
-
`error: ${err3 instanceof Error ? err3.message : String(err3)}
|
|
32868
|
-
`
|
|
32869
|
-
);
|
|
33186
|
+
printTrpcError(err3, resolved.value.server);
|
|
32870
33187
|
process.exit(EXIT_RUNTIME_FAILURE);
|
|
32871
33188
|
}
|
|
32872
33189
|
});
|
|
@@ -32890,10 +33207,7 @@ function buildTokenRevokeCommand(deps) {
|
|
|
32890
33207
|
process.stdout.write(`\u2713 Revoked ${id}
|
|
32891
33208
|
`);
|
|
32892
33209
|
} catch (err3) {
|
|
32893
|
-
|
|
32894
|
-
`error: ${err3 instanceof Error ? err3.message : String(err3)}
|
|
32895
|
-
`
|
|
32896
|
-
);
|
|
33210
|
+
printTrpcError(err3, resolved.value.server);
|
|
32897
33211
|
process.exit(EXIT_RUNTIME_FAILURE);
|
|
32898
33212
|
}
|
|
32899
33213
|
});
|
|
@@ -32967,17 +33281,6 @@ function createAuthConfigProbe(opts = {}) {
|
|
|
32967
33281
|
};
|
|
32968
33282
|
}
|
|
32969
33283
|
|
|
32970
|
-
// src/modules/auth/infrastructure/auth-env-reader.ts
|
|
32971
|
-
var DAM_TOKEN_ENV_VAR = "DAM_TOKEN";
|
|
32972
|
-
function createProcessAuthEnvReader(env = process.env) {
|
|
32973
|
-
return {
|
|
32974
|
-
damToken() {
|
|
32975
|
-
const v2 = env[DAM_TOKEN_ENV_VAR];
|
|
32976
|
-
return v2 && v2.length > 0 ? v2 : void 0;
|
|
32977
|
-
}
|
|
32978
|
-
};
|
|
32979
|
-
}
|
|
32980
|
-
|
|
32981
33284
|
// src/modules/auth/infrastructure/auth-path.ts
|
|
32982
33285
|
import { homedir } from "os";
|
|
32983
33286
|
import { join } from "path";
|
|
@@ -35339,60 +35642,679 @@ function composeAuthModule(opts) {
|
|
|
35339
35642
|
const authService = createAuthService({
|
|
35340
35643
|
compatService: opts.compatService,
|
|
35341
35644
|
configService: opts.configService,
|
|
35342
|
-
authConfigProbe,
|
|
35343
|
-
oidcDiscovery,
|
|
35344
|
-
deviceFlowClient,
|
|
35345
|
-
tokenEndpointClient,
|
|
35346
|
-
revokeClient,
|
|
35347
|
-
browserOpener,
|
|
35348
|
-
authStore,
|
|
35349
|
-
authEnvReader
|
|
35350
|
-
});
|
|
35351
|
-
const authParent = new Command("auth").description(
|
|
35352
|
-
"Authenticate against a Platform deployment (OAuth 2.0 Device Authorization Grant)"
|
|
35645
|
+
authConfigProbe,
|
|
35646
|
+
oidcDiscovery,
|
|
35647
|
+
deviceFlowClient,
|
|
35648
|
+
tokenEndpointClient,
|
|
35649
|
+
revokeClient,
|
|
35650
|
+
browserOpener,
|
|
35651
|
+
authStore,
|
|
35652
|
+
authEnvReader
|
|
35653
|
+
});
|
|
35654
|
+
const authParent = new Command("auth").description(
|
|
35655
|
+
"Authenticate against a Platform deployment (OAuth 2.0 Device Authorization Grant)"
|
|
35656
|
+
);
|
|
35657
|
+
authParent.addCommand(
|
|
35658
|
+
buildLoginCommand({
|
|
35659
|
+
authService,
|
|
35660
|
+
configService: opts.configService,
|
|
35661
|
+
authEnvReader
|
|
35662
|
+
})
|
|
35663
|
+
);
|
|
35664
|
+
authParent.addCommand(
|
|
35665
|
+
buildLogoutCommand({
|
|
35666
|
+
authService,
|
|
35667
|
+
configService: opts.configService
|
|
35668
|
+
})
|
|
35669
|
+
);
|
|
35670
|
+
authParent.addCommand(buildStatusCommand({ authService }));
|
|
35671
|
+
const buildTrpc = (host) => createTrpcClient({ host, tokenProvider });
|
|
35672
|
+
const tokenParent = new Command("token").description(
|
|
35673
|
+
"Manage API keys for headless / CI use"
|
|
35674
|
+
);
|
|
35675
|
+
tokenParent.addCommand(
|
|
35676
|
+
buildTokenCreateCommand({
|
|
35677
|
+
configService: opts.configService,
|
|
35678
|
+
buildTrpc
|
|
35679
|
+
})
|
|
35680
|
+
);
|
|
35681
|
+
tokenParent.addCommand(
|
|
35682
|
+
buildTokenListCommand({
|
|
35683
|
+
configService: opts.configService,
|
|
35684
|
+
buildTrpc
|
|
35685
|
+
})
|
|
35686
|
+
);
|
|
35687
|
+
tokenParent.addCommand(
|
|
35688
|
+
buildTokenRevokeCommand({
|
|
35689
|
+
configService: opts.configService,
|
|
35690
|
+
buildTrpc
|
|
35691
|
+
})
|
|
35692
|
+
);
|
|
35693
|
+
authParent.addCommand(tokenParent);
|
|
35694
|
+
return {
|
|
35695
|
+
commands: [authParent],
|
|
35696
|
+
exports: { tokenProvider },
|
|
35697
|
+
internals: { authStore, authPath, authEnvReader }
|
|
35698
|
+
};
|
|
35699
|
+
}
|
|
35700
|
+
|
|
35701
|
+
// src/modules/channel/commands/allow.ts
|
|
35702
|
+
var collect = (v2, acc) => [...acc, v2];
|
|
35703
|
+
var emailSchema = external_exports.email();
|
|
35704
|
+
function buildAllowCommand(deps) {
|
|
35705
|
+
return new Command("allow").description(
|
|
35706
|
+
"Add one or more users to an Agent's allowed-user list (gates Slack drivers)"
|
|
35707
|
+
).argument("<agent>", "Agent Ref \u2014 name or 'agent-\u2026' ID").option(
|
|
35708
|
+
"--user <email>",
|
|
35709
|
+
"user email to allow (repeatable)",
|
|
35710
|
+
collect,
|
|
35711
|
+
[]
|
|
35712
|
+
).option(
|
|
35713
|
+
"--server <url>",
|
|
35714
|
+
"override the configured server URL for this call"
|
|
35715
|
+
).option("--json", "emit { ok, agentId, allowedUserEmails } as JSON").addHelpText(
|
|
35716
|
+
"after",
|
|
35717
|
+
"\nExamples:\n dam channel allow my-agent --user teammate@example.com\n dam channel allow my-agent --user a@x.com --user b@y.com\n"
|
|
35718
|
+
).action(
|
|
35719
|
+
async (ref, opts) => {
|
|
35720
|
+
const users = opts.user;
|
|
35721
|
+
if (users.length === 0) {
|
|
35722
|
+
process.stderr.write("error: pass at least one --user <email>\n");
|
|
35723
|
+
process.exit(EXIT_INVALID_INPUT);
|
|
35724
|
+
}
|
|
35725
|
+
const invalid = users.filter((u) => !emailSchema.safeParse(u).success);
|
|
35726
|
+
if (invalid.length > 0) {
|
|
35727
|
+
process.stderr.write(
|
|
35728
|
+
`error: invalid email(s): ${invalid.join(", ")}
|
|
35729
|
+
`
|
|
35730
|
+
);
|
|
35731
|
+
process.exit(EXIT_INVALID_INPUT);
|
|
35732
|
+
}
|
|
35733
|
+
const host = await resolveActiveHost(deps, {
|
|
35734
|
+
flag: opts.server ? { server: opts.server } : void 0,
|
|
35735
|
+
exitCodes: {
|
|
35736
|
+
runtimeFailure: EXIT_RUNTIME_FAILURE,
|
|
35737
|
+
belowFloor: EXIT_BELOW_FLOOR
|
|
35738
|
+
}
|
|
35739
|
+
});
|
|
35740
|
+
const svc = deps.createAgentService(host);
|
|
35741
|
+
const resolver = createAgentResolver({ agentService: svc });
|
|
35742
|
+
const resolved = await resolver.resolve(ref);
|
|
35743
|
+
if (!resolved.ok) {
|
|
35744
|
+
printResolveError(resolved.error, host);
|
|
35745
|
+
process.exit(exitCodeForResolveError(resolved.error));
|
|
35746
|
+
}
|
|
35747
|
+
const merged = mergeAllowedUserEmails(
|
|
35748
|
+
resolved.value.allowedUserEmails,
|
|
35749
|
+
{
|
|
35750
|
+
add: users
|
|
35751
|
+
}
|
|
35752
|
+
);
|
|
35753
|
+
const res = await svc.updateAllowedUserEmails(
|
|
35754
|
+
resolved.value.id,
|
|
35755
|
+
merged
|
|
35756
|
+
);
|
|
35757
|
+
if (!res.ok) {
|
|
35758
|
+
if (res.error.kind === "invalid-input") {
|
|
35759
|
+
process.stderr.write(`error: ${res.error.message}
|
|
35760
|
+
`);
|
|
35761
|
+
process.exit(EXIT_INVALID_INPUT);
|
|
35762
|
+
}
|
|
35763
|
+
if (res.error.kind === "not-found") {
|
|
35764
|
+
process.stderr.write(
|
|
35765
|
+
`error: no agent with id \`${resolved.value.id}\`
|
|
35766
|
+
`
|
|
35767
|
+
);
|
|
35768
|
+
process.exit(EXIT_AGENT_NOT_RESOLVED);
|
|
35769
|
+
}
|
|
35770
|
+
printServiceError(res.error, host);
|
|
35771
|
+
process.exit(EXIT_RUNTIME_FAILURE);
|
|
35772
|
+
}
|
|
35773
|
+
if (opts.json) {
|
|
35774
|
+
process.stdout.write(
|
|
35775
|
+
`${JSON.stringify({ ok: true, agentId: resolved.value.id, allowedUserEmails: res.value.allowedUserEmails })}
|
|
35776
|
+
`
|
|
35777
|
+
);
|
|
35778
|
+
} else {
|
|
35779
|
+
process.stdout.write(
|
|
35780
|
+
`\u2713 Allowed ${users.length} user(s) on ${resolved.value.name}. Agent now has ${res.value.allowedUserEmails.length} allowed user(s).
|
|
35781
|
+
`
|
|
35782
|
+
);
|
|
35783
|
+
}
|
|
35784
|
+
process.exit(EXIT_SUCCESS);
|
|
35785
|
+
}
|
|
35786
|
+
);
|
|
35787
|
+
}
|
|
35788
|
+
|
|
35789
|
+
// src/modules/channel/commands/available.ts
|
|
35790
|
+
var PROVIDER_ORDER = [
|
|
35791
|
+
"slack" /* Slack */,
|
|
35792
|
+
"telegram" /* Telegram */
|
|
35793
|
+
];
|
|
35794
|
+
function buildAvailableCommand(deps) {
|
|
35795
|
+
return new Command("available").description(
|
|
35796
|
+
"List the messenger providers the operator enabled on this host"
|
|
35797
|
+
).option(
|
|
35798
|
+
"--server <url>",
|
|
35799
|
+
"override the configured server URL for this call"
|
|
35800
|
+
).option("--json", "emit the raw { slack?, telegram? } object as JSON").addHelpText(
|
|
35801
|
+
"after",
|
|
35802
|
+
"\nExamples:\n dam channel available\n dam channel available --json\n"
|
|
35803
|
+
).action(async (opts) => {
|
|
35804
|
+
const host = await resolveActiveHost(deps, {
|
|
35805
|
+
flag: opts.server ? { server: opts.server } : void 0,
|
|
35806
|
+
exitCodes: {
|
|
35807
|
+
runtimeFailure: EXIT_RUNTIME_FAILURE,
|
|
35808
|
+
belowFloor: EXIT_BELOW_FLOOR
|
|
35809
|
+
}
|
|
35810
|
+
});
|
|
35811
|
+
const svc = deps.createChannelService(host);
|
|
35812
|
+
const res = await svc.available();
|
|
35813
|
+
if (!res.ok) {
|
|
35814
|
+
printServiceError(res.error, host);
|
|
35815
|
+
process.exit(EXIT_RUNTIME_FAILURE);
|
|
35816
|
+
}
|
|
35817
|
+
if (opts.json) {
|
|
35818
|
+
return writeStdoutAndExit(
|
|
35819
|
+
`${JSON.stringify(res.value)}
|
|
35820
|
+
`,
|
|
35821
|
+
EXIT_SUCCESS
|
|
35822
|
+
);
|
|
35823
|
+
}
|
|
35824
|
+
const enabled = PROVIDER_ORDER.filter((p2) => res.value[p2]);
|
|
35825
|
+
if (enabled.length === 0) {
|
|
35826
|
+
process.stderr.write("No messenger channels enabled on this host.\n");
|
|
35827
|
+
process.exit(EXIT_SUCCESS);
|
|
35828
|
+
}
|
|
35829
|
+
const lines = enabled.map((p2) => `${p2.padEnd(10)}enabled`).join("\n");
|
|
35830
|
+
return writeStdoutAndExit(`${lines}
|
|
35831
|
+
`, EXIT_SUCCESS);
|
|
35832
|
+
});
|
|
35833
|
+
}
|
|
35834
|
+
|
|
35835
|
+
// src/modules/channel/commands/disallow.ts
|
|
35836
|
+
var collect2 = (v2, acc) => [...acc, v2];
|
|
35837
|
+
function buildDisallowCommand(deps) {
|
|
35838
|
+
return new Command("disallow").description(
|
|
35839
|
+
"Remove one or more users from an Agent's allowed-user list. Idempotent."
|
|
35840
|
+
).argument("<agent>", "Agent Ref \u2014 name or 'agent-\u2026' ID").option(
|
|
35841
|
+
"--user <email>",
|
|
35842
|
+
"user email to remove (repeatable)",
|
|
35843
|
+
collect2,
|
|
35844
|
+
[]
|
|
35845
|
+
).option(
|
|
35846
|
+
"--server <url>",
|
|
35847
|
+
"override the configured server URL for this call"
|
|
35848
|
+
).option("--json", "emit { ok, agentId, allowedUserEmails } as JSON").addHelpText(
|
|
35849
|
+
"after",
|
|
35850
|
+
"\nExamples:\n dam channel disallow my-agent --user teammate@example.com\n"
|
|
35851
|
+
).action(
|
|
35852
|
+
async (ref, opts) => {
|
|
35853
|
+
const users = opts.user;
|
|
35854
|
+
if (users.length === 0) {
|
|
35855
|
+
process.stderr.write("error: pass at least one --user <email>\n");
|
|
35856
|
+
process.exit(EXIT_INVALID_INPUT);
|
|
35857
|
+
}
|
|
35858
|
+
const host = await resolveActiveHost(deps, {
|
|
35859
|
+
flag: opts.server ? { server: opts.server } : void 0,
|
|
35860
|
+
exitCodes: {
|
|
35861
|
+
runtimeFailure: EXIT_RUNTIME_FAILURE,
|
|
35862
|
+
belowFloor: EXIT_BELOW_FLOOR
|
|
35863
|
+
}
|
|
35864
|
+
});
|
|
35865
|
+
const svc = deps.createAgentService(host);
|
|
35866
|
+
const resolver = createAgentResolver({ agentService: svc });
|
|
35867
|
+
const resolved = await resolver.resolve(ref);
|
|
35868
|
+
if (!resolved.ok) {
|
|
35869
|
+
printResolveError(resolved.error, host);
|
|
35870
|
+
process.exit(exitCodeForResolveError(resolved.error));
|
|
35871
|
+
}
|
|
35872
|
+
const merged = mergeAllowedUserEmails(
|
|
35873
|
+
resolved.value.allowedUserEmails,
|
|
35874
|
+
{
|
|
35875
|
+
remove: users
|
|
35876
|
+
}
|
|
35877
|
+
);
|
|
35878
|
+
const res = await svc.updateAllowedUserEmails(
|
|
35879
|
+
resolved.value.id,
|
|
35880
|
+
merged
|
|
35881
|
+
);
|
|
35882
|
+
if (!res.ok) {
|
|
35883
|
+
if (res.error.kind === "invalid-input") {
|
|
35884
|
+
process.stderr.write(`error: ${res.error.message}
|
|
35885
|
+
`);
|
|
35886
|
+
process.exit(EXIT_INVALID_INPUT);
|
|
35887
|
+
}
|
|
35888
|
+
if (res.error.kind === "not-found") {
|
|
35889
|
+
process.stderr.write(
|
|
35890
|
+
`error: no agent with id \`${resolved.value.id}\`
|
|
35891
|
+
`
|
|
35892
|
+
);
|
|
35893
|
+
process.exit(EXIT_AGENT_NOT_RESOLVED);
|
|
35894
|
+
}
|
|
35895
|
+
printServiceError(res.error, host);
|
|
35896
|
+
process.exit(EXIT_RUNTIME_FAILURE);
|
|
35897
|
+
}
|
|
35898
|
+
if (opts.json) {
|
|
35899
|
+
process.stdout.write(
|
|
35900
|
+
`${JSON.stringify({ ok: true, agentId: resolved.value.id, allowedUserEmails: res.value.allowedUserEmails })}
|
|
35901
|
+
`
|
|
35902
|
+
);
|
|
35903
|
+
} else {
|
|
35904
|
+
process.stdout.write(
|
|
35905
|
+
`\u2713 Disallowed ${users.length} user(s) from ${resolved.value.name}. Agent now has ${res.value.allowedUserEmails.length} allowed user(s).
|
|
35906
|
+
`
|
|
35907
|
+
);
|
|
35908
|
+
}
|
|
35909
|
+
process.exit(EXIT_SUCCESS);
|
|
35910
|
+
}
|
|
35911
|
+
);
|
|
35912
|
+
}
|
|
35913
|
+
|
|
35914
|
+
// src/modules/channel/commands/list.ts
|
|
35915
|
+
function renderHuman(channels, allowedUserEmails) {
|
|
35916
|
+
const channelsBlock = channels.length === 0 ? "No channels connected.\n" : renderTable([
|
|
35917
|
+
["TYPE", "IDENTIFIER"],
|
|
35918
|
+
...channels.map(
|
|
35919
|
+
(c2) => (
|
|
35920
|
+
// Telegram has no readable identifier — the bot token is write-only.
|
|
35921
|
+
c2.type === "slack" /* Slack */ ? ["slack", c2.slackChannelId] : ["telegram", "\u2014"]
|
|
35922
|
+
)
|
|
35923
|
+
)
|
|
35924
|
+
]);
|
|
35925
|
+
const allowed = allowedUserEmails.length === 0 ? " (unrestricted)\n" : `${allowedUserEmails.map((e2) => ` ${e2}`).join("\n")}
|
|
35926
|
+
`;
|
|
35927
|
+
return `${channelsBlock}
|
|
35928
|
+
Allowed users:
|
|
35929
|
+
${allowed}`;
|
|
35930
|
+
}
|
|
35931
|
+
function buildListCommand3(deps) {
|
|
35932
|
+
return new Command("list").description("List an Agent's connected channels and its Slack allow-list").argument("<agent>", "Agent Ref \u2014 name or 'agent-\u2026' ID").option(
|
|
35933
|
+
"--server <url>",
|
|
35934
|
+
"override the configured server URL for this call"
|
|
35935
|
+
).option(
|
|
35936
|
+
"--json",
|
|
35937
|
+
"emit { channels, allowedUserEmails } as JSON instead of the default tables"
|
|
35938
|
+
).addHelpText(
|
|
35939
|
+
"after",
|
|
35940
|
+
"\nExamples:\n dam channel list my-agent\n dam channel list my-agent --json\n"
|
|
35941
|
+
).action(async (ref, opts) => {
|
|
35942
|
+
const host = await resolveActiveHost(deps, {
|
|
35943
|
+
flag: opts.server ? { server: opts.server } : void 0,
|
|
35944
|
+
exitCodes: {
|
|
35945
|
+
runtimeFailure: EXIT_RUNTIME_FAILURE,
|
|
35946
|
+
belowFloor: EXIT_BELOW_FLOOR
|
|
35947
|
+
}
|
|
35948
|
+
});
|
|
35949
|
+
const resolver = createAgentResolver({
|
|
35950
|
+
agentService: deps.createAgentService(host)
|
|
35951
|
+
});
|
|
35952
|
+
const resolved = await resolver.resolve(ref);
|
|
35953
|
+
if (!resolved.ok) {
|
|
35954
|
+
printResolveError(resolved.error, host);
|
|
35955
|
+
process.exit(exitCodeForResolveError(resolved.error));
|
|
35956
|
+
}
|
|
35957
|
+
const { channels, allowedUserEmails } = resolved.value;
|
|
35958
|
+
if (opts.json) {
|
|
35959
|
+
return writeStdoutAndExit(
|
|
35960
|
+
`${JSON.stringify({ channels, allowedUserEmails })}
|
|
35961
|
+
`,
|
|
35962
|
+
EXIT_SUCCESS
|
|
35963
|
+
);
|
|
35964
|
+
}
|
|
35965
|
+
return writeStdoutAndExit(
|
|
35966
|
+
renderHuman(channels, allowedUserEmails),
|
|
35967
|
+
EXIT_SUCCESS
|
|
35968
|
+
);
|
|
35969
|
+
});
|
|
35970
|
+
}
|
|
35971
|
+
|
|
35972
|
+
// src/modules/channel/commands/precheck.ts
|
|
35973
|
+
var UNAVAILABLE_MESSAGE = {
|
|
35974
|
+
["slack" /* Slack */]: "Slack app token not configured",
|
|
35975
|
+
["telegram" /* Telegram */]: "Telegram channel not enabled"
|
|
35976
|
+
};
|
|
35977
|
+
async function ensureProviderAvailable(svc, provider, host) {
|
|
35978
|
+
const res = await svc.available();
|
|
35979
|
+
if (!res.ok) {
|
|
35980
|
+
printServiceError(res.error, host);
|
|
35981
|
+
process.exit(EXIT_RUNTIME_FAILURE);
|
|
35982
|
+
}
|
|
35983
|
+
if (!res.value[provider]) {
|
|
35984
|
+
process.stderr.write(`error: ${UNAVAILABLE_MESSAGE[provider]}
|
|
35985
|
+
`);
|
|
35986
|
+
process.exit(EXIT_INVALID_INPUT);
|
|
35987
|
+
}
|
|
35988
|
+
}
|
|
35989
|
+
|
|
35990
|
+
// src/modules/channel/commands/slack-connect.ts
|
|
35991
|
+
function buildSlackConnectCommand(deps) {
|
|
35992
|
+
return new Command("connect").description("Bind a Slack channel to an Agent").argument("<agent>", "Agent Ref \u2014 name or 'agent-\u2026' ID").requiredOption("--channel-id <id>", "Slack channel id (e.g. C0123ABCD)").option(
|
|
35993
|
+
"--server <url>",
|
|
35994
|
+
"override the configured server URL for this call"
|
|
35995
|
+
).option("--json", "emit the updated ChannelConfig[] as JSON").addHelpText(
|
|
35996
|
+
"after",
|
|
35997
|
+
"\nExamples:\n dam channel slack connect my-agent --channel-id C0123ABCD\n"
|
|
35998
|
+
).action(
|
|
35999
|
+
async (ref, opts) => {
|
|
36000
|
+
const channelId = opts.channelId.trim();
|
|
36001
|
+
if (channelId.length === 0) {
|
|
36002
|
+
process.stderr.write("error: --channel-id must not be empty\n");
|
|
36003
|
+
process.exit(EXIT_INVALID_INPUT);
|
|
36004
|
+
}
|
|
36005
|
+
const host = await resolveActiveHost(deps, {
|
|
36006
|
+
flag: opts.server ? { server: opts.server } : void 0,
|
|
36007
|
+
exitCodes: {
|
|
36008
|
+
runtimeFailure: EXIT_RUNTIME_FAILURE,
|
|
36009
|
+
belowFloor: EXIT_BELOW_FLOOR
|
|
36010
|
+
}
|
|
36011
|
+
});
|
|
36012
|
+
const resolver = createAgentResolver({
|
|
36013
|
+
agentService: deps.createAgentService(host)
|
|
36014
|
+
});
|
|
36015
|
+
const resolved = await resolver.resolve(ref);
|
|
36016
|
+
if (!resolved.ok) {
|
|
36017
|
+
printResolveError(resolved.error, host);
|
|
36018
|
+
process.exit(exitCodeForResolveError(resolved.error));
|
|
36019
|
+
}
|
|
36020
|
+
const svc = deps.createChannelService(host);
|
|
36021
|
+
await ensureProviderAvailable(svc, "slack" /* Slack */, host);
|
|
36022
|
+
const res = await svc.connectSlack(resolved.value.id, channelId);
|
|
36023
|
+
if (!res.ok) {
|
|
36024
|
+
if (res.error.kind === "channel-conflict") {
|
|
36025
|
+
process.stderr.write(
|
|
36026
|
+
"error: Slack channel already bound to another agent\n"
|
|
36027
|
+
);
|
|
36028
|
+
process.exit(EXIT_INVALID_INPUT);
|
|
36029
|
+
}
|
|
36030
|
+
if (res.error.kind === "channel-precondition" || res.error.kind === "invalid-input") {
|
|
36031
|
+
process.stderr.write(`error: ${res.error.message}
|
|
36032
|
+
`);
|
|
36033
|
+
process.exit(EXIT_INVALID_INPUT);
|
|
36034
|
+
}
|
|
36035
|
+
printServiceError(res.error, host);
|
|
36036
|
+
process.exit(EXIT_RUNTIME_FAILURE);
|
|
36037
|
+
}
|
|
36038
|
+
if (opts.json) {
|
|
36039
|
+
process.stdout.write(`${JSON.stringify(res.value)}
|
|
36040
|
+
`);
|
|
36041
|
+
} else {
|
|
36042
|
+
process.stdout.write(
|
|
36043
|
+
`\u2713 Slack channel ${channelId} connected to ${resolved.value.name}.
|
|
36044
|
+
`
|
|
36045
|
+
);
|
|
36046
|
+
process.stderr.write(
|
|
36047
|
+
"hint: users must run `/platform login` inside Slack before they can drive this agent\n"
|
|
36048
|
+
);
|
|
36049
|
+
}
|
|
36050
|
+
process.exit(EXIT_SUCCESS);
|
|
36051
|
+
}
|
|
36052
|
+
);
|
|
36053
|
+
}
|
|
36054
|
+
|
|
36055
|
+
// src/modules/channel/commands/slack-disconnect.ts
|
|
36056
|
+
function buildSlackDisconnectCommand(deps) {
|
|
36057
|
+
return new Command("disconnect").description(
|
|
36058
|
+
"Unbind an Agent's Slack channel. Idempotent \u2014 a not-connected agent exits 0."
|
|
36059
|
+
).argument("<agent>", "Agent Ref \u2014 name or 'agent-\u2026' ID").option(
|
|
36060
|
+
"--server <url>",
|
|
36061
|
+
"override the configured server URL for this call"
|
|
36062
|
+
).option("--json", "emit the updated ChannelConfig[] as JSON").addHelpText(
|
|
36063
|
+
"after",
|
|
36064
|
+
"\nExamples:\n dam channel slack disconnect my-agent\n"
|
|
36065
|
+
).action(async (ref, opts) => {
|
|
36066
|
+
const host = await resolveActiveHost(deps, {
|
|
36067
|
+
flag: opts.server ? { server: opts.server } : void 0,
|
|
36068
|
+
exitCodes: {
|
|
36069
|
+
runtimeFailure: EXIT_RUNTIME_FAILURE,
|
|
36070
|
+
belowFloor: EXIT_BELOW_FLOOR
|
|
36071
|
+
}
|
|
36072
|
+
});
|
|
36073
|
+
const resolver = createAgentResolver({
|
|
36074
|
+
agentService: deps.createAgentService(host)
|
|
36075
|
+
});
|
|
36076
|
+
const resolved = await resolver.resolve(ref);
|
|
36077
|
+
if (!resolved.ok) {
|
|
36078
|
+
printResolveError(resolved.error, host);
|
|
36079
|
+
process.exit(exitCodeForResolveError(resolved.error));
|
|
36080
|
+
}
|
|
36081
|
+
const svc = deps.createChannelService(host);
|
|
36082
|
+
const res = await svc.disconnectSlack(resolved.value.id);
|
|
36083
|
+
if (!res.ok) {
|
|
36084
|
+
printServiceError(res.error, host);
|
|
36085
|
+
process.exit(EXIT_RUNTIME_FAILURE);
|
|
36086
|
+
}
|
|
36087
|
+
if (opts.json) {
|
|
36088
|
+
process.stdout.write(`${JSON.stringify(res.value)}
|
|
36089
|
+
`);
|
|
36090
|
+
} else {
|
|
36091
|
+
process.stdout.write(
|
|
36092
|
+
`\u2713 Slack disconnected from ${resolved.value.name}.
|
|
36093
|
+
`
|
|
36094
|
+
);
|
|
36095
|
+
}
|
|
36096
|
+
process.exit(EXIT_SUCCESS);
|
|
36097
|
+
});
|
|
36098
|
+
}
|
|
36099
|
+
|
|
36100
|
+
// src/modules/channel/commands/telegram-connect.ts
|
|
36101
|
+
function buildTelegramConnectCommand(deps) {
|
|
36102
|
+
return new Command("connect").description("Bind a Telegram bot to an Agent").argument("<agent>", "Agent Ref \u2014 name or 'agent-\u2026' ID").option(
|
|
36103
|
+
"--bot-token <token>",
|
|
36104
|
+
"bot token from @BotFather (prompted, masked, if omitted on a TTY)"
|
|
36105
|
+
).option(
|
|
36106
|
+
"--server <url>",
|
|
36107
|
+
"override the configured server URL for this call"
|
|
36108
|
+
).option("--json", "emit the updated ChannelConfig[] as JSON").addHelpText(
|
|
36109
|
+
"after",
|
|
36110
|
+
"\nExamples:\n dam channel telegram connect my-agent\n dam channel telegram connect my-agent --bot-token 123:ABC\n"
|
|
36111
|
+
).action(
|
|
36112
|
+
async (ref, opts) => {
|
|
36113
|
+
const host = await resolveActiveHost(deps, {
|
|
36114
|
+
flag: opts.server ? { server: opts.server } : void 0,
|
|
36115
|
+
exitCodes: {
|
|
36116
|
+
runtimeFailure: EXIT_RUNTIME_FAILURE,
|
|
36117
|
+
belowFloor: EXIT_BELOW_FLOOR
|
|
36118
|
+
}
|
|
36119
|
+
});
|
|
36120
|
+
const resolver = createAgentResolver({
|
|
36121
|
+
agentService: deps.createAgentService(host)
|
|
36122
|
+
});
|
|
36123
|
+
const resolved = await resolver.resolve(ref);
|
|
36124
|
+
if (!resolved.ok) {
|
|
36125
|
+
printResolveError(resolved.error, host);
|
|
36126
|
+
process.exit(exitCodeForResolveError(resolved.error));
|
|
36127
|
+
}
|
|
36128
|
+
const token = await resolveToken(opts);
|
|
36129
|
+
const svc = deps.createChannelService(host);
|
|
36130
|
+
await ensureProviderAvailable(svc, "telegram" /* Telegram */, host);
|
|
36131
|
+
const res = await svc.connectTelegram(resolved.value.id, token);
|
|
36132
|
+
if (!res.ok) {
|
|
36133
|
+
if (res.error.kind === "channel-precondition" || res.error.kind === "invalid-input") {
|
|
36134
|
+
process.stderr.write(`error: ${res.error.message}
|
|
36135
|
+
`);
|
|
36136
|
+
process.exit(EXIT_INVALID_INPUT);
|
|
36137
|
+
}
|
|
36138
|
+
printServiceError(res.error, host);
|
|
36139
|
+
process.exit(EXIT_RUNTIME_FAILURE);
|
|
36140
|
+
}
|
|
36141
|
+
if (opts.json) {
|
|
36142
|
+
process.stdout.write(`${JSON.stringify(res.value)}
|
|
36143
|
+
`);
|
|
36144
|
+
} else {
|
|
36145
|
+
process.stdout.write(
|
|
36146
|
+
`\u2713 Telegram bot connected to ${resolved.value.name}.
|
|
36147
|
+
`
|
|
36148
|
+
);
|
|
36149
|
+
}
|
|
36150
|
+
process.exit(EXIT_SUCCESS);
|
|
36151
|
+
}
|
|
36152
|
+
);
|
|
36153
|
+
}
|
|
36154
|
+
async function resolveToken(opts) {
|
|
36155
|
+
const flag = opts.botToken?.trim();
|
|
36156
|
+
if (flag) return flag;
|
|
36157
|
+
if (!process.stdin.isTTY) {
|
|
36158
|
+
process.stderr.write("error: --bot-token is required on a non-TTY\n");
|
|
36159
|
+
process.exit(EXIT_INVALID_INPUT);
|
|
36160
|
+
}
|
|
36161
|
+
const answer = await Ce({
|
|
36162
|
+
message: "Telegram bot token (from @BotFather)",
|
|
36163
|
+
validate: (v2) => v2 && v2.trim().length > 0 ? void 0 : "Required"
|
|
36164
|
+
});
|
|
36165
|
+
if (q(answer)) exitCancelled({ json: opts.json });
|
|
36166
|
+
return String(answer).trim();
|
|
36167
|
+
}
|
|
36168
|
+
|
|
36169
|
+
// src/modules/channel/commands/telegram-disconnect.ts
|
|
36170
|
+
function buildTelegramDisconnectCommand(deps) {
|
|
36171
|
+
return new Command("disconnect").description(
|
|
36172
|
+
"Unbind an Agent's Telegram bot (deletes its k8s Secret). Idempotent \u2014 a not-connected agent exits 0."
|
|
36173
|
+
).argument("<agent>", "Agent Ref \u2014 name or 'agent-\u2026' ID").option(
|
|
36174
|
+
"--server <url>",
|
|
36175
|
+
"override the configured server URL for this call"
|
|
36176
|
+
).option("--json", "emit the updated ChannelConfig[] as JSON").addHelpText(
|
|
36177
|
+
"after",
|
|
36178
|
+
"\nExamples:\n dam channel telegram disconnect my-agent\n"
|
|
36179
|
+
).action(async (ref, opts) => {
|
|
36180
|
+
const host = await resolveActiveHost(deps, {
|
|
36181
|
+
flag: opts.server ? { server: opts.server } : void 0,
|
|
36182
|
+
exitCodes: {
|
|
36183
|
+
runtimeFailure: EXIT_RUNTIME_FAILURE,
|
|
36184
|
+
belowFloor: EXIT_BELOW_FLOOR
|
|
36185
|
+
}
|
|
36186
|
+
});
|
|
36187
|
+
const resolver = createAgentResolver({
|
|
36188
|
+
agentService: deps.createAgentService(host)
|
|
36189
|
+
});
|
|
36190
|
+
const resolved = await resolver.resolve(ref);
|
|
36191
|
+
if (!resolved.ok) {
|
|
36192
|
+
printResolveError(resolved.error, host);
|
|
36193
|
+
process.exit(exitCodeForResolveError(resolved.error));
|
|
36194
|
+
}
|
|
36195
|
+
const svc = deps.createChannelService(host);
|
|
36196
|
+
const res = await svc.disconnectTelegram(resolved.value.id);
|
|
36197
|
+
if (!res.ok) {
|
|
36198
|
+
printServiceError(res.error, host);
|
|
36199
|
+
process.exit(EXIT_RUNTIME_FAILURE);
|
|
36200
|
+
}
|
|
36201
|
+
if (opts.json) {
|
|
36202
|
+
process.stdout.write(`${JSON.stringify(res.value)}
|
|
36203
|
+
`);
|
|
36204
|
+
} else {
|
|
36205
|
+
process.stdout.write(
|
|
36206
|
+
`\u2713 Telegram disconnected from ${resolved.value.name}.
|
|
36207
|
+
`
|
|
36208
|
+
);
|
|
36209
|
+
}
|
|
36210
|
+
process.exit(EXIT_SUCCESS);
|
|
36211
|
+
});
|
|
36212
|
+
}
|
|
36213
|
+
|
|
36214
|
+
// src/modules/channel/services/channel-service.ts
|
|
36215
|
+
function createChannelService(deps) {
|
|
36216
|
+
return {
|
|
36217
|
+
async available() {
|
|
36218
|
+
return trpcCall(() => deps.trpc.channels.available.query());
|
|
36219
|
+
},
|
|
36220
|
+
async connectSlack(id, slackChannelId) {
|
|
36221
|
+
try {
|
|
36222
|
+
const agent = await deps.trpc.agents.connectSlack.mutate({
|
|
36223
|
+
id,
|
|
36224
|
+
slackChannelId
|
|
36225
|
+
});
|
|
36226
|
+
return ok2(agent.channels);
|
|
36227
|
+
} catch (e2) {
|
|
36228
|
+
const code = e2?.data?.code;
|
|
36229
|
+
const message = e2 instanceof Error ? e2.message : String(e2);
|
|
36230
|
+
if (code === "CONFLICT")
|
|
36231
|
+
return err2({ kind: "channel-conflict", message });
|
|
36232
|
+
if (code === "PRECONDITION_FAILED")
|
|
36233
|
+
return err2({ kind: "channel-precondition", message });
|
|
36234
|
+
if (code === "BAD_REQUEST")
|
|
36235
|
+
return err2({ kind: "invalid-input", message });
|
|
36236
|
+
return classifyTrpcError(e2);
|
|
36237
|
+
}
|
|
36238
|
+
},
|
|
36239
|
+
async disconnectSlack(id) {
|
|
36240
|
+
return trpcCall(async () => {
|
|
36241
|
+
const agent = await deps.trpc.agents.disconnectSlack.mutate({ id });
|
|
36242
|
+
return agent.channels;
|
|
36243
|
+
});
|
|
36244
|
+
},
|
|
36245
|
+
async connectTelegram(id, botToken) {
|
|
36246
|
+
try {
|
|
36247
|
+
const agent = await deps.trpc.agents.connectTelegram.mutate({
|
|
36248
|
+
id,
|
|
36249
|
+
botToken
|
|
36250
|
+
});
|
|
36251
|
+
return ok2(agent.channels);
|
|
36252
|
+
} catch (e2) {
|
|
36253
|
+
const code = e2?.data?.code;
|
|
36254
|
+
const message = e2 instanceof Error ? e2.message : String(e2);
|
|
36255
|
+
if (code === "PRECONDITION_FAILED")
|
|
36256
|
+
return err2({ kind: "channel-precondition", message });
|
|
36257
|
+
if (code === "BAD_REQUEST")
|
|
36258
|
+
return err2({ kind: "invalid-input", message });
|
|
36259
|
+
return classifyTrpcError(e2);
|
|
36260
|
+
}
|
|
36261
|
+
},
|
|
36262
|
+
async disconnectTelegram(id) {
|
|
36263
|
+
return trpcCall(async () => {
|
|
36264
|
+
const agent = await deps.trpc.agents.disconnectTelegram.mutate({ id });
|
|
36265
|
+
return agent.channels;
|
|
36266
|
+
});
|
|
36267
|
+
}
|
|
36268
|
+
};
|
|
36269
|
+
}
|
|
36270
|
+
|
|
36271
|
+
// src/modules/channel/compose.ts
|
|
36272
|
+
function composeChannelModule(opts) {
|
|
36273
|
+
const buildTrpc = (host) => createTrpcClient({ host, tokenProvider: opts.tokenProvider });
|
|
36274
|
+
const createService = (host) => createChannelService({ trpc: buildTrpc(host) });
|
|
36275
|
+
const agentScoped = {
|
|
36276
|
+
compatService: opts.compatService,
|
|
36277
|
+
configService: opts.configService,
|
|
36278
|
+
createAgentService: opts.createAgentService,
|
|
36279
|
+
createChannelService: createService
|
|
36280
|
+
};
|
|
36281
|
+
const parent = new Command("channel").description(
|
|
36282
|
+
"Manage messenger channel bindings (Slack, Telegram)"
|
|
35353
36283
|
);
|
|
35354
|
-
|
|
35355
|
-
|
|
35356
|
-
|
|
36284
|
+
parent.addCommand(
|
|
36285
|
+
buildAvailableCommand({
|
|
36286
|
+
compatService: opts.compatService,
|
|
35357
36287
|
configService: opts.configService,
|
|
35358
|
-
|
|
35359
|
-
})
|
|
35360
|
-
);
|
|
35361
|
-
authParent.addCommand(
|
|
35362
|
-
buildLogoutCommand({
|
|
35363
|
-
authService,
|
|
35364
|
-
configService: opts.configService
|
|
36288
|
+
createChannelService: createService
|
|
35365
36289
|
})
|
|
35366
36290
|
);
|
|
35367
|
-
|
|
35368
|
-
|
|
35369
|
-
|
|
35370
|
-
"Manage API keys for headless / CI use"
|
|
35371
|
-
);
|
|
35372
|
-
tokenParent.addCommand(
|
|
35373
|
-
buildTokenCreateCommand({
|
|
36291
|
+
parent.addCommand(
|
|
36292
|
+
buildListCommand3({
|
|
36293
|
+
compatService: opts.compatService,
|
|
35374
36294
|
configService: opts.configService,
|
|
35375
|
-
|
|
36295
|
+
createAgentService: opts.createAgentService
|
|
35376
36296
|
})
|
|
35377
36297
|
);
|
|
35378
|
-
|
|
35379
|
-
|
|
35380
|
-
configService: opts.configService,
|
|
35381
|
-
buildTrpc
|
|
35382
|
-
})
|
|
36298
|
+
const slack = new Command("slack").description(
|
|
36299
|
+
"Bind or unbind an Agent's Slack channel"
|
|
35383
36300
|
);
|
|
35384
|
-
|
|
35385
|
-
|
|
35386
|
-
|
|
35387
|
-
|
|
35388
|
-
|
|
36301
|
+
slack.addCommand(buildSlackConnectCommand(agentScoped));
|
|
36302
|
+
slack.addCommand(buildSlackDisconnectCommand(agentScoped));
|
|
36303
|
+
parent.addCommand(slack);
|
|
36304
|
+
const telegram = new Command("telegram").description(
|
|
36305
|
+
"Bind or unbind an Agent's Telegram bot"
|
|
35389
36306
|
);
|
|
35390
|
-
|
|
35391
|
-
|
|
35392
|
-
|
|
35393
|
-
|
|
35394
|
-
|
|
36307
|
+
telegram.addCommand(buildTelegramConnectCommand(agentScoped));
|
|
36308
|
+
telegram.addCommand(buildTelegramDisconnectCommand(agentScoped));
|
|
36309
|
+
parent.addCommand(telegram);
|
|
36310
|
+
const allowScoped = {
|
|
36311
|
+
compatService: opts.compatService,
|
|
36312
|
+
configService: opts.configService,
|
|
36313
|
+
createAgentService: opts.createAgentService
|
|
35395
36314
|
};
|
|
36315
|
+
parent.addCommand(buildAllowCommand(allowScoped));
|
|
36316
|
+
parent.addCommand(buildDisallowCommand(allowScoped));
|
|
36317
|
+
return { commands: [parent], exports: { createService } };
|
|
35396
36318
|
}
|
|
35397
36319
|
|
|
35398
36320
|
// src/modules/chat/compose.ts
|
|
@@ -37890,7 +38812,7 @@ function createProcessEnvReader() {
|
|
|
37890
38812
|
|
|
37891
38813
|
// src/modules/cli/infrastructure/package-version.ts
|
|
37892
38814
|
function readPackageVersion() {
|
|
37893
|
-
return true ? "0.2.
|
|
38815
|
+
return true ? "0.2.5-rc1" : DEV_VERSION;
|
|
37894
38816
|
}
|
|
37895
38817
|
|
|
37896
38818
|
// src/modules/cli/infrastructure/version-probe.ts
|
|
@@ -38121,6 +39043,11 @@ function buildConnectCommand(deps) {
|
|
|
38121
39043
|
"--env-name <name>",
|
|
38122
39044
|
"input: expose the credential to the agent as this env var (custom header credentials)"
|
|
38123
39045
|
).option("--value <value>", "input: header secret value").option(
|
|
39046
|
+
"-c, --config <key=value>",
|
|
39047
|
+
"set an optional template config input (e.g. -c model=premium-shell), repeatable",
|
|
39048
|
+
(val, prev) => [...prev, val],
|
|
39049
|
+
[]
|
|
39050
|
+
).option(
|
|
38124
39051
|
"--server <url>",
|
|
38125
39052
|
"override the configured server URL for this call"
|
|
38126
39053
|
).option(
|
|
@@ -38132,7 +39059,7 @@ function buildConnectCommand(deps) {
|
|
|
38132
39059
|
String(DEFAULT_TIMEOUT_SECONDS3)
|
|
38133
39060
|
).addHelpText(
|
|
38134
39061
|
"after",
|
|
38135
|
-
"\nExamples:\n dam connection connect github\n dam connection connect github --client-id Iv1.\u2026 --client-secret \u2026 # use your own OAuth app\n dam connection connect github --no-browser\n dam connection connect my-api --header-name X-API-Key --value sk-\u2026\n dam connection connect https://mcp.example.com\n dam connection connect https://mcp.example.com --auth none\n"
|
|
39062
|
+
"\nExamples:\n dam connection connect github\n dam connection connect github --client-id Iv1.\u2026 --client-secret \u2026 # use your own OAuth app\n dam connection connect github --no-browser\n dam connection connect my-api --header-name X-API-Key --value sk-\u2026\n dam connection connect bob --value sk-\u2026 --config model=premium-shell --config chatMode=code\n dam connection connect https://mcp.example.com\n dam connection connect https://mcp.example.com --auth none\n"
|
|
38136
39063
|
).action(async (providerOrUrl, opts) => {
|
|
38137
39064
|
const json2 = opts.json ?? false;
|
|
38138
39065
|
const timeoutSeconds = parseTimeout2(opts.timeout);
|
|
@@ -38171,7 +39098,18 @@ function buildConnectCommand(deps) {
|
|
|
38171
39098
|
opts,
|
|
38172
39099
|
json: json2
|
|
38173
39100
|
});
|
|
38174
|
-
const
|
|
39101
|
+
const configRes = resolveConfigInputFlags(template, opts.config ?? []);
|
|
39102
|
+
if (!configRes.ok) {
|
|
39103
|
+
process.stderr.write(
|
|
39104
|
+
`error: ${formatConfigFlagError(configRes.error)}
|
|
39105
|
+
`
|
|
39106
|
+
);
|
|
39107
|
+
process.exit(EXIT_INVALID_INPUT);
|
|
39108
|
+
}
|
|
39109
|
+
const payload = buildPayload(template, name, {
|
|
39110
|
+
...values,
|
|
39111
|
+
...configRes.value
|
|
39112
|
+
});
|
|
38175
39113
|
if ("error" in payload) {
|
|
38176
39114
|
process.stderr.write(`error: ${payload.error}
|
|
38177
39115
|
`);
|
|
@@ -38471,6 +39409,18 @@ var FIELD_LABELS = {
|
|
|
38471
39409
|
function labelFor(key) {
|
|
38472
39410
|
return FIELD_LABELS[key] ?? key;
|
|
38473
39411
|
}
|
|
39412
|
+
function formatConfigFlagError(e2) {
|
|
39413
|
+
switch (e2.kind) {
|
|
39414
|
+
case "missing-equals":
|
|
39415
|
+
return `invalid --config value \`${e2.input}\`; expected key=value`;
|
|
39416
|
+
case "unknown-key": {
|
|
39417
|
+
const accepts = e2.validKeys.map((k2) => `\`${k2}\``).join(", ");
|
|
39418
|
+
return accepts ? `unknown --config key \`${e2.key}\`; this template accepts: ${accepts}` : `unknown --config key \`${e2.key}\`; this template has no config inputs`;
|
|
39419
|
+
}
|
|
39420
|
+
case "invalid-value":
|
|
39421
|
+
return e2.message;
|
|
39422
|
+
}
|
|
39423
|
+
}
|
|
38474
39424
|
function formatPresetNote(inputs) {
|
|
38475
39425
|
const fields = inputs.map((i) => labelFor(i.name)).join(", ");
|
|
38476
39426
|
return `Using preset values (${fields}). Pass ${flagListFor(inputs)} to use your own.
|
|
@@ -38539,12 +39489,12 @@ function buildDisconnectCommand(deps) {
|
|
|
38539
39489
|
}
|
|
38540
39490
|
|
|
38541
39491
|
// src/modules/connection/commands/grant.ts
|
|
38542
|
-
var
|
|
39492
|
+
var collect3 = (v2, acc) => [...acc, v2];
|
|
38543
39493
|
function buildGrantCommand(deps) {
|
|
38544
39494
|
return new Command("grant").description("Grant one or more connections to an Agent").argument("<agent>", "Agent Ref \u2014 name or 'agent-\u2026' ID").option(
|
|
38545
39495
|
"--connection <id-or-name>",
|
|
38546
39496
|
"connection id or unique name to grant (repeatable)",
|
|
38547
|
-
|
|
39497
|
+
collect3,
|
|
38548
39498
|
[]
|
|
38549
39499
|
).option(
|
|
38550
39500
|
"--server <url>",
|
|
@@ -38643,7 +39593,7 @@ function tableFor(views) {
|
|
|
38643
39593
|
])
|
|
38644
39594
|
]);
|
|
38645
39595
|
}
|
|
38646
|
-
function
|
|
39596
|
+
function buildListCommand4(deps) {
|
|
38647
39597
|
return new Command("list").description(
|
|
38648
39598
|
"List team connections, or the connections granted to one Agent"
|
|
38649
39599
|
).argument("[agent]", "Agent Ref \u2014 name or 'agent-\u2026' ID (optional)").option(
|
|
@@ -38740,14 +39690,14 @@ function buildListCommand3(deps) {
|
|
|
38740
39690
|
}
|
|
38741
39691
|
|
|
38742
39692
|
// src/modules/connection/commands/revoke.ts
|
|
38743
|
-
var
|
|
39693
|
+
var collect4 = (v2, acc) => [...acc, v2];
|
|
38744
39694
|
function buildRevokeCommand(deps) {
|
|
38745
39695
|
return new Command("revoke").description(
|
|
38746
39696
|
"Revoke one or more connections from an Agent. Idempotent \u2014 revoking an ungranted id exits 0."
|
|
38747
39697
|
).argument("<agent>", "Agent Ref \u2014 name or 'agent-\u2026' ID").option(
|
|
38748
39698
|
"--connection <id-or-name>",
|
|
38749
39699
|
"connection id or unique name to revoke (repeatable)",
|
|
38750
|
-
|
|
39700
|
+
collect4,
|
|
38751
39701
|
[]
|
|
38752
39702
|
).option(
|
|
38753
39703
|
"--server <url>",
|
|
@@ -38885,67 +39835,87 @@ function buildTemplatesCommand(deps) {
|
|
|
38885
39835
|
});
|
|
38886
39836
|
}
|
|
38887
39837
|
|
|
38888
|
-
// src/modules/connection/
|
|
38889
|
-
function
|
|
38890
|
-
|
|
38891
|
-
|
|
38892
|
-
|
|
38893
|
-
|
|
38894
|
-
|
|
38895
|
-
|
|
38896
|
-
|
|
38897
|
-
|
|
38898
|
-
|
|
38899
|
-
|
|
38900
|
-
|
|
38901
|
-
|
|
38902
|
-
|
|
38903
|
-
async
|
|
38904
|
-
|
|
38905
|
-
|
|
38906
|
-
|
|
38907
|
-
|
|
38908
|
-
|
|
38909
|
-
|
|
38910
|
-
},
|
|
38911
|
-
async discoverMcp(url2) {
|
|
38912
|
-
return trpcCall(() => deps.trpc.connections.discoverMcp.mutate({ url: url2 }));
|
|
38913
|
-
},
|
|
38914
|
-
async getConnection(id) {
|
|
38915
|
-
return trpcCall(() => deps.trpc.connections.get.query({ id }));
|
|
38916
|
-
},
|
|
38917
|
-
async agentConnectionIds(agentId) {
|
|
38918
|
-
return trpcCall(() => readIds(agentId));
|
|
38919
|
-
},
|
|
38920
|
-
async grant(agentId, add) {
|
|
38921
|
-
return trpcCall(async () => {
|
|
38922
|
-
const current = await readIds(agentId);
|
|
38923
|
-
const next = Array.from(/* @__PURE__ */ new Set([...current, ...add]));
|
|
38924
|
-
await deps.trpc.connections.setAgentConnections.mutate({
|
|
38925
|
-
agentId,
|
|
38926
|
-
connectionIds: next
|
|
38927
|
-
});
|
|
38928
|
-
return next;
|
|
38929
|
-
});
|
|
38930
|
-
},
|
|
38931
|
-
async revoke(agentId, remove) {
|
|
38932
|
-
return trpcCall(async () => {
|
|
38933
|
-
const drop = new Set(remove);
|
|
38934
|
-
const current = await readIds(agentId);
|
|
38935
|
-
const next = current.filter((id) => !drop.has(id));
|
|
38936
|
-
await deps.trpc.connections.setAgentConnections.mutate({
|
|
38937
|
-
agentId,
|
|
38938
|
-
connectionIds: next
|
|
38939
|
-
});
|
|
38940
|
-
return next;
|
|
38941
|
-
});
|
|
38942
|
-
},
|
|
38943
|
-
async disconnect(id) {
|
|
38944
|
-
return trpcCall(async () => {
|
|
38945
|
-
await deps.trpc.connections.delete.mutate({ id });
|
|
39838
|
+
// src/modules/connection/commands/update.ts
|
|
39839
|
+
function buildUpdateCommand(deps) {
|
|
39840
|
+
return new Command("update").description("Replace a connection's stored credential value").argument(
|
|
39841
|
+
"<id-or-name>",
|
|
39842
|
+
"Connection id ('conn-\u2026') or unique name (from `dam connection list`)"
|
|
39843
|
+
).option(
|
|
39844
|
+
"--value <value>",
|
|
39845
|
+
"the new credential value (prompts securely if omitted)"
|
|
39846
|
+
).option(
|
|
39847
|
+
"--server <url>",
|
|
39848
|
+
"override the configured server URL for this call"
|
|
39849
|
+
).option("--json", "emit { ok, id, name } as JSON").addHelpText(
|
|
39850
|
+
"after",
|
|
39851
|
+
"\nExamples:\n dam connection update conn-61cc7b9137b0 --value sk-ant-...\n dam connection update anthropic # prompts for the value\n"
|
|
39852
|
+
).action(
|
|
39853
|
+
async (ref, opts) => {
|
|
39854
|
+
const host = await resolveActiveHost(deps, {
|
|
39855
|
+
flag: opts.server ? { server: opts.server } : void 0,
|
|
39856
|
+
exitCodes: {
|
|
39857
|
+
runtimeFailure: EXIT_RUNTIME_FAILURE,
|
|
39858
|
+
belowFloor: EXIT_BELOW_FLOOR
|
|
39859
|
+
}
|
|
38946
39860
|
});
|
|
39861
|
+
const svc = deps.createConnectionService(host);
|
|
39862
|
+
const listed = await svc.list();
|
|
39863
|
+
if (!listed.ok) {
|
|
39864
|
+
printServiceError(listed.error, host);
|
|
39865
|
+
process.exit(EXIT_RUNTIME_FAILURE);
|
|
39866
|
+
}
|
|
39867
|
+
const match = resolveConnectionRef(listed.value, ref);
|
|
39868
|
+
if (!match) {
|
|
39869
|
+
process.stderr.write(
|
|
39870
|
+
`error: no connection with id or name '${ref}'
|
|
39871
|
+
`
|
|
39872
|
+
);
|
|
39873
|
+
process.stderr.write(
|
|
39874
|
+
"hint: run `dam connection list` to see ids and names\n"
|
|
39875
|
+
);
|
|
39876
|
+
process.exit(EXIT_INVALID_INPUT);
|
|
39877
|
+
}
|
|
39878
|
+
if (match.authKind !== "header") {
|
|
39879
|
+
process.stderr.write(
|
|
39880
|
+
`error: only header-credential connections can be updated; '${match.name}' uses ${match.authKind} auth
|
|
39881
|
+
`
|
|
39882
|
+
);
|
|
39883
|
+
process.exit(EXIT_INVALID_INPUT);
|
|
39884
|
+
}
|
|
39885
|
+
let value = opts.value;
|
|
39886
|
+
if (value === void 0) {
|
|
39887
|
+
if (!process.stdin.isTTY) {
|
|
39888
|
+
process.stderr.write(
|
|
39889
|
+
"error: pass --value <value> when not running interactively\n"
|
|
39890
|
+
);
|
|
39891
|
+
process.exit(EXIT_INVALID_INPUT);
|
|
39892
|
+
}
|
|
39893
|
+
const entered = await promptSecret(
|
|
39894
|
+
`New credential value for ${match.name}`
|
|
39895
|
+
);
|
|
39896
|
+
if (q(entered)) {
|
|
39897
|
+
me("Cancelled");
|
|
39898
|
+
process.exit(EXIT_SUCCESS);
|
|
39899
|
+
}
|
|
39900
|
+
value = entered;
|
|
39901
|
+
}
|
|
39902
|
+
const result = await svc.update(match.id, value);
|
|
39903
|
+
if (!result.ok) {
|
|
39904
|
+
printServiceError(result.error, host);
|
|
39905
|
+
process.exit(EXIT_RUNTIME_FAILURE);
|
|
39906
|
+
}
|
|
39907
|
+
if (opts.json) {
|
|
39908
|
+
process.stdout.write(
|
|
39909
|
+
`${JSON.stringify({ ok: true, id: match.id, name: match.name })}
|
|
39910
|
+
`
|
|
39911
|
+
);
|
|
39912
|
+
} else {
|
|
39913
|
+
process.stdout.write(`\u2713 Updated ${match.name} (${match.id}).
|
|
39914
|
+
`);
|
|
39915
|
+
}
|
|
39916
|
+
process.exit(EXIT_SUCCESS);
|
|
38947
39917
|
}
|
|
38948
|
-
|
|
39918
|
+
);
|
|
38949
39919
|
}
|
|
38950
39920
|
|
|
38951
39921
|
// src/modules/connection/compose.ts
|
|
@@ -38961,7 +39931,7 @@ function composeConnectionModule(opts) {
|
|
|
38961
39931
|
const parent = new Command("connection").description(
|
|
38962
39932
|
"Manage OAuth connections and agent connection grants"
|
|
38963
39933
|
);
|
|
38964
|
-
parent.addCommand(
|
|
39934
|
+
parent.addCommand(buildListCommand4(agentScoped));
|
|
38965
39935
|
parent.addCommand(
|
|
38966
39936
|
buildTemplatesCommand({
|
|
38967
39937
|
compatService: opts.compatService,
|
|
@@ -38984,6 +39954,13 @@ function composeConnectionModule(opts) {
|
|
|
38984
39954
|
createConnectionService: createService
|
|
38985
39955
|
})
|
|
38986
39956
|
);
|
|
39957
|
+
parent.addCommand(
|
|
39958
|
+
buildUpdateCommand({
|
|
39959
|
+
compatService: opts.compatService,
|
|
39960
|
+
configService: opts.configService,
|
|
39961
|
+
createConnectionService: createService
|
|
39962
|
+
})
|
|
39963
|
+
);
|
|
38987
39964
|
parent.addCommand(buildGrantCommand(agentScoped));
|
|
38988
39965
|
parent.addCommand(buildRevokeCommand(agentScoped));
|
|
38989
39966
|
return { commands: [parent], exports: { createService } };
|
|
@@ -39125,7 +40102,7 @@ function buildCreateCommand2(deps) {
|
|
|
39125
40102
|
}
|
|
39126
40103
|
|
|
39127
40104
|
// src/modules/egress/commands/list.ts
|
|
39128
|
-
function
|
|
40105
|
+
function buildListCommand5(deps) {
|
|
39129
40106
|
return new Command("list").description("List network access rules for an Agent").argument("<agent>", "Agent Ref \u2014 name or 'agent-\u2026' ID").option(
|
|
39130
40107
|
"--server <url>",
|
|
39131
40108
|
"override the configured server URL for this call"
|
|
@@ -39294,7 +40271,7 @@ function buildTrustedHostsCommand(deps) {
|
|
|
39294
40271
|
}
|
|
39295
40272
|
|
|
39296
40273
|
// src/modules/egress/commands/update.ts
|
|
39297
|
-
function
|
|
40274
|
+
function buildUpdateCommand2(deps) {
|
|
39298
40275
|
return new Command("update").description(
|
|
39299
40276
|
"Update a network access rule; flips source to 'manual'. Partial \u2014 pass only the fields you want to change."
|
|
39300
40277
|
).argument("<rule-id>", "Rule UUID (copy from `dam network list`)").option("--method <m>", "new HTTP method").option("--path <p>", "new path pattern").addOption(
|
|
@@ -39425,9 +40402,9 @@ function composeEgressModule(opts) {
|
|
|
39425
40402
|
const parent = new Command("network").description(
|
|
39426
40403
|
"Manage per-Agent network access rules (the pre-approvals that let an Agent reach external hosts)"
|
|
39427
40404
|
);
|
|
39428
|
-
parent.addCommand(
|
|
40405
|
+
parent.addCommand(buildListCommand5(agentScoped));
|
|
39429
40406
|
parent.addCommand(buildCreateCommand2(agentScoped));
|
|
39430
|
-
parent.addCommand(
|
|
40407
|
+
parent.addCommand(buildUpdateCommand2(idScoped));
|
|
39431
40408
|
parent.addCommand(buildRevokeCommand2(idScoped));
|
|
39432
40409
|
parent.addCommand(buildPresetCommand(agentScoped));
|
|
39433
40410
|
parent.addCommand(buildApplyPresetCommand(agentScoped));
|
|
@@ -39536,15 +40513,6 @@ async function fileExists(path2) {
|
|
|
39536
40513
|
}
|
|
39537
40514
|
}
|
|
39538
40515
|
function printTrpcReadError(e2, path2, host) {
|
|
39539
|
-
const classified = classifyTrpcError(e2);
|
|
39540
|
-
if (!classified.ok && classified.error.kind === "auth-required") {
|
|
39541
|
-
process.stderr.write(
|
|
39542
|
-
`error: not authenticated: ${classified.error.reason}
|
|
39543
|
-
hint: run \`dam auth login\` first
|
|
39544
|
-
`
|
|
39545
|
-
);
|
|
39546
|
-
return;
|
|
39547
|
-
}
|
|
39548
40516
|
const code = e2 instanceof TRPCClientError ? e2.data?.code : void 0;
|
|
39549
40517
|
if (code === "NOT_FOUND") {
|
|
39550
40518
|
process.stderr.write(`error: not found: ${path2}
|
|
@@ -39558,9 +40526,7 @@ hint: run \`dam auth login\` first
|
|
|
39558
40526
|
);
|
|
39559
40527
|
return;
|
|
39560
40528
|
}
|
|
39561
|
-
|
|
39562
|
-
process.stderr.write(`error: cannot reach server \`${host}\`: ${msg}
|
|
39563
|
-
`);
|
|
40529
|
+
printTrpcError(e2, host);
|
|
39564
40530
|
}
|
|
39565
40531
|
|
|
39566
40532
|
// src/modules/file/commands/list.ts
|
|
@@ -39623,20 +40589,6 @@ function buildFileListCommand(deps) {
|
|
|
39623
40589
|
}
|
|
39624
40590
|
);
|
|
39625
40591
|
}
|
|
39626
|
-
function printTrpcError(e2, host) {
|
|
39627
|
-
const classified = classifyTrpcError(e2);
|
|
39628
|
-
if (!classified.ok && classified.error.kind === "auth-required") {
|
|
39629
|
-
process.stderr.write(
|
|
39630
|
-
`error: not authenticated: ${classified.error.reason}
|
|
39631
|
-
hint: run \`dam auth login\` first
|
|
39632
|
-
`
|
|
39633
|
-
);
|
|
39634
|
-
return;
|
|
39635
|
-
}
|
|
39636
|
-
const msg = e2 instanceof Error ? e2.message : String(e2);
|
|
39637
|
-
process.stderr.write(`error: cannot reach server \`${host}\`: ${msg}
|
|
39638
|
-
`);
|
|
39639
|
-
}
|
|
39640
40592
|
|
|
39641
40593
|
// src/modules/file/commands/put.ts
|
|
39642
40594
|
import { open as open2 } from "fs/promises";
|
|
@@ -39721,15 +40673,6 @@ function buildFilePutCommand(deps) {
|
|
|
39721
40673
|
);
|
|
39722
40674
|
}
|
|
39723
40675
|
function printTrpcUploadError(e2, remotePath, host) {
|
|
39724
|
-
const classified = classifyTrpcError(e2);
|
|
39725
|
-
if (!classified.ok && classified.error.kind === "auth-required") {
|
|
39726
|
-
process.stderr.write(
|
|
39727
|
-
`error: not authenticated: ${classified.error.reason}
|
|
39728
|
-
hint: run \`dam auth login\` first
|
|
39729
|
-
`
|
|
39730
|
-
);
|
|
39731
|
-
return;
|
|
39732
|
-
}
|
|
39733
40676
|
const trpcErr = e2 instanceof TRPCClientError ? e2 : void 0;
|
|
39734
40677
|
const code = trpcErr?.data?.code;
|
|
39735
40678
|
const message = trpcErr?.data?.message ?? "";
|
|
@@ -39752,9 +40695,7 @@ hint: run \`dam auth login\` first
|
|
|
39752
40695
|
);
|
|
39753
40696
|
return;
|
|
39754
40697
|
}
|
|
39755
|
-
|
|
39756
|
-
process.stderr.write(`error: cannot reach server \`${host}\`: ${msg}
|
|
39757
|
-
`);
|
|
40698
|
+
printTrpcError(e2, host);
|
|
39758
40699
|
}
|
|
39759
40700
|
|
|
39760
40701
|
// src/modules/file/compose.ts
|
|
@@ -40016,9 +40957,7 @@ async function uploadAndReport(args) {
|
|
|
40016
40957
|
const e2 = tokenResult.error;
|
|
40017
40958
|
if (e2.kind === "not-logged-in" || e2.kind === "session-expired") {
|
|
40018
40959
|
const reason = e2.kind === "not-logged-in" ? `not logged in to ${e2.host}` : `session expired for ${e2.host}`;
|
|
40019
|
-
process.stderr.write(
|
|
40020
|
-
`);
|
|
40021
|
-
process.stderr.write("hint: run `dam auth login` first\n");
|
|
40960
|
+
process.stderr.write(formatAuthRejection(reason));
|
|
40022
40961
|
} else {
|
|
40023
40962
|
process.stderr.write(`error: ${e2.reason}
|
|
40024
40963
|
`);
|
|
@@ -40071,11 +41010,7 @@ async function uploadAndReport(args) {
|
|
|
40071
41010
|
const serverMessage = extractServerError(body) ?? res.statusText;
|
|
40072
41011
|
switch (res.status) {
|
|
40073
41012
|
case 401:
|
|
40074
|
-
process.stderr.write(
|
|
40075
|
-
`error: not authenticated: ${serverMessage}
|
|
40076
|
-
run "dam auth login" first
|
|
40077
|
-
`
|
|
40078
|
-
);
|
|
41013
|
+
process.stderr.write(formatAuthRejection(serverMessage));
|
|
40079
41014
|
return EXIT_RUNTIME_FAILURE;
|
|
40080
41015
|
case 404:
|
|
40081
41016
|
process.stderr.write("error: agent no longer exists\n");
|
|
@@ -40096,7 +41031,7 @@ async function uploadAndReport(args) {
|
|
|
40096
41031
|
return EXIT_RUNTIME_FAILURE;
|
|
40097
41032
|
default:
|
|
40098
41033
|
process.stderr.write(
|
|
40099
|
-
`error:
|
|
41034
|
+
`error: ${serverMessage || `the server rejected the request (HTTP ${res.status})`}
|
|
40100
41035
|
`
|
|
40101
41036
|
);
|
|
40102
41037
|
return EXIT_RUNTIME_FAILURE;
|
|
@@ -40524,7 +41459,7 @@ function buildGetCommand2(deps) {
|
|
|
40524
41459
|
function recurrenceText(view) {
|
|
40525
41460
|
return view.rrule !== null ? rruleToText(view.rrule) : view.cron ?? "";
|
|
40526
41461
|
}
|
|
40527
|
-
function
|
|
41462
|
+
function buildListCommand6(deps) {
|
|
40528
41463
|
return new Command("list").description("List the schedules attached to an Agent").argument("<agent>", "Agent Ref \u2014 name or 'agent-\u2026' ID").option(
|
|
40529
41464
|
"--server <url>",
|
|
40530
41465
|
"override the configured server URL for this call"
|
|
@@ -40655,7 +41590,7 @@ function buildResetSessionCommand(deps) {
|
|
|
40655
41590
|
}
|
|
40656
41591
|
|
|
40657
41592
|
// src/modules/schedule/commands/update.ts
|
|
40658
|
-
function
|
|
41593
|
+
function buildUpdateCommand3(deps) {
|
|
40659
41594
|
return new Command("update").description(
|
|
40660
41595
|
"Update an RRULE schedule (read-merge-write). Partial \u2014 pass only the fields to change. Legacy cron schedules are read-only."
|
|
40661
41596
|
).argument("<schedule-id>", "Schedule id (from `dam schedule list`)").option("--name <name>", "new schedule name").option("--task <task>", "new task prompt").option("--daily <HH:MM>", "rebuild recurrence: daily at HH:MM").option("--every <interval>", "rebuild recurrence: every Nm/Nh").option("--rrule <body>", "rebuild recurrence: raw RFC 5545 RRULE body").option(
|
|
@@ -40885,10 +41820,10 @@ function composeScheduleModule(opts) {
|
|
|
40885
41820
|
const parent = new Command("schedule").description(
|
|
40886
41821
|
"Manage time-triggered tasks (schedules) attached to an Agent"
|
|
40887
41822
|
);
|
|
40888
|
-
parent.addCommand(
|
|
41823
|
+
parent.addCommand(buildListCommand6(agentScoped));
|
|
40889
41824
|
parent.addCommand(buildGetCommand2(idScoped));
|
|
40890
41825
|
parent.addCommand(buildCreateCommand3(agentScoped));
|
|
40891
|
-
parent.addCommand(
|
|
41826
|
+
parent.addCommand(buildUpdateCommand3(idScoped));
|
|
40892
41827
|
parent.addCommand(buildEnableCommand(idScoped));
|
|
40893
41828
|
parent.addCommand(buildDisableCommand(idScoped));
|
|
40894
41829
|
parent.addCommand(buildDeleteCommand2(idScoped));
|
|
@@ -41167,7 +42102,7 @@ function buildInstallCommand(deps) {
|
|
|
41167
42102
|
// src/modules/skill/commands/list.ts
|
|
41168
42103
|
var INSTALLED_HEADER = ["SOURCE", "NAME", "VERSION"];
|
|
41169
42104
|
var STANDALONE_HEADER = ["NAME", "PUBLISHED"];
|
|
41170
|
-
function
|
|
42105
|
+
function buildListCommand7(deps) {
|
|
41171
42106
|
return new Command("list").description("List the skills on an Agent \u2014 installed and standalone").argument("<agent>", "Agent Ref \u2014 name or 'agent-\u2026' ID").option(
|
|
41172
42107
|
"--server <url>",
|
|
41173
42108
|
"override the configured server URL for this call"
|
|
@@ -41925,7 +42860,7 @@ function composeSkillModule(opts) {
|
|
|
41925
42860
|
sourceGroup.addCommand(buildSourceRefreshCommand(shared));
|
|
41926
42861
|
parent.addCommand(sourceGroup);
|
|
41927
42862
|
parent.addCommand(buildCatalogCommand(shared));
|
|
41928
|
-
parent.addCommand(
|
|
42863
|
+
parent.addCommand(buildListCommand7(shared));
|
|
41929
42864
|
parent.addCommand(buildInstallCommand(shared));
|
|
41930
42865
|
parent.addCommand(buildUninstallCommand(shared));
|
|
41931
42866
|
parent.addCommand(buildPublishCommand(shared));
|
|
@@ -42490,7 +43425,7 @@ function composeSshModule(opts) {
|
|
|
42490
43425
|
|
|
42491
43426
|
// src/modules/template/commands/list.ts
|
|
42492
43427
|
var DESCRIPTION_MAX = 60;
|
|
42493
|
-
function
|
|
43428
|
+
function buildListCommand8(deps) {
|
|
42494
43429
|
return new Command("list").description("List agent templates available on the active host").option(
|
|
42495
43430
|
"--server <url>",
|
|
42496
43431
|
"override the configured server URL for this call"
|
|
@@ -42575,7 +43510,7 @@ function composeTemplateModule(opts) {
|
|
|
42575
43510
|
"Discover agent templates on the active host"
|
|
42576
43511
|
);
|
|
42577
43512
|
parent.addCommand(
|
|
42578
|
-
|
|
43513
|
+
buildListCommand8({
|
|
42579
43514
|
compatService: opts.compatService,
|
|
42580
43515
|
configService: opts.configService,
|
|
42581
43516
|
createTemplateService: createService
|
|
@@ -42668,6 +43603,12 @@ function compose(opts = {}) {
|
|
|
42668
43603
|
createAgentService: agent.exports.createService,
|
|
42669
43604
|
createEgressService: egress.exports.createService
|
|
42670
43605
|
});
|
|
43606
|
+
const channel = composeChannelModule({
|
|
43607
|
+
tokenProvider: auth.exports.tokenProvider,
|
|
43608
|
+
configService: cli.services.configService,
|
|
43609
|
+
compatService: cli.services.compatService,
|
|
43610
|
+
createAgentService: agent.exports.createService
|
|
43611
|
+
});
|
|
42671
43612
|
const program3 = new Command();
|
|
42672
43613
|
program3.name("dam").description("Command-line client for a Platform deployment").version(cli.cliVersion);
|
|
42673
43614
|
for (const command of cli.commands) program3.addCommand(command);
|
|
@@ -42683,6 +43624,7 @@ function compose(opts = {}) {
|
|
|
42683
43624
|
for (const command of schedule.commands) program3.addCommand(command);
|
|
42684
43625
|
for (const command of skill.commands) program3.addCommand(command);
|
|
42685
43626
|
for (const command of ssh.commands) program3.addCommand(command);
|
|
43627
|
+
for (const command of channel.commands) program3.addCommand(command);
|
|
42686
43628
|
return program3;
|
|
42687
43629
|
}
|
|
42688
43630
|
|
|
@@ -42695,6 +43637,13 @@ try {
|
|
|
42695
43637
|
process.stderr.write(
|
|
42696
43638
|
`error: Terms of Use acceptance required
|
|
42697
43639
|
hint: open ${err3.host} to accept
|
|
43640
|
+
`
|
|
43641
|
+
);
|
|
43642
|
+
process.exit(1);
|
|
43643
|
+
}
|
|
43644
|
+
if (err3 instanceof ForbiddenAtTransportError) {
|
|
43645
|
+
process.stderr.write(
|
|
43646
|
+
`error: access denied${err3.detail ? `: ${err3.detail}` : ""}
|
|
42698
43647
|
`
|
|
42699
43648
|
);
|
|
42700
43649
|
process.exit(1);
|