@tea-agent/loop-agent 0.28.2-beta.1 → 0.28.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/AGENTS.md +1 -1
- package/CHANGELOG.md +25 -0
- package/README.md +11 -1
- package/dist/cli/command-definitions.js +2 -1
- package/dist/commands/client-recovery.js +111 -8
- package/dist/commands/dag-init-hybrid.js +1 -1
- package/dist/commands/init-upgrade.js +2479 -0
- package/dist/commands/init.js +120 -9
- package/dist/governance/manifest-types.js +65 -0
- package/dist/shared/operator/capabilities.js +350 -2
- package/dist/task/worktree.js +256 -39
- package/dist/worker/cli.js +22 -12
- package/dist/worker/console/chat/workspace-landing.js +16 -6
- package/dist/worker/console/observe-health-match.js +2 -0
- package/dist/worker/console/observe-link.js +4 -0
- package/dist/worker/console/operator-actions.js +183 -4
- package/dist/worker/console/operator-selection.js +13 -0
- package/dist/worker/console/static/assets/index-BfRgtLF4.js +29 -0
- package/dist/worker/console/static/index.html +1 -1
- package/dist/worker/observe/health.js +1 -0
- package/dist/worker/observe/night-jobs.js +104 -0
- package/dist/worker/observe/routes.js +48 -0
- package/dist/worker/observe/static/app.js +3 -0
- package/dist/worker/observe/static/constants.js +1 -0
- package/dist/worker/observe/static/index.html +47 -0
- package/dist/worker/observe/static/router.js +10 -0
- package/dist/worker/observe/static/shell-chrome.js +1 -0
- package/dist/worker/observe/static/views/night.js +201 -0
- package/dist/worker/report/morning-report.js +56 -16
- package/dist/worker/run-task/execute-prepared-task.js +153 -0
- package/dist/worker/runner/single-task-attempt.js +147 -0
- package/dist/worker/scheduler/admission.js +536 -0
- package/dist/worker/scheduler/auto-followup.js +99 -0
- package/dist/worker/scheduler/cli.js +539 -0
- package/dist/worker/scheduler/dispatcher.js +503 -0
- package/dist/worker/scheduler/doctor.js +346 -0
- package/dist/worker/scheduler/evidence.js +170 -0
- package/dist/worker/scheduler/git-base.js +52 -0
- package/dist/worker/scheduler/index.js +23 -0
- package/dist/worker/scheduler/lease.js +114 -0
- package/dist/worker/scheduler/lifecycle.js +348 -0
- package/dist/worker/scheduler/lock.js +80 -0
- package/dist/worker/scheduler/morning-window.js +161 -0
- package/dist/worker/scheduler/night-git-finalizer.js +88 -0
- package/dist/worker/scheduler/night-harvest.js +421 -0
- package/dist/worker/scheduler/paths.js +84 -0
- package/dist/worker/scheduler/prepared-attempt-recovery.js +471 -0
- package/dist/worker/scheduler/recovery.js +277 -0
- package/dist/worker/scheduler/reservation.js +146 -0
- package/dist/worker/scheduler/retry.js +199 -0
- package/dist/worker/scheduler/scheduler-loop.js +272 -0
- package/dist/worker/scheduler/store.js +275 -0
- package/dist/worker/scheduler/traceability.js +54 -0
- package/dist/worker/scheduler/trigger.js +258 -0
- package/dist/worker/scheduler/types.js +369 -0
- package/dist/worker/scheduler/workspace-adapter.js +91 -0
- package/dist/workflows/dag/frontend-implementation-contract.js +2 -102
- package/docs/architecture/runtime-boundaries.md +9 -0
- package/docs/init-surface.manifest.json +9 -2
- package/docs/templates/harness.schema.json +107 -0
- package/docs/templates/init-managed-agents.md +18 -8
- package/harness.json +22 -0
- package/package.json +1 -1
- package/skills/loop-agent/SKILL.md +28 -36
- package/skills/loop-agent/references/command-reference.md +40 -16
- package/skills/loop-agent/references/hybrid-dag.md +1 -1
- package/dist/worker/console/static/assets/index-CNO7n6qB.js +0 -29
|
@@ -23,6 +23,11 @@ import { issueHumanGateToken, mutationGatePayloadHash, verifyHumanGateToken, } f
|
|
|
23
23
|
const MUTATION_GATE_ACTIONS = new Set([
|
|
24
24
|
"standaloneTaskRerun",
|
|
25
25
|
"workerTaskRetry",
|
|
26
|
+
"workerAdmissionPrepare",
|
|
27
|
+
"workerSchedulerAdd",
|
|
28
|
+
"workerSchedulerCancel",
|
|
29
|
+
"workerSchedulerHarvest",
|
|
30
|
+
"workerSchedulerDiscard",
|
|
26
31
|
]);
|
|
27
32
|
const MUTATION_OR_LONG = new Set([
|
|
28
33
|
"newTask",
|
|
@@ -382,7 +387,13 @@ export async function dispatchOperatorAction(ctx, req) {
|
|
|
382
387
|
const notFound = body.ok === true && snap.exists === false;
|
|
383
388
|
return {
|
|
384
389
|
kind: "sync",
|
|
385
|
-
status: notFound
|
|
390
|
+
status: notFound
|
|
391
|
+
? 404
|
|
392
|
+
: body.ok
|
|
393
|
+
? 200
|
|
394
|
+
: body.outcome === "not-found"
|
|
395
|
+
? 404
|
|
396
|
+
: 400,
|
|
386
397
|
body: reshaped,
|
|
387
398
|
};
|
|
388
399
|
}
|
|
@@ -893,9 +904,8 @@ export async function dispatchOperatorAction(ctx, req) {
|
|
|
893
904
|
cliArgs: ["task", "advance", taskId, title, "--json"],
|
|
894
905
|
});
|
|
895
906
|
}
|
|
896
|
-
case "bootstrapFromPrd":
|
|
907
|
+
case "bootstrapFromPrd":
|
|
897
908
|
return dispatchBootstrapFromPrd(ctx, p);
|
|
898
|
-
}
|
|
899
909
|
case "importPrd": {
|
|
900
910
|
const taskId = str(p.taskId);
|
|
901
911
|
const content = str(p.content) ?? str(p.fileText);
|
|
@@ -1252,6 +1262,175 @@ export async function dispatchOperatorAction(ctx, req) {
|
|
|
1252
1262
|
await finalizeMutationGateReceipt(ctx, gated.receiptId, accepted);
|
|
1253
1263
|
return accepted;
|
|
1254
1264
|
}
|
|
1265
|
+
case "workerAdmissionPrepare": {
|
|
1266
|
+
const featureDir = str(p.featureDir);
|
|
1267
|
+
const taskId = str(p.taskId);
|
|
1268
|
+
const at = str(p.at);
|
|
1269
|
+
const tz = str(p.tz);
|
|
1270
|
+
const taskCard = str(p.taskCard);
|
|
1271
|
+
const clientRequestId = str(req.clientRequestId);
|
|
1272
|
+
if (!featureDir || !taskId || !at || !clientRequestId) {
|
|
1273
|
+
return invalid(action, "featureDir, taskId, at, and clientRequestId are required");
|
|
1274
|
+
}
|
|
1275
|
+
const gated = await consumeMutationGateReceipt(ctx, action, p);
|
|
1276
|
+
if (gated.kind === "error")
|
|
1277
|
+
return gated;
|
|
1278
|
+
if (gated.kind === "idempotent")
|
|
1279
|
+
return gated.result;
|
|
1280
|
+
const args = [
|
|
1281
|
+
"admission",
|
|
1282
|
+
"prepare",
|
|
1283
|
+
"--repo",
|
|
1284
|
+
ctx.repoRoot,
|
|
1285
|
+
"--feature-dir",
|
|
1286
|
+
featureDir,
|
|
1287
|
+
"--task-id",
|
|
1288
|
+
taskId,
|
|
1289
|
+
"--at",
|
|
1290
|
+
at,
|
|
1291
|
+
"--json",
|
|
1292
|
+
];
|
|
1293
|
+
if (tz)
|
|
1294
|
+
args.push("--tz", tz);
|
|
1295
|
+
if (taskCard)
|
|
1296
|
+
args.push("--task-card", taskCard);
|
|
1297
|
+
const accepted = await acceptOperation(ctx, {
|
|
1298
|
+
action,
|
|
1299
|
+
actionParams: p,
|
|
1300
|
+
clientRequestId,
|
|
1301
|
+
taskId,
|
|
1302
|
+
cliArgs: args,
|
|
1303
|
+
externalCommand: resolveSiblingAgentWorkerBin(),
|
|
1304
|
+
});
|
|
1305
|
+
await finalizeMutationGateReceipt(ctx, gated.receiptId, accepted);
|
|
1306
|
+
return accepted;
|
|
1307
|
+
}
|
|
1308
|
+
case "workerSchedulerAdd": {
|
|
1309
|
+
const scheduleId = str(p.scheduleId);
|
|
1310
|
+
const approveGate = str(p.approveGate);
|
|
1311
|
+
const clientRequestId = str(req.clientRequestId);
|
|
1312
|
+
if (!scheduleId || !approveGate || !clientRequestId) {
|
|
1313
|
+
return invalid(action, "scheduleId, approveGate, and clientRequestId are required");
|
|
1314
|
+
}
|
|
1315
|
+
const gated = await consumeMutationGateReceipt(ctx, action, p);
|
|
1316
|
+
if (gated.kind === "error")
|
|
1317
|
+
return gated;
|
|
1318
|
+
if (gated.kind === "idempotent")
|
|
1319
|
+
return gated.result;
|
|
1320
|
+
const accepted = await acceptOperation(ctx, {
|
|
1321
|
+
action,
|
|
1322
|
+
actionParams: p,
|
|
1323
|
+
clientRequestId,
|
|
1324
|
+
cliArgs: [
|
|
1325
|
+
"scheduler",
|
|
1326
|
+
"add",
|
|
1327
|
+
scheduleId,
|
|
1328
|
+
"--repo",
|
|
1329
|
+
ctx.repoRoot,
|
|
1330
|
+
"--approve-gate",
|
|
1331
|
+
approveGate,
|
|
1332
|
+
"--json",
|
|
1333
|
+
],
|
|
1334
|
+
externalCommand: resolveSiblingAgentWorkerBin(),
|
|
1335
|
+
});
|
|
1336
|
+
await finalizeMutationGateReceipt(ctx, gated.receiptId, accepted);
|
|
1337
|
+
return accepted;
|
|
1338
|
+
}
|
|
1339
|
+
case "workerSchedulerCancel": {
|
|
1340
|
+
const scheduleId = str(p.scheduleId);
|
|
1341
|
+
const reason = str(p.reason);
|
|
1342
|
+
const clientRequestId = str(req.clientRequestId);
|
|
1343
|
+
if (!scheduleId || !clientRequestId) {
|
|
1344
|
+
return invalid(action, "scheduleId and clientRequestId are required");
|
|
1345
|
+
}
|
|
1346
|
+
const gated = await consumeMutationGateReceipt(ctx, action, p);
|
|
1347
|
+
if (gated.kind === "error")
|
|
1348
|
+
return gated;
|
|
1349
|
+
if (gated.kind === "idempotent")
|
|
1350
|
+
return gated.result;
|
|
1351
|
+
const args = [
|
|
1352
|
+
"scheduler",
|
|
1353
|
+
"cancel",
|
|
1354
|
+
scheduleId,
|
|
1355
|
+
"--repo",
|
|
1356
|
+
ctx.repoRoot,
|
|
1357
|
+
"--json",
|
|
1358
|
+
];
|
|
1359
|
+
if (reason)
|
|
1360
|
+
args.push("--reason", reason);
|
|
1361
|
+
const accepted = await acceptOperation(ctx, {
|
|
1362
|
+
action,
|
|
1363
|
+
actionParams: p,
|
|
1364
|
+
clientRequestId,
|
|
1365
|
+
cliArgs: args,
|
|
1366
|
+
externalCommand: resolveSiblingAgentWorkerBin(),
|
|
1367
|
+
});
|
|
1368
|
+
await finalizeMutationGateReceipt(ctx, gated.receiptId, accepted);
|
|
1369
|
+
return accepted;
|
|
1370
|
+
}
|
|
1371
|
+
case "workerSchedulerHarvest": {
|
|
1372
|
+
const scheduleId = str(p.scheduleId);
|
|
1373
|
+
const clientRequestId = str(req.clientRequestId);
|
|
1374
|
+
if (!scheduleId || !clientRequestId) {
|
|
1375
|
+
return invalid(action, "scheduleId and clientRequestId are required");
|
|
1376
|
+
}
|
|
1377
|
+
const gated = await consumeMutationGateReceipt(ctx, action, p);
|
|
1378
|
+
if (gated.kind === "error")
|
|
1379
|
+
return gated;
|
|
1380
|
+
if (gated.kind === "idempotent")
|
|
1381
|
+
return gated.result;
|
|
1382
|
+
const accepted = await acceptOperation(ctx, {
|
|
1383
|
+
action,
|
|
1384
|
+
actionParams: p,
|
|
1385
|
+
clientRequestId,
|
|
1386
|
+
cliArgs: [
|
|
1387
|
+
"scheduler",
|
|
1388
|
+
"harvest",
|
|
1389
|
+
scheduleId,
|
|
1390
|
+
"--repo",
|
|
1391
|
+
ctx.repoRoot,
|
|
1392
|
+
"--json",
|
|
1393
|
+
],
|
|
1394
|
+
externalCommand: resolveSiblingAgentWorkerBin(),
|
|
1395
|
+
});
|
|
1396
|
+
await finalizeMutationGateReceipt(ctx, gated.receiptId, accepted);
|
|
1397
|
+
return accepted;
|
|
1398
|
+
}
|
|
1399
|
+
case "workerSchedulerDiscard": {
|
|
1400
|
+
const scheduleId = str(p.scheduleId);
|
|
1401
|
+
const reason = str(p.reason);
|
|
1402
|
+
const force = p.force === true;
|
|
1403
|
+
const clientRequestId = str(req.clientRequestId);
|
|
1404
|
+
if (!scheduleId || !reason || !clientRequestId) {
|
|
1405
|
+
return invalid(action, "scheduleId, reason, and clientRequestId are required");
|
|
1406
|
+
}
|
|
1407
|
+
const gated = await consumeMutationGateReceipt(ctx, action, p);
|
|
1408
|
+
if (gated.kind === "error")
|
|
1409
|
+
return gated;
|
|
1410
|
+
if (gated.kind === "idempotent")
|
|
1411
|
+
return gated.result;
|
|
1412
|
+
const args = [
|
|
1413
|
+
"scheduler",
|
|
1414
|
+
"discard",
|
|
1415
|
+
scheduleId,
|
|
1416
|
+
"--repo",
|
|
1417
|
+
ctx.repoRoot,
|
|
1418
|
+
"--reason",
|
|
1419
|
+
reason,
|
|
1420
|
+
"--json",
|
|
1421
|
+
];
|
|
1422
|
+
if (force)
|
|
1423
|
+
args.push("--force");
|
|
1424
|
+
const accepted = await acceptOperation(ctx, {
|
|
1425
|
+
action,
|
|
1426
|
+
actionParams: p,
|
|
1427
|
+
clientRequestId,
|
|
1428
|
+
cliArgs: args,
|
|
1429
|
+
externalCommand: resolveSiblingAgentWorkerBin(),
|
|
1430
|
+
});
|
|
1431
|
+
await finalizeMutationGateReceipt(ctx, gated.receiptId, accepted);
|
|
1432
|
+
return accepted;
|
|
1433
|
+
}
|
|
1255
1434
|
case "prepareMutationGate": {
|
|
1256
1435
|
const targetAction = str(p.action);
|
|
1257
1436
|
const actionParams = p.actionParams &&
|
|
@@ -1263,7 +1442,7 @@ export async function dispatchOperatorAction(ctx, req) {
|
|
|
1263
1442
|
return invalid(action, "action and actionParams are required");
|
|
1264
1443
|
}
|
|
1265
1444
|
if (!MUTATION_GATE_ACTIONS.has(targetAction)) {
|
|
1266
|
-
return invalid(action, "action must be standaloneTaskRerun
|
|
1445
|
+
return invalid(action, "action must be a mutation-gate target (standaloneTaskRerun | workerTaskRetry | workerAdmissionPrepare | workerSchedulerAdd | workerSchedulerCancel | workerSchedulerHarvest | workerSchedulerDiscard)");
|
|
1267
1446
|
}
|
|
1268
1447
|
const secret = ctx.humanGateSecret;
|
|
1269
1448
|
if (!secret) {
|
|
@@ -20,6 +20,10 @@ export function encodeInspectHash(selection) {
|
|
|
20
20
|
return `#/run/${segment(selection.workerRunId)}`;
|
|
21
21
|
case "batch":
|
|
22
22
|
return `#/batch/${segment(selection.batchRunId)}`;
|
|
23
|
+
case "night-jobs":
|
|
24
|
+
return `#/night`;
|
|
25
|
+
case "night-job":
|
|
26
|
+
return `#/night/${segment(selection.scheduleId)}`;
|
|
23
27
|
}
|
|
24
28
|
}
|
|
25
29
|
export function buildInspectPath(selection) {
|
|
@@ -48,6 +52,9 @@ export function decodeInspectHash(hash) {
|
|
|
48
52
|
if (parts.length === 0)
|
|
49
53
|
return null;
|
|
50
54
|
const [kind, first, third, fourth] = parts;
|
|
55
|
+
// Collection views without an id segment (e.g. #/night).
|
|
56
|
+
if (kind === "night" && parts.length === 1)
|
|
57
|
+
return { kind: "night-jobs" };
|
|
51
58
|
const id = decodeSegment(first);
|
|
52
59
|
if (!id)
|
|
53
60
|
return null;
|
|
@@ -66,6 +73,8 @@ export function decodeInspectHash(hash) {
|
|
|
66
73
|
return { kind: "worker-run", workerRunId: id };
|
|
67
74
|
if (kind === "batch" && parts.length === 2)
|
|
68
75
|
return { kind: "batch", batchRunId: id };
|
|
76
|
+
if (kind === "night" && parts.length === 2)
|
|
77
|
+
return { kind: "night-job", scheduleId: id };
|
|
69
78
|
return null;
|
|
70
79
|
}
|
|
71
80
|
export function selectionFromObserveLinkTarget(target) {
|
|
@@ -80,6 +89,10 @@ export function selectionFromObserveLinkTarget(target) {
|
|
|
80
89
|
return { kind: "worker-run", workerRunId: target.workerRunId };
|
|
81
90
|
case "batch":
|
|
82
91
|
return { kind: "batch", batchRunId: target.batchRunId };
|
|
92
|
+
case "night":
|
|
93
|
+
return target.scheduleId
|
|
94
|
+
? { kind: "night-job", scheduleId: target.scheduleId }
|
|
95
|
+
: { kind: "night-jobs" };
|
|
83
96
|
}
|
|
84
97
|
}
|
|
85
98
|
/** Canonicalize only the historical Console root hash shape. */
|