agent-relay 4.0.4 → 4.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +19 -19
- package/dist/index.cjs +8 -7
- package/dist/src/cli/commands/auth.js +1 -1
- package/dist/src/cli/commands/auth.js.map +1 -1
- package/dist/src/cli/commands/on.js +2 -2
- package/dist/src/cli/commands/setup.js +1 -1
- package/dist/src/cli/lib/auth-ssh.d.ts.map +1 -1
- package/dist/src/cli/lib/auth-ssh.js +19 -10
- package/dist/src/cli/lib/auth-ssh.js.map +1 -1
- package/dist/src/cli/lib/connect-daytona.d.ts.map +1 -1
- package/dist/src/cli/lib/connect-daytona.js +4 -2
- package/dist/src/cli/lib/connect-daytona.js.map +1 -1
- package/package.json +12 -13
- package/packages/acp-bridge/package.json +2 -2
- package/packages/brand/package.json +1 -1
- package/packages/cloud/dist/types.d.ts +2 -2
- package/packages/cloud/dist/types.d.ts.map +1 -1
- package/packages/cloud/dist/types.js +5 -12
- package/packages/cloud/dist/types.js.map +1 -1
- package/packages/cloud/dist/workflows.d.ts +1 -1
- package/packages/cloud/dist/workflows.d.ts.map +1 -1
- package/packages/cloud/dist/workflows.js +113 -113
- package/packages/cloud/dist/workflows.js.map +1 -1
- package/packages/cloud/package.json +2 -2
- package/packages/cloud/src/types.ts +7 -14
- package/packages/cloud/src/workflows.ts +146 -148
- package/packages/config/dist/cloud-config.d.ts.map +1 -1
- package/packages/config/dist/cloud-config.js +1 -3
- package/packages/config/dist/cloud-config.js.map +1 -1
- package/packages/config/package.json +1 -1
- package/packages/config/src/cloud-config.ts +10 -11
- package/packages/hooks/package.json +4 -4
- package/packages/memory/package.json +2 -2
- package/packages/openclaw/package.json +2 -2
- package/packages/openclaw/skill/SKILL.md +12 -12
- package/packages/policy/package.json +2 -2
- package/packages/sdk/dist/relay.js +1 -1
- package/packages/sdk/dist/workflows/__tests__/permissions-integration.test.js +42 -0
- package/packages/sdk/dist/workflows/__tests__/permissions-integration.test.js.map +1 -1
- package/packages/sdk/dist/workflows/cli.js +4 -2
- package/packages/sdk/dist/workflows/cli.js.map +1 -1
- package/packages/sdk/dist/workflows/listr-renderer.d.ts.map +1 -1
- package/packages/sdk/dist/workflows/listr-renderer.js +2 -4
- package/packages/sdk/dist/workflows/listr-renderer.js.map +1 -1
- package/packages/sdk/dist/workflows/runner.d.ts.map +1 -1
- package/packages/sdk/dist/workflows/runner.js +6 -5
- package/packages/sdk/dist/workflows/runner.js.map +1 -1
- package/packages/sdk/package.json +2 -2
- package/packages/sdk/src/__tests__/unit.test.ts +1 -1
- package/packages/sdk/src/relay.ts +1 -1
- package/packages/sdk/src/workflows/__tests__/permissions-integration.test.ts +44 -0
- package/packages/sdk/src/workflows/cli.ts +6 -4
- package/packages/sdk/src/workflows/listr-renderer.ts +5 -7
- package/packages/sdk/src/workflows/runner.ts +6 -5
- package/packages/sdk-py/pyproject.toml +1 -1
- package/packages/telemetry/dist/client.js +1 -1
- package/packages/telemetry/package.json +1 -1
- package/packages/telemetry/src/client.ts +1 -1
- package/packages/trajectory/package.json +2 -2
- package/packages/user-directory/package.json +2 -2
- package/packages/utils/package.json +2 -2
|
@@ -1,12 +1,18 @@
|
|
|
1
|
-
import fs from
|
|
2
|
-
import path from
|
|
3
|
-
|
|
4
|
-
import { PutObjectCommand, S3Client } from
|
|
5
|
-
import ignore from
|
|
6
|
-
import * as tar from
|
|
7
|
-
|
|
8
|
-
import { ensureAuthenticated, authorizedApiFetch } from
|
|
9
|
-
import {
|
|
1
|
+
import fs from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
|
|
4
|
+
import { PutObjectCommand, S3Client } from '@aws-sdk/client-s3';
|
|
5
|
+
import ignore from 'ignore';
|
|
6
|
+
import * as tar from 'tar';
|
|
7
|
+
|
|
8
|
+
import { ensureAuthenticated, authorizedApiFetch } from './auth.js';
|
|
9
|
+
import {
|
|
10
|
+
defaultApiUrl,
|
|
11
|
+
type WorkflowFileType,
|
|
12
|
+
type RunWorkflowResponse,
|
|
13
|
+
type WorkflowLogsResponse,
|
|
14
|
+
type SyncPatchResponse,
|
|
15
|
+
} from './types.js';
|
|
10
16
|
|
|
11
17
|
type ResolvedWorkflowInput = {
|
|
12
18
|
workflow: string;
|
|
@@ -35,57 +41,56 @@ type RunWorkflowOptions = {
|
|
|
35
41
|
};
|
|
36
42
|
|
|
37
43
|
const CODE_SYNC_EXCLUDES = [
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
44
|
+
'.git',
|
|
45
|
+
'node_modules',
|
|
46
|
+
'.sst',
|
|
47
|
+
'.next',
|
|
48
|
+
'.open-next',
|
|
49
|
+
'.env',
|
|
50
|
+
'.env.*',
|
|
51
|
+
'.env.local',
|
|
52
|
+
'.env.production',
|
|
53
|
+
'*.pem',
|
|
54
|
+
'*.key',
|
|
55
|
+
'credentials.json',
|
|
56
|
+
'.aws',
|
|
57
|
+
'.ssh',
|
|
52
58
|
];
|
|
53
59
|
|
|
54
60
|
function validateYamlWorkflow(content: string): void {
|
|
55
|
-
const hasField = (field: string) =>
|
|
56
|
-
new RegExp(`^${field}\\s*:`, "m").test(content);
|
|
61
|
+
const hasField = (field: string) => new RegExp(`^${field}\\s*:`, 'm').test(content);
|
|
57
62
|
|
|
58
|
-
if (!hasField(
|
|
63
|
+
if (!hasField('version')) {
|
|
59
64
|
throw new Error('missing required field "version"');
|
|
60
65
|
}
|
|
61
|
-
if (!hasField(
|
|
66
|
+
if (!hasField('swarm')) {
|
|
62
67
|
throw new Error('missing required field "swarm"');
|
|
63
68
|
}
|
|
64
|
-
if (!hasField(
|
|
69
|
+
if (!hasField('agents')) {
|
|
65
70
|
throw new Error('missing required field "agents"');
|
|
66
71
|
}
|
|
67
|
-
if (!hasField(
|
|
72
|
+
if (!hasField('workflows')) {
|
|
68
73
|
throw new Error('missing required field "workflows"');
|
|
69
74
|
}
|
|
70
75
|
}
|
|
71
76
|
|
|
72
77
|
async function validateTypeScriptWorkflow(content: string): Promise<void> {
|
|
73
78
|
try {
|
|
74
|
-
const { execSync } = await import(
|
|
75
|
-
execSync(
|
|
79
|
+
const { execSync } = await import('node:child_process');
|
|
80
|
+
execSync('npx --yes esbuild --loader=ts', {
|
|
76
81
|
input: content,
|
|
77
|
-
encoding:
|
|
78
|
-
stdio: [
|
|
82
|
+
encoding: 'utf-8',
|
|
83
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
79
84
|
timeout: 30000,
|
|
80
85
|
});
|
|
81
86
|
} catch (error) {
|
|
82
87
|
const err = error as { status?: number; killed?: boolean; stderr?: unknown };
|
|
83
88
|
if (err.killed || !err.status) {
|
|
84
|
-
console.error(
|
|
89
|
+
console.error('TypeScript validation skipped: esbuild not available or timed out');
|
|
85
90
|
return;
|
|
86
91
|
}
|
|
87
|
-
const stderr = typeof err.stderr ===
|
|
88
|
-
const message = stderr ||
|
|
92
|
+
const stderr = typeof err.stderr === 'string' ? err.stderr.trim() : '';
|
|
93
|
+
const message = stderr || 'TypeScript validation failed';
|
|
89
94
|
throw new Error(`Workflow file has syntax errors:\n${message}`);
|
|
90
95
|
}
|
|
91
96
|
}
|
|
@@ -93,37 +98,35 @@ async function validateTypeScriptWorkflow(content: string): Promise<void> {
|
|
|
93
98
|
export function inferWorkflowFileType(filePath: string): WorkflowFileType | null {
|
|
94
99
|
const ext = path.extname(filePath).toLowerCase();
|
|
95
100
|
switch (ext) {
|
|
96
|
-
case
|
|
97
|
-
case
|
|
98
|
-
return
|
|
99
|
-
case
|
|
100
|
-
case
|
|
101
|
-
case
|
|
102
|
-
return
|
|
103
|
-
case
|
|
104
|
-
return
|
|
101
|
+
case '.yaml':
|
|
102
|
+
case '.yml':
|
|
103
|
+
return 'yaml';
|
|
104
|
+
case '.ts':
|
|
105
|
+
case '.mts':
|
|
106
|
+
case '.cts':
|
|
107
|
+
return 'ts';
|
|
108
|
+
case '.py':
|
|
109
|
+
return 'py';
|
|
105
110
|
default:
|
|
106
111
|
return null;
|
|
107
112
|
}
|
|
108
113
|
}
|
|
109
114
|
|
|
110
|
-
export function shouldSyncCodeByDefault(
|
|
111
|
-
_workflowArg: string,
|
|
112
|
-
_explicitFileType?: WorkflowFileType,
|
|
113
|
-
): boolean {
|
|
115
|
+
export function shouldSyncCodeByDefault(_workflowArg: string, _explicitFileType?: WorkflowFileType): boolean {
|
|
114
116
|
return true;
|
|
115
117
|
}
|
|
116
118
|
|
|
117
119
|
export async function resolveWorkflowInput(
|
|
118
120
|
workflowArg: string,
|
|
119
|
-
explicitFileType?: WorkflowFileType
|
|
121
|
+
explicitFileType?: WorkflowFileType
|
|
120
122
|
): Promise<ResolvedWorkflowInput> {
|
|
121
|
-
const looksLikeFile =
|
|
123
|
+
const looksLikeFile =
|
|
124
|
+
path.isAbsolute(workflowArg) ||
|
|
122
125
|
workflowArg.includes(path.sep) ||
|
|
123
126
|
inferWorkflowFileType(workflowArg) !== null;
|
|
124
127
|
|
|
125
128
|
try {
|
|
126
|
-
const workflow = await fs.readFile(workflowArg,
|
|
129
|
+
const workflow = await fs.readFile(workflowArg, 'utf-8');
|
|
127
130
|
const fileType = explicitFileType ?? inferWorkflowFileType(workflowArg);
|
|
128
131
|
if (!fileType) {
|
|
129
132
|
throw new Error(`Could not infer workflow type from ${workflowArg}. Use --file-type.`);
|
|
@@ -131,7 +134,7 @@ export async function resolveWorkflowInput(
|
|
|
131
134
|
return { workflow, fileType };
|
|
132
135
|
} catch (error) {
|
|
133
136
|
const err = error as NodeJS.ErrnoException;
|
|
134
|
-
if (err.code ===
|
|
137
|
+
if (err.code === 'EISDIR') {
|
|
135
138
|
throw new Error(`Workflow path is not a file: ${workflowArg}`);
|
|
136
139
|
}
|
|
137
140
|
if (!isMissingFileError(error)) {
|
|
@@ -145,22 +148,22 @@ export async function resolveWorkflowInput(
|
|
|
145
148
|
|
|
146
149
|
return {
|
|
147
150
|
workflow: workflowArg,
|
|
148
|
-
fileType: explicitFileType ??
|
|
151
|
+
fileType: explicitFileType ?? 'yaml',
|
|
149
152
|
};
|
|
150
153
|
}
|
|
151
154
|
|
|
152
155
|
export async function runWorkflow(
|
|
153
156
|
workflowArg: string,
|
|
154
|
-
options: RunWorkflowOptions = {}
|
|
157
|
+
options: RunWorkflowOptions = {}
|
|
155
158
|
): Promise<RunWorkflowResponse> {
|
|
156
159
|
const apiUrl = options.apiUrl ?? defaultApiUrl();
|
|
157
160
|
let auth = await ensureAuthenticated(apiUrl);
|
|
158
161
|
const input = await resolveWorkflowInput(workflowArg, options.fileType);
|
|
159
162
|
|
|
160
|
-
if (input.fileType ===
|
|
163
|
+
if (input.fileType === 'ts') {
|
|
161
164
|
await validateTypeScriptWorkflow(input.workflow);
|
|
162
|
-
} else if (input.fileType ===
|
|
163
|
-
console.error(
|
|
165
|
+
} else if (input.fileType === 'yaml') {
|
|
166
|
+
console.error('Validating workflow...');
|
|
164
167
|
validateYamlWorkflow(input.workflow);
|
|
165
168
|
}
|
|
166
169
|
|
|
@@ -175,11 +178,15 @@ export async function runWorkflow(
|
|
|
175
178
|
|
|
176
179
|
if (syncCode) {
|
|
177
180
|
const t0 = Date.now();
|
|
178
|
-
console.error(
|
|
179
|
-
const { response: prepResponse, auth: prepAuth } = await authorizedApiFetch(
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
181
|
+
console.error('Preparing run...');
|
|
182
|
+
const { response: prepResponse, auth: prepAuth } = await authorizedApiFetch(
|
|
183
|
+
auth,
|
|
184
|
+
'/api/v1/workflows/prepare',
|
|
185
|
+
{
|
|
186
|
+
method: 'POST',
|
|
187
|
+
headers: { Accept: 'application/json' },
|
|
188
|
+
}
|
|
189
|
+
);
|
|
183
190
|
auth = prepAuth;
|
|
184
191
|
|
|
185
192
|
const prepPayload = await readJsonResponse(prepResponse);
|
|
@@ -188,28 +195,30 @@ export async function runWorkflow(
|
|
|
188
195
|
}
|
|
189
196
|
|
|
190
197
|
if (!isPrepareWorkflowResponse(prepPayload)) {
|
|
191
|
-
throw new Error(
|
|
198
|
+
throw new Error('Workflow prepare response was not valid JSON.');
|
|
192
199
|
}
|
|
193
200
|
|
|
194
201
|
const prepared = prepPayload;
|
|
195
202
|
console.error(` Prepared in ${((Date.now() - t0) / 1000).toFixed(1)}s`);
|
|
196
203
|
|
|
197
204
|
const t1 = Date.now();
|
|
198
|
-
console.error(
|
|
205
|
+
console.error('Creating tarball...');
|
|
199
206
|
const s3Client = createScopedS3Client(prepared.s3Credentials);
|
|
200
207
|
const tarball = await createTarball(process.cwd());
|
|
201
|
-
console.error(
|
|
208
|
+
console.error(
|
|
209
|
+
` Tarball: ${(tarball.length / 1024).toFixed(0)}KB in ${((Date.now() - t1) / 1000).toFixed(1)}s`
|
|
210
|
+
);
|
|
202
211
|
|
|
203
212
|
const t2 = Date.now();
|
|
204
|
-
console.error(
|
|
213
|
+
console.error('Uploading to S3...');
|
|
205
214
|
const key = scopedCodeKey(prepared.s3Credentials.prefix, prepared.s3CodeKey);
|
|
206
215
|
await s3Client.send(
|
|
207
216
|
new PutObjectCommand({
|
|
208
217
|
Bucket: prepared.s3Credentials.bucket,
|
|
209
218
|
Key: key,
|
|
210
219
|
Body: tarball,
|
|
211
|
-
ContentType:
|
|
212
|
-
})
|
|
220
|
+
ContentType: 'application/gzip',
|
|
221
|
+
})
|
|
213
222
|
);
|
|
214
223
|
console.error(` Uploaded in ${((Date.now() - t2) / 1000).toFixed(1)}s`);
|
|
215
224
|
|
|
@@ -218,19 +227,15 @@ export async function runWorkflow(
|
|
|
218
227
|
}
|
|
219
228
|
|
|
220
229
|
const t3 = Date.now();
|
|
221
|
-
console.error(
|
|
222
|
-
const { response, auth: updatedAuth } = await authorizedApiFetch(
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
headers: {
|
|
228
|
-
"Content-Type": "application/json",
|
|
229
|
-
Accept: "application/json",
|
|
230
|
-
},
|
|
231
|
-
body: JSON.stringify(requestBody),
|
|
230
|
+
console.error('Launching workflow...');
|
|
231
|
+
const { response, auth: updatedAuth } = await authorizedApiFetch(auth, '/api/v1/workflows/run', {
|
|
232
|
+
method: 'POST',
|
|
233
|
+
headers: {
|
|
234
|
+
'Content-Type': 'application/json',
|
|
235
|
+
Accept: 'application/json',
|
|
232
236
|
},
|
|
233
|
-
|
|
237
|
+
body: JSON.stringify(requestBody),
|
|
238
|
+
});
|
|
234
239
|
auth = updatedAuth;
|
|
235
240
|
|
|
236
241
|
console.error(` Launched in ${((Date.now() - t3) / 1000).toFixed(1)}s`);
|
|
@@ -242,11 +247,11 @@ export async function runWorkflow(
|
|
|
242
247
|
|
|
243
248
|
if (
|
|
244
249
|
!payload ||
|
|
245
|
-
typeof payload !==
|
|
246
|
-
typeof (payload as { runId?: unknown }).runId !==
|
|
247
|
-
typeof (payload as { status?: unknown }).status !==
|
|
250
|
+
typeof payload !== 'object' ||
|
|
251
|
+
typeof (payload as { runId?: unknown }).runId !== 'string' ||
|
|
252
|
+
typeof (payload as { status?: unknown }).status !== 'string'
|
|
248
253
|
) {
|
|
249
|
-
throw new Error(
|
|
254
|
+
throw new Error('Workflow run response was not valid JSON.');
|
|
250
255
|
}
|
|
251
256
|
|
|
252
257
|
return payload as RunWorkflowResponse;
|
|
@@ -254,25 +259,21 @@ export async function runWorkflow(
|
|
|
254
259
|
|
|
255
260
|
export async function getRunStatus(
|
|
256
261
|
runId: string,
|
|
257
|
-
options: { apiUrl?: string } = {}
|
|
262
|
+
options: { apiUrl?: string } = {}
|
|
258
263
|
): Promise<Record<string, unknown>> {
|
|
259
264
|
const apiUrl = options.apiUrl ?? defaultApiUrl();
|
|
260
265
|
const auth = await ensureAuthenticated(apiUrl);
|
|
261
|
-
const { response } = await authorizedApiFetch(
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
{
|
|
265
|
-
headers: { Accept: "application/json" },
|
|
266
|
-
},
|
|
267
|
-
);
|
|
266
|
+
const { response } = await authorizedApiFetch(auth, `/api/v1/workflows/runs/${encodeURIComponent(runId)}`, {
|
|
267
|
+
headers: { Accept: 'application/json' },
|
|
268
|
+
});
|
|
268
269
|
|
|
269
270
|
const payload = await readJsonResponse(response);
|
|
270
271
|
if (!response.ok) {
|
|
271
272
|
throw new Error(`Status request failed: ${describeResponseError(response, payload)}`);
|
|
272
273
|
}
|
|
273
274
|
|
|
274
|
-
if (!payload || typeof payload !==
|
|
275
|
-
throw new Error(
|
|
275
|
+
if (!payload || typeof payload !== 'object' || Array.isArray(payload)) {
|
|
276
|
+
throw new Error('Status response was not valid JSON.');
|
|
276
277
|
}
|
|
277
278
|
|
|
278
279
|
return payload as Record<string, unknown>;
|
|
@@ -280,7 +281,7 @@ export async function getRunStatus(
|
|
|
280
281
|
|
|
281
282
|
export async function cancelWorkflow(
|
|
282
283
|
runId: string,
|
|
283
|
-
options: { apiUrl?: string } = {}
|
|
284
|
+
options: { apiUrl?: string } = {}
|
|
284
285
|
): Promise<{ runId: string; status: string }> {
|
|
285
286
|
const apiUrl = options.apiUrl ?? defaultApiUrl();
|
|
286
287
|
const auth = await ensureAuthenticated(apiUrl);
|
|
@@ -288,9 +289,9 @@ export async function cancelWorkflow(
|
|
|
288
289
|
auth,
|
|
289
290
|
`/api/v1/workflows/runs/${encodeURIComponent(runId)}/cancel`,
|
|
290
291
|
{
|
|
291
|
-
method:
|
|
292
|
-
headers: { Accept:
|
|
293
|
-
}
|
|
292
|
+
method: 'POST',
|
|
293
|
+
headers: { Accept: 'application/json' },
|
|
294
|
+
}
|
|
294
295
|
);
|
|
295
296
|
|
|
296
297
|
const payload = await readJsonResponse(response);
|
|
@@ -298,8 +299,8 @@ export async function cancelWorkflow(
|
|
|
298
299
|
throw new Error(`Cancel failed: ${describeResponseError(response, payload)}`);
|
|
299
300
|
}
|
|
300
301
|
|
|
301
|
-
if (!payload || typeof payload !==
|
|
302
|
-
throw new Error(
|
|
302
|
+
if (!payload || typeof payload !== 'object' || Array.isArray(payload)) {
|
|
303
|
+
throw new Error('Cancel response was not valid JSON.');
|
|
303
304
|
}
|
|
304
305
|
|
|
305
306
|
return payload as { runId: string; status: string };
|
|
@@ -311,22 +312,22 @@ export async function getRunLogs(
|
|
|
311
312
|
apiUrl?: string;
|
|
312
313
|
offset?: number;
|
|
313
314
|
sandboxId?: string;
|
|
314
|
-
} = {}
|
|
315
|
+
} = {}
|
|
315
316
|
): Promise<WorkflowLogsResponse> {
|
|
316
317
|
const apiUrl = options.apiUrl ?? defaultApiUrl();
|
|
317
318
|
const auth = await ensureAuthenticated(apiUrl);
|
|
318
319
|
const searchParams = new URLSearchParams();
|
|
319
|
-
if (typeof options.offset ===
|
|
320
|
-
searchParams.set(
|
|
320
|
+
if (typeof options.offset === 'number') {
|
|
321
|
+
searchParams.set('offset', String(options.offset));
|
|
321
322
|
}
|
|
322
323
|
if (options.sandboxId) {
|
|
323
|
-
searchParams.set(
|
|
324
|
+
searchParams.set('sandboxId', options.sandboxId);
|
|
324
325
|
}
|
|
325
326
|
|
|
326
|
-
const requestPath = `/api/v1/workflows/runs/${encodeURIComponent(runId)}/logs${searchParams.size ? `?${searchParams.toString()}` :
|
|
327
|
+
const requestPath = `/api/v1/workflows/runs/${encodeURIComponent(runId)}/logs${searchParams.size ? `?${searchParams.toString()}` : ''}`;
|
|
327
328
|
|
|
328
329
|
const { response } = await authorizedApiFetch(auth, requestPath, {
|
|
329
|
-
headers: { Accept:
|
|
330
|
+
headers: { Accept: 'application/json' },
|
|
330
331
|
});
|
|
331
332
|
|
|
332
333
|
const payload = await readJsonResponse(response);
|
|
@@ -336,13 +337,13 @@ export async function getRunLogs(
|
|
|
336
337
|
|
|
337
338
|
if (
|
|
338
339
|
!payload ||
|
|
339
|
-
typeof payload !==
|
|
340
|
-
typeof (payload as { content?: unknown }).content !==
|
|
341
|
-
typeof (payload as { offset?: unknown }).offset !==
|
|
342
|
-
typeof (payload as { totalSize?: unknown }).totalSize !==
|
|
343
|
-
typeof (payload as { done?: unknown }).done !==
|
|
340
|
+
typeof payload !== 'object' ||
|
|
341
|
+
typeof (payload as { content?: unknown }).content !== 'string' ||
|
|
342
|
+
typeof (payload as { offset?: unknown }).offset !== 'number' ||
|
|
343
|
+
typeof (payload as { totalSize?: unknown }).totalSize !== 'number' ||
|
|
344
|
+
typeof (payload as { done?: unknown }).done !== 'boolean'
|
|
344
345
|
) {
|
|
345
|
-
throw new Error(
|
|
346
|
+
throw new Error('Log response was not valid JSON.');
|
|
346
347
|
}
|
|
347
348
|
|
|
348
349
|
return payload as WorkflowLogsResponse;
|
|
@@ -350,7 +351,7 @@ export async function getRunLogs(
|
|
|
350
351
|
|
|
351
352
|
export async function syncWorkflowPatch(
|
|
352
353
|
runId: string,
|
|
353
|
-
options: { apiUrl?: string } = {}
|
|
354
|
+
options: { apiUrl?: string } = {}
|
|
354
355
|
): Promise<SyncPatchResponse> {
|
|
355
356
|
const apiUrl = options.apiUrl ?? defaultApiUrl();
|
|
356
357
|
let auth = await ensureAuthenticated(apiUrl);
|
|
@@ -359,7 +360,7 @@ export async function syncWorkflowPatch(
|
|
|
359
360
|
const { response: statusResponse, auth: a1 } = await authorizedApiFetch(
|
|
360
361
|
auth,
|
|
361
362
|
`/api/v1/workflows/runs/${encodeURIComponent(runId)}`,
|
|
362
|
-
{ headers: { Accept:
|
|
363
|
+
{ headers: { Accept: 'application/json' } }
|
|
363
364
|
);
|
|
364
365
|
auth = a1;
|
|
365
366
|
|
|
@@ -369,15 +370,15 @@ export async function syncWorkflowPatch(
|
|
|
369
370
|
}
|
|
370
371
|
|
|
371
372
|
const runData = (await statusResponse.json()) as { status?: string };
|
|
372
|
-
if (runData.status !==
|
|
373
|
-
throw new Error(`Run is still ${runData.status ??
|
|
373
|
+
if (runData.status !== 'completed' && runData.status !== 'failed' && runData.status !== 'cancelled') {
|
|
374
|
+
throw new Error(`Run is still ${runData.status ?? 'unknown'}. Wait for completion before syncing.`);
|
|
374
375
|
}
|
|
375
376
|
|
|
376
377
|
// Download the patch
|
|
377
378
|
const { response } = await authorizedApiFetch(
|
|
378
379
|
auth,
|
|
379
380
|
`/api/v1/workflows/runs/${encodeURIComponent(runId)}/patch`,
|
|
380
|
-
{ headers: { Accept:
|
|
381
|
+
{ headers: { Accept: 'application/json' } }
|
|
381
382
|
);
|
|
382
383
|
|
|
383
384
|
const payload = await readJsonResponse(response);
|
|
@@ -387,10 +388,10 @@ export async function syncWorkflowPatch(
|
|
|
387
388
|
|
|
388
389
|
if (
|
|
389
390
|
!payload ||
|
|
390
|
-
typeof payload !==
|
|
391
|
-
typeof (payload as { hasChanges?: unknown }).hasChanges !==
|
|
391
|
+
typeof payload !== 'object' ||
|
|
392
|
+
typeof (payload as { hasChanges?: unknown }).hasChanges !== 'boolean'
|
|
392
393
|
) {
|
|
393
|
-
throw new Error(
|
|
394
|
+
throw new Error('Patch response was not valid JSON.');
|
|
394
395
|
}
|
|
395
396
|
|
|
396
397
|
return payload as SyncPatchResponse;
|
|
@@ -412,14 +413,14 @@ async function readJsonResponse(response: Response): Promise<unknown> {
|
|
|
412
413
|
}
|
|
413
414
|
|
|
414
415
|
function describeResponseError(response: Response, payload: unknown): string {
|
|
415
|
-
if (typeof payload ===
|
|
416
|
+
if (typeof payload === 'string' && payload.trim()) {
|
|
416
417
|
return `${response.status} ${response.statusText}: ${payload.trim()}`;
|
|
417
418
|
}
|
|
418
419
|
|
|
419
|
-
if (payload && typeof payload ===
|
|
420
|
+
if (payload && typeof payload === 'object' && !Array.isArray(payload)) {
|
|
420
421
|
const record = payload as Record<string, unknown>;
|
|
421
422
|
const message = record.error ?? record.message;
|
|
422
|
-
if (typeof message ===
|
|
423
|
+
if (typeof message === 'string' && message.trim()) {
|
|
423
424
|
return `${response.status} ${response.statusText}: ${message.trim()}`;
|
|
424
425
|
}
|
|
425
426
|
}
|
|
@@ -428,35 +429,35 @@ function describeResponseError(response: Response, payload: unknown): string {
|
|
|
428
429
|
}
|
|
429
430
|
|
|
430
431
|
function isMissingFileError(error: unknown): error is NodeJS.ErrnoException {
|
|
431
|
-
return Boolean(error && typeof error ===
|
|
432
|
+
return Boolean(error && typeof error === 'object' && 'code' in error && error.code === 'ENOENT');
|
|
432
433
|
}
|
|
433
434
|
|
|
434
435
|
function isPrepareWorkflowResponse(payload: unknown): payload is PrepareWorkflowResponse {
|
|
435
|
-
if (!payload || typeof payload !==
|
|
436
|
+
if (!payload || typeof payload !== 'object' || Array.isArray(payload)) {
|
|
436
437
|
return false;
|
|
437
438
|
}
|
|
438
439
|
|
|
439
440
|
const record = payload as Record<string, unknown>;
|
|
440
441
|
const s3Creds = record.s3Credentials;
|
|
441
|
-
if (!s3Creds || typeof s3Creds !==
|
|
442
|
+
if (!s3Creds || typeof s3Creds !== 'object' || Array.isArray(s3Creds)) {
|
|
442
443
|
return false;
|
|
443
444
|
}
|
|
444
445
|
|
|
445
446
|
const creds = s3Creds as Record<string, unknown>;
|
|
446
447
|
return (
|
|
447
|
-
typeof record.runId ===
|
|
448
|
-
typeof record.s3CodeKey ===
|
|
449
|
-
typeof creds.accessKeyId ===
|
|
450
|
-
typeof creds.secretAccessKey ===
|
|
451
|
-
typeof creds.sessionToken ===
|
|
452
|
-
typeof creds.bucket ===
|
|
453
|
-
typeof creds.prefix ===
|
|
448
|
+
typeof record.runId === 'string' &&
|
|
449
|
+
typeof record.s3CodeKey === 'string' &&
|
|
450
|
+
typeof creds.accessKeyId === 'string' &&
|
|
451
|
+
typeof creds.secretAccessKey === 'string' &&
|
|
452
|
+
typeof creds.sessionToken === 'string' &&
|
|
453
|
+
typeof creds.bucket === 'string' &&
|
|
454
|
+
typeof creds.prefix === 'string'
|
|
454
455
|
);
|
|
455
456
|
}
|
|
456
457
|
|
|
457
458
|
function createScopedS3Client(s3Credentials: S3Credentials): S3Client {
|
|
458
459
|
return new S3Client({
|
|
459
|
-
region: process.env.AWS_REGION ?? process.env.AWS_DEFAULT_REGION ??
|
|
460
|
+
region: process.env.AWS_REGION ?? process.env.AWS_DEFAULT_REGION ?? 'us-east-1',
|
|
460
461
|
credentials: {
|
|
461
462
|
accessKeyId: s3Credentials.accessKeyId,
|
|
462
463
|
secretAccessKey: s3Credentials.secretAccessKey,
|
|
@@ -469,18 +470,15 @@ async function createTarball(rootDir: string): Promise<Buffer> {
|
|
|
469
470
|
const absoluteRoot = path.resolve(rootDir);
|
|
470
471
|
|
|
471
472
|
try {
|
|
472
|
-
const { execSync } = await import(
|
|
473
|
-
const gitFiles = execSync(
|
|
473
|
+
const { execSync } = await import('node:child_process');
|
|
474
|
+
const gitFiles = execSync('git ls-files -z', {
|
|
474
475
|
cwd: absoluteRoot,
|
|
475
|
-
encoding:
|
|
476
|
+
encoding: 'utf-8',
|
|
476
477
|
maxBuffer: 50 * 1024 * 1024,
|
|
477
478
|
});
|
|
478
|
-
const files = gitFiles.split(
|
|
479
|
+
const files = gitFiles.split('\0').filter(Boolean);
|
|
479
480
|
if (files.length > 0) {
|
|
480
|
-
const tarStream = tar.create(
|
|
481
|
-
{ gzip: true, cwd: absoluteRoot, portable: true },
|
|
482
|
-
files,
|
|
483
|
-
);
|
|
481
|
+
const tarStream = tar.create({ gzip: true, cwd: absoluteRoot, portable: true }, files);
|
|
484
482
|
const chunks: Buffer[] = [];
|
|
485
483
|
for await (const chunk of tarStream) {
|
|
486
484
|
chunks.push(Buffer.from(chunk as Uint8Array));
|
|
@@ -499,11 +497,11 @@ async function createTarball(rootDir: string): Promise<Buffer> {
|
|
|
499
497
|
portable: true,
|
|
500
498
|
filter(entryPath: string): boolean {
|
|
501
499
|
const normalized = normalizeEntryPath(entryPath);
|
|
502
|
-
if (!normalized || normalized ===
|
|
500
|
+
if (!normalized || normalized === '.') return true;
|
|
503
501
|
return !ig.ignores(normalized);
|
|
504
502
|
},
|
|
505
503
|
},
|
|
506
|
-
[
|
|
504
|
+
['.']
|
|
507
505
|
);
|
|
508
506
|
|
|
509
507
|
const chunks: Buffer[] = [];
|
|
@@ -519,7 +517,7 @@ async function buildIgnoreMatcher(rootDir: string): Promise<ignore.Ignore> {
|
|
|
519
517
|
ig.add(CODE_SYNC_EXCLUDES);
|
|
520
518
|
|
|
521
519
|
try {
|
|
522
|
-
const gitignoreContent = await fs.readFile(path.join(rootDir,
|
|
520
|
+
const gitignoreContent = await fs.readFile(path.join(rootDir, '.gitignore'), 'utf-8');
|
|
523
521
|
ig.add(gitignoreContent);
|
|
524
522
|
} catch (error) {
|
|
525
523
|
if (!isMissingFileError(error)) {
|
|
@@ -531,9 +529,9 @@ async function buildIgnoreMatcher(rootDir: string): Promise<ignore.Ignore> {
|
|
|
531
529
|
}
|
|
532
530
|
|
|
533
531
|
function normalizeEntryPath(entryPath: string): string {
|
|
534
|
-
return entryPath.replace(/^\.\//,
|
|
532
|
+
return entryPath.replace(/^\.\//, '').replace(/\\/g, '/');
|
|
535
533
|
}
|
|
536
534
|
|
|
537
535
|
function scopedCodeKey(prefix: string, key: string): string {
|
|
538
|
-
return [prefix, key].filter(Boolean).join(
|
|
536
|
+
return [prefix, key].filter(Boolean).join('/');
|
|
539
537
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cloud-config.d.ts","sourceRoot":"","sources":["../src/cloud-config.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,WAAW,WAAW;IAE1B,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,EAAE,MAAM,CAAC;IAItB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAG3B,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IAGjB,MAAM,EAAE;QACN,QAAQ,EAAE,MAAM,CAAC;QACjB,YAAY,EAAE,MAAM,CAAC;QACrB,aAAa,CAAC,EAAE,MAAM,CAAC;KACxB,CAAC;IAIF,SAAS,EAAE;QAET,SAAS,CAAC,EAAE;YAAE,QAAQ,EAAE,MAAM,CAAA;SAAE,CAAC;QAEjC,MAAM,CAAC,EAAE;YAAE,QAAQ,EAAE,MAAM,CAAA;SAAE,CAAC;QAE9B,MAAM,CAAC,EAAE;YAAE,QAAQ,EAAE,MAAM,CAAC;YAAC,YAAY,EAAE,MAAM,CAAA;SAAE,CAAC;KACrD,CAAC;IAGF,KAAK,EAAE;QACL,SAAS,EAAE,MAAM,CAAC;KACnB,CAAC;IAGF,OAAO,EAAE;QACP,QAAQ,EAAE,KAAK,GAAG,SAAS,GAAG,QAAQ,GAAG,SAAS,CAAC;QACnD,GAAG,CAAC,EAAE;YACJ,QAAQ,EAAE,MAAM,CAAC;YACjB,GAAG,EAAE,MAAM,CAAC;YACZ,MAAM,CAAC,EAAE,MAAM,CAAC;YAChB,eAAe,CAAC,EAAE,MAAM,CAAC;YACzB,YAAY,CAAC,EAAE;gBACb,QAAQ,EAAE,MAAM,CAAC;gBACjB,QAAQ,EAAE,MAAM,CAAC;aAClB,CAAC;YAEF,qBAAqB,CAAC,EAAE,MAAM,CAAC;YAC/B,YAAY,CAAC,EAAE,MAAM,CAAC;SACvB,CAAC;QACF,OAAO,CAAC,EAAE;YACR,QAAQ,EAAE,MAAM,CAAC;SAClB,CAAC;KACH,CAAC;IAGF,KAAK,EAAE;QACL,SAAS,EAAE,MAAM,CAAC;QAClB,IAAI,CAAC,EAAE,MAAM,CAAC;KACf,CAAC;IAGF,MAAM,EAAE;QACN,SAAS,EAAE,MAAM,CAAC;QAClB,cAAc,EAAE,MAAM,CAAC;QACvB,aAAa,EAAE,MAAM,CAAC;QACtB,QAAQ,EAAE;YACR,UAAU,CAAC,EAAE,MAAM,CAAC;YACpB,SAAS,CAAC,EAAE,MAAM,CAAC;YACnB,WAAW,CAAC,EAAE,MAAM,CAAC;YACrB,UAAU,CAAC,EAAE,MAAM,CAAC;YACpB,iBAAiB,CAAC,EAAE,MAAM,CAAC;YAC3B,gBAAgB,CAAC,EAAE,MAAM,CAAC;SAC3B,CAAC;KACH,CAAC;IAGF,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB;AAcD,wBAAgB,UAAU,IAAI,WAAW,
|
|
1
|
+
{"version":3,"file":"cloud-config.d.ts","sourceRoot":"","sources":["../src/cloud-config.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,WAAW,WAAW;IAE1B,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,EAAE,MAAM,CAAC;IAItB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAG3B,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IAGjB,MAAM,EAAE;QACN,QAAQ,EAAE,MAAM,CAAC;QACjB,YAAY,EAAE,MAAM,CAAC;QACrB,aAAa,CAAC,EAAE,MAAM,CAAC;KACxB,CAAC;IAIF,SAAS,EAAE;QAET,SAAS,CAAC,EAAE;YAAE,QAAQ,EAAE,MAAM,CAAA;SAAE,CAAC;QAEjC,MAAM,CAAC,EAAE;YAAE,QAAQ,EAAE,MAAM,CAAA;SAAE,CAAC;QAE9B,MAAM,CAAC,EAAE;YAAE,QAAQ,EAAE,MAAM,CAAC;YAAC,YAAY,EAAE,MAAM,CAAA;SAAE,CAAC;KACrD,CAAC;IAGF,KAAK,EAAE;QACL,SAAS,EAAE,MAAM,CAAC;KACnB,CAAC;IAGF,OAAO,EAAE;QACP,QAAQ,EAAE,KAAK,GAAG,SAAS,GAAG,QAAQ,GAAG,SAAS,CAAC;QACnD,GAAG,CAAC,EAAE;YACJ,QAAQ,EAAE,MAAM,CAAC;YACjB,GAAG,EAAE,MAAM,CAAC;YACZ,MAAM,CAAC,EAAE,MAAM,CAAC;YAChB,eAAe,CAAC,EAAE,MAAM,CAAC;YACzB,YAAY,CAAC,EAAE;gBACb,QAAQ,EAAE,MAAM,CAAC;gBACjB,QAAQ,EAAE,MAAM,CAAC;aAClB,CAAC;YAEF,qBAAqB,CAAC,EAAE,MAAM,CAAC;YAC/B,YAAY,CAAC,EAAE,MAAM,CAAC;SACvB,CAAC;QACF,OAAO,CAAC,EAAE;YACR,QAAQ,EAAE,MAAM,CAAC;SAClB,CAAC;KACH,CAAC;IAGF,KAAK,EAAE;QACL,SAAS,EAAE,MAAM,CAAC;QAClB,IAAI,CAAC,EAAE,MAAM,CAAC;KACf,CAAC;IAGF,MAAM,EAAE;QACN,SAAS,EAAE,MAAM,CAAC;QAClB,cAAc,EAAE,MAAM,CAAC;QACvB,aAAa,EAAE,MAAM,CAAC;QACtB,QAAQ,EAAE;YACR,UAAU,CAAC,EAAE,MAAM,CAAC;YACpB,SAAS,CAAC,EAAE,MAAM,CAAC;YACnB,WAAW,CAAC,EAAE,MAAM,CAAC;YACrB,UAAU,CAAC,EAAE,MAAM,CAAC;YACpB,iBAAiB,CAAC,EAAE,MAAM,CAAC;YAC3B,gBAAgB,CAAC,EAAE,MAAM,CAAC;SAC3B,CAAC;KACH,CAAC;IAGF,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB;AAcD,wBAAgB,UAAU,IAAI,WAAW,CAwFxC;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAG3D;AAKD,wBAAgB,SAAS,IAAI,WAAW,CAKvC"}
|
|
@@ -30,9 +30,7 @@ export function loadConfig() {
|
|
|
30
30
|
anthropic: optionalEnv('ANTHROPIC_CLIENT_ID')
|
|
31
31
|
? { clientId: optionalEnv('ANTHROPIC_CLIENT_ID') }
|
|
32
32
|
: undefined,
|
|
33
|
-
openai: optionalEnv('OPENAI_CLIENT_ID')
|
|
34
|
-
? { clientId: optionalEnv('OPENAI_CLIENT_ID') }
|
|
35
|
-
: undefined,
|
|
33
|
+
openai: optionalEnv('OPENAI_CLIENT_ID') ? { clientId: optionalEnv('OPENAI_CLIENT_ID') } : undefined,
|
|
36
34
|
google: optionalEnv('GOOGLE_CLIENT_ID') && optionalEnv('GOOGLE_CLIENT_SECRET')
|
|
37
35
|
? {
|
|
38
36
|
clientId: optionalEnv('GOOGLE_CLIENT_ID'),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cloud-config.js","sourceRoot":"","sources":["../src/cloud-config.ts"],"names":[],"mappings":"AAAA;;GAEG;AAsFH,SAAS,UAAU,CAAC,IAAY;IAC9B,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAChC,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,IAAI,KAAK,CAAC,0CAA0C,IAAI,EAAE,CAAC,CAAC;IACpE,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,WAAW,CAAC,IAAY;IAC/B,OAAO,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;AAC3B,CAAC;AAED,MAAM,UAAU,UAAU;IACxB,OAAO;QACL,IAAI,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,MAAM,EAAE,EAAE,CAAC;QAC9C,SAAS,EAAE,OAAO,CAAC,GAAG,CAAC,UAAU,IAAI,uBAAuB;QAC5D,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,OAAO,IAAI,OAAO,CAAC,GAAG,CAAC,UAAU,IAAI,uBAAuB;QAChF,aAAa,EAAE,UAAU,CAAC,gBAAgB,CAAC;QAE3C,6DAA6D;QAC7D,iBAAiB,EAAE,WAAW,CAAC,qBAAqB,CAAC;QAErD,WAAW,EAAE,UAAU,CAAC,cAAc,CAAC;QACvC,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,SAAS,IAAI,wBAAwB;QAE3D,MAAM,EAAE;YACN,QAAQ,EAAE,UAAU,CAAC,kBAAkB,CAAC;YACxC,YAAY,EAAE,UAAU,CAAC,sBAAsB,CAAC;YAChD,aAAa,EAAE,WAAW,CAAC,uBAAuB,CAAC;SACpD;QAED,SAAS,EAAE;YACT,SAAS,EAAE,WAAW,CAAC,qBAAqB,CAAC;gBAC3C,CAAC,CAAC,EAAE,QAAQ,EAAE,WAAW,CAAC,qBAAqB,CAAE,EAAE;gBACnD,CAAC,CAAC,SAAS;YACb,MAAM,EAAE,WAAW,CAAC,kBAAkB,CAAC
|
|
1
|
+
{"version":3,"file":"cloud-config.js","sourceRoot":"","sources":["../src/cloud-config.ts"],"names":[],"mappings":"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"}
|