@kb-labs/qa-entry 2.14.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 +1 -0
- package/dist/cli/commands/baseline-status.d.ts +10 -0
- package/dist/cli/commands/baseline-status.js +32 -0
- package/dist/cli/commands/baseline-status.js.map +1 -0
- package/dist/cli/commands/baseline-update.d.ts +10 -0
- package/dist/cli/commands/baseline-update.js +33 -0
- package/dist/cli/commands/baseline-update.js.map +1 -0
- package/dist/cli/commands/flags.d.ts +106 -0
- package/dist/cli/commands/flags.js +99 -0
- package/dist/cli/commands/flags.js.map +1 -0
- package/dist/cli/commands/qa-history.d.ts +10 -0
- package/dist/cli/commands/qa-history.js +41 -0
- package/dist/cli/commands/qa-history.js.map +1 -0
- package/dist/cli/commands/qa-regressions.d.ts +10 -0
- package/dist/cli/commands/qa-regressions.js +33 -0
- package/dist/cli/commands/qa-regressions.js.map +1 -0
- package/dist/cli/commands/qa-run.d.ts +16 -0
- package/dist/cli/commands/qa-run.js +159 -0
- package/dist/cli/commands/qa-run.js.map +1 -0
- package/dist/cli/commands/qa-save.d.ts +10 -0
- package/dist/cli/commands/qa-save.js +69 -0
- package/dist/cli/commands/qa-save.js.map +1 -0
- package/dist/cli/commands/qa-trends.d.ts +10 -0
- package/dist/cli/commands/qa-trends.js +35 -0
- package/dist/cli/commands/qa-trends.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +390 -0
- package/dist/index.js.map +1 -0
- package/dist/manifest.d.ts +198 -0
- package/dist/manifest.js +391 -0
- package/dist/manifest.js.map +1 -0
- package/dist/rest/handlers/baseline-diff-handler.d.ts +33 -0
- package/dist/rest/handlers/baseline-diff-handler.js +51 -0
- package/dist/rest/handlers/baseline-diff-handler.js.map +1 -0
- package/dist/rest/handlers/baseline-handler.d.ts +19 -0
- package/dist/rest/handlers/baseline-handler.js +14 -0
- package/dist/rest/handlers/baseline-handler.js.map +1 -0
- package/dist/rest/handlers/baseline-update-handler.d.ts +20 -0
- package/dist/rest/handlers/baseline-update-handler.js +23 -0
- package/dist/rest/handlers/baseline-update-handler.js.map +1 -0
- package/dist/rest/handlers/details-handler.d.ts +61 -0
- package/dist/rest/handlers/details-handler.js +70 -0
- package/dist/rest/handlers/details-handler.js.map +1 -0
- package/dist/rest/handlers/error-groups-handler.d.ts +15 -0
- package/dist/rest/handlers/error-groups-handler.js +17 -0
- package/dist/rest/handlers/error-groups-handler.js.map +1 -0
- package/dist/rest/handlers/history-handler.d.ts +25 -0
- package/dist/rest/handlers/history-handler.js +22 -0
- package/dist/rest/handlers/history-handler.js.map +1 -0
- package/dist/rest/handlers/latest-handler.d.ts +22 -0
- package/dist/rest/handlers/latest-handler.js +17 -0
- package/dist/rest/handlers/latest-handler.js.map +1 -0
- package/dist/rest/handlers/package-timeline-handler.d.ts +26 -0
- package/dist/rest/handlers/package-timeline-handler.js +18 -0
- package/dist/rest/handlers/package-timeline-handler.js.map +1 -0
- package/dist/rest/handlers/regressions-handler.d.ts +16 -0
- package/dist/rest/handlers/regressions-handler.js +14 -0
- package/dist/rest/handlers/regressions-handler.js.map +1 -0
- package/dist/rest/handlers/run-check-handler.d.ts +20 -0
- package/dist/rest/handlers/run-check-handler.js +58 -0
- package/dist/rest/handlers/run-check-handler.js.map +1 -0
- package/dist/rest/handlers/run-handler.d.ts +33 -0
- package/dist/rest/handlers/run-handler.js +75 -0
- package/dist/rest/handlers/run-handler.js.map +1 -0
- package/dist/rest/handlers/summary-handler.d.ts +26 -0
- package/dist/rest/handlers/summary-handler.js +35 -0
- package/dist/rest/handlers/summary-handler.js.map +1 -0
- package/dist/rest/handlers/trends-handler.d.ts +48 -0
- package/dist/rest/handlers/trends-handler.js +30 -0
- package/dist/rest/handlers/trends-handler.js.map +1 -0
- package/package.json +71 -0
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { defineCommand } from '@kb-labs/sdk';
|
|
2
|
+
import { runQA, createHistoryEntry, appendEntry } from '@kb-labs/qa-core';
|
|
3
|
+
|
|
4
|
+
// src/cli/commands/qa-save.ts
|
|
5
|
+
var qa_save_default = defineCommand({
|
|
6
|
+
id: "qa:save",
|
|
7
|
+
description: "Run QA checks and save results to history",
|
|
8
|
+
handler: {
|
|
9
|
+
async execute(ctx, input) {
|
|
10
|
+
const { ui } = ctx;
|
|
11
|
+
const flags = input.flags ?? input;
|
|
12
|
+
const rootDir = ctx.cwd;
|
|
13
|
+
const startTime = Date.now();
|
|
14
|
+
const { results } = await runQA({ rootDir });
|
|
15
|
+
const durationMs = Date.now() - startTime;
|
|
16
|
+
const entry = createHistoryEntry(results, rootDir);
|
|
17
|
+
appendEntry(rootDir, entry);
|
|
18
|
+
const analytics = ctx.platform.analytics;
|
|
19
|
+
if (analytics) {
|
|
20
|
+
for (const ct of Object.keys(results)) {
|
|
21
|
+
const r = results[ct];
|
|
22
|
+
await analytics.track("qa.check.completed", {
|
|
23
|
+
checkType: ct,
|
|
24
|
+
status: r.failed.length > 0 ? "failed" : "passed",
|
|
25
|
+
passed: r.passed.length,
|
|
26
|
+
failed: r.failed.length,
|
|
27
|
+
skipped: r.skipped.length,
|
|
28
|
+
gitCommit: entry.git.commit,
|
|
29
|
+
gitBranch: entry.git.branch
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
const checkKeys = Object.keys(results);
|
|
33
|
+
await analytics.track("qa.run.completed", {
|
|
34
|
+
status: entry.status,
|
|
35
|
+
...Object.fromEntries(checkKeys.flatMap((ct) => [
|
|
36
|
+
[`${ct}Passed`, results[ct].passed.length],
|
|
37
|
+
[`${ct}Failed`, results[ct].failed.length]
|
|
38
|
+
])),
|
|
39
|
+
totalPassed: checkKeys.reduce((s, ct) => s + results[ct].passed.length, 0),
|
|
40
|
+
totalFailed: checkKeys.reduce((s, ct) => s + results[ct].failed.length, 0),
|
|
41
|
+
totalSkipped: checkKeys.reduce((s, ct) => s + results[ct].skipped.length, 0),
|
|
42
|
+
gitCommit: entry.git.commit,
|
|
43
|
+
gitBranch: entry.git.branch,
|
|
44
|
+
durationMs
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
if (flags.json) {
|
|
48
|
+
ui?.json?.(entry);
|
|
49
|
+
return { exitCode: 0 };
|
|
50
|
+
}
|
|
51
|
+
ui?.success?.("QA state saved to history", {
|
|
52
|
+
title: "QA Save",
|
|
53
|
+
sections: [{
|
|
54
|
+
header: "Saved Entry",
|
|
55
|
+
items: [
|
|
56
|
+
`Status: ${entry.status}`,
|
|
57
|
+
`Git: ${entry.git.commit} (${entry.git.branch})`,
|
|
58
|
+
`Message: ${entry.git.message}`
|
|
59
|
+
]
|
|
60
|
+
}]
|
|
61
|
+
});
|
|
62
|
+
return { exitCode: 0 };
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
export { qa_save_default as default };
|
|
68
|
+
//# sourceMappingURL=qa-save.js.map
|
|
69
|
+
//# sourceMappingURL=qa-save.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/cli/commands/qa-save.ts"],"names":[],"mappings":";;;;AAMA,IAAO,kBAAQ,aAAA,CAAc;AAAA,EAC3B,EAAA,EAAI,SAAA;AAAA,EACJ,WAAA,EAAa,2CAAA;AAAA,EAEb,OAAA,EAAS;AAAA,IACP,MAAM,OAAA,CAAQ,GAAA,EAAsB,KAAA,EAAoB;AACtD,MAAA,MAAM,EAAE,IAAG,GAAI,GAAA;AACf,MAAA,MAAM,KAAA,GAAS,MAAc,KAAA,IAAS,KAAA;AACtC,MAAA,MAAM,UAAU,GAAA,CAAI,GAAA;AAEpB,MAAA,MAAM,SAAA,GAAY,KAAK,GAAA,EAAI;AAC3B,MAAA,MAAM,EAAE,OAAA,EAAQ,GAAI,MAAM,KAAA,CAAM,EAAE,SAAS,CAAA;AAC3C,MAAA,MAAM,UAAA,GAAa,IAAA,CAAK,GAAA,EAAI,GAAI,SAAA;AAChC,MAAA,MAAM,KAAA,GAAQ,kBAAA,CAAmB,OAAA,EAAS,OAAO,CAAA;AACjD,MAAA,WAAA,CAAY,SAAS,KAAK,CAAA;AAG1B,MAAA,MAAM,SAAA,GAAY,IAAI,QAAA,CAAS,SAAA;AAC/B,MAAA,IAAI,SAAA,EAAW;AACb,QAAA,KAAA,MAAW,EAAA,IAAM,MAAA,CAAO,IAAA,CAAK,OAAO,CAAA,EAAG;AACrC,UAAA,MAAM,CAAA,GAAI,QAAQ,EAAE,CAAA;AACpB,UAAA,MAAM,SAAA,CAAU,MAAM,oBAAA,EAAsB;AAAA,YAC1C,SAAA,EAAW,EAAA;AAAA,YACX,MAAA,EAAQ,CAAA,CAAE,MAAA,CAAO,MAAA,GAAS,IAAI,QAAA,GAAW,QAAA;AAAA,YACzC,MAAA,EAAQ,EAAE,MAAA,CAAO,MAAA;AAAA,YACjB,MAAA,EAAQ,EAAE,MAAA,CAAO,MAAA;AAAA,YACjB,OAAA,EAAS,EAAE,OAAA,CAAQ,MAAA;AAAA,YACnB,SAAA,EAAW,MAAM,GAAA,CAAI,MAAA;AAAA,YACrB,SAAA,EAAW,MAAM,GAAA,CAAI;AAAA,WACtB,CAAA;AAAA,QACH;AACA,QAAA,MAAM,SAAA,GAAY,MAAA,CAAO,IAAA,CAAK,OAAO,CAAA;AACrC,QAAA,MAAM,SAAA,CAAU,MAAM,kBAAA,EAAoB;AAAA,UACxC,QAAQ,KAAA,CAAM,MAAA;AAAA,UACd,GAAG,MAAA,CAAO,WAAA,CAAY,SAAA,CAAU,OAAA,CAAQ,CAAC,EAAA,KAAO;AAAA,YAC9C,CAAC,GAAG,EAAE,CAAA,MAAA,CAAA,EAAU,QAAQ,EAAE,CAAA,CAAG,OAAO,MAAM,CAAA;AAAA,YAC1C,CAAC,GAAG,EAAE,CAAA,MAAA,CAAA,EAAU,QAAQ,EAAE,CAAA,CAAG,OAAO,MAAM;AAAA,WAC3C,CAAC,CAAA;AAAA,UACF,WAAA,EAAa,SAAA,CAAU,MAAA,CAAO,CAAC,CAAA,EAAG,EAAA,KAAO,CAAA,GAAI,OAAA,CAAQ,EAAE,CAAA,CAAG,MAAA,CAAO,MAAA,EAAQ,CAAC,CAAA;AAAA,UAC1E,WAAA,EAAa,SAAA,CAAU,MAAA,CAAO,CAAC,CAAA,EAAG,EAAA,KAAO,CAAA,GAAI,OAAA,CAAQ,EAAE,CAAA,CAAG,MAAA,CAAO,MAAA,EAAQ,CAAC,CAAA;AAAA,UAC1E,YAAA,EAAc,SAAA,CAAU,MAAA,CAAO,CAAC,CAAA,EAAG,EAAA,KAAO,CAAA,GAAI,OAAA,CAAQ,EAAE,CAAA,CAAG,OAAA,CAAQ,MAAA,EAAQ,CAAC,CAAA;AAAA,UAC5E,SAAA,EAAW,MAAM,GAAA,CAAI,MAAA;AAAA,UAAQ,SAAA,EAAW,MAAM,GAAA,CAAI,MAAA;AAAA,UAClD;AAAA,SACD,CAAA;AAAA,MACH;AAEA,MAAA,IAAI,MAAM,IAAA,EAAM;AACd,QAAA,EAAA,EAAI,OAAO,KAAK,CAAA;AAChB,QAAA,OAAO,EAAE,UAAU,CAAA,EAAE;AAAA,MACvB;AAEA,MAAA,EAAA,EAAI,UAAU,2BAAA,EAA6B;AAAA,QACzC,KAAA,EAAO,SAAA;AAAA,QACP,UAAU,CAAC;AAAA,UACT,MAAA,EAAQ,aAAA;AAAA,UACR,KAAA,EAAO;AAAA,YACL,CAAA,QAAA,EAAW,MAAM,MAAM,CAAA,CAAA;AAAA,YACvB,QAAQ,KAAA,CAAM,GAAA,CAAI,MAAM,CAAA,EAAA,EAAK,KAAA,CAAM,IAAI,MAAM,CAAA,CAAA,CAAA;AAAA,YAC7C,CAAA,SAAA,EAAY,KAAA,CAAM,GAAA,CAAI,OAAO,CAAA;AAAA;AAC/B,SACD;AAAA,OACF,CAAA;AAED,MAAA,OAAO,EAAE,UAAU,CAAA,EAAE;AAAA,IACvB;AAAA;AAEJ,CAAC","file":"qa-save.js","sourcesContent":["import { defineCommand, type PluginContextV3 } from '@kb-labs/sdk';\nimport { runQA, createHistoryEntry, appendEntry } from '@kb-labs/qa-core';\nimport type { QASaveFlags } from './flags.js';\n\ntype QASaveInput = QASaveFlags & { argv?: string[]; flags?: any };\n\nexport default defineCommand({\n id: 'qa:save',\n description: 'Run QA checks and save results to history',\n\n handler: {\n async execute(ctx: PluginContextV3, input: QASaveInput) {\n const { ui } = ctx;\n const flags = (input as any).flags ?? input;\n const rootDir = ctx.cwd;\n\n const startTime = Date.now();\n const { results } = await runQA({ rootDir });\n const durationMs = Date.now() - startTime;\n const entry = createHistoryEntry(results, rootDir);\n appendEntry(rootDir, entry);\n\n // Track analytics events\n const analytics = ctx.platform.analytics;\n if (analytics) {\n for (const ct of Object.keys(results)) {\n const r = results[ct]!;\n await analytics.track('qa.check.completed', {\n checkType: ct,\n status: r.failed.length > 0 ? 'failed' : 'passed',\n passed: r.passed.length,\n failed: r.failed.length,\n skipped: r.skipped.length,\n gitCommit: entry.git.commit,\n gitBranch: entry.git.branch,\n });\n }\n const checkKeys = Object.keys(results);\n await analytics.track('qa.run.completed', {\n status: entry.status,\n ...Object.fromEntries(checkKeys.flatMap((ct) => [\n [`${ct}Passed`, results[ct]!.passed.length],\n [`${ct}Failed`, results[ct]!.failed.length],\n ])),\n totalPassed: checkKeys.reduce((s, ct) => s + results[ct]!.passed.length, 0),\n totalFailed: checkKeys.reduce((s, ct) => s + results[ct]!.failed.length, 0),\n totalSkipped: checkKeys.reduce((s, ct) => s + results[ct]!.skipped.length, 0),\n gitCommit: entry.git.commit, gitBranch: entry.git.branch,\n durationMs,\n });\n }\n\n if (flags.json) {\n ui?.json?.(entry);\n return { exitCode: 0 };\n }\n\n ui?.success?.('QA state saved to history', {\n title: 'QA Save',\n sections: [{\n header: 'Saved Entry',\n items: [\n `Status: ${entry.status}`,\n `Git: ${entry.git.commit} (${entry.git.branch})`,\n `Message: ${entry.git.message}`,\n ],\n }],\n });\n\n return { exitCode: 0 };\n },\n },\n});\n"]}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import * as _kb_labs_shared_command_kit from '@kb-labs/shared-command-kit';
|
|
2
|
+
import { QATrendsFlags } from './flags.js';
|
|
3
|
+
|
|
4
|
+
type QATrendsInput = QATrendsFlags & {
|
|
5
|
+
argv?: string[];
|
|
6
|
+
flags?: any;
|
|
7
|
+
};
|
|
8
|
+
declare const _default: _kb_labs_shared_command_kit.CommandHandlerV3<unknown, QATrendsInput, unknown>;
|
|
9
|
+
|
|
10
|
+
export { _default as default };
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { defineCommand } from '@kb-labs/sdk';
|
|
2
|
+
import { loadHistory, analyzeTrends, analyzeEnrichedTrends, buildTrendsReport } from '@kb-labs/qa-core';
|
|
3
|
+
|
|
4
|
+
// src/cli/commands/qa-trends.ts
|
|
5
|
+
var qa_trends_default = defineCommand({
|
|
6
|
+
id: "qa:trends",
|
|
7
|
+
description: "Show QA quality trends over time",
|
|
8
|
+
handler: {
|
|
9
|
+
async execute(ctx, input) {
|
|
10
|
+
const { ui } = ctx;
|
|
11
|
+
const flags = input.flags ?? input;
|
|
12
|
+
const rootDir = ctx.cwd;
|
|
13
|
+
const history = loadHistory(rootDir);
|
|
14
|
+
const window = typeof flags.window === "number" ? flags.window : 10;
|
|
15
|
+
const trends = analyzeTrends(history, window);
|
|
16
|
+
if (flags.json) {
|
|
17
|
+
const enrichedTrends = analyzeEnrichedTrends(history, window);
|
|
18
|
+
ui?.json?.({ trends: enrichedTrends, historyCount: history.length, window });
|
|
19
|
+
return { exitCode: 0 };
|
|
20
|
+
}
|
|
21
|
+
const sections = buildTrendsReport(trends, history);
|
|
22
|
+
for (const section of sections) {
|
|
23
|
+
ui?.success?.(section.header, {
|
|
24
|
+
title: section.header,
|
|
25
|
+
sections: [{ header: "", items: section.lines }]
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
return { exitCode: 0 };
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
export { qa_trends_default as default };
|
|
34
|
+
//# sourceMappingURL=qa-trends.js.map
|
|
35
|
+
//# sourceMappingURL=qa-trends.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/cli/commands/qa-trends.ts"],"names":[],"mappings":";;;;AAMA,IAAO,oBAAQ,aAAA,CAAc;AAAA,EAC3B,EAAA,EAAI,WAAA;AAAA,EACJ,WAAA,EAAa,kCAAA;AAAA,EAEb,OAAA,EAAS;AAAA,IACP,MAAM,OAAA,CAAQ,GAAA,EAAsB,KAAA,EAAsB;AACxD,MAAA,MAAM,EAAE,IAAG,GAAI,GAAA;AACf,MAAA,MAAM,KAAA,GAAS,MAAc,KAAA,IAAS,KAAA;AACtC,MAAA,MAAM,UAAU,GAAA,CAAI,GAAA;AAEpB,MAAA,MAAM,OAAA,GAAU,YAAY,OAAO,CAAA;AACnC,MAAA,MAAM,SAAS,OAAO,KAAA,CAAM,MAAA,KAAW,QAAA,GAAW,MAAM,MAAA,GAAS,EAAA;AACjE,MAAA,MAAM,MAAA,GAAS,aAAA,CAAc,OAAA,EAAS,MAAM,CAAA;AAE5C,MAAA,IAAI,MAAM,IAAA,EAAM;AACd,QAAA,MAAM,cAAA,GAAiB,qBAAA,CAAsB,OAAA,EAAS,MAAM,CAAA;AAC5D,QAAA,EAAA,EAAI,IAAA,GAAO,EAAE,MAAA,EAAQ,cAAA,EAAgB,cAAc,OAAA,CAAQ,MAAA,EAAQ,QAAQ,CAAA;AAC3E,QAAA,OAAO,EAAE,UAAU,CAAA,EAAE;AAAA,MACvB;AAEA,MAAA,MAAM,QAAA,GAAW,iBAAA,CAAkB,MAAA,EAAQ,OAAO,CAAA;AAClD,MAAA,KAAA,MAAW,WAAW,QAAA,EAAU;AAC9B,QAAA,EAAA,EAAI,OAAA,GAAU,QAAQ,MAAA,EAAQ;AAAA,UAC5B,OAAO,OAAA,CAAQ,MAAA;AAAA,UACf,QAAA,EAAU,CAAC,EAAE,MAAA,EAAQ,IAAI,KAAA,EAAO,OAAA,CAAQ,OAAO;AAAA,SAChD,CAAA;AAAA,MACH;AAEA,MAAA,OAAO,EAAE,UAAU,CAAA,EAAE;AAAA,IACvB;AAAA;AAEJ,CAAC","file":"qa-trends.js","sourcesContent":["import { defineCommand, type PluginContextV3 } from '@kb-labs/sdk';\nimport { loadHistory, analyzeTrends, analyzeEnrichedTrends, buildTrendsReport } from '@kb-labs/qa-core';\nimport type { QATrendsFlags } from './flags.js';\n\ntype QATrendsInput = QATrendsFlags & { argv?: string[]; flags?: any };\n\nexport default defineCommand({\n id: 'qa:trends',\n description: 'Show QA quality trends over time',\n\n handler: {\n async execute(ctx: PluginContextV3, input: QATrendsInput) {\n const { ui } = ctx;\n const flags = (input as any).flags ?? input;\n const rootDir = ctx.cwd;\n\n const history = loadHistory(rootDir);\n const window = typeof flags.window === 'number' ? flags.window : 10;\n const trends = analyzeTrends(history, window);\n\n if (flags.json) {\n const enrichedTrends = analyzeEnrichedTrends(history, window);\n ui?.json?.({ trends: enrichedTrends, historyCount: history.length, window });\n return { exitCode: 0 };\n }\n\n const sections = buildTrendsReport(trends, history);\n for (const section of sections) {\n ui?.success?.(section.header, {\n title: section.header,\n sections: [{ header: '', items: section.lines }],\n });\n }\n\n return { exitCode: 0 };\n },\n },\n});\n"]}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,390 @@
|
|
|
1
|
+
import { combinePermissions, kbPlatformPreset, defineCommandFlags } from '@kb-labs/sdk';
|
|
2
|
+
import { QA_ROUTES, QA_BASE_PATH } from '@kb-labs/qa-contracts';
|
|
3
|
+
|
|
4
|
+
// src/manifest.ts
|
|
5
|
+
|
|
6
|
+
// src/cli/commands/flags.ts
|
|
7
|
+
var JSON_FLAG_DESCRIPTION = "Output JSON format";
|
|
8
|
+
var qaRunFlags = {
|
|
9
|
+
json: {
|
|
10
|
+
type: "boolean",
|
|
11
|
+
description: JSON_FLAG_DESCRIPTION,
|
|
12
|
+
default: false
|
|
13
|
+
},
|
|
14
|
+
"skip-check": {
|
|
15
|
+
type: "array",
|
|
16
|
+
description: "Skip specific check IDs (e.g. --skip-check build --skip-check lint)"
|
|
17
|
+
},
|
|
18
|
+
"no-cache": {
|
|
19
|
+
type: "boolean",
|
|
20
|
+
description: "Disable caching (force full run)",
|
|
21
|
+
default: false
|
|
22
|
+
},
|
|
23
|
+
all: {
|
|
24
|
+
type: "boolean",
|
|
25
|
+
description: "Run all packages, ignoring affected analysis",
|
|
26
|
+
default: false
|
|
27
|
+
},
|
|
28
|
+
package: {
|
|
29
|
+
type: "string",
|
|
30
|
+
description: "Filter by package name",
|
|
31
|
+
alias: "p"
|
|
32
|
+
},
|
|
33
|
+
repo: {
|
|
34
|
+
type: "string",
|
|
35
|
+
description: "Filter by repo name",
|
|
36
|
+
alias: "r"
|
|
37
|
+
},
|
|
38
|
+
scope: {
|
|
39
|
+
type: "string",
|
|
40
|
+
description: "Filter by npm scope",
|
|
41
|
+
alias: "s"
|
|
42
|
+
},
|
|
43
|
+
summary: {
|
|
44
|
+
type: "boolean",
|
|
45
|
+
description: "Show summary-only report (legacy flat format)",
|
|
46
|
+
default: false
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
var qaSaveFlags = {
|
|
50
|
+
json: {
|
|
51
|
+
type: "boolean",
|
|
52
|
+
description: JSON_FLAG_DESCRIPTION,
|
|
53
|
+
default: false
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
var qaHistoryFlags = {
|
|
57
|
+
json: {
|
|
58
|
+
type: "boolean",
|
|
59
|
+
description: JSON_FLAG_DESCRIPTION,
|
|
60
|
+
default: false
|
|
61
|
+
},
|
|
62
|
+
limit: {
|
|
63
|
+
type: "number",
|
|
64
|
+
description: "Number of entries to show",
|
|
65
|
+
default: 20
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
var qaTrendsFlags = {
|
|
69
|
+
json: {
|
|
70
|
+
type: "boolean",
|
|
71
|
+
description: JSON_FLAG_DESCRIPTION,
|
|
72
|
+
default: false
|
|
73
|
+
},
|
|
74
|
+
window: {
|
|
75
|
+
type: "number",
|
|
76
|
+
description: "Number of entries for trend window",
|
|
77
|
+
default: 10
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
var qaRegressionsFlags = {
|
|
81
|
+
json: {
|
|
82
|
+
type: "boolean",
|
|
83
|
+
description: JSON_FLAG_DESCRIPTION,
|
|
84
|
+
default: false
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
var baselineUpdateFlags = {
|
|
88
|
+
json: {
|
|
89
|
+
type: "boolean",
|
|
90
|
+
description: JSON_FLAG_DESCRIPTION,
|
|
91
|
+
default: false
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
var baselineStatusFlags = {
|
|
95
|
+
json: {
|
|
96
|
+
type: "boolean",
|
|
97
|
+
description: JSON_FLAG_DESCRIPTION,
|
|
98
|
+
default: false
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
var pluginPermissions = combinePermissions().with(kbPlatformPreset).withFs({
|
|
102
|
+
mode: "readWrite",
|
|
103
|
+
allow: ["**"]
|
|
104
|
+
}).withPlatform({
|
|
105
|
+
cache: ["qa:"],
|
|
106
|
+
analytics: true
|
|
107
|
+
}).withQuotas({
|
|
108
|
+
timeoutMs: 6e5,
|
|
109
|
+
memoryMb: 2048
|
|
110
|
+
}).build();
|
|
111
|
+
var manifest = {
|
|
112
|
+
schema: "kb.plugin/3",
|
|
113
|
+
id: "@kb-labs/qa",
|
|
114
|
+
version: "0.1.0",
|
|
115
|
+
configSection: "qa",
|
|
116
|
+
display: {
|
|
117
|
+
name: "QA Plugin",
|
|
118
|
+
description: "Automated quality checks, baseline tracking, and regression detection",
|
|
119
|
+
tags: ["qa", "quality", "baseline", "regression", "testing"]
|
|
120
|
+
},
|
|
121
|
+
platform: {
|
|
122
|
+
requires: ["storage"],
|
|
123
|
+
optional: ["cache", "analytics", "logger"]
|
|
124
|
+
},
|
|
125
|
+
cli: {
|
|
126
|
+
commands: [
|
|
127
|
+
{
|
|
128
|
+
id: "qa:run",
|
|
129
|
+
group: "qa",
|
|
130
|
+
describe: "Run all QA checks (build, lint, types, tests)",
|
|
131
|
+
longDescription: "Runs comprehensive QA checks across the monorepo: build, lint, type check, and tests. Compares with baseline if available. Supports incremental builds and package filtering.",
|
|
132
|
+
handler: "./cli/commands/qa-run.js#default",
|
|
133
|
+
handlerPath: "./cli/commands/qa-run.js",
|
|
134
|
+
flags: defineCommandFlags(qaRunFlags),
|
|
135
|
+
permissions: pluginPermissions
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
id: "qa:save",
|
|
139
|
+
group: "qa",
|
|
140
|
+
describe: "Run QA checks and save results to history",
|
|
141
|
+
longDescription: "Runs all QA checks and saves the results as a history entry. History is stored in .kb/qa/history.json (max 50 entries).",
|
|
142
|
+
handler: "./cli/commands/qa-save.js#default",
|
|
143
|
+
handlerPath: "./cli/commands/qa-save.js",
|
|
144
|
+
flags: defineCommandFlags(qaSaveFlags),
|
|
145
|
+
permissions: pluginPermissions
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
id: "qa:history",
|
|
149
|
+
group: "qa",
|
|
150
|
+
describe: "Show QA run history",
|
|
151
|
+
longDescription: "Displays the QA run history with pass/fail status for each check type.",
|
|
152
|
+
handler: "./cli/commands/qa-history.js#default",
|
|
153
|
+
handlerPath: "./cli/commands/qa-history.js",
|
|
154
|
+
flags: defineCommandFlags(qaHistoryFlags),
|
|
155
|
+
permissions: pluginPermissions
|
|
156
|
+
},
|
|
157
|
+
{
|
|
158
|
+
id: "qa:trends",
|
|
159
|
+
group: "qa",
|
|
160
|
+
describe: "Show QA quality trends over time",
|
|
161
|
+
longDescription: "Analyzes quality trends by comparing failure counts over a sliding window of history entries.",
|
|
162
|
+
handler: "./cli/commands/qa-trends.js#default",
|
|
163
|
+
handlerPath: "./cli/commands/qa-trends.js",
|
|
164
|
+
flags: defineCommandFlags(qaTrendsFlags),
|
|
165
|
+
permissions: pluginPermissions
|
|
166
|
+
},
|
|
167
|
+
{
|
|
168
|
+
id: "qa:regressions",
|
|
169
|
+
group: "qa",
|
|
170
|
+
describe: "Detect regressions since last QA save",
|
|
171
|
+
longDescription: "Compares the last two history entries to detect new failures. Exits with code 1 if regressions are found. Use before merging.",
|
|
172
|
+
handler: "./cli/commands/qa-regressions.js#default",
|
|
173
|
+
handlerPath: "./cli/commands/qa-regressions.js",
|
|
174
|
+
flags: defineCommandFlags(qaRegressionsFlags),
|
|
175
|
+
permissions: pluginPermissions
|
|
176
|
+
},
|
|
177
|
+
{
|
|
178
|
+
id: "baseline:update",
|
|
179
|
+
group: "qa",
|
|
180
|
+
describe: "Run full QA and save as new baseline",
|
|
181
|
+
longDescription: "Runs all QA checks and saves the results as the current baseline. Future qa:run calls will compare against this baseline.",
|
|
182
|
+
handler: "./cli/commands/baseline-update.js#default",
|
|
183
|
+
handlerPath: "./cli/commands/baseline-update.js",
|
|
184
|
+
flags: defineCommandFlags(baselineUpdateFlags),
|
|
185
|
+
permissions: pluginPermissions
|
|
186
|
+
},
|
|
187
|
+
{
|
|
188
|
+
id: "baseline:status",
|
|
189
|
+
group: "qa",
|
|
190
|
+
describe: "Show current baseline status",
|
|
191
|
+
longDescription: "Displays the current baseline snapshot with pass/fail counts per check type.",
|
|
192
|
+
handler: "./cli/commands/baseline-status.js#default",
|
|
193
|
+
handlerPath: "./cli/commands/baseline-status.js",
|
|
194
|
+
flags: defineCommandFlags(baselineStatusFlags),
|
|
195
|
+
permissions: pluginPermissions
|
|
196
|
+
}
|
|
197
|
+
]
|
|
198
|
+
},
|
|
199
|
+
// REST API routes
|
|
200
|
+
rest: {
|
|
201
|
+
basePath: QA_BASE_PATH,
|
|
202
|
+
routes: [
|
|
203
|
+
// GET /summary
|
|
204
|
+
{
|
|
205
|
+
method: "GET",
|
|
206
|
+
path: QA_ROUTES.SUMMARY,
|
|
207
|
+
handler: "./rest/handlers/summary-handler.js#default",
|
|
208
|
+
input: {
|
|
209
|
+
zod: "@kb-labs/qa-contracts#QASummaryRequestSchema"
|
|
210
|
+
},
|
|
211
|
+
output: {
|
|
212
|
+
zod: "@kb-labs/qa-contracts#QASummaryResponseSchema"
|
|
213
|
+
}
|
|
214
|
+
},
|
|
215
|
+
// GET /latest
|
|
216
|
+
{
|
|
217
|
+
method: "GET",
|
|
218
|
+
path: QA_ROUTES.LATEST,
|
|
219
|
+
handler: "./rest/handlers/latest-handler.js#default",
|
|
220
|
+
input: {
|
|
221
|
+
zod: "@kb-labs/qa-contracts#QALatestRequestSchema"
|
|
222
|
+
},
|
|
223
|
+
output: {
|
|
224
|
+
zod: "@kb-labs/qa-contracts#QALatestResponseSchema"
|
|
225
|
+
}
|
|
226
|
+
},
|
|
227
|
+
// GET /history
|
|
228
|
+
{
|
|
229
|
+
method: "GET",
|
|
230
|
+
path: QA_ROUTES.HISTORY,
|
|
231
|
+
handler: "./rest/handlers/history-handler.js#default",
|
|
232
|
+
input: {
|
|
233
|
+
zod: "@kb-labs/qa-contracts#QAHistoryRequestSchema"
|
|
234
|
+
},
|
|
235
|
+
output: {
|
|
236
|
+
zod: "@kb-labs/qa-contracts#QAHistoryResponseSchema"
|
|
237
|
+
}
|
|
238
|
+
},
|
|
239
|
+
// GET /trends
|
|
240
|
+
{
|
|
241
|
+
method: "GET",
|
|
242
|
+
path: QA_ROUTES.TRENDS,
|
|
243
|
+
handler: "./rest/handlers/trends-handler.js#default",
|
|
244
|
+
input: {
|
|
245
|
+
zod: "@kb-labs/qa-contracts#QATrendsRequestSchema"
|
|
246
|
+
},
|
|
247
|
+
output: {
|
|
248
|
+
zod: "@kb-labs/qa-contracts#QATrendsResponseSchema"
|
|
249
|
+
}
|
|
250
|
+
},
|
|
251
|
+
// GET /regressions
|
|
252
|
+
{
|
|
253
|
+
method: "GET",
|
|
254
|
+
path: QA_ROUTES.REGRESSIONS,
|
|
255
|
+
handler: "./rest/handlers/regressions-handler.js#default",
|
|
256
|
+
input: {
|
|
257
|
+
zod: "@kb-labs/qa-contracts#QARegressionsRequestSchema"
|
|
258
|
+
},
|
|
259
|
+
output: {
|
|
260
|
+
zod: "@kb-labs/qa-contracts#QARegressionsResponseSchema"
|
|
261
|
+
}
|
|
262
|
+
},
|
|
263
|
+
// GET /baseline
|
|
264
|
+
{
|
|
265
|
+
method: "GET",
|
|
266
|
+
path: QA_ROUTES.BASELINE,
|
|
267
|
+
handler: "./rest/handlers/baseline-handler.js#default",
|
|
268
|
+
input: {
|
|
269
|
+
zod: "@kb-labs/qa-contracts#QABaselineRequestSchema"
|
|
270
|
+
},
|
|
271
|
+
output: {
|
|
272
|
+
zod: "@kb-labs/qa-contracts#QABaselineResponseSchema"
|
|
273
|
+
}
|
|
274
|
+
},
|
|
275
|
+
// POST /run
|
|
276
|
+
{
|
|
277
|
+
method: "POST",
|
|
278
|
+
path: QA_ROUTES.RUN,
|
|
279
|
+
handler: "./rest/handlers/run-handler.js#default",
|
|
280
|
+
input: {
|
|
281
|
+
zod: "@kb-labs/qa-contracts#QARunRequestSchema"
|
|
282
|
+
},
|
|
283
|
+
output: {
|
|
284
|
+
zod: "@kb-labs/qa-contracts#QARunResponseSchema"
|
|
285
|
+
}
|
|
286
|
+
},
|
|
287
|
+
// GET /details — per-package details with error text
|
|
288
|
+
{
|
|
289
|
+
method: "GET",
|
|
290
|
+
path: QA_ROUTES.DETAILS,
|
|
291
|
+
handler: "./rest/handlers/details-handler.js#default",
|
|
292
|
+
input: {
|
|
293
|
+
zod: "@kb-labs/qa-contracts#QADetailsRequestSchema"
|
|
294
|
+
},
|
|
295
|
+
output: {
|
|
296
|
+
zod: "@kb-labs/qa-contracts#QADetailsResponseSchema"
|
|
297
|
+
}
|
|
298
|
+
},
|
|
299
|
+
// POST /run/check — run a single check type
|
|
300
|
+
{
|
|
301
|
+
method: "POST",
|
|
302
|
+
path: QA_ROUTES.RUN_CHECK,
|
|
303
|
+
handler: "./rest/handlers/run-check-handler.js#default",
|
|
304
|
+
input: {
|
|
305
|
+
zod: "@kb-labs/qa-contracts#QARunCheckRequestSchema"
|
|
306
|
+
},
|
|
307
|
+
output: {
|
|
308
|
+
zod: "@kb-labs/qa-contracts#QARunCheckResponseSchema"
|
|
309
|
+
}
|
|
310
|
+
},
|
|
311
|
+
// POST /baseline/update — update baseline from last run
|
|
312
|
+
{
|
|
313
|
+
method: "POST",
|
|
314
|
+
path: QA_ROUTES.BASELINE_UPDATE,
|
|
315
|
+
handler: "./rest/handlers/baseline-update-handler.js#default",
|
|
316
|
+
input: {
|
|
317
|
+
zod: "@kb-labs/qa-contracts#QABaselineUpdateRequestSchema"
|
|
318
|
+
},
|
|
319
|
+
output: {
|
|
320
|
+
zod: "@kb-labs/qa-contracts#QABaselineUpdateResponseSchema"
|
|
321
|
+
}
|
|
322
|
+
},
|
|
323
|
+
// GET /baseline/diff — diff current state vs baseline
|
|
324
|
+
{
|
|
325
|
+
method: "GET",
|
|
326
|
+
path: QA_ROUTES.BASELINE_DIFF,
|
|
327
|
+
handler: "./rest/handlers/baseline-diff-handler.js#default",
|
|
328
|
+
input: {
|
|
329
|
+
zod: "@kb-labs/qa-contracts#QABaselineDiffRequestSchema"
|
|
330
|
+
},
|
|
331
|
+
output: {
|
|
332
|
+
zod: "@kb-labs/qa-contracts#QABaselineDiffResponseSchema"
|
|
333
|
+
}
|
|
334
|
+
},
|
|
335
|
+
// GET /packages/:name/timeline — per-package QA timeline
|
|
336
|
+
{
|
|
337
|
+
method: "GET",
|
|
338
|
+
path: QA_ROUTES.PACKAGE_TIMELINE,
|
|
339
|
+
handler: "./rest/handlers/package-timeline-handler.js#default",
|
|
340
|
+
input: {
|
|
341
|
+
zod: "@kb-labs/qa-contracts#QAPackageTimelineRequestSchema"
|
|
342
|
+
},
|
|
343
|
+
output: {
|
|
344
|
+
zod: "@kb-labs/qa-contracts#QAPackageTimelineResponseSchema"
|
|
345
|
+
}
|
|
346
|
+
},
|
|
347
|
+
// GET /errors/groups — grouped errors by pattern
|
|
348
|
+
{
|
|
349
|
+
method: "GET",
|
|
350
|
+
path: QA_ROUTES.ERROR_GROUPS,
|
|
351
|
+
handler: "./rest/handlers/error-groups-handler.js#default",
|
|
352
|
+
input: {
|
|
353
|
+
zod: "@kb-labs/qa-contracts#QAErrorGroupsRequestSchema"
|
|
354
|
+
},
|
|
355
|
+
output: {
|
|
356
|
+
zod: "@kb-labs/qa-contracts#QAErrorGroupsResponseSchema"
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
]
|
|
360
|
+
},
|
|
361
|
+
// Studio V2 — Module Federation pages
|
|
362
|
+
studio: {
|
|
363
|
+
version: 2,
|
|
364
|
+
remoteName: "qaPlugin",
|
|
365
|
+
pages: [
|
|
366
|
+
{
|
|
367
|
+
id: "qa.overview",
|
|
368
|
+
title: "QA",
|
|
369
|
+
icon: "ExperimentOutlined",
|
|
370
|
+
route: "/p/qa",
|
|
371
|
+
entry: "./QADashboard",
|
|
372
|
+
order: 1
|
|
373
|
+
}
|
|
374
|
+
],
|
|
375
|
+
menus: [
|
|
376
|
+
{
|
|
377
|
+
id: "qa",
|
|
378
|
+
label: "QA",
|
|
379
|
+
icon: "ExperimentOutlined",
|
|
380
|
+
target: "qa.overview",
|
|
381
|
+
order: 50
|
|
382
|
+
}
|
|
383
|
+
]
|
|
384
|
+
},
|
|
385
|
+
permissions: pluginPermissions
|
|
386
|
+
};
|
|
387
|
+
|
|
388
|
+
export { manifest };
|
|
389
|
+
//# sourceMappingURL=index.js.map
|
|
390
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli/commands/flags.ts","../src/manifest.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * QA Plugin CLI flag definitions.\n * DRY: Define once, use in manifest and command handlers.\n */\n\nconst JSON_FLAG_DESCRIPTION = 'Output JSON format';\n\nexport const qaRunFlags = {\n json: {\n type: 'boolean',\n description: JSON_FLAG_DESCRIPTION,\n default: false,\n },\n 'skip-check': {\n type: 'array',\n description: 'Skip specific check IDs (e.g. --skip-check build --skip-check lint)',\n },\n 'no-cache': {\n type: 'boolean',\n description: 'Disable caching (force full run)',\n default: false,\n },\n all: {\n type: 'boolean',\n description: 'Run all packages, ignoring affected analysis',\n default: false,\n },\n package: {\n type: 'string',\n description: 'Filter by package name',\n alias: 'p',\n },\n repo: {\n type: 'string',\n description: 'Filter by repo name',\n alias: 'r',\n },\n scope: {\n type: 'string',\n description: 'Filter by npm scope',\n alias: 's',\n },\n summary: {\n type: 'boolean',\n description: 'Show summary-only report (legacy flat format)',\n default: false,\n },\n} as const;\n\nexport type QARunFlags = typeof qaRunFlags;\n\nexport const qaSaveFlags = {\n json: {\n type: 'boolean',\n description: JSON_FLAG_DESCRIPTION,\n default: false,\n },\n} as const;\n\nexport type QASaveFlags = typeof qaSaveFlags;\n\nexport const qaHistoryFlags = {\n json: {\n type: 'boolean',\n description: JSON_FLAG_DESCRIPTION,\n default: false,\n },\n limit: {\n type: 'number',\n description: 'Number of entries to show',\n default: 20,\n },\n} as const;\n\nexport type QAHistoryFlags = typeof qaHistoryFlags;\n\nexport const qaTrendsFlags = {\n json: {\n type: 'boolean',\n description: JSON_FLAG_DESCRIPTION,\n default: false,\n },\n window: {\n type: 'number',\n description: 'Number of entries for trend window',\n default: 10,\n },\n} as const;\n\nexport type QATrendsFlags = typeof qaTrendsFlags;\n\nexport const qaRegressionsFlags = {\n json: {\n type: 'boolean',\n description: JSON_FLAG_DESCRIPTION,\n default: false,\n },\n} as const;\n\nexport type QARegressionsFlags = typeof qaRegressionsFlags;\n\nexport const baselineUpdateFlags = {\n json: {\n type: 'boolean',\n description: JSON_FLAG_DESCRIPTION,\n default: false,\n },\n} as const;\n\nexport type BaselineUpdateFlags = typeof baselineUpdateFlags;\n\nexport const baselineStatusFlags = {\n json: {\n type: 'boolean',\n description: JSON_FLAG_DESCRIPTION,\n default: false,\n },\n} as const;\n\nexport type BaselineStatusFlags = typeof baselineStatusFlags;\n","/**\n * QA Plugin Manifest V3\n *\n * Automated quality checks, baseline tracking, and regression detection.\n */\n\nimport {\n combinePermissions,\n kbPlatformPreset,\n defineCommandFlags,\n} from '@kb-labs/sdk';\nimport {\n qaRunFlags,\n qaSaveFlags,\n qaHistoryFlags,\n qaTrendsFlags,\n qaRegressionsFlags,\n baselineUpdateFlags,\n baselineStatusFlags,\n} from './cli/commands/flags.js';\nimport {\n QA_BASE_PATH,\n QA_ROUTES,\n} from '@kb-labs/qa-contracts';\n\nconst pluginPermissions = combinePermissions()\n .with(kbPlatformPreset)\n .withFs({\n mode: 'readWrite',\n allow: ['**'],\n })\n .withPlatform({\n cache: ['qa:'],\n analytics: true,\n })\n .withQuotas({\n timeoutMs: 600000,\n memoryMb: 2048,\n })\n .build();\n\nexport const manifest = {\n schema: 'kb.plugin/3',\n id: '@kb-labs/qa',\n version: '0.1.0',\n\n configSection: 'qa',\n\n display: {\n name: 'QA Plugin',\n description: 'Automated quality checks, baseline tracking, and regression detection',\n tags: ['qa', 'quality', 'baseline', 'regression', 'testing'],\n },\n\n platform: {\n requires: ['storage'],\n optional: ['cache', 'analytics', 'logger'],\n },\n\n cli: {\n commands: [\n {\n id: 'qa:run',\n group: 'qa',\n describe: 'Run all QA checks (build, lint, types, tests)',\n longDescription:\n 'Runs comprehensive QA checks across the monorepo: build, lint, type check, and tests. ' +\n 'Compares with baseline if available. Supports incremental builds and package filtering.',\n handler: './cli/commands/qa-run.js#default',\n handlerPath: './cli/commands/qa-run.js',\n flags: defineCommandFlags(qaRunFlags),\n permissions: pluginPermissions,\n },\n {\n id: 'qa:save',\n group: 'qa',\n describe: 'Run QA checks and save results to history',\n longDescription:\n 'Runs all QA checks and saves the results as a history entry. ' +\n 'History is stored in .kb/qa/history.json (max 50 entries).',\n handler: './cli/commands/qa-save.js#default',\n handlerPath: './cli/commands/qa-save.js',\n flags: defineCommandFlags(qaSaveFlags),\n permissions: pluginPermissions,\n },\n {\n id: 'qa:history',\n group: 'qa',\n describe: 'Show QA run history',\n longDescription: 'Displays the QA run history with pass/fail status for each check type.',\n handler: './cli/commands/qa-history.js#default',\n handlerPath: './cli/commands/qa-history.js',\n flags: defineCommandFlags(qaHistoryFlags),\n permissions: pluginPermissions,\n },\n {\n id: 'qa:trends',\n group: 'qa',\n describe: 'Show QA quality trends over time',\n longDescription:\n 'Analyzes quality trends by comparing failure counts over a sliding window of history entries.',\n handler: './cli/commands/qa-trends.js#default',\n handlerPath: './cli/commands/qa-trends.js',\n flags: defineCommandFlags(qaTrendsFlags),\n permissions: pluginPermissions,\n },\n {\n id: 'qa:regressions',\n group: 'qa',\n describe: 'Detect regressions since last QA save',\n longDescription:\n 'Compares the last two history entries to detect new failures. ' +\n 'Exits with code 1 if regressions are found. Use before merging.',\n handler: './cli/commands/qa-regressions.js#default',\n handlerPath: './cli/commands/qa-regressions.js',\n flags: defineCommandFlags(qaRegressionsFlags),\n permissions: pluginPermissions,\n },\n {\n id: 'baseline:update',\n group: 'qa',\n describe: 'Run full QA and save as new baseline',\n longDescription:\n 'Runs all QA checks and saves the results as the current baseline. ' +\n 'Future qa:run calls will compare against this baseline.',\n handler: './cli/commands/baseline-update.js#default',\n handlerPath: './cli/commands/baseline-update.js',\n flags: defineCommandFlags(baselineUpdateFlags),\n permissions: pluginPermissions,\n },\n {\n id: 'baseline:status',\n group: 'qa',\n describe: 'Show current baseline status',\n longDescription: 'Displays the current baseline snapshot with pass/fail counts per check type.',\n handler: './cli/commands/baseline-status.js#default',\n handlerPath: './cli/commands/baseline-status.js',\n flags: defineCommandFlags(baselineStatusFlags),\n permissions: pluginPermissions,\n },\n ],\n },\n\n // REST API routes\n rest: {\n basePath: QA_BASE_PATH,\n routes: [\n // GET /summary\n {\n method: 'GET',\n path: QA_ROUTES.SUMMARY,\n handler: './rest/handlers/summary-handler.js#default',\n input: {\n zod: '@kb-labs/qa-contracts#QASummaryRequestSchema',\n },\n output: {\n zod: '@kb-labs/qa-contracts#QASummaryResponseSchema',\n },\n },\n // GET /latest\n {\n method: 'GET',\n path: QA_ROUTES.LATEST,\n handler: './rest/handlers/latest-handler.js#default',\n input: {\n zod: '@kb-labs/qa-contracts#QALatestRequestSchema',\n },\n output: {\n zod: '@kb-labs/qa-contracts#QALatestResponseSchema',\n },\n },\n // GET /history\n {\n method: 'GET',\n path: QA_ROUTES.HISTORY,\n handler: './rest/handlers/history-handler.js#default',\n input: {\n zod: '@kb-labs/qa-contracts#QAHistoryRequestSchema',\n },\n output: {\n zod: '@kb-labs/qa-contracts#QAHistoryResponseSchema',\n },\n },\n // GET /trends\n {\n method: 'GET',\n path: QA_ROUTES.TRENDS,\n handler: './rest/handlers/trends-handler.js#default',\n input: {\n zod: '@kb-labs/qa-contracts#QATrendsRequestSchema',\n },\n output: {\n zod: '@kb-labs/qa-contracts#QATrendsResponseSchema',\n },\n },\n // GET /regressions\n {\n method: 'GET',\n path: QA_ROUTES.REGRESSIONS,\n handler: './rest/handlers/regressions-handler.js#default',\n input: {\n zod: '@kb-labs/qa-contracts#QARegressionsRequestSchema',\n },\n output: {\n zod: '@kb-labs/qa-contracts#QARegressionsResponseSchema',\n },\n },\n // GET /baseline\n {\n method: 'GET',\n path: QA_ROUTES.BASELINE,\n handler: './rest/handlers/baseline-handler.js#default',\n input: {\n zod: '@kb-labs/qa-contracts#QABaselineRequestSchema',\n },\n output: {\n zod: '@kb-labs/qa-contracts#QABaselineResponseSchema',\n },\n },\n // POST /run\n {\n method: 'POST',\n path: QA_ROUTES.RUN,\n handler: './rest/handlers/run-handler.js#default',\n input: {\n zod: '@kb-labs/qa-contracts#QARunRequestSchema',\n },\n output: {\n zod: '@kb-labs/qa-contracts#QARunResponseSchema',\n },\n },\n // GET /details — per-package details with error text\n {\n method: 'GET',\n path: QA_ROUTES.DETAILS,\n handler: './rest/handlers/details-handler.js#default',\n input: {\n zod: '@kb-labs/qa-contracts#QADetailsRequestSchema',\n },\n output: {\n zod: '@kb-labs/qa-contracts#QADetailsResponseSchema',\n },\n },\n // POST /run/check — run a single check type\n {\n method: 'POST',\n path: QA_ROUTES.RUN_CHECK,\n handler: './rest/handlers/run-check-handler.js#default',\n input: {\n zod: '@kb-labs/qa-contracts#QARunCheckRequestSchema',\n },\n output: {\n zod: '@kb-labs/qa-contracts#QARunCheckResponseSchema',\n },\n },\n // POST /baseline/update — update baseline from last run\n {\n method: 'POST',\n path: QA_ROUTES.BASELINE_UPDATE,\n handler: './rest/handlers/baseline-update-handler.js#default',\n input: {\n zod: '@kb-labs/qa-contracts#QABaselineUpdateRequestSchema',\n },\n output: {\n zod: '@kb-labs/qa-contracts#QABaselineUpdateResponseSchema',\n },\n },\n // GET /baseline/diff — diff current state vs baseline\n {\n method: 'GET',\n path: QA_ROUTES.BASELINE_DIFF,\n handler: './rest/handlers/baseline-diff-handler.js#default',\n input: {\n zod: '@kb-labs/qa-contracts#QABaselineDiffRequestSchema',\n },\n output: {\n zod: '@kb-labs/qa-contracts#QABaselineDiffResponseSchema',\n },\n },\n // GET /packages/:name/timeline — per-package QA timeline\n {\n method: 'GET',\n path: QA_ROUTES.PACKAGE_TIMELINE,\n handler: './rest/handlers/package-timeline-handler.js#default',\n input: {\n zod: '@kb-labs/qa-contracts#QAPackageTimelineRequestSchema',\n },\n output: {\n zod: '@kb-labs/qa-contracts#QAPackageTimelineResponseSchema',\n },\n },\n // GET /errors/groups — grouped errors by pattern\n {\n method: 'GET',\n path: QA_ROUTES.ERROR_GROUPS,\n handler: './rest/handlers/error-groups-handler.js#default',\n input: {\n zod: '@kb-labs/qa-contracts#QAErrorGroupsRequestSchema',\n },\n output: {\n zod: '@kb-labs/qa-contracts#QAErrorGroupsResponseSchema',\n },\n },\n ],\n },\n\n // Studio V2 — Module Federation pages\n studio: {\n version: 2 as const,\n remoteName: 'qaPlugin',\n pages: [\n {\n id: 'qa.overview',\n title: 'QA',\n icon: 'ExperimentOutlined',\n route: '/p/qa',\n entry: './QADashboard',\n order: 1,\n },\n ],\n menus: [\n {\n id: 'qa',\n label: 'QA',\n icon: 'ExperimentOutlined',\n target: 'qa.overview',\n order: 50,\n },\n ],\n },\n\n permissions: pluginPermissions,\n};\n\nexport default manifest;\n"]}
|