feat(pi-workflow): add human-readable run labels

This commit is contained in:
jb
2026-08-25 21:22:08 -04:00
parent a1d0b1415c
commit 54a7921227
17 changed files with 385 additions and 52 deletions
@@ -84,6 +84,8 @@ function workflowView(
): WorkflowView {
return {
runId: "run-1",
featureName: "example-feature",
request: "Build example feature",
revision,
status: context.status === "ready" ? "running" : "waiting",
background: false,
@@ -257,6 +259,7 @@ test("/workflow continue lists only valid runs and resume is an alias", async ()
revision: 10,
status: "waiting",
request: `Request ${runId}`,
featureName: runId === "historical" ? "historical" : "shared-feature",
parentSessionIds: [activeParentSessionId],
lease: { activeParentSessionId },
planArtifact: { path: "/plan.md", revision: 1, digest: "digest" },
@@ -336,6 +339,10 @@ test("/workflow continue lists only valid runs and resume is an alias", async ()
]);
assert.equal(selectedOptions[0]?.length, 2);
assert.equal(selectedOptions[1]?.length, 2);
assert.deepEqual(selectedOptions[0], [
"shared-feature · run-1 · waiting",
"shared-feature · run-2 · waiting",
]);
assert.ok(
selectedOptions.every((options) =>
options.every((label) => !label.includes("historical")),
@@ -366,6 +373,29 @@ test("/workflow continue without a run ID gives actionable non-UI guidance", asy
);
});
test("/workflow continue reports the supplied run ID when inspection cannot load it", async () => {
const registered = fakeApi();
registerWorkflowContextTransitions(registered.api, {
store: { listRuns: async () => [] },
engineForContext: () =>
({
async execute() {
throw new Error("not found");
},
}) as unknown as WorkflowEngine,
} as unknown as ContextTransitionRuntime);
const command = commandContext({
sessionId: "session-1",
sessionFile: "/sessions/source.jsonl",
});
await registered.command()("continue missing-run-id", command.context);
assert.ok(
command.notifications.some((message) =>
message.includes("Workflow Run missing-run-id could not be loaded"),
),
);
});
test("/workflow stop selects among active runs owned by the current session", async () => {
const run = (
runId: string,
@@ -377,6 +407,7 @@ test("/workflow stop selects among active runs owned by the current session", as
revision: 4,
status,
request: `Request ${runId}`,
featureName: "duplicate-label",
parentSessionIds: [activeParentSessionId],
lease: { activeParentSessionId },
}) as unknown as WorkflowRun;
@@ -419,8 +450,10 @@ test("/workflow stop selects among active runs owned by the current session", as
},
});
await registered.command()("stop", command.context);
assert.equal(choices.length, 2);
assert.ok(choices.every((label) => !label.includes("completed")));
assert.deepEqual(choices, [
"duplicate-label · run-1 · running",
"duplicate-label · run-2 · waiting",
]);
assert.deepEqual(
commands.map((entry) =>
`${entry.action}:${"runId" in entry ? entry.runId : ""}`,
@@ -565,6 +598,7 @@ test("/workflow continue invokes and fences normal compaction callbacks", async
},
});
await registered.command()("continue run-1", ctx);
assert.match(compactOptions?.customInstructions ?? "", /pi-workflow run example-feature/);
assert.match(compactOptions?.customInstructions ?? "", /Approved plan/);
compactOptions?.onComplete?.({
summary: "summary",
@@ -832,6 +866,8 @@ test("fresh continuation claims shutdown target and consumes only in withSession
});
await registered.command()("continue run-1", old.context);
assert.equal(sent.length, 1);
const handoffMessage = sent[0] as { content: string };
assert.match(handoffMessage.content, /Continue pi-workflow run example-feature/);
const handoff = JSON.stringify(sent[0]);
assert.match(handoff, /Handoff plan/);
assert.doesNotMatch(handoff, /�|😀/);