@hasna/loops 0.3.53 → 0.3.55
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 +77 -4
- package/dist/cli/index.js +477 -108
- package/dist/daemon/index.js +223 -29
- package/dist/index.js +308 -75
- package/dist/lib/store.d.ts +16 -1
- package/dist/lib/store.js +202 -11
- package/dist/lib/templates.d.ts +4 -2
- package/dist/lib/workflow-spec.d.ts +8 -2
- package/dist/sdk/index.js +219 -25
- package/dist/types.d.ts +24 -8
- package/docs/USAGE.md +82 -4
- package/docs/workflows/transcript-feedback-to-loops.json +2 -2
- package/package.json +1 -1
package/dist/lib/store.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { CreateLoopInput, CreateWorkflowInvocationInput, CreateWorkflowInput, Goal, GoalAutoExecute, GoalPlanNode, GoalRun, GoalStatus, Loop, LoopRun, LoopStatus, RunStatus, WorkflowEvent, WorkflowInvocation, WorkflowRun, WorkflowRunStatus, WorkflowSpec, WorkflowStepRun, WorkflowWorkItem, WorkflowWorkItemStatus, UpsertWorkflowWorkItemInput } from "../types.js";
|
|
1
|
+
import type { CreateLoopInput, CreateWorkflowInvocationInput, CreateWorkflowInput, Goal, GoalAutoExecute, GoalPlanNode, GoalRun, GoalStatus, Loop, LoopRun, LoopStatus, RunStatus, TimeoutMs, WorkflowEvent, WorkflowInvocation, WorkflowRun, WorkflowRunStatus, WorkflowSpec, WorkflowStepRun, WorkflowWorkItem, WorkflowWorkItemStatus, UpsertWorkflowWorkItemInput } from "../types.js";
|
|
2
2
|
interface DaemonLeaseFence {
|
|
3
3
|
daemonLeaseId?: string;
|
|
4
4
|
now?: Date;
|
|
@@ -74,6 +74,7 @@ export declare class Store {
|
|
|
74
74
|
createLoop(input: CreateLoopInput, from?: Date): Loop;
|
|
75
75
|
getLoop(id: string): Loop | undefined;
|
|
76
76
|
findLoopByName(name: string): Loop | undefined;
|
|
77
|
+
requireUniqueLoop(idOrName: string): Loop;
|
|
77
78
|
requireLoop(idOrName: string): Loop;
|
|
78
79
|
listLoops(opts?: {
|
|
79
80
|
status?: LoopStatus;
|
|
@@ -83,6 +84,20 @@ export declare class Store {
|
|
|
83
84
|
}): Loop[];
|
|
84
85
|
dueLoops(now: Date, limit?: number): Loop[];
|
|
85
86
|
updateLoop(id: string, patch: Partial<Pick<Loop, "status" | "nextRunAt" | "retryScheduledFor" | "expiresAt">>, opts?: DaemonLeaseFence): Loop;
|
|
87
|
+
private activeLoopReferenceCount;
|
|
88
|
+
private archiveWorkflowIfUnreferenced;
|
|
89
|
+
retargetWorkflowLoop(idOrName: string, workflowId: string, opts?: DaemonLeaseFence & {
|
|
90
|
+
workflowTimeoutMs?: TimeoutMs;
|
|
91
|
+
}): Loop;
|
|
92
|
+
createAndRetargetWorkflowLoop(idOrName: string, workflowInput: CreateWorkflowInput, opts?: DaemonLeaseFence & {
|
|
93
|
+
workflowTimeoutMs?: TimeoutMs;
|
|
94
|
+
archiveOld?: boolean;
|
|
95
|
+
}): {
|
|
96
|
+
loop: Loop;
|
|
97
|
+
workflow: WorkflowSpec;
|
|
98
|
+
previousWorkflow: WorkflowSpec;
|
|
99
|
+
archivedOld?: WorkflowSpec;
|
|
100
|
+
};
|
|
86
101
|
renameLoop(id: string, name: string, opts?: DaemonLeaseFence): Loop;
|
|
87
102
|
archiveLoop(idOrName: string): Loop;
|
|
88
103
|
unarchiveLoop(idOrName: string): Loop;
|
package/dist/lib/store.js
CHANGED
|
@@ -312,6 +312,8 @@ function updateReadyFlags(nodes, planStatus) {
|
|
|
312
312
|
}
|
|
313
313
|
|
|
314
314
|
// src/lib/workflow-spec.ts
|
|
315
|
+
import { readFileSync } from "fs";
|
|
316
|
+
import { isAbsolute, resolve } from "path";
|
|
315
317
|
function assertObject(value, label) {
|
|
316
318
|
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
317
319
|
throw new Error(`${label} must be an object`);
|
|
@@ -327,6 +329,15 @@ function optionalPositiveInteger(value, label) {
|
|
|
327
329
|
throw new Error(`${label} must be a positive integer`);
|
|
328
330
|
return value;
|
|
329
331
|
}
|
|
332
|
+
function optionalTimeoutMs(value, label) {
|
|
333
|
+
if (value === undefined)
|
|
334
|
+
return;
|
|
335
|
+
if (value === null)
|
|
336
|
+
return null;
|
|
337
|
+
if (!Number.isInteger(value) || value <= 0)
|
|
338
|
+
throw new Error(`${label} must be a positive integer or null for unlimited`);
|
|
339
|
+
return value;
|
|
340
|
+
}
|
|
330
341
|
function optionalBoolean(value, label) {
|
|
331
342
|
if (value === undefined)
|
|
332
343
|
return;
|
|
@@ -357,6 +368,38 @@ function optionalAccountRef(value, label) {
|
|
|
357
368
|
tool: typeof value.tool === "string" ? value.tool.trim() : undefined
|
|
358
369
|
};
|
|
359
370
|
}
|
|
371
|
+
function promptFilePath(rawPath, opts) {
|
|
372
|
+
return isAbsolute(rawPath) ? resolve(rawPath) : resolve(opts.baseDir ?? process.cwd(), rawPath);
|
|
373
|
+
}
|
|
374
|
+
function readPromptFile(rawPath, label, opts) {
|
|
375
|
+
assertString(rawPath, `${label}.promptFile`);
|
|
376
|
+
const path = promptFilePath(rawPath.trim(), opts);
|
|
377
|
+
let prompt;
|
|
378
|
+
try {
|
|
379
|
+
prompt = readFileSync(path, "utf8");
|
|
380
|
+
} catch (error) {
|
|
381
|
+
const code = error && typeof error === "object" && "code" in error ? String(error.code) : undefined;
|
|
382
|
+
throw new Error(`${label}.promptFile could not be read${code ? `: ${code}` : ""}`);
|
|
383
|
+
}
|
|
384
|
+
if (prompt.trim() === "")
|
|
385
|
+
throw new Error(`${label}.promptFile must contain a non-empty prompt`);
|
|
386
|
+
return { prompt, promptSource: { type: "file", path } };
|
|
387
|
+
}
|
|
388
|
+
function matchingPromptSource(value, prompt, opts) {
|
|
389
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
390
|
+
return;
|
|
391
|
+
if (value.type !== "file")
|
|
392
|
+
return;
|
|
393
|
+
const rawPath = value.path;
|
|
394
|
+
if (typeof rawPath !== "string" || rawPath.trim() === "")
|
|
395
|
+
return;
|
|
396
|
+
const path = promptFilePath(rawPath.trim(), opts);
|
|
397
|
+
try {
|
|
398
|
+
return readFileSync(path, "utf8") === prompt ? { type: "file", path } : undefined;
|
|
399
|
+
} catch {
|
|
400
|
+
return;
|
|
401
|
+
}
|
|
402
|
+
}
|
|
360
403
|
function normalizeGoalSpec(value, label = "goal") {
|
|
361
404
|
if (value === undefined)
|
|
362
405
|
return;
|
|
@@ -379,11 +422,11 @@ function normalizeGoalSpec(value, label = "goal") {
|
|
|
379
422
|
autoExecute
|
|
380
423
|
};
|
|
381
424
|
}
|
|
382
|
-
function validateTarget(value, label) {
|
|
425
|
+
function validateTarget(value, label, opts) {
|
|
383
426
|
assertObject(value, label);
|
|
384
427
|
if (value.type === "command") {
|
|
385
428
|
assertString(value.command, `${label}.command`);
|
|
386
|
-
|
|
429
|
+
optionalTimeoutMs(value.timeoutMs, `${label}.timeoutMs`);
|
|
387
430
|
optionalPositiveInteger(value.idleTimeoutMs, `${label}.idleTimeoutMs`);
|
|
388
431
|
if (value.shell !== true && /\s/.test(value.command.trim())) {
|
|
389
432
|
throw new Error(`${label}.command must be an executable without spaces when shell is false; put flags in args or set shell true`);
|
|
@@ -392,11 +435,17 @@ function validateTarget(value, label) {
|
|
|
392
435
|
}
|
|
393
436
|
if (value.type === "agent") {
|
|
394
437
|
assertString(value.provider, `${label}.provider`);
|
|
395
|
-
|
|
438
|
+
const hasPrompt = typeof value.prompt === "string" && value.prompt.trim() !== "";
|
|
439
|
+
const hasPromptFile = typeof value.promptFile === "string" && value.promptFile.trim() !== "";
|
|
440
|
+
if (hasPrompt && hasPromptFile)
|
|
441
|
+
throw new Error(`${label} must use either prompt or promptFile, not both`);
|
|
442
|
+
if (!hasPrompt && !hasPromptFile)
|
|
443
|
+
throw new Error(`${label}.prompt must be a non-empty string or ${label}.promptFile must be set`);
|
|
444
|
+
const promptFields = hasPrompt ? { prompt: value.prompt, promptSource: matchingPromptSource(value.promptSource, value.prompt, opts) } : readPromptFile(value.promptFile, label, opts);
|
|
396
445
|
const providers = ["claude", "cursor", "codewith", "aicopilot", "opencode", "codex"];
|
|
397
446
|
if (!providers.includes(value.provider))
|
|
398
447
|
throw new Error(`${label}.provider must be one of ${providers.join(", ")}`);
|
|
399
|
-
|
|
448
|
+
optionalTimeoutMs(value.timeoutMs, `${label}.timeoutMs`);
|
|
400
449
|
optionalPositiveInteger(value.idleTimeoutMs, `${label}.idleTimeoutMs`);
|
|
401
450
|
if (value.authProfile !== undefined) {
|
|
402
451
|
assertString(value.authProfile, `${label}.authProfile`);
|
|
@@ -493,11 +542,14 @@ function validateTarget(value, label) {
|
|
|
493
542
|
if (value.routing.eventSource !== undefined)
|
|
494
543
|
assertString(value.routing.eventSource, `${label}.routing.eventSource`);
|
|
495
544
|
}
|
|
496
|
-
|
|
545
|
+
const target = { ...value };
|
|
546
|
+
delete target.promptFile;
|
|
547
|
+
delete target.promptSource;
|
|
548
|
+
return { ...target, ...promptFields };
|
|
497
549
|
}
|
|
498
550
|
throw new Error(`${label}.type must be command or agent`);
|
|
499
551
|
}
|
|
500
|
-
function normalizeCreateWorkflowInput(input) {
|
|
552
|
+
function normalizeCreateWorkflowInput(input, opts = {}) {
|
|
501
553
|
assertString(input.name, "workflow.name");
|
|
502
554
|
const goal = normalizeGoalSpec(input.goal, "goal");
|
|
503
555
|
if (!Array.isArray(input.steps) || input.steps.length === 0)
|
|
@@ -513,10 +565,10 @@ function normalizeCreateWorkflowInput(input) {
|
|
|
513
565
|
...step,
|
|
514
566
|
id: step.id,
|
|
515
567
|
goal: normalizeGoalSpec(step.goal, `workflow.steps[${index}].goal`),
|
|
516
|
-
target: validateTarget(step.target, `workflow.steps[${index}].target
|
|
568
|
+
target: validateTarget(step.target, `workflow.steps[${index}].target`, opts),
|
|
517
569
|
dependsOn: optionalStringArray(step.dependsOn, `workflow.steps[${index}].dependsOn`) ?? [],
|
|
518
570
|
continueOnFailure: optionalBoolean(step.continueOnFailure, `workflow.steps[${index}].continueOnFailure`) ?? false,
|
|
519
|
-
timeoutMs:
|
|
571
|
+
timeoutMs: optionalTimeoutMs(step.timeoutMs, `workflow.steps[${index}].timeoutMs`),
|
|
520
572
|
account: optionalAccountRef(step.account, `workflow.steps[${index}].account`)
|
|
521
573
|
};
|
|
522
574
|
});
|
|
@@ -556,7 +608,7 @@ function workflowExecutionOrder(workflow) {
|
|
|
556
608
|
visit(step);
|
|
557
609
|
return order;
|
|
558
610
|
}
|
|
559
|
-
function workflowBodyFromJson(value, fallbackName) {
|
|
611
|
+
function workflowBodyFromJson(value, fallbackName, opts = {}) {
|
|
560
612
|
assertObject(value, "workflow file");
|
|
561
613
|
const rawName = fallbackName ?? value.name;
|
|
562
614
|
assertString(rawName, "workflow.name");
|
|
@@ -568,7 +620,7 @@ function workflowBodyFromJson(value, fallbackName) {
|
|
|
568
620
|
goal: normalizeGoalSpec(value.goal, "goal"),
|
|
569
621
|
version: typeof value.version === "number" ? value.version : undefined,
|
|
570
622
|
steps: value.steps
|
|
571
|
-
});
|
|
623
|
+
}, opts);
|
|
572
624
|
}
|
|
573
625
|
|
|
574
626
|
// src/lib/run-artifacts.ts
|
|
@@ -1205,13 +1257,17 @@ class Store {
|
|
|
1205
1257
|
}
|
|
1206
1258
|
createLoop(input, from = new Date) {
|
|
1207
1259
|
const now = nowIso();
|
|
1260
|
+
const target = input.target.type === "workflow" ? input.target : normalizeCreateWorkflowInput({
|
|
1261
|
+
name: "loop-target-validation",
|
|
1262
|
+
steps: [{ id: "target", target: input.target }]
|
|
1263
|
+
}).steps[0].target;
|
|
1208
1264
|
const loop = {
|
|
1209
1265
|
id: genId(),
|
|
1210
1266
|
name: input.name,
|
|
1211
1267
|
description: input.description,
|
|
1212
1268
|
status: "active",
|
|
1213
1269
|
schedule: input.schedule,
|
|
1214
|
-
target
|
|
1270
|
+
target,
|
|
1215
1271
|
goal: input.goal,
|
|
1216
1272
|
machine: input.machine,
|
|
1217
1273
|
nextRunAt: initialNextRun(input.schedule, from),
|
|
@@ -1258,6 +1314,17 @@ class Store {
|
|
|
1258
1314
|
const row = this.db.query("SELECT * FROM loops WHERE name = ? ORDER BY created_at DESC LIMIT 1").get(name);
|
|
1259
1315
|
return row ? rowToLoop(row) : undefined;
|
|
1260
1316
|
}
|
|
1317
|
+
requireUniqueLoop(idOrName) {
|
|
1318
|
+
const byId = this.getLoop(idOrName);
|
|
1319
|
+
if (byId)
|
|
1320
|
+
return byId;
|
|
1321
|
+
const rows = this.db.query("SELECT * FROM loops WHERE name = ? ORDER BY created_at DESC LIMIT 2").all(idOrName);
|
|
1322
|
+
if (rows.length === 0)
|
|
1323
|
+
throw new Error(`loop not found: ${idOrName}`);
|
|
1324
|
+
if (rows.length > 1)
|
|
1325
|
+
throw new Error(`ambiguous loop name: ${idOrName}; use a loop id`);
|
|
1326
|
+
return rowToLoop(rows[0]);
|
|
1327
|
+
}
|
|
1261
1328
|
requireLoop(idOrName) {
|
|
1262
1329
|
return this.getLoop(idOrName) ?? this.findLoopByName(idOrName) ?? (() => {
|
|
1263
1330
|
throw new Error(`loop not found: ${idOrName}`);
|
|
@@ -1332,6 +1399,130 @@ class Store {
|
|
|
1332
1399
|
throw new Error(`loop not found after update: ${id}`);
|
|
1333
1400
|
return after;
|
|
1334
1401
|
}
|
|
1402
|
+
activeLoopReferenceCount(workflowId) {
|
|
1403
|
+
const rows = this.db.query("SELECT target_json FROM loops WHERE archived_at IS NULL").all();
|
|
1404
|
+
let count = 0;
|
|
1405
|
+
for (const row of rows) {
|
|
1406
|
+
try {
|
|
1407
|
+
const target = JSON.parse(row.target_json);
|
|
1408
|
+
if (target.type === "workflow" && target.workflowId === workflowId)
|
|
1409
|
+
count += 1;
|
|
1410
|
+
} catch {}
|
|
1411
|
+
}
|
|
1412
|
+
return count;
|
|
1413
|
+
}
|
|
1414
|
+
archiveWorkflowIfUnreferenced(workflowId, updated) {
|
|
1415
|
+
if (this.activeLoopReferenceCount(workflowId) > 0)
|
|
1416
|
+
return;
|
|
1417
|
+
const workflow = this.getWorkflow(workflowId);
|
|
1418
|
+
if (!workflow || workflow.status !== "active")
|
|
1419
|
+
return;
|
|
1420
|
+
const res = this.db.query("UPDATE workflow_specs SET status='archived', updated_at=? WHERE id=? AND status='active'").run(updated, workflowId);
|
|
1421
|
+
if (res.changes !== 1)
|
|
1422
|
+
return;
|
|
1423
|
+
return this.getWorkflow(workflowId);
|
|
1424
|
+
}
|
|
1425
|
+
retargetWorkflowLoop(idOrName, workflowId, opts = {}) {
|
|
1426
|
+
const updated = (opts.now ?? new Date).toISOString();
|
|
1427
|
+
this.db.exec("BEGIN IMMEDIATE");
|
|
1428
|
+
try {
|
|
1429
|
+
const current = this.requireLoop(idOrName);
|
|
1430
|
+
if (current.target.type !== "workflow")
|
|
1431
|
+
throw new Error(`loop is not a workflow loop: ${idOrName}`);
|
|
1432
|
+
if (this.hasRunningRun(current.id))
|
|
1433
|
+
throw new Error(`refusing to retarget running loop: ${current.id}`);
|
|
1434
|
+
const workflow = this.requireWorkflow(workflowId);
|
|
1435
|
+
const target = { ...current.target, workflowId: workflow.id };
|
|
1436
|
+
if (opts.workflowTimeoutMs !== undefined)
|
|
1437
|
+
target.timeoutMs = opts.workflowTimeoutMs;
|
|
1438
|
+
const res = this.db.query(`UPDATE loops SET target_json=$target, updated_at=$updated
|
|
1439
|
+
WHERE id=$id
|
|
1440
|
+
AND ($daemonLeaseId IS NULL OR EXISTS (
|
|
1441
|
+
SELECT 1 FROM daemon_lease WHERE id=$daemonLeaseId AND expires_at > $now
|
|
1442
|
+
))`).run({
|
|
1443
|
+
$id: current.id,
|
|
1444
|
+
$target: JSON.stringify(target),
|
|
1445
|
+
$updated: updated,
|
|
1446
|
+
$daemonLeaseId: opts.daemonLeaseId ?? null,
|
|
1447
|
+
$now: updated
|
|
1448
|
+
});
|
|
1449
|
+
if (res.changes !== 1)
|
|
1450
|
+
throw new Error("daemon lease lost");
|
|
1451
|
+
this.db.exec("COMMIT");
|
|
1452
|
+
const after = this.getLoop(current.id);
|
|
1453
|
+
if (!after)
|
|
1454
|
+
throw new Error(`loop not found after retarget: ${current.id}`);
|
|
1455
|
+
return after;
|
|
1456
|
+
} catch (error) {
|
|
1457
|
+
try {
|
|
1458
|
+
this.db.exec("ROLLBACK");
|
|
1459
|
+
} catch {}
|
|
1460
|
+
throw error;
|
|
1461
|
+
}
|
|
1462
|
+
}
|
|
1463
|
+
createAndRetargetWorkflowLoop(idOrName, workflowInput, opts = {}) {
|
|
1464
|
+
const normalized = normalizeCreateWorkflowInput(workflowInput);
|
|
1465
|
+
const updated = (opts.now ?? new Date).toISOString();
|
|
1466
|
+
this.db.exec("BEGIN IMMEDIATE");
|
|
1467
|
+
try {
|
|
1468
|
+
const current = this.requireUniqueLoop(idOrName);
|
|
1469
|
+
if (current.target.type !== "workflow")
|
|
1470
|
+
throw new Error(`loop is not a workflow loop: ${idOrName}`);
|
|
1471
|
+
if (this.hasRunningRun(current.id))
|
|
1472
|
+
throw new Error(`refusing to retarget running loop: ${current.id}`);
|
|
1473
|
+
const previousWorkflow = this.requireWorkflow(current.target.workflowId);
|
|
1474
|
+
const workflow = {
|
|
1475
|
+
id: genId(),
|
|
1476
|
+
name: normalized.name,
|
|
1477
|
+
description: normalized.description,
|
|
1478
|
+
version: normalized.version ?? 1,
|
|
1479
|
+
status: "active",
|
|
1480
|
+
goal: normalized.goal,
|
|
1481
|
+
steps: normalized.steps,
|
|
1482
|
+
createdAt: updated,
|
|
1483
|
+
updatedAt: updated
|
|
1484
|
+
};
|
|
1485
|
+
this.db.query(`INSERT INTO workflow_specs (id, name, description, version, status, goal_json, steps_json, created_at, updated_at)
|
|
1486
|
+
VALUES ($id, $name, $description, $version, $status, $goal, $steps, $created, $updated)`).run({
|
|
1487
|
+
$id: workflow.id,
|
|
1488
|
+
$name: workflow.name,
|
|
1489
|
+
$description: workflow.description ?? null,
|
|
1490
|
+
$version: workflow.version,
|
|
1491
|
+
$status: workflow.status,
|
|
1492
|
+
$goal: workflow.goal ? JSON.stringify(workflow.goal) : null,
|
|
1493
|
+
$steps: JSON.stringify(workflow.steps),
|
|
1494
|
+
$created: workflow.createdAt,
|
|
1495
|
+
$updated: workflow.updatedAt
|
|
1496
|
+
});
|
|
1497
|
+
const target = { ...current.target, workflowId: workflow.id };
|
|
1498
|
+
if (opts.workflowTimeoutMs !== undefined)
|
|
1499
|
+
target.timeoutMs = opts.workflowTimeoutMs;
|
|
1500
|
+
const res = this.db.query(`UPDATE loops SET target_json=$target, updated_at=$updated
|
|
1501
|
+
WHERE id=$id
|
|
1502
|
+
AND ($daemonLeaseId IS NULL OR EXISTS (
|
|
1503
|
+
SELECT 1 FROM daemon_lease WHERE id=$daemonLeaseId AND expires_at > $now
|
|
1504
|
+
))`).run({
|
|
1505
|
+
$id: current.id,
|
|
1506
|
+
$target: JSON.stringify(target),
|
|
1507
|
+
$updated: updated,
|
|
1508
|
+
$daemonLeaseId: opts.daemonLeaseId ?? null,
|
|
1509
|
+
$now: updated
|
|
1510
|
+
});
|
|
1511
|
+
if (res.changes !== 1)
|
|
1512
|
+
throw new Error("daemon lease lost");
|
|
1513
|
+
const archivedOld = opts.archiveOld ? this.archiveWorkflowIfUnreferenced(previousWorkflow.id, updated) : undefined;
|
|
1514
|
+
this.db.exec("COMMIT");
|
|
1515
|
+
const loop = this.getLoop(current.id);
|
|
1516
|
+
if (!loop)
|
|
1517
|
+
throw new Error(`loop not found after retarget: ${current.id}`);
|
|
1518
|
+
return { loop, workflow, previousWorkflow, archivedOld };
|
|
1519
|
+
} catch (error) {
|
|
1520
|
+
try {
|
|
1521
|
+
this.db.exec("ROLLBACK");
|
|
1522
|
+
} catch {}
|
|
1523
|
+
throw error;
|
|
1524
|
+
}
|
|
1525
|
+
}
|
|
1335
1526
|
renameLoop(id, name, opts = {}) {
|
|
1336
1527
|
const current = this.getLoop(id);
|
|
1337
1528
|
if (!current)
|
package/dist/lib/templates.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AccountRef, AgentPermissionMode, AgentProvider, AgentSandbox, AgentWorktreeMode, CreateWorkflowInput, LoopTemplateSource, LoopTemplateSummary } from "../types.js";
|
|
1
|
+
import type { AccountRef, AgentPermissionMode, AgentProvider, AgentSandbox, AgentWorktreeMode, CreateWorkflowInput, LoopTemplateSource, LoopTemplateSummary, TimeoutMs } from "../types.js";
|
|
2
2
|
export declare const TODOS_TASK_WORKER_VERIFIER_TEMPLATE_ID = "todos-task-worker-verifier";
|
|
3
3
|
export declare const EVENT_WORKER_VERIFIER_TEMPLATE_ID = "event-worker-verifier";
|
|
4
4
|
export declare const BOUNDED_AGENT_WORKER_VERIFIER_TEMPLATE_ID = "bounded-agent-worker-verifier";
|
|
@@ -40,6 +40,7 @@ export interface TodosTaskWorkflowTemplateInput {
|
|
|
40
40
|
worktreeMode?: AgentWorktreeMode;
|
|
41
41
|
worktreeRoot?: string;
|
|
42
42
|
worktreeBranchPrefix?: string;
|
|
43
|
+
timeoutMs?: TimeoutMs;
|
|
43
44
|
eventId?: string;
|
|
44
45
|
eventType?: string;
|
|
45
46
|
}
|
|
@@ -76,6 +77,7 @@ export interface EventWorkflowTemplateInput {
|
|
|
76
77
|
worktreeMode?: AgentWorktreeMode;
|
|
77
78
|
worktreeRoot?: string;
|
|
78
79
|
worktreeBranchPrefix?: string;
|
|
80
|
+
timeoutMs?: TimeoutMs;
|
|
79
81
|
}
|
|
80
82
|
export interface BoundedAgentWorkflowTemplateInput {
|
|
81
83
|
name?: string;
|
|
@@ -107,7 +109,7 @@ export interface BoundedAgentWorkflowTemplateInput {
|
|
|
107
109
|
worktreeMode?: AgentWorktreeMode;
|
|
108
110
|
worktreeRoot?: string;
|
|
109
111
|
worktreeBranchPrefix?: string;
|
|
110
|
-
timeoutMs?:
|
|
112
|
+
timeoutMs?: TimeoutMs;
|
|
111
113
|
}
|
|
112
114
|
export type LoopTemplateSourceFilter = LoopTemplateSource | "all";
|
|
113
115
|
export interface ListLoopTemplatesOptions {
|
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import type { CreateWorkflowInput, GoalSpec, WorkflowSpec, WorkflowStep } from "../types.js";
|
|
2
2
|
export type WorkflowSpecBody = Pick<WorkflowSpec, "name" | "description" | "version" | "steps">;
|
|
3
|
+
export type NormalizedCreateWorkflowInput = Omit<CreateWorkflowInput, "steps"> & {
|
|
4
|
+
steps: WorkflowStep[];
|
|
5
|
+
};
|
|
6
|
+
export interface WorkflowNormalizeOptions {
|
|
7
|
+
baseDir?: string;
|
|
8
|
+
}
|
|
3
9
|
export declare function normalizeGoalSpec(value: unknown, label?: string): GoalSpec | undefined;
|
|
4
|
-
export declare function normalizeCreateWorkflowInput(input: CreateWorkflowInput):
|
|
10
|
+
export declare function normalizeCreateWorkflowInput(input: CreateWorkflowInput, opts?: WorkflowNormalizeOptions): NormalizedCreateWorkflowInput;
|
|
5
11
|
export declare function workflowExecutionOrder(workflow: Pick<WorkflowSpec, "steps">): WorkflowStep[];
|
|
6
|
-
export declare function workflowBodyFromJson(value: unknown, fallbackName?: string):
|
|
12
|
+
export declare function workflowBodyFromJson(value: unknown, fallbackName?: string, opts?: WorkflowNormalizeOptions): NormalizedCreateWorkflowInput;
|