@epoint-testtech/ep-stage-skill 0.0.15 → 0.0.17
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/codex-skill/ep-stage/code-list-generate/SKILL.md +1 -1
- package/codex-skill/ep-stage/glue-create-project/SKILL.md +1 -1
- package/codex-skill/ep-stage/glue-generate-testcase/SKILL.md +7 -6
- package/codex-skill/ep-stage/glue-run-test/SKILL.md +100 -38
- package/codex-skill/ep-stage/glue-run-test/references/ai-runtime-loop.md +15 -9
- package/codex-skill/ep-stage/glue-run-test/references/crud-pipeline.md +10 -3
- package/codex-skill/ep-stage/glue-run-test/references/gap-review-protocol.md +11 -0
- package/codex-skill/ep-stage/glue-run-test/references/playwright-cli-odav.md +13 -2
- package/codex-skill/ep-stage/page-element-scan/SKILL.md +92 -91
- package/codex-skill/ep-stage/scripts/validate-skill.mjs +4 -1
- package/dist/src/cli/calibrate.d.ts +75 -0
- package/dist/src/cli/calibrate.d.ts.map +1 -0
- package/dist/src/cli/calibrate.js +318 -0
- package/dist/src/cli/demote.d.ts +53 -0
- package/dist/src/cli/demote.d.ts.map +1 -0
- package/dist/src/cli/demote.js +111 -0
- package/dist/src/cli/index.d.ts +5 -3
- package/dist/src/cli/index.d.ts.map +1 -1
- package/dist/src/cli/index.js +45 -6
- package/dist/src/cli/run-report.d.ts +6 -0
- package/dist/src/cli/run-report.d.ts.map +1 -1
- package/dist/src/cli/run-report.js +161 -147
- package/dist/src/cli/run.d.ts +51 -0
- package/dist/src/cli/run.d.ts.map +1 -1
- package/dist/src/cli/run.js +233 -31
- package/dist/src/contracts/glue-contract-v1.d.ts +37 -1
- package/dist/src/contracts/glue-contract-v1.d.ts.map +1 -1
- package/dist/src/extractors/code-list-json5.d.ts +29 -0
- package/dist/src/extractors/code-list-json5.d.ts.map +1 -1
- package/dist/src/generators/stage-skeleton-script.d.ts +30 -1
- package/dist/src/generators/stage-skeleton-script.d.ts.map +1 -1
- package/dist/src/generators/stage-skeleton-script.js +74 -11
- package/dist/src/runtime/ai-runtime-trace.d.ts +6 -0
- package/dist/src/runtime/ai-runtime-trace.d.ts.map +1 -1
- package/dist/src/testcase/contract-testcase-assembler.d.ts +23 -4
- package/dist/src/testcase/contract-testcase-assembler.d.ts.map +1 -1
- package/dist/src/testcase/contract-testcase-assembler.js +204 -27
- package/dist/src/testcase/query-component-map.d.ts +51 -0
- package/dist/src/testcase/query-component-map.d.ts.map +1 -0
- package/dist/src/testcase/query-component-map.js +64 -0
- package/dist/src/validation/contract.d.ts.map +1 -1
- package/dist/src/validation/contract.js +45 -3
- package/package.json +1 -1
|
@@ -121,26 +121,36 @@ function renderTestCard(item, strategy, caseId) {
|
|
|
121
121
|
const errorHtml = item.errorMessage
|
|
122
122
|
? `<div class="error"><strong>错误信息:</strong><pre>${escapeHtml(item.errorMessage)}</pre></div>`
|
|
123
123
|
: '';
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
<
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
124
|
+
// 骨架运行时有复核结论(reviewNote)时覆盖呈现为「待审阅」:
|
|
125
|
+
// Playwright 层 passed 只代表脚本无异常,业务语义(如过滤是否生效)未验证。
|
|
126
|
+
const needsReview = Boolean(item.reviewNote);
|
|
127
|
+
const statusBadge = needsReview
|
|
128
|
+
? '<span class="badge badge--status badge--needs_review">待审阅</span>'
|
|
129
|
+
: `<span class="badge badge--status badge--${escapeHtml(STATUS_BADGE_CLASS[item.status])}">${escapeHtml(STATUS_LABEL[item.status])}</span>`;
|
|
130
|
+
const reviewHtml = needsReview
|
|
131
|
+
? `<div class="review"><strong>审阅原因:</strong>${escapeHtml(item.reviewNote)}</div>`
|
|
132
|
+
: '';
|
|
133
|
+
return `
|
|
134
|
+
<article class="workflow workflow--${escapeHtml(needsReview ? 'needs_review' : STATUS_BADGE_CLASS[item.status])}" data-strategy="${escapeHtml(strategy)}" data-status="${escapeHtml(needsReview ? 'needs_review' : item.status)}">
|
|
135
|
+
<header class="workflow__header">
|
|
136
|
+
<div class="workflow__title">
|
|
137
|
+
<h2>${escapeHtml(item.title)}</h2>
|
|
138
|
+
<code class="workflow__id">${escapeHtml(item.location ?? '')}</code>
|
|
139
|
+
</div>
|
|
140
|
+
<div class="workflow__meta">
|
|
141
|
+
<span class="badge badge--kind">${escapeHtml(item.projectName)}</span>
|
|
142
|
+
<span class="badge badge--source">${escapeHtml(strategy === 'agent_inferred' ? 'Agent推理执行' : '胶水编码执行')}</span>
|
|
143
|
+
${statusBadge}
|
|
144
|
+
</div>
|
|
145
|
+
</header>
|
|
146
|
+
<dl class="workflow__body">
|
|
147
|
+
${caseId ? `<dt>用例ID</dt><dd><code>${escapeHtml(caseId)}</code></dd>` : ''}
|
|
148
|
+
<dt>套件路径</dt><dd>${escapeHtml(item.suitePath)}</dd>
|
|
149
|
+
<dt>耗时</dt><dd>${escapeHtml(formatDuration(item.durationMs))}</dd>
|
|
150
|
+
</dl>
|
|
151
|
+
${errorHtml}
|
|
152
|
+
${reviewHtml}
|
|
153
|
+
</article>
|
|
144
154
|
`;
|
|
145
155
|
}
|
|
146
156
|
/**
|
|
@@ -178,17 +188,20 @@ export function renderRunReportHtml(data) {
|
|
|
178
188
|
['胶水编码执行', data.items.length - agentCount, 'glue', 'glue_code'],
|
|
179
189
|
['Agent推理执行', agentCount, 'agent', 'agent_inferred'],
|
|
180
190
|
];
|
|
191
|
+
const reviewCount = data.items.filter((i) => i.reviewNote).length;
|
|
181
192
|
const resultCards = [
|
|
182
|
-
|
|
193
|
+
// 「通过」只计无复核标记的干净通过;带 reviewNote 的归入「待审阅」,避免双重计数
|
|
194
|
+
['通过', data.items.filter((i) => i.status === 'passed' && !i.reviewNote).length, 'passed', 'passed'],
|
|
183
195
|
['失败', count('failed'), 'failed', 'failed'],
|
|
184
|
-
['
|
|
185
|
-
['
|
|
196
|
+
['待审阅', reviewCount, 'review', 'needs_review'],
|
|
197
|
+
['不稳定', data.items.filter((i) => i.status === 'flaky' && !i.reviewNote).length, 'review', 'flaky'],
|
|
198
|
+
['跳过', data.items.filter((i) => i.status === 'skipped' && !i.reviewNote).length, 'unresolved', 'skipped'],
|
|
186
199
|
];
|
|
187
200
|
const renderCards = (cards, filterGroup) => cards
|
|
188
|
-
.map(([label, value, kind, filterValue]) => `
|
|
189
|
-
<div class="summary-card summary-card--${kind}" data-filter-group="${filterGroup}" data-filter-value="${filterValue}" role="button" tabindex="0">
|
|
190
|
-
<div class="summary-card__value">${value}</div>
|
|
191
|
-
<div class="summary-card__label">${escapeHtml(label)}</div>
|
|
201
|
+
.map(([label, value, kind, filterValue]) => `
|
|
202
|
+
<div class="summary-card summary-card--${kind}" data-filter-group="${filterGroup}" data-filter-value="${filterValue}" role="button" tabindex="0">
|
|
203
|
+
<div class="summary-card__value">${value}</div>
|
|
204
|
+
<div class="summary-card__label">${escapeHtml(label)}</div>
|
|
192
205
|
</div>`)
|
|
193
206
|
.join('');
|
|
194
207
|
const workflowsHtml = sortedItems.length
|
|
@@ -206,126 +219,127 @@ export function renderRunReportHtml(data) {
|
|
|
206
219
|
]
|
|
207
220
|
.filter(Boolean)
|
|
208
221
|
.join(' ');
|
|
209
|
-
const style = `
|
|
210
|
-
body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", sans-serif; background: #f7f8fa; color: #1f2933; margin: 0; padding: 24px; }
|
|
211
|
-
h1 { margin: 0 0 16px; font-size: 22px; }
|
|
212
|
-
h2 { font-size: 16px; margin: 16px 0 8px; }
|
|
213
|
-
section.overview { background: #fff; border-radius: 8px; padding: 20px; box-shadow: 0 1px 3px rgba(0,0,0,0.05); margin-bottom: 24px; }
|
|
214
|
-
.overview-table { width: 100%; border-collapse: collapse; margin-bottom: 16px; }
|
|
215
|
-
.overview-table th, .overview-table td { text-align: left; padding: 6px 12px; border-bottom: 1px solid #eee; font-size: 13px; }
|
|
216
|
-
.overview-table th { width: 140px; color: #52606d; font-weight: 600; }
|
|
217
|
-
.summary-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); gap: 12px; }
|
|
218
|
-
.summary-card { background: #f0f4f8; border-radius: 6px; padding: 12px; text-align: center; cursor: pointer; transition: box-shadow 0.15s, transform 0.1s; }
|
|
219
|
-
.summary-card:hover { box-shadow: 0 2px 6px rgba(0,0,0,0.1); transform: translateY(-1px); }
|
|
220
|
-
.summary-card--active { box-shadow: 0 0 0 2px #2563eb; }
|
|
221
|
-
.summary-card__value { font-size: 22px; font-weight: 600; }
|
|
222
|
-
.summary-card__label { font-size: 12px; color: #52606d; margin-top: 4px; }
|
|
223
|
-
.summary-card--passed { background: #e3fcec; }
|
|
224
|
-
.summary-card--failed { background: #ffe3e3; }
|
|
225
|
-
.summary-card--review { background: #fff4d6; }
|
|
226
|
-
.summary-card--unresolved { background: #f0e8ff; }
|
|
227
|
-
article.workflow { background: #fff; border-radius: 8px; padding: 16px 20px; margin-bottom: 16px; box-shadow: 0 1px 3px rgba(0,0,0,0.05); border-left: 4px solid #cbd2d9; }
|
|
228
|
-
article.workflow--passed { border-left-color: #2f9e44; }
|
|
229
|
-
article.workflow--failed { border-left-color: #e03131; }
|
|
230
|
-
article.workflow--needs_review { border-left-color: #f59f00; }
|
|
231
|
-
article.workflow--unresolved { border-left-color: #7048e8; }
|
|
232
|
-
.workflow__header { display: flex; justify-content: space-between; align-items: flex-start; flex-wrap: wrap; gap: 12px; }
|
|
233
|
-
.workflow__title h2 { margin: 0; font-size: 16px; }
|
|
234
|
-
.workflow__id { font-size: 12px; color: #52606d; }
|
|
235
|
-
.workflow__meta { display: flex; gap: 8px; flex-wrap: wrap; }
|
|
236
|
-
.badge { display: inline-block; padding: 2px 8px; font-size: 12px; border-radius: 12px; background: #e4e7eb; color: #1f2933; }
|
|
237
|
-
.badge--passed { background: #2f9e44; color: #fff; }
|
|
238
|
-
.badge--failed { background: #e03131; color: #fff; }
|
|
239
|
-
.badge--needs_review { background: #f59f00; color: #fff; }
|
|
240
|
-
.badge--unresolved { background: #7048e8; color: #fff; }
|
|
241
|
-
dl.workflow__body { display: grid; grid-template-columns: 100px 1fr; gap: 6px 12px; margin: 12px 0 4px; font-size: 13px; }
|
|
242
|
-
dl.workflow__body dt { color: #52606d; font-weight: 600; }
|
|
243
|
-
code { background: #f0f4f8; padding: 1px 4px; border-radius: 3px; font-size: 12px; }
|
|
244
|
-
.error pre { background: #fff5f5; color: #c92a2a; padding: 8px; border-radius: 4px; overflow-x: auto; font-size: 12px; white-space: pre-wrap; }
|
|
245
|
-
.muted { color: #829ab1; font-size: 13px; }
|
|
246
|
-
footer.footer { background: #fff; border-radius: 8px; padding: 16px 20px; margin-top: 16px; box-shadow: 0 1px 3px rgba(0,0,0,0.05); }
|
|
247
|
-
.pw-link { display: inline-block; padding: 8px 16px; background: #2563eb; color: #fff; border-radius: 4px; text-decoration: none; font-size: 14px; margin-right: 8px; }
|
|
248
|
-
.pw-link:hover { background: #1d4ed8; }
|
|
249
|
-
.pw-link--secondary { background: #334e68; }
|
|
250
|
-
.workflow-toolbar { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap; margin: 16px 0 8px; }
|
|
251
|
-
.workflow-toolbar h2 { margin: 0; }
|
|
252
|
-
.workflow-filters { display: flex; gap: 8px; }
|
|
253
|
-
.workflow-filters select { padding: 4px 8px; font-size: 13px; border: 1px solid #cbd2d9; border-radius: 4px; background: #fff; color: #1f2933; }
|
|
254
|
-
.summary-section-title { font-size: 13px; color: #52606d; margin: 12px 0 4px; font-weight: 600; }
|
|
222
|
+
const style = `
|
|
223
|
+
body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", sans-serif; background: #f7f8fa; color: #1f2933; margin: 0; padding: 24px; }
|
|
224
|
+
h1 { margin: 0 0 16px; font-size: 22px; }
|
|
225
|
+
h2 { font-size: 16px; margin: 16px 0 8px; }
|
|
226
|
+
section.overview { background: #fff; border-radius: 8px; padding: 20px; box-shadow: 0 1px 3px rgba(0,0,0,0.05); margin-bottom: 24px; }
|
|
227
|
+
.overview-table { width: 100%; border-collapse: collapse; margin-bottom: 16px; }
|
|
228
|
+
.overview-table th, .overview-table td { text-align: left; padding: 6px 12px; border-bottom: 1px solid #eee; font-size: 13px; }
|
|
229
|
+
.overview-table th { width: 140px; color: #52606d; font-weight: 600; }
|
|
230
|
+
.summary-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); gap: 12px; }
|
|
231
|
+
.summary-card { background: #f0f4f8; border-radius: 6px; padding: 12px; text-align: center; cursor: pointer; transition: box-shadow 0.15s, transform 0.1s; }
|
|
232
|
+
.summary-card:hover { box-shadow: 0 2px 6px rgba(0,0,0,0.1); transform: translateY(-1px); }
|
|
233
|
+
.summary-card--active { box-shadow: 0 0 0 2px #2563eb; }
|
|
234
|
+
.summary-card__value { font-size: 22px; font-weight: 600; }
|
|
235
|
+
.summary-card__label { font-size: 12px; color: #52606d; margin-top: 4px; }
|
|
236
|
+
.summary-card--passed { background: #e3fcec; }
|
|
237
|
+
.summary-card--failed { background: #ffe3e3; }
|
|
238
|
+
.summary-card--review { background: #fff4d6; }
|
|
239
|
+
.summary-card--unresolved { background: #f0e8ff; }
|
|
240
|
+
article.workflow { background: #fff; border-radius: 8px; padding: 16px 20px; margin-bottom: 16px; box-shadow: 0 1px 3px rgba(0,0,0,0.05); border-left: 4px solid #cbd2d9; }
|
|
241
|
+
article.workflow--passed { border-left-color: #2f9e44; }
|
|
242
|
+
article.workflow--failed { border-left-color: #e03131; }
|
|
243
|
+
article.workflow--needs_review { border-left-color: #f59f00; }
|
|
244
|
+
article.workflow--unresolved { border-left-color: #7048e8; }
|
|
245
|
+
.workflow__header { display: flex; justify-content: space-between; align-items: flex-start; flex-wrap: wrap; gap: 12px; }
|
|
246
|
+
.workflow__title h2 { margin: 0; font-size: 16px; }
|
|
247
|
+
.workflow__id { font-size: 12px; color: #52606d; }
|
|
248
|
+
.workflow__meta { display: flex; gap: 8px; flex-wrap: wrap; }
|
|
249
|
+
.badge { display: inline-block; padding: 2px 8px; font-size: 12px; border-radius: 12px; background: #e4e7eb; color: #1f2933; }
|
|
250
|
+
.badge--passed { background: #2f9e44; color: #fff; }
|
|
251
|
+
.badge--failed { background: #e03131; color: #fff; }
|
|
252
|
+
.badge--needs_review { background: #f59f00; color: #fff; }
|
|
253
|
+
.badge--unresolved { background: #7048e8; color: #fff; }
|
|
254
|
+
dl.workflow__body { display: grid; grid-template-columns: 100px 1fr; gap: 6px 12px; margin: 12px 0 4px; font-size: 13px; }
|
|
255
|
+
dl.workflow__body dt { color: #52606d; font-weight: 600; }
|
|
256
|
+
code { background: #f0f4f8; padding: 1px 4px; border-radius: 3px; font-size: 12px; }
|
|
257
|
+
.error pre { background: #fff5f5; color: #c92a2a; padding: 8px; border-radius: 4px; overflow-x: auto; font-size: 12px; white-space: pre-wrap; }
|
|
258
|
+
.muted { color: #829ab1; font-size: 13px; }
|
|
259
|
+
footer.footer { background: #fff; border-radius: 8px; padding: 16px 20px; margin-top: 16px; box-shadow: 0 1px 3px rgba(0,0,0,0.05); }
|
|
260
|
+
.pw-link { display: inline-block; padding: 8px 16px; background: #2563eb; color: #fff; border-radius: 4px; text-decoration: none; font-size: 14px; margin-right: 8px; }
|
|
261
|
+
.pw-link:hover { background: #1d4ed8; }
|
|
262
|
+
.pw-link--secondary { background: #334e68; }
|
|
263
|
+
.workflow-toolbar { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap; margin: 16px 0 8px; }
|
|
264
|
+
.workflow-toolbar h2 { margin: 0; }
|
|
265
|
+
.workflow-filters { display: flex; gap: 8px; }
|
|
266
|
+
.workflow-filters select { padding: 4px 8px; font-size: 13px; border: 1px solid #cbd2d9; border-radius: 4px; background: #fff; color: #1f2933; }
|
|
267
|
+
.summary-section-title { font-size: 13px; color: #52606d; margin: 12px 0 4px; font-weight: 600; }
|
|
255
268
|
`;
|
|
256
|
-
return `<!DOCTYPE html>
|
|
257
|
-
<html lang="zh-CN">
|
|
258
|
-
<head>
|
|
259
|
-
<meta charset="UTF-8" />
|
|
260
|
-
<meta name="viewport" content="width=device-width,initial-scale=1.0" />
|
|
261
|
-
<title>胶水编码-测试执行</title>
|
|
262
|
-
<style>${style}</style>
|
|
263
|
-
</head>
|
|
264
|
-
<body>
|
|
265
|
-
<section class="overview">
|
|
266
|
-
<h1>胶水编码-测试执行(综合报告)</h1>
|
|
267
|
-
<table class="overview-table">${overviewHtml}</table>
|
|
268
|
-
<h3 class="summary-section-title">执行策略</h3>
|
|
269
|
-
<div class="summary-grid summary-grid--strategy">${renderCards(strategyCards, 'strategy')}</div>
|
|
270
|
-
<h3 class="summary-section-title">执行结果</h3>
|
|
271
|
-
<div class="summary-grid summary-grid--result">${renderCards(resultCards, 'status')}</div>
|
|
272
|
-
</section>
|
|
273
|
-
<section class="workflows">
|
|
274
|
-
<div class="workflow-toolbar">
|
|
275
|
-
<h2>用例执行明细</h2>
|
|
276
|
-
<div class="workflow-filters">
|
|
277
|
-
<select id="filter-strategy">
|
|
278
|
-
<option value="">全部执行策略</option>
|
|
279
|
-
<option value="glue_code">胶水编码执行</option>
|
|
280
|
-
<option value="agent_inferred">Agent推理执行</option>
|
|
281
|
-
</select>
|
|
282
|
-
<select id="filter-status">
|
|
283
|
-
<option value="">全部执行结果</option>
|
|
284
|
-
<option value="passed">通过</option>
|
|
285
|
-
<option value="failed">失败</option>
|
|
286
|
-
<option value="
|
|
287
|
-
<option value="
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
var
|
|
300
|
-
var
|
|
301
|
-
var
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
var
|
|
307
|
-
c.
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
var
|
|
312
|
-
card.
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
select
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
</
|
|
329
|
-
</
|
|
269
|
+
return `<!DOCTYPE html>
|
|
270
|
+
<html lang="zh-CN">
|
|
271
|
+
<head>
|
|
272
|
+
<meta charset="UTF-8" />
|
|
273
|
+
<meta name="viewport" content="width=device-width,initial-scale=1.0" />
|
|
274
|
+
<title>胶水编码-测试执行</title>
|
|
275
|
+
<style>${style}</style>
|
|
276
|
+
</head>
|
|
277
|
+
<body>
|
|
278
|
+
<section class="overview">
|
|
279
|
+
<h1>胶水编码-测试执行(综合报告)</h1>
|
|
280
|
+
<table class="overview-table">${overviewHtml}</table>
|
|
281
|
+
<h3 class="summary-section-title">执行策略</h3>
|
|
282
|
+
<div class="summary-grid summary-grid--strategy">${renderCards(strategyCards, 'strategy')}</div>
|
|
283
|
+
<h3 class="summary-section-title">执行结果</h3>
|
|
284
|
+
<div class="summary-grid summary-grid--result">${renderCards(resultCards, 'status')}</div>
|
|
285
|
+
</section>
|
|
286
|
+
<section class="workflows">
|
|
287
|
+
<div class="workflow-toolbar">
|
|
288
|
+
<h2>用例执行明细</h2>
|
|
289
|
+
<div class="workflow-filters">
|
|
290
|
+
<select id="filter-strategy">
|
|
291
|
+
<option value="">全部执行策略</option>
|
|
292
|
+
<option value="glue_code">胶水编码执行</option>
|
|
293
|
+
<option value="agent_inferred">Agent推理执行</option>
|
|
294
|
+
</select>
|
|
295
|
+
<select id="filter-status">
|
|
296
|
+
<option value="">全部执行结果</option>
|
|
297
|
+
<option value="passed">通过</option>
|
|
298
|
+
<option value="failed">失败</option>
|
|
299
|
+
<option value="needs_review">待审阅</option>
|
|
300
|
+
<option value="flaky">不稳定</option>
|
|
301
|
+
<option value="skipped">跳过</option>
|
|
302
|
+
</select>
|
|
303
|
+
</div>
|
|
304
|
+
</div>
|
|
305
|
+
${workflowsHtml}
|
|
306
|
+
</section>
|
|
307
|
+
<footer class="footer">
|
|
308
|
+
${footerLinks || '<p class="muted">本次未发现关联报告产物</p>'}
|
|
309
|
+
</footer>
|
|
310
|
+
<script>
|
|
311
|
+
(function() {
|
|
312
|
+
var fs = document.getElementById('filter-strategy');
|
|
313
|
+
var fst = document.getElementById('filter-status');
|
|
314
|
+
var cards = document.querySelectorAll('article.workflow');
|
|
315
|
+
var summaryCards = document.querySelectorAll('.summary-card');
|
|
316
|
+
function apply() {
|
|
317
|
+
var s = fs.value, st = fst.value;
|
|
318
|
+
for (var i = 0; i < cards.length; i++) {
|
|
319
|
+
var c = cards[i];
|
|
320
|
+
var show = (!s || c.dataset.strategy === s) && (!st || c.dataset.status === st);
|
|
321
|
+
c.style.display = show ? '' : 'none';
|
|
322
|
+
}
|
|
323
|
+
for (var j = 0; j < summaryCards.length; j++) {
|
|
324
|
+
var card = summaryCards[j];
|
|
325
|
+
var select = card.dataset.filterGroup === 'strategy' ? fs : fst;
|
|
326
|
+
card.classList.toggle('summary-card--active', select.value !== '' && select.value === card.dataset.filterValue);
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
fs.addEventListener('change', apply);
|
|
330
|
+
fst.addEventListener('change', apply);
|
|
331
|
+
for (var j = 0; j < summaryCards.length; j++) {
|
|
332
|
+
(function(card) {
|
|
333
|
+
card.addEventListener('click', function() {
|
|
334
|
+
var select = card.dataset.filterGroup === 'strategy' ? fs : fst;
|
|
335
|
+
select.value = select.value === card.dataset.filterValue ? '' : card.dataset.filterValue;
|
|
336
|
+
apply();
|
|
337
|
+
});
|
|
338
|
+
})(summaryCards[j]);
|
|
339
|
+
}
|
|
340
|
+
})();
|
|
341
|
+
</script>
|
|
342
|
+
</body>
|
|
343
|
+
</html>
|
|
330
344
|
`;
|
|
331
345
|
}
|
package/dist/src/cli/run.d.ts
CHANGED
|
@@ -11,6 +11,8 @@ export type RunArgs = {
|
|
|
11
11
|
testcase: string;
|
|
12
12
|
headless: boolean;
|
|
13
13
|
aiSnippets?: string;
|
|
14
|
+
/** true 时恢复旧语义:任一 AI 任务缺 resolved snippet 则整体短路不执行(默认 false = 部分执行) */
|
|
15
|
+
strictAi?: boolean;
|
|
14
16
|
};
|
|
15
17
|
/**
|
|
16
18
|
* run 子命令产物(新协议 v1-draft)。
|
|
@@ -31,6 +33,8 @@ export type RunResult = {
|
|
|
31
33
|
aiRuntimeTracePath?: string;
|
|
32
34
|
repairReportPath?: string;
|
|
33
35
|
comprehensiveReportPath?: string;
|
|
36
|
+
/** 部分执行语义下未执行(needs_review)的 AI 任务数;0/undefined = 全部任务已就绪 */
|
|
37
|
+
needsReviewCount?: number;
|
|
34
38
|
};
|
|
35
39
|
/**
|
|
36
40
|
* runRun 的可注入依赖(测试即契约:允许单测替换推理与执行,避免触发真机)。
|
|
@@ -132,6 +136,21 @@ export declare function loadAiSnippets(input: {
|
|
|
132
136
|
testcasePath: string;
|
|
133
137
|
tasks: AiRuntimeTask[];
|
|
134
138
|
}): AiRuntimeResult[];
|
|
139
|
+
/**
|
|
140
|
+
* 读取 Agent 在 ai-snippets.json5 中自评的 needs_review 结论。
|
|
141
|
+
*
|
|
142
|
+
* 与 loadAiSnippets 互补:resolved 走 spec 合并,needs_review 走 trace/报告透传——
|
|
143
|
+
* Agent 的差异化复审证据(reviewReason / observation / evidence)必须保留,
|
|
144
|
+
* 不得被 CLI 占位文本覆盖。
|
|
145
|
+
*
|
|
146
|
+
* @param input - snippets 路径、testcase 路径和当前 AI tasks。
|
|
147
|
+
* @returns Agent 自评 needs_review 的 AiRuntimeResult 列表。
|
|
148
|
+
*/
|
|
149
|
+
export declare function loadAiSnippetReviewResults(input: {
|
|
150
|
+
snippetsPath: string;
|
|
151
|
+
testcasePath: string;
|
|
152
|
+
tasks: AiRuntimeTask[];
|
|
153
|
+
}): AiRuntimeResult[];
|
|
135
154
|
/**
|
|
136
155
|
* 从 testcase 构建 AI Runtime Task 列表。
|
|
137
156
|
*
|
|
@@ -151,6 +170,38 @@ export declare function buildAiRuntimeTasks(testcase: EpStageTestcaseV1Draft, pa
|
|
|
151
170
|
* @returns trace 路径、spec 路径和任务摘要。
|
|
152
171
|
*/
|
|
153
172
|
export declare function prepareAiRuntimeTasks(testcasePath: string): PrepareAiRuntimeTasksResult;
|
|
173
|
+
/**
|
|
174
|
+
* run 执行前置凭据门禁。
|
|
175
|
+
*
|
|
176
|
+
* 背景:glue 骨架运行时(stage-core loadCredentials / spec 内 `credential.url`)只读
|
|
177
|
+
* `url / username / password`;credentials.json5 只写 loginUrl 时 CLI 侧宽松校验能过,
|
|
178
|
+
* 却要等到骨架 `page.goto(undefined)` 才爆。这里在执行 Playwright 前显式拦截:
|
|
179
|
+
* 文件存在则每条必须 url / username / password 非空(validateCredentials 先保证结构
|
|
180
|
+
* 与 username/password,本门禁再强制 url 字段本身存在)。
|
|
181
|
+
* 文件缺失仍走 credentialsNotice 软提示(保持既有行为,由 skill Step 3 引导补齐)。
|
|
182
|
+
*
|
|
183
|
+
* @param testcase - 已校验 testcase。
|
|
184
|
+
* @param testcasePath - testcase.json5 绝对路径。
|
|
185
|
+
*/
|
|
186
|
+
export declare function assertRunCredentialsReady(testcase: EpStageTestcaseV1Draft, testcasePath: string): void;
|
|
187
|
+
/**
|
|
188
|
+
* 从项目 glue-report 下最新的 stage-glue 执行记录 JSON 提取复核结论映射。
|
|
189
|
+
*
|
|
190
|
+
* 与 run 的关系:recorder 由 spec 内 afterAll 在 Playwright 进程内写出
|
|
191
|
+
* (glue-report/<执行时间戳>/stage-glue-<时间戳>.json),本函数在 Playwright 结束后调用。
|
|
192
|
+
*
|
|
193
|
+
* 串轮防线:只消费「本轮执行」产生的记录。最新目录的 JSON startedAt 早于
|
|
194
|
+
* executionStartedAt(含 30s 时钟容差)时说明本轮 recorder 未落盘(如执行在
|
|
195
|
+
* afterAll 前崩溃),直接返回空 Map——严禁回退到上一轮目录,否则历史复核结论
|
|
196
|
+
* (如「搜索前后数据量相同」)会贴到本轮已通过用例的卡片上。
|
|
197
|
+
*
|
|
198
|
+
* 任一环节缺失(目录/文件/结构不符)返回空 Map——综合报告退化为仅 Playwright 视角,不阻断。
|
|
199
|
+
*
|
|
200
|
+
* @param projectDir - glue 项目根目录。
|
|
201
|
+
* @param executionStartedAt - 本轮 Playwright 启动时刻(早于 executor 调用采集)。
|
|
202
|
+
* @returns playwrightTestTitle → 复核原因(仅 needs_review 工作流)。
|
|
203
|
+
*/
|
|
204
|
+
export declare function loadRecorderReviewNotes(projectDir: string, executionStartedAt: Date): Map<string, string>;
|
|
154
205
|
/**
|
|
155
206
|
* run 子命令主体(REQ-CHAIN-02 / REQ-SPEC-01,新协议 v1-draft)。
|
|
156
207
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../../src/cli/run.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../../src/cli/run.ts"],"names":[],"mappings":"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"}
|