agent-relay 3.2.17 → 3.2.21
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/bin/agent-relay-broker-darwin-arm64 +0 -0
- package/bin/agent-relay-broker-darwin-x64 +0 -0
- package/bin/agent-relay-broker-linux-arm64 +0 -0
- package/bin/agent-relay-broker-linux-x64 +0 -0
- package/dist/index.cjs +86 -43
- package/dist/src/cli/commands/cloud.d.ts +1 -9
- package/dist/src/cli/commands/cloud.d.ts.map +1 -1
- package/dist/src/cli/commands/cloud.js +326 -323
- package/dist/src/cli/commands/cloud.js.map +1 -1
- package/dist/src/cli/commands/connect.d.ts.map +1 -1
- package/dist/src/cli/commands/connect.js +6 -10
- package/dist/src/cli/commands/connect.js.map +1 -1
- package/package.json +16 -10
- package/packages/acp-bridge/package.json +2 -2
- package/packages/brand/README.md +36 -0
- package/packages/brand/brand.css +226 -0
- package/packages/brand/package.json +20 -0
- package/packages/cloud/dist/api-client.d.ts +33 -0
- package/packages/cloud/dist/api-client.d.ts.map +1 -0
- package/packages/cloud/dist/api-client.js +123 -0
- package/packages/cloud/dist/api-client.js.map +1 -0
- package/packages/cloud/dist/auth.d.ts +13 -0
- package/packages/cloud/dist/auth.d.ts.map +1 -0
- package/packages/cloud/dist/auth.js +248 -0
- package/packages/cloud/dist/auth.js.map +1 -0
- package/packages/cloud/dist/index.d.ts +5 -0
- package/packages/cloud/dist/index.d.ts.map +1 -0
- package/packages/cloud/dist/index.js +5 -0
- package/packages/cloud/dist/index.js.map +1 -0
- package/packages/cloud/dist/types.d.ts +73 -0
- package/packages/cloud/dist/types.d.ts.map +1 -0
- package/packages/cloud/dist/types.js +19 -0
- package/packages/cloud/dist/types.js.map +1 -0
- package/packages/cloud/dist/workflows.d.ts +34 -0
- package/packages/cloud/dist/workflows.d.ts.map +1 -0
- package/packages/cloud/dist/workflows.js +389 -0
- package/packages/cloud/dist/workflows.js.map +1 -0
- package/packages/cloud/package.json +44 -0
- package/packages/cloud/src/api-client.ts +169 -0
- package/packages/cloud/src/auth.ts +314 -0
- package/packages/cloud/src/index.ts +41 -0
- package/packages/cloud/src/types.ts +97 -0
- package/packages/cloud/src/workflows.ts +539 -0
- package/packages/cloud/tsconfig.json +21 -0
- package/packages/config/package.json +1 -1
- package/packages/hooks/package.json +4 -4
- package/packages/memory/package.json +2 -2
- package/packages/openclaw/package.json +2 -2
- package/packages/policy/package.json +2 -2
- package/packages/sdk/dist/workflows/__tests__/e2big-and-verify.test.d.ts +2 -0
- package/packages/sdk/dist/workflows/__tests__/e2big-and-verify.test.d.ts.map +1 -0
- package/packages/sdk/dist/workflows/__tests__/e2big-and-verify.test.js +62 -0
- package/packages/sdk/dist/workflows/__tests__/e2big-and-verify.test.js.map +1 -0
- package/packages/sdk/dist/workflows/runner.d.ts +4 -0
- package/packages/sdk/dist/workflows/runner.d.ts.map +1 -1
- package/packages/sdk/dist/workflows/runner.js +76 -39
- package/packages/sdk/dist/workflows/runner.js.map +1 -1
- package/packages/sdk/package.json +2 -2
- package/packages/sdk/src/__tests__/workflow-runner.test.ts +73 -2
- package/packages/sdk/src/workflows/__tests__/e2big-and-verify.test.ts +117 -0
- package/packages/sdk/src/workflows/runner.ts +105 -38
- package/packages/sdk-py/pyproject.toml +1 -1
- package/packages/sdk-swift/Sources/AgentRelaySDK/RelayObserver.swift +2 -0
- package/packages/telemetry/package.json +1 -1
- package/packages/trajectory/package.json +2 -2
- package/packages/user-directory/package.json +2 -2
- package/packages/utils/package.json +2 -2
|
@@ -0,0 +1,389 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { PutObjectCommand, S3Client } from "@aws-sdk/client-s3";
|
|
4
|
+
import ignore from "ignore";
|
|
5
|
+
import * as tar from "tar";
|
|
6
|
+
import { ensureAuthenticated, authorizedApiFetch } from "./auth.js";
|
|
7
|
+
import { defaultApiUrl } from "./types.js";
|
|
8
|
+
const CODE_SYNC_EXCLUDES = [
|
|
9
|
+
".git",
|
|
10
|
+
"node_modules",
|
|
11
|
+
".sst",
|
|
12
|
+
".next",
|
|
13
|
+
".open-next",
|
|
14
|
+
".env",
|
|
15
|
+
".env.*",
|
|
16
|
+
".env.local",
|
|
17
|
+
".env.production",
|
|
18
|
+
"*.pem",
|
|
19
|
+
"*.key",
|
|
20
|
+
"credentials.json",
|
|
21
|
+
".aws",
|
|
22
|
+
".ssh",
|
|
23
|
+
];
|
|
24
|
+
function validateYamlWorkflow(content) {
|
|
25
|
+
const hasField = (field) => new RegExp(`^${field}\\s*:`, "m").test(content);
|
|
26
|
+
if (!hasField("version")) {
|
|
27
|
+
throw new Error('missing required field "version"');
|
|
28
|
+
}
|
|
29
|
+
if (!hasField("swarm")) {
|
|
30
|
+
throw new Error('missing required field "swarm"');
|
|
31
|
+
}
|
|
32
|
+
if (!hasField("agents")) {
|
|
33
|
+
throw new Error('missing required field "agents"');
|
|
34
|
+
}
|
|
35
|
+
if (!hasField("workflows")) {
|
|
36
|
+
throw new Error('missing required field "workflows"');
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
async function validateTypeScriptWorkflow(content) {
|
|
40
|
+
try {
|
|
41
|
+
const { execSync } = await import("node:child_process");
|
|
42
|
+
execSync("npx --yes esbuild --bundle=false --format=esm --loader=ts", {
|
|
43
|
+
input: content,
|
|
44
|
+
encoding: "utf-8",
|
|
45
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
46
|
+
timeout: 30000,
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
catch (error) {
|
|
50
|
+
const err = error;
|
|
51
|
+
if (err.killed || !err.status) {
|
|
52
|
+
console.error("TypeScript validation skipped: esbuild not available or timed out");
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
const stderr = typeof err.stderr === "string" ? err.stderr.trim() : "";
|
|
56
|
+
const message = stderr || "TypeScript validation failed";
|
|
57
|
+
throw new Error(`Workflow file has syntax errors:\n${message}`);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
export function inferWorkflowFileType(filePath) {
|
|
61
|
+
const ext = path.extname(filePath).toLowerCase();
|
|
62
|
+
switch (ext) {
|
|
63
|
+
case ".yaml":
|
|
64
|
+
case ".yml":
|
|
65
|
+
return "yaml";
|
|
66
|
+
case ".ts":
|
|
67
|
+
case ".mts":
|
|
68
|
+
case ".cts":
|
|
69
|
+
return "ts";
|
|
70
|
+
case ".py":
|
|
71
|
+
return "py";
|
|
72
|
+
default:
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
export function shouldSyncCodeByDefault(_workflowArg, _explicitFileType) {
|
|
77
|
+
return true;
|
|
78
|
+
}
|
|
79
|
+
export async function resolveWorkflowInput(workflowArg, explicitFileType) {
|
|
80
|
+
const looksLikeFile = path.isAbsolute(workflowArg) ||
|
|
81
|
+
workflowArg.includes(path.sep) ||
|
|
82
|
+
inferWorkflowFileType(workflowArg) !== null;
|
|
83
|
+
try {
|
|
84
|
+
const workflow = await fs.readFile(workflowArg, "utf-8");
|
|
85
|
+
const fileType = explicitFileType ?? inferWorkflowFileType(workflowArg);
|
|
86
|
+
if (!fileType) {
|
|
87
|
+
throw new Error(`Could not infer workflow type from ${workflowArg}. Use --file-type.`);
|
|
88
|
+
}
|
|
89
|
+
return { workflow, fileType };
|
|
90
|
+
}
|
|
91
|
+
catch (error) {
|
|
92
|
+
const err = error;
|
|
93
|
+
if (err.code === "EISDIR") {
|
|
94
|
+
throw new Error(`Workflow path is not a file: ${workflowArg}`);
|
|
95
|
+
}
|
|
96
|
+
if (!isMissingFileError(error)) {
|
|
97
|
+
throw error;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
if (looksLikeFile) {
|
|
101
|
+
throw new Error(`Workflow file not found: ${workflowArg}`);
|
|
102
|
+
}
|
|
103
|
+
return {
|
|
104
|
+
workflow: workflowArg,
|
|
105
|
+
fileType: explicitFileType ?? "yaml",
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
export async function runWorkflow(workflowArg, options = {}) {
|
|
109
|
+
const apiUrl = options.apiUrl ?? defaultApiUrl();
|
|
110
|
+
let auth = await ensureAuthenticated(apiUrl);
|
|
111
|
+
const input = await resolveWorkflowInput(workflowArg, options.fileType);
|
|
112
|
+
if (input.fileType === "ts") {
|
|
113
|
+
await validateTypeScriptWorkflow(input.workflow);
|
|
114
|
+
}
|
|
115
|
+
else if (input.fileType === "yaml") {
|
|
116
|
+
console.error("Validating workflow...");
|
|
117
|
+
validateYamlWorkflow(input.workflow);
|
|
118
|
+
}
|
|
119
|
+
const syncCode = options.syncCode ?? shouldSyncCodeByDefault(workflowArg, options.fileType);
|
|
120
|
+
const requestBody = {
|
|
121
|
+
workflow: input.workflow,
|
|
122
|
+
fileType: input.fileType,
|
|
123
|
+
};
|
|
124
|
+
if (input.sourceFileType) {
|
|
125
|
+
requestBody.sourceFileType = input.sourceFileType;
|
|
126
|
+
}
|
|
127
|
+
if (syncCode) {
|
|
128
|
+
const t0 = Date.now();
|
|
129
|
+
console.error("Preparing run...");
|
|
130
|
+
const { response: prepResponse, auth: prepAuth } = await authorizedApiFetch(auth, "/api/v1/workflows/prepare", {
|
|
131
|
+
method: "POST",
|
|
132
|
+
headers: { Accept: "application/json" },
|
|
133
|
+
});
|
|
134
|
+
auth = prepAuth;
|
|
135
|
+
const prepPayload = await readJsonResponse(prepResponse);
|
|
136
|
+
if (!prepResponse.ok) {
|
|
137
|
+
throw new Error(`Workflow prepare failed: ${describeResponseError(prepResponse, prepPayload)}`);
|
|
138
|
+
}
|
|
139
|
+
if (!isPrepareWorkflowResponse(prepPayload)) {
|
|
140
|
+
throw new Error("Workflow prepare response was not valid JSON.");
|
|
141
|
+
}
|
|
142
|
+
const prepared = prepPayload;
|
|
143
|
+
console.error(` Prepared in ${((Date.now() - t0) / 1000).toFixed(1)}s`);
|
|
144
|
+
const t1 = Date.now();
|
|
145
|
+
console.error("Creating tarball...");
|
|
146
|
+
const s3Client = createScopedS3Client(prepared.s3Credentials);
|
|
147
|
+
const tarball = await createTarball(process.cwd());
|
|
148
|
+
console.error(` Tarball: ${(tarball.length / 1024).toFixed(0)}KB in ${((Date.now() - t1) / 1000).toFixed(1)}s`);
|
|
149
|
+
const t2 = Date.now();
|
|
150
|
+
console.error("Uploading to S3...");
|
|
151
|
+
const key = scopedCodeKey(prepared.s3Credentials.prefix, prepared.s3CodeKey);
|
|
152
|
+
await s3Client.send(new PutObjectCommand({
|
|
153
|
+
Bucket: prepared.s3Credentials.bucket,
|
|
154
|
+
Key: key,
|
|
155
|
+
Body: tarball,
|
|
156
|
+
ContentType: "application/gzip",
|
|
157
|
+
}));
|
|
158
|
+
console.error(` Uploaded in ${((Date.now() - t2) / 1000).toFixed(1)}s`);
|
|
159
|
+
requestBody.runId = prepared.runId;
|
|
160
|
+
requestBody.s3CodeKey = prepared.s3CodeKey;
|
|
161
|
+
}
|
|
162
|
+
const t3 = Date.now();
|
|
163
|
+
console.error("Launching workflow...");
|
|
164
|
+
const { response, auth: updatedAuth } = await authorizedApiFetch(auth, "/api/v1/workflows/run", {
|
|
165
|
+
method: "POST",
|
|
166
|
+
headers: {
|
|
167
|
+
"Content-Type": "application/json",
|
|
168
|
+
Accept: "application/json",
|
|
169
|
+
},
|
|
170
|
+
body: JSON.stringify(requestBody),
|
|
171
|
+
});
|
|
172
|
+
auth = updatedAuth;
|
|
173
|
+
console.error(` Launched in ${((Date.now() - t3) / 1000).toFixed(1)}s`);
|
|
174
|
+
const payload = await readJsonResponse(response);
|
|
175
|
+
if (!response.ok) {
|
|
176
|
+
throw new Error(`Workflow run failed: ${describeResponseError(response, payload)}`);
|
|
177
|
+
}
|
|
178
|
+
if (!payload ||
|
|
179
|
+
typeof payload !== "object" ||
|
|
180
|
+
typeof payload.runId !== "string" ||
|
|
181
|
+
typeof payload.status !== "string") {
|
|
182
|
+
throw new Error("Workflow run response was not valid JSON.");
|
|
183
|
+
}
|
|
184
|
+
return payload;
|
|
185
|
+
}
|
|
186
|
+
export async function getRunStatus(runId, options = {}) {
|
|
187
|
+
const apiUrl = options.apiUrl ?? defaultApiUrl();
|
|
188
|
+
const auth = await ensureAuthenticated(apiUrl);
|
|
189
|
+
const { response } = await authorizedApiFetch(auth, `/api/v1/workflows/runs/${encodeURIComponent(runId)}`, {
|
|
190
|
+
headers: { Accept: "application/json" },
|
|
191
|
+
});
|
|
192
|
+
const payload = await readJsonResponse(response);
|
|
193
|
+
if (!response.ok) {
|
|
194
|
+
throw new Error(`Status request failed: ${describeResponseError(response, payload)}`);
|
|
195
|
+
}
|
|
196
|
+
if (!payload || typeof payload !== "object" || Array.isArray(payload)) {
|
|
197
|
+
throw new Error("Status response was not valid JSON.");
|
|
198
|
+
}
|
|
199
|
+
return payload;
|
|
200
|
+
}
|
|
201
|
+
export async function cancelWorkflow(runId, options = {}) {
|
|
202
|
+
const apiUrl = options.apiUrl ?? defaultApiUrl();
|
|
203
|
+
const auth = await ensureAuthenticated(apiUrl);
|
|
204
|
+
const { response } = await authorizedApiFetch(auth, `/api/v1/workflows/runs/${encodeURIComponent(runId)}/cancel`, {
|
|
205
|
+
method: "POST",
|
|
206
|
+
headers: { Accept: "application/json" },
|
|
207
|
+
});
|
|
208
|
+
const payload = await readJsonResponse(response);
|
|
209
|
+
if (!response.ok) {
|
|
210
|
+
throw new Error(`Cancel failed: ${describeResponseError(response, payload)}`);
|
|
211
|
+
}
|
|
212
|
+
if (!payload || typeof payload !== "object" || Array.isArray(payload)) {
|
|
213
|
+
throw new Error("Cancel response was not valid JSON.");
|
|
214
|
+
}
|
|
215
|
+
return payload;
|
|
216
|
+
}
|
|
217
|
+
export async function getRunLogs(runId, options = {}) {
|
|
218
|
+
const apiUrl = options.apiUrl ?? defaultApiUrl();
|
|
219
|
+
const auth = await ensureAuthenticated(apiUrl);
|
|
220
|
+
const searchParams = new URLSearchParams();
|
|
221
|
+
if (typeof options.offset === "number") {
|
|
222
|
+
searchParams.set("offset", String(options.offset));
|
|
223
|
+
}
|
|
224
|
+
if (options.sandboxId) {
|
|
225
|
+
searchParams.set("sandboxId", options.sandboxId);
|
|
226
|
+
}
|
|
227
|
+
const requestPath = `/api/v1/workflows/runs/${encodeURIComponent(runId)}/logs${searchParams.size ? `?${searchParams.toString()}` : ""}`;
|
|
228
|
+
const { response } = await authorizedApiFetch(auth, requestPath, {
|
|
229
|
+
headers: { Accept: "application/json" },
|
|
230
|
+
});
|
|
231
|
+
const payload = await readJsonResponse(response);
|
|
232
|
+
if (!response.ok) {
|
|
233
|
+
throw new Error(`Log request failed: ${describeResponseError(response, payload)}`);
|
|
234
|
+
}
|
|
235
|
+
if (!payload ||
|
|
236
|
+
typeof payload !== "object" ||
|
|
237
|
+
typeof payload.content !== "string" ||
|
|
238
|
+
typeof payload.offset !== "number" ||
|
|
239
|
+
typeof payload.totalSize !== "number" ||
|
|
240
|
+
typeof payload.done !== "boolean") {
|
|
241
|
+
throw new Error("Log response was not valid JSON.");
|
|
242
|
+
}
|
|
243
|
+
return payload;
|
|
244
|
+
}
|
|
245
|
+
export async function syncWorkflowPatch(runId, options = {}) {
|
|
246
|
+
const apiUrl = options.apiUrl ?? defaultApiUrl();
|
|
247
|
+
let auth = await ensureAuthenticated(apiUrl);
|
|
248
|
+
// Verify the run is completed
|
|
249
|
+
const { response: statusResponse, auth: a1 } = await authorizedApiFetch(auth, `/api/v1/workflows/runs/${encodeURIComponent(runId)}`, { headers: { Accept: "application/json" } });
|
|
250
|
+
auth = a1;
|
|
251
|
+
if (!statusResponse.ok) {
|
|
252
|
+
const payload = await readJsonResponse(statusResponse);
|
|
253
|
+
throw new Error(`Failed to fetch run status: ${describeResponseError(statusResponse, payload)}`);
|
|
254
|
+
}
|
|
255
|
+
const runData = (await statusResponse.json());
|
|
256
|
+
if (runData.status !== "completed" && runData.status !== "failed" && runData.status !== "cancelled") {
|
|
257
|
+
throw new Error(`Run is still ${runData.status ?? "unknown"}. Wait for completion before syncing.`);
|
|
258
|
+
}
|
|
259
|
+
// Download the patch
|
|
260
|
+
const { response } = await authorizedApiFetch(auth, `/api/v1/workflows/runs/${encodeURIComponent(runId)}/patch`, { headers: { Accept: "application/json" } });
|
|
261
|
+
const payload = await readJsonResponse(response);
|
|
262
|
+
if (!response.ok) {
|
|
263
|
+
throw new Error(`Patch download failed: ${describeResponseError(response, payload)}`);
|
|
264
|
+
}
|
|
265
|
+
if (!payload ||
|
|
266
|
+
typeof payload !== "object" ||
|
|
267
|
+
typeof payload.hasChanges !== "boolean") {
|
|
268
|
+
throw new Error("Patch response was not valid JSON.");
|
|
269
|
+
}
|
|
270
|
+
return payload;
|
|
271
|
+
}
|
|
272
|
+
// ── Internal helpers ──────────────────────────────────────────────────────────
|
|
273
|
+
async function readJsonResponse(response) {
|
|
274
|
+
const rawBody = await response.text();
|
|
275
|
+
if (!rawBody) {
|
|
276
|
+
return null;
|
|
277
|
+
}
|
|
278
|
+
try {
|
|
279
|
+
return JSON.parse(rawBody);
|
|
280
|
+
}
|
|
281
|
+
catch {
|
|
282
|
+
return rawBody;
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
function describeResponseError(response, payload) {
|
|
286
|
+
if (typeof payload === "string" && payload.trim()) {
|
|
287
|
+
return `${response.status} ${response.statusText}: ${payload.trim()}`;
|
|
288
|
+
}
|
|
289
|
+
if (payload && typeof payload === "object" && !Array.isArray(payload)) {
|
|
290
|
+
const record = payload;
|
|
291
|
+
const message = record.error ?? record.message;
|
|
292
|
+
if (typeof message === "string" && message.trim()) {
|
|
293
|
+
return `${response.status} ${response.statusText}: ${message.trim()}`;
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
return `${response.status} ${response.statusText}`;
|
|
297
|
+
}
|
|
298
|
+
function isMissingFileError(error) {
|
|
299
|
+
return Boolean(error && typeof error === "object" && "code" in error && error.code === "ENOENT");
|
|
300
|
+
}
|
|
301
|
+
function isPrepareWorkflowResponse(payload) {
|
|
302
|
+
if (!payload || typeof payload !== "object" || Array.isArray(payload)) {
|
|
303
|
+
return false;
|
|
304
|
+
}
|
|
305
|
+
const record = payload;
|
|
306
|
+
const s3Creds = record.s3Credentials;
|
|
307
|
+
if (!s3Creds || typeof s3Creds !== "object" || Array.isArray(s3Creds)) {
|
|
308
|
+
return false;
|
|
309
|
+
}
|
|
310
|
+
const creds = s3Creds;
|
|
311
|
+
return (typeof record.runId === "string" &&
|
|
312
|
+
typeof record.s3CodeKey === "string" &&
|
|
313
|
+
typeof creds.accessKeyId === "string" &&
|
|
314
|
+
typeof creds.secretAccessKey === "string" &&
|
|
315
|
+
typeof creds.sessionToken === "string" &&
|
|
316
|
+
typeof creds.bucket === "string" &&
|
|
317
|
+
typeof creds.prefix === "string");
|
|
318
|
+
}
|
|
319
|
+
function createScopedS3Client(s3Credentials) {
|
|
320
|
+
return new S3Client({
|
|
321
|
+
region: process.env.AWS_REGION ?? process.env.AWS_DEFAULT_REGION ?? "us-east-1",
|
|
322
|
+
credentials: {
|
|
323
|
+
accessKeyId: s3Credentials.accessKeyId,
|
|
324
|
+
secretAccessKey: s3Credentials.secretAccessKey,
|
|
325
|
+
sessionToken: s3Credentials.sessionToken,
|
|
326
|
+
},
|
|
327
|
+
});
|
|
328
|
+
}
|
|
329
|
+
async function createTarball(rootDir) {
|
|
330
|
+
const absoluteRoot = path.resolve(rootDir);
|
|
331
|
+
try {
|
|
332
|
+
const { execSync } = await import("node:child_process");
|
|
333
|
+
const gitFiles = execSync("git ls-files -z", {
|
|
334
|
+
cwd: absoluteRoot,
|
|
335
|
+
encoding: "utf-8",
|
|
336
|
+
maxBuffer: 50 * 1024 * 1024,
|
|
337
|
+
});
|
|
338
|
+
const files = gitFiles.split("\0").filter(Boolean);
|
|
339
|
+
if (files.length > 0) {
|
|
340
|
+
const tarStream = tar.create({ gzip: true, cwd: absoluteRoot, portable: true }, files);
|
|
341
|
+
const chunks = [];
|
|
342
|
+
for await (const chunk of tarStream) {
|
|
343
|
+
chunks.push(Buffer.from(chunk));
|
|
344
|
+
}
|
|
345
|
+
return Buffer.concat(chunks);
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
catch {
|
|
349
|
+
// Not a git repo or git not available — fall back to ignore-based filter
|
|
350
|
+
}
|
|
351
|
+
const ig = await buildIgnoreMatcher(absoluteRoot);
|
|
352
|
+
const tarStream = tar.create({
|
|
353
|
+
gzip: true,
|
|
354
|
+
cwd: absoluteRoot,
|
|
355
|
+
portable: true,
|
|
356
|
+
filter(entryPath) {
|
|
357
|
+
const normalized = normalizeEntryPath(entryPath);
|
|
358
|
+
if (!normalized || normalized === ".")
|
|
359
|
+
return true;
|
|
360
|
+
return !ig.ignores(normalized);
|
|
361
|
+
},
|
|
362
|
+
}, ["."]);
|
|
363
|
+
const chunks = [];
|
|
364
|
+
for await (const chunk of tarStream) {
|
|
365
|
+
chunks.push(Buffer.from(chunk));
|
|
366
|
+
}
|
|
367
|
+
return Buffer.concat(chunks);
|
|
368
|
+
}
|
|
369
|
+
async function buildIgnoreMatcher(rootDir) {
|
|
370
|
+
const ig = ignore();
|
|
371
|
+
ig.add(CODE_SYNC_EXCLUDES);
|
|
372
|
+
try {
|
|
373
|
+
const gitignoreContent = await fs.readFile(path.join(rootDir, ".gitignore"), "utf-8");
|
|
374
|
+
ig.add(gitignoreContent);
|
|
375
|
+
}
|
|
376
|
+
catch (error) {
|
|
377
|
+
if (!isMissingFileError(error)) {
|
|
378
|
+
throw error;
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
return ig;
|
|
382
|
+
}
|
|
383
|
+
function normalizeEntryPath(entryPath) {
|
|
384
|
+
return entryPath.replace(/^\.\//, "").replace(/\\/g, "/");
|
|
385
|
+
}
|
|
386
|
+
function scopedCodeKey(prefix, key) {
|
|
387
|
+
return [prefix, key].filter(Boolean).join("/");
|
|
388
|
+
}
|
|
389
|
+
//# sourceMappingURL=workflows.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workflows.js","sourceRoot":"","sources":["../src/workflows.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@agent-relay/cloud",
|
|
3
|
+
"version": "3.2.21",
|
|
4
|
+
"description": "Cloud SDK for Agent Relay — auth, workflow execution, and provider connections",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.js"
|
|
12
|
+
},
|
|
13
|
+
"./package.json": "./package.json"
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"dist",
|
|
17
|
+
"README.md"
|
|
18
|
+
],
|
|
19
|
+
"scripts": {
|
|
20
|
+
"build": "tsc",
|
|
21
|
+
"clean": "rm -rf dist",
|
|
22
|
+
"test": "vitest run",
|
|
23
|
+
"test:watch": "vitest"
|
|
24
|
+
},
|
|
25
|
+
"dependencies": {
|
|
26
|
+
"@agent-relay/config": "3.2.21",
|
|
27
|
+
"@aws-sdk/client-s3": "^3.1004.0",
|
|
28
|
+
"ignore": "^7.0.5",
|
|
29
|
+
"tar": "^7.5.10"
|
|
30
|
+
},
|
|
31
|
+
"devDependencies": {
|
|
32
|
+
"@types/node": "^22.19.3",
|
|
33
|
+
"typescript": "^5.9.3",
|
|
34
|
+
"vitest": "^3.2.4"
|
|
35
|
+
},
|
|
36
|
+
"publishConfig": {
|
|
37
|
+
"access": "public"
|
|
38
|
+
},
|
|
39
|
+
"repository": {
|
|
40
|
+
"type": "git",
|
|
41
|
+
"url": "git+https://github.com/AgentWorkforce/relay.git",
|
|
42
|
+
"directory": "packages/cloud"
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import { REFRESH_WINDOW_MS } from "./types.js";
|
|
2
|
+
|
|
3
|
+
export type CloudApiClientOptions = {
|
|
4
|
+
apiUrl: string;
|
|
5
|
+
accessToken: string;
|
|
6
|
+
refreshToken: string;
|
|
7
|
+
accessTokenExpiresAt: string;
|
|
8
|
+
refreshTokenExpiresAt?: string;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export type CloudApiClientSnapshot = {
|
|
12
|
+
apiUrl: string;
|
|
13
|
+
accessToken: string;
|
|
14
|
+
refreshToken: string;
|
|
15
|
+
accessTokenExpiresAt: string;
|
|
16
|
+
refreshTokenExpiresAt?: string;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
function trimLeadingSlash(p: string): string {
|
|
20
|
+
return p.replace(/^\/+/, "");
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function withTrailingSlash(p: string): string {
|
|
24
|
+
return p.endsWith("/") ? p : `${p}/`;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function buildApiUrl(apiUrl: string, p: string): URL {
|
|
28
|
+
return new URL(trimLeadingSlash(p), withTrailingSlash(apiUrl));
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export class CloudApiClient {
|
|
32
|
+
private accessToken: string;
|
|
33
|
+
private refreshToken: string;
|
|
34
|
+
private accessTokenExpiresAt: string;
|
|
35
|
+
private refreshTokenExpiresAt?: string;
|
|
36
|
+
private refreshPromise: Promise<void> | null = null;
|
|
37
|
+
|
|
38
|
+
constructor(private readonly options: CloudApiClientOptions) {
|
|
39
|
+
this.accessToken = options.accessToken;
|
|
40
|
+
this.refreshToken = options.refreshToken;
|
|
41
|
+
this.accessTokenExpiresAt = options.accessTokenExpiresAt;
|
|
42
|
+
this.refreshTokenExpiresAt = options.refreshTokenExpiresAt;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
static fromEnv(env: NodeJS.ProcessEnv): CloudApiClient | null {
|
|
46
|
+
const apiUrl = env.CLOUD_API_URL?.trim();
|
|
47
|
+
const accessToken = env.CLOUD_API_ACCESS_TOKEN?.trim();
|
|
48
|
+
const refreshToken = env.CLOUD_API_REFRESH_TOKEN?.trim();
|
|
49
|
+
const accessTokenExpiresAt = env.CLOUD_API_ACCESS_TOKEN_EXPIRES_AT?.trim();
|
|
50
|
+
const refreshTokenExpiresAt = env.CLOUD_API_REFRESH_TOKEN_EXPIRES_AT?.trim();
|
|
51
|
+
|
|
52
|
+
if (!apiUrl || !accessToken || !refreshToken || !accessTokenExpiresAt) {
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return new CloudApiClient({
|
|
57
|
+
apiUrl,
|
|
58
|
+
accessToken,
|
|
59
|
+
refreshToken,
|
|
60
|
+
accessTokenExpiresAt,
|
|
61
|
+
refreshTokenExpiresAt,
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
snapshot(): CloudApiClientSnapshot {
|
|
66
|
+
return {
|
|
67
|
+
apiUrl: this.options.apiUrl,
|
|
68
|
+
accessToken: this.accessToken,
|
|
69
|
+
refreshToken: this.refreshToken,
|
|
70
|
+
accessTokenExpiresAt: this.accessTokenExpiresAt,
|
|
71
|
+
...(this.refreshTokenExpiresAt ? { refreshTokenExpiresAt: this.refreshTokenExpiresAt } : {}),
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
async fetch(p: string, init: RequestInit = {}): Promise<Response> {
|
|
76
|
+
await this.refresh();
|
|
77
|
+
|
|
78
|
+
const response = await fetch(buildApiUrl(this.options.apiUrl, p), {
|
|
79
|
+
...init,
|
|
80
|
+
headers: this.buildHeaders(init.headers),
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
if (response.status !== 401) {
|
|
84
|
+
return response;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
await this.refresh(true);
|
|
88
|
+
|
|
89
|
+
return fetch(buildApiUrl(this.options.apiUrl, p), {
|
|
90
|
+
...init,
|
|
91
|
+
headers: this.buildHeaders(init.headers),
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
async revoke(): Promise<void> {
|
|
96
|
+
const response = await fetch(buildApiUrl(this.options.apiUrl, "/api/v1/auth/token/revoke"), {
|
|
97
|
+
method: "POST",
|
|
98
|
+
headers: {
|
|
99
|
+
"Content-Type": "application/json",
|
|
100
|
+
},
|
|
101
|
+
body: JSON.stringify({ token: this.refreshToken }),
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
if (!response.ok && response.status !== 404) {
|
|
105
|
+
throw new Error(`Failed to revoke API token: ${response.status} ${response.statusText}`);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
private async refresh(force = false): Promise<void> {
|
|
110
|
+
if (this.refreshPromise) {
|
|
111
|
+
return this.refreshPromise;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
if (!force && !this.shouldRefresh()) {
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
this.refreshPromise = this.doRefresh().finally(() => {
|
|
119
|
+
this.refreshPromise = null;
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
return this.refreshPromise;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
private async doRefresh(): Promise<void> {
|
|
126
|
+
const response = await fetch(buildApiUrl(this.options.apiUrl, "/api/v1/auth/token/refresh"), {
|
|
127
|
+
method: "POST",
|
|
128
|
+
headers: {
|
|
129
|
+
"Content-Type": "application/json",
|
|
130
|
+
},
|
|
131
|
+
body: JSON.stringify({ refreshToken: this.refreshToken }),
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
if (!response.ok) {
|
|
135
|
+
throw new Error(`Failed to refresh API token: ${response.status} ${response.statusText}`);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const payload = (await response.json()) as {
|
|
139
|
+
accessToken?: string;
|
|
140
|
+
accessTokenExpiresAt?: string;
|
|
141
|
+
refreshToken?: string;
|
|
142
|
+
refreshTokenExpiresAt?: string;
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
if (!payload.accessToken || !payload.accessTokenExpiresAt || !payload.refreshToken) {
|
|
146
|
+
throw new Error("Refresh response missing token fields");
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
this.accessToken = payload.accessToken;
|
|
150
|
+
this.accessTokenExpiresAt = payload.accessTokenExpiresAt;
|
|
151
|
+
this.refreshToken = payload.refreshToken;
|
|
152
|
+
this.refreshTokenExpiresAt = payload.refreshTokenExpiresAt;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
private buildHeaders(headers: HeadersInit | undefined): Headers {
|
|
156
|
+
const merged = new Headers(headers);
|
|
157
|
+
merged.set("Authorization", `Bearer ${this.accessToken}`);
|
|
158
|
+
return merged;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
private shouldRefresh(): boolean {
|
|
162
|
+
const expiresAt = Date.parse(this.accessTokenExpiresAt);
|
|
163
|
+
if (Number.isNaN(expiresAt)) {
|
|
164
|
+
return true;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
return expiresAt - Date.now() <= REFRESH_WINDOW_MS;
|
|
168
|
+
}
|
|
169
|
+
}
|