@runtypelabs/cli 0.2.0 → 0.2.2
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 +7 -0
- package/dist/index.js +531 -107
- package/dist/index.js.map +1 -1
- package/package.json +3 -2
package/dist/index.js
CHANGED
|
@@ -231,91 +231,184 @@ var CallbackServer = class {
|
|
|
231
231
|
}
|
|
232
232
|
}
|
|
233
233
|
successHTML() {
|
|
234
|
-
return
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
234
|
+
return `<!DOCTYPE html>
|
|
235
|
+
<html lang="en">
|
|
236
|
+
<head>
|
|
237
|
+
<meta charset="utf-8">
|
|
238
|
+
<title>Authentication Successful</title>
|
|
239
|
+
<style>
|
|
240
|
+
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
241
|
+
body {
|
|
242
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
243
|
+
height: 100vh;
|
|
244
|
+
overflow: hidden;
|
|
245
|
+
background: #0a0a0a;
|
|
246
|
+
}
|
|
247
|
+
.grid-bg {
|
|
248
|
+
position: absolute;
|
|
249
|
+
inset: 0;
|
|
250
|
+
z-index: 0;
|
|
251
|
+
overflow: hidden;
|
|
252
|
+
}
|
|
253
|
+
.grid-bg .gradient {
|
|
254
|
+
position: absolute;
|
|
255
|
+
inset: 0;
|
|
256
|
+
background: linear-gradient(to bottom, #0a0a0a 0%, #171717 50%, #262626 100%);
|
|
257
|
+
}
|
|
258
|
+
@keyframes gridMove {
|
|
259
|
+
0% { background-position-y: 0; }
|
|
260
|
+
100% { background-position-y: 30px; }
|
|
261
|
+
}
|
|
262
|
+
.grid-bg .grid-vertical-wrap {
|
|
263
|
+
position: absolute;
|
|
264
|
+
left: 0;
|
|
265
|
+
right: 0;
|
|
266
|
+
bottom: 0;
|
|
267
|
+
top: 40%;
|
|
268
|
+
transform-origin: top center;
|
|
269
|
+
transform: perspective(500px) rotateX(60deg);
|
|
270
|
+
}
|
|
271
|
+
.grid-bg .grid-vertical-wrap .fade {
|
|
272
|
+
position: absolute;
|
|
273
|
+
inset: 0;
|
|
274
|
+
background: linear-gradient(to bottom, transparent 0%, rgba(255,255,255,0.02) 100%);
|
|
275
|
+
}
|
|
276
|
+
.grid-bg .grid-vertical-wrap .lines {
|
|
277
|
+
position: absolute;
|
|
278
|
+
inset: 0;
|
|
279
|
+
background-image: repeating-linear-gradient(
|
|
280
|
+
90deg,
|
|
281
|
+
transparent 0,
|
|
282
|
+
transparent 49px,
|
|
283
|
+
rgba(255,255,255,0.08) 49px,
|
|
284
|
+
rgba(255,255,255,0.08) 50px
|
|
285
|
+
);
|
|
286
|
+
background-size: 50px 100%;
|
|
287
|
+
}
|
|
288
|
+
.grid-bg .grid-horizontal {
|
|
289
|
+
position: absolute;
|
|
290
|
+
left: 0;
|
|
291
|
+
right: 0;
|
|
292
|
+
bottom: 0;
|
|
293
|
+
top: 40%;
|
|
294
|
+
transform-origin: top center;
|
|
295
|
+
transform: perspective(500px) rotateX(60deg);
|
|
296
|
+
background-image: repeating-linear-gradient(
|
|
297
|
+
0deg,
|
|
298
|
+
transparent 0,
|
|
299
|
+
transparent 29px,
|
|
300
|
+
rgba(255,255,255,0.06) 29px,
|
|
301
|
+
rgba(255,255,255,0.06) 30px
|
|
302
|
+
);
|
|
303
|
+
background-size: 100% 30px;
|
|
304
|
+
animation: gridMove 2s linear infinite;
|
|
305
|
+
}
|
|
306
|
+
.card-wrap {
|
|
307
|
+
position: absolute;
|
|
308
|
+
left: 50%;
|
|
309
|
+
top: 50%;
|
|
310
|
+
transform: translate(-50%, -50%);
|
|
311
|
+
z-index: 10;
|
|
312
|
+
width: 100%;
|
|
313
|
+
max-width: 400px;
|
|
314
|
+
perspective: 1400px;
|
|
315
|
+
animation: cardIn 0.4s ease-out;
|
|
316
|
+
}
|
|
317
|
+
@keyframes cardIn {
|
|
318
|
+
from { opacity: 0; transform: translate(-50%, -50%) translateY(16px); }
|
|
319
|
+
to { opacity: 1; transform: translate(-50%, -50%) translateY(0); }
|
|
320
|
+
}
|
|
321
|
+
.card-inner {
|
|
322
|
+
position: relative;
|
|
323
|
+
}
|
|
324
|
+
.card-layer-back,
|
|
325
|
+
.card-layer-mid {
|
|
326
|
+
position: absolute;
|
|
327
|
+
inset: 0;
|
|
328
|
+
border-radius: 12px;
|
|
329
|
+
border: 1px solid #e5e7eb;
|
|
330
|
+
pointer-events: none;
|
|
331
|
+
}
|
|
332
|
+
.card-layer-back {
|
|
333
|
+
background: rgba(0, 0, 0, 0.08);
|
|
334
|
+
transform: translate3d(0, -18px, -36px) rotateX(6deg);
|
|
335
|
+
}
|
|
336
|
+
.card-layer-mid {
|
|
337
|
+
background: rgba(0, 0, 0, 0.05);
|
|
338
|
+
transform: translate3d(0, -10px, -20px) rotateX(3deg);
|
|
339
|
+
}
|
|
340
|
+
.card-front {
|
|
341
|
+
position: relative;
|
|
342
|
+
border-radius: 12px;
|
|
343
|
+
border: 1px solid rgba(255, 255, 255, 1);
|
|
344
|
+
background: rgba(0, 0, 0, .5);
|
|
345
|
+
backdrop-filter: blur(10px);
|
|
346
|
+
-webkit-backdrop-filter: blur(10px);
|
|
347
|
+
padding: 2rem 2.5rem;
|
|
348
|
+
text-align: center;
|
|
349
|
+
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
|
|
350
|
+
transform: rotateX(-10deg) translateZ(0);
|
|
351
|
+
transform-style: preserve-3d;
|
|
352
|
+
}
|
|
353
|
+
.card-front .section-title {
|
|
354
|
+
color: #ffffff;
|
|
355
|
+
font-size: 0.8125rem;
|
|
356
|
+
font-weight: 600;
|
|
357
|
+
letter-spacing: 0.05em;
|
|
358
|
+
text-transform: uppercase;
|
|
359
|
+
margin-bottom: 1rem;
|
|
360
|
+
}
|
|
361
|
+
.card-front .flow-arrow {
|
|
362
|
+
color: rgba(255, 255, 255, 0.7);
|
|
363
|
+
font-size: 1rem;
|
|
364
|
+
margin-bottom: 1rem;
|
|
365
|
+
line-height: 1;
|
|
366
|
+
}
|
|
367
|
+
.card-front .message {
|
|
368
|
+
color: #ffffff;
|
|
369
|
+
font-size: 0.75rem;
|
|
370
|
+
font-weight: 100;
|
|
371
|
+
margin-bottom: 0.5rem;
|
|
372
|
+
font-family: monospace;
|
|
373
|
+
}
|
|
374
|
+
.card-front .progress {
|
|
375
|
+
color: rgba(255, 255, 255, 0.75);
|
|
376
|
+
font-size: 0.8125rem;
|
|
377
|
+
}
|
|
378
|
+
</style>
|
|
379
|
+
</head>
|
|
380
|
+
<body>
|
|
381
|
+
<div class="grid-bg">
|
|
382
|
+
<div class="gradient"></div>
|
|
383
|
+
<div class="grid-vertical-wrap">
|
|
384
|
+
<div class="fade"></div>
|
|
385
|
+
<div class="lines"></div>
|
|
386
|
+
</div>
|
|
387
|
+
<div class="grid-horizontal"></div>
|
|
388
|
+
</div>
|
|
389
|
+
<div id="card-wrap" class="card-wrap">
|
|
390
|
+
<div class="card-inner">
|
|
391
|
+
<div class="card-layer-back" aria-hidden="true"></div>
|
|
392
|
+
<div class="card-layer-mid" aria-hidden="true"></div>
|
|
393
|
+
<div id="card" class="card-front">
|
|
394
|
+
<div class="section-title">Authentication Successful</div>
|
|
395
|
+
<div class="flow-arrow" aria-hidden="true">\u2193</div>
|
|
396
|
+
<p class="message">You can close this window and return to your terminal.</p>
|
|
397
|
+
<p class="progress" id="progress">Closing automatically in 3 seconds\u2026</p>
|
|
398
|
+
</div>
|
|
399
|
+
</div>
|
|
400
|
+
</div>
|
|
401
|
+
<script>
|
|
402
|
+
setTimeout(function() {
|
|
403
|
+
window.close();
|
|
404
|
+
var prog = document.getElementById('progress');
|
|
405
|
+
if (prog) prog.textContent = 'You can now close this window.';
|
|
406
|
+
var card = document.getElementById('card');
|
|
407
|
+
if (card) card.innerHTML = '<div class="section-title">Runtype is Ready</div><p class="message">You can now close this window</p>';
|
|
408
|
+
}, 3000);
|
|
409
|
+
</script>
|
|
410
|
+
</body>
|
|
411
|
+
</html>`;
|
|
319
412
|
}
|
|
320
413
|
errorHTML(error) {
|
|
321
414
|
return `
|
|
@@ -469,10 +562,10 @@ var isAuthMeResponse = (value) => {
|
|
|
469
562
|
return typeof record.user_id === "string";
|
|
470
563
|
};
|
|
471
564
|
var ApiKeyManager = class {
|
|
472
|
-
async exchangeSessionForApiKey(authCode, apiUrl) {
|
|
565
|
+
async exchangeSessionForApiKey(authCode, apiUrl, dashboardUrl) {
|
|
473
566
|
void apiUrl;
|
|
474
|
-
const
|
|
475
|
-
const authResponse = await fetch(`${
|
|
567
|
+
const base = dashboardUrl ?? getDashboardUrl();
|
|
568
|
+
const authResponse = await fetch(`${base.replace(/\/$/, "")}/api/cli/auth?code=${encodeURIComponent(authCode)}`, {
|
|
476
569
|
method: "GET",
|
|
477
570
|
headers: {
|
|
478
571
|
"Content-Type": "application/json"
|
|
@@ -544,7 +637,8 @@ authCommand.command("signup").description("Create a new Runtype account").option
|
|
|
544
637
|
const apiKeyManager = new ApiKeyManager();
|
|
545
638
|
const { key, userId, orgId } = await apiKeyManager.exchangeSessionForApiKey(
|
|
546
639
|
sessionToken,
|
|
547
|
-
options.apiUrl || getApiUrl()
|
|
640
|
+
options.apiUrl || getApiUrl(),
|
|
641
|
+
options.dashboardUrl || getDashboardUrl()
|
|
548
642
|
);
|
|
549
643
|
spinner.text = "Storing credentials securely...";
|
|
550
644
|
const store = new CredentialStore();
|
|
@@ -610,7 +704,8 @@ authCommand.command("login").description("Login to existing account").option("--
|
|
|
610
704
|
const apiKeyManager = new ApiKeyManager();
|
|
611
705
|
const { key, userId, orgId } = await apiKeyManager.exchangeSessionForApiKey(
|
|
612
706
|
sessionToken,
|
|
613
|
-
options.apiUrl || getApiUrl()
|
|
707
|
+
options.apiUrl || getApiUrl(),
|
|
708
|
+
options.dashboardUrl || getDashboardUrl()
|
|
614
709
|
);
|
|
615
710
|
spinner.text = "Storing credentials...";
|
|
616
711
|
await store.saveCredentials({
|
|
@@ -886,7 +981,8 @@ async function handleBrowserLogin(store, apiUrl) {
|
|
|
886
981
|
const apiKeyManager = new ApiKeyManager();
|
|
887
982
|
const { key, userId, orgId } = await apiKeyManager.exchangeSessionForApiKey(
|
|
888
983
|
sessionToken,
|
|
889
|
-
apiUrl || getApiUrl()
|
|
984
|
+
apiUrl || getApiUrl(),
|
|
985
|
+
getDashboardUrl()
|
|
890
986
|
);
|
|
891
987
|
spinner.text = "Storing credentials...";
|
|
892
988
|
await store.saveCredentials({
|
|
@@ -2500,7 +2596,8 @@ async function handleBrowserAuth(store, mode, apiUrl) {
|
|
|
2500
2596
|
const apiKeyManager = new ApiKeyManager();
|
|
2501
2597
|
const { key, userId, orgId } = await apiKeyManager.exchangeSessionForApiKey(
|
|
2502
2598
|
sessionToken,
|
|
2503
|
-
apiUrl || getApiUrl()
|
|
2599
|
+
apiUrl || getApiUrl(),
|
|
2600
|
+
getDashboardUrl()
|
|
2504
2601
|
);
|
|
2505
2602
|
await store.saveCredentials({
|
|
2506
2603
|
apiKey: key,
|
|
@@ -2812,6 +2909,205 @@ function saveState(filePath, state) {
|
|
|
2812
2909
|
fs3.mkdirSync(dir, { recursive: true });
|
|
2813
2910
|
fs3.writeFileSync(filePath, JSON.stringify(state, null, 2));
|
|
2814
2911
|
}
|
|
2912
|
+
function isRecord(value) {
|
|
2913
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2914
|
+
}
|
|
2915
|
+
function parseSandboxProvider(value) {
|
|
2916
|
+
if (!value) return void 0;
|
|
2917
|
+
const normalized = value.trim().toLowerCase();
|
|
2918
|
+
if (normalized === "quickjs" || normalized === "daytona") return normalized;
|
|
2919
|
+
return void 0;
|
|
2920
|
+
}
|
|
2921
|
+
function parseSandboxLanguage(provider, value) {
|
|
2922
|
+
if (provider === "quickjs") return "javascript";
|
|
2923
|
+
if (typeof value === "string") {
|
|
2924
|
+
const normalized = value.trim().toLowerCase();
|
|
2925
|
+
if (normalized === "javascript" || normalized === "typescript" || normalized === "python") {
|
|
2926
|
+
return normalized;
|
|
2927
|
+
}
|
|
2928
|
+
}
|
|
2929
|
+
return "javascript";
|
|
2930
|
+
}
|
|
2931
|
+
function parseSandboxTimeout(value, provider) {
|
|
2932
|
+
const fallback = provider === "quickjs" ? 5e3 : 3e4;
|
|
2933
|
+
let numericValue;
|
|
2934
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
2935
|
+
numericValue = value;
|
|
2936
|
+
} else if (typeof value === "string" && value.trim() !== "") {
|
|
2937
|
+
const parsed = Number(value);
|
|
2938
|
+
if (Number.isFinite(parsed)) {
|
|
2939
|
+
numericValue = parsed;
|
|
2940
|
+
}
|
|
2941
|
+
}
|
|
2942
|
+
if (numericValue === void 0) return fallback;
|
|
2943
|
+
return Math.max(1, Math.min(3e4, Math.floor(numericValue)));
|
|
2944
|
+
}
|
|
2945
|
+
function parseDaytonaExecutionResult(value) {
|
|
2946
|
+
if (typeof value !== "string") return value;
|
|
2947
|
+
const trimmed = value.trim();
|
|
2948
|
+
if (!trimmed) return "";
|
|
2949
|
+
try {
|
|
2950
|
+
return JSON.parse(trimmed);
|
|
2951
|
+
} catch {
|
|
2952
|
+
const lines = trimmed.split("\n").map((line) => line.trim()).filter(Boolean);
|
|
2953
|
+
const lastLine = lines[lines.length - 1];
|
|
2954
|
+
if (!lastLine) return value;
|
|
2955
|
+
try {
|
|
2956
|
+
return JSON.parse(lastLine);
|
|
2957
|
+
} catch {
|
|
2958
|
+
return value;
|
|
2959
|
+
}
|
|
2960
|
+
}
|
|
2961
|
+
}
|
|
2962
|
+
function createSandboxInstructions(provider) {
|
|
2963
|
+
if (provider === "quickjs") {
|
|
2964
|
+
return [
|
|
2965
|
+
"--- Sandbox Tooling (QuickJS) ---",
|
|
2966
|
+
"You can execute JavaScript snippets with the local tool `run_sandbox_code`.",
|
|
2967
|
+
"Call shape:",
|
|
2968
|
+
'{ "code": "...", "parameters": { ... }, "timeoutMs": 5000 }',
|
|
2969
|
+
"QuickJS rules:",
|
|
2970
|
+
"1. Use JavaScript only (no TypeScript or Python).",
|
|
2971
|
+
"2. Inputs are passed in the `parameters` object (for example: `const x = parameters.x`).",
|
|
2972
|
+
"3. The snippet is wrapped in a function. Use top-level `return ...` to produce the result.",
|
|
2973
|
+
"4. Return JSON-serializable values (object, array, string, number, boolean, null).",
|
|
2974
|
+
"5. No Node/Bun/Deno APIs, imports/require, process, filesystem, or network calls.",
|
|
2975
|
+
"Example:",
|
|
2976
|
+
"const nums = parameters.nums || []",
|
|
2977
|
+
"const sum = nums.reduce((acc, n) => acc + n, 0)",
|
|
2978
|
+
"return { sum, count: nums.length }"
|
|
2979
|
+
].join("\n");
|
|
2980
|
+
}
|
|
2981
|
+
return [
|
|
2982
|
+
"--- Sandbox Tooling (Daytona) ---",
|
|
2983
|
+
"You can execute code snippets with the local tool `run_sandbox_code`.",
|
|
2984
|
+
"Call shape:",
|
|
2985
|
+
'{ "code": "...", "parameters": { ... }, "language": "javascript|typescript|python", "timeoutMs": 30000 }',
|
|
2986
|
+
"Daytona rules:",
|
|
2987
|
+
"1. Choose one language: javascript, typescript, or python.",
|
|
2988
|
+
"2. Parameters are injected as top-level variables before your code (do not rely on `parameters`).",
|
|
2989
|
+
"3. Your snippet runs as a full program. Do not use top-level `return`.",
|
|
2990
|
+
"4. For structured results, write a single JSON value to stdout as the final output.",
|
|
2991
|
+
"5. JS/TS: `console.log(JSON.stringify({ ... }))`; Python: `import json` then `print(json.dumps({ ... }))`.",
|
|
2992
|
+
"6. Avoid extra logs before the final JSON line, or parsing may fail."
|
|
2993
|
+
].join("\n");
|
|
2994
|
+
}
|
|
2995
|
+
function buildResumeCommand(agent, message, options, parsedSandbox) {
|
|
2996
|
+
const nameFlag = options.name ? ` --name ${options.name}` : "";
|
|
2997
|
+
const sandboxFlag = parsedSandbox ? ` --sandbox ${parsedSandbox}` : "";
|
|
2998
|
+
return `runtype marathon ${agent} -m "${message}" --resume${nameFlag}${sandboxFlag}`;
|
|
2999
|
+
}
|
|
3000
|
+
function createSandboxLocalTool(client, provider, debugMode) {
|
|
3001
|
+
return {
|
|
3002
|
+
description: provider === "quickjs" ? "Execute JavaScript code in QuickJS sandbox. Inputs are passed via parameters object." : "Execute JavaScript/TypeScript/Python code in Daytona sandbox. Inputs are injected as top-level variables.",
|
|
3003
|
+
parametersSchema: {
|
|
3004
|
+
type: "object",
|
|
3005
|
+
properties: {
|
|
3006
|
+
code: { type: "string", description: "Code snippet to execute" },
|
|
3007
|
+
parameters: {
|
|
3008
|
+
type: "object",
|
|
3009
|
+
description: "Input parameters for the code (JSON object)"
|
|
3010
|
+
},
|
|
3011
|
+
language: {
|
|
3012
|
+
type: "string",
|
|
3013
|
+
enum: provider === "quickjs" ? ["javascript"] : ["javascript", "typescript", "python"],
|
|
3014
|
+
description: provider === "quickjs" ? "QuickJS only accepts javascript" : "Daytona code language"
|
|
3015
|
+
},
|
|
3016
|
+
timeoutMs: { type: "number", description: "Execution timeout in ms (max 30000)" }
|
|
3017
|
+
},
|
|
3018
|
+
required: ["code"]
|
|
3019
|
+
},
|
|
3020
|
+
execute: async (args) => {
|
|
3021
|
+
const rawCode = args.code;
|
|
3022
|
+
const code = typeof rawCode === "string" ? rawCode : "";
|
|
3023
|
+
if (!code.trim()) {
|
|
3024
|
+
return { success: false, error: "code is required" };
|
|
3025
|
+
}
|
|
3026
|
+
const language = parseSandboxLanguage(provider, args.language);
|
|
3027
|
+
const timeout = parseSandboxTimeout(args.timeoutMs, provider);
|
|
3028
|
+
const parameters = isRecord(args.parameters) ? args.parameters : {};
|
|
3029
|
+
const gateDecision = (0, import_sdk5.evaluateGeneratedRuntimeToolProposal)(
|
|
3030
|
+
{
|
|
3031
|
+
name: "run_sandbox_code",
|
|
3032
|
+
description: `Execute code in ${provider}`,
|
|
3033
|
+
toolType: "custom",
|
|
3034
|
+
parametersSchema: { type: "object" },
|
|
3035
|
+
config: {
|
|
3036
|
+
code,
|
|
3037
|
+
timeout,
|
|
3038
|
+
sandboxProvider: provider,
|
|
3039
|
+
language
|
|
3040
|
+
}
|
|
3041
|
+
},
|
|
3042
|
+
{
|
|
3043
|
+
allowedToolTypes: ["custom"],
|
|
3044
|
+
allowedSandboxProviders: [provider],
|
|
3045
|
+
allowedLanguages: provider === "quickjs" ? ["javascript"] : ["javascript", "typescript", "python"],
|
|
3046
|
+
maxTimeoutMs: 3e4,
|
|
3047
|
+
maxCodeLength: 12e3
|
|
3048
|
+
}
|
|
3049
|
+
);
|
|
3050
|
+
if (!gateDecision.approved) {
|
|
3051
|
+
return {
|
|
3052
|
+
success: false,
|
|
3053
|
+
error: gateDecision.reason,
|
|
3054
|
+
violations: gateDecision.violations
|
|
3055
|
+
};
|
|
3056
|
+
}
|
|
3057
|
+
const tempToolName = `marathon_${provider}_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
|
|
3058
|
+
let tempToolId;
|
|
3059
|
+
try {
|
|
3060
|
+
const createRequest = {
|
|
3061
|
+
name: tempToolName,
|
|
3062
|
+
description: `Ephemeral ${provider} sandbox execution`,
|
|
3063
|
+
toolType: "custom",
|
|
3064
|
+
parametersSchema: { type: "object", properties: {} },
|
|
3065
|
+
config: {
|
|
3066
|
+
code,
|
|
3067
|
+
timeout,
|
|
3068
|
+
allowedApis: [],
|
|
3069
|
+
sandboxProvider: provider,
|
|
3070
|
+
language
|
|
3071
|
+
}
|
|
3072
|
+
};
|
|
3073
|
+
const created = await client.tools.create(createRequest);
|
|
3074
|
+
tempToolId = created.id;
|
|
3075
|
+
const executeRequest = {
|
|
3076
|
+
toolId: created.id,
|
|
3077
|
+
parameters
|
|
3078
|
+
};
|
|
3079
|
+
const execution = await client.tools.execute(created.id, executeRequest);
|
|
3080
|
+
const parsedResult = provider === "daytona" ? parseDaytonaExecutionResult(execution.result) : execution.result;
|
|
3081
|
+
return {
|
|
3082
|
+
success: execution.status === "success",
|
|
3083
|
+
sandboxProvider: provider,
|
|
3084
|
+
language,
|
|
3085
|
+
result: parsedResult,
|
|
3086
|
+
executionId: execution.executionId,
|
|
3087
|
+
...execution.errorMessage ? { error: execution.errorMessage } : {}
|
|
3088
|
+
};
|
|
3089
|
+
} catch (error) {
|
|
3090
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
3091
|
+
if (debugMode) {
|
|
3092
|
+
console.log(import_chalk15.default.gray(` [sandbox:${provider}] execution error: ${message}`));
|
|
3093
|
+
}
|
|
3094
|
+
return {
|
|
3095
|
+
success: false,
|
|
3096
|
+
sandboxProvider: provider,
|
|
3097
|
+
language,
|
|
3098
|
+
error: message
|
|
3099
|
+
};
|
|
3100
|
+
} finally {
|
|
3101
|
+
if (tempToolId) {
|
|
3102
|
+
try {
|
|
3103
|
+
await client.tools.delete(tempToolId);
|
|
3104
|
+
} catch {
|
|
3105
|
+
}
|
|
3106
|
+
}
|
|
3107
|
+
}
|
|
3108
|
+
}
|
|
3109
|
+
};
|
|
3110
|
+
}
|
|
2815
3111
|
async function taskAction(agent, options) {
|
|
2816
3112
|
const apiKey = await ensureAuth();
|
|
2817
3113
|
if (!apiKey) return;
|
|
@@ -2819,6 +3115,11 @@ async function taskAction(agent, options) {
|
|
|
2819
3115
|
apiKey,
|
|
2820
3116
|
baseUrl: getApiUrl()
|
|
2821
3117
|
});
|
|
3118
|
+
const parsedSandbox = parseSandboxProvider(options.sandbox);
|
|
3119
|
+
if (options.sandbox && !parsedSandbox) {
|
|
3120
|
+
console.error(import_chalk15.default.red(`Invalid --sandbox value "${options.sandbox}". Use: quickjs or daytona`));
|
|
3121
|
+
process.exit(1);
|
|
3122
|
+
}
|
|
2822
3123
|
let agentId = agent;
|
|
2823
3124
|
if (!agent.startsWith("agent_")) {
|
|
2824
3125
|
const spinner = (0, import_ora10.default)("Looking up agent by name...").start();
|
|
@@ -2831,13 +3132,21 @@ async function taskAction(agent, options) {
|
|
|
2831
3132
|
agentId = found.id;
|
|
2832
3133
|
spinner.succeed(`Found agent: ${import_chalk15.default.green(agentId)}`);
|
|
2833
3134
|
} else {
|
|
2834
|
-
spinner.
|
|
2835
|
-
|
|
2836
|
-
|
|
3135
|
+
spinner.text = `Creating agent "${agent}"...`;
|
|
3136
|
+
try {
|
|
3137
|
+
const created = await client.agents.create({ name: agent });
|
|
3138
|
+
agentId = created.id;
|
|
3139
|
+
spinner.succeed(`Created agent: ${import_chalk15.default.green(agentId)}`);
|
|
3140
|
+
} catch (createErr) {
|
|
3141
|
+
spinner.fail(`Failed to create agent "${agent}"`);
|
|
3142
|
+
const errMsg = createErr instanceof Error ? createErr.message : String(createErr);
|
|
3143
|
+
console.error(import_chalk15.default.red(errMsg));
|
|
3144
|
+
process.exit(1);
|
|
3145
|
+
}
|
|
2837
3146
|
}
|
|
2838
3147
|
} catch (error) {
|
|
2839
|
-
spinner.fail("Failed to
|
|
2840
|
-
const errMsg = error instanceof Error ? error.message :
|
|
3148
|
+
spinner.fail("Failed to list agents");
|
|
3149
|
+
const errMsg = error instanceof Error ? error.message : String(error);
|
|
2841
3150
|
console.error(import_chalk15.default.red(errMsg));
|
|
2842
3151
|
process.exit(1);
|
|
2843
3152
|
}
|
|
@@ -2881,7 +3190,7 @@ async function taskAction(agent, options) {
|
|
|
2881
3190
|
}
|
|
2882
3191
|
console.log(
|
|
2883
3192
|
import_chalk15.default.gray(
|
|
2884
|
-
` Resume with:
|
|
3193
|
+
` Resume with: ${buildResumeCommand(agent, options.message, options, parsedSandbox)}`
|
|
2885
3194
|
)
|
|
2886
3195
|
);
|
|
2887
3196
|
process.exit(0);
|
|
@@ -2889,32 +3198,63 @@ async function taskAction(agent, options) {
|
|
|
2889
3198
|
process.on("SIGINT", onSigint);
|
|
2890
3199
|
const remainingSessions = maxSessions - priorSessionCount;
|
|
2891
3200
|
const remainingCost = maxCost ? maxCost - priorCost : void 0;
|
|
3201
|
+
const sandboxPrompt = parsedSandbox ? createSandboxInstructions(parsedSandbox) : "";
|
|
3202
|
+
const taskMessage = sandboxPrompt ? `${options.message}
|
|
3203
|
+
|
|
3204
|
+
${sandboxPrompt}` : options.message;
|
|
2892
3205
|
console.log(import_chalk15.default.cyan(`
|
|
2893
3206
|
Running task "${taskName}" on ${agentId}`));
|
|
2894
3207
|
console.log(
|
|
2895
3208
|
import_chalk15.default.gray(
|
|
2896
|
-
` Sessions: ${priorSessionCount > 0 ? `${priorSessionCount} done, ` : ""}${remainingSessions} remaining${maxCost ? ` | Budget: $${maxCost.toFixed(2)}` : ""}`
|
|
3209
|
+
` Sessions: ${priorSessionCount > 0 ? `${priorSessionCount} done, ` : ""}${remainingSessions} remaining${maxCost ? ` | Budget: $${maxCost.toFixed(2)}` : ""}${options.model ? ` | Model: ${options.model}` : ""}${parsedSandbox ? ` | Sandbox: ${parsedSandbox}` : ""}`
|
|
2897
3210
|
)
|
|
2898
3211
|
);
|
|
2899
3212
|
console.log(import_chalk15.default.gray(` State: ${filePath}
|
|
2900
3213
|
`));
|
|
2901
3214
|
try {
|
|
2902
3215
|
let currentSession = priorSessionCount;
|
|
3216
|
+
let thinkingSpinner = null;
|
|
3217
|
+
let thinkingChars = 0;
|
|
2903
3218
|
const streamCallbacks = {
|
|
2904
3219
|
onAgentStart: () => {
|
|
2905
3220
|
currentSession++;
|
|
2906
3221
|
console.log(import_chalk15.default.cyan(`
|
|
2907
3222
|
\u2500\u2500 Session ${currentSession} \u2500\u2500
|
|
2908
3223
|
`));
|
|
3224
|
+
thinkingChars = 0;
|
|
3225
|
+
thinkingSpinner = (0, import_ora10.default)({ text: import_chalk15.default.dim("Thinking..."), color: "gray" }).start();
|
|
2909
3226
|
},
|
|
2910
3227
|
onTurnDelta: (event) => {
|
|
2911
3228
|
if (event.contentType === "text") {
|
|
3229
|
+
if (thinkingSpinner) {
|
|
3230
|
+
thinkingSpinner.stop();
|
|
3231
|
+
thinkingSpinner = null;
|
|
3232
|
+
}
|
|
2912
3233
|
process.stdout.write(event.delta);
|
|
2913
|
-
} else if (event.contentType === "thinking"
|
|
2914
|
-
|
|
3234
|
+
} else if (event.contentType === "thinking") {
|
|
3235
|
+
thinkingChars += event.delta.length;
|
|
3236
|
+
const approxTokens = Math.round(thinkingChars / 4);
|
|
3237
|
+
const tokenStr = approxTokens.toLocaleString();
|
|
3238
|
+
if (!thinkingSpinner) {
|
|
3239
|
+
thinkingSpinner = (0, import_ora10.default)({
|
|
3240
|
+
text: import_chalk15.default.dim(`Thinking... (~${tokenStr} tokens)`),
|
|
3241
|
+
color: "gray"
|
|
3242
|
+
}).start();
|
|
3243
|
+
} else {
|
|
3244
|
+
thinkingSpinner.text = import_chalk15.default.dim(`Thinking... (~${tokenStr} tokens)`);
|
|
3245
|
+
}
|
|
3246
|
+
if (options.debug) {
|
|
3247
|
+
thinkingSpinner.stop();
|
|
3248
|
+
process.stdout.write(import_chalk15.default.dim(event.delta));
|
|
3249
|
+
thinkingSpinner.start();
|
|
3250
|
+
}
|
|
2915
3251
|
}
|
|
2916
3252
|
},
|
|
2917
3253
|
onToolStart: (event) => {
|
|
3254
|
+
if (thinkingSpinner) {
|
|
3255
|
+
thinkingSpinner.stop();
|
|
3256
|
+
thinkingSpinner = null;
|
|
3257
|
+
}
|
|
2918
3258
|
if (options.debug) {
|
|
2919
3259
|
console.log(import_chalk15.default.gray(`
|
|
2920
3260
|
[tool] ${event.toolName}...`));
|
|
@@ -2926,18 +3266,100 @@ Running task "${taskName}" on ${agentId}`));
|
|
|
2926
3266
|
console.log(import_chalk15.default.gray(` [tool] ${event.toolName} \u2192 ${status}`));
|
|
2927
3267
|
}
|
|
2928
3268
|
},
|
|
3269
|
+
onAgentPaused: (event) => {
|
|
3270
|
+
if (thinkingSpinner) {
|
|
3271
|
+
thinkingSpinner.stop();
|
|
3272
|
+
thinkingSpinner = null;
|
|
3273
|
+
}
|
|
3274
|
+
const rawParams = event.parameters;
|
|
3275
|
+
const paramPreview = typeof rawParams === "string" ? `string(${rawParams.length} chars)` : rawParams && typeof rawParams === "object" ? `object(${Object.keys(rawParams).join(", ")})` : typeof rawParams;
|
|
3276
|
+
console.log(
|
|
3277
|
+
import_chalk15.default.cyan(
|
|
3278
|
+
`
|
|
3279
|
+
[local tool] ${event.toolName} called (params: ${paramPreview})`
|
|
3280
|
+
)
|
|
3281
|
+
);
|
|
3282
|
+
if (options.debug) {
|
|
3283
|
+
console.log(import_chalk15.default.gray(` executionId: ${event.executionId}`));
|
|
3284
|
+
console.log(import_chalk15.default.gray(` raw params: ${JSON.stringify(event.parameters).slice(0, 300)}`));
|
|
3285
|
+
}
|
|
3286
|
+
},
|
|
2929
3287
|
onError: (event) => {
|
|
3288
|
+
if (thinkingSpinner) {
|
|
3289
|
+
thinkingSpinner.stop();
|
|
3290
|
+
thinkingSpinner = null;
|
|
3291
|
+
}
|
|
2930
3292
|
console.error(import_chalk15.default.red(`
|
|
2931
3293
|
Error: ${event.error}`));
|
|
2932
3294
|
}
|
|
2933
3295
|
};
|
|
3296
|
+
const defaultLocalTools = {
|
|
3297
|
+
read_file: {
|
|
3298
|
+
description: "Read the contents of a file at the given path",
|
|
3299
|
+
parametersSchema: {
|
|
3300
|
+
type: "object",
|
|
3301
|
+
properties: { path: { type: "string", description: "File path to read" } },
|
|
3302
|
+
required: ["path"]
|
|
3303
|
+
},
|
|
3304
|
+
execute: async (args) => {
|
|
3305
|
+
const filePath2 = String(args.path || "");
|
|
3306
|
+
if (!filePath2) return "Error: path is required";
|
|
3307
|
+
return fs3.readFileSync(filePath2, "utf-8");
|
|
3308
|
+
}
|
|
3309
|
+
},
|
|
3310
|
+
write_file: {
|
|
3311
|
+
description: "Write content to a file, creating directories as needed",
|
|
3312
|
+
parametersSchema: {
|
|
3313
|
+
type: "object",
|
|
3314
|
+
properties: {
|
|
3315
|
+
path: { type: "string", description: "File path to write" },
|
|
3316
|
+
content: { type: "string", description: "Content to write" }
|
|
3317
|
+
},
|
|
3318
|
+
required: ["path", "content"]
|
|
3319
|
+
},
|
|
3320
|
+
execute: async (args) => {
|
|
3321
|
+
const filePath2 = String(args.path || "");
|
|
3322
|
+
if (!filePath2) return "Error: path is required";
|
|
3323
|
+
const content = String(args.content || "");
|
|
3324
|
+
const dir = path4.dirname(filePath2);
|
|
3325
|
+
fs3.mkdirSync(dir, { recursive: true });
|
|
3326
|
+
fs3.writeFileSync(filePath2, content);
|
|
3327
|
+
return "ok";
|
|
3328
|
+
}
|
|
3329
|
+
},
|
|
3330
|
+
list_directory: {
|
|
3331
|
+
description: "List files and directories at the given path",
|
|
3332
|
+
parametersSchema: {
|
|
3333
|
+
type: "object",
|
|
3334
|
+
properties: { path: { type: "string", description: 'Directory path (defaults to ".")' } }
|
|
3335
|
+
},
|
|
3336
|
+
execute: async (args) => {
|
|
3337
|
+
const dirPath = String(args.path || ".");
|
|
3338
|
+
return fs3.readdirSync(dirPath).join("\n");
|
|
3339
|
+
}
|
|
3340
|
+
}
|
|
3341
|
+
};
|
|
3342
|
+
const enabledLocalTools = {};
|
|
3343
|
+
if (!options.noLocalTools) {
|
|
3344
|
+
Object.assign(enabledLocalTools, defaultLocalTools);
|
|
3345
|
+
}
|
|
3346
|
+
if (parsedSandbox) {
|
|
3347
|
+
enabledLocalTools.run_sandbox_code = createSandboxLocalTool(
|
|
3348
|
+
client,
|
|
3349
|
+
parsedSandbox,
|
|
3350
|
+
options.debug
|
|
3351
|
+
);
|
|
3352
|
+
}
|
|
3353
|
+
const localTools = Object.keys(enabledLocalTools).length > 0 ? enabledLocalTools : void 0;
|
|
2934
3354
|
const result = await client.agents.runTask(agentId, {
|
|
2935
|
-
message:
|
|
3355
|
+
message: taskMessage,
|
|
2936
3356
|
maxSessions: remainingSessions,
|
|
2937
3357
|
maxCost: remainingCost,
|
|
3358
|
+
model: options.model,
|
|
2938
3359
|
debugMode: options.debug,
|
|
2939
3360
|
stream: true,
|
|
2940
3361
|
streamCallbacks,
|
|
3362
|
+
localTools,
|
|
2941
3363
|
trackProgress: options.track ? taskName : void 0,
|
|
2942
3364
|
onSession: (state) => {
|
|
2943
3365
|
const adjustedState = {
|
|
@@ -2951,7 +3373,7 @@ Running task "${taskName}" on ${agentId}`));
|
|
|
2951
3373
|
if (latest) {
|
|
2952
3374
|
const total = adjustedState.sessionCount;
|
|
2953
3375
|
const costStr = import_chalk15.default.yellow(`$${adjustedState.totalCost.toFixed(4)}`);
|
|
2954
|
-
const reasonColor = latest.stopReason === "complete" ? import_chalk15.default.green : import_chalk15.default.gray;
|
|
3376
|
+
const reasonColor = latest.stopReason === "complete" ? import_chalk15.default.green : latest.stopReason === "error" ? import_chalk15.default.red : import_chalk15.default.gray;
|
|
2955
3377
|
console.log(
|
|
2956
3378
|
`
|
|
2957
3379
|
${import_chalk15.default.dim(`[${total}/${maxSessions}]`)} ${reasonColor(latest.stopReason)} | total: ${costStr}`
|
|
@@ -2988,7 +3410,7 @@ Running task "${taskName}" on ${agentId}`));
|
|
|
2988
3410
|
console.log(
|
|
2989
3411
|
import_chalk15.default.gray(
|
|
2990
3412
|
`
|
|
2991
|
-
Resume:
|
|
3413
|
+
Resume: ${buildResumeCommand(agent, options.message, options, parsedSandbox)}`
|
|
2992
3414
|
)
|
|
2993
3415
|
);
|
|
2994
3416
|
}
|
|
@@ -3011,7 +3433,7 @@ Task failed: ${errMsg}`));
|
|
|
3011
3433
|
}
|
|
3012
3434
|
}
|
|
3013
3435
|
function applyTaskOptions(cmd) {
|
|
3014
|
-
return cmd.argument("<agent>", "Agent ID or name").requiredOption("-m, --message <text>", "Task message for the agent").option("--max-sessions <n>", "Maximum sessions", "50").option("--max-cost <n>", "Budget in USD").option("--name <name>", "Task name (used for state file, defaults to agent name)").option("--state-dir <path>", "Directory for state files (default: .runtype/tasks/)").option("--resume", "Resume from existing local state").option("--track", "Sync progress to a Runtype record (visible in dashboard)").option("--debug", "Show debug output from each session").option("--json", "Output final result as JSON").action(taskAction);
|
|
3436
|
+
return cmd.argument("<agent>", "Agent ID or name").requiredOption("-m, --message <text>", "Task message for the agent").option("--max-sessions <n>", "Maximum sessions", "50").option("--max-cost <n>", "Budget in USD").option("--model <modelId>", "Model ID to use (overrides agent config)").option("--name <name>", "Task name (used for state file, defaults to agent name)").option("--state-dir <path>", "Directory for state files (default: .runtype/tasks/)").option("--resume", "Resume from existing local state").option("--track", "Sync progress to a Runtype record (visible in dashboard)").option("--debug", "Show debug output from each session").option("--json", "Output final result as JSON").option("--sandbox <provider>", "Enable sandbox code execution tool (quickjs or daytona)").option("--no-local-tools", "Disable built-in local tool execution (read_file, write_file, list_directory)").action(taskAction);
|
|
3015
3437
|
}
|
|
3016
3438
|
var taskCommand = applyTaskOptions(
|
|
3017
3439
|
new import_commander11.Command("task").description("Run a multi-session agent task")
|
|
@@ -4095,10 +4517,12 @@ program.addCommand(flowVersionsCommand);
|
|
|
4095
4517
|
program.addCommand(createMarathonCommand());
|
|
4096
4518
|
program.exitOverride();
|
|
4097
4519
|
try {
|
|
4098
|
-
|
|
4520
|
+
const userArgs = process.argv.slice(2);
|
|
4521
|
+
const cleanArgs = userArgs[0] === "--" ? userArgs.slice(1) : userArgs;
|
|
4522
|
+
if (!cleanArgs.length) {
|
|
4099
4523
|
handleNoCommand();
|
|
4100
4524
|
} else {
|
|
4101
|
-
program.parse(
|
|
4525
|
+
program.parse(cleanArgs, { from: "user" });
|
|
4102
4526
|
}
|
|
4103
4527
|
} catch (error) {
|
|
4104
4528
|
const commanderError = error;
|