@pellux/goodvibes-agent 1.3.0 → 1.4.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/CHANGELOG.md +45 -0
- package/README.md +0 -1
- package/dist/package/{ast-grep-napi.linux-x64-gnu-swtppvy9.node → ast-grep-napi.linux-x64-gnu-mkk8xwww.node} +0 -0
- package/dist/package/{ast-grep-napi.linux-x64-musl-ttfcdtap.node → ast-grep-napi.linux-x64-musl-ryqtgdv6.node} +0 -0
- package/dist/package/main.js +55623 -55535
- package/docs/README.md +0 -1
- package/docs/tools-and-commands.md +0 -3
- package/package.json +1 -1
- package/release/release-notes.md +7 -156
- package/src/agent/competitive-feature-inventory.ts +1 -1
- package/src/agent/setup-wizard.ts +28 -21
- package/src/cli/tui-startup.ts +2 -2
- package/src/input/agent-workspace-activation.ts +2 -2
- package/src/input/agent-workspace-categories.ts +3 -20
- package/src/input/agent-workspace-onboarding-finish.ts +21 -0
- package/src/input/agent-workspace-settings.ts +14 -19
- package/src/input/agent-workspace-setup-snapshot.ts +2 -10
- package/src/input/agent-workspace-setup.ts +14 -47
- package/src/input/agent-workspace-snapshot.ts +0 -7
- package/src/input/agent-workspace-types.ts +5 -2
- package/src/input/agent-workspace.ts +19 -8
- package/src/input/commands.ts +0 -4
- package/src/input/handler.ts +70 -5
- package/src/main.ts +1 -40
- package/src/panels/builtin/agent.ts +0 -28
- package/src/renderer/agent-workspace-context-lines.ts +11 -42
- package/src/renderer/agent-workspace.ts +414 -31
- package/src/renderer/help-overlay.ts +0 -2
- package/src/tools/agent-harness-setup-posture.ts +7 -7
- package/src/version.ts +1 -1
- package/docs/project-planning.md +0 -81
- package/src/input/commands/planning-runtime.ts +0 -215
- package/src/input/commands/work-plan-runtime.ts +0 -191
- package/src/panels/plan-dashboard-panel.ts +0 -274
- package/src/panels/project-planning-panel.ts +0 -721
- package/src/panels/work-plan-panel.ts +0 -175
- package/src/planning/project-planning-coordinator.ts +0 -543
|
@@ -1,274 +0,0 @@
|
|
|
1
|
-
import type { Line } from '../types/grid.ts';
|
|
2
|
-
import type { ExecutionPlan, PlanItem, PlanItemStatus } from '@pellux/goodvibes-sdk/platform/core';
|
|
3
|
-
import { BasePanel } from './base-panel.ts';
|
|
4
|
-
import type { PlanDashboardQuery } from '../runtime/ui-service-queries.ts';
|
|
5
|
-
import {
|
|
6
|
-
buildEmptyState,
|
|
7
|
-
buildPanelLine,
|
|
8
|
-
buildPanelWorkspace,
|
|
9
|
-
resolveScrollablePanelSection,
|
|
10
|
-
DEFAULT_PANEL_PALETTE,
|
|
11
|
-
type PanelWorkspaceSection,
|
|
12
|
-
} from './polish.ts';
|
|
13
|
-
|
|
14
|
-
// ---------------------------------------------------------------------------
|
|
15
|
-
// Status display maps
|
|
16
|
-
// ---------------------------------------------------------------------------
|
|
17
|
-
|
|
18
|
-
const STATUS_ICON: Record<PlanItemStatus, string> = {
|
|
19
|
-
complete: '✓',
|
|
20
|
-
in_progress: '▸',
|
|
21
|
-
pending: '•',
|
|
22
|
-
failed: '✗',
|
|
23
|
-
skipped: '–',
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
const STATUS_FG: Record<PlanItemStatus, string> = {
|
|
27
|
-
complete: '#22c55e',
|
|
28
|
-
in_progress: '#00ffff',
|
|
29
|
-
pending: '244',
|
|
30
|
-
failed: '#ef4444',
|
|
31
|
-
skipped: '238',
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
// ---------------------------------------------------------------------------
|
|
35
|
-
// PlanDashboardPanel
|
|
36
|
-
// ---------------------------------------------------------------------------
|
|
37
|
-
|
|
38
|
-
export class PlanDashboardPanel extends BasePanel {
|
|
39
|
-
private scrollOffset = 0;
|
|
40
|
-
private selectedIndex = 0;
|
|
41
|
-
|
|
42
|
-
// Flat list of navigable row indices (set during render)
|
|
43
|
-
private totalRows = 0;
|
|
44
|
-
private readonly planManager: PlanDashboardQuery;
|
|
45
|
-
|
|
46
|
-
constructor(planManager: PlanDashboardQuery) {
|
|
47
|
-
super('plan', 'Plan', 'P', 'agent');
|
|
48
|
-
this.planManager = planManager;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
override onActivate(): void {
|
|
52
|
-
super.onActivate();
|
|
53
|
-
// Re-read plan from disk each time the panel is activated
|
|
54
|
-
this.markDirty();
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
// --------------------------------------------------------------------------
|
|
58
|
-
// Input
|
|
59
|
-
// --------------------------------------------------------------------------
|
|
60
|
-
|
|
61
|
-
handleInput(key: string): boolean {
|
|
62
|
-
if (key === 'up' || key === 'k') {
|
|
63
|
-
if (this.selectedIndex > 0) {
|
|
64
|
-
this.selectedIndex--;
|
|
65
|
-
this.markDirty();
|
|
66
|
-
return true;
|
|
67
|
-
}
|
|
68
|
-
} else if (key === 'down' || key === 'j') {
|
|
69
|
-
if (this.selectedIndex < this.totalRows - 1) {
|
|
70
|
-
this.selectedIndex++;
|
|
71
|
-
this.markDirty();
|
|
72
|
-
return true;
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
return false;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
// --------------------------------------------------------------------------
|
|
79
|
-
// Render
|
|
80
|
-
// --------------------------------------------------------------------------
|
|
81
|
-
|
|
82
|
-
render(width: number, height: number): Line[] {
|
|
83
|
-
return this.trackedRender(() => {
|
|
84
|
-
const plan = this.planManager.getActive();
|
|
85
|
-
if (!plan) {
|
|
86
|
-
return buildPanelWorkspace(width, height, {
|
|
87
|
-
title: ' Plan Dashboard',
|
|
88
|
-
intro: 'Track the active execution plan, item status, phase grouping, and overall completion.',
|
|
89
|
-
sections: [
|
|
90
|
-
{
|
|
91
|
-
lines: buildEmptyState(
|
|
92
|
-
width,
|
|
93
|
-
' No active execution plan',
|
|
94
|
-
'Use /plan to create a plan and the execution dashboard will populate here.',
|
|
95
|
-
[],
|
|
96
|
-
DEFAULT_PANEL_PALETTE,
|
|
97
|
-
),
|
|
98
|
-
},
|
|
99
|
-
],
|
|
100
|
-
palette: DEFAULT_PANEL_PALETTE,
|
|
101
|
-
});
|
|
102
|
-
}
|
|
103
|
-
return this.renderPlan(plan, width, height);
|
|
104
|
-
});
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
// --------------------------------------------------------------------------
|
|
108
|
-
// Empty state
|
|
109
|
-
// --------------------------------------------------------------------------
|
|
110
|
-
|
|
111
|
-
private renderPlan(plan: ExecutionPlan, width: number, height: number): Line[] {
|
|
112
|
-
const phaseOrder: string[] = [];
|
|
113
|
-
const byPhase = new Map<string, PlanItem[]>();
|
|
114
|
-
for (const item of plan.items) {
|
|
115
|
-
if (!byPhase.has(item.phase)) {
|
|
116
|
-
byPhase.set(item.phase, []);
|
|
117
|
-
phaseOrder.push(item.phase);
|
|
118
|
-
}
|
|
119
|
-
byPhase.get(item.phase)!.push(item);
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
// Build a set of complete item IDs for dependency blocking detection
|
|
123
|
-
const completeIds = new Set(
|
|
124
|
-
plan.items
|
|
125
|
-
.filter((i) => i.status === 'complete' || i.status === 'skipped')
|
|
126
|
-
.map((i) => i.id),
|
|
127
|
-
);
|
|
128
|
-
|
|
129
|
-
let rowCount = 0;
|
|
130
|
-
let selectedLineIndex = 0;
|
|
131
|
-
const planLines: Line[] = [];
|
|
132
|
-
|
|
133
|
-
for (const phase of phaseOrder) {
|
|
134
|
-
const items = byPhase.get(phase)!;
|
|
135
|
-
planLines.push(this.renderPhaseHeaderLine(phase, items, width));
|
|
136
|
-
for (const item of items) {
|
|
137
|
-
const isSelected = rowCount === this.selectedIndex;
|
|
138
|
-
if (isSelected) selectedLineIndex = planLines.length;
|
|
139
|
-
const isBlocked =
|
|
140
|
-
item.status === 'pending' &&
|
|
141
|
-
item.dependencies !== undefined &&
|
|
142
|
-
item.dependencies.length > 0 &&
|
|
143
|
-
!item.dependencies.every((depId) => completeIds.has(depId));
|
|
144
|
-
|
|
145
|
-
planLines.push(this.renderItem(item, isSelected, isBlocked, width));
|
|
146
|
-
rowCount++;
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
this.totalRows = rowCount;
|
|
151
|
-
if (this.selectedIndex >= this.totalRows) {
|
|
152
|
-
this.selectedIndex = Math.max(0, this.totalRows - 1);
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
const total = plan.items.length;
|
|
156
|
-
const done = plan.items.filter((i) => i.status === 'complete' || i.status === 'skipped').length;
|
|
157
|
-
const pct = total > 0 ? Math.round((done / total) * 100) : 0;
|
|
158
|
-
const summary: PanelWorkspaceSection = {
|
|
159
|
-
title: 'Summary',
|
|
160
|
-
lines: [
|
|
161
|
-
buildPanelLine(width, [
|
|
162
|
-
[' Status ', DEFAULT_PANEL_PALETTE.label],
|
|
163
|
-
[plan.status, this.statusColor(plan.status)],
|
|
164
|
-
[' Progress ', DEFAULT_PANEL_PALETTE.label],
|
|
165
|
-
[`${pct}%`, pct === 100 ? DEFAULT_PANEL_PALETTE.good : DEFAULT_PANEL_PALETTE.info],
|
|
166
|
-
[' Items ', DEFAULT_PANEL_PALETTE.label],
|
|
167
|
-
[`${done}/${total}`, DEFAULT_PANEL_PALETTE.value],
|
|
168
|
-
]),
|
|
169
|
-
],
|
|
170
|
-
};
|
|
171
|
-
|
|
172
|
-
const planSection = resolveScrollablePanelSection(width, height, {
|
|
173
|
-
intro: plan.title,
|
|
174
|
-
footerLines: [
|
|
175
|
-
buildPanelLine(width, [[' Up/Down', DEFAULT_PANEL_PALETTE.info], [' navigate', DEFAULT_PANEL_PALETTE.dim]]),
|
|
176
|
-
],
|
|
177
|
-
palette: DEFAULT_PANEL_PALETTE,
|
|
178
|
-
beforeSections: [summary],
|
|
179
|
-
section: {
|
|
180
|
-
title: 'Execution Plan',
|
|
181
|
-
scrollableLines: planLines,
|
|
182
|
-
selectedIndex: selectedLineIndex,
|
|
183
|
-
scrollOffset: this.scrollOffset,
|
|
184
|
-
minRows: 8,
|
|
185
|
-
},
|
|
186
|
-
});
|
|
187
|
-
this.scrollOffset = planSection.scrollOffset;
|
|
188
|
-
|
|
189
|
-
return buildPanelWorkspace(width, height, {
|
|
190
|
-
title: ` Plan Dashboard`,
|
|
191
|
-
intro: plan.title,
|
|
192
|
-
sections: [
|
|
193
|
-
summary,
|
|
194
|
-
planSection.section,
|
|
195
|
-
],
|
|
196
|
-
footerLines: [
|
|
197
|
-
buildPanelLine(width, [[' Up/Down', DEFAULT_PANEL_PALETTE.info], [' navigate', DEFAULT_PANEL_PALETTE.dim]]),
|
|
198
|
-
],
|
|
199
|
-
palette: DEFAULT_PANEL_PALETTE,
|
|
200
|
-
});
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
// --------------------------------------------------------------------------
|
|
204
|
-
// Header — title + overall completion percentage
|
|
205
|
-
// --------------------------------------------------------------------------
|
|
206
|
-
|
|
207
|
-
private renderPhaseHeaderLine(phase: string, items: PlanItem[], width: number): Line {
|
|
208
|
-
const done = items.filter(
|
|
209
|
-
(i) => i.status === 'complete' || i.status === 'skipped',
|
|
210
|
-
).length;
|
|
211
|
-
const total = items.length;
|
|
212
|
-
const active = items.some((i) => i.status === 'in_progress');
|
|
213
|
-
const failed = items.some((i) => i.status === 'failed');
|
|
214
|
-
|
|
215
|
-
const phaseFg = failed ? '#ef4444' : active ? '#00ffff' : done === total ? '#22c55e' : '250';
|
|
216
|
-
|
|
217
|
-
const barW = 8;
|
|
218
|
-
const filledB = total > 0 ? Math.round((done / total) * barW) : 0;
|
|
219
|
-
const bar = '#'.repeat(filledB) + '-'.repeat(barW - filledB);
|
|
220
|
-
|
|
221
|
-
const progressText = `[${bar}] ${done}/${total}`;
|
|
222
|
-
const phaseText = ` > ${phase}`;
|
|
223
|
-
const spacer = Math.max(1, width - phaseText.length - progressText.length - 1);
|
|
224
|
-
return buildPanelLine(width, [
|
|
225
|
-
[phaseText, phaseFg],
|
|
226
|
-
[' '.repeat(spacer), phaseFg],
|
|
227
|
-
[progressText, phaseFg],
|
|
228
|
-
[' ', phaseFg],
|
|
229
|
-
]);
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
// --------------------------------------------------------------------------
|
|
233
|
-
// Individual item
|
|
234
|
-
// --------------------------------------------------------------------------
|
|
235
|
-
|
|
236
|
-
private renderItem(
|
|
237
|
-
item: PlanItem,
|
|
238
|
-
isSelected: boolean,
|
|
239
|
-
isBlocked: boolean,
|
|
240
|
-
width: number,
|
|
241
|
-
): Line {
|
|
242
|
-
const icon = STATUS_ICON[item.status];
|
|
243
|
-
const fg = isBlocked ? '238' : STATUS_FG[item.status];
|
|
244
|
-
const dim = item.status === 'skipped' || isBlocked;
|
|
245
|
-
|
|
246
|
-
// Indent blocked items to visually signal they depend on others
|
|
247
|
-
const indent = isBlocked ? ' ' : ' ';
|
|
248
|
-
const selectedMark = isSelected ? '▸' : ' ';
|
|
249
|
-
|
|
250
|
-
let text = `${selectedMark}${indent}${icon} ${item.description}`;
|
|
251
|
-
|
|
252
|
-
// Append agent ID for in-progress and complete items
|
|
253
|
-
if (item.agentId && (item.status === 'in_progress' || item.status === 'complete')) {
|
|
254
|
-
text += ` [${item.agentId}]`;
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
// Append dependency note for blocked items (first unmet dep description)
|
|
258
|
-
if (isBlocked && item.dependencies && item.dependencies.length > 0) {
|
|
259
|
-
text += ' (blocked)';
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
return buildPanelLine(width, [[text, fg, isSelected ? '#1e293b' : undefined]]);
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
private statusColor(status: ExecutionPlan['status']): string {
|
|
266
|
-
return status === 'complete'
|
|
267
|
-
? DEFAULT_PANEL_PALETTE.good
|
|
268
|
-
: status === 'failed'
|
|
269
|
-
? DEFAULT_PANEL_PALETTE.bad
|
|
270
|
-
: status === 'active'
|
|
271
|
-
? DEFAULT_PANEL_PALETTE.info
|
|
272
|
-
: DEFAULT_PANEL_PALETTE.dim;
|
|
273
|
-
}
|
|
274
|
-
}
|