@useorgx/openclaw-plugin 0.7.15 → 0.7.16
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/dashboard/dist/assets/8pbG6uLK.js +1 -0
- package/dashboard/dist/assets/8pbG6uLK.js.br +0 -0
- package/dashboard/dist/assets/8pbG6uLK.js.gz +0 -0
- package/dashboard/dist/assets/B1LENRC8.js +212 -0
- package/dashboard/dist/assets/B1LENRC8.js.br +0 -0
- package/dashboard/dist/assets/B1LENRC8.js.gz +0 -0
- package/dashboard/dist/assets/{gZr_xKlA.js → BM75sh1f.js} +1 -1
- package/dashboard/dist/assets/BM75sh1f.js.br +0 -0
- package/dashboard/dist/assets/BM75sh1f.js.gz +0 -0
- package/dashboard/dist/assets/{CJjEAGFN.js → BYVYH9CH.js} +1 -1
- package/dashboard/dist/assets/BYVYH9CH.js.br +0 -0
- package/dashboard/dist/assets/BYVYH9CH.js.gz +0 -0
- package/dashboard/dist/assets/BkMrrjAv.js +1 -0
- package/dashboard/dist/assets/BkMrrjAv.js.br +0 -0
- package/dashboard/dist/assets/BkMrrjAv.js.gz +0 -0
- package/dashboard/dist/assets/BpF7v1Dk.js +1 -0
- package/dashboard/dist/assets/BpF7v1Dk.js.br +0 -0
- package/dashboard/dist/assets/BpF7v1Dk.js.gz +0 -0
- package/dashboard/dist/assets/{C9fvfXmS.js → Bv_86bUY.js} +1 -1
- package/dashboard/dist/assets/Bv_86bUY.js.br +0 -0
- package/dashboard/dist/assets/Bv_86bUY.js.gz +0 -0
- package/dashboard/dist/assets/{CFZ4Swr5.js → C3PrI8L7.js} +1 -1
- package/dashboard/dist/assets/C3PrI8L7.js.br +0 -0
- package/dashboard/dist/assets/C3PrI8L7.js.gz +0 -0
- package/dashboard/dist/assets/{C91KLKit.js → C6AqbA9J.js} +1 -1
- package/dashboard/dist/assets/C6AqbA9J.js.br +0 -0
- package/dashboard/dist/assets/C6AqbA9J.js.gz +0 -0
- package/dashboard/dist/assets/{7DhYqBrM.js → CUXb_4F3.js} +1 -1
- package/dashboard/dist/assets/CUXb_4F3.js.br +0 -0
- package/dashboard/dist/assets/CUXb_4F3.js.gz +0 -0
- package/dashboard/dist/assets/{3TtV4moZ.js → Cn8sRTkO.js} +1 -1
- package/dashboard/dist/assets/Cn8sRTkO.js.br +0 -0
- package/dashboard/dist/assets/Cn8sRTkO.js.gz +0 -0
- package/dashboard/dist/assets/{CnPC783_.js → D5IgXoTj.js} +1 -1
- package/dashboard/dist/assets/D5IgXoTj.js.br +0 -0
- package/dashboard/dist/assets/D5IgXoTj.js.gz +0 -0
- package/dashboard/dist/assets/DMKyYAtD.js +1 -0
- package/dashboard/dist/assets/DMKyYAtD.js.br +0 -0
- package/dashboard/dist/assets/DMKyYAtD.js.gz +0 -0
- package/dashboard/dist/assets/{CGj8kRhg.js → DXzpQUC0.js} +1 -1
- package/dashboard/dist/assets/DXzpQUC0.js.br +0 -0
- package/dashboard/dist/assets/DXzpQUC0.js.gz +0 -0
- package/dashboard/dist/assets/JDPvhd68.js +1 -0
- package/dashboard/dist/assets/JDPvhd68.js.br +0 -0
- package/dashboard/dist/assets/JDPvhd68.js.gz +0 -0
- package/dashboard/dist/assets/{3VwNyxUf.js → R6N_VVqm.js} +1 -1
- package/dashboard/dist/assets/R6N_VVqm.js.br +0 -0
- package/dashboard/dist/assets/R6N_VVqm.js.gz +0 -0
- package/dashboard/dist/assets/{CKrH5fYO.js → cEP7N1dn.js} +1 -1
- package/dashboard/dist/assets/cEP7N1dn.js.br +0 -0
- package/dashboard/dist/assets/cEP7N1dn.js.gz +0 -0
- package/dashboard/dist/assets/iLnvdWmW.css +1 -0
- package/dashboard/dist/assets/iLnvdWmW.css.br +0 -0
- package/dashboard/dist/assets/iLnvdWmW.css.gz +0 -0
- package/dashboard/dist/assets/{Ctw95IkC.js → konqMbVI.js} +1 -1
- package/dashboard/dist/assets/konqMbVI.js.br +0 -0
- package/dashboard/dist/assets/konqMbVI.js.gz +0 -0
- package/dashboard/dist/assets/{T2NFtzAv.js → wc6cgXzV.js} +1 -1
- package/dashboard/dist/assets/wc6cgXzV.js.br +0 -0
- package/dashboard/dist/assets/wc6cgXzV.js.gz +0 -0
- package/dashboard/dist/index.html +3 -3
- package/dashboard/dist/index.html.br +0 -0
- package/dashboard/dist/index.html.gz +0 -0
- package/dist/http/helpers/auto-continue-engine.d.ts +15 -0
- package/dist/http/helpers/auto-continue-engine.js +165 -0
- package/dist/http/helpers/mission-control.d.ts +3 -0
- package/dist/http/helpers/mission-control.js +38 -7
- package/dist/http/helpers/value-utils.d.ts +1 -1
- package/dist/http/helpers/value-utils.js +5 -2
- package/dist/http/index.js +3 -1
- package/dist/http/routes/chat.d.ts +1 -1
- package/dist/http/routes/chat.js +2 -2
- package/dist/http/routes/entities.js +60 -2
- package/dist/http/routes/entity-dynamic.js +49 -9
- package/dist/http/routes/live-snapshot.d.ts +10 -1
- package/dist/http/routes/live-snapshot.js +11 -3
- package/dist/http/routes/mission-control-actions.d.ts +6 -0
- package/dist/http/routes/mission-control-actions.js +33 -0
- package/package.json +1 -1
- package/dashboard/dist/assets/0RUEVzJa.js +0 -1
- package/dashboard/dist/assets/0RUEVzJa.js.br +0 -0
- package/dashboard/dist/assets/0RUEVzJa.js.gz +0 -0
- package/dashboard/dist/assets/3TtV4moZ.js.br +0 -0
- package/dashboard/dist/assets/3TtV4moZ.js.gz +0 -0
- package/dashboard/dist/assets/3VwNyxUf.js.br +0 -0
- package/dashboard/dist/assets/3VwNyxUf.js.gz +0 -0
- package/dashboard/dist/assets/7DhYqBrM.js.br +0 -0
- package/dashboard/dist/assets/7DhYqBrM.js.gz +0 -0
- package/dashboard/dist/assets/BVvffj0x.js +0 -1
- package/dashboard/dist/assets/BVvffj0x.js.br +0 -0
- package/dashboard/dist/assets/BVvffj0x.js.gz +0 -0
- package/dashboard/dist/assets/BiOgVMED.js +0 -1
- package/dashboard/dist/assets/BiOgVMED.js.br +0 -0
- package/dashboard/dist/assets/BiOgVMED.js.gz +0 -0
- package/dashboard/dist/assets/C91KLKit.js.br +0 -0
- package/dashboard/dist/assets/C91KLKit.js.gz +0 -0
- package/dashboard/dist/assets/C9fvfXmS.js.br +0 -0
- package/dashboard/dist/assets/C9fvfXmS.js.gz +0 -0
- package/dashboard/dist/assets/CFZ4Swr5.js.br +0 -0
- package/dashboard/dist/assets/CFZ4Swr5.js.gz +0 -0
- package/dashboard/dist/assets/CGj8kRhg.js.br +0 -0
- package/dashboard/dist/assets/CGj8kRhg.js.gz +0 -0
- package/dashboard/dist/assets/CJjEAGFN.js.br +0 -0
- package/dashboard/dist/assets/CJjEAGFN.js.gz +0 -0
- package/dashboard/dist/assets/CKrH5fYO.js.br +0 -0
- package/dashboard/dist/assets/CKrH5fYO.js.gz +0 -0
- package/dashboard/dist/assets/CMTTPXch.js +0 -1
- package/dashboard/dist/assets/CMTTPXch.js.br +0 -0
- package/dashboard/dist/assets/CMTTPXch.js.gz +0 -0
- package/dashboard/dist/assets/CnPC783_.js.br +0 -0
- package/dashboard/dist/assets/CnPC783_.js.gz +0 -0
- package/dashboard/dist/assets/Ctw95IkC.js.br +0 -0
- package/dashboard/dist/assets/Ctw95IkC.js.gz +0 -0
- package/dashboard/dist/assets/DHz-aQPw.js +0 -1
- package/dashboard/dist/assets/DHz-aQPw.js.br +0 -0
- package/dashboard/dist/assets/DHz-aQPw.js.gz +0 -0
- package/dashboard/dist/assets/DNX2foSJ.css +0 -1
- package/dashboard/dist/assets/DNX2foSJ.css.br +0 -0
- package/dashboard/dist/assets/DNX2foSJ.css.gz +0 -0
- package/dashboard/dist/assets/DxUw4FMR.js +0 -212
- package/dashboard/dist/assets/DxUw4FMR.js.br +0 -0
- package/dashboard/dist/assets/DxUw4FMR.js.gz +0 -0
- package/dashboard/dist/assets/T2NFtzAv.js.br +0 -0
- package/dashboard/dist/assets/T2NFtzAv.js.gz +0 -0
- package/dashboard/dist/assets/gZr_xKlA.js.br +0 -0
- package/dashboard/dist/assets/gZr_xKlA.js.gz +0 -0
|
@@ -485,6 +485,21 @@ export declare function createAutoContinueEngine(deps: CreateAutoContinueEngineD
|
|
|
485
485
|
activeRunId: string | null;
|
|
486
486
|
activeTaskTokenEstimate: number | null;
|
|
487
487
|
}>;
|
|
488
|
+
skipCurrentWorkstream: (initiativeId: string, workstreamId: string, reason?: string) => Promise<{
|
|
489
|
+
ok: boolean;
|
|
490
|
+
skippedWorkstreamId: string;
|
|
491
|
+
nextWorkstreamId?: string;
|
|
492
|
+
nextWorkstreamTitle?: string;
|
|
493
|
+
}>;
|
|
494
|
+
getCanonicalAutopilotState: (initiativeId: string) => {
|
|
495
|
+
state: "idle" | "running" | "blocked" | "stopping";
|
|
496
|
+
reason: string | null;
|
|
497
|
+
activeRunId: string | null;
|
|
498
|
+
activeWorkstreamId: string | null;
|
|
499
|
+
activeWorkstreamTitle: string | null;
|
|
500
|
+
queueHeadTitle: string | null;
|
|
501
|
+
lastTransitionAt: string;
|
|
502
|
+
} | null;
|
|
488
503
|
workstreamSessionStore: Map<string, {
|
|
489
504
|
sessionId: string;
|
|
490
505
|
workstreamId: string;
|
|
@@ -1554,6 +1554,20 @@ export function createAutoContinueEngine(deps) {
|
|
|
1554
1554
|
decision_count: decisionIds.length,
|
|
1555
1555
|
last_error: input.run.lastError,
|
|
1556
1556
|
error_location: errorLocation,
|
|
1557
|
+
...(input.reason === "blocked" || input.reason === "error"
|
|
1558
|
+
? {
|
|
1559
|
+
blocker: {
|
|
1560
|
+
kind: decisionRequired ? "decision_required" : "error",
|
|
1561
|
+
summary: input.error ?? input.run.lastError ?? "Execution blocked",
|
|
1562
|
+
required_actor: decisionRequired ? "user" : "system",
|
|
1563
|
+
required_action: decisionRequired
|
|
1564
|
+
? "Resolve the pending decision in Decisions panel"
|
|
1565
|
+
: "Review the error and retry",
|
|
1566
|
+
can_skip: true,
|
|
1567
|
+
skip_route: "/orgx/api/autopilot/skip",
|
|
1568
|
+
},
|
|
1569
|
+
}
|
|
1570
|
+
: {}),
|
|
1557
1571
|
},
|
|
1558
1572
|
});
|
|
1559
1573
|
// Emit autopilot_transition event for state observers.
|
|
@@ -2278,12 +2292,53 @@ export function createAutoContinueEngine(deps) {
|
|
|
2278
2292
|
...mockMeta(slice),
|
|
2279
2293
|
user_summary: userSummary,
|
|
2280
2294
|
next_actions: nextActions,
|
|
2295
|
+
outcomes: {
|
|
2296
|
+
pr_url: typeof parsed?.pr_url === "string" ? parsed.pr_url : null,
|
|
2297
|
+
pr_number: typeof parsed?.pr_number === "number" ? parsed.pr_number : null,
|
|
2298
|
+
commit_sha: typeof parsed?.commit_sha === "string" ? parsed.commit_sha : null,
|
|
2299
|
+
commit_url: typeof parsed?.commit_url === "string" ? parsed.commit_url : null,
|
|
2300
|
+
tests: null,
|
|
2301
|
+
artifact_ids: artifacts.map((a) => a.name).filter(Boolean),
|
|
2302
|
+
task_updates: taskUpdates?.length ?? 0,
|
|
2303
|
+
},
|
|
2281
2304
|
},
|
|
2282
2305
|
});
|
|
2283
2306
|
}
|
|
2284
2307
|
catch {
|
|
2285
2308
|
// best effort
|
|
2286
2309
|
}
|
|
2310
|
+
// Emit explicit session completion event for canonical agent panel state
|
|
2311
|
+
if (slice.status === "completed" || reportedParsedStatus === "completed") {
|
|
2312
|
+
await emitActivitySafe({
|
|
2313
|
+
initiativeId: run.initiativeId,
|
|
2314
|
+
runId: slice.runId,
|
|
2315
|
+
correlationId: slice.runId,
|
|
2316
|
+
phase: "completed",
|
|
2317
|
+
level: "info",
|
|
2318
|
+
message: userSummary ?? `Completed work on ${slice.workstreamTitle ?? "task"}`,
|
|
2319
|
+
metadata: {
|
|
2320
|
+
...buildSliceEnrichment({
|
|
2321
|
+
run,
|
|
2322
|
+
slice,
|
|
2323
|
+
workstreamId: slice.workstreamId,
|
|
2324
|
+
workstreamTitle: slice.workstreamTitle ?? null,
|
|
2325
|
+
domain: slice.domain,
|
|
2326
|
+
requiredSkills: slice.requiredSkills,
|
|
2327
|
+
userSummary,
|
|
2328
|
+
event: "session_completed",
|
|
2329
|
+
}),
|
|
2330
|
+
session_id: slice.cliSessionId ?? null,
|
|
2331
|
+
source_client: slice.sourceClient,
|
|
2332
|
+
workstream_title: slice.workstreamTitle ?? null,
|
|
2333
|
+
task_title: slice.workstreamTitle ?? slice.workstreamId,
|
|
2334
|
+
duration_ms: slice.finishedAt
|
|
2335
|
+
? new Date(slice.finishedAt).getTime() - new Date(slice.startedAt).getTime()
|
|
2336
|
+
: null,
|
|
2337
|
+
outcome: reportedParsedStatus ?? slice.status,
|
|
2338
|
+
artifacts_produced: artifacts.length,
|
|
2339
|
+
},
|
|
2340
|
+
});
|
|
2341
|
+
}
|
|
2287
2342
|
if (slice.status === "completed") {
|
|
2288
2343
|
await emitActivitySafe({
|
|
2289
2344
|
initiativeId: run.initiativeId,
|
|
@@ -2754,8 +2809,11 @@ export function createAutoContinueEngine(deps) {
|
|
|
2754
2809
|
};
|
|
2755
2810
|
// Select the next eligible workstream by scanning ordered todos.
|
|
2756
2811
|
let selectedWorkstreamId = null;
|
|
2812
|
+
let selectedQueueRank = 0;
|
|
2757
2813
|
let deferredBySpawnGuardRateLimit = 0;
|
|
2814
|
+
let queueScanIndex = 0;
|
|
2758
2815
|
for (const taskId of graph.recentTodos) {
|
|
2816
|
+
queueScanIndex++;
|
|
2759
2817
|
const node = nodeById.get(taskId);
|
|
2760
2818
|
if (!node || node.type !== "task")
|
|
2761
2819
|
continue;
|
|
@@ -2797,6 +2855,7 @@ export function createAutoContinueEngine(deps) {
|
|
|
2797
2855
|
continue;
|
|
2798
2856
|
}
|
|
2799
2857
|
selectedWorkstreamId = node.workstreamId;
|
|
2858
|
+
selectedQueueRank = queueScanIndex + 1;
|
|
2800
2859
|
break;
|
|
2801
2860
|
}
|
|
2802
2861
|
if (!selectedWorkstreamId) {
|
|
@@ -3675,6 +3734,10 @@ export function createAutoContinueEngine(deps) {
|
|
|
3675
3734
|
scope_milestone_ids: slice.scopeMilestoneIds,
|
|
3676
3735
|
log_path: logPath,
|
|
3677
3736
|
output_path: outputPath,
|
|
3737
|
+
dispatch_queue_rank: selectedQueueRank > 0 ? selectedQueueRank : null,
|
|
3738
|
+
dispatch_workstream_title: workstreamTitle ?? null,
|
|
3739
|
+
dispatch_task_title: primaryTask.title ?? null,
|
|
3740
|
+
dispatch_selection_reason: "top_of_queue",
|
|
3678
3741
|
...mockMeta(slice),
|
|
3679
3742
|
},
|
|
3680
3743
|
});
|
|
@@ -3714,6 +3777,10 @@ export function createAutoContinueEngine(deps) {
|
|
|
3714
3777
|
scope_milestone_ids: slice.scopeMilestoneIds,
|
|
3715
3778
|
log_path: logPath,
|
|
3716
3779
|
output_path: outputPath,
|
|
3780
|
+
dispatch_queue_rank: selectedQueueRank > 0 ? selectedQueueRank : null,
|
|
3781
|
+
dispatch_workstream_title: workstreamTitle ?? null,
|
|
3782
|
+
dispatch_task_title: primaryTask.title ?? null,
|
|
3783
|
+
dispatch_selection_reason: "top_of_queue",
|
|
3717
3784
|
...mockMeta(slice),
|
|
3718
3785
|
},
|
|
3719
3786
|
});
|
|
@@ -4286,6 +4353,102 @@ export function createAutoContinueEngine(deps) {
|
|
|
4286
4353
|
}
|
|
4287
4354
|
return run;
|
|
4288
4355
|
}
|
|
4356
|
+
async function skipCurrentWorkstream(initiativeId, workstreamId, reason) {
|
|
4357
|
+
const run = autoContinueRuns.get(initiativeId) ?? null;
|
|
4358
|
+
if (!run) {
|
|
4359
|
+
return { ok: false, skippedWorkstreamId: workstreamId };
|
|
4360
|
+
}
|
|
4361
|
+
ensureRunInternals(run);
|
|
4362
|
+
if (!run.blockedWorkstreamIds.includes(workstreamId)) {
|
|
4363
|
+
run.blockedWorkstreamIds.push(workstreamId);
|
|
4364
|
+
}
|
|
4365
|
+
setLaneState(run, {
|
|
4366
|
+
workstreamId,
|
|
4367
|
+
state: LaneState.BLOCKED,
|
|
4368
|
+
activeRunId: null,
|
|
4369
|
+
activeTaskIds: [],
|
|
4370
|
+
blockedReason: reason ?? "Skipped by user",
|
|
4371
|
+
waitingOnWorkstreamIds: [],
|
|
4372
|
+
retryAt: null,
|
|
4373
|
+
});
|
|
4374
|
+
run.updatedAt = new Date().toISOString();
|
|
4375
|
+
try {
|
|
4376
|
+
await emitActivitySafe({
|
|
4377
|
+
initiativeId,
|
|
4378
|
+
runId: run.lastRunId ?? undefined,
|
|
4379
|
+
correlationId: run.lastRunId ?? undefined,
|
|
4380
|
+
phase: "review",
|
|
4381
|
+
level: "info",
|
|
4382
|
+
message: `Workstream ${workstreamId} skipped${reason ? `: ${reason}` : ""}.`,
|
|
4383
|
+
metadata: {
|
|
4384
|
+
...buildSliceEnrichment({
|
|
4385
|
+
run,
|
|
4386
|
+
workstreamId,
|
|
4387
|
+
event: "autopilot_item_skipped",
|
|
4388
|
+
}),
|
|
4389
|
+
skipped_workstream_id: workstreamId,
|
|
4390
|
+
skip_reason: reason ?? null,
|
|
4391
|
+
},
|
|
4392
|
+
});
|
|
4393
|
+
}
|
|
4394
|
+
catch {
|
|
4395
|
+
// best effort
|
|
4396
|
+
}
|
|
4397
|
+
// Re-enable the run if it was stopped due to the blocked workstream.
|
|
4398
|
+
if (run.status === RunStatus.STOPPED && run.stopReason === "blocked") {
|
|
4399
|
+
run.status = RunStatus.RUNNING;
|
|
4400
|
+
run.stopReason = null;
|
|
4401
|
+
run.stoppedAt = null;
|
|
4402
|
+
run.stopRequested = false;
|
|
4403
|
+
run.lastError = null;
|
|
4404
|
+
}
|
|
4405
|
+
// Trigger the next tick to pick up a different workstream.
|
|
4406
|
+
try {
|
|
4407
|
+
await tickAutoContinueRun(run);
|
|
4408
|
+
}
|
|
4409
|
+
catch {
|
|
4410
|
+
// best effort
|
|
4411
|
+
}
|
|
4412
|
+
// Determine what the next workstream is, if any.
|
|
4413
|
+
const nextLane = Object.values(run.laneByWorkstreamId ?? {}).find((lane) => lane.state === LaneState.RUNNING && lane.workstreamId !== workstreamId) ?? null;
|
|
4414
|
+
return {
|
|
4415
|
+
ok: true,
|
|
4416
|
+
skippedWorkstreamId: workstreamId,
|
|
4417
|
+
nextWorkstreamId: nextLane?.workstreamId ?? undefined,
|
|
4418
|
+
nextWorkstreamTitle: undefined,
|
|
4419
|
+
};
|
|
4420
|
+
}
|
|
4421
|
+
function getCanonicalAutopilotState(initiativeId) {
|
|
4422
|
+
const run = autoContinueRuns.get(initiativeId) ?? null;
|
|
4423
|
+
if (!run)
|
|
4424
|
+
return null;
|
|
4425
|
+
const canonicalState = run.status === RunStatus.RUNNING
|
|
4426
|
+
? "running"
|
|
4427
|
+
: run.status === RunStatus.STOPPING
|
|
4428
|
+
? "stopping"
|
|
4429
|
+
: run.stopReason === "blocked" || run.stopReason === "error"
|
|
4430
|
+
? "blocked"
|
|
4431
|
+
: "idle";
|
|
4432
|
+
const reason = canonicalState === "blocked"
|
|
4433
|
+
? run.lastError ?? run.stopReason ?? null
|
|
4434
|
+
: canonicalState === "stopping"
|
|
4435
|
+
? "stop_requested"
|
|
4436
|
+
: null;
|
|
4437
|
+
// Find the first active slice to identify the current workstream.
|
|
4438
|
+
const activeSliceRunId = (run.activeSliceRunIds ?? [])[0] ?? run.activeRunId ?? null;
|
|
4439
|
+
const activeSlice = activeSliceRunId
|
|
4440
|
+
? autoContinueSliceRuns.get(activeSliceRunId) ?? null
|
|
4441
|
+
: null;
|
|
4442
|
+
return {
|
|
4443
|
+
state: canonicalState,
|
|
4444
|
+
reason,
|
|
4445
|
+
activeRunId: activeSliceRunId,
|
|
4446
|
+
activeWorkstreamId: activeSlice?.workstreamId ?? null,
|
|
4447
|
+
activeWorkstreamTitle: activeSlice?.workstreamTitle ?? null,
|
|
4448
|
+
queueHeadTitle: activeSlice?.workstreamTitle ?? null,
|
|
4449
|
+
lastTransitionAt: run.updatedAt ?? run.startedAt,
|
|
4450
|
+
};
|
|
4451
|
+
}
|
|
4289
4452
|
return {
|
|
4290
4453
|
autoContinueRuns,
|
|
4291
4454
|
autoContinueSliceRuns,
|
|
@@ -4307,6 +4470,8 @@ export function createAutoContinueEngine(deps) {
|
|
|
4307
4470
|
getAutoContinueLaneForWorkstream,
|
|
4308
4471
|
scheduleAutoFixForWorkstream,
|
|
4309
4472
|
startAutoContinueRun,
|
|
4473
|
+
skipCurrentWorkstream,
|
|
4474
|
+
getCanonicalAutopilotState,
|
|
4310
4475
|
// Session store (for resume support)
|
|
4311
4476
|
workstreamSessionStore,
|
|
4312
4477
|
getWorkstreamSession,
|
|
@@ -87,7 +87,10 @@ export declare const DEFAULT_TOKEN_BUDGET_ASSUMPTIONS: {
|
|
|
87
87
|
export declare function pickStringArray(record: Record<string, unknown>, keys: string[]): string[];
|
|
88
88
|
export declare function dedupeStrings(items: string[]): string[];
|
|
89
89
|
export declare function isTodoStatus(status: string): boolean;
|
|
90
|
+
export declare function isPausedStatus(status: string): boolean;
|
|
91
|
+
export declare function isBlockedStatus(status: string): boolean;
|
|
90
92
|
export declare function isInProgressStatus(status: string): boolean;
|
|
93
|
+
export declare function deriveInitiativeLifecycleStatus(currentStatus: string, childStatuses: string[]): string;
|
|
91
94
|
export declare function isDispatchableWorkstreamStatus(status: string): boolean;
|
|
92
95
|
export declare function isDoneStatus(status: string): boolean;
|
|
93
96
|
export declare function listEntitiesSafe(client: OrgXClient, type: MissionControlNodeType, filters: Record<string, unknown>): Promise<{
|
|
@@ -637,6 +637,18 @@ export function isTodoStatus(status) {
|
|
|
637
637
|
normalized === "backlog" ||
|
|
638
638
|
normalized === "pending");
|
|
639
639
|
}
|
|
640
|
+
export function isPausedStatus(status) {
|
|
641
|
+
const normalized = status.toLowerCase();
|
|
642
|
+
return (normalized === "paused" ||
|
|
643
|
+
normalized === "idle" ||
|
|
644
|
+
normalized === "hold" ||
|
|
645
|
+
normalized === "on_hold" ||
|
|
646
|
+
normalized === "waiting");
|
|
647
|
+
}
|
|
648
|
+
export function isBlockedStatus(status) {
|
|
649
|
+
const normalized = status.toLowerCase();
|
|
650
|
+
return normalized === "blocked" || normalized === "at_risk" || normalized === "needs_input";
|
|
651
|
+
}
|
|
640
652
|
export function isInProgressStatus(status) {
|
|
641
653
|
const normalized = status.toLowerCase();
|
|
642
654
|
return (normalized === "in_progress" ||
|
|
@@ -644,6 +656,30 @@ export function isInProgressStatus(status) {
|
|
|
644
656
|
normalized === "running" ||
|
|
645
657
|
normalized === "queued");
|
|
646
658
|
}
|
|
659
|
+
export function deriveInitiativeLifecycleStatus(currentStatus, childStatuses) {
|
|
660
|
+
const normalizedCurrent = currentStatus.toLowerCase();
|
|
661
|
+
if (!childStatuses.length)
|
|
662
|
+
return currentStatus;
|
|
663
|
+
const hasInProgressChildren = childStatuses.some((status) => isInProgressStatus(status));
|
|
664
|
+
const hasRemainingChildren = childStatuses.some((status) => !isDoneStatus(status));
|
|
665
|
+
const hasBlockedChildren = childStatuses.some((status) => isBlockedStatus(status));
|
|
666
|
+
const hasPausedChildren = childStatuses.some((status) => isPausedStatus(status));
|
|
667
|
+
const hasTodoChildren = childStatuses.some((status) => isTodoStatus(status));
|
|
668
|
+
const isActiveLikeCurrent = normalizedCurrent === "active" ||
|
|
669
|
+
normalizedCurrent === "running" ||
|
|
670
|
+
normalizedCurrent === "in_progress" ||
|
|
671
|
+
normalizedCurrent === "queued";
|
|
672
|
+
if (!hasInProgressChildren && isActiveLikeCurrent && hasRemainingChildren) {
|
|
673
|
+
if (hasBlockedChildren && !hasPausedChildren && !hasTodoChildren) {
|
|
674
|
+
return "blocked";
|
|
675
|
+
}
|
|
676
|
+
return "paused";
|
|
677
|
+
}
|
|
678
|
+
if (hasInProgressChildren && (normalizedCurrent === "paused" || normalizedCurrent === "idle")) {
|
|
679
|
+
return "active";
|
|
680
|
+
}
|
|
681
|
+
return currentStatus;
|
|
682
|
+
}
|
|
647
683
|
export function isDispatchableWorkstreamStatus(status) {
|
|
648
684
|
const normalized = status.toLowerCase();
|
|
649
685
|
if (!normalized)
|
|
@@ -889,13 +925,8 @@ export async function buildMissionControlGraph(client, initiativeId, options) {
|
|
|
889
925
|
}
|
|
890
926
|
}
|
|
891
927
|
const taskNodesOnly = nodes.filter((node) => node.type === "task");
|
|
892
|
-
const
|
|
893
|
-
|
|
894
|
-
if (initiativeNode.status.toLowerCase() === "active" &&
|
|
895
|
-
!hasActiveTasks &&
|
|
896
|
-
hasTodoTasks) {
|
|
897
|
-
initiativeNode.status = "paused";
|
|
898
|
-
}
|
|
928
|
+
const lifecycleChildren = taskNodesOnly.length > 0 ? taskNodesOnly : workstreamNodes;
|
|
929
|
+
initiativeNode.status = deriveInitiativeLifecycleStatus(initiativeNode.status, lifecycleChildren.map((node) => node.status));
|
|
899
930
|
const nodeById = new Map(nodes.map((node) => [node.id, node]));
|
|
900
931
|
const taskIsReady = (task) => task.dependencyIds.every((depId) => {
|
|
901
932
|
const dependency = nodeById.get(depId);
|
|
@@ -2,5 +2,5 @@ export declare function pickString(record: Record<string, unknown>, keys: string
|
|
|
2
2
|
export declare function pickNumber(record: Record<string, unknown>, keys: string[]): number | null;
|
|
3
3
|
export declare function pickHeaderString(headers: Record<string, string | string[] | undefined>, keys: string[]): string | null;
|
|
4
4
|
export declare function toIsoString(value: string | null): string | null;
|
|
5
|
-
export declare function parsePositiveInt(raw: string | null, fallback: number): number;
|
|
5
|
+
export declare function parsePositiveInt(raw: string | null, fallback: number, max?: number): number;
|
|
6
6
|
export declare function parseBooleanQuery(raw: string | null): boolean;
|
|
@@ -48,7 +48,7 @@ export function toIsoString(value) {
|
|
|
48
48
|
return null;
|
|
49
49
|
return new Date(parsed).toISOString();
|
|
50
50
|
}
|
|
51
|
-
export function parsePositiveInt(raw, fallback) {
|
|
51
|
+
export function parsePositiveInt(raw, fallback, max = Number.POSITIVE_INFINITY) {
|
|
52
52
|
if (!raw)
|
|
53
53
|
return fallback;
|
|
54
54
|
const normalized = raw.trim();
|
|
@@ -59,7 +59,10 @@ export function parsePositiveInt(raw, fallback) {
|
|
|
59
59
|
return fallback;
|
|
60
60
|
// Offset-like parameters may intentionally allow zero when fallback is zero.
|
|
61
61
|
const minimum = fallback <= 0 ? 0 : 1;
|
|
62
|
-
|
|
62
|
+
const clamped = Math.max(minimum, Math.floor(parsed));
|
|
63
|
+
if (!Number.isFinite(max))
|
|
64
|
+
return clamped;
|
|
65
|
+
return Math.min(clamped, Math.max(minimum, Math.floor(max)));
|
|
63
66
|
}
|
|
64
67
|
export function parseBooleanQuery(raw) {
|
|
65
68
|
if (!raw)
|
package/dist/http/index.js
CHANGED
|
@@ -1846,7 +1846,7 @@ export function createHttpHandler(config, client, getSnapshot, onboarding, diagn
|
|
|
1846
1846
|
};
|
|
1847
1847
|
const codexBinResolver = createCodexBinResolver();
|
|
1848
1848
|
const resolveCodexBinInfo = () => codexBinResolver.resolveCodexBinInfo();
|
|
1849
|
-
const { autoContinueRuns, autoContinueSliceRuns, localInitiativeStatusOverrides, writeRuntimeEvent, autoContinueTickMs: AUTO_CONTINUE_TICK_MS, defaultAutoContinueTokenBudget, defaultAutoContinueMaxParallelSlices, setLocalInitiativeStatusOverride, clearLocalInitiativeStatusOverride, applyLocalInitiativeOverrides, applyLocalInitiativeOverrideToGraph, updateInitiativeAutoContinueState, stopAutoContinueRun, tickAutoContinueRun, tickAllAutoContinue, isInitiativeActiveStatus, runningAutoContinueForWorkstream, getAutoContinueLaneForWorkstream, scheduleAutoFixForWorkstream, startAutoContinueRun, } = createAutoContinueEngine({
|
|
1849
|
+
const { autoContinueRuns, autoContinueSliceRuns, localInitiativeStatusOverrides, writeRuntimeEvent, autoContinueTickMs: AUTO_CONTINUE_TICK_MS, defaultAutoContinueTokenBudget, defaultAutoContinueMaxParallelSlices, setLocalInitiativeStatusOverride, clearLocalInitiativeStatusOverride, applyLocalInitiativeOverrides, applyLocalInitiativeOverrideToGraph, updateInitiativeAutoContinueState, stopAutoContinueRun, tickAutoContinueRun, tickAllAutoContinue, isInitiativeActiveStatus, runningAutoContinueForWorkstream, getAutoContinueLaneForWorkstream, scheduleAutoFixForWorkstream, startAutoContinueRun, skipCurrentWorkstream, getCanonicalAutopilotState, } = createAutoContinueEngine({
|
|
1850
1850
|
client,
|
|
1851
1851
|
filename: __filename,
|
|
1852
1852
|
safeErrorMessage,
|
|
@@ -3417,6 +3417,7 @@ export function createHttpHandler(config, client, getSnapshot, onboarding, diagn
|
|
|
3417
3417
|
dispatchFallbackWorkstreamTurn,
|
|
3418
3418
|
tickAutoContinueRun,
|
|
3419
3419
|
stopAutoContinueRun,
|
|
3420
|
+
skipCurrentWorkstream,
|
|
3420
3421
|
updateInitiativeAutoContinueState,
|
|
3421
3422
|
tickAllAutoContinue,
|
|
3422
3423
|
scheduleAutoFixForWorkstream,
|
|
@@ -3592,6 +3593,7 @@ export function createHttpHandler(config, client, getSnapshot, onboarding, diagn
|
|
|
3592
3593
|
},
|
|
3593
3594
|
runAction: (runId, action, input) => client.runAction(runId, action, input),
|
|
3594
3595
|
listChatThreads: ({ commandCenterId, initiativeId, limit, offset }) => listChatThreads({ commandCenterId, initiativeId, limit, offset }),
|
|
3596
|
+
getCanonicalAutopilotState,
|
|
3595
3597
|
sendJson,
|
|
3596
3598
|
});
|
|
3597
3599
|
registerRuntimeHookRoutes(apiRouter, {
|
|
@@ -3,7 +3,7 @@ type JsonRecord = Record<string, unknown>;
|
|
|
3
3
|
type RegisterChatRoutesDeps<TReq, TRes> = {
|
|
4
4
|
parseJsonRequest: (req: TReq) => Promise<JsonRecord>;
|
|
5
5
|
pickString: (input: Record<string, unknown>, keys: string[]) => string | null;
|
|
6
|
-
parsePositiveInt: (raw: string | null, fallback: number) => number;
|
|
6
|
+
parsePositiveInt: (raw: string | null, fallback: number, max?: number) => number;
|
|
7
7
|
emitActivitySafe?: (input: {
|
|
8
8
|
initiativeId: string | null;
|
|
9
9
|
sourceClient?: string;
|
package/dist/http/routes/chat.js
CHANGED
|
@@ -161,8 +161,8 @@ export function registerChatRoutes(router, deps) {
|
|
|
161
161
|
const initiativeId = query.get("initiative_id") ?? query.get("initiative");
|
|
162
162
|
const searchQuery = query.get("query") ?? query.get("q");
|
|
163
163
|
const status = query.get("status");
|
|
164
|
-
const limit = deps.parsePositiveInt(query.get("limit"), 60);
|
|
165
|
-
const offset = deps.parsePositiveInt(query.get("offset"), 0);
|
|
164
|
+
const limit = deps.parsePositiveInt(query.get("limit"), 60, 200);
|
|
165
|
+
const offset = deps.parsePositiveInt(query.get("offset"), 0, 10000);
|
|
166
166
|
sendThreadList(deps, res, {
|
|
167
167
|
commandCenterId: commandCenterId?.trim() ?? null,
|
|
168
168
|
initiativeId: initiativeId?.trim() ?? null,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { resolveWorkspaceScope, workspaceScopeFromHeaders, } from "../helpers/workspace-scope.js";
|
|
2
|
+
import { deriveInitiativeLifecycleStatus } from "../helpers/mission-control.js";
|
|
2
3
|
const WORKSTREAM_REASSIGNMENT_FIELDS = [
|
|
3
4
|
"domain",
|
|
4
5
|
"role",
|
|
@@ -38,6 +39,59 @@ function toObjectArray(input) {
|
|
|
38
39
|
return [];
|
|
39
40
|
return input.filter((item) => Boolean(item) && typeof item === "object");
|
|
40
41
|
}
|
|
42
|
+
async function reconcileInitiativeStatusesFromWorkstreams(deps, rows, input) {
|
|
43
|
+
if (rows.length === 0)
|
|
44
|
+
return rows;
|
|
45
|
+
const initiativeIds = new Set(rows
|
|
46
|
+
.map((row) => deps.pickString(row, ["id"]))
|
|
47
|
+
.filter((value) => Boolean(value)));
|
|
48
|
+
if (initiativeIds.size === 0)
|
|
49
|
+
return rows;
|
|
50
|
+
const scopedInitiativeId = input.initiativeId?.trim() ?? "";
|
|
51
|
+
const scopedWorkspaceId = input.workspaceId?.trim() ?? "";
|
|
52
|
+
if (!scopedInitiativeId && !scopedWorkspaceId) {
|
|
53
|
+
// Avoid unscoped global workstream scans.
|
|
54
|
+
return rows;
|
|
55
|
+
}
|
|
56
|
+
const filters = { limit: 2000 };
|
|
57
|
+
if (scopedInitiativeId) {
|
|
58
|
+
filters.initiative_id = scopedInitiativeId;
|
|
59
|
+
}
|
|
60
|
+
if (scopedWorkspaceId) {
|
|
61
|
+
filters.workspace_id = scopedWorkspaceId;
|
|
62
|
+
filters.command_center_id = scopedWorkspaceId;
|
|
63
|
+
}
|
|
64
|
+
const response = await deps.client.listEntities("workstream", filters);
|
|
65
|
+
const workstreamRows = toObjectArray(response && typeof response === "object"
|
|
66
|
+
? response.data
|
|
67
|
+
: []);
|
|
68
|
+
const childStatusesByInitiative = new Map();
|
|
69
|
+
for (const workstreamRow of workstreamRows) {
|
|
70
|
+
const initiativeId = deps.pickString(workstreamRow, ["initiative_id", "initiativeId"]);
|
|
71
|
+
if (!initiativeId || !initiativeIds.has(initiativeId))
|
|
72
|
+
continue;
|
|
73
|
+
const status = deps.pickString(workstreamRow, ["status"]) ?? "todo";
|
|
74
|
+
const statuses = childStatusesByInitiative.get(initiativeId) ?? [];
|
|
75
|
+
statuses.push(status);
|
|
76
|
+
childStatusesByInitiative.set(initiativeId, statuses);
|
|
77
|
+
}
|
|
78
|
+
return rows.map((row) => {
|
|
79
|
+
const initiativeId = deps.pickString(row, ["id"]);
|
|
80
|
+
const status = deps.pickString(row, ["status"]);
|
|
81
|
+
if (!initiativeId || !status)
|
|
82
|
+
return row;
|
|
83
|
+
const childStatuses = childStatusesByInitiative.get(initiativeId) ?? [];
|
|
84
|
+
if (childStatuses.length === 0)
|
|
85
|
+
return row;
|
|
86
|
+
const normalized = deriveInitiativeLifecycleStatus(status, childStatuses);
|
|
87
|
+
if (normalized === status)
|
|
88
|
+
return row;
|
|
89
|
+
return {
|
|
90
|
+
...row,
|
|
91
|
+
status: normalized,
|
|
92
|
+
};
|
|
93
|
+
});
|
|
94
|
+
}
|
|
41
95
|
export function registerEntitiesRoutes(router, deps) {
|
|
42
96
|
router.add("POST", "entities", async ({ req, res }) => {
|
|
43
97
|
try {
|
|
@@ -305,13 +359,17 @@ export function registerEntitiesRoutes(router, deps) {
|
|
|
305
359
|
return rowScope.trim() === workspaceScopeId;
|
|
306
360
|
})
|
|
307
361
|
: searchedRows;
|
|
362
|
+
const reconciledRows = await reconcileInitiativeStatusesFromWorkstreams(deps, rows, {
|
|
363
|
+
initiativeId: id,
|
|
364
|
+
workspaceId: workspaceScopeId,
|
|
365
|
+
}).catch(() => rows);
|
|
308
366
|
deps.sendJson(res, 200, {
|
|
309
367
|
...payload,
|
|
310
|
-
data: deps.applyLocalInitiativeOverrides(
|
|
368
|
+
data: deps.applyLocalInitiativeOverrides(reconciledRows),
|
|
311
369
|
pagination: payload.pagination && typeof payload.pagination === "object"
|
|
312
370
|
? {
|
|
313
371
|
...payload.pagination,
|
|
314
|
-
total:
|
|
372
|
+
total: reconciledRows.length,
|
|
315
373
|
}
|
|
316
374
|
: payload.pagination,
|
|
317
375
|
});
|
|
@@ -1,3 +1,51 @@
|
|
|
1
|
+
function resolveEntityActionStatus(entityType, entityAction) {
|
|
2
|
+
const normalizedType = entityType.trim().toLowerCase();
|
|
3
|
+
const normalizedAction = entityAction.trim().toLowerCase();
|
|
4
|
+
const defaultStatusMap = {
|
|
5
|
+
start: "in_progress",
|
|
6
|
+
complete: "done",
|
|
7
|
+
block: "blocked",
|
|
8
|
+
unblock: "in_progress",
|
|
9
|
+
pause: "paused",
|
|
10
|
+
resume: "active",
|
|
11
|
+
};
|
|
12
|
+
const statusMapByEntityType = {
|
|
13
|
+
initiative: {
|
|
14
|
+
start: "active",
|
|
15
|
+
complete: "completed",
|
|
16
|
+
block: "blocked",
|
|
17
|
+
unblock: "active",
|
|
18
|
+
pause: "paused",
|
|
19
|
+
resume: "active",
|
|
20
|
+
},
|
|
21
|
+
workstream: {
|
|
22
|
+
start: "active",
|
|
23
|
+
complete: "completed",
|
|
24
|
+
block: "blocked",
|
|
25
|
+
unblock: "active",
|
|
26
|
+
pause: "paused",
|
|
27
|
+
resume: "active",
|
|
28
|
+
},
|
|
29
|
+
milestone: {
|
|
30
|
+
start: "in_progress",
|
|
31
|
+
complete: "completed",
|
|
32
|
+
block: "at_risk",
|
|
33
|
+
unblock: "in_progress",
|
|
34
|
+
pause: "planned",
|
|
35
|
+
resume: "in_progress",
|
|
36
|
+
},
|
|
37
|
+
task: {
|
|
38
|
+
start: "in_progress",
|
|
39
|
+
complete: "done",
|
|
40
|
+
block: "blocked",
|
|
41
|
+
unblock: "in_progress",
|
|
42
|
+
pause: "todo",
|
|
43
|
+
resume: "in_progress",
|
|
44
|
+
},
|
|
45
|
+
};
|
|
46
|
+
const map = statusMapByEntityType[normalizedType] ?? defaultStatusMap;
|
|
47
|
+
return map[normalizedAction] ?? null;
|
|
48
|
+
}
|
|
1
49
|
export function registerEntityDynamicRoutes(router, deps) {
|
|
2
50
|
router.add("*", "entities/*", async ({ req, res, path }) => {
|
|
3
51
|
const method = (req.method ?? "GET").toUpperCase();
|
|
@@ -137,15 +185,7 @@ export function registerEntityDynamicRoutes(router, deps) {
|
|
|
137
185
|
}
|
|
138
186
|
return;
|
|
139
187
|
}
|
|
140
|
-
const
|
|
141
|
-
start: "in_progress",
|
|
142
|
-
complete: "done",
|
|
143
|
-
block: "blocked",
|
|
144
|
-
unblock: "in_progress",
|
|
145
|
-
pause: "paused",
|
|
146
|
-
resume: "active",
|
|
147
|
-
};
|
|
148
|
-
const newStatus = statusMap[entityAction];
|
|
188
|
+
const newStatus = resolveEntityActionStatus(entityType, entityAction);
|
|
149
189
|
if (!newStatus) {
|
|
150
190
|
deps.sendJson(res, 400, {
|
|
151
191
|
error: `Unknown entity action: ${entityAction}`,
|
|
@@ -14,7 +14,7 @@ type SnapshotPersistState = {
|
|
|
14
14
|
lastPersistAt: number;
|
|
15
15
|
};
|
|
16
16
|
type LiveSnapshotRoutesDeps<TReq, TRes> = {
|
|
17
|
-
parsePositiveInt: (raw: string | null, fallback: number) => number;
|
|
17
|
+
parsePositiveInt: (raw: string | null, fallback: number, max?: number) => number;
|
|
18
18
|
readSnapshotResponseCache: (key: string) => Record<string, unknown> | null;
|
|
19
19
|
writeSnapshotResponseCache: (key: string, payload: Record<string, unknown>) => void;
|
|
20
20
|
safeErrorMessage: (err: unknown) => string;
|
|
@@ -131,6 +131,15 @@ type LiveSnapshotRoutesDeps<TReq, TRes> = {
|
|
|
131
131
|
total: number;
|
|
132
132
|
updatedAt: string;
|
|
133
133
|
};
|
|
134
|
+
getCanonicalAutopilotState?: (initiativeId: string) => {
|
|
135
|
+
state: "idle" | "running" | "blocked" | "stopping";
|
|
136
|
+
reason: string | null;
|
|
137
|
+
activeRunId: string | null;
|
|
138
|
+
activeWorkstreamId: string | null;
|
|
139
|
+
activeWorkstreamTitle: string | null;
|
|
140
|
+
queueHeadTitle: string | null;
|
|
141
|
+
lastTransitionAt: string;
|
|
142
|
+
} | null;
|
|
134
143
|
sendJson: (res: TRes, status: number, payload: unknown) => void;
|
|
135
144
|
};
|
|
136
145
|
export declare function registerLiveSnapshotRoutes<TReq, TRes>(router: Router<Record<string, never>, TReq, TRes>, deps: LiveSnapshotRoutesDeps<TReq, TRes>): void;
|
|
@@ -231,9 +231,9 @@ export function registerLiveSnapshotRoutes(router, deps) {
|
|
|
231
231
|
};
|
|
232
232
|
const headerScopeFromRequest = (req) => workspaceScopeFromHeaders(req?.headers);
|
|
233
233
|
function parseSnapshotQuery(query, headerScope) {
|
|
234
|
-
const sessionsLimit = deps.parsePositiveInt(query.get("sessionsLimit") ?? query.get("sessions_limit"), 320);
|
|
235
|
-
const activityLimit = deps.parsePositiveInt(query.get("activityLimit") ?? query.get("activity_limit"), 600);
|
|
236
|
-
const decisionsLimit = deps.parsePositiveInt(query.get("decisionsLimit") ?? query.get("decisions_limit"), 120);
|
|
234
|
+
const sessionsLimit = deps.parsePositiveInt(query.get("sessionsLimit") ?? query.get("sessions_limit"), 320, 1000);
|
|
235
|
+
const activityLimit = deps.parsePositiveInt(query.get("activityLimit") ?? query.get("activity_limit"), 600, 2000);
|
|
236
|
+
const decisionsLimit = deps.parsePositiveInt(query.get("decisionsLimit") ?? query.get("decisions_limit"), 120, 500);
|
|
237
237
|
const initiative = query.get("initiative");
|
|
238
238
|
const scope = resolveWorkspaceScope(query, headerScope, {
|
|
239
239
|
allowProjectScope: false,
|
|
@@ -523,6 +523,14 @@ export function registerLiveSnapshotRoutes(router, deps) {
|
|
|
523
523
|
projectId,
|
|
524
524
|
degraded: degraded.length > 0 ? degraded : undefined,
|
|
525
525
|
};
|
|
526
|
+
if (typeof deps.getCanonicalAutopilotState === "function" && initiative) {
|
|
527
|
+
try {
|
|
528
|
+
payload.autopilot = deps.getCanonicalAutopilotState(initiative) ?? null;
|
|
529
|
+
}
|
|
530
|
+
catch {
|
|
531
|
+
// best effort
|
|
532
|
+
}
|
|
533
|
+
}
|
|
526
534
|
if (typeof deps.listChatThreads === "function") {
|
|
527
535
|
try {
|
|
528
536
|
const listed = deps.listChatThreads({
|
|
@@ -66,6 +66,12 @@ type RegisterMissionControlActionsRoutesDeps<TReq, TRes> = {
|
|
|
66
66
|
}>;
|
|
67
67
|
tickAutoContinueRun: (run: any) => Promise<void>;
|
|
68
68
|
stopAutoContinueRun: (input: any) => Promise<void>;
|
|
69
|
+
skipCurrentWorkstream: (initiativeId: string, workstreamId: string, reason?: string) => Promise<{
|
|
70
|
+
ok: boolean;
|
|
71
|
+
skippedWorkstreamId: string;
|
|
72
|
+
nextWorkstreamId?: string;
|
|
73
|
+
nextWorkstreamTitle?: string;
|
|
74
|
+
}>;
|
|
69
75
|
updateInitiativeAutoContinueState: (input: any) => Promise<void>;
|
|
70
76
|
tickAllAutoContinue: () => Promise<void>;
|
|
71
77
|
scheduleAutoFixForWorkstream: (input: {
|