@unbrained/pm-web 2026.6.4 → 2026.6.13-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.
@@ -0,0 +1,191 @@
1
+ const DONE_STATUSES = new Set(['done', 'completed', 'closed']);
2
+ const BLOCKED_STATUSES = new Set(['blocked']);
3
+ function normalizeStatus(status) {
4
+ const value = (status || 'pending').trim().toLowerCase().replace(/\s+/g, '_');
5
+ return value || 'pending';
6
+ }
7
+ function normalizeStepRef(step, index) {
8
+ const candidate = (step.ref || step.id || '').trim();
9
+ return candidate || `step-${index + 1}`;
10
+ }
11
+ function normalizeDependsOn(step) {
12
+ const raw = Array.isArray(step.dependsOn)
13
+ ? step.dependsOn
14
+ : (Array.isArray(step.depends_on) ? step.depends_on : []);
15
+ const unique = new Set();
16
+ for (const dep of raw) {
17
+ const trimmed = String(dep || '').trim();
18
+ if (trimmed)
19
+ unique.add(trimmed);
20
+ }
21
+ return Array.from(unique);
22
+ }
23
+ function formatStepLine(step) {
24
+ return `- [${step.ref}] ${step.title}`;
25
+ }
26
+ function formatWaitReason(step) {
27
+ const blockers = [
28
+ ...step.incompleteDependencies,
29
+ ...step.unresolvedDependencies.map(dep => `${dep} (missing)`),
30
+ ];
31
+ if (blockers.length === 0)
32
+ return 'waiting';
33
+ return `waiting on ${blockers.join(', ')}`;
34
+ }
35
+ function stepDependencyBlockers(step) {
36
+ return [
37
+ ...step.incompleteDependencies,
38
+ ...step.unresolvedDependencies.map(dep => `${dep} (missing)`),
39
+ ];
40
+ }
41
+ export function buildPlanExecutionSnapshot(steps) {
42
+ const normalized = steps.map((step, index) => {
43
+ const status = normalizeStatus(step.status);
44
+ return {
45
+ ref: normalizeStepRef(step, index),
46
+ title: (step.title || '(untitled)').trim() || '(untitled)',
47
+ description: (step.description || '').trim(),
48
+ status,
49
+ blockedReason: (step.blockedReason || step.blocked_reason || '').trim(),
50
+ dependsOn: normalizeDependsOn(step),
51
+ unresolvedDependencies: [],
52
+ incompleteDependencies: [],
53
+ isDone: DONE_STATUSES.has(status),
54
+ isBlocked: BLOCKED_STATUSES.has(status),
55
+ original: step,
56
+ };
57
+ });
58
+ const stepByRef = {};
59
+ for (const step of normalized) {
60
+ if (!stepByRef[step.ref])
61
+ stepByRef[step.ref] = step;
62
+ }
63
+ const completedRefs = new Set(normalized.filter(step => step.isDone).map(step => step.ref));
64
+ for (const step of normalized) {
65
+ if (step.isDone || step.isBlocked)
66
+ continue;
67
+ for (const dep of step.dependsOn) {
68
+ if (!stepByRef[dep]) {
69
+ step.unresolvedDependencies.push(dep);
70
+ }
71
+ else if (!completedRefs.has(dep)) {
72
+ step.incompleteDependencies.push(dep);
73
+ }
74
+ }
75
+ }
76
+ const readySteps = [];
77
+ const waitingSteps = [];
78
+ const blockedStepDetails = [];
79
+ for (const step of normalized) {
80
+ if (step.isDone)
81
+ continue;
82
+ if (step.isBlocked) {
83
+ blockedStepDetails.push(step);
84
+ continue;
85
+ }
86
+ if (step.incompleteDependencies.length === 0 && step.unresolvedDependencies.length === 0) {
87
+ readySteps.push(step);
88
+ }
89
+ else {
90
+ waitingSteps.push(step);
91
+ }
92
+ }
93
+ const totalSteps = normalized.length;
94
+ const completedSteps = normalized.filter(step => step.isDone).length;
95
+ const blockedSteps = blockedStepDetails.length;
96
+ const completionPct = totalSteps > 0 ? Math.round((completedSteps / totalSteps) * 100) : 0;
97
+ return {
98
+ totalSteps,
99
+ completedSteps,
100
+ blockedSteps,
101
+ waitingSteps,
102
+ readySteps,
103
+ blockedStepDetails,
104
+ allSteps: normalized,
105
+ stepByRef,
106
+ completionPct,
107
+ nextReadyStep: readySteps[0] || null,
108
+ };
109
+ }
110
+ export function buildPlanAgentBrief(plan, snapshot) {
111
+ const title = (plan.title || plan.id || '(untitled)').trim();
112
+ const lines = [
113
+ '# Plan execution brief',
114
+ `Plan: ${title}`,
115
+ ];
116
+ if (plan.id)
117
+ lines.push(`Plan ID: ${plan.id}`);
118
+ if (plan.status)
119
+ lines.push(`Status: ${plan.status}`);
120
+ if (plan.scope)
121
+ lines.push(`Scope: ${plan.scope}`);
122
+ if (plan.description)
123
+ lines.push('', 'Description:', plan.description.trim());
124
+ lines.push('', 'Execution summary:', `- Completed: ${snapshot.completedSteps}/${snapshot.totalSteps} (${snapshot.completionPct}%)`, `- Ready now: ${snapshot.readySteps.length}`, `- Waiting on dependencies: ${snapshot.waitingSteps.length}`, `- Explicitly blocked: ${snapshot.blockedStepDetails.length}`);
125
+ if (snapshot.readySteps.length > 0) {
126
+ lines.push('', `Ready now (${snapshot.readySteps.length}):`);
127
+ for (const step of snapshot.readySteps)
128
+ lines.push(formatStepLine(step));
129
+ }
130
+ else {
131
+ lines.push('', 'Ready now: none');
132
+ }
133
+ if (snapshot.waitingSteps.length > 0) {
134
+ lines.push('', `Waiting (${snapshot.waitingSteps.length}):`);
135
+ for (const step of snapshot.waitingSteps) {
136
+ lines.push(`${formatStepLine(step)} (${formatWaitReason(step)})`);
137
+ }
138
+ }
139
+ if (snapshot.blockedStepDetails.length > 0) {
140
+ lines.push('', `Blocked (${snapshot.blockedStepDetails.length}):`);
141
+ for (const step of snapshot.blockedStepDetails) {
142
+ const reason = step.blockedReason ? `: ${step.blockedReason}` : '';
143
+ lines.push(`${formatStepLine(step)}${reason}`);
144
+ }
145
+ }
146
+ lines.push('', 'Instruction:', 'Pick the top ready step, execute it end-to-end, and report tests/evidence before moving to the next.');
147
+ return lines.join('\n');
148
+ }
149
+ export function buildNextStepPrompt(plan, snapshot, stepRef) {
150
+ const step = stepRef ? snapshot.stepByRef[stepRef] : snapshot.nextReadyStep;
151
+ if (!step) {
152
+ const planName = (plan.title || plan.id || '(untitled)').trim();
153
+ return [
154
+ `No ready step is currently available for plan "${planName}".`,
155
+ 'Please inspect waiting and blocked steps, resolve dependencies, and refresh the plan.',
156
+ ].join('\n');
157
+ }
158
+ const planName = (plan.title || plan.id || '(untitled)').trim();
159
+ const dependencyBlockers = stepDependencyBlockers(step);
160
+ const isWaiting = dependencyBlockers.length > 0 && !step.isBlocked;
161
+ const readinessLabel = step.isBlocked ? 'blocked' : (isWaiting ? 'waiting' : 'ready');
162
+ const lines = [
163
+ '# Next step execution prompt',
164
+ `You are working on plan "${planName}"${plan.id ? ` (${plan.id})` : ''}.`,
165
+ `Current progress: ${snapshot.completedSteps}/${snapshot.totalSteps} complete.`,
166
+ `Step readiness: ${readinessLabel}.`,
167
+ '',
168
+ `Execute step [${step.ref}] ${step.title}.`,
169
+ ];
170
+ if (step.description) {
171
+ lines.push(`Step details: ${step.description}`);
172
+ }
173
+ if (step.isBlocked) {
174
+ lines.push(`Blocked reason: ${step.blockedReason || 'No reason provided.'}`, 'This step is explicitly blocked. Resolve the blocker before implementation.');
175
+ }
176
+ else if (isWaiting) {
177
+ lines.push(`Pending dependencies: ${dependencyBlockers.join(', ')}`, 'This step is waiting on dependencies. Do not start implementation until dependencies are complete.');
178
+ }
179
+ else if (step.dependsOn.length > 0) {
180
+ lines.push(`Dependencies already satisfied: ${step.dependsOn.join(', ')}`);
181
+ }
182
+ lines.push('', 'Execution requirements:');
183
+ if (step.isBlocked || isWaiting) {
184
+ lines.push('- Resolve blockers/dependencies first, then refresh this plan snapshot.', '- Once ready, execute the step in production-ready quality.', '- Report exact commands/outcomes and evidence collected.', '- Update dependency and step status notes after each change.');
185
+ }
186
+ else {
187
+ lines.push('- Implement in production-ready quality.', '- Add or update tests where feasible.', '- Report the exact commands and outcomes.', '- Update the step status when done.');
188
+ }
189
+ return lines.join('\n');
190
+ }
191
+ //# sourceMappingURL=plan-execution.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plan-execution.js","sourceRoot":"","sources":["plan-execution.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,279 @@
1
+ type PlanStepInput = {
2
+ id?: string;
3
+ ref?: string;
4
+ title?: string;
5
+ description?: string;
6
+ status?: string;
7
+ blockedReason?: string;
8
+ blocked_reason?: string;
9
+ dependsOn?: string[];
10
+ depends_on?: string[];
11
+ };
12
+
13
+ type PlanInput = {
14
+ id?: string;
15
+ title?: string;
16
+ description?: string;
17
+ scope?: string;
18
+ status?: string;
19
+ };
20
+
21
+ export type AnalyzedPlanStep = {
22
+ ref: string;
23
+ title: string;
24
+ description: string;
25
+ status: string;
26
+ blockedReason: string;
27
+ dependsOn: string[];
28
+ unresolvedDependencies: string[];
29
+ incompleteDependencies: string[];
30
+ isDone: boolean;
31
+ isBlocked: boolean;
32
+ original: PlanStepInput;
33
+ };
34
+
35
+ export type PlanExecutionSnapshot = {
36
+ totalSteps: number;
37
+ completedSteps: number;
38
+ blockedSteps: number;
39
+ waitingSteps: AnalyzedPlanStep[];
40
+ readySteps: AnalyzedPlanStep[];
41
+ blockedStepDetails: AnalyzedPlanStep[];
42
+ allSteps: AnalyzedPlanStep[];
43
+ stepByRef: Record<string, AnalyzedPlanStep>;
44
+ completionPct: number;
45
+ nextReadyStep: AnalyzedPlanStep | null;
46
+ };
47
+
48
+ const DONE_STATUSES = new Set(['done', 'completed', 'closed']);
49
+ const BLOCKED_STATUSES = new Set(['blocked']);
50
+
51
+ function normalizeStatus(status?: string): string {
52
+ const value = (status || 'pending').trim().toLowerCase().replace(/\s+/g, '_');
53
+ return value || 'pending';
54
+ }
55
+
56
+ function normalizeStepRef(step: PlanStepInput, index: number): string {
57
+ const candidate = (step.ref || step.id || '').trim();
58
+ return candidate || `step-${index + 1}`;
59
+ }
60
+
61
+ function normalizeDependsOn(step: PlanStepInput): string[] {
62
+ const raw = Array.isArray(step.dependsOn)
63
+ ? step.dependsOn
64
+ : (Array.isArray(step.depends_on) ? step.depends_on : []);
65
+ const unique = new Set<string>();
66
+ for (const dep of raw) {
67
+ const trimmed = String(dep || '').trim();
68
+ if (trimmed) unique.add(trimmed);
69
+ }
70
+ return Array.from(unique);
71
+ }
72
+
73
+ function formatStepLine(step: AnalyzedPlanStep): string {
74
+ return `- [${step.ref}] ${step.title}`;
75
+ }
76
+
77
+ function formatWaitReason(step: AnalyzedPlanStep): string {
78
+ const blockers = [
79
+ ...step.incompleteDependencies,
80
+ ...step.unresolvedDependencies.map(dep => `${dep} (missing)`),
81
+ ];
82
+ if (blockers.length === 0) return 'waiting';
83
+ return `waiting on ${blockers.join(', ')}`;
84
+ }
85
+
86
+ function stepDependencyBlockers(step: AnalyzedPlanStep): string[] {
87
+ return [
88
+ ...step.incompleteDependencies,
89
+ ...step.unresolvedDependencies.map(dep => `${dep} (missing)`),
90
+ ];
91
+ }
92
+
93
+ export function buildPlanExecutionSnapshot(steps: PlanStepInput[]): PlanExecutionSnapshot {
94
+ const normalized: AnalyzedPlanStep[] = steps.map((step, index) => {
95
+ const status = normalizeStatus(step.status);
96
+ return {
97
+ ref: normalizeStepRef(step, index),
98
+ title: (step.title || '(untitled)').trim() || '(untitled)',
99
+ description: (step.description || '').trim(),
100
+ status,
101
+ blockedReason: (step.blockedReason || step.blocked_reason || '').trim(),
102
+ dependsOn: normalizeDependsOn(step),
103
+ unresolvedDependencies: [],
104
+ incompleteDependencies: [],
105
+ isDone: DONE_STATUSES.has(status),
106
+ isBlocked: BLOCKED_STATUSES.has(status),
107
+ original: step,
108
+ };
109
+ });
110
+
111
+ const stepByRef: Record<string, AnalyzedPlanStep> = {};
112
+ for (const step of normalized) {
113
+ if (!stepByRef[step.ref]) stepByRef[step.ref] = step;
114
+ }
115
+
116
+ const completedRefs = new Set(normalized.filter(step => step.isDone).map(step => step.ref));
117
+
118
+ for (const step of normalized) {
119
+ if (step.isDone || step.isBlocked) continue;
120
+ for (const dep of step.dependsOn) {
121
+ if (!stepByRef[dep]) {
122
+ step.unresolvedDependencies.push(dep);
123
+ } else if (!completedRefs.has(dep)) {
124
+ step.incompleteDependencies.push(dep);
125
+ }
126
+ }
127
+ }
128
+
129
+ const readySteps: AnalyzedPlanStep[] = [];
130
+ const waitingSteps: AnalyzedPlanStep[] = [];
131
+ const blockedStepDetails: AnalyzedPlanStep[] = [];
132
+
133
+ for (const step of normalized) {
134
+ if (step.isDone) continue;
135
+ if (step.isBlocked) {
136
+ blockedStepDetails.push(step);
137
+ continue;
138
+ }
139
+ if (step.incompleteDependencies.length === 0 && step.unresolvedDependencies.length === 0) {
140
+ readySteps.push(step);
141
+ } else {
142
+ waitingSteps.push(step);
143
+ }
144
+ }
145
+
146
+ const totalSteps = normalized.length;
147
+ const completedSteps = normalized.filter(step => step.isDone).length;
148
+ const blockedSteps = blockedStepDetails.length;
149
+ const completionPct = totalSteps > 0 ? Math.round((completedSteps / totalSteps) * 100) : 0;
150
+
151
+ return {
152
+ totalSteps,
153
+ completedSteps,
154
+ blockedSteps,
155
+ waitingSteps,
156
+ readySteps,
157
+ blockedStepDetails,
158
+ allSteps: normalized,
159
+ stepByRef,
160
+ completionPct,
161
+ nextReadyStep: readySteps[0] || null,
162
+ };
163
+ }
164
+
165
+ export function buildPlanAgentBrief(plan: PlanInput, snapshot: PlanExecutionSnapshot): string {
166
+ const title = (plan.title || plan.id || '(untitled)').trim();
167
+ const lines: string[] = [
168
+ '# Plan execution brief',
169
+ `Plan: ${title}`,
170
+ ];
171
+ if (plan.id) lines.push(`Plan ID: ${plan.id}`);
172
+ if (plan.status) lines.push(`Status: ${plan.status}`);
173
+ if (plan.scope) lines.push(`Scope: ${plan.scope}`);
174
+ if (plan.description) lines.push('', 'Description:', plan.description.trim());
175
+
176
+ lines.push(
177
+ '',
178
+ 'Execution summary:',
179
+ `- Completed: ${snapshot.completedSteps}/${snapshot.totalSteps} (${snapshot.completionPct}%)`,
180
+ `- Ready now: ${snapshot.readySteps.length}`,
181
+ `- Waiting on dependencies: ${snapshot.waitingSteps.length}`,
182
+ `- Explicitly blocked: ${snapshot.blockedStepDetails.length}`
183
+ );
184
+
185
+ if (snapshot.readySteps.length > 0) {
186
+ lines.push('', `Ready now (${snapshot.readySteps.length}):`);
187
+ for (const step of snapshot.readySteps) lines.push(formatStepLine(step));
188
+ } else {
189
+ lines.push('', 'Ready now: none');
190
+ }
191
+
192
+ if (snapshot.waitingSteps.length > 0) {
193
+ lines.push('', `Waiting (${snapshot.waitingSteps.length}):`);
194
+ for (const step of snapshot.waitingSteps) {
195
+ lines.push(`${formatStepLine(step)} (${formatWaitReason(step)})`);
196
+ }
197
+ }
198
+
199
+ if (snapshot.blockedStepDetails.length > 0) {
200
+ lines.push('', `Blocked (${snapshot.blockedStepDetails.length}):`);
201
+ for (const step of snapshot.blockedStepDetails) {
202
+ const reason = step.blockedReason ? `: ${step.blockedReason}` : '';
203
+ lines.push(`${formatStepLine(step)}${reason}`);
204
+ }
205
+ }
206
+
207
+ lines.push(
208
+ '',
209
+ 'Instruction:',
210
+ 'Pick the top ready step, execute it end-to-end, and report tests/evidence before moving to the next.'
211
+ );
212
+
213
+ return lines.join('\n');
214
+ }
215
+
216
+ export function buildNextStepPrompt(
217
+ plan: PlanInput,
218
+ snapshot: PlanExecutionSnapshot,
219
+ stepRef?: string
220
+ ): string {
221
+ const step = stepRef ? snapshot.stepByRef[stepRef] : snapshot.nextReadyStep;
222
+ if (!step) {
223
+ const planName = (plan.title || plan.id || '(untitled)').trim();
224
+ return [
225
+ `No ready step is currently available for plan "${planName}".`,
226
+ 'Please inspect waiting and blocked steps, resolve dependencies, and refresh the plan.',
227
+ ].join('\n');
228
+ }
229
+
230
+ const planName = (plan.title || plan.id || '(untitled)').trim();
231
+ const dependencyBlockers = stepDependencyBlockers(step);
232
+ const isWaiting = dependencyBlockers.length > 0 && !step.isBlocked;
233
+ const readinessLabel = step.isBlocked ? 'blocked' : (isWaiting ? 'waiting' : 'ready');
234
+ const lines: string[] = [
235
+ '# Next step execution prompt',
236
+ `You are working on plan "${planName}"${plan.id ? ` (${plan.id})` : ''}.`,
237
+ `Current progress: ${snapshot.completedSteps}/${snapshot.totalSteps} complete.`,
238
+ `Step readiness: ${readinessLabel}.`,
239
+ '',
240
+ `Execute step [${step.ref}] ${step.title}.`,
241
+ ];
242
+
243
+ if (step.description) {
244
+ lines.push(`Step details: ${step.description}`);
245
+ }
246
+
247
+ if (step.isBlocked) {
248
+ lines.push(
249
+ `Blocked reason: ${step.blockedReason || 'No reason provided.'}`,
250
+ 'This step is explicitly blocked. Resolve the blocker before implementation.'
251
+ );
252
+ } else if (isWaiting) {
253
+ lines.push(
254
+ `Pending dependencies: ${dependencyBlockers.join(', ')}`,
255
+ 'This step is waiting on dependencies. Do not start implementation until dependencies are complete.'
256
+ );
257
+ } else if (step.dependsOn.length > 0) {
258
+ lines.push(`Dependencies already satisfied: ${step.dependsOn.join(', ')}`);
259
+ }
260
+
261
+ lines.push('', 'Execution requirements:');
262
+ if (step.isBlocked || isWaiting) {
263
+ lines.push(
264
+ '- Resolve blockers/dependencies first, then refresh this plan snapshot.',
265
+ '- Once ready, execute the step in production-ready quality.',
266
+ '- Report exact commands/outcomes and evidence collected.',
267
+ '- Update dependency and step status notes after each change.'
268
+ );
269
+ } else {
270
+ lines.push(
271
+ '- Implement in production-ready quality.',
272
+ '- Add or update tests where feasible.',
273
+ '- Report the exact commands and outcomes.',
274
+ '- Update the step status when done.'
275
+ );
276
+ }
277
+
278
+ return lines.join('\n');
279
+ }