pdd-skills 3.0.2 → 3.0.3
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/bin/pdd.js +3 -1
- package/lib/vm/dashboard/api-routes.js +66 -9
- package/lib/vm/dashboard/server.js +1 -1
- package/lib/vm/dashboard/static/index.html +6 -6
- package/lib/vm/dashboard/static/js/app.js +7 -2
- package/lib/vm/dashboard/static/js/charts.js +1 -1
- package/lib/vm/data-provider.js +3 -2
- package/lib/vm/event-bus.js +1 -1
- package/package.json +1 -1
package/bin/pdd.js
CHANGED
|
@@ -252,7 +252,9 @@ program
|
|
|
252
252
|
.option('-r, --refresh <sec>', '自动刷新间隔(秒)', '30')
|
|
253
253
|
.action(async (options) => {
|
|
254
254
|
const { DashboardServer } = await import('../lib/vm/dashboard/server.js');
|
|
255
|
-
const
|
|
255
|
+
const { PDDDataProvider } = await import('../lib/vm/data-provider.js');
|
|
256
|
+
const dataProvider = new PDDDataProvider(process.cwd());
|
|
257
|
+
const server = new DashboardServer(dataProvider);
|
|
256
258
|
await server.start(parseInt(options.port, 10), {
|
|
257
259
|
open: !options.noBrowser && !options.noOpen,
|
|
258
260
|
refreshInterval: parseInt(options.refresh, 10) * 1000
|
|
@@ -122,7 +122,15 @@ async function getProject(req, dataProvider) {
|
|
|
122
122
|
}
|
|
123
123
|
};
|
|
124
124
|
} catch (err) {
|
|
125
|
-
|
|
125
|
+
return {
|
|
126
|
+
success: true,
|
|
127
|
+
data: {
|
|
128
|
+
summary: {},
|
|
129
|
+
schemaVersion: '1.0.0',
|
|
130
|
+
timestamp: new Date().toISOString(),
|
|
131
|
+
notice: '项目尚未初始化'
|
|
132
|
+
}
|
|
133
|
+
};
|
|
126
134
|
}
|
|
127
135
|
}
|
|
128
136
|
|
|
@@ -152,7 +160,15 @@ async function getFeatures(req, dataProvider) {
|
|
|
152
160
|
}
|
|
153
161
|
};
|
|
154
162
|
} catch (err) {
|
|
155
|
-
|
|
163
|
+
return {
|
|
164
|
+
success: true,
|
|
165
|
+
data: {
|
|
166
|
+
features: [],
|
|
167
|
+
total: 0,
|
|
168
|
+
timestamp: new Date().toISOString(),
|
|
169
|
+
notice: '项目尚未初始化'
|
|
170
|
+
}
|
|
171
|
+
};
|
|
156
172
|
}
|
|
157
173
|
}
|
|
158
174
|
|
|
@@ -213,7 +229,14 @@ async function getSummary(req, dataProvider) {
|
|
|
213
229
|
}
|
|
214
230
|
};
|
|
215
231
|
} catch (err) {
|
|
216
|
-
|
|
232
|
+
return {
|
|
233
|
+
success: true,
|
|
234
|
+
data: {
|
|
235
|
+
summary: { totalFeatures: 0, doneCount: 0, avgScore: 0, tokensUsed: 0, tokensTotal: 0 },
|
|
236
|
+
timestamp: new Date().toISOString(),
|
|
237
|
+
notice: '项目尚未初始化'
|
|
238
|
+
}
|
|
239
|
+
};
|
|
217
240
|
}
|
|
218
241
|
}
|
|
219
242
|
|
|
@@ -234,7 +257,14 @@ async function getQualityMatrix(req, dataProvider) {
|
|
|
234
257
|
}
|
|
235
258
|
};
|
|
236
259
|
} catch (err) {
|
|
237
|
-
|
|
260
|
+
return {
|
|
261
|
+
success: true,
|
|
262
|
+
data: {
|
|
263
|
+
matrix: {},
|
|
264
|
+
timestamp: new Date().toISOString(),
|
|
265
|
+
notice: '项目尚未初始化'
|
|
266
|
+
}
|
|
267
|
+
};
|
|
238
268
|
}
|
|
239
269
|
}
|
|
240
270
|
|
|
@@ -288,12 +318,11 @@ async function getCacheStats(req, dataProvider) {
|
|
|
288
318
|
*/
|
|
289
319
|
async function getIterationList(req, dataProvider) {
|
|
290
320
|
try {
|
|
291
|
-
// 如果 dataProvider 支持迭代查询
|
|
292
321
|
let iterations = [];
|
|
293
322
|
|
|
294
323
|
if (typeof dataProvider.getIterations === 'function') {
|
|
295
324
|
iterations = dataProvider.getIterations() || [];
|
|
296
|
-
} else if (dataProvider.summary &&
|
|
325
|
+
} else if (dataProvider.summary && dataProvider.summary.iterations) {
|
|
297
326
|
iterations = dataProvider.summary.iterations || [];
|
|
298
327
|
}
|
|
299
328
|
|
|
@@ -306,7 +335,14 @@ async function getIterationList(req, dataProvider) {
|
|
|
306
335
|
}
|
|
307
336
|
};
|
|
308
337
|
} catch (err) {
|
|
309
|
-
|
|
338
|
+
return {
|
|
339
|
+
success: true,
|
|
340
|
+
data: {
|
|
341
|
+
iterations: [],
|
|
342
|
+
total: 0,
|
|
343
|
+
timestamp: new Date().toISOString()
|
|
344
|
+
}
|
|
345
|
+
};
|
|
310
346
|
}
|
|
311
347
|
}
|
|
312
348
|
|
|
@@ -335,7 +371,19 @@ async function getSystemHealth(req, dataProvider) {
|
|
|
335
371
|
}
|
|
336
372
|
};
|
|
337
373
|
} catch (err) {
|
|
338
|
-
|
|
374
|
+
return {
|
|
375
|
+
success: true,
|
|
376
|
+
data: {
|
|
377
|
+
health: {
|
|
378
|
+
status: 'ok',
|
|
379
|
+
uptime: process.uptime(),
|
|
380
|
+
memory: process.memoryUsage(),
|
|
381
|
+
platform: process.platform,
|
|
382
|
+
nodeVersion: process.version
|
|
383
|
+
},
|
|
384
|
+
timestamp: new Date().toISOString()
|
|
385
|
+
}
|
|
386
|
+
};
|
|
339
387
|
}
|
|
340
388
|
}
|
|
341
389
|
|
|
@@ -496,6 +544,15 @@ function _generateMarkdownExport(dataProvider) {
|
|
|
496
544
|
return md;
|
|
497
545
|
}
|
|
498
546
|
|
|
547
|
+
function _escapeCSVField(str) {
|
|
548
|
+
if (!str) return '""';
|
|
549
|
+
if (str.includes(',') || str.includes('"') || str.includes('\n')) {
|
|
550
|
+
const escaped = str.replace(/"/g, '""');
|
|
551
|
+
return `"${escaped}"`;
|
|
552
|
+
}
|
|
553
|
+
return str;
|
|
554
|
+
}
|
|
555
|
+
|
|
499
556
|
/**
|
|
500
557
|
* 生成 CSV 格式导出数据
|
|
501
558
|
* @param {Object} dataProvider
|
|
@@ -511,7 +568,7 @@ function _generateCSVExport(dataProvider) {
|
|
|
511
568
|
for (const f of features) {
|
|
512
569
|
csv += [
|
|
513
570
|
f.id,
|
|
514
|
-
|
|
571
|
+
_escapeCSVField(f.name),
|
|
515
572
|
f.stage || '',
|
|
516
573
|
f.status || '',
|
|
517
574
|
f.priority || '',
|
|
@@ -87,16 +87,16 @@
|
|
|
87
87
|
============================================================ -->
|
|
88
88
|
|
|
89
89
|
<!-- 核心应用控制器 -->
|
|
90
|
-
<script src="/js/app.js"></script>
|
|
90
|
+
<script src="/js/app.js?v=3.0.2"></script>
|
|
91
91
|
|
|
92
92
|
<!-- 图表绘制工具 -->
|
|
93
|
-
<script src="/js/charts.js"></script>
|
|
93
|
+
<script src="/js/charts.js?v=3.0.2"></script>
|
|
94
94
|
|
|
95
95
|
<!-- 各视图模块 -->
|
|
96
|
-
<script src="/js/pipeline-view.js"></script>
|
|
97
|
-
<script src="/js/kanban-view.js"></script>
|
|
98
|
-
<script src="/js/quality-view.js"></script>
|
|
99
|
-
<script src="/js/system-view.js"></script>
|
|
96
|
+
<script src="/js/pipeline-view.js?v=3.0.2"></script>
|
|
97
|
+
<script src="/js/kanban-view.js?v=3.0.2"></script>
|
|
98
|
+
<script src="/js/quality-view.js?v=3.0.2"></script>
|
|
99
|
+
<script src="/js/system-view.js?v=3.0.2"></script>
|
|
100
100
|
|
|
101
101
|
<!-- 无 JavaScript 时的降级提示 -->
|
|
102
102
|
<noscript>
|
|
@@ -563,7 +563,12 @@ const App = {
|
|
|
563
563
|
const viewInstance = this.state.viewInstances[tab];
|
|
564
564
|
|
|
565
565
|
if (viewInstance?.render) {
|
|
566
|
-
|
|
566
|
+
const sharedData = this.getSharedData();
|
|
567
|
+
if (tab === 'pipeline' || tab === 'kanban') {
|
|
568
|
+
viewInstance.render(sharedData.features, sharedData.summary);
|
|
569
|
+
} else {
|
|
570
|
+
viewInstance.render(sharedData);
|
|
571
|
+
}
|
|
567
572
|
}
|
|
568
573
|
},
|
|
569
574
|
|
|
@@ -637,7 +642,7 @@ const App = {
|
|
|
637
642
|
|
|
638
643
|
try {
|
|
639
644
|
const res = await fetch('/api/refresh', { method: 'POST' });
|
|
640
|
-
const data = await res.json()
|
|
645
|
+
const data = await res.json();
|
|
641
646
|
|
|
642
647
|
if (data.success) {
|
|
643
648
|
// 刷新本地数据
|
package/lib/vm/data-provider.js
CHANGED
|
@@ -900,7 +900,7 @@ class PDDDataProvider {
|
|
|
900
900
|
md += '## Token 使用统计\n\n';
|
|
901
901
|
md += `- **总配额**: ${tokenStats.total.toLocaleString()}\n`;
|
|
902
902
|
md += `- **已使用**: ${tokenStats.used.toLocaleString()} (${tokenStats.percent}%)\n`;
|
|
903
|
-
md += `- **剩余**: ${tokenStats.remaining.toLocaleString()}\n\n
|
|
903
|
+
md += `- **剩余**: ${tokenStats.remaining.toLocaleString()}\n\n`;
|
|
904
904
|
|
|
905
905
|
return md;
|
|
906
906
|
}
|
|
@@ -929,7 +929,8 @@ class PDDDataProvider {
|
|
|
929
929
|
const str = String(value);
|
|
930
930
|
// 如果包含逗号、引号或换行,需要用引号包裹并转义内部引号
|
|
931
931
|
if (str.includes(',') || str.includes('"') || str.includes('\n')) {
|
|
932
|
-
|
|
932
|
+
const escaped = str.replace(/"/g, '""');
|
|
933
|
+
return `"${escaped}"`;
|
|
933
934
|
}
|
|
934
935
|
return str;
|
|
935
936
|
};
|
package/lib/vm/event-bus.js
CHANGED
|
@@ -26,7 +26,7 @@ export const VMEvents = Object.freeze({
|
|
|
26
26
|
QUALITY_UPDATED: 'quality_updated',
|
|
27
27
|
/** Token 使用阈值告警 */
|
|
28
28
|
TOKEN_THRESHOLD: 'token_threshold',
|
|
29
|
-
|
|
29
|
+
/** 缓存命中统计 */
|
|
30
30
|
CACHE_HIT: 'cache_hit',
|
|
31
31
|
/** 迭代轮次完成 */
|
|
32
32
|
ITERATION_ROUND_COMPLETE: 'iteration_round_complete',
|
package/package.json
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
{"name": "pdd-skills",
|
|
2
|
-
"version": "3.0.
|
|
2
|
+
"version": "3.0.3", "description": "PRD Driven Development Skills - AI原生软件开发工作流", "type": "module", "main": "index.js", "bin": {"pdd": "./bin/pdd.js", "pdd-skills": "./bin/pdd.js"}, "files": ["bin/", "lib/", "skills/", "templates/", "scaffolds/", "scripts/", "config/", "hooks/", "index.js"], "scripts": {"start": "node bin/pdd.js", "list": "node bin/pdd.js list", "lint": "node bin/pdd.js linter --type code prd sql activiti", "generate": "node bin/pdd.js generate", "verify": "node bin/pdd.js verify", "report": "node bin/pdd.js report", "config": "node bin/pdd.js config --list", "api": "node bin/pdd.js api", "api:dev": "node bin/pdd.js api -p 3000 --cors", "init": "node bin/pdd.js init", "update": "node bin/pdd.js update", "cso": "node bin/pdd.js cso", "eval": "node bin/pdd.js eval", "token": "node bin/pdd.js token", "i18n": "node bin/pdd.js i18n"}, "keywords": ["pdd", "prd-driven-development", "ai", "claude", "skills", "tdd", "code-generation", "linter", "api-server", "cli"], "author": "PDD Team", "license": "MIT", "engines": {"node": ">=18.0.0"}, "dependencies": {"commander": "^12.0.0", "chalk": "^5.3.0", "fs-extra": "^11.2.0", "yaml": "^2.3.0"}}
|