@runtypelabs/cli 2.18.0 → 2.19.1
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 +28 -1
- package/dist/index.js +548 -166
- package/package.json +5 -4
package/README.md
CHANGED
|
@@ -211,7 +211,7 @@ milestones:
|
|
|
211
211
|
EOF
|
|
212
212
|
```
|
|
213
213
|
|
|
214
|
-
**Search order**: Exact path → `.runtype/marathons/playbooks/<name>.yaml|yml|json` (repo) → `~/.runtype/marathons/playbooks/<name>.yaml|yml|json` (user).
|
|
214
|
+
**Search order**: Exact path → `.runtype/marathons/playbooks/<name>.yaml|yml|json|ts|mts` (repo) → `~/.runtype/marathons/playbooks/<name>.yaml|yml|json|ts|mts` (user).
|
|
215
215
|
|
|
216
216
|
**Completion criteria types**:
|
|
217
217
|
|
|
@@ -248,6 +248,33 @@ milestones:
|
|
|
248
248
|
| `requireVerification` | `boolean` | Require verification before `TASK_COMPLETE`. |
|
|
249
249
|
| `outputRoot` | `string` | For creation tasks: confine writes to this directory (e.g. `"public/"`). |
|
|
250
250
|
|
|
251
|
+
#### TypeScript playbooks
|
|
252
|
+
|
|
253
|
+
Playbooks can also be TypeScript modules (`.ts`/`.mts`), loaded at runtime via jiti — no build step or special Node version required. Every behavior slot (`instructions`, `completionCriteria`, `recovery`, `intercept`, ...) then accepts a plain function in addition to inline data and hook references:
|
|
254
|
+
|
|
255
|
+
```ts
|
|
256
|
+
// .runtype/marathons/playbooks/my-task.ts
|
|
257
|
+
import { definePlaybook, type RunTaskStateSlice } from '@runtypelabs/sdk'
|
|
258
|
+
|
|
259
|
+
export default definePlaybook({
|
|
260
|
+
name: 'my-task',
|
|
261
|
+
stallPolicy: { nudgeAfter: 1, stopAfter: 4 },
|
|
262
|
+
milestones: [
|
|
263
|
+
{
|
|
264
|
+
name: 'build',
|
|
265
|
+
instructions: (state: RunTaskStateSlice) => `Build it. Plan: ${state.planPath}`,
|
|
266
|
+
recovery: (state) =>
|
|
267
|
+
`You went ${state.consecutiveEmptySessions ?? 0} sessions without a tool call. Write a file now.`,
|
|
268
|
+
canAcceptCompletion: true,
|
|
269
|
+
},
|
|
270
|
+
],
|
|
271
|
+
})
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
`definePlaybook` (from `@runtypelabs/sdk`, install as a devDependency for editor types) is optional sugar — a plain object export with the same shape works without the package installed. To register named hooks (reusable from YAML playbooks too), export a factory instead: `export default ({ registerWorkflowHook }) => ({ ... })`. A complete example lives at [`examples/playbooks/release-notes.ts`](./examples/playbooks/release-notes.ts).
|
|
275
|
+
|
|
276
|
+
**Hook references**: any slot can reference a registered behavior by name instead of carrying data — `builtin:*` names expose the default workflow's behaviors (e.g. `instructions: builtin:research-instructions`, `completionCriteria: { type: builtin:research-complete }`), and YAML playbooks can load custom hooks from JS modules listed under `plugins:` (paths relative to the playbook file). See the comments in [`examples/playbooks/design-library.yaml`](./examples/playbooks/design-library.yaml).
|
|
277
|
+
|
|
251
278
|
#### Marathon Anatomy
|
|
252
279
|
|
|
253
280
|
```
|
package/dist/index.js
CHANGED
|
@@ -7,8 +7,13 @@ var __require = /* @__PURE__ */ ((x2) => typeof require !== "undefined" ? requir
|
|
|
7
7
|
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
8
8
|
throw Error('Dynamic require of "' + x2 + '" is not supported');
|
|
9
9
|
});
|
|
10
|
-
var __esm = (fn, res) => function __init() {
|
|
11
|
-
|
|
10
|
+
var __esm = (fn, res, err) => function __init() {
|
|
11
|
+
if (err) throw err[0];
|
|
12
|
+
try {
|
|
13
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
14
|
+
} catch (e) {
|
|
15
|
+
throw err = [e], e;
|
|
16
|
+
}
|
|
12
17
|
};
|
|
13
18
|
var __export = (target, all) => {
|
|
14
19
|
for (var name in all)
|
|
@@ -15159,7 +15164,7 @@ var apiRoutingDocSchema = external_exports.object({
|
|
|
15159
15164
|
path: ["api", "activeScript"]
|
|
15160
15165
|
});
|
|
15161
15166
|
|
|
15162
|
-
// ../shared/dist/chunk-
|
|
15167
|
+
// ../shared/dist/chunk-R66POVE6.mjs
|
|
15163
15168
|
function getNestedValue(obj, path18) {
|
|
15164
15169
|
let normalizedPath = path18;
|
|
15165
15170
|
normalizedPath = normalizedPath.replace(/^\$\.?/, "");
|
|
@@ -15195,6 +15200,55 @@ function getNestedValue(obj, path18) {
|
|
|
15195
15200
|
return current;
|
|
15196
15201
|
}
|
|
15197
15202
|
var DANGEROUS_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
|
|
15203
|
+
var SYSTEM_VARIABLES = /* @__PURE__ */ new Set([
|
|
15204
|
+
"_flow",
|
|
15205
|
+
"_user",
|
|
15206
|
+
"_execution",
|
|
15207
|
+
"_record",
|
|
15208
|
+
"_now",
|
|
15209
|
+
"_schedule",
|
|
15210
|
+
"messages",
|
|
15211
|
+
"userMessage",
|
|
15212
|
+
"lastMessage",
|
|
15213
|
+
"messageCount"
|
|
15214
|
+
]);
|
|
15215
|
+
var SECRET_REF_PATTERN = /\{\{secret:([A-Z][A-Z0-9_]*[A-Z0-9])\}\}/g;
|
|
15216
|
+
var RUNTIME_PREFIXES = {
|
|
15217
|
+
"secret:": {
|
|
15218
|
+
prefix: "secret:",
|
|
15219
|
+
namespace: "secret",
|
|
15220
|
+
resolvedBy: "the secret pre-pass (substituteSecretReferences) before the template engine runs \u2014 never the template engine itself",
|
|
15221
|
+
mayReachModelUnresolved: false
|
|
15222
|
+
},
|
|
15223
|
+
"flow:": {
|
|
15224
|
+
prefix: "flow:",
|
|
15225
|
+
namespace: "flow",
|
|
15226
|
+
resolvedBy: "the template engine, which treats it as an alias for the bare flow variable of the same name",
|
|
15227
|
+
mayReachModelUnresolved: false
|
|
15228
|
+
}
|
|
15229
|
+
};
|
|
15230
|
+
var PREFIX_PATTERN = /^([A-Za-z][A-Za-z0-9_-]*):(.*)$/s;
|
|
15231
|
+
function classifyVariableReference(token) {
|
|
15232
|
+
const trimmed = token.trim();
|
|
15233
|
+
const prefixMatch = PREFIX_PATTERN.exec(trimmed);
|
|
15234
|
+
if (prefixMatch) {
|
|
15235
|
+
const prefix = `${prefixMatch[1]}:`;
|
|
15236
|
+
const rest = prefixMatch[2] ?? "";
|
|
15237
|
+
const spec = RUNTIME_PREFIXES[prefix];
|
|
15238
|
+
if (spec) {
|
|
15239
|
+
return { namespace: spec.namespace, baseName: rest.trim() };
|
|
15240
|
+
}
|
|
15241
|
+
return { namespace: "unknown", raw: trimmed };
|
|
15242
|
+
}
|
|
15243
|
+
if (isSystemVariable(trimmed)) {
|
|
15244
|
+
return { namespace: "system", baseName: trimmed };
|
|
15245
|
+
}
|
|
15246
|
+
return { namespace: "plain", baseName: trimmed };
|
|
15247
|
+
}
|
|
15248
|
+
function isSystemVariable(varName) {
|
|
15249
|
+
const rootSegment = varName.split(".")[0] || "";
|
|
15250
|
+
return SYSTEM_VARIABLES.has(rootSegment);
|
|
15251
|
+
}
|
|
15198
15252
|
var TEMPLATE_EXPRESSION_PATTERN = /\{\{([^{}]+)\}\}/g;
|
|
15199
15253
|
function parseTemplateExpression(expr) {
|
|
15200
15254
|
const tokens = tokenizeFallbackExpression(expr);
|
|
@@ -15281,7 +15335,7 @@ function parseOperand(raw) {
|
|
|
15281
15335
|
}
|
|
15282
15336
|
function evaluateOperand(operand, context) {
|
|
15283
15337
|
if (operand.kind === "literal") return operand.value;
|
|
15284
|
-
return getNestedValue(context, operand.path);
|
|
15338
|
+
return getNestedValue(context, classifiedLookupKey(operand.path));
|
|
15285
15339
|
}
|
|
15286
15340
|
function countTrailingBackslashes(s, i) {
|
|
15287
15341
|
let n = 0;
|
|
@@ -15306,6 +15360,7 @@ var _SimpleTemplateEngine = class _SimpleTemplateEngine2 {
|
|
|
15306
15360
|
const usedVariables = [];
|
|
15307
15361
|
const usedDefaults = [];
|
|
15308
15362
|
const missingVariables = [];
|
|
15363
|
+
const unknownNamespaceVariables = [];
|
|
15309
15364
|
const result = template.replace(_SimpleTemplateEngine2.EXPRESSION_PATTERN, (match, expr) => {
|
|
15310
15365
|
let parsed;
|
|
15311
15366
|
try {
|
|
@@ -15318,12 +15373,14 @@ var _SimpleTemplateEngine = class _SimpleTemplateEngine2 {
|
|
|
15318
15373
|
usedVariables,
|
|
15319
15374
|
usedDefaults,
|
|
15320
15375
|
missingVariables,
|
|
15376
|
+
unknownNamespaceVariables,
|
|
15321
15377
|
match
|
|
15322
15378
|
});
|
|
15323
15379
|
}
|
|
15324
15380
|
return resolveFallback(parsed, context, {
|
|
15325
15381
|
usedVariables,
|
|
15326
15382
|
missingVariables,
|
|
15383
|
+
unknownNamespaceVariables,
|
|
15327
15384
|
match
|
|
15328
15385
|
});
|
|
15329
15386
|
});
|
|
@@ -15331,7 +15388,8 @@ var _SimpleTemplateEngine = class _SimpleTemplateEngine2 {
|
|
|
15331
15388
|
result,
|
|
15332
15389
|
usedVariables,
|
|
15333
15390
|
usedDefaults,
|
|
15334
|
-
missingVariables
|
|
15391
|
+
missingVariables,
|
|
15392
|
+
unknownNamespaceVariables
|
|
15335
15393
|
};
|
|
15336
15394
|
}
|
|
15337
15395
|
/**
|
|
@@ -15406,28 +15464,49 @@ var _SimpleTemplateEngine = class _SimpleTemplateEngine2 {
|
|
|
15406
15464
|
};
|
|
15407
15465
|
_SimpleTemplateEngine.EXPRESSION_PATTERN = TEMPLATE_EXPRESSION_PATTERN;
|
|
15408
15466
|
var SimpleTemplateEngine = _SimpleTemplateEngine;
|
|
15467
|
+
function classifiedLookupKey(rawKey, onUnknown) {
|
|
15468
|
+
const classification = classifyVariableReference(rawKey);
|
|
15469
|
+
if (classification.namespace === "flow") {
|
|
15470
|
+
return classification.baseName;
|
|
15471
|
+
}
|
|
15472
|
+
if (classification.namespace === "unknown") {
|
|
15473
|
+
onUnknown?.(classification.raw);
|
|
15474
|
+
return rawKey;
|
|
15475
|
+
}
|
|
15476
|
+
return rawKey;
|
|
15477
|
+
}
|
|
15409
15478
|
function resolveLegacy(parsed, context, tracking) {
|
|
15410
|
-
const
|
|
15479
|
+
const lookupKey = classifiedLookupKey(
|
|
15480
|
+
parsed.variable,
|
|
15481
|
+
(raw) => tracking.unknownNamespaceVariables.push(raw)
|
|
15482
|
+
);
|
|
15483
|
+
const value = getNestedValue(context, lookupKey);
|
|
15411
15484
|
if (value !== void 0 && value !== null) {
|
|
15412
|
-
tracking.usedVariables.push(
|
|
15485
|
+
tracking.usedVariables.push(lookupKey);
|
|
15413
15486
|
return stringifyValue(value);
|
|
15414
15487
|
}
|
|
15415
15488
|
if (parsed.defaultValue !== void 0) {
|
|
15416
15489
|
tracking.usedDefaults.push({
|
|
15417
|
-
variable:
|
|
15490
|
+
variable: lookupKey,
|
|
15418
15491
|
defaultValue: parsed.defaultValue
|
|
15419
15492
|
});
|
|
15420
15493
|
return parsed.defaultValue;
|
|
15421
15494
|
}
|
|
15422
|
-
tracking.missingVariables.push(
|
|
15495
|
+
tracking.missingVariables.push(lookupKey);
|
|
15423
15496
|
return tracking.match;
|
|
15424
15497
|
}
|
|
15425
15498
|
function resolveFallback(parsed, context, tracking) {
|
|
15426
15499
|
let chosen = null;
|
|
15427
15500
|
for (const operand of parsed.operands) {
|
|
15428
15501
|
const value = evaluateOperand(operand, context);
|
|
15429
|
-
if (operand.kind === "path"
|
|
15430
|
-
|
|
15502
|
+
if (operand.kind === "path") {
|
|
15503
|
+
const key = classifiedLookupKey(
|
|
15504
|
+
operand.path,
|
|
15505
|
+
(raw) => tracking.unknownNamespaceVariables.push(raw)
|
|
15506
|
+
);
|
|
15507
|
+
if (value !== void 0) {
|
|
15508
|
+
tracking.usedVariables.push(key);
|
|
15509
|
+
}
|
|
15431
15510
|
}
|
|
15432
15511
|
if (chosen === null && passesOperator(value, parsed.operator)) {
|
|
15433
15512
|
chosen = { value, isPath: operand.kind === "path" };
|
|
@@ -15439,13 +15518,18 @@ function resolveFallback(parsed, context, tracking) {
|
|
|
15439
15518
|
return stringifyValue(last.value);
|
|
15440
15519
|
}
|
|
15441
15520
|
for (const operand of parsed.operands) {
|
|
15442
|
-
if (operand.kind === "path")
|
|
15521
|
+
if (operand.kind === "path") {
|
|
15522
|
+
tracking.missingVariables.push(classifiedLookupKey(operand.path));
|
|
15523
|
+
}
|
|
15443
15524
|
}
|
|
15444
15525
|
return tracking.match;
|
|
15445
15526
|
}
|
|
15446
15527
|
var templateEngine = new SimpleTemplateEngine();
|
|
15447
15528
|
|
|
15448
15529
|
// ../shared/dist/index.mjs
|
|
15530
|
+
function neutralizeCsvFormula(value) {
|
|
15531
|
+
return /^[=+\-@\t\r\n]/.test(value) ? `'${value}` : value;
|
|
15532
|
+
}
|
|
15449
15533
|
var mediaAnnotationsSchema = external_exports.object({
|
|
15450
15534
|
audience: external_exports.array(external_exports.enum(["user", "assistant"])).optional()
|
|
15451
15535
|
});
|
|
@@ -30444,7 +30528,7 @@ var CORE_BUILTIN_TOOLS_REGISTRY = [
|
|
|
30444
30528
|
{
|
|
30445
30529
|
id: "publish_page",
|
|
30446
30530
|
name: "Publish Page",
|
|
30447
|
-
description: "Publish an HTML page on Runtype's CDN and get back a shareable URL that renders the page inline in the browser. Two source modes: (1) pass `url` to download an HTML file from an HTTP(S) URL, or (2) pass base64-encoded `content` (defaults to `contentType: text/html`) to upload inline HTML directly \u2014 useful when running inside a sandboxed code-execution environment with restricted outbound network. Exactly one of `url` or `content` must be provided. Served inline from a `/preview/` path under a locked-down CSP that blocks scripts, network requests, and form submissions. Page URLs are public and expire
|
|
30531
|
+
description: "Publish an HTML page on Runtype's CDN and get back a shareable URL that renders the page inline in the browser. Two source modes: (1) pass `url` to download an HTML file from an HTTP(S) URL, or (2) pass base64-encoded `content` (defaults to `contentType: text/html`) to upload inline HTML directly \u2014 useful when running inside a sandboxed code-execution environment with restricted outbound network. Exactly one of `url` or `content` must be provided. Served inline from a `/preview/` path under a locked-down CSP that blocks scripts, network requests, and form submissions. Page URLs are public and expire based on the account's plan (7 days on the default plan; longer or permanent on higher tiers \u2014 check `expiresAt` in the result). Pass `expiresInSeconds` to choose a shorter lifetime; the plan TTL is a hard ceiling. A page can be re-upped to the current plan TTL at the same URL via `POST /v1/assets/:assetId/extend`. Accepts only HTML content. 25 MB max. To host a non-HTML file, or HTML as a permanent downloadable file, use `store_asset` instead.",
|
|
30448
30532
|
category: BuiltInToolCategory.FILE_OPERATIONS,
|
|
30449
30533
|
toolGroup: BuiltInToolGroup.FILE_OUTPUTS,
|
|
30450
30534
|
providers: [BuiltInToolProvider.MULTI],
|
|
@@ -30466,6 +30550,10 @@ var CORE_BUILTIN_TOOLS_REGISTRY = [
|
|
|
30466
30550
|
filename: {
|
|
30467
30551
|
type: "string",
|
|
30468
30552
|
description: "Optional filename for the stored page"
|
|
30553
|
+
},
|
|
30554
|
+
expiresInSeconds: {
|
|
30555
|
+
type: "number",
|
|
30556
|
+
description: "Optional page lifetime in seconds (positive integer). Capped at the account plan's preview TTL \u2014 a shorter lifetime is honored, a longer one is clamped to the plan ceiling. Omit to use the plan default."
|
|
30469
30557
|
}
|
|
30470
30558
|
},
|
|
30471
30559
|
required: []
|
|
@@ -33515,7 +33603,15 @@ var userProfileFeaturesSchema = external_exports.object({
|
|
|
33515
33603
|
enableDashboardAssistant: external_exports.boolean(),
|
|
33516
33604
|
// Routed model id the dashboard assistant dispatches with. Driven by the
|
|
33517
33605
|
// `dashboard-assistant-model` string flag.
|
|
33518
|
-
dashboardAssistantModel: external_exports.string()
|
|
33606
|
+
dashboardAssistantModel: external_exports.string(),
|
|
33607
|
+
// Gates the chrome_extension surface type in the dashboard (surface picker
|
|
33608
|
+
// and downstream config/ship UI). Driven by the `CHROME_SURFACE` boolean
|
|
33609
|
+
// flag.
|
|
33610
|
+
enableChromeSurface: external_exports.boolean(),
|
|
33611
|
+
// Gates the Runtype Apps nav entry + routes in the dashboard. Driven by the
|
|
33612
|
+
// `enable-runtype-apps` boolean flag (fail-closed in production until the
|
|
33613
|
+
// prod ops set lands). The whole /v1/apps surface 404s when this is off.
|
|
33614
|
+
enableRuntypeApps: external_exports.boolean()
|
|
33519
33615
|
});
|
|
33520
33616
|
var MODEL_FAMILY_PROVIDER_IDS = {
|
|
33521
33617
|
"claude-fable-5": {
|
|
@@ -36151,7 +36247,6 @@ var agentRuntimeConfigSchema = external_exports.object({
|
|
|
36151
36247
|
// mirroring how `temporalConfigSchema` is shared.
|
|
36152
36248
|
memory: memoryConfigSchema.optional()
|
|
36153
36249
|
});
|
|
36154
|
-
var SECRET_REF_PATTERN = /\{\{secret:([A-Z][A-Z0-9_]*[A-Z0-9])\}\}/g;
|
|
36155
36250
|
function extractSecretReferences(template) {
|
|
36156
36251
|
const keys = /* @__PURE__ */ new Set();
|
|
36157
36252
|
let match;
|
|
@@ -36482,7 +36577,8 @@ var surfaceSchema = external_exports.object({
|
|
|
36482
36577
|
"messaging",
|
|
36483
36578
|
"telegram",
|
|
36484
36579
|
"a2a",
|
|
36485
|
-
"hosted-page"
|
|
36580
|
+
"hosted-page",
|
|
36581
|
+
"chrome_extension"
|
|
36486
36582
|
]),
|
|
36487
36583
|
config: external_exports.record(external_exports.string(), external_exports.any()),
|
|
36488
36584
|
createPolicy: createPolicySchema,
|
|
@@ -37946,7 +38042,8 @@ var PLATFORM_CATALOG = {
|
|
|
37946
38042
|
"whatsapp",
|
|
37947
38043
|
"messaging",
|
|
37948
38044
|
"telegram",
|
|
37949
|
-
"a2a"
|
|
38045
|
+
"a2a",
|
|
38046
|
+
"chrome_extension"
|
|
37950
38047
|
],
|
|
37951
38048
|
availableFlowPrimitives: FLOW_STEP_TYPES.map((stepType) => {
|
|
37952
38049
|
const meta3 = FLOW_STEP_TYPE_METADATA[stepType];
|
|
@@ -38336,6 +38433,37 @@ var SURFACE_TYPE_METADATA = {
|
|
|
38336
38433
|
maxResponseLength: null,
|
|
38337
38434
|
executionHint: null
|
|
38338
38435
|
}
|
|
38436
|
+
},
|
|
38437
|
+
// @snake-case-ok: surface type identifier
|
|
38438
|
+
chrome_extension: {
|
|
38439
|
+
description: "Downloadable Manifest V3 Chrome extension embedding the agent in the browser side panel, with packaged browser tools (read page, fill forms, navigate tabs) executed locally via the WebMCP client-tool loop.",
|
|
38440
|
+
useCases: [
|
|
38441
|
+
"browser copilots",
|
|
38442
|
+
"page-aware assistants",
|
|
38443
|
+
"form filling and data extraction",
|
|
38444
|
+
"internal browser tooling"
|
|
38445
|
+
],
|
|
38446
|
+
examples: [
|
|
38447
|
+
"CRM sidekick that reads and updates records on the page",
|
|
38448
|
+
"Research assistant that summarizes and compares open tabs",
|
|
38449
|
+
"Support agent that drafts replies inside a ticketing UI"
|
|
38450
|
+
],
|
|
38451
|
+
traits: {
|
|
38452
|
+
streaming: "required",
|
|
38453
|
+
messagesMutable: false,
|
|
38454
|
+
deliveryModel: "real_time",
|
|
38455
|
+
mediaSupport: "images",
|
|
38456
|
+
interactiveUI: "generative",
|
|
38457
|
+
inboundMediaSupport: true,
|
|
38458
|
+
consumerType: "human",
|
|
38459
|
+
reasoningVisibility: "pass_through",
|
|
38460
|
+
markdownDialect: "mdx",
|
|
38461
|
+
threadModel: "flat",
|
|
38462
|
+
senderIdentity: "anonymous",
|
|
38463
|
+
maxResponseLength: null,
|
|
38464
|
+
executionHint: "You are running inside a Chrome extension side panel. You may have browser tools (chrome:*) to read the current page, interact with forms, and manage tabs \u2014 use them when the user asks about or wants to act on the page they are viewing. Mutating actions (clicking, filling, navigating) ask the user for confirmation before running."
|
|
38465
|
+
},
|
|
38466
|
+
behaviorTypeRef: "runtype://types/surface-configs"
|
|
38339
38467
|
}
|
|
38340
38468
|
};
|
|
38341
38469
|
var SURFACE_TYPE_GUIDE = (() => {
|
|
@@ -41084,6 +41212,131 @@ recordsCommand.command("get <id>").description("Get record details").option("--j
|
|
|
41084
41212
|
const { waitUntilExit } = render3(React3.createElement(App));
|
|
41085
41213
|
await waitUntilExit();
|
|
41086
41214
|
});
|
|
41215
|
+
recordsCommand.command("results <id>").description("Get step-level execution results for a record").option("--flow-id <flowId>", "Filter by flow ID").option("--batch-id <batchId>", "Filter by batch ID").option("--status <status>", "Filter by status").option("--limit <n>", "Limit number of results").option("--offset <n>", "Offset for pagination").option("--json", "Output as JSON").option("--tty", "Force TTY mode").option("--no-tty", "Force non-TTY mode").action(
|
|
41216
|
+
async (id, options) => {
|
|
41217
|
+
const apiKey = await ensureAuth();
|
|
41218
|
+
if (!apiKey) return;
|
|
41219
|
+
const client = createCliClient(apiKey);
|
|
41220
|
+
const params = {
|
|
41221
|
+
...options.flowId ? { flowId: options.flowId } : {},
|
|
41222
|
+
...options.batchId ? { batchId: options.batchId } : {},
|
|
41223
|
+
...options.status ? { status: options.status } : {},
|
|
41224
|
+
...options.limit ? { limit: parseInt(options.limit, 10) } : {},
|
|
41225
|
+
...options.offset ? { offset: parseInt(options.offset, 10) } : {}
|
|
41226
|
+
};
|
|
41227
|
+
if (!isTTY(options) || options.json) {
|
|
41228
|
+
try {
|
|
41229
|
+
const data = await client.records.getStepResults(id, params);
|
|
41230
|
+
if (options.json) {
|
|
41231
|
+
printJson(data);
|
|
41232
|
+
return;
|
|
41233
|
+
}
|
|
41234
|
+
const results = data.data ?? [];
|
|
41235
|
+
if (results.length === 0) {
|
|
41236
|
+
console.log(chalk6.yellow("No step results found"));
|
|
41237
|
+
return;
|
|
41238
|
+
}
|
|
41239
|
+
for (const r of results) {
|
|
41240
|
+
console.log(
|
|
41241
|
+
` ${chalk6.green(r.id)} ${r.stepName} (${r.stepType}) ${r.status}` + (r.modelUsed ? ` ${r.modelUsed}` : "")
|
|
41242
|
+
);
|
|
41243
|
+
}
|
|
41244
|
+
} catch (error51) {
|
|
41245
|
+
const message = error51 instanceof Error ? error51.message : "Unknown error";
|
|
41246
|
+
console.error(chalk6.red(`Failed to fetch step results: ${message}`));
|
|
41247
|
+
process.exit(1);
|
|
41248
|
+
}
|
|
41249
|
+
return;
|
|
41250
|
+
}
|
|
41251
|
+
const App = () => {
|
|
41252
|
+
const [items, setItems] = useState4(null);
|
|
41253
|
+
const [error51, setError] = useState4(null);
|
|
41254
|
+
useEffect5(() => {
|
|
41255
|
+
client.records.getStepResults(id, params).then((res) => setItems(res.data ?? [])).catch((err) => setError(err instanceof Error ? err : new Error(String(err))));
|
|
41256
|
+
}, []);
|
|
41257
|
+
return React3.createElement(DataList, {
|
|
41258
|
+
title: "Step results",
|
|
41259
|
+
items,
|
|
41260
|
+
error: error51,
|
|
41261
|
+
loading: items === null && error51 === null,
|
|
41262
|
+
renderCard: (item) => {
|
|
41263
|
+
const r = item;
|
|
41264
|
+
return React3.createElement(EntityCard, {
|
|
41265
|
+
fields: [
|
|
41266
|
+
{ label: "ID", value: r.id, color: "green" },
|
|
41267
|
+
{ label: "Step", value: `${r.stepName} (${r.stepType})` },
|
|
41268
|
+
{ label: "Status", value: r.status },
|
|
41269
|
+
{ label: "Model", value: r.modelUsed ?? null },
|
|
41270
|
+
{
|
|
41271
|
+
label: "Duration",
|
|
41272
|
+
value: r.durationMs !== null ? `${r.durationMs}ms` : null
|
|
41273
|
+
}
|
|
41274
|
+
]
|
|
41275
|
+
});
|
|
41276
|
+
}
|
|
41277
|
+
});
|
|
41278
|
+
};
|
|
41279
|
+
const { waitUntilExit } = render3(React3.createElement(App));
|
|
41280
|
+
await waitUntilExit();
|
|
41281
|
+
}
|
|
41282
|
+
);
|
|
41283
|
+
recordsCommand.command("costs <id>").description("Get aggregated cost breakdown for a record").option("--json", "Output as JSON").option("--tty", "Force TTY mode").option("--no-tty", "Force non-TTY mode").action(async (id, options) => {
|
|
41284
|
+
const apiKey = await ensureAuth();
|
|
41285
|
+
if (!apiKey) return;
|
|
41286
|
+
const client = createCliClient(apiKey);
|
|
41287
|
+
if (!isTTY(options) || options.json) {
|
|
41288
|
+
try {
|
|
41289
|
+
const data = await client.records.getCosts(id);
|
|
41290
|
+
if (options.json) {
|
|
41291
|
+
printJson(data);
|
|
41292
|
+
return;
|
|
41293
|
+
}
|
|
41294
|
+
console.log(` Total cost: $${data.totalCost}`);
|
|
41295
|
+
console.log(` Total tokens: ${data.totalTokens}`);
|
|
41296
|
+
console.log(` Executions: ${data.executionCount}`);
|
|
41297
|
+
if (data.modelBreakdown.length > 0) {
|
|
41298
|
+
console.log(" By model:");
|
|
41299
|
+
for (const m2 of data.modelBreakdown) {
|
|
41300
|
+
console.log(` ${m2.model}: $${m2.cost} ${m2.tokens} tokens ${m2.count} calls`);
|
|
41301
|
+
}
|
|
41302
|
+
}
|
|
41303
|
+
} catch (error51) {
|
|
41304
|
+
const message = error51 instanceof Error ? error51.message : "Unknown error";
|
|
41305
|
+
console.error(chalk6.red(`Failed to fetch record costs: ${message}`));
|
|
41306
|
+
process.exit(1);
|
|
41307
|
+
}
|
|
41308
|
+
return;
|
|
41309
|
+
}
|
|
41310
|
+
const App = () => {
|
|
41311
|
+
const [items, setItems] = useState4(null);
|
|
41312
|
+
const [error51, setError] = useState4(null);
|
|
41313
|
+
useEffect5(() => {
|
|
41314
|
+
client.records.getCosts(id).then((res) => setItems([res])).catch((err) => setError(err instanceof Error ? err : new Error(String(err))));
|
|
41315
|
+
}, []);
|
|
41316
|
+
return React3.createElement(DataList, {
|
|
41317
|
+
title: "Record costs",
|
|
41318
|
+
items,
|
|
41319
|
+
error: error51,
|
|
41320
|
+
loading: items === null && error51 === null,
|
|
41321
|
+
renderCard: (item) => {
|
|
41322
|
+
const c2 = item;
|
|
41323
|
+
return React3.createElement(EntityCard, {
|
|
41324
|
+
fields: [
|
|
41325
|
+
{ label: "Total cost", value: `$${c2.totalCost}`, color: "green" },
|
|
41326
|
+
{ label: "Total tokens", value: String(c2.totalTokens) },
|
|
41327
|
+
{ label: "Executions", value: String(c2.executionCount) },
|
|
41328
|
+
{
|
|
41329
|
+
label: "Models",
|
|
41330
|
+
value: c2.modelBreakdown.map((m2) => `${m2.model} ($${m2.cost})`).join(", ") || null
|
|
41331
|
+
}
|
|
41332
|
+
]
|
|
41333
|
+
});
|
|
41334
|
+
}
|
|
41335
|
+
});
|
|
41336
|
+
};
|
|
41337
|
+
const { waitUntilExit } = render3(React3.createElement(App));
|
|
41338
|
+
await waitUntilExit();
|
|
41339
|
+
});
|
|
41087
41340
|
recordsCommand.command("create").description("Create a new record").requiredOption("-n, --name <name>", "Record name").requiredOption("-t, --type <type>", "Record type").option("-m, --metadata <json>", "Metadata as JSON string").option("--json", "Output as JSON").option("--tty", "Force TTY mode").option("--no-tty", "Force non-TTY mode").action(
|
|
41088
41341
|
async (options) => {
|
|
41089
41342
|
const apiKey = await ensureAuth();
|
|
@@ -41491,10 +41744,11 @@ recordsCommand.command("export").description("Export records to a file").option(
|
|
|
41491
41744
|
}
|
|
41492
41745
|
});
|
|
41493
41746
|
function csvEscape(value) {
|
|
41494
|
-
|
|
41495
|
-
|
|
41747
|
+
const text = neutralizeCsvFormula(value);
|
|
41748
|
+
if (text.includes(",") || text.includes('"') || text.includes("\n")) {
|
|
41749
|
+
return `"${text.replace(/"/g, '""')}"`;
|
|
41496
41750
|
}
|
|
41497
|
-
return
|
|
41751
|
+
return text;
|
|
41498
41752
|
}
|
|
41499
41753
|
|
|
41500
41754
|
// src/commands/prompts.ts
|
|
@@ -48861,29 +49115,40 @@ function primeTreeLogSyncFromState(stateFilePath2, log, state) {
|
|
|
48861
49115
|
lastCheckpointJson: JSON.stringify(toCheckpoint(state))
|
|
48862
49116
|
});
|
|
48863
49117
|
}
|
|
49118
|
+
function ensureTreeLogSync(stateFilePath2, seed) {
|
|
49119
|
+
const logPath = treeLogPathForStateFile(stateFilePath2);
|
|
49120
|
+
let sync = syncStates.get(stateFilePath2);
|
|
49121
|
+
if (!sync || sync.log.filePath !== logPath) {
|
|
49122
|
+
const existing = loadTreeLog(logPath);
|
|
49123
|
+
if (existing) {
|
|
49124
|
+
const materialized = materializeAtHead(existing);
|
|
49125
|
+
sync = {
|
|
49126
|
+
log: existing,
|
|
49127
|
+
lastMessages: materialized?.messages ?? [],
|
|
49128
|
+
lastCheckpointJson: JSON.stringify(materialized?.state ?? null)
|
|
49129
|
+
};
|
|
49130
|
+
} else {
|
|
49131
|
+
const log = createTreeLog(logPath, {
|
|
49132
|
+
taskName: seed.taskName,
|
|
49133
|
+
agentId: seed.agentId,
|
|
49134
|
+
...seed.originalMessage ? { originalMessage: seed.originalMessage } : {}
|
|
49135
|
+
});
|
|
49136
|
+
sync = { log, lastMessages: [], lastCheckpointJson: "null" };
|
|
49137
|
+
}
|
|
49138
|
+
syncStates.set(stateFilePath2, sync);
|
|
49139
|
+
}
|
|
49140
|
+
return sync;
|
|
49141
|
+
}
|
|
49142
|
+
function getOrLoadTreeLogSync(stateFilePath2, seed) {
|
|
49143
|
+
return ensureTreeLogSync(stateFilePath2, seed).log;
|
|
49144
|
+
}
|
|
48864
49145
|
function syncTreeLogWithState(stateFilePath2, state) {
|
|
48865
49146
|
try {
|
|
48866
|
-
const
|
|
48867
|
-
|
|
48868
|
-
|
|
48869
|
-
|
|
48870
|
-
|
|
48871
|
-
const materialized = materializeAtHead(existing);
|
|
48872
|
-
sync = {
|
|
48873
|
-
log: existing,
|
|
48874
|
-
lastMessages: materialized?.messages ?? [],
|
|
48875
|
-
lastCheckpointJson: JSON.stringify(materialized?.state ?? null)
|
|
48876
|
-
};
|
|
48877
|
-
} else {
|
|
48878
|
-
const log = createTreeLog(logPath, {
|
|
48879
|
-
taskName: state.taskName,
|
|
48880
|
-
agentId: state.agentId,
|
|
48881
|
-
...state.originalMessage ? { originalMessage: state.originalMessage } : {}
|
|
48882
|
-
});
|
|
48883
|
-
sync = { log, lastMessages: [], lastCheckpointJson: "null" };
|
|
48884
|
-
}
|
|
48885
|
-
syncStates.set(stateFilePath2, sync);
|
|
48886
|
-
}
|
|
49147
|
+
const sync = ensureTreeLogSync(stateFilePath2, {
|
|
49148
|
+
taskName: state.taskName,
|
|
49149
|
+
agentId: state.agentId,
|
|
49150
|
+
...state.originalMessage ? { originalMessage: state.originalMessage } : {}
|
|
49151
|
+
});
|
|
48887
49152
|
const nextMessages = state.messages ?? sync.lastMessages;
|
|
48888
49153
|
const messagesDelta = computeMessagesDelta(sync.lastMessages, nextMessages);
|
|
48889
49154
|
const checkpoint = toCheckpoint(state);
|
|
@@ -55430,9 +55695,8 @@ function stateFilePathForTask(taskName, stateDir) {
|
|
|
55430
55695
|
}
|
|
55431
55696
|
function recordOffloadedArtifact(details) {
|
|
55432
55697
|
const stateFilePath2 = details.options.ledger?.stateFilePath || stateFilePathForTask(details.taskName, details.stateDir);
|
|
55433
|
-
const logPath = treeLogPathForStateFile(stateFilePath2);
|
|
55434
55698
|
try {
|
|
55435
|
-
const log =
|
|
55699
|
+
const log = getOrLoadTreeLogSync(stateFilePath2, {
|
|
55436
55700
|
taskName: details.taskName,
|
|
55437
55701
|
agentId: details.options.ledger?.agentId || "unknown",
|
|
55438
55702
|
...details.options.ledger?.originalMessage ? { originalMessage: details.options.ledger.originalMessage } : {}
|
|
@@ -55751,14 +56015,17 @@ function resolveErrorHandlingForPhase(phase, cliFallbackModel, milestoneFallback
|
|
|
55751
56015
|
import * as fs14 from "fs";
|
|
55752
56016
|
import * as path15 from "path";
|
|
55753
56017
|
import * as os5 from "os";
|
|
56018
|
+
import { pathToFileURL } from "url";
|
|
56019
|
+
import { createJiti } from "jiti";
|
|
55754
56020
|
import micromatch from "micromatch";
|
|
55755
56021
|
import { parse as parseYaml } from "yaml";
|
|
55756
|
-
|
|
55757
|
-
|
|
55758
|
-
|
|
55759
|
-
|
|
55760
|
-
|
|
55761
|
-
|
|
56022
|
+
import {
|
|
56023
|
+
DEFAULT_STALL_STOP_AFTER,
|
|
56024
|
+
compileWorkflowConfig,
|
|
56025
|
+
ensureDefaultWorkflowHooks,
|
|
56026
|
+
isWorkflowHookRef,
|
|
56027
|
+
registerWorkflowHook
|
|
56028
|
+
} from "@runtypelabs/sdk";
|
|
55762
56029
|
var PLAYBOOKS_DIR = ".runtype/marathons/playbooks";
|
|
55763
56030
|
function getCandidatePaths(nameOrPath, cwd) {
|
|
55764
56031
|
const home = os5.homedir();
|
|
@@ -55769,12 +56036,43 @@ function getCandidatePaths(nameOrPath, cwd) {
|
|
|
55769
56036
|
path15.resolve(cwd, PLAYBOOKS_DIR, `${nameOrPath}.yaml`),
|
|
55770
56037
|
path15.resolve(cwd, PLAYBOOKS_DIR, `${nameOrPath}.yml`),
|
|
55771
56038
|
path15.resolve(cwd, PLAYBOOKS_DIR, `${nameOrPath}.json`),
|
|
56039
|
+
path15.resolve(cwd, PLAYBOOKS_DIR, `${nameOrPath}.ts`),
|
|
56040
|
+
path15.resolve(cwd, PLAYBOOKS_DIR, `${nameOrPath}.mts`),
|
|
55772
56041
|
// User-level
|
|
55773
56042
|
path15.resolve(home, PLAYBOOKS_DIR, `${nameOrPath}.yaml`),
|
|
55774
56043
|
path15.resolve(home, PLAYBOOKS_DIR, `${nameOrPath}.yml`),
|
|
55775
|
-
path15.resolve(home, PLAYBOOKS_DIR, `${nameOrPath}.json`)
|
|
56044
|
+
path15.resolve(home, PLAYBOOKS_DIR, `${nameOrPath}.json`),
|
|
56045
|
+
path15.resolve(home, PLAYBOOKS_DIR, `${nameOrPath}.ts`),
|
|
56046
|
+
path15.resolve(home, PLAYBOOKS_DIR, `${nameOrPath}.mts`)
|
|
55776
56047
|
];
|
|
55777
56048
|
}
|
|
56049
|
+
var MODULE_PLAYBOOK_EXTENSIONS = /* @__PURE__ */ new Set([".ts", ".mts"]);
|
|
56050
|
+
var jitiLoader;
|
|
56051
|
+
async function loadModulePlaybook(filePath) {
|
|
56052
|
+
jitiLoader ??= createJiti(import.meta.url, { interopDefault: false });
|
|
56053
|
+
let mod;
|
|
56054
|
+
try {
|
|
56055
|
+
mod = await jitiLoader.import(filePath);
|
|
56056
|
+
} catch (error51) {
|
|
56057
|
+
const message = error51 instanceof Error ? error51.message : String(error51);
|
|
56058
|
+
throw new Error(`Failed to load TypeScript playbook at ${filePath}: ${message}`, {
|
|
56059
|
+
cause: error51
|
|
56060
|
+
});
|
|
56061
|
+
}
|
|
56062
|
+
const exported = mod.default;
|
|
56063
|
+
if (exported === void 0 || exported === null) {
|
|
56064
|
+
throw new Error(
|
|
56065
|
+
`TypeScript playbook at ${filePath} must have a default export: a playbook config object, or a factory function receiving { registerWorkflowHook }. Wrap it in definePlaybook(...) from @runtypelabs/sdk for type inference.`
|
|
56066
|
+
);
|
|
56067
|
+
}
|
|
56068
|
+
const config3 = typeof exported === "function" ? await exported({ registerWorkflowHook }) : exported;
|
|
56069
|
+
if (!config3 || typeof config3 !== "object" || Array.isArray(config3)) {
|
|
56070
|
+
throw new Error(
|
|
56071
|
+
`TypeScript playbook at ${filePath} did not produce a playbook config object.`
|
|
56072
|
+
);
|
|
56073
|
+
}
|
|
56074
|
+
return config3;
|
|
56075
|
+
}
|
|
55778
56076
|
function parsePlaybookFile(filePath) {
|
|
55779
56077
|
const raw = fs14.readFileSync(filePath, "utf-8");
|
|
55780
56078
|
const ext = path15.extname(filePath).toLowerCase();
|
|
@@ -55783,6 +56081,12 @@ function parsePlaybookFile(filePath) {
|
|
|
55783
56081
|
}
|
|
55784
56082
|
return parseYaml(raw);
|
|
55785
56083
|
}
|
|
56084
|
+
function assertPositiveInteger(value, label, playbookName) {
|
|
56085
|
+
if (value === void 0) return;
|
|
56086
|
+
if (typeof value !== "number" || !Number.isInteger(value) || value < 1) {
|
|
56087
|
+
throw new Error(`Playbook '${playbookName}': ${label} must be a positive integer`);
|
|
56088
|
+
}
|
|
56089
|
+
}
|
|
55786
56090
|
function validatePlaybook(config3, filePath) {
|
|
55787
56091
|
if (!config3.name) {
|
|
55788
56092
|
throw new Error(`Playbook at ${filePath} is missing required 'name' field`);
|
|
@@ -55797,131 +56101,140 @@ function validatePlaybook(config3, filePath) {
|
|
|
55797
56101
|
if (!milestone.instructions) {
|
|
55798
56102
|
throw new Error(`Playbook '${config3.name}': milestone '${milestone.name}' is missing 'instructions'`);
|
|
55799
56103
|
}
|
|
56104
|
+
if (milestone.recovery !== void 0 && typeof milestone.recovery !== "function" && !isWorkflowHookRef(milestone.recovery)) {
|
|
56105
|
+
const recovery = milestone.recovery;
|
|
56106
|
+
if (typeof recovery.message !== "string" || !recovery.message.trim()) {
|
|
56107
|
+
throw new Error(
|
|
56108
|
+
`Playbook '${config3.name}': milestone '${milestone.name}' recovery is missing 'message'`
|
|
56109
|
+
);
|
|
56110
|
+
}
|
|
56111
|
+
assertPositiveInteger(
|
|
56112
|
+
recovery.afterEmptySessions,
|
|
56113
|
+
`milestone '${milestone.name}' recovery.afterEmptySessions`,
|
|
56114
|
+
config3.name
|
|
56115
|
+
);
|
|
56116
|
+
}
|
|
55800
56117
|
}
|
|
55801
|
-
|
|
55802
|
-
|
|
55803
|
-
|
|
55804
|
-
|
|
55805
|
-
|
|
55806
|
-
|
|
55807
|
-
|
|
55808
|
-
|
|
55809
|
-
|
|
55810
|
-
if (
|
|
55811
|
-
|
|
55812
|
-
|
|
55813
|
-
|
|
55814
|
-
|
|
55815
|
-
|
|
55816
|
-
|
|
55817
|
-
|
|
55818
|
-
let baselineSessionCount;
|
|
55819
|
-
return (ctx) => {
|
|
55820
|
-
const minSessions = criteria.minSessions ?? 1;
|
|
55821
|
-
if (baselineSessionCount === void 0) {
|
|
55822
|
-
baselineSessionCount = ctx.state.sessions.length;
|
|
55823
|
-
}
|
|
55824
|
-
return ctx.state.sessions.length - baselineSessionCount >= minSessions;
|
|
55825
|
-
};
|
|
56118
|
+
if (config3.stallPolicy) {
|
|
56119
|
+
assertPositiveInteger(config3.stallPolicy.nudgeAfter, "stallPolicy.nudgeAfter", config3.name);
|
|
56120
|
+
assertPositiveInteger(
|
|
56121
|
+
config3.stallPolicy.escalateModelAfter,
|
|
56122
|
+
"stallPolicy.escalateModelAfter",
|
|
56123
|
+
config3.name
|
|
56124
|
+
);
|
|
56125
|
+
assertPositiveInteger(config3.stallPolicy.stopAfter, "stallPolicy.stopAfter", config3.name);
|
|
56126
|
+
}
|
|
56127
|
+
if (config3.plugins !== void 0) {
|
|
56128
|
+
if (!Array.isArray(config3.plugins)) {
|
|
56129
|
+
throw new Error(`Playbook '${config3.name}': 'plugins' must be a list of relative module paths`);
|
|
56130
|
+
}
|
|
56131
|
+
for (const plugin of config3.plugins) {
|
|
56132
|
+
if (typeof plugin !== "string" || !plugin.trim()) {
|
|
56133
|
+
throw new Error(`Playbook '${config3.name}': each plugins entry must be a relative module path`);
|
|
56134
|
+
}
|
|
55826
56135
|
}
|
|
55827
|
-
case "planWritten":
|
|
55828
|
-
return (ctx) => {
|
|
55829
|
-
return ctx.trace.planWritten;
|
|
55830
|
-
};
|
|
55831
|
-
case "never":
|
|
55832
|
-
default:
|
|
55833
|
-
return () => false;
|
|
55834
56136
|
}
|
|
55835
56137
|
}
|
|
55836
|
-
function
|
|
55837
|
-
|
|
55838
|
-
|
|
55839
|
-
|
|
55840
|
-
const blockedSet = new Set(
|
|
55841
|
-
(policy.blockedTools ?? []).map((t) => t.trim()).filter(Boolean)
|
|
56138
|
+
function collectPlaybookWarnings(config3) {
|
|
56139
|
+
const warnings = [];
|
|
56140
|
+
const anyCompletable = config3.milestones.some(
|
|
56141
|
+
(m2) => m2.canAcceptCompletion === true || typeof m2.canAcceptCompletion === "function" || isWorkflowHookRef(m2.canAcceptCompletion)
|
|
55842
56142
|
);
|
|
55843
|
-
|
|
55844
|
-
|
|
55845
|
-
|
|
55846
|
-
|
|
55847
|
-
|
|
55848
|
-
|
|
55849
|
-
|
|
55850
|
-
|
|
55851
|
-
|
|
55852
|
-
|
|
55853
|
-
|
|
55854
|
-
|
|
55855
|
-
const isRead = toolName === "read_file";
|
|
55856
|
-
if (isRead && readGlobs.length > 0) {
|
|
55857
|
-
const allowed = micromatch.some(pathArg, readGlobs, { dot: true });
|
|
55858
|
-
if (!allowed) {
|
|
55859
|
-
return `Blocked by playbook policy: ${toolName} path "${pathArg}" is outside allowed read globs: ${readGlobs.join(", ")}`;
|
|
55860
|
-
}
|
|
55861
|
-
}
|
|
55862
|
-
if (isWrite && writeGlobs.length > 0) {
|
|
55863
|
-
const planPath = ctx.state.planPath ? ctx.normalizePath(ctx.state.planPath) : void 0;
|
|
55864
|
-
if (planPath && pathArg === planPath) {
|
|
55865
|
-
} else {
|
|
55866
|
-
const allowed = micromatch.some(pathArg, writeGlobs, { dot: true });
|
|
55867
|
-
if (!allowed) {
|
|
55868
|
-
return `Blocked by playbook policy: ${toolName} path "${pathArg}" is outside allowed write globs: ${writeGlobs.join(", ")}`;
|
|
55869
|
-
}
|
|
55870
|
-
}
|
|
55871
|
-
}
|
|
55872
|
-
if (isWrite && policy.requirePlanBeforeWrite && !ctx.state.planWritten && !ctx.trace.planWritten) {
|
|
55873
|
-
const planPath = ctx.state.planPath ? ctx.normalizePath(ctx.state.planPath) : void 0;
|
|
55874
|
-
if (!planPath || pathArg !== planPath) {
|
|
55875
|
-
return `Blocked by playbook policy: write the plan before creating other files.`;
|
|
55876
|
-
}
|
|
55877
|
-
}
|
|
56143
|
+
if (!anyCompletable) {
|
|
56144
|
+
warnings.push(
|
|
56145
|
+
`Playbook '${config3.name}': no milestone sets canAcceptCompletion: true \u2014 TASK_COMPLETE will never be accepted and the run can only end by stalling or exhausting its budget. Set it on the final milestone.`
|
|
56146
|
+
);
|
|
56147
|
+
}
|
|
56148
|
+
const escalateAfter = config3.stallPolicy?.escalateModelAfter;
|
|
56149
|
+
if (escalateAfter !== void 0) {
|
|
56150
|
+
const anyFallbacks = config3.milestones.some((m2) => m2.fallbackModels?.length);
|
|
56151
|
+
if (!anyFallbacks) {
|
|
56152
|
+
warnings.push(
|
|
56153
|
+
`Playbook '${config3.name}': stallPolicy.escalateModelAfter is set but no milestone defines fallbackModels \u2014 the escalation signal will have no model to switch to.`
|
|
56154
|
+
);
|
|
55878
56155
|
}
|
|
55879
|
-
|
|
55880
|
-
|
|
56156
|
+
const stopAfter = config3.stallPolicy?.stopAfter ?? DEFAULT_STALL_STOP_AFTER;
|
|
56157
|
+
if (escalateAfter >= stopAfter) {
|
|
56158
|
+
warnings.push(
|
|
56159
|
+
`Playbook '${config3.name}': stallPolicy.escalateModelAfter (${escalateAfter}) is not below stopAfter (${stopAfter}) \u2014 the run will stall before model escalation can fire.`
|
|
56160
|
+
);
|
|
56161
|
+
}
|
|
56162
|
+
}
|
|
56163
|
+
return warnings;
|
|
55881
56164
|
}
|
|
55882
|
-
|
|
55883
|
-
|
|
55884
|
-
|
|
56165
|
+
var PLUGIN_EXTENSIONS = /* @__PURE__ */ new Set([".js", ".mjs", ".cjs"]);
|
|
56166
|
+
async function loadPlaybookPlugins(plugins, playbookFilePath, playbookName) {
|
|
56167
|
+
if (!plugins?.length) return;
|
|
56168
|
+
const baseDir = path15.dirname(playbookFilePath);
|
|
56169
|
+
for (const plugin of plugins) {
|
|
56170
|
+
if (path15.isAbsolute(plugin)) {
|
|
56171
|
+
throw new Error(
|
|
56172
|
+
`Playbook '${playbookName}': plugin "${plugin}" must be a relative path (resolved against the playbook's directory).`
|
|
56173
|
+
);
|
|
56174
|
+
}
|
|
56175
|
+
const resolved = path15.resolve(baseDir, plugin);
|
|
56176
|
+
if (resolved !== baseDir && !resolved.startsWith(baseDir + path15.sep)) {
|
|
56177
|
+
throw new Error(
|
|
56178
|
+
`Playbook '${playbookName}': plugin "${plugin}" resolves outside the playbook's directory. Keep plugin modules next to the playbook.`
|
|
56179
|
+
);
|
|
56180
|
+
}
|
|
56181
|
+
if (!PLUGIN_EXTENSIONS.has(path15.extname(resolved).toLowerCase())) {
|
|
56182
|
+
throw new Error(
|
|
56183
|
+
`Playbook '${playbookName}': plugin "${plugin}" must be a .js, .mjs, or .cjs module.`
|
|
56184
|
+
);
|
|
56185
|
+
}
|
|
56186
|
+
if (!fs14.existsSync(resolved)) {
|
|
56187
|
+
throw new Error(`Playbook '${playbookName}': plugin "${plugin}" not found at ${resolved}.`);
|
|
56188
|
+
}
|
|
56189
|
+
const mod = await import(pathToFileURL(resolved).href);
|
|
56190
|
+
if (typeof mod.default !== "function") {
|
|
56191
|
+
throw new Error(
|
|
56192
|
+
`Playbook '${playbookName}': plugin "${plugin}" must export a default function: export default ({ registerWorkflowHook }) => { ... }`
|
|
56193
|
+
);
|
|
56194
|
+
}
|
|
56195
|
+
await mod.default({ registerWorkflowHook });
|
|
56196
|
+
}
|
|
56197
|
+
}
|
|
56198
|
+
function toWorkflowConfig(config3) {
|
|
56199
|
+
const milestones = config3.milestones.map((milestone) => ({
|
|
55885
56200
|
name: milestone.name,
|
|
55886
|
-
description: milestone.description,
|
|
55887
|
-
|
|
55888
|
-
|
|
55889
|
-
|
|
55890
|
-
|
|
55891
|
-
|
|
55892
|
-
|
|
55893
|
-
|
|
55894
|
-
|
|
55895
|
-
|
|
55896
|
-
|
|
55897
|
-
|
|
55898
|
-
isComplete: buildIsComplete(milestone.completionCriteria),
|
|
55899
|
-
interceptToolCall: policyIntercept,
|
|
55900
|
-
// Default to rejecting TASK_COMPLETE unless the playbook explicitly allows it.
|
|
55901
|
-
// The SDK accepts completion by default when canAcceptCompletion is undefined,
|
|
55902
|
-
// which would let the model end the marathon prematurely in early phases.
|
|
55903
|
-
canAcceptCompletion: milestone.canAcceptCompletion !== void 0 ? () => milestone.canAcceptCompletion : () => false
|
|
56201
|
+
...milestone.description !== void 0 ? { description: milestone.description } : {},
|
|
56202
|
+
instructions: milestone.instructions,
|
|
56203
|
+
...milestone.toolGuidance !== void 0 ? { toolGuidance: milestone.toolGuidance } : {},
|
|
56204
|
+
...milestone.completionCriteria ? { completionCriteria: milestone.completionCriteria } : {},
|
|
56205
|
+
...milestone.recovery !== void 0 ? { recovery: milestone.recovery } : {},
|
|
56206
|
+
...milestone.transitionSummary !== void 0 ? { transitionSummary: milestone.transitionSummary } : {},
|
|
56207
|
+
...milestone.intercept ? { intercept: milestone.intercept } : {},
|
|
56208
|
+
...milestone.forceEndTurn ? { forceEndTurn: milestone.forceEndTurn } : {},
|
|
56209
|
+
// Playbooks reject TASK_COMPLETE unless explicitly allowed — the SDK
|
|
56210
|
+
// accepts completion when the slot is absent, which would let the model
|
|
56211
|
+
// end the marathon prematurely in early milestones.
|
|
56212
|
+
canAcceptCompletion: milestone.canAcceptCompletion ?? false
|
|
55904
56213
|
}));
|
|
55905
56214
|
return {
|
|
55906
56215
|
name: config3.name,
|
|
55907
|
-
|
|
55908
|
-
|
|
55909
|
-
}
|
|
55910
|
-
|
|
55911
|
-
|
|
55912
|
-
|
|
55913
|
-
|
|
55914
|
-
...input.temperature !== void 0 ? { temperature: input.temperature } : {},
|
|
55915
|
-
...input.maxTokens !== void 0 ? { maxTokens: input.maxTokens } : {}
|
|
56216
|
+
...config3.description !== void 0 ? { description: config3.description } : {},
|
|
56217
|
+
...config3.stallPolicy ? { stallPolicy: config3.stallPolicy } : {},
|
|
56218
|
+
...config3.policy ? { policy: config3.policy } : {},
|
|
56219
|
+
...config3.classifyVariant ? { classifyVariant: config3.classifyVariant } : {},
|
|
56220
|
+
...config3.bootstrap ? { bootstrap: config3.bootstrap } : {},
|
|
56221
|
+
...config3.candidateBlock ? { candidateBlock: config3.candidateBlock } : {},
|
|
56222
|
+
milestones
|
|
55916
56223
|
};
|
|
55917
56224
|
}
|
|
55918
|
-
function loadPlaybook(nameOrPath, cwd) {
|
|
56225
|
+
async function loadPlaybook(nameOrPath, cwd) {
|
|
55919
56226
|
const baseCwd = cwd || process.cwd();
|
|
55920
56227
|
const candidates = getCandidatePaths(nameOrPath, baseCwd);
|
|
55921
56228
|
for (const candidate of candidates) {
|
|
55922
56229
|
if (!fs14.existsSync(candidate) || fs14.statSync(candidate).isDirectory()) continue;
|
|
55923
|
-
const
|
|
56230
|
+
const ext = path15.extname(candidate).toLowerCase();
|
|
56231
|
+
const config3 = MODULE_PLAYBOOK_EXTENSIONS.has(ext) ? await loadModulePlaybook(candidate) : parsePlaybookFile(candidate);
|
|
55924
56232
|
validatePlaybook(config3, candidate);
|
|
56233
|
+
await loadPlaybookPlugins(config3.plugins, candidate, config3.name);
|
|
56234
|
+
ensureDefaultWorkflowHooks();
|
|
56235
|
+
const workflow = compileWorkflowConfig(toWorkflowConfig(config3), {
|
|
56236
|
+
matchPathGlobs: (filePath, globs) => micromatch.some(filePath, globs, { dot: true })
|
|
56237
|
+
});
|
|
55925
56238
|
const milestoneModels = {};
|
|
55926
56239
|
const milestoneFallbackModels = {};
|
|
55927
56240
|
for (const m2 of config3.milestones) {
|
|
@@ -55931,13 +56244,14 @@ function loadPlaybook(nameOrPath, cwd) {
|
|
|
55931
56244
|
}
|
|
55932
56245
|
}
|
|
55933
56246
|
return {
|
|
55934
|
-
workflow
|
|
56247
|
+
workflow,
|
|
55935
56248
|
milestones: config3.milestones.map((m2) => m2.name),
|
|
55936
56249
|
milestoneModels: Object.keys(milestoneModels).length > 0 ? milestoneModels : void 0,
|
|
55937
56250
|
milestoneFallbackModels: Object.keys(milestoneFallbackModels).length > 0 ? milestoneFallbackModels : void 0,
|
|
55938
56251
|
verification: config3.verification,
|
|
55939
56252
|
rules: config3.rules,
|
|
55940
|
-
policy: config3.policy
|
|
56253
|
+
policy: config3.policy,
|
|
56254
|
+
warnings: collectPlaybookWarnings(config3)
|
|
55941
56255
|
};
|
|
55942
56256
|
}
|
|
55943
56257
|
throw new Error(
|
|
@@ -55945,6 +56259,14 @@ function loadPlaybook(nameOrPath, cwd) {
|
|
|
55945
56259
|
${candidates.map((c2) => ` ${c2}`).join("\n")}`
|
|
55946
56260
|
);
|
|
55947
56261
|
}
|
|
56262
|
+
function normalizeFallbackModel(input) {
|
|
56263
|
+
if (typeof input === "string") return { model: input };
|
|
56264
|
+
return {
|
|
56265
|
+
model: input.model,
|
|
56266
|
+
...input.temperature !== void 0 ? { temperature: input.temperature } : {},
|
|
56267
|
+
...input.maxTokens !== void 0 ? { maxTokens: input.maxTokens } : {}
|
|
56268
|
+
};
|
|
56269
|
+
}
|
|
55948
56270
|
|
|
55949
56271
|
// src/commands/agents-task.ts
|
|
55950
56272
|
function shouldRequestResumeCheckpoint(status, resumeMessage, noCheckpoint, originalMessage, continuations) {
|
|
@@ -56485,12 +56807,19 @@ async function taskAction(agent, options) {
|
|
|
56485
56807
|
let playbookMilestoneFallbackModels;
|
|
56486
56808
|
let playbookPolicy;
|
|
56487
56809
|
if (options.playbook) {
|
|
56488
|
-
const result = loadPlaybook(options.playbook);
|
|
56810
|
+
const result = await loadPlaybook(options.playbook);
|
|
56489
56811
|
playbookWorkflow = result.workflow;
|
|
56490
56812
|
playbookMilestones = result.milestones;
|
|
56491
56813
|
playbookMilestoneModels = result.milestoneModels;
|
|
56492
56814
|
playbookMilestoneFallbackModels = result.milestoneFallbackModels;
|
|
56493
56815
|
playbookPolicy = result.policy;
|
|
56816
|
+
for (const warning of result.warnings) {
|
|
56817
|
+
if (useStartupShell) {
|
|
56818
|
+
setStartupStatus(`playbook warning: ${warning}`);
|
|
56819
|
+
} else {
|
|
56820
|
+
console.log(chalk23.yellow(`Playbook warning: ${warning}`));
|
|
56821
|
+
}
|
|
56822
|
+
}
|
|
56494
56823
|
} else {
|
|
56495
56824
|
playbookPolicy = void 0;
|
|
56496
56825
|
}
|
|
@@ -56696,6 +57025,30 @@ ${rulesContext}`;
|
|
|
56696
57025
|
return tools;
|
|
56697
57026
|
};
|
|
56698
57027
|
localTools = applyOffloadWrapping(localTools);
|
|
57028
|
+
const ledgerOffloadRecorder = offloadOptions ? (details) => {
|
|
57029
|
+
const result = offloadToolOutput(
|
|
57030
|
+
taskName,
|
|
57031
|
+
details.toolName,
|
|
57032
|
+
details.content,
|
|
57033
|
+
{
|
|
57034
|
+
...offloadOptions,
|
|
57035
|
+
threshold: 0,
|
|
57036
|
+
ledger: { stateFilePath: filePath, agentId, originalMessage: baseMessage },
|
|
57037
|
+
onEvent: (event) => {
|
|
57038
|
+
if (event.kind !== "offloaded") return;
|
|
57039
|
+
reportContextNotice({
|
|
57040
|
+
kind: "tool_output_offloaded",
|
|
57041
|
+
message: `${event.toolName} returned ${Math.ceil(event.outputLength / 4).toLocaleString()} estimated tokens and was offloaded to the context ledger to protect the context window.`,
|
|
57042
|
+
toolName: event.toolName,
|
|
57043
|
+
outputLength: event.outputLength,
|
|
57044
|
+
filePath: event.filePath
|
|
57045
|
+
});
|
|
57046
|
+
}
|
|
57047
|
+
},
|
|
57048
|
+
options.stateDir
|
|
57049
|
+
);
|
|
57050
|
+
return result.offloaded ? { reference: result.content } : void 0;
|
|
57051
|
+
} : void 0;
|
|
56699
57052
|
let toolsEnabled = true;
|
|
56700
57053
|
const checkpointHasConfigChanges = (result) => Boolean(result.model) || result.tools === true || result.sandbox !== void 0;
|
|
56701
57054
|
const rebuildCheckpointTools = () => applyOffloadWrapping(
|
|
@@ -56866,6 +57219,20 @@ Saving state... done. Session saved to ${filePath}`);
|
|
|
56866
57219
|
break;
|
|
56867
57220
|
}
|
|
56868
57221
|
}
|
|
57222
|
+
const stallEscalationUsedModels = /* @__PURE__ */ new Map();
|
|
57223
|
+
const pickNextStallFallbackModel = (phase, currentModel) => {
|
|
57224
|
+
if (!phase) return void 0;
|
|
57225
|
+
const chain = [
|
|
57226
|
+
...playbookMilestoneFallbackModels?.[phase]?.map((fb) => fb.model) ?? [],
|
|
57227
|
+
...options.fallbackModel ? [options.fallbackModel] : []
|
|
57228
|
+
];
|
|
57229
|
+
const used = stallEscalationUsedModels.get(phase) ?? /* @__PURE__ */ new Set();
|
|
57230
|
+
const next = chain.find((model) => model !== currentModel && !used.has(model));
|
|
57231
|
+
if (!next) return void 0;
|
|
57232
|
+
used.add(next);
|
|
57233
|
+
stallEscalationUsedModels.set(phase, used);
|
|
57234
|
+
return next;
|
|
57235
|
+
};
|
|
56869
57236
|
let shouldContinue = true;
|
|
56870
57237
|
let accumulatedSessions = 0;
|
|
56871
57238
|
let accumulatedCost = 0;
|
|
@@ -56932,6 +57299,7 @@ Saving state... done. Session saved to ${filePath}`);
|
|
|
56932
57299
|
stream: true,
|
|
56933
57300
|
streamCallbacks: currentStreamCallbacks,
|
|
56934
57301
|
localTools,
|
|
57302
|
+
...ledgerOffloadRecorder ? { offloadRecorder: ledgerOffloadRecorder } : {},
|
|
56935
57303
|
trackProgress: options.track ? taskName : void 0,
|
|
56936
57304
|
// Mid-run steering queue (Enter while streaming): the UI owns the
|
|
56937
57305
|
// queue; the SDK drains it at session boundaries and ends in-flight
|
|
@@ -57081,6 +57449,20 @@ Saving state... done. Session saved to ${filePath}`);
|
|
|
57081
57449
|
});
|
|
57082
57450
|
}
|
|
57083
57451
|
}
|
|
57452
|
+
if (state.stallEscalationRequested && state.status === "running") {
|
|
57453
|
+
const escalationPhase = state.workflowPhase;
|
|
57454
|
+
const activeModel = phaseModel || options.model;
|
|
57455
|
+
const nextModel = pickNextStallFallbackModel(escalationPhase, activeModel);
|
|
57456
|
+
if (escalationPhase && nextModel) {
|
|
57457
|
+
playbookMilestoneModels = {
|
|
57458
|
+
...playbookMilestoneModels ?? {},
|
|
57459
|
+
[escalationPhase]: nextModel
|
|
57460
|
+
};
|
|
57461
|
+
options.model = nextModel;
|
|
57462
|
+
shouldContinue = true;
|
|
57463
|
+
return false;
|
|
57464
|
+
}
|
|
57465
|
+
}
|
|
57084
57466
|
if (state.recentActionKeys && state.recentActionKeys.length > 0) {
|
|
57085
57467
|
for (const key of state.recentActionKeys) {
|
|
57086
57468
|
loopDetector.recordAction(key);
|
|
@@ -59901,9 +60283,9 @@ import { execFileSync } from "child_process";
|
|
|
59901
60283
|
// src/lib/persona-init.ts
|
|
59902
60284
|
init_credential_store();
|
|
59903
60285
|
|
|
59904
|
-
// ../../node_modules/.pnpm/@runtypelabs+persona@3.
|
|
59905
|
-
var S =
|
|
59906
|
-
var c = S
|
|
60286
|
+
// ../../node_modules/.pnpm/@runtypelabs+persona@3.34.0/node_modules/@runtypelabs/persona/dist/codegen.js
|
|
60287
|
+
var S = "3.34.0";
|
|
60288
|
+
var c = S;
|
|
59907
60289
|
function u(e) {
|
|
59908
60290
|
if (e !== void 0) return typeof e == "string" ? e : Array.isArray(e) ? `[${e.map((r) => r.toString()).join(", ")}]` : e.toString();
|
|
59909
60291
|
}
|
|
@@ -60065,7 +60447,7 @@ function I(e, r = "esm", n) {
|
|
|
60065
60447
|
let s = { ...e };
|
|
60066
60448
|
delete s.postprocessMessage, delete s.initialMessages;
|
|
60067
60449
|
let o = n ? { ...n, hooks: T(n.hooks) } : void 0;
|
|
60068
|
-
return r === "esm" ? W(s, o) : r === "script-installer" ?
|
|
60450
|
+
return r === "esm" ? W(s, o) : r === "script-installer" ? D(s, o) : r === "script-advanced" ? F(s, o) : r === "react-component" ? H(s, o) : r === "react-advanced" ? N(s, o) : k(s, o);
|
|
60069
60451
|
}
|
|
60070
60452
|
function W(e, r) {
|
|
60071
60453
|
let n = r == null ? void 0 : r.hooks, s = h(e), o = s !== "plain", t = ["import '@runtypelabs/persona/widget.css';", "import { initAgentWidget, markdownPostprocessor } from '@runtypelabs/persona';", "", "initAgentWidget({", ` target: '${g(r)}',`, " config: {"];
|
|
@@ -60161,11 +60543,11 @@ function P(e) {
|
|
|
60161
60543
|
}
|
|
60162
60544
|
return s;
|
|
60163
60545
|
}
|
|
60164
|
-
function
|
|
60546
|
+
function D(e, r) {
|
|
60165
60547
|
let n = P(e), o = !!(r != null && r.windowKey || r != null && r.target) ? { config: n, ...r != null && r.windowKey ? { windowKey: r.windowKey } : {}, ...r != null && r.target ? { target: r.target } : {} } : n, t = JSON.stringify(o, null, 0).replace(/'/g, "'");
|
|
60166
60548
|
return `<script src="https://cdn.jsdelivr.net/npm/@runtypelabs/persona@${c}/dist/install.global.js" data-config='${t}'></script>`;
|
|
60167
60549
|
}
|
|
60168
|
-
function
|
|
60550
|
+
function k(e, r) {
|
|
60169
60551
|
let n = r == null ? void 0 : r.hooks, s = h(e), o = s !== "plain", t = ["<!-- Load CSS -->", `<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@runtypelabs/persona@${c}/dist/widget.css" />`, "", "<!-- Load JavaScript -->", `<script src="https://cdn.jsdelivr.net/npm/@runtypelabs/persona@${c}/dist/index.global.js"></script>`, "", "<!-- Initialize widget -->", "<script>", " var handle = window.AgentWidget.initAgentWidget({", ` target: '${g(r)}',`, ...r != null && r.windowKey ? [` windowKey: '${r.windowKey}',`] : [], " config: {"];
|
|
60170
60552
|
return e.apiUrl && t.push(` apiUrl: "${e.apiUrl}",`), e.clientToken && t.push(` clientToken: "${e.clientToken}",`), e.flowId && t.push(` flowId: "${e.flowId}",`), o && t.push(` parserType: "${s}",`), e.theme && typeof e.theme == "object" && Object.keys(e.theme).length > 0 && l(t, "theme", e.theme, " "), e.launcher && l(t, "launcher", e.launcher, " "), e.copy && (t.push(" copy: {"), Object.entries(e.copy).forEach(([i, a]) => {
|
|
60171
60553
|
t.push(` ${i}: "${a}",`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@runtypelabs/cli",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.19.1",
|
|
4
4
|
"description": "Command-line interface for Runtype AI platform",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
"ink": "6.7.0",
|
|
17
17
|
"ink-select-input": "^6.2.0",
|
|
18
18
|
"ink-text-input": "^6.0.0",
|
|
19
|
+
"jiti": "^2.7.0",
|
|
19
20
|
"micromatch": "^4.0.8",
|
|
20
21
|
"oauth4webapi": "^3.8.5",
|
|
21
22
|
"open": "^10.1.0",
|
|
@@ -23,11 +24,11 @@
|
|
|
23
24
|
"rosie-skills": "0.8.1",
|
|
24
25
|
"yaml": "^2.9.0",
|
|
25
26
|
"@runtypelabs/ink-components": "0.3.2",
|
|
26
|
-
"@runtypelabs/sdk": "4.
|
|
27
|
+
"@runtypelabs/sdk": "4.12.0",
|
|
27
28
|
"@runtypelabs/terminal-animations": "0.2.1"
|
|
28
29
|
},
|
|
29
30
|
"devDependencies": {
|
|
30
|
-
"@runtypelabs/persona": "3.
|
|
31
|
+
"@runtypelabs/persona": "3.34.0",
|
|
31
32
|
"@types/express": "^5.0.6",
|
|
32
33
|
"@types/micromatch": "^4.0.9",
|
|
33
34
|
"@types/node": "^25.3.3",
|
|
@@ -38,7 +39,7 @@
|
|
|
38
39
|
"tsx": "^4.7.1",
|
|
39
40
|
"typescript": "^5.3.3",
|
|
40
41
|
"vitest": "^4.1.0",
|
|
41
|
-
"@runtypelabs/shared": "1.
|
|
42
|
+
"@runtypelabs/shared": "1.26.0"
|
|
42
43
|
},
|
|
43
44
|
"engines": {
|
|
44
45
|
"node": ">=22.0.0"
|