@tianhai/pi-workflow-kit 0.5.3 → 0.6.0
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 +44 -494
- package/docs/developer-usage-guide.md +41 -401
- package/docs/oversight-model.md +13 -34
- package/docs/workflow-phases.md +32 -46
- package/extensions/workflow-guard.ts +67 -0
- package/package.json +3 -7
- package/skills/brainstorming/SKILL.md +16 -67
- package/skills/executing-tasks/SKILL.md +26 -227
- package/skills/finalizing/SKILL.md +33 -0
- package/skills/writing-plans/SKILL.md +23 -132
- package/ROADMAP.md +0 -16
- package/agents/code-reviewer.md +0 -18
- package/agents/config.ts +0 -5
- package/agents/implementer.md +0 -26
- package/agents/spec-reviewer.md +0 -13
- package/agents/worker.md +0 -17
- package/docs/plans/2026-04-10-brainstorming-boundary-enforcement-design.md +0 -60
- package/docs/plans/completed/2026-04-09-cleanup-legacy-state-and-enforce-think-phases-design.md +0 -56
- package/docs/plans/completed/2026-04-09-cleanup-legacy-state-and-enforce-think-phases-implementation.md +0 -196
- package/docs/plans/completed/2026-04-09-workflow-next-autocomplete-design.md +0 -185
- package/docs/plans/completed/2026-04-09-workflow-next-autocomplete-implementation.md +0 -334
- package/docs/plans/completed/2026-04-09-workflow-next-handoff-state-design.md +0 -251
- package/docs/plans/completed/2026-04-09-workflow-next-handoff-state-implementation.md +0 -253
- package/extensions/constants.ts +0 -15
- package/extensions/lib/logging.ts +0 -138
- package/extensions/plan-tracker.ts +0 -508
- package/extensions/subagent/agents.ts +0 -144
- package/extensions/subagent/concurrency.ts +0 -52
- package/extensions/subagent/env.ts +0 -47
- package/extensions/subagent/index.ts +0 -1181
- package/extensions/subagent/lifecycle.ts +0 -25
- package/extensions/subagent/timeout.ts +0 -13
- package/extensions/workflow-monitor/debug-monitor.ts +0 -98
- package/extensions/workflow-monitor/git.ts +0 -31
- package/extensions/workflow-monitor/heuristics.ts +0 -58
- package/extensions/workflow-monitor/investigation.ts +0 -52
- package/extensions/workflow-monitor/reference-tool.ts +0 -42
- package/extensions/workflow-monitor/skip-confirmation.ts +0 -19
- package/extensions/workflow-monitor/tdd-monitor.ts +0 -137
- package/extensions/workflow-monitor/test-runner.ts +0 -37
- package/extensions/workflow-monitor/verification-monitor.ts +0 -61
- package/extensions/workflow-monitor/warnings.ts +0 -81
- package/extensions/workflow-monitor/workflow-handler.ts +0 -363
- package/extensions/workflow-monitor/workflow-next-completions.ts +0 -68
- package/extensions/workflow-monitor/workflow-next-state.ts +0 -112
- package/extensions/workflow-monitor/workflow-tracker.ts +0 -286
- package/extensions/workflow-monitor/workflow-transitions.ts +0 -88
- package/extensions/workflow-monitor.ts +0 -909
- package/skills/dispatching-parallel-agents/SKILL.md +0 -194
- package/skills/receiving-code-review/SKILL.md +0 -196
- package/skills/systematic-debugging/SKILL.md +0 -170
- package/skills/systematic-debugging/condition-based-waiting-example.ts +0 -158
- package/skills/systematic-debugging/condition-based-waiting.md +0 -115
- package/skills/systematic-debugging/defense-in-depth.md +0 -122
- package/skills/systematic-debugging/find-polluter.sh +0 -63
- package/skills/systematic-debugging/reference/rationalizations.md +0 -61
- package/skills/systematic-debugging/root-cause-tracing.md +0 -169
- package/skills/test-driven-development/SKILL.md +0 -266
- package/skills/test-driven-development/reference/examples.md +0 -101
- package/skills/test-driven-development/reference/rationalizations.md +0 -67
- package/skills/test-driven-development/reference/when-stuck.md +0 -33
- package/skills/test-driven-development/testing-anti-patterns.md +0 -299
- package/skills/using-git-worktrees/SKILL.md +0 -231
|
@@ -1,286 +0,0 @@
|
|
|
1
|
-
import type { SessionEntry } from "@mariozechner/pi-coding-agent";
|
|
2
|
-
|
|
3
|
-
export const WORKFLOW_PHASES = ["brainstorm", "plan", "execute", "finalize"] as const;
|
|
4
|
-
|
|
5
|
-
export type Phase = (typeof WORKFLOW_PHASES)[number];
|
|
6
|
-
export type PhaseStatus = "pending" | "active" | "complete" | "skipped";
|
|
7
|
-
|
|
8
|
-
export interface WorkflowTrackerState {
|
|
9
|
-
phases: Record<Phase, PhaseStatus>;
|
|
10
|
-
currentPhase: Phase | null;
|
|
11
|
-
artifacts: Record<Phase, string | null>;
|
|
12
|
-
prompted: Record<Phase, boolean>;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export type TransitionBoundary =
|
|
16
|
-
| "design_reviewable"
|
|
17
|
-
| "plan_reviewable"
|
|
18
|
-
| "design_committed"
|
|
19
|
-
| "plan_ready"
|
|
20
|
-
| "execution_complete";
|
|
21
|
-
|
|
22
|
-
export function computeBoundaryToPrompt(state: WorkflowTrackerState): TransitionBoundary | null {
|
|
23
|
-
// Reviewable: current phase has its deliverable artifact but hasn't been
|
|
24
|
-
// user-confirmed as complete. Prompt the user to review before moving on.
|
|
25
|
-
if (
|
|
26
|
-
state.currentPhase === "brainstorm" &&
|
|
27
|
-
state.artifacts.brainstorm &&
|
|
28
|
-
state.phases.brainstorm === "active" &&
|
|
29
|
-
!state.prompted.brainstorm
|
|
30
|
-
) {
|
|
31
|
-
return "design_reviewable";
|
|
32
|
-
}
|
|
33
|
-
if (state.currentPhase === "plan" && state.artifacts.plan && state.phases.plan === "active" && !state.prompted.plan) {
|
|
34
|
-
return "plan_reviewable";
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
// Committed: phase is complete but user hasn't been prompted for
|
|
38
|
-
// transition options yet (e.g. phases completed via skip-confirmation
|
|
39
|
-
// "mark complete" or execute phase auto-completing on all tasks terminal).
|
|
40
|
-
if (state.phases.brainstorm === "complete" && !state.prompted.brainstorm) {
|
|
41
|
-
return "design_committed";
|
|
42
|
-
}
|
|
43
|
-
if (state.phases.plan === "complete" && !state.prompted.plan) {
|
|
44
|
-
return "plan_ready";
|
|
45
|
-
}
|
|
46
|
-
if (state.phases.execute === "complete" && !state.prompted.execute) {
|
|
47
|
-
return "execution_complete";
|
|
48
|
-
}
|
|
49
|
-
return null;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
function cloneState(state: WorkflowTrackerState): WorkflowTrackerState {
|
|
53
|
-
return JSON.parse(JSON.stringify(state)) as WorkflowTrackerState;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
function emptyState(): WorkflowTrackerState {
|
|
57
|
-
const phases = Object.fromEntries(WORKFLOW_PHASES.map((p) => [p, "pending"])) as Record<Phase, PhaseStatus>;
|
|
58
|
-
|
|
59
|
-
const artifacts = Object.fromEntries(WORKFLOW_PHASES.map((p) => [p, null])) as Record<Phase, string | null>;
|
|
60
|
-
|
|
61
|
-
const prompted = Object.fromEntries(WORKFLOW_PHASES.map((p) => [p, false])) as Record<Phase, boolean>;
|
|
62
|
-
|
|
63
|
-
return { phases, currentPhase: null, artifacts, prompted };
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
export const WORKFLOW_TRACKER_ENTRY_TYPE = "workflow_tracker_state";
|
|
67
|
-
|
|
68
|
-
export function parseSkillName(line: string): string | null {
|
|
69
|
-
const slashMatch = line.match(/^\s*\/skill:([^\s]+)/);
|
|
70
|
-
const xmlMatch = line.match(/<skill\s+name="([^"]+)"/);
|
|
71
|
-
return slashMatch?.[1] ?? xmlMatch?.[1] ?? null;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
export const SKILL_TO_PHASE: Record<string, Phase> = {
|
|
75
|
-
brainstorming: "brainstorm",
|
|
76
|
-
"writing-plans": "plan",
|
|
77
|
-
"using-git-worktrees": "plan", // pre-execute worktree setup belongs to plan
|
|
78
|
-
"executing-tasks": "execute",
|
|
79
|
-
"systematic-debugging": "execute", // used within execute phase
|
|
80
|
-
"dispatching-parallel-agents": "execute", // used within execute phase
|
|
81
|
-
"test-driven-development": "execute", // makes TDD skill phase-aware
|
|
82
|
-
"receiving-code-review": "finalize", // post-PR external review
|
|
83
|
-
};
|
|
84
|
-
|
|
85
|
-
export function resolveSkillPhase(skill: string, state: WorkflowTrackerState | null | undefined): Phase | null {
|
|
86
|
-
if (skill === "executing-tasks") {
|
|
87
|
-
if (state?.currentPhase === "finalize" || state?.phases.execute === "complete") {
|
|
88
|
-
return "finalize";
|
|
89
|
-
}
|
|
90
|
-
return "execute";
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
return SKILL_TO_PHASE[skill] ?? null;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
const PLANS_DIR_RE = /^docs\/plans\//;
|
|
97
|
-
const DESIGN_RE = /-design\.md$/;
|
|
98
|
-
const IMPLEMENTATION_RE = /-implementation\.md$/;
|
|
99
|
-
|
|
100
|
-
export class WorkflowTracker {
|
|
101
|
-
private state: WorkflowTrackerState = emptyState();
|
|
102
|
-
|
|
103
|
-
getState(): WorkflowTrackerState {
|
|
104
|
-
return cloneState(this.state);
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
setState(state: WorkflowTrackerState): void {
|
|
108
|
-
this.state = cloneState(state);
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
reset(): void {
|
|
112
|
-
this.state = emptyState();
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
advanceTo(phase: Phase): boolean {
|
|
116
|
-
const current = this.state.currentPhase;
|
|
117
|
-
const nextIdx = WORKFLOW_PHASES.indexOf(phase);
|
|
118
|
-
|
|
119
|
-
if (current) {
|
|
120
|
-
const curIdx = WORKFLOW_PHASES.indexOf(current);
|
|
121
|
-
if (nextIdx === curIdx) {
|
|
122
|
-
// Same-phase navigation is a no-op. This prevents accidental resets
|
|
123
|
-
// when plan_tracker init is called while already in execute, or when
|
|
124
|
-
// a skill is re-invoked during its own phase.
|
|
125
|
-
return false;
|
|
126
|
-
}
|
|
127
|
-
if (nextIdx < curIdx) {
|
|
128
|
-
// Backward navigation = intentional new task. Reset everything.
|
|
129
|
-
this.reset();
|
|
130
|
-
// Fall through to activate the target phase below.
|
|
131
|
-
} else {
|
|
132
|
-
// Forward advance: do NOT auto-complete the current phase.
|
|
133
|
-
// Phase completion requires explicit user confirmation via
|
|
134
|
-
// boundary prompts or skip-confirmation "mark complete".
|
|
135
|
-
// However, refuse to jump over unresolved intermediate phases.
|
|
136
|
-
for (let i = curIdx + 1; i < nextIdx; i++) {
|
|
137
|
-
const intermediate = WORKFLOW_PHASES[i]!;
|
|
138
|
-
const status = this.state.phases[intermediate];
|
|
139
|
-
if (status !== "complete" && status !== "skipped") {
|
|
140
|
-
// Can't advance past an unresolved intermediate phase.
|
|
141
|
-
return false;
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
this.state.currentPhase = phase;
|
|
148
|
-
if (this.state.phases[phase] === "pending") {
|
|
149
|
-
this.state.phases[phase] = "active";
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
return true;
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
skipPhase(phase: Phase): boolean {
|
|
156
|
-
const status = this.state.phases[phase];
|
|
157
|
-
if (status !== "pending" && status !== "active") return false;
|
|
158
|
-
this.state.phases[phase] = "skipped";
|
|
159
|
-
return true;
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
skipPhases(phases: Phase[]): boolean {
|
|
163
|
-
let changed = false;
|
|
164
|
-
for (const p of phases) changed = this.skipPhase(p) || changed;
|
|
165
|
-
return changed;
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
completeCurrent(): boolean {
|
|
169
|
-
const phase = this.state.currentPhase;
|
|
170
|
-
if (!phase) return false;
|
|
171
|
-
return this.completePhase(phase);
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
completePhase(phase: Phase): boolean {
|
|
175
|
-
if (this.state.phases[phase] === "complete") return false;
|
|
176
|
-
this.state.phases[phase] = "complete";
|
|
177
|
-
return true;
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
recordArtifact(phase: Phase, path: string): boolean {
|
|
181
|
-
if (this.state.artifacts[phase] === path) return false;
|
|
182
|
-
this.state.artifacts[phase] = path;
|
|
183
|
-
return true;
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
markPrompted(phase: Phase): boolean {
|
|
187
|
-
if (this.state.prompted[phase]) return false;
|
|
188
|
-
this.state.prompted[phase] = true;
|
|
189
|
-
return true;
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
onInputText(text: string): boolean {
|
|
193
|
-
const lines = text.split(/\r?\n/);
|
|
194
|
-
let changed = false;
|
|
195
|
-
|
|
196
|
-
for (const line of lines) {
|
|
197
|
-
const skill = parseSkillName(line);
|
|
198
|
-
if (!skill) continue;
|
|
199
|
-
const phase = resolveSkillPhase(skill, this.state);
|
|
200
|
-
if (!phase) continue;
|
|
201
|
-
// Guard against backward navigation: skills shared across phases (e.g. executing-tasks
|
|
202
|
-
// covers both execute and finalize) must not reset state when re-invoked in a later phase.
|
|
203
|
-
const currentIdx = this.state.currentPhase ? WORKFLOW_PHASES.indexOf(this.state.currentPhase) : -1;
|
|
204
|
-
const targetIdx = WORKFLOW_PHASES.indexOf(phase);
|
|
205
|
-
if (targetIdx <= currentIdx) continue;
|
|
206
|
-
if (this.advanceTo(phase)) changed = true;
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
return changed;
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
onSkillFileRead(path: string): boolean {
|
|
213
|
-
const match = path.match(/\/skills\/([^/]+)\/SKILL\.md$/);
|
|
214
|
-
if (!match) return false;
|
|
215
|
-
const phase = resolveSkillPhase(match[1], this.state);
|
|
216
|
-
if (!phase) return false;
|
|
217
|
-
// Guard against backward navigation: some skills (e.g. executing-tasks) serve
|
|
218
|
-
// multiple phases. Re-reading their SKILL.md during a later phase (e.g. finalize)
|
|
219
|
-
// must not reset workflow state. Rely on plan_tracker init or explicit /workflow-reset
|
|
220
|
-
// to restart from scratch.
|
|
221
|
-
const currentIdx = this.state.currentPhase ? WORKFLOW_PHASES.indexOf(this.state.currentPhase) : -1;
|
|
222
|
-
const targetIdx = WORKFLOW_PHASES.indexOf(phase);
|
|
223
|
-
if (targetIdx <= currentIdx) return false;
|
|
224
|
-
return this.advanceTo(phase);
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
onFileWritten(path: string): boolean {
|
|
228
|
-
if (!PLANS_DIR_RE.test(path)) return false;
|
|
229
|
-
|
|
230
|
-
if (DESIGN_RE.test(path)) {
|
|
231
|
-
// Only advance if we haven't already passed the brainstorm phase.
|
|
232
|
-
// Writing a design doc during plan/execute/finalize (e.g., updating
|
|
233
|
-
// the plan) must NOT reset workflow state.
|
|
234
|
-
const curIdx = this.state.currentPhase ? WORKFLOW_PHASES.indexOf(this.state.currentPhase) : -1;
|
|
235
|
-
if (curIdx > WORKFLOW_PHASES.indexOf("brainstorm")) {
|
|
236
|
-
return this.recordArtifact("brainstorm", path);
|
|
237
|
-
}
|
|
238
|
-
let changed = false;
|
|
239
|
-
changed = this.recordArtifact("brainstorm", path) || changed;
|
|
240
|
-
// Activate brainstorm phase but do NOT auto-complete.
|
|
241
|
-
// User confirms completion via the reviewable boundary prompt at agent_end.
|
|
242
|
-
changed = this.advanceTo("brainstorm") || changed;
|
|
243
|
-
return changed;
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
if (IMPLEMENTATION_RE.test(path)) {
|
|
247
|
-
// Only advance if we haven't already passed the plan phase.
|
|
248
|
-
const curIdx = this.state.currentPhase ? WORKFLOW_PHASES.indexOf(this.state.currentPhase) : -1;
|
|
249
|
-
if (curIdx > WORKFLOW_PHASES.indexOf("plan")) {
|
|
250
|
-
return this.recordArtifact("plan", path);
|
|
251
|
-
}
|
|
252
|
-
let changed = false;
|
|
253
|
-
changed = this.recordArtifact("plan", path) || changed;
|
|
254
|
-
// Activate plan phase but do NOT auto-complete.
|
|
255
|
-
// User confirms completion via the reviewable boundary prompt at agent_end.
|
|
256
|
-
changed = this.advanceTo("plan") || changed;
|
|
257
|
-
return changed;
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
return false;
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
onPlanTrackerInit(): boolean {
|
|
264
|
-
// Guard: don't advance if already in execute (prevents accidental resets).
|
|
265
|
-
// Also refuse to jump over unresolved phases (e.g., plan still active).
|
|
266
|
-
if (this.state.currentPhase === "execute") return false;
|
|
267
|
-
return this.advanceTo("execute");
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
static reconstructFromBranch(branch: SessionEntry[]): WorkflowTrackerState | null {
|
|
271
|
-
let last: WorkflowTrackerState | null = null;
|
|
272
|
-
|
|
273
|
-
for (const entry of branch) {
|
|
274
|
-
if (entry.type !== "custom") continue;
|
|
275
|
-
// biome-ignore lint/suspicious/noExplicitAny: pi SDK session entry type
|
|
276
|
-
if ((entry as any).customType !== WORKFLOW_TRACKER_ENTRY_TYPE) continue;
|
|
277
|
-
// biome-ignore lint/suspicious/noExplicitAny: pi SDK session entry type
|
|
278
|
-
const data = (entry as any).data as WorkflowTrackerState | undefined;
|
|
279
|
-
if (data && typeof data === "object") {
|
|
280
|
-
last = cloneState(data);
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
return last;
|
|
285
|
-
}
|
|
286
|
-
}
|
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
import type { Phase, TransitionBoundary } from "./workflow-tracker";
|
|
2
|
-
|
|
3
|
-
export type TransitionChoice = "next" | "fresh" | "skip" | "revise" | "discuss";
|
|
4
|
-
|
|
5
|
-
export interface TransitionPrompt {
|
|
6
|
-
boundary: TransitionBoundary;
|
|
7
|
-
title: string;
|
|
8
|
-
nextPhase: Phase;
|
|
9
|
-
artifactPath: string | null;
|
|
10
|
-
options: { choice: TransitionChoice; label: string }[];
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
const BASE_OPTIONS: TransitionPrompt["options"] = [
|
|
14
|
-
{ choice: "next", label: "Next step (this session)" },
|
|
15
|
-
{ choice: "fresh", label: "Fresh session → next step" },
|
|
16
|
-
{ choice: "skip", label: "Skip" },
|
|
17
|
-
{ choice: "discuss", label: "Discuss" },
|
|
18
|
-
];
|
|
19
|
-
|
|
20
|
-
// Reviewable options: shown when a phase has its artifact but hasn't
|
|
21
|
-
// been user-confirmed as complete. Includes explicit approval + revision.
|
|
22
|
-
const REVIEWABLE_OPTIONS: TransitionPrompt["options"] = [
|
|
23
|
-
{ choice: "next", label: "✓ Looks good, next step (this session)" },
|
|
24
|
-
{ choice: "fresh", label: "✓ Looks good, fresh session → next step" },
|
|
25
|
-
{ choice: "skip", label: "Skip phase" },
|
|
26
|
-
{ choice: "revise", label: "✗ Needs more work" },
|
|
27
|
-
{ choice: "discuss", label: "Discuss" },
|
|
28
|
-
];
|
|
29
|
-
|
|
30
|
-
export function getTransitionPrompt(boundary: TransitionBoundary, artifactPath: string | null): TransitionPrompt {
|
|
31
|
-
switch (boundary) {
|
|
32
|
-
// Reviewable: phase has artifact but user hasn't confirmed completion
|
|
33
|
-
case "design_reviewable":
|
|
34
|
-
return {
|
|
35
|
-
boundary,
|
|
36
|
-
title: `Design written${artifactPath ? `: ${artifactPath}` : ""}. Ready to proceed?`,
|
|
37
|
-
nextPhase: "plan",
|
|
38
|
-
artifactPath,
|
|
39
|
-
options: REVIEWABLE_OPTIONS,
|
|
40
|
-
};
|
|
41
|
-
case "plan_reviewable":
|
|
42
|
-
return {
|
|
43
|
-
boundary,
|
|
44
|
-
title: `Plan written${artifactPath ? `: ${artifactPath}` : ""}. Ready to proceed?`,
|
|
45
|
-
nextPhase: "execute",
|
|
46
|
-
artifactPath,
|
|
47
|
-
options: REVIEWABLE_OPTIONS,
|
|
48
|
-
};
|
|
49
|
-
// Committed: phase already complete, user chooses how to proceed
|
|
50
|
-
case "design_committed":
|
|
51
|
-
return {
|
|
52
|
-
boundary,
|
|
53
|
-
title: "Design committed. What next?",
|
|
54
|
-
nextPhase: "plan",
|
|
55
|
-
artifactPath,
|
|
56
|
-
options: BASE_OPTIONS,
|
|
57
|
-
};
|
|
58
|
-
case "plan_ready":
|
|
59
|
-
return {
|
|
60
|
-
boundary,
|
|
61
|
-
title: "Plan ready. What next?",
|
|
62
|
-
nextPhase: "execute",
|
|
63
|
-
artifactPath,
|
|
64
|
-
options: BASE_OPTIONS,
|
|
65
|
-
};
|
|
66
|
-
case "execution_complete":
|
|
67
|
-
return {
|
|
68
|
-
boundary,
|
|
69
|
-
title: "All tasks complete. What next?",
|
|
70
|
-
nextPhase: "finalize",
|
|
71
|
-
artifactPath,
|
|
72
|
-
options: BASE_OPTIONS,
|
|
73
|
-
};
|
|
74
|
-
default:
|
|
75
|
-
return {
|
|
76
|
-
boundary,
|
|
77
|
-
title: "What next?",
|
|
78
|
-
nextPhase: "plan",
|
|
79
|
-
artifactPath,
|
|
80
|
-
options: BASE_OPTIONS,
|
|
81
|
-
};
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
/** Whether a boundary represents a phase that still needs user confirmation. */
|
|
86
|
-
export function isReviewableBoundary(boundary: TransitionBoundary): boolean {
|
|
87
|
-
return boundary === "design_reviewable" || boundary === "plan_reviewable";
|
|
88
|
-
}
|