plankit-cli 1.3.1 → 1.5.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 +104 -3
- package/package.json +1 -1
- package/src/agents.js +8 -4
- package/src/analyzer/dotnetScanner.js +111 -0
- package/src/analyzer/engine.js +290 -0
- package/src/analyzer/vueScanner.js +200 -0
- package/src/cli.js +165 -5
- package/src/commandBundles.js +105 -0
- package/src/config.js +20 -2
- package/src/dashboard/dashboard.js +272 -0
- package/templates/PLANKIT.md +7 -0
- package/templates/dotnet-commands/codex/dotnet-architecture-audit.md +25 -0
- package/templates/dotnet-commands/codex/dotnet-clean-guardrails.md +24 -0
- package/templates/dotnet-commands/codex/dotnet-ef-migration.md +25 -0
- package/templates/dotnet-commands/codex/dotnet-endpoint-from-model.md +26 -0
- package/templates/dotnet-commands/codex/dotnet-extract-service.md +25 -0
- package/templates/dotnet-commands/codex/dotnet-feature.md +26 -0
- package/templates/dotnet-commands/codex/dotnet-generate-tests.md +25 -0
- package/templates/dotnet-commands/codex/dotnet-health.md +24 -0
- package/templates/dotnet-commands/codex/dotnet-migrate-minimal-api.md +25 -0
- package/templates/dotnet-commands/codex/dotnet-modernize.md +25 -0
- package/templates/dotnet-commands/cursor/dotnet-architecture-audit.md +26 -0
- package/templates/dotnet-commands/cursor/dotnet-clean-guardrails.md +25 -0
- package/templates/dotnet-commands/cursor/dotnet-ef-migration.md +26 -0
- package/templates/dotnet-commands/cursor/dotnet-endpoint-from-model.md +27 -0
- package/templates/dotnet-commands/cursor/dotnet-extract-service.md +26 -0
- package/templates/dotnet-commands/cursor/dotnet-feature.md +27 -0
- package/templates/dotnet-commands/cursor/dotnet-generate-tests.md +26 -0
- package/templates/dotnet-commands/cursor/dotnet-health.md +25 -0
- package/templates/dotnet-commands/cursor/dotnet-migrate-minimal-api.md +26 -0
- package/templates/dotnet-commands/cursor/dotnet-modernize.md +26 -0
- package/templates/dotnet-commands/opencode/dotnet-architecture-audit.md +23 -0
- package/templates/dotnet-commands/opencode/dotnet-clean-guardrails.md +22 -0
- package/templates/dotnet-commands/opencode/dotnet-ef-migration.md +23 -0
- package/templates/dotnet-commands/opencode/dotnet-endpoint-from-model.md +24 -0
- package/templates/dotnet-commands/opencode/dotnet-extract-service.md +23 -0
- package/templates/dotnet-commands/opencode/dotnet-feature.md +24 -0
- package/templates/dotnet-commands/opencode/dotnet-generate-tests.md +23 -0
- package/templates/dotnet-commands/opencode/dotnet-health.md +22 -0
- package/templates/dotnet-commands/opencode/dotnet-migrate-minimal-api.md +23 -0
- package/templates/dotnet-commands/opencode/dotnet-modernize.md +23 -0
- package/templates/dotnet-skills/gemini/dotnet-architecture-audit/SKILL.md +26 -0
- package/templates/dotnet-skills/gemini/dotnet-clean-guardrails/SKILL.md +25 -0
- package/templates/dotnet-skills/gemini/dotnet-ef-migration/SKILL.md +26 -0
- package/templates/dotnet-skills/gemini/dotnet-endpoint-from-model/SKILL.md +27 -0
- package/templates/dotnet-skills/gemini/dotnet-extract-service/SKILL.md +26 -0
- package/templates/dotnet-skills/gemini/dotnet-feature/SKILL.md +27 -0
- package/templates/dotnet-skills/gemini/dotnet-generate-tests/SKILL.md +26 -0
- package/templates/dotnet-skills/gemini/dotnet-health/SKILL.md +25 -0
- package/templates/dotnet-skills/gemini/dotnet-migrate-minimal-api/SKILL.md +26 -0
- package/templates/dotnet-skills/gemini/dotnet-modernize/SKILL.md +26 -0
- package/templates/vue-commands/codex/component-pattern-audit.md +24 -0
- package/templates/vue-commands/codex/design-token-discover.md +24 -0
- package/templates/vue-commands/codex/design-token-migrate.md +24 -0
- package/templates/vue-commands/codex/js-to-ts.md +25 -0
- package/templates/vue-commands/codex/reactivity-audit.md +25 -0
- package/templates/vue-commands/codex/state-strategy-audit.md +23 -0
- package/templates/vue-commands/codex/vue-guardrails.md +24 -0
- package/templates/vue-commands/codex/vue-health.md +28 -0
- package/templates/vue-commands/codex/vue-legacy-map.md +25 -0
- package/templates/vue-commands/codex/vue-migration-plan.md +24 -0
- package/templates/vue-commands/codex/vue-modernize-slice.md +26 -0
- package/templates/vue-commands/codex/vue-pattern-map.md +24 -0
- package/templates/vue-commands/codex/vue-standardize.md +26 -0
- package/templates/vue-commands/codex/vue-style-audit.md +24 -0
- package/templates/vue-commands/codex/vue-target-architecture.md +24 -0
- package/templates/vue-commands/cursor/component-pattern-audit.md +25 -0
- package/templates/vue-commands/cursor/design-token-discover.md +25 -0
- package/templates/vue-commands/cursor/design-token-migrate.md +25 -0
- package/templates/vue-commands/cursor/js-to-ts.md +26 -0
- package/templates/vue-commands/cursor/reactivity-audit.md +26 -0
- package/templates/vue-commands/cursor/state-strategy-audit.md +24 -0
- package/templates/vue-commands/cursor/vue-guardrails.md +25 -0
- package/templates/vue-commands/cursor/vue-health.md +29 -0
- package/templates/vue-commands/cursor/vue-legacy-map.md +26 -0
- package/templates/vue-commands/cursor/vue-migration-plan.md +25 -0
- package/templates/vue-commands/cursor/vue-modernize-slice.md +27 -0
- package/templates/vue-commands/cursor/vue-pattern-map.md +25 -0
- package/templates/vue-commands/cursor/vue-standardize.md +27 -0
- package/templates/vue-commands/cursor/vue-style-audit.md +25 -0
- package/templates/vue-commands/cursor/vue-target-architecture.md +25 -0
- package/templates/vue-commands/opencode/component-pattern-audit.md +22 -0
- package/templates/vue-commands/opencode/design-token-discover.md +22 -0
- package/templates/vue-commands/opencode/design-token-migrate.md +22 -0
- package/templates/vue-commands/opencode/js-to-ts.md +23 -0
- package/templates/vue-commands/opencode/reactivity-audit.md +23 -0
- package/templates/vue-commands/opencode/state-strategy-audit.md +21 -0
- package/templates/vue-commands/opencode/vue-guardrails.md +22 -0
- package/templates/vue-commands/opencode/vue-health.md +26 -0
- package/templates/vue-commands/opencode/vue-legacy-map.md +23 -0
- package/templates/vue-commands/opencode/vue-migration-plan.md +22 -0
- package/templates/vue-commands/opencode/vue-modernize-slice.md +24 -0
- package/templates/vue-commands/opencode/vue-pattern-map.md +22 -0
- package/templates/vue-commands/opencode/vue-standardize.md +24 -0
- package/templates/vue-commands/opencode/vue-style-audit.md +22 -0
- package/templates/vue-commands/opencode/vue-target-architecture.md +22 -0
- package/templates/vue-skills/gemini/component-pattern-audit/SKILL.md +25 -0
- package/templates/vue-skills/gemini/design-token-discover/SKILL.md +25 -0
- package/templates/vue-skills/gemini/design-token-migrate/SKILL.md +25 -0
- package/templates/vue-skills/gemini/js-to-ts/SKILL.md +26 -0
- package/templates/vue-skills/gemini/reactivity-audit/SKILL.md +26 -0
- package/templates/vue-skills/gemini/state-strategy-audit/SKILL.md +24 -0
- package/templates/vue-skills/gemini/vue-guardrails/SKILL.md +25 -0
- package/templates/vue-skills/gemini/vue-health/SKILL.md +29 -0
- package/templates/vue-skills/gemini/vue-legacy-map/SKILL.md +26 -0
- package/templates/vue-skills/gemini/vue-migration-plan/SKILL.md +25 -0
- package/templates/vue-skills/gemini/vue-modernize-slice/SKILL.md +27 -0
- package/templates/vue-skills/gemini/vue-pattern-map/SKILL.md +25 -0
- package/templates/vue-skills/gemini/vue-standardize/SKILL.md +27 -0
- package/templates/vue-skills/gemini/vue-style-audit/SKILL.md +25 -0
- package/templates/vue-skills/gemini/vue-target-architecture/SKILL.md +25 -0
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import readline from 'node:readline';
|
|
4
|
+
import { listDirectories, safeJoin } from '../config.js';
|
|
5
|
+
import { runAnalysis, formatReport } from '../analyzer/engine.js';
|
|
6
|
+
|
|
7
|
+
export function loadDashboardData(cwd, config) {
|
|
8
|
+
const artifactsDir = safeJoin(cwd, config.artifactsDir || 'artifacts');
|
|
9
|
+
const currentDir = path.join(artifactsDir, 'current');
|
|
10
|
+
const archivedDir = path.join(artifactsDir, 'archived');
|
|
11
|
+
|
|
12
|
+
const activeNames = listDirectories(currentDir);
|
|
13
|
+
const archivedNames = listDirectories(archivedDir);
|
|
14
|
+
|
|
15
|
+
const activeFeatures = activeNames.map((name) => {
|
|
16
|
+
const featureDir = path.join(currentDir, name);
|
|
17
|
+
const phasesDir = path.join(featureDir, 'phases');
|
|
18
|
+
const outputsDir = path.join(featureDir, 'outputs');
|
|
19
|
+
|
|
20
|
+
const phaseFiles = fs.existsSync(phasesDir)
|
|
21
|
+
? fs.readdirSync(phasesDir).filter((f) => f.startsWith('phase-') && f.endsWith('.md')).sort()
|
|
22
|
+
: [];
|
|
23
|
+
const outputFiles = fs.existsSync(outputsDir)
|
|
24
|
+
? fs.readdirSync(outputsDir).filter((f) => f.startsWith('phase-') && f.endsWith('.md')).sort()
|
|
25
|
+
: [];
|
|
26
|
+
|
|
27
|
+
let state = null;
|
|
28
|
+
const stateFile = path.join(featureDir, 'plankit.json');
|
|
29
|
+
if (fs.existsSync(stateFile)) {
|
|
30
|
+
try {
|
|
31
|
+
state = JSON.parse(fs.readFileSync(stateFile, 'utf8'));
|
|
32
|
+
} catch {
|
|
33
|
+
state = null;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const phases = phaseFiles.map((pf, idx) => {
|
|
38
|
+
const num = idx + 1;
|
|
39
|
+
const expectedOutput = `phase-${num}-output.md`;
|
|
40
|
+
const hasOutput = outputFiles.includes(expectedOutput);
|
|
41
|
+
return {
|
|
42
|
+
number: num,
|
|
43
|
+
specFile: pf,
|
|
44
|
+
hasOutput,
|
|
45
|
+
status: hasOutput ? 'DONE' : (num === outputFiles.length + 1 ? 'IN_PROGRESS' : 'PENDING')
|
|
46
|
+
};
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
const completedCount = phases.filter((p) => p.hasOutput).length;
|
|
50
|
+
const totalCount = phases.length || 1;
|
|
51
|
+
const progressPercent = Math.round((completedCount / totalCount) * 100);
|
|
52
|
+
|
|
53
|
+
return {
|
|
54
|
+
name,
|
|
55
|
+
phases,
|
|
56
|
+
phaseCount: phases.length,
|
|
57
|
+
completedCount,
|
|
58
|
+
progressPercent,
|
|
59
|
+
state
|
|
60
|
+
};
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
return {
|
|
64
|
+
activeFeatures,
|
|
65
|
+
archivedCount: archivedNames.length,
|
|
66
|
+
archivedNames
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export function renderStaticDashboard(data, io) {
|
|
71
|
+
io.stdout('================================================================');
|
|
72
|
+
io.stdout(' PlanKit Feature Management Matrix ');
|
|
73
|
+
io.stdout('================================================================');
|
|
74
|
+
io.stdout(`Active Features: ${data.activeFeatures.length} | Archived Features: ${data.archivedCount}`);
|
|
75
|
+
io.stdout('');
|
|
76
|
+
|
|
77
|
+
if (data.activeFeatures.length === 0) {
|
|
78
|
+
io.stdout(' No active features found in artifacts/current/.');
|
|
79
|
+
io.stdout(' Run "plankit plan <feature-name>" to start a feature.');
|
|
80
|
+
io.stdout('================================================================');
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
io.stdout(padRight('Feature Name', 25) + padRight('Phases', 12) + padRight('Progress', 20) + 'Status');
|
|
85
|
+
io.stdout('-'.repeat(64));
|
|
86
|
+
|
|
87
|
+
data.activeFeatures.forEach((feat) => {
|
|
88
|
+
const progressText = `${progressBar(feat.progressPercent, 10)} ${feat.progressPercent}%`;
|
|
89
|
+
const statusText = feat.completedCount === feat.phaseCount ? 'READY_FOR_REVIEW' : `PHASE_${feat.completedCount + 1}`;
|
|
90
|
+
io.stdout(padRight(feat.name, 25) + padRight(`${feat.completedCount}/${feat.phaseCount}`, 12) + padRight(progressText, 20) + statusText);
|
|
91
|
+
|
|
92
|
+
feat.phases.forEach((p) => {
|
|
93
|
+
const check = p.hasOutput ? '[x]' : '[ ]';
|
|
94
|
+
io.stdout(` ${check} Phase ${p.number}: ${p.specFile} (${p.status})`);
|
|
95
|
+
});
|
|
96
|
+
io.stdout('');
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
io.stdout('================================================================');
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export async function runInteractiveDashboard(cwd, io, config, handlers = {}) {
|
|
103
|
+
const isTTY = Boolean(process.stdin.isTTY && process.stdout.isTTY);
|
|
104
|
+
const data = loadDashboardData(cwd, config);
|
|
105
|
+
|
|
106
|
+
if (!isTTY) {
|
|
107
|
+
renderStaticDashboard(data, io);
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
let selectedIndex = 0;
|
|
112
|
+
let statusMessage = 'Use [↑/↓] or [j/k] to navigate. Press [q] to exit.';
|
|
113
|
+
|
|
114
|
+
function refresh() {
|
|
115
|
+
const freshData = loadDashboardData(cwd, config);
|
|
116
|
+
console.clear();
|
|
117
|
+
console.log('\x1b[1m================================================================\x1b[0m');
|
|
118
|
+
console.log('\x1b[1m\x1b[36m PlanKit Interactive Feature Dashboard \x1b[0m');
|
|
119
|
+
console.log('\x1b[1m================================================================\x1b[0m');
|
|
120
|
+
console.log(`Active Features: \x1b[32m${freshData.activeFeatures.length}\x1b[0m | Archived Features: \x1b[33m${freshData.archivedCount}\x1b[0m`);
|
|
121
|
+
console.log('');
|
|
122
|
+
|
|
123
|
+
if (freshData.activeFeatures.length === 0) {
|
|
124
|
+
console.log(' No active features in artifacts/current/.');
|
|
125
|
+
console.log(' Press [p] to plan a new feature, or [q] to exit.');
|
|
126
|
+
console.log('\x1b[1m================================================================\x1b[0m');
|
|
127
|
+
console.log(`Status: ${statusMessage}`);
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
if (selectedIndex >= freshData.activeFeatures.length) {
|
|
132
|
+
selectedIndex = freshData.activeFeatures.length - 1;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
freshData.activeFeatures.forEach((feat, index) => {
|
|
136
|
+
const isSelected = index === selectedIndex;
|
|
137
|
+
const pointer = isSelected ? '\x1b[36m▶ \x1b[0m' : ' ';
|
|
138
|
+
const nameFmt = isSelected ? `\x1b[1m\x1b[36m${padRight(feat.name, 22)}\x1b[0m` : padRight(feat.name, 22);
|
|
139
|
+
const progress = `${progressBar(feat.progressPercent, 10)} ${feat.progressPercent}%`;
|
|
140
|
+
console.log(`${pointer}${nameFmt} ${padRight(progress, 18)} (${feat.completedCount}/${feat.phaseCount} phases)`);
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
console.log('');
|
|
144
|
+
const selectedFeature = freshData.activeFeatures[selectedIndex];
|
|
145
|
+
if (selectedFeature) {
|
|
146
|
+
console.log(`\x1b[1mPhase Breakdown for "${selectedFeature.name}":\x1b[0m`);
|
|
147
|
+
selectedFeature.phases.forEach((p) => {
|
|
148
|
+
const badge = p.hasOutput ? '\x1b[32m[COMPLETED]\x1b[0m' : '\x1b[33m[PENDING]\x1b[0m';
|
|
149
|
+
console.log(` Phase ${p.number}: ${padRight(p.specFile, 32)} ${badge}`);
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
console.log('');
|
|
154
|
+
console.log('\x1b[1m----------------------------------------------------------------\x1b[0m');
|
|
155
|
+
console.log('\x1b[2mActions: [i] Implement Next Phase | [c] Clarify | [r] Review | [s] Scan | [q] Quit\x1b[0m');
|
|
156
|
+
console.log(`\x1b[33m${statusMessage}\x1b[0m`);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
return new Promise((resolve) => {
|
|
160
|
+
readline.emitKeypressEvents(process.stdin);
|
|
161
|
+
if (process.stdin.setRawMode) {
|
|
162
|
+
process.stdin.setRawMode(true);
|
|
163
|
+
}
|
|
164
|
+
process.stdin.resume();
|
|
165
|
+
|
|
166
|
+
refresh();
|
|
167
|
+
|
|
168
|
+
const onKeypress = async (str, key) => {
|
|
169
|
+
if ((key && key.ctrl && key.name === 'c') || (key && key.name === 'q')) {
|
|
170
|
+
cleanup();
|
|
171
|
+
console.clear();
|
|
172
|
+
io.stdout('Exited PlanKit Dashboard.');
|
|
173
|
+
resolve();
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
const freshData = loadDashboardData(cwd, config);
|
|
178
|
+
const currentFeature = freshData.activeFeatures[selectedIndex];
|
|
179
|
+
|
|
180
|
+
if (key && (key.name === 'up' || key.name === 'k')) {
|
|
181
|
+
if (selectedIndex > 0) selectedIndex -= 1;
|
|
182
|
+
statusMessage = `Selected ${freshData.activeFeatures[selectedIndex]?.name || ''}`;
|
|
183
|
+
refresh();
|
|
184
|
+
} else if (key && (key.name === 'down' || key.name === 'j')) {
|
|
185
|
+
if (selectedIndex < freshData.activeFeatures.length - 1) selectedIndex += 1;
|
|
186
|
+
statusMessage = `Selected ${freshData.activeFeatures[selectedIndex]?.name || ''}`;
|
|
187
|
+
refresh();
|
|
188
|
+
} else if (str === 's') {
|
|
189
|
+
cleanup();
|
|
190
|
+
console.clear();
|
|
191
|
+
io.stdout('Running PlanKit Static Analysis...\n');
|
|
192
|
+
const report = await runAnalysis(cwd, { artifactsDir: config.artifactsDir });
|
|
193
|
+
io.stdout(formatReport(report, true));
|
|
194
|
+
io.stdout('\nPress any key to return to dashboard...');
|
|
195
|
+
process.stdin.once('data', () => {
|
|
196
|
+
readline.emitKeypressEvents(process.stdin);
|
|
197
|
+
if (process.stdin.setRawMode) process.stdin.setRawMode(true);
|
|
198
|
+
process.stdin.resume();
|
|
199
|
+
process.stdin.on('keypress', onKeypress);
|
|
200
|
+
statusMessage = 'Completed static analysis scan.';
|
|
201
|
+
refresh();
|
|
202
|
+
});
|
|
203
|
+
} else if (str === 'i' && currentFeature && handlers.implement) {
|
|
204
|
+
const nextPhase = currentFeature.completedCount + 1;
|
|
205
|
+
if (nextPhase > currentFeature.phaseCount) {
|
|
206
|
+
statusMessage = `Feature "${currentFeature.name}" has completed all phases! Press [r] to review.`;
|
|
207
|
+
refresh();
|
|
208
|
+
} else {
|
|
209
|
+
cleanup();
|
|
210
|
+
console.clear();
|
|
211
|
+
io.stdout(`Preparing Phase ${nextPhase} for "${currentFeature.name}"...\n`);
|
|
212
|
+
try {
|
|
213
|
+
await handlers.implement(currentFeature.name, nextPhase);
|
|
214
|
+
statusMessage = `Phase ${nextPhase} prepared successfully for "${currentFeature.name}".`;
|
|
215
|
+
} catch (err) {
|
|
216
|
+
statusMessage = `Error: ${err.message}`;
|
|
217
|
+
}
|
|
218
|
+
resume();
|
|
219
|
+
}
|
|
220
|
+
} else if (str === 'c' && currentFeature && handlers.clarify) {
|
|
221
|
+
cleanup();
|
|
222
|
+
console.clear();
|
|
223
|
+
try {
|
|
224
|
+
await handlers.clarify(currentFeature.name);
|
|
225
|
+
statusMessage = `Clarifications prepared for "${currentFeature.name}".`;
|
|
226
|
+
} catch (err) {
|
|
227
|
+
statusMessage = `Error: ${err.message}`;
|
|
228
|
+
}
|
|
229
|
+
resume();
|
|
230
|
+
} else if (str === 'r' && currentFeature && handlers.review) {
|
|
231
|
+
cleanup();
|
|
232
|
+
console.clear();
|
|
233
|
+
try {
|
|
234
|
+
await handlers.review(currentFeature.name);
|
|
235
|
+
statusMessage = `Feature "${currentFeature.name}" reviewed and archived.`;
|
|
236
|
+
} catch (err) {
|
|
237
|
+
statusMessage = `Review error: ${err.message}`;
|
|
238
|
+
}
|
|
239
|
+
resume();
|
|
240
|
+
}
|
|
241
|
+
};
|
|
242
|
+
|
|
243
|
+
function cleanup() {
|
|
244
|
+
process.stdin.removeListener('keypress', onKeypress);
|
|
245
|
+
if (process.stdin.setRawMode) {
|
|
246
|
+
process.stdin.setRawMode(false);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
function resume() {
|
|
251
|
+
readline.emitKeypressEvents(process.stdin);
|
|
252
|
+
if (process.stdin.setRawMode) {
|
|
253
|
+
process.stdin.setRawMode(true);
|
|
254
|
+
}
|
|
255
|
+
process.stdin.resume();
|
|
256
|
+
process.stdin.on('keypress', onKeypress);
|
|
257
|
+
refresh();
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
process.stdin.on('keypress', onKeypress);
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
function progressBar(percent, length = 10) {
|
|
265
|
+
const filled = Math.round((percent / 100) * length);
|
|
266
|
+
const empty = length - filled;
|
|
267
|
+
return `[${'='.repeat(filled)}${'-'.repeat(empty)}]`;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
function padRight(str, len) {
|
|
271
|
+
return String(str).padEnd(len, ' ');
|
|
272
|
+
}
|
package/templates/PLANKIT.md
CHANGED
|
@@ -35,6 +35,13 @@ Prepares the phase output artifact after validating that the phase spec and prio
|
|
|
35
35
|
|
|
36
36
|
Runs configured verification commands and archives the completed feature.
|
|
37
37
|
|
|
38
|
+
## Framework Suites
|
|
39
|
+
|
|
40
|
+
PlanKit supports modular framework engineering command suites selectable during `plankit init` via prompt or `--framework <angular|vue|dotnet|none|all>`:
|
|
41
|
+
- **Angular**: Deterministic Angular workflows (`component-from`, `feature`, `signalize`, `modernize`, etc.)
|
|
42
|
+
- **Vue**: Legacy modernization and standardization workflows (`vue-health`, `vue-pattern-map`, `vue-standardize`, `vue-modernize-slice`, etc.)
|
|
43
|
+
- **.NET**: Clean Architecture & Minimal API workflows (`dotnet-health`, `dotnet-architecture-audit`, `dotnet-feature`, `dotnet-modernize`, etc.)
|
|
44
|
+
|
|
38
45
|
## Customization
|
|
39
46
|
|
|
40
47
|
Configure PlanKit with `plankit.config.json`. Override generated templates by setting `templatesDir` and matching the package template file names.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# dotnet-architecture-audit
|
|
2
|
+
> Audit layer dependencies (Clean Architecture / Vertical Slices / DDD) and circular dependencies.
|
|
3
|
+
|
|
4
|
+
# /dotnet-architecture-audit
|
|
5
|
+
|
|
6
|
+
Analyze architectural layer boundaries and project references across the .NET solution.
|
|
7
|
+
|
|
8
|
+
## Workflow
|
|
9
|
+
1. Parse project references between .csproj files.
|
|
10
|
+
2. Verify Domain layer has zero external project dependencies.
|
|
11
|
+
3. Verify Application layer depends only on Domain.
|
|
12
|
+
4. Detect illegal Infrastructure/API leaks into core layers or circular dependencies.
|
|
13
|
+
5. Generate dependency graph and compliance matrix.
|
|
14
|
+
|
|
15
|
+
## Guardrail
|
|
16
|
+
Read-only architectural analysis.
|
|
17
|
+
|
|
18
|
+
## Options
|
|
19
|
+
- --strict fail on any layer boundary violation
|
|
20
|
+
- --json output dependency graph as JSON
|
|
21
|
+
|
|
22
|
+
## Execution
|
|
23
|
+
1. Run .NET solution discovery against the repository.
|
|
24
|
+
2. Apply the workflow above with the provided target.
|
|
25
|
+
3. Report files created/modified and patterns applied.
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# dotnet-clean-guardrails
|
|
2
|
+
> Generate NetArchTest architectural unit tests and EditorConfig rules to guard layer boundaries.
|
|
3
|
+
|
|
4
|
+
# /dotnet-clean-guardrails
|
|
5
|
+
|
|
6
|
+
Enforce clean architecture layer boundaries with automated architectural unit tests and EditorConfig.
|
|
7
|
+
|
|
8
|
+
## Workflow
|
|
9
|
+
1. Detect solution architecture layers (Domain, Application, Infrastructure, API).
|
|
10
|
+
2. Generate NetArchTest tests asserting layer boundaries (e.g. Domain should not reference Infrastructure).
|
|
11
|
+
3. Generate or update .editorconfig with C# formatting, naming rules, and diagnostic severities.
|
|
12
|
+
4. Run architectural tests to verify current compliance.
|
|
13
|
+
|
|
14
|
+
## Guardrail
|
|
15
|
+
Do not break legacy builds; apply warnings first or scope enforcement gradually.
|
|
16
|
+
|
|
17
|
+
## Options
|
|
18
|
+
- --netarchtest generate NetArchTest test project
|
|
19
|
+
- --editorconfig generate .editorconfig rules
|
|
20
|
+
|
|
21
|
+
## Execution
|
|
22
|
+
1. Run .NET solution discovery against the repository.
|
|
23
|
+
2. Apply the workflow above with the provided target.
|
|
24
|
+
3. Report files created/modified and patterns applied.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# dotnet-ef-migration
|
|
2
|
+
> Safe Entity Framework Core migration workflow with entity audit, SQL review, and rollback.
|
|
3
|
+
|
|
4
|
+
# /dotnet-ef-migration
|
|
5
|
+
|
|
6
|
+
Plan, generate, and review safe Entity Framework Core database migrations.
|
|
7
|
+
|
|
8
|
+
## Workflow
|
|
9
|
+
1. Audit entity configurations (Fluent API vs DataAnnotations) in target DbContext.
|
|
10
|
+
2. Check for missing indexes, foreign key cascading issues, and property lengths.
|
|
11
|
+
3. Generate migration with a descriptive name (dotnet ef migrations add <Name>).
|
|
12
|
+
4. Generate and inspect raw migration SQL script (dotnet ef migrations script).
|
|
13
|
+
5. Check for destructive schema changes (table drops, column drops, data loss warnings).
|
|
14
|
+
|
|
15
|
+
## Guardrail
|
|
16
|
+
Never execute irreversible or destructive migrations without explicit user confirmation.
|
|
17
|
+
|
|
18
|
+
## Options
|
|
19
|
+
- --name <Name> descriptive migration name
|
|
20
|
+
- --preview-sql inspect generated SQL before applying
|
|
21
|
+
|
|
22
|
+
## Execution
|
|
23
|
+
1. Run .NET solution discovery against the repository.
|
|
24
|
+
2. Apply the workflow above with the provided target.
|
|
25
|
+
3. Report files created/modified and patterns applied.
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# dotnet-endpoint-from-model
|
|
2
|
+
> Generate ASP.NET Core Minimal API or Controller endpoints from an entity/model with validation.
|
|
3
|
+
|
|
4
|
+
# /dotnet-endpoint-from-model
|
|
5
|
+
|
|
6
|
+
Generate robust CRUD endpoints from a domain model or entity.
|
|
7
|
+
|
|
8
|
+
## Workflow
|
|
9
|
+
1. Inspect entity/model properties, keys, and navigation properties.
|
|
10
|
+
2. Generate Request/Response DTOs to avoid overposting or leaking domain entities.
|
|
11
|
+
3. Generate endpoint handlers using TypedResults (Ok, Created, NotFound, ValidationProblem).
|
|
12
|
+
4. Configure authorization, route groups, and OpenAPI metadata (.WithName(), .Produces()).
|
|
13
|
+
5. Verify endpoint route constraints.
|
|
14
|
+
|
|
15
|
+
## Guardrail
|
|
16
|
+
Never expose raw database entities directly to API responses. Always map through DTOs.
|
|
17
|
+
|
|
18
|
+
## Options
|
|
19
|
+
- --minimal use ASP.NET Core Minimal APIs (default)
|
|
20
|
+
- --controller use Controller-based architecture
|
|
21
|
+
- --dto <Type> use existing DTO type
|
|
22
|
+
|
|
23
|
+
## Execution
|
|
24
|
+
1. Run .NET solution discovery against the repository.
|
|
25
|
+
2. Apply the workflow above with the provided target.
|
|
26
|
+
3. Report files created/modified and patterns applied.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# dotnet-extract-service
|
|
2
|
+
> Refactor fat services or bloated controllers into isolated CQRS handlers or domain services.
|
|
3
|
+
|
|
4
|
+
# /dotnet-extract-service
|
|
5
|
+
|
|
6
|
+
Decompose fat classes into single-responsibility handlers or domain services.
|
|
7
|
+
|
|
8
|
+
## Workflow
|
|
9
|
+
1. Identify oversized methods or multi-responsibility service classes.
|
|
10
|
+
2. Extract target method into an independent Command/Query handler or domain service.
|
|
11
|
+
3. Define required interfaces and register with Microsoft.Extensions.DependencyInjection.
|
|
12
|
+
4. Update caller references and ensure backward compatibility.
|
|
13
|
+
5. Create unit tests for extracted handler.
|
|
14
|
+
|
|
15
|
+
## Guardrail
|
|
16
|
+
Preserve existing behavior and contract signatures. Do not introduce breaking API changes.
|
|
17
|
+
|
|
18
|
+
## Options
|
|
19
|
+
- --class <Name> source class to refactor
|
|
20
|
+
- --method <Name> specific method to extract
|
|
21
|
+
|
|
22
|
+
## Execution
|
|
23
|
+
1. Run .NET solution discovery against the repository.
|
|
24
|
+
2. Apply the workflow above with the provided target.
|
|
25
|
+
3. Report files created/modified and patterns applied.
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# dotnet-feature
|
|
2
|
+
> Build an end-to-end vertical slice feature (Command/Query, MediatR, FluentValidation, Endpoint).
|
|
3
|
+
|
|
4
|
+
# /dotnet-feature
|
|
5
|
+
|
|
6
|
+
Generate a complete, self-contained feature slice following Vertical Slice Architecture.
|
|
7
|
+
|
|
8
|
+
## Workflow
|
|
9
|
+
1. Determine feature name, operation type (Command or Query), and target domain.
|
|
10
|
+
2. Generate Request and Response DTO records with immutable properties.
|
|
11
|
+
3. Generate FluentValidation validator with standard validation rules.
|
|
12
|
+
4. Generate MediatR / Wolverine handler with DbContext or repository access.
|
|
13
|
+
5. Expose via Minimal API endpoint or Controller with TypedResults.
|
|
14
|
+
6. Scaffold unit tests and integration tests.
|
|
15
|
+
|
|
16
|
+
## Guardrail
|
|
17
|
+
Adhere to existing solution conventions (Vertical Slices vs Clean Architecture). Do not introduce unnecessary abstractions.
|
|
18
|
+
|
|
19
|
+
## Options
|
|
20
|
+
- --type <command|query> operation type
|
|
21
|
+
- --model <Entity> domain entity to base feature on
|
|
22
|
+
|
|
23
|
+
## Execution
|
|
24
|
+
1. Run .NET solution discovery against the repository.
|
|
25
|
+
2. Apply the workflow above with the provided target.
|
|
26
|
+
3. Report files created/modified and patterns applied.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# dotnet-generate-tests
|
|
2
|
+
> Generate xUnit/NUnit tests with FluentAssertions and WebApplicationFactory integration tests.
|
|
3
|
+
|
|
4
|
+
# /dotnet-generate-tests
|
|
5
|
+
|
|
6
|
+
Generate comprehensive unit and integration tests for .NET handlers, services, and endpoints.
|
|
7
|
+
|
|
8
|
+
## Workflow
|
|
9
|
+
1. Inspect target class (Handler, Validator, Service, or Endpoint).
|
|
10
|
+
2. Generate unit tests covering valid input, boundary conditions, and error cases.
|
|
11
|
+
3. Use Moq or NSubstitute for dependencies and FluentAssertions for assertions.
|
|
12
|
+
4. For endpoints, generate WebApplicationFactory integration tests verifying status codes and payloads.
|
|
13
|
+
5. Run tests with dotnet test.
|
|
14
|
+
|
|
15
|
+
## Guardrail
|
|
16
|
+
Mock only external boundaries (I/O, database, third-party APIs); test real business domain logic.
|
|
17
|
+
|
|
18
|
+
## Options
|
|
19
|
+
- --framework <xunit|nunit> test framework (default: xunit)
|
|
20
|
+
- --integration generate WebApplicationFactory integration tests
|
|
21
|
+
|
|
22
|
+
## Execution
|
|
23
|
+
1. Run .NET solution discovery against the repository.
|
|
24
|
+
2. Apply the workflow above with the provided target.
|
|
25
|
+
3. Report files created/modified and patterns applied.
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# dotnet-health
|
|
2
|
+
> Audit .NET solution health: SDK versions, NuGet packages, vulnerabilities, and compiler warnings.
|
|
3
|
+
|
|
4
|
+
# /dotnet-health
|
|
5
|
+
|
|
6
|
+
Comprehensive health check for .NET solutions and projects.
|
|
7
|
+
|
|
8
|
+
## Workflow
|
|
9
|
+
1. Locate .sln and .csproj files, target frameworks (e.g. net8.0, net9.0), and SDK versions.
|
|
10
|
+
2. Check for vulnerable and outdated NuGet packages (dotnet list package --vulnerable).
|
|
11
|
+
3. Audit nullable reference types (<Nullable>enable</Nullable>) and compiler warning configurations.
|
|
12
|
+
4. Output structured markdown diagnostic report with prioritized security and health recommendations.
|
|
13
|
+
|
|
14
|
+
## Guardrail
|
|
15
|
+
Read-only diagnostic audit. Never modify project files during health check.
|
|
16
|
+
|
|
17
|
+
## Options
|
|
18
|
+
- --json output machine-readable JSON metrics
|
|
19
|
+
- --project <path> restrict audit to a specific project
|
|
20
|
+
|
|
21
|
+
## Execution
|
|
22
|
+
1. Run .NET solution discovery against the repository.
|
|
23
|
+
2. Apply the workflow above with the provided target.
|
|
24
|
+
3. Report files created/modified and patterns applied.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# dotnet-migrate-minimal-api
|
|
2
|
+
> Migrate ASP.NET Core controllers to modern Minimal APIs with RouteGroups and typed results.
|
|
3
|
+
|
|
4
|
+
# /dotnet-migrate-minimal-api
|
|
5
|
+
|
|
6
|
+
Refactor traditional controllers to modern, high-performance Minimal API route groups.
|
|
7
|
+
|
|
8
|
+
## Workflow
|
|
9
|
+
1. Inspect controller routes, actions, authorization attributes, and filter pipeline.
|
|
10
|
+
2. Create endpoint extension class (MapXxxEndpoints()) using MapGroup().
|
|
11
|
+
3. Convert ActionResult<T> to TypedResults with explicit return types.
|
|
12
|
+
4. Replace controller DI with endpoint parameter injection ([FromServices], [FromBody]).
|
|
13
|
+
5. Verify route parity and run integration tests.
|
|
14
|
+
|
|
15
|
+
## Guardrail
|
|
16
|
+
Preserve exact route paths, query parameter names, and HTTP status code behaviors.
|
|
17
|
+
|
|
18
|
+
## Options
|
|
19
|
+
- --controller <Name> name of the controller to migrate
|
|
20
|
+
- --dry-run preview changes without modifying files
|
|
21
|
+
|
|
22
|
+
## Execution
|
|
23
|
+
1. Run .NET solution discovery against the repository.
|
|
24
|
+
2. Apply the workflow above with the provided target.
|
|
25
|
+
3. Report files created/modified and patterns applied.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# dotnet-modernize
|
|
2
|
+
> Upgrade legacy C# code to modern C# 12+ / .NET 8+ patterns (primary constructors, pattern matching).
|
|
3
|
+
|
|
4
|
+
# /dotnet-modernize
|
|
5
|
+
|
|
6
|
+
Modernize legacy C# syntax using modern C# language features.
|
|
7
|
+
|
|
8
|
+
## Workflow
|
|
9
|
+
1. Convert block-scoped namespaces to file-scoped namespaces (namespace X;).
|
|
10
|
+
2. Convert classes/records with boilerplate constructors to primary constructors where appropriate.
|
|
11
|
+
3. Adopt collection expressions ([] instead of new List<T>(), Array.Empty<T>()).
|
|
12
|
+
4. Use pattern matching (is not null, switch expressions, property patterns).
|
|
13
|
+
5. Build solution and run test suite to verify zero semantic changes.
|
|
14
|
+
|
|
15
|
+
## Guardrail
|
|
16
|
+
Only apply safe, semantic-preserving modernizations. Never compromise readability for conciseness.
|
|
17
|
+
|
|
18
|
+
## Options
|
|
19
|
+
- --project <path> target specific project
|
|
20
|
+
- --dry-run preview modernization diffs
|
|
21
|
+
|
|
22
|
+
## Execution
|
|
23
|
+
1. Run .NET solution discovery against the repository.
|
|
24
|
+
2. Apply the workflow above with the provided target.
|
|
25
|
+
3. Report files created/modified and patterns applied.
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Audit layer dependencies (Clean Architecture / Vertical Slices / DDD) and circular dependencies.
|
|
3
|
+
globs: **/*.cs, **/*.csproj, **/*.sln
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# dotnet-architecture-audit
|
|
7
|
+
|
|
8
|
+
# /dotnet-architecture-audit
|
|
9
|
+
|
|
10
|
+
Analyze architectural layer boundaries and project references across the .NET solution.
|
|
11
|
+
|
|
12
|
+
## Workflow
|
|
13
|
+
1. Parse project references between .csproj files.
|
|
14
|
+
2. Verify Domain layer has zero external project dependencies.
|
|
15
|
+
3. Verify Application layer depends only on Domain.
|
|
16
|
+
4. Detect illegal Infrastructure/API leaks into core layers or circular dependencies.
|
|
17
|
+
5. Generate dependency graph and compliance matrix.
|
|
18
|
+
|
|
19
|
+
## Guardrail
|
|
20
|
+
Read-only architectural analysis.
|
|
21
|
+
|
|
22
|
+
## Options
|
|
23
|
+
- --strict fail on any layer boundary violation
|
|
24
|
+
- --json output dependency graph as JSON
|
|
25
|
+
|
|
26
|
+
Follow this workflow whenever asked to build, modernize, or test .NET code in this repository.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Generate NetArchTest architectural unit tests and EditorConfig rules to guard layer boundaries.
|
|
3
|
+
globs: **/*.cs, **/*.csproj, **/*.sln
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# dotnet-clean-guardrails
|
|
7
|
+
|
|
8
|
+
# /dotnet-clean-guardrails
|
|
9
|
+
|
|
10
|
+
Enforce clean architecture layer boundaries with automated architectural unit tests and EditorConfig.
|
|
11
|
+
|
|
12
|
+
## Workflow
|
|
13
|
+
1. Detect solution architecture layers (Domain, Application, Infrastructure, API).
|
|
14
|
+
2. Generate NetArchTest tests asserting layer boundaries (e.g. Domain should not reference Infrastructure).
|
|
15
|
+
3. Generate or update .editorconfig with C# formatting, naming rules, and diagnostic severities.
|
|
16
|
+
4. Run architectural tests to verify current compliance.
|
|
17
|
+
|
|
18
|
+
## Guardrail
|
|
19
|
+
Do not break legacy builds; apply warnings first or scope enforcement gradually.
|
|
20
|
+
|
|
21
|
+
## Options
|
|
22
|
+
- --netarchtest generate NetArchTest test project
|
|
23
|
+
- --editorconfig generate .editorconfig rules
|
|
24
|
+
|
|
25
|
+
Follow this workflow whenever asked to build, modernize, or test .NET code in this repository.
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Safe Entity Framework Core migration workflow with entity audit, SQL review, and rollback.
|
|
3
|
+
globs: **/*.cs, **/*.csproj, **/*.sln
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# dotnet-ef-migration
|
|
7
|
+
|
|
8
|
+
# /dotnet-ef-migration
|
|
9
|
+
|
|
10
|
+
Plan, generate, and review safe Entity Framework Core database migrations.
|
|
11
|
+
|
|
12
|
+
## Workflow
|
|
13
|
+
1. Audit entity configurations (Fluent API vs DataAnnotations) in target DbContext.
|
|
14
|
+
2. Check for missing indexes, foreign key cascading issues, and property lengths.
|
|
15
|
+
3. Generate migration with a descriptive name (dotnet ef migrations add <Name>).
|
|
16
|
+
4. Generate and inspect raw migration SQL script (dotnet ef migrations script).
|
|
17
|
+
5. Check for destructive schema changes (table drops, column drops, data loss warnings).
|
|
18
|
+
|
|
19
|
+
## Guardrail
|
|
20
|
+
Never execute irreversible or destructive migrations without explicit user confirmation.
|
|
21
|
+
|
|
22
|
+
## Options
|
|
23
|
+
- --name <Name> descriptive migration name
|
|
24
|
+
- --preview-sql inspect generated SQL before applying
|
|
25
|
+
|
|
26
|
+
Follow this workflow whenever asked to build, modernize, or test .NET code in this repository.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Generate ASP.NET Core Minimal API or Controller endpoints from an entity/model with validation.
|
|
3
|
+
globs: **/*.cs, **/*.csproj, **/*.sln
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# dotnet-endpoint-from-model
|
|
7
|
+
|
|
8
|
+
# /dotnet-endpoint-from-model
|
|
9
|
+
|
|
10
|
+
Generate robust CRUD endpoints from a domain model or entity.
|
|
11
|
+
|
|
12
|
+
## Workflow
|
|
13
|
+
1. Inspect entity/model properties, keys, and navigation properties.
|
|
14
|
+
2. Generate Request/Response DTOs to avoid overposting or leaking domain entities.
|
|
15
|
+
3. Generate endpoint handlers using TypedResults (Ok, Created, NotFound, ValidationProblem).
|
|
16
|
+
4. Configure authorization, route groups, and OpenAPI metadata (.WithName(), .Produces()).
|
|
17
|
+
5. Verify endpoint route constraints.
|
|
18
|
+
|
|
19
|
+
## Guardrail
|
|
20
|
+
Never expose raw database entities directly to API responses. Always map through DTOs.
|
|
21
|
+
|
|
22
|
+
## Options
|
|
23
|
+
- --minimal use ASP.NET Core Minimal APIs (default)
|
|
24
|
+
- --controller use Controller-based architecture
|
|
25
|
+
- --dto <Type> use existing DTO type
|
|
26
|
+
|
|
27
|
+
Follow this workflow whenever asked to build, modernize, or test .NET code in this repository.
|