@kb-labs/qa-entry 2.109.0 → 2.111.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.
Files changed (59) hide show
  1. package/dist/cli/commands/baseline-diff.d.ts +1 -3
  2. package/dist/cli/commands/baseline-diff.js +3 -3
  3. package/dist/cli/commands/baseline-diff.js.map +1 -1
  4. package/dist/cli/commands/baseline-status.d.ts +1 -3
  5. package/dist/cli/commands/baseline-status.js +1 -1
  6. package/dist/cli/commands/baseline-status.js.map +1 -1
  7. package/dist/cli/commands/baseline-update.d.ts +1 -3
  8. package/dist/cli/commands/baseline-update.js +1 -1
  9. package/dist/cli/commands/baseline-update.js.map +1 -1
  10. package/dist/cli/commands/flags.d.ts +70 -1
  11. package/dist/cli/commands/flags.js +67 -1
  12. package/dist/cli/commands/flags.js.map +1 -1
  13. package/dist/cli/commands/qa-check.d.ts +1 -3
  14. package/dist/cli/commands/qa-check.js +1 -1
  15. package/dist/cli/commands/qa-check.js.map +1 -1
  16. package/dist/cli/commands/qa-ci-evidence-capture.d.ts +29 -0
  17. package/dist/cli/commands/qa-ci-evidence-capture.js +59 -0
  18. package/dist/cli/commands/qa-ci-evidence-capture.js.map +1 -0
  19. package/dist/cli/commands/qa-ci-evidence-sync.d.ts +31 -0
  20. package/dist/cli/commands/qa-ci-evidence-sync.js +51 -0
  21. package/dist/cli/commands/qa-ci-evidence-sync.js.map +1 -0
  22. package/dist/cli/commands/qa-ci-overview.d.ts +21 -0
  23. package/dist/cli/commands/qa-ci-overview.js +49 -0
  24. package/dist/cli/commands/qa-ci-overview.js.map +1 -0
  25. package/dist/cli/commands/qa-e2e-flaky.d.ts +1 -3
  26. package/dist/cli/commands/qa-e2e-flaky.js +6 -6
  27. package/dist/cli/commands/qa-e2e-flaky.js.map +1 -1
  28. package/dist/cli/commands/qa-gate.d.ts +1 -3
  29. package/dist/cli/commands/qa-gate.js +1 -1
  30. package/dist/cli/commands/qa-gate.js.map +1 -1
  31. package/dist/cli/commands/qa-history.d.ts +1 -3
  32. package/dist/cli/commands/qa-history.js +1 -1
  33. package/dist/cli/commands/qa-history.js.map +1 -1
  34. package/dist/cli/commands/qa-regressions.d.ts +1 -3
  35. package/dist/cli/commands/qa-regressions.js +1 -1
  36. package/dist/cli/commands/qa-regressions.js.map +1 -1
  37. package/dist/cli/commands/qa-run.d.ts +1 -3
  38. package/dist/cli/commands/qa-run.js +1 -1
  39. package/dist/cli/commands/qa-run.js.map +1 -1
  40. package/dist/cli/commands/qa-stats.d.ts +1 -3
  41. package/dist/cli/commands/qa-stats.js +1 -1
  42. package/dist/cli/commands/qa-stats.js.map +1 -1
  43. package/dist/cli/commands/qa-trends.d.ts +1 -3
  44. package/dist/cli/commands/qa-trends.js +1 -1
  45. package/dist/cli/commands/qa-trends.js.map +1 -1
  46. package/dist/index.js +99 -3
  47. package/dist/index.js.map +1 -1
  48. package/dist/manifest.d.ts +4 -0
  49. package/dist/manifest.js +99 -3
  50. package/dist/manifest.js.map +1 -1
  51. package/dist/manifest.json +245 -12
  52. package/dist/rest/handlers/ci-overview-handler.d.ts +7 -0
  53. package/dist/rest/handlers/ci-overview-handler.js +19 -0
  54. package/dist/rest/handlers/ci-overview-handler.js.map +1 -0
  55. package/dist/widgets/__federation_expose_QADashboard.js +1 -1
  56. package/dist/widgets/mf-manifest.json +12 -12
  57. package/dist/widgets/mf-stats.json +12 -12
  58. package/dist/widgets/remoteEntry.js +2 -2
  59. package/package.json +4 -4
@@ -0,0 +1,49 @@
1
+ import { mkdirSync, writeFileSync } from 'fs';
2
+ import { resolve, dirname } from 'path';
3
+ import { defineCommand } from '@kb-labs/sdk';
4
+ import { loadCiDossiers, analyzeCiReliability } from '@kb-labs/qa-core';
5
+
6
+ // src/cli/commands/qa-ci-overview.ts
7
+ var qa_ci_overview_default = defineCommand({
8
+ id: "qa:ci-overview",
9
+ description: "Show a compact CI reliability overview from captured dossiers",
10
+ handler: {
11
+ async execute(ctx, input) {
12
+ const cwd = ctx.cwd ?? process.cwd();
13
+ const inputPath = resolve(cwd, input.flags.input);
14
+ const dossiers = loadCiDossiers(inputPath);
15
+ if (dossiers.length === 0) {
16
+ ctx.ui?.error?.(`No CI dossiers found under ${inputPath}. Run \`kb qa ci evidence capture\` in CI first.`);
17
+ return { ok: false, error: "Command failed" };
18
+ }
19
+ const overview = analyzeCiReliability(dossiers);
20
+ if (input.flags.output) {
21
+ const output = resolve(cwd, input.flags.output);
22
+ mkdirSync(dirname(output), { recursive: true });
23
+ writeFileSync(output, `${JSON.stringify(overview, null, 2)}
24
+ `);
25
+ }
26
+ if (input.flags.json) {
27
+ ctx.ui?.json?.(overview);
28
+ } else {
29
+ ctx.ui?.success?.(`CI reliability (${overview.runsAnalyzed} run${overview.runsAnalyzed === 1 ? "" : "s"})`, {
30
+ sections: [
31
+ { header: "Summary", items: [
32
+ `failed runs: ${overview.failedRuns}`,
33
+ `failed before tests: ${overview.failedBeforeTests}`,
34
+ `evidence: ${overview.collection.complete} complete, ${overview.collection.partial} partial`,
35
+ ...input.flags.output ? [`saved JSON: ${resolve(cwd, input.flags.output)}`] : []
36
+ ] },
37
+ { header: "Top findings", items: overview.findings.length > 0 ? overview.findings.map((finding) => `${finding.fingerprint} \u2014 ${finding.occurrences} occurrence(s), ${(finding.confidence * 100).toFixed(0)}% confidence; ${finding.affectedJobs.join(", ")}`) : ["No failed CI steps in the captured evidence."] },
38
+ { header: "Drill down", items: overview.drillDown.runIds.map((runId) => `kb qa ci run --run-id ${runId} --json`) }
39
+ ]
40
+ });
41
+ }
42
+ return { ok: true };
43
+ }
44
+ }
45
+ });
46
+
47
+ export { qa_ci_overview_default as default };
48
+ //# sourceMappingURL=qa-ci-overview.js.map
49
+ //# sourceMappingURL=qa-ci-overview.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/cli/commands/qa-ci-overview.ts"],"names":[],"mappings":"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","file":"qa-ci-overview.js","sourcesContent":["import { mkdirSync, writeFileSync } from 'node:fs';\nimport { dirname, resolve } from 'node:path';\nimport { defineCommand, type CLIInput, type PluginContextV3 , type CommandResult} from '@kb-labs/sdk';\nimport { analyzeCiReliability, loadCiDossiers } from '@kb-labs/qa-core';\nimport type { QaCiOverviewFlags } from './flags.js';\n\nexport default defineCommand<unknown, CLIInput<QaCiOverviewFlags>, unknown>({\n id: 'qa:ci-overview',\n description: 'Show a compact CI reliability overview from captured dossiers',\n handler: {\n async execute(ctx: PluginContextV3, input: CLIInput<QaCiOverviewFlags>): Promise<CommandResult> {\n const cwd = ctx.cwd ?? process.cwd();\n const inputPath = resolve(cwd, input.flags.input);\n const dossiers = loadCiDossiers(inputPath);\n if (dossiers.length === 0) {\n ctx.ui?.error?.(`No CI dossiers found under ${inputPath}. Run \\`kb qa ci evidence capture\\` in CI first.`);\n return { ok: false, error: 'Command failed' };\n }\n const overview = analyzeCiReliability(dossiers);\n if (input.flags.output) {\n const output = resolve(cwd, input.flags.output);\n mkdirSync(dirname(output), { recursive: true });\n writeFileSync(output, `${JSON.stringify(overview, null, 2)}\\n`);\n }\n if (input.flags.json) {\n ctx.ui?.json?.(overview);\n } else {\n ctx.ui?.success?.(`CI reliability (${overview.runsAnalyzed} run${overview.runsAnalyzed === 1 ? '' : 's'})`, {\n sections: [\n { header: 'Summary', items: [\n `failed runs: ${overview.failedRuns}`,\n `failed before tests: ${overview.failedBeforeTests}`,\n `evidence: ${overview.collection.complete} complete, ${overview.collection.partial} partial`,\n ...(input.flags.output ? [`saved JSON: ${resolve(cwd, input.flags.output)}`] : []),\n ] },\n { header: 'Top findings', items: overview.findings.length > 0\n ? overview.findings.map(finding => `${finding.fingerprint} — ${finding.occurrences} occurrence(s), ${(finding.confidence * 100).toFixed(0)}% confidence; ${finding.affectedJobs.join(', ')}`)\n : ['No failed CI steps in the captured evidence.'] },\n { header: 'Drill down', items: overview.drillDown.runIds.map(runId => `kb qa ci run --run-id ${runId} --json`) },\n ],\n });\n }\n return { ok: true };\n },\n },\n});\n"]}
@@ -30,8 +30,6 @@ declare const _default: _kb_labs_shared_command_kit.CommandHandlerV3<unknown, CL
30
30
  type: "string";
31
31
  description: string;
32
32
  };
33
- }>>, {
34
- exitCode: number;
35
- }>;
33
+ }>>, unknown>;
36
34
 
37
35
  export { _default as default };
@@ -21,13 +21,13 @@ async function runIngest(ctx, cwd, store, dir) {
21
21
  }
22
22
  if (cases.length === 0) {
23
23
  ctx.ui?.error?.(`No flaky-report.json files found under ${dir} \u2014 nothing to ingest.`);
24
- return { exitCode: 1 };
24
+ return { ok: false, error: "Command failed" };
25
25
  }
26
26
  const git = await captureGit(ctx.api.shell, cwd);
27
27
  const snap = store.saveE2eFlaky(cases, 0, git);
28
28
  ctx.ui?.success?.(`Ingested ${cases.length} e2e case result(s) from ${dir} into flaky history`, {});
29
29
  ctx.ui?.json?.(snap);
30
- return { exitCode: 0 };
30
+ return { ok: true };
31
31
  }
32
32
  async function runSync(ctx, cwd) {
33
33
  const fetch = await ctx.api.shell.exec("git", ["fetch", "origin", "ci-data"], { cwd, throwOnError: false });
@@ -62,7 +62,7 @@ var qa_e2e_flaky_default = defineCommand({
62
62
  if (flags.sync) {
63
63
  const synced = await runSync(ctx, cwd);
64
64
  if (!synced) {
65
- return { exitCode: 1 };
65
+ return { ok: false, error: "Command failed" };
66
66
  }
67
67
  }
68
68
  if (flags.ingest) {
@@ -74,7 +74,7 @@ var qa_e2e_flaky_default = defineCommand({
74
74
  const timeline = buildCaseTimeline(history.slice(-window), flags.case);
75
75
  if (!timeline) {
76
76
  ctx.ui?.error?.(`No history found for case "${flags.case}". Run with --agent to see the "top" list of known cases.`);
77
- return { exitCode: 1 };
77
+ return { ok: false, error: "Command failed" };
78
78
  }
79
79
  if (json) {
80
80
  ctx.ui?.json?.(timeline);
@@ -92,7 +92,7 @@ var qa_e2e_flaky_default = defineCommand({
92
92
  ]
93
93
  });
94
94
  }
95
- return { exitCode: 0 };
95
+ return { ok: true };
96
96
  }
97
97
  const overview = analyzeFlakyCases(history, window);
98
98
  if (json) {
@@ -110,7 +110,7 @@ var qa_e2e_flaky_default = defineCommand({
110
110
  ]
111
111
  });
112
112
  }
113
- return { exitCode: 0 };
113
+ return { ok: true };
114
114
  }
115
115
  }
116
116
  });
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/cli/commands/qa-e2e-flaky.ts"],"names":[],"mappings":";;;;;;;AAiBA,eAAe,SAAA,CACb,GAAA,EACA,GAAA,EACA,KAAA,EACA,GAAA,EAC+B;AAC/B,EAAA,MAAM,QAAyB,EAAC;AAChC,EAAA,IAAI,UAAA,CAAW,GAAG,CAAA,EAAG;AACnB,IAAA,KAAA,MAAW,SAAS,WAAA,CAAY,GAAA,EAAK,EAAE,aAAA,EAAe,IAAA,EAAM,CAAA,EAAG;AAC7D,MAAA,MAAM,OAAO,KAAA,CAAM,WAAA,EAAY,GAC3B,IAAA,CAAK,KAAK,KAAA,CAAM,IAAA,EAAM,mBAAmB,CAAA,GACzC,MAAM,IAAA,KAAS,mBAAA,GAAsB,KAAK,GAAA,EAAK,KAAA,CAAM,IAAI,CAAA,GAAI,IAAA;AACjE,MAAA,IAAI,CAAC,IAAA,IAAQ,CAAC,UAAA,CAAW,IAAI,CAAA,EAAG;AAAC,QAAA;AAAA,MAAS;AAC1C,MAAA,IAAI;AACF,QAAA,KAAA,CAAM,IAAA,CAAK,GAAI,IAAA,CAAK,KAAA,CAAM,aAAa,IAAA,EAAM,OAAO,CAAC,CAAqB,CAAA;AAAA,MAC5E,CAAA,CAAA,MAAQ;AAAA,MAER;AAAA,IACF;AAAA,EACF;AAEA,EAAA,IAAI,KAAA,CAAM,WAAW,CAAA,EAAG;AAKtB,IAAA,GAAA,CAAI,EAAA,EAAI,KAAA,GAAQ,CAAA,uCAAA,EAA0C,GAAG,CAAA,0BAAA,CAAuB,CAAA;AACpF,IAAA,OAAO,EAAE,UAAU,CAAA,EAAE;AAAA,EACvB;AAEA,EAAA,MAAM,MAAM,MAAM,UAAA,CAAW,GAAA,CAAI,GAAA,CAAI,OAAO,GAAG,CAAA;AAC/C,EAAA,MAAM,IAAA,GAAO,KAAA,CAAM,YAAA,CAAa,KAAA,EAAO,GAAG,GAAG,CAAA;AAC7C,EAAA,GAAA,CAAI,EAAA,EAAI,UAAU,CAAA,SAAA,EAAY,KAAA,CAAM,MAAM,CAAA,yBAAA,EAA4B,GAAG,CAAA,mBAAA,CAAA,EAAuB,EAAE,CAAA;AAClG,EAAA,GAAA,CAAI,EAAA,EAAI,OAAO,IAAI,CAAA;AACnB,EAAA,OAAO,EAAE,UAAU,CAAA,EAAE;AACvB;AAEA,eAAe,OAAA,CAAQ,KAAsB,GAAA,EAA+B;AAC1E,EAAA,MAAM,QAAQ,MAAM,GAAA,CAAI,GAAA,CAAI,KAAA,CAAM,KAAK,KAAA,EAAO,CAAC,OAAA,EAAS,QAAA,EAAU,SAAS,CAAA,EAAG,EAAE,GAAA,EAAK,YAAA,EAAc,OAAO,CAAA;AAC1G,EAAA,IAAI,CAAC,MAAM,EAAA,EAAI;AACb,IAAA,GAAA,CAAI,EAAA,EAAI,QAAQ,8EAAyE,CAAA;AACzF,IAAA,OAAO,KAAA;AAAA,EACT;AACA,EAAA,MAAM,IAAA,GAAO,MAAM,GAAA,CAAI,GAAA,CAAI,KAAA,CAAM,IAAA;AAAA,IAC/B,KAAA;AAAA,IACA,CAAC,MAAA,EAAQ,CAAA,eAAA,EAAkB,KAAA,CAAM,mBAAmB,CAAA,CAAE,CAAA;AAAA,IACtD,EAAE,GAAA,EAAK,YAAA,EAAc,KAAA;AAAM,GAC7B;AACA,EAAA,IAAI,CAAC,KAAK,EAAA,EAAI;AACZ,IAAA,GAAA,CAAI,EAAA,EAAI,QAAQ,+EAA0E,CAAA;AAC1F,IAAA,OAAO,KAAA;AAAA,EACT;AACA,EAAA,MAAM,MAAA,GAAS,IAAA,CAAK,GAAA,EAAK,KAAA,CAAM,mBAAmB,CAAA;AAClD,EAAA,SAAA,CAAU,QAAQ,MAAM,CAAA,EAAG,EAAE,SAAA,EAAW,MAAM,CAAA;AAC9C,EAAA,aAAA,CAAc,MAAA,EAAQ,KAAK,MAAM,CAAA;AACjC,EAAA,OAAO,IAAA;AACT;AAEA,IAAO,uBAAQ,aAAA,CAAwE;AAAA,EACrF,EAAA,EAAI,cAAA;AAAA,EACJ,WAAA,EAAa,yGAAA;AAAA,EAEb,OAAA,EAAS;AAAA,IACP,MAAM,OAAA,CAAQ,GAAA,EAAsB,KAAA,EAAiE;AACnG,MAAA,MAAM,EAAE,OAAM,GAAI,KAAA;AAClB,MAAA,MAAM,MAAA,GAAS,MAAM,SAAA,EAA0B;AAC/C,MAAA,MAAM,GAAA,GAAM,GAAA,CAAI,GAAA,IAAO,OAAA,CAAQ,GAAA,EAAI;AACnC,MAAA,MAAM,KAAA,GAAQ,IAAI,aAAA,CAAc,GAAA,EAAK,QAAQ,iBAAiB,CAAA;AAC9D,MAAA,MAAM,IAAA,GAAO,KAAA,CAAM,KAAA,IAAS,KAAA,CAAM,IAAA;AAKlC,MAAA,IAAI,MAAM,IAAA,EAAM;AACd,QAAA,MAAM,MAAA,GAAS,MAAM,OAAA,CAAQ,GAAA,EAAK,GAAG,CAAA;AACrC,QAAA,IAAI,CAAC,MAAA,EAAQ;AAAC,UAAA,OAAO,EAAE,UAAU,CAAA,EAAE;AAAA,QAAE;AAAA,MACvC;AAEA,MAAA,IAAI,MAAM,MAAA,EAAQ;AAChB,QAAA,OAAO,SAAA,CAAU,GAAA,EAAK,GAAA,EAAK,KAAA,EAAO,MAAM,MAAM,CAAA;AAAA,MAChD;AAEA,MAAA,MAAM,OAAA,GAAU,MAAM,mBAAA,EAAoB;AAC1C,MAAA,MAAM,MAAA,GAAS,MAAM,MAAA,IAAU,aAAA;AAE/B,MAAA,IAAI,MAAM,IAAA,EAAM;AACd,QAAA,MAAM,QAAA,GAAW,kBAAkB,OAAA,CAAQ,KAAA,CAAM,CAAC,MAAM,CAAA,EAAG,MAAM,IAAI,CAAA;AACrE,QAAA,IAAI,CAAC,QAAA,EAAU;AACb,UAAA,GAAA,CAAI,EAAA,EAAI,KAAA,GAAQ,CAAA,2BAAA,EAA8B,KAAA,CAAM,IAAI,CAAA,yDAAA,CAA2D,CAAA;AACnH,UAAA,OAAO,EAAE,UAAU,CAAA,EAAE;AAAA,QACvB;AACA,QAAA,IAAI,IAAA,EAAM;AACR,UAAA,GAAA,CAAI,EAAA,EAAI,OAAO,QAAQ,CAAA;AAAA,QACzB,CAAA,MAAO;AACL,UAAA,GAAA,CAAI,EAAA,EAAI,OAAA,GAAU,CAAA,eAAA,EAAkB,QAAA,CAAS,OAAO,CAAA,CAAA,EAAI;AAAA,YACtD,QAAA,EAAU;AAAA,cACR,EAAE,MAAA,EAAQ,SAAA,EAAW,KAAA,EAAO;AAAA,gBAC1B,CAAA,YAAA,EAAe,SAAS,UAAU,CAAA,CAAA;AAAA,gBAClC,WAAW,QAAA,CAAS,aAAA,CAAc,MAAM,CAAA,EAAA,EAAK,QAAA,CAAS,cAAc,KAAK,CAAA,CAAA;AAAA,gBACzE,CAAA,cAAA,EAAiB,QAAA,CAAS,YAAA,IAAgB,MAAM,CAAA;AAAA,eAClD,EAAE;AAAA,cACF,EAAE,MAAA,EAAQ,SAAA,EAAW,KAAA,EAAO,SAAS,OAAA,CAAQ,GAAA;AAAA,gBAC3C,CAAA,CAAA,KAAK,GAAG,CAAA,CAAE,SAAS,KAAK,CAAA,CAAE,SAAS,KAAK,CAAA,CAAE,MAAM,GAAG,CAAA,CAAE,aAAA,GAAgB,KAAK,CAAA,CAAE,aAAa,KAAK,CAAA,CAAE,YAAA,IAAgB,EAAE,CAAA,CAAA,CAAA,GAAM,EAAE,CAAA;AAAA,eAC5H;AAAE;AACJ,WACD,CAAA;AAAA,QACH;AACA,QAAA,OAAO,EAAE,UAAU,CAAA,EAAE;AAAA,MACvB;AAEA,MAAA,MAAM,QAAA,GAAW,iBAAA,CAAkB,OAAA,EAAS,MAAM,CAAA;AAClD,MAAA,IAAI,IAAA,EAAM;AACR,QAAA,GAAA,CAAI,EAAA,EAAI,OAAO,QAAQ,CAAA;AAAA,MACzB,CAAA,MAAO;AACL,QAAA,GAAA,CAAI,EAAA,EAAI,OAAA,GAAU,CAAA,yBAAA,EAA4B,QAAA,CAAS,YAAY,CAAA,MAAA,CAAA,EAAU;AAAA,UAC3E,QAAA,EAAU;AAAA,YACR,EAAE,MAAA,EAAQ,SAAA,EAAW,KAAA,EAAO;AAAA,cAC1B,CAAA,YAAA,EAAe,QAAA,CAAS,UAAU,CAAA,cAAA,EAAiB,SAAS,UAAU,CAAA,CAAA;AAAA,cACtE,CAAA,QAAA,EAAW,QAAA,CAAS,KAAA,CAAM,GAAA,CAAI,MAAM,CAAA,OAAA,EAAU,QAAA,CAAS,KAAA,CAAM,KAAA,CAAM,MAAM,CAAA,QAAA,EAAW,QAAA,CAAS,KAAA,CAAM,UAAU,MAAM,CAAA,UAAA;AAAA,aACrH,EAAE;AAAA,YACF,EAAE,MAAA,EAAQ,iBAAA,EAAmB,KAAA,EAAO,SAAS,GAAA,CAAI,GAAA;AAAA,cAC/C,CAAA,CAAA,KAAK,CAAA,EAAG,CAAA,CAAE,IAAI,CAAA,cAAA,EAAY,CAAA,CAAE,UAAU,CAAA,EAAA,EAAK,CAAA,CAAE,MAAM,CAAA,EAAA,EAAK,CAAA,CAAE,QAAQ,CAAA;AAAA,aACpE;AAAE;AACJ,SACD,CAAA;AAAA,MACH;AACA,MAAA,OAAO,EAAE,UAAU,CAAA,EAAE;AAAA,IACvB;AAAA;AAEJ,CAAC","file":"qa-e2e-flaky.js","sourcesContent":["import { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport {\n defineCommand,\n useConfig,\n type CLIInput,\n type PluginContextV3,\n} from '@kb-labs/sdk';\nimport {\n SnapshotStore,\n captureGit,\n analyzeFlakyCases,\n buildCaseTimeline,\n} from '@kb-labs/qa-core';\nimport { PATHS, TRENDS_WINDOW, type QAPluginConfig, type E2eCaseResult } from '@kb-labs/qa-contracts';\nimport type { QaE2eFlakyFlags } from './flags.js';\n\nasync function runIngest(\n ctx: PluginContextV3,\n cwd: string,\n store: SnapshotStore,\n dir: string,\n): Promise<{ exitCode: number }> {\n const cases: E2eCaseResult[] = [];\n if (existsSync(dir)) {\n for (const entry of readdirSync(dir, { withFileTypes: true })) {\n const file = entry.isDirectory()\n ? join(dir, entry.name, 'flaky-report.json')\n : entry.name === 'flaky-report.json' ? join(dir, entry.name) : null;\n if (!file || !existsSync(file)) {continue;}\n try {\n cases.push(...(JSON.parse(readFileSync(file, 'utf-8')) as E2eCaseResult[]));\n } catch {\n // A crashed/partial shard shouldn't block ingesting the rest.\n }\n }\n }\n\n if (cases.length === 0) {\n // No flaky-report.json files found under any shard — most likely every\n // shard failed before Playwright's reporter ever ran. Don't push an\n // empty snapshot into history; it would silently dilute the flip-rate\n // window with a run that carried no real signal.\n ctx.ui?.error?.(`No flaky-report.json files found under ${dir} — nothing to ingest.`);\n return { exitCode: 1 };\n }\n\n const git = await captureGit(ctx.api.shell, cwd);\n const snap = store.saveE2eFlaky(cases, 0, git);\n ctx.ui?.success?.(`Ingested ${cases.length} e2e case result(s) from ${dir} into flaky history`, {});\n ctx.ui?.json?.(snap);\n return { exitCode: 0 };\n}\n\nasync function runSync(ctx: PluginContextV3, cwd: string): Promise<boolean> {\n const fetch = await ctx.api.shell.exec('git', ['fetch', 'origin', 'ci-data'], { cwd, throwOnError: false });\n if (!fetch.ok) {\n ctx.ui?.error?.('No flaky history yet — the \"ci-data\" branch has not been created by CI.');\n return false;\n }\n const show = await ctx.api.shell.exec(\n 'git',\n ['show', `origin/ci-data:${PATHS.SNAPSHOTS_E2E_FLAKY}`],\n { cwd, throwOnError: false },\n );\n if (!show.ok) {\n ctx.ui?.error?.('No flaky history yet — \"ci-data\" branch exists but has no snapshot file.');\n return false;\n }\n const target = join(cwd, PATHS.SNAPSHOTS_E2E_FLAKY);\n mkdirSync(dirname(target), { recursive: true });\n writeFileSync(target, show.stdout);\n return true;\n}\n\nexport default defineCommand<unknown, CLIInput<QaE2eFlakyFlags>, { exitCode: number }>({\n id: 'qa:e2e-flaky',\n description: 'Track flaky e2e cases across CI runs — compact overview by default, per-case drill-down on request',\n\n handler: {\n async execute(ctx: PluginContextV3, input: CLIInput<QaE2eFlakyFlags>): Promise<{ exitCode: number }> {\n const { flags } = input;\n const config = await useConfig<QAPluginConfig>();\n const cwd = ctx.cwd ?? process.cwd();\n const store = new SnapshotStore(cwd, config?.historyMaxEntries);\n const json = flags.agent || flags.json;\n\n // --sync runs first so --ingest (if also passed) builds on the synced\n // history instead of silently ignoring --sync — the two compose rather\n // than one implicitly winning.\n if (flags.sync) {\n const synced = await runSync(ctx, cwd);\n if (!synced) {return { exitCode: 1 };}\n }\n\n if (flags.ingest) {\n return runIngest(ctx, cwd, store, flags.ingest);\n }\n\n const history = store.loadE2eFlakyHistory();\n const window = flags.window ?? TRENDS_WINDOW;\n\n if (flags.case) {\n const timeline = buildCaseTimeline(history.slice(-window), flags.case);\n if (!timeline) {\n ctx.ui?.error?.(`No history found for case \"${flags.case}\". Run with --agent to see the \"top\" list of known cases.`);\n return { exitCode: 1 };\n }\n if (json) {\n ctx.ui?.json?.(timeline);\n } else {\n ctx.ui?.success?.(`Case timeline: ${timeline.caseKey}`, {\n sections: [\n { header: 'Summary', items: [\n `flakyScore: ${timeline.flakyScore}`,\n `streak: ${timeline.currentStreak.status} x${timeline.currentStreak.count}`,\n `firstFailure: ${timeline.firstFailure ?? 'none'}`,\n ] },\n { header: 'History', items: timeline.history.map(\n h => `${h.timestamp} [${h.gitCommit}] ${h.status}${h.errorCategory ? ` (${h.errorCategory}: ${h.errorMessage ?? ''})` : ''}`,\n ) },\n ],\n });\n }\n return { exitCode: 0 };\n }\n\n const overview = analyzeFlakyCases(history, window);\n if (json) {\n ctx.ui?.json?.(overview);\n } else {\n ctx.ui?.success?.(`E2E flaky overview (last ${overview.runsAnalyzed} runs)`, {\n sections: [\n { header: 'Summary', items: [\n `totalCases: ${overview.totalCases}, flakyCases: ${overview.flakyCases}`,\n `delta: +${overview.delta.new.length} new, -${overview.delta.fixed.length} fixed, ${overview.delta.unchanged.length} unchanged`,\n ] },\n { header: 'Top flaky cases', items: overview.top.map(\n t => `${t.case} — score ${t.flakyScore}, ${t.streak}, ${t.category}`,\n ) },\n ],\n });\n }\n return { exitCode: 0 };\n },\n },\n});\n"]}
1
+ {"version":3,"sources":["../../../src/cli/commands/qa-e2e-flaky.ts"],"names":[],"mappings":"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","file":"qa-e2e-flaky.js","sourcesContent":["import { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport {\n defineCommand,\n useConfig,\n type CLIInput,\n type PluginContextV3,\n type CommandResult,\n} from '@kb-labs/sdk';\nimport {\n SnapshotStore,\n captureGit,\n analyzeFlakyCases,\n buildCaseTimeline,\n} from '@kb-labs/qa-core';\nimport { PATHS, TRENDS_WINDOW, type QAPluginConfig, type E2eCaseResult } from '@kb-labs/qa-contracts';\nimport type { QaE2eFlakyFlags } from './flags.js';\n\nasync function runIngest(\n ctx: PluginContextV3,\n cwd: string,\n store: SnapshotStore,\n dir: string,\n): Promise<CommandResult> {\n const cases: E2eCaseResult[] = [];\n if (existsSync(dir)) {\n for (const entry of readdirSync(dir, { withFileTypes: true })) {\n const file = entry.isDirectory()\n ? join(dir, entry.name, 'flaky-report.json')\n : entry.name === 'flaky-report.json' ? join(dir, entry.name) : null;\n if (!file || !existsSync(file)) {continue;}\n try {\n cases.push(...(JSON.parse(readFileSync(file, 'utf-8')) as E2eCaseResult[]));\n } catch {\n // A crashed/partial shard shouldn't block ingesting the rest.\n }\n }\n }\n\n if (cases.length === 0) {\n // No flaky-report.json files found under any shard — most likely every\n // shard failed before Playwright's reporter ever ran. Don't push an\n // empty snapshot into history; it would silently dilute the flip-rate\n // window with a run that carried no real signal.\n ctx.ui?.error?.(`No flaky-report.json files found under ${dir} — nothing to ingest.`);\n return { ok: false, error: 'Command failed' };\n }\n\n const git = await captureGit(ctx.api.shell, cwd);\n const snap = store.saveE2eFlaky(cases, 0, git);\n ctx.ui?.success?.(`Ingested ${cases.length} e2e case result(s) from ${dir} into flaky history`, {});\n ctx.ui?.json?.(snap);\n return { ok: true };\n}\n\nasync function runSync(ctx: PluginContextV3, cwd: string): Promise<boolean> {\n const fetch = await ctx.api.shell.exec('git', ['fetch', 'origin', 'ci-data'], { cwd, throwOnError: false });\n if (!fetch.ok) {\n ctx.ui?.error?.('No flaky history yet — the \"ci-data\" branch has not been created by CI.');\n return false;\n }\n const show = await ctx.api.shell.exec(\n 'git',\n ['show', `origin/ci-data:${PATHS.SNAPSHOTS_E2E_FLAKY}`],\n { cwd, throwOnError: false },\n );\n if (!show.ok) {\n ctx.ui?.error?.('No flaky history yet — \"ci-data\" branch exists but has no snapshot file.');\n return false;\n }\n const target = join(cwd, PATHS.SNAPSHOTS_E2E_FLAKY);\n mkdirSync(dirname(target), { recursive: true });\n writeFileSync(target, show.stdout);\n return true;\n}\n\nexport default defineCommand<unknown, CLIInput<QaE2eFlakyFlags>, unknown>({\n id: 'qa:e2e-flaky',\n description: 'Track flaky e2e cases across CI runs — compact overview by default, per-case drill-down on request',\n\n handler: {\n async execute(ctx: PluginContextV3, input: CLIInput<QaE2eFlakyFlags>): Promise<CommandResult> {\n const { flags } = input;\n const config = await useConfig<QAPluginConfig>();\n const cwd = ctx.cwd ?? process.cwd();\n const store = new SnapshotStore(cwd, config?.historyMaxEntries);\n const json = flags.agent || flags.json;\n\n // --sync runs first so --ingest (if also passed) builds on the synced\n // history instead of silently ignoring --sync — the two compose rather\n // than one implicitly winning.\n if (flags.sync) {\n const synced = await runSync(ctx, cwd);\n if (!synced) {return { ok: false, error: 'Command failed' };}\n }\n\n if (flags.ingest) {\n return runIngest(ctx, cwd, store, flags.ingest);\n }\n\n const history = store.loadE2eFlakyHistory();\n const window = flags.window ?? TRENDS_WINDOW;\n\n if (flags.case) {\n const timeline = buildCaseTimeline(history.slice(-window), flags.case);\n if (!timeline) {\n ctx.ui?.error?.(`No history found for case \"${flags.case}\". Run with --agent to see the \"top\" list of known cases.`);\n return { ok: false, error: 'Command failed' };\n }\n if (json) {\n ctx.ui?.json?.(timeline);\n } else {\n ctx.ui?.success?.(`Case timeline: ${timeline.caseKey}`, {\n sections: [\n { header: 'Summary', items: [\n `flakyScore: ${timeline.flakyScore}`,\n `streak: ${timeline.currentStreak.status} x${timeline.currentStreak.count}`,\n `firstFailure: ${timeline.firstFailure ?? 'none'}`,\n ] },\n { header: 'History', items: timeline.history.map(\n h => `${h.timestamp} [${h.gitCommit}] ${h.status}${h.errorCategory ? ` (${h.errorCategory}: ${h.errorMessage ?? ''})` : ''}`,\n ) },\n ],\n });\n }\n return { ok: true };\n }\n\n const overview = analyzeFlakyCases(history, window);\n if (json) {\n ctx.ui?.json?.(overview);\n } else {\n ctx.ui?.success?.(`E2E flaky overview (last ${overview.runsAnalyzed} runs)`, {\n sections: [\n { header: 'Summary', items: [\n `totalCases: ${overview.totalCases}, flakyCases: ${overview.flakyCases}`,\n `delta: +${overview.delta.new.length} new, -${overview.delta.fixed.length} fixed, ${overview.delta.unchanged.length} unchanged`,\n ] },\n { header: 'Top flaky cases', items: overview.top.map(\n t => `${t.case} — score ${t.flakyScore}, ${t.streak}, ${t.category}`,\n ) },\n ],\n });\n }\n return { ok: true };\n },\n },\n});\n"]}
@@ -12,8 +12,6 @@ declare const _default: _kb_labs_shared_command_kit.CommandHandlerV3<unknown, CL
12
12
  description: string;
13
13
  default: false;
14
14
  };
15
- }>>, {
16
- exitCode: number;
17
- }>;
15
+ }>>, unknown>;
18
16
 
19
17
  export { _default as default };
@@ -26,7 +26,7 @@ var qa_gate_default = defineCommand({
26
26
  const items = raw.violations.map((v) => `[${v.severity}] ${v.package} ${v.check}: ${v.message}`);
27
27
  ctx.ui?.error?.("Gate failed", { sections: [{ header: "Violations", items }] });
28
28
  }
29
- return { exitCode: raw.ok ? 0 : 1 };
29
+ return raw.ok ? { ok: true, result: raw } : { ok: false, error: "QA gate failed", result: raw };
30
30
  }
31
31
  }
32
32
  });
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/cli/commands/qa-gate.ts"],"names":[],"mappings":";;;;AAeA,IAAO,kBAAQ,aAAA,CAAoE;AAAA,EACjF,EAAA,EAAI,SAAA;AAAA,EACJ,WAAA,EAAa,yDAAA;AAAA,EAEb,OAAA,EAAS;AAAA,IACP,MAAM,OAAA,CAAQ,GAAA,EAAsB,KAAA,EAA6D;AAC/F,MAAA,MAAM,EAAE,OAAM,GAAI,KAAA;AAClB,MAAA,MAAM,MAAA,GAAS,MAAM,SAAA,EAA0B;AAC/C,MAAA,MAAM,GAAA,GAAM,GAAA,CAAI,GAAA,IAAO,OAAA,CAAQ,GAAA,EAAI;AAEnC,MAAA,MAAM,UAAA,GAAa,gBAAA,CAAiB,GAAA,EAAK,MAAA,EAAQ,UAAU,CAAA;AAC3D,MAAA,MAAM,OAAA,GAAU,IAAI,aAAA,CAAc,EAAE,UAAA,EAAY,KAAK,KAAA,EAAO,GAAA,CAAI,GAAA,CAAI,KAAA,EAAO,CAAA;AAC3E,MAAA,MAAM,KAAA,GAAQ,IAAI,aAAA,CAAc,GAAA,EAAK,QAAQ,iBAAiB,CAAA;AAE9D,MAAA,MAAM,MAAM,MAAM,UAAA,CAAW,GAAA,CAAI,GAAA,CAAI,OAAO,GAAG,CAAA;AAE/C,MAAA,MAAM,KAAA,GAAQ,KAAK,GAAA,EAAI;AACvB,MAAA,MAAM,GAAA,GAAM,MAAM,OAAA,CAAQ,IAAA,EAAK;AAC/B,MAAA,MAAM,UAAA,GAAa,IAAA,CAAK,GAAA,EAAI,GAAI,KAAA;AAEhC,MAAA,IAAI,MAAM,IAAA,EAAM,KAAA,CAAM,QAAA,CAAS,GAAA,EAAK,YAAY,GAAG,CAAA;AAEnD,MAAA,IAAI,MAAM,IAAA,EAAM;AACd,QAAA,GAAA,CAAI,EAAA,EAAI,OAAO,GAAG,CAAA;AAAA,MACpB,CAAA,MAAA,IAAW,IAAI,EAAA,EAAI;AACjB,QAAA,GAAA,CAAI,EAAA,EAAI,OAAA,GAAU,CAAA,aAAA,EAAgB,GAAA,CAAI,YAAY,CAAA,+BAAA,CAAiC,CAAA;AAAA,MACrF,CAAA,MAAO;AACL,QAAA,MAAM,QAAQ,GAAA,CAAI,UAAA,CAAW,GAAA,CAAI,CAAA,CAAA,KAAK,IAAI,CAAA,CAAE,QAAQ,CAAA,EAAA,EAAK,CAAA,CAAE,OAAO,CAAA,EAAA,EAAK,CAAA,CAAE,KAAK,CAAA,EAAA,EAAK,CAAA,CAAE,OAAO,CAAA,CAAE,CAAA;AAC9F,QAAA,GAAA,CAAI,EAAA,EAAI,KAAA,GAAQ,aAAA,EAAe,EAAE,QAAA,EAAU,CAAC,EAAE,MAAA,EAAQ,YAAA,EAAc,KAAA,EAAO,CAAA,EAAG,CAAA;AAAA,MAChF;AAEA,MAAA,OAAO,EAAE,QAAA,EAAU,GAAA,CAAI,EAAA,GAAK,IAAI,CAAA,EAAE;AAAA,IACpC;AAAA;AAEJ,CAAC","file":"qa-gate.js","sourcesContent":["import {\n defineCommand,\n useConfig,\n type CLIInput,\n type PluginContextV3,\n} from '@kb-labs/sdk';\nimport {\n DevkitAdapter,\n SnapshotStore,\n resolveDevkitBin,\n captureGit,\n} from '@kb-labs/qa-core';\nimport { type QAPluginConfig } from '@kb-labs/qa-contracts';\nimport type { QaGateFlags } from './flags.js';\n\nexport default defineCommand<unknown, CLIInput<QaGateFlags>, { exitCode: number }>({\n id: 'qa:gate',\n description: 'Run pre-commit gate check (exits 1 if violations found)',\n\n handler: {\n async execute(ctx: PluginContextV3, input: CLIInput<QaGateFlags>): Promise<{ exitCode: number }> {\n const { flags } = input;\n const config = await useConfig<QAPluginConfig>();\n const cwd = ctx.cwd ?? process.cwd();\n\n const binaryPath = resolveDevkitBin(cwd, config?.devkitPath);\n const adapter = new DevkitAdapter({ binaryPath, cwd, shell: ctx.api.shell });\n const store = new SnapshotStore(cwd, config?.historyMaxEntries);\n\n const git = await captureGit(ctx.api.shell, cwd);\n\n const start = Date.now();\n const raw = await adapter.gate();\n const durationMs = Date.now() - start;\n\n if (flags.save) store.saveGate(raw, durationMs, git);\n\n if (flags.json) {\n ctx.ui?.json?.(raw);\n } else if (raw.ok) {\n ctx.ui?.success?.(`Gate passed. ${raw.staged_files} staged file(s), no violations.`);\n } else {\n const items = raw.violations.map(v => `[${v.severity}] ${v.package} ${v.check}: ${v.message}`);\n ctx.ui?.error?.('Gate failed', { sections: [{ header: 'Violations', items }] });\n }\n\n return { exitCode: raw.ok ? 0 : 1 };\n },\n },\n});\n"]}
1
+ {"version":3,"sources":["../../../src/cli/commands/qa-gate.ts"],"names":[],"mappings":";;;;AAgBA,IAAO,kBAAQ,aAAA,CAAuD;AAAA,EACpE,EAAA,EAAI,SAAA;AAAA,EACJ,WAAA,EAAa,yDAAA;AAAA,EAEb,OAAA,EAAS;AAAA,IACP,MAAM,OAAA,CAAQ,GAAA,EAAsB,KAAA,EAAsD;AACxF,MAAA,MAAM,EAAE,OAAM,GAAI,KAAA;AAClB,MAAA,MAAM,MAAA,GAAS,MAAM,SAAA,EAA0B;AAC/C,MAAA,MAAM,GAAA,GAAM,GAAA,CAAI,GAAA,IAAO,OAAA,CAAQ,GAAA,EAAI;AAEnC,MAAA,MAAM,UAAA,GAAa,gBAAA,CAAiB,GAAA,EAAK,MAAA,EAAQ,UAAU,CAAA;AAC3D,MAAA,MAAM,OAAA,GAAU,IAAI,aAAA,CAAc,EAAE,UAAA,EAAY,KAAK,KAAA,EAAO,GAAA,CAAI,GAAA,CAAI,KAAA,EAAO,CAAA;AAC3E,MAAA,MAAM,KAAA,GAAQ,IAAI,aAAA,CAAc,GAAA,EAAK,QAAQ,iBAAiB,CAAA;AAE9D,MAAA,MAAM,MAAM,MAAM,UAAA,CAAW,GAAA,CAAI,GAAA,CAAI,OAAO,GAAG,CAAA;AAE/C,MAAA,MAAM,KAAA,GAAQ,KAAK,GAAA,EAAI;AACvB,MAAA,MAAM,GAAA,GAAM,MAAM,OAAA,CAAQ,IAAA,EAAK;AAC/B,MAAA,MAAM,UAAA,GAAa,IAAA,CAAK,GAAA,EAAI,GAAI,KAAA;AAEhC,MAAA,IAAI,MAAM,IAAA,EAAM,KAAA,CAAM,QAAA,CAAS,GAAA,EAAK,YAAY,GAAG,CAAA;AAEnD,MAAA,IAAI,MAAM,IAAA,EAAM;AACd,QAAA,GAAA,CAAI,EAAA,EAAI,OAAO,GAAG,CAAA;AAAA,MACpB,CAAA,MAAA,IAAW,IAAI,EAAA,EAAI;AACjB,QAAA,GAAA,CAAI,EAAA,EAAI,OAAA,GAAU,CAAA,aAAA,EAAgB,GAAA,CAAI,YAAY,CAAA,+BAAA,CAAiC,CAAA;AAAA,MACrF,CAAA,MAAO;AACL,QAAA,MAAM,QAAQ,GAAA,CAAI,UAAA,CAAW,GAAA,CAAI,CAAA,CAAA,KAAK,IAAI,CAAA,CAAE,QAAQ,CAAA,EAAA,EAAK,CAAA,CAAE,OAAO,CAAA,EAAA,EAAK,CAAA,CAAE,KAAK,CAAA,EAAA,EAAK,CAAA,CAAE,OAAO,CAAA,CAAE,CAAA;AAC9F,QAAA,GAAA,CAAI,EAAA,EAAI,KAAA,GAAQ,aAAA,EAAe,EAAE,QAAA,EAAU,CAAC,EAAE,MAAA,EAAQ,YAAA,EAAc,KAAA,EAAO,CAAA,EAAG,CAAA;AAAA,MAChF;AAEA,MAAA,OAAO,GAAA,CAAI,EAAA,GAAK,EAAE,EAAA,EAAI,MAAM,MAAA,EAAQ,GAAA,EAAI,GAAI,EAAE,EAAA,EAAI,KAAA,EAAO,KAAA,EAAO,gBAAA,EAAkB,QAAQ,GAAA,EAAI;AAAA,IAChG;AAAA;AAEJ,CAAC","file":"qa-gate.js","sourcesContent":["import {\n defineCommand,\n useConfig,\n type CLIInput,\n type PluginContextV3,\n type CommandResult,\n} from '@kb-labs/sdk';\nimport {\n DevkitAdapter,\n SnapshotStore,\n resolveDevkitBin,\n captureGit,\n} from '@kb-labs/qa-core';\nimport { type QAPluginConfig } from '@kb-labs/qa-contracts';\nimport type { QaGateFlags } from './flags.js';\n\nexport default defineCommand<unknown, CLIInput<QaGateFlags>, unknown>({\n id: 'qa:gate',\n description: 'Run pre-commit gate check (exits 1 if violations found)',\n\n handler: {\n async execute(ctx: PluginContextV3, input: CLIInput<QaGateFlags>): Promise<CommandResult> {\n const { flags } = input;\n const config = await useConfig<QAPluginConfig>();\n const cwd = ctx.cwd ?? process.cwd();\n\n const binaryPath = resolveDevkitBin(cwd, config?.devkitPath);\n const adapter = new DevkitAdapter({ binaryPath, cwd, shell: ctx.api.shell });\n const store = new SnapshotStore(cwd, config?.historyMaxEntries);\n\n const git = await captureGit(ctx.api.shell, cwd);\n\n const start = Date.now();\n const raw = await adapter.gate();\n const durationMs = Date.now() - start;\n\n if (flags.save) store.saveGate(raw, durationMs, git);\n\n if (flags.json) {\n ctx.ui?.json?.(raw);\n } else if (raw.ok) {\n ctx.ui?.success?.(`Gate passed. ${raw.staged_files} staged file(s), no violations.`);\n } else {\n const items = raw.violations.map(v => `[${v.severity}] ${v.package} ${v.check}: ${v.message}`);\n ctx.ui?.error?.('Gate failed', { sections: [{ header: 'Violations', items }] });\n }\n\n return raw.ok ? { ok: true, result: raw } : { ok: false, error: 'QA gate failed', result: raw };\n },\n },\n});\n"]}
@@ -12,8 +12,6 @@ declare const _default: _kb_labs_shared_command_kit.CommandHandlerV3<unknown, CL
12
12
  description: string;
13
13
  default: false;
14
14
  };
15
- }>>, {
16
- exitCode: number;
17
- }>;
15
+ }>>, unknown>;
18
16
 
19
17
  export { _default as default };
@@ -20,7 +20,7 @@ var qa_history_default = defineCommand({
20
20
  ctx.ui?.success?.(`${section.header}`, { sections: [{ items: section.lines }] });
21
21
  }
22
22
  }
23
- return { exitCode: 0 };
23
+ return { ok: true };
24
24
  }
25
25
  }
26
26
  });
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/cli/commands/qa-history.ts"],"names":[],"mappings":";;;;AAaA,IAAO,qBAAQ,aAAA,CAAuE;AAAA,EACpF,EAAA,EAAI,YAAA;AAAA,EACJ,WAAA,EAAa,qBAAA;AAAA,EAEb,OAAA,EAAS;AAAA,IACP,MAAM,OAAA,CAAQ,GAAA,EAAsB,KAAA,EAAgE;AAClG,MAAA,MAAM,EAAE,OAAM,GAAI,KAAA;AAClB,MAAA,MAAM,MAAA,GAAS,MAAM,SAAA,EAA0B;AAC/C,MAAA,MAAM,GAAA,GAAM,GAAA,CAAI,GAAA,IAAO,OAAA,CAAQ,GAAA,EAAI;AAEnC,MAAA,MAAM,KAAA,GAAQ,IAAI,aAAA,CAAc,GAAA,EAAK,QAAQ,iBAAiB,CAAA;AAC9D,MAAA,MAAM,KAAA,GAAQ,MAAM,KAAA,IAAS,EAAA;AAC7B,MAAA,MAAM,OAAA,GAAU,MAAM,cAAA,EAAe;AAErC,MAAA,IAAI,MAAM,IAAA,EAAM;AACd,QAAA,GAAA,CAAI,EAAA,EAAI,IAAA,GAAO,CAAC,GAAG,OAAO,CAAA,CAAE,OAAA,EAAQ,CAAE,KAAA,CAAM,CAAA,EAAG,KAAK,CAAC,CAAA;AAAA,MACvD,CAAA,MAAO;AACL,QAAA,KAAA,MAAW,OAAA,IAAW,iBAAA,CAAkB,OAAA,EAAS,KAAK,CAAA,EAAG;AACvD,UAAA,GAAA,CAAI,EAAA,EAAI,OAAA,GAAU,CAAA,EAAG,OAAA,CAAQ,MAAM,CAAA,CAAA,EAAI,EAAE,QAAA,EAAU,CAAC,EAAE,KAAA,EAAO,OAAA,CAAQ,KAAA,EAAO,GAAG,CAAA;AAAA,QACjF;AAAA,MACF;AAEA,MAAA,OAAO,EAAE,UAAU,CAAA,EAAE;AAAA,IACvB;AAAA;AAEJ,CAAC","file":"qa-history.js","sourcesContent":["import {\n defineCommand,\n useConfig,\n type CLIInput,\n type PluginContextV3,\n} from '@kb-labs/sdk';\nimport {\n SnapshotStore,\n buildHistoryTable,\n} from '@kb-labs/qa-core';\nimport { type QAPluginConfig } from '@kb-labs/qa-contracts';\nimport type { QaHistoryFlags } from './flags.js';\n\nexport default defineCommand<unknown, CLIInput<QaHistoryFlags>, { exitCode: number }>({\n id: 'qa:history',\n description: 'Show QA run history',\n\n handler: {\n async execute(ctx: PluginContextV3, input: CLIInput<QaHistoryFlags>): Promise<{ exitCode: number }> {\n const { flags } = input;\n const config = await useConfig<QAPluginConfig>();\n const cwd = ctx.cwd ?? process.cwd();\n\n const store = new SnapshotStore(cwd, config?.historyMaxEntries);\n const limit = flags.limit ?? 20;\n const history = store.loadRunHistory();\n\n if (flags.json) {\n ctx.ui?.json?.([...history].reverse().slice(0, limit));\n } else {\n for (const section of buildHistoryTable(history, limit)) {\n ctx.ui?.success?.(`${section.header}`, { sections: [{ items: section.lines }] });\n }\n }\n\n return { exitCode: 0 };\n },\n },\n});\n"]}
1
+ {"version":3,"sources":["../../../src/cli/commands/qa-history.ts"],"names":[],"mappings":";;;;AAcA,IAAO,qBAAQ,aAAA,CAA0D;AAAA,EACvE,EAAA,EAAI,YAAA;AAAA,EACJ,WAAA,EAAa,qBAAA;AAAA,EAEb,OAAA,EAAS;AAAA,IACP,MAAM,OAAA,CAAQ,GAAA,EAAsB,KAAA,EAAyD;AAC3F,MAAA,MAAM,EAAE,OAAM,GAAI,KAAA;AAClB,MAAA,MAAM,MAAA,GAAS,MAAM,SAAA,EAA0B;AAC/C,MAAA,MAAM,GAAA,GAAM,GAAA,CAAI,GAAA,IAAO,OAAA,CAAQ,GAAA,EAAI;AAEnC,MAAA,MAAM,KAAA,GAAQ,IAAI,aAAA,CAAc,GAAA,EAAK,QAAQ,iBAAiB,CAAA;AAC9D,MAAA,MAAM,KAAA,GAAQ,MAAM,KAAA,IAAS,EAAA;AAC7B,MAAA,MAAM,OAAA,GAAU,MAAM,cAAA,EAAe;AAErC,MAAA,IAAI,MAAM,IAAA,EAAM;AACd,QAAA,GAAA,CAAI,EAAA,EAAI,IAAA,GAAO,CAAC,GAAG,OAAO,CAAA,CAAE,OAAA,EAAQ,CAAE,KAAA,CAAM,CAAA,EAAG,KAAK,CAAC,CAAA;AAAA,MACvD,CAAA,MAAO;AACL,QAAA,KAAA,MAAW,OAAA,IAAW,iBAAA,CAAkB,OAAA,EAAS,KAAK,CAAA,EAAG;AACvD,UAAA,GAAA,CAAI,EAAA,EAAI,OAAA,GAAU,CAAA,EAAG,OAAA,CAAQ,MAAM,CAAA,CAAA,EAAI,EAAE,QAAA,EAAU,CAAC,EAAE,KAAA,EAAO,OAAA,CAAQ,KAAA,EAAO,GAAG,CAAA;AAAA,QACjF;AAAA,MACF;AAEA,MAAA,OAAO,EAAE,IAAI,IAAA,EAAK;AAAA,IACpB;AAAA;AAEJ,CAAC","file":"qa-history.js","sourcesContent":["import {\n defineCommand,\n useConfig,\n type CLIInput,\n type PluginContextV3,\n type CommandResult,\n} from '@kb-labs/sdk';\nimport {\n SnapshotStore,\n buildHistoryTable,\n} from '@kb-labs/qa-core';\nimport { type QAPluginConfig } from '@kb-labs/qa-contracts';\nimport type { QaHistoryFlags } from './flags.js';\n\nexport default defineCommand<unknown, CLIInput<QaHistoryFlags>, unknown>({\n id: 'qa:history',\n description: 'Show QA run history',\n\n handler: {\n async execute(ctx: PluginContextV3, input: CLIInput<QaHistoryFlags>): Promise<CommandResult> {\n const { flags } = input;\n const config = await useConfig<QAPluginConfig>();\n const cwd = ctx.cwd ?? process.cwd();\n\n const store = new SnapshotStore(cwd, config?.historyMaxEntries);\n const limit = flags.limit ?? 20;\n const history = store.loadRunHistory();\n\n if (flags.json) {\n ctx.ui?.json?.([...history].reverse().slice(0, limit));\n } else {\n for (const section of buildHistoryTable(history, limit)) {\n ctx.ui?.success?.(`${section.header}`, { sections: [{ items: section.lines }] });\n }\n }\n\n return { ok: true };\n },\n },\n});\n"]}
@@ -7,8 +7,6 @@ declare const _default: _kb_labs_shared_command_kit.CommandHandlerV3<unknown, CL
7
7
  description: string;
8
8
  default: false;
9
9
  };
10
- }>>, {
11
- exitCode: number;
12
- }>;
10
+ }>>, unknown>;
13
11
 
14
12
  export { _default as default };
@@ -20,7 +20,7 @@ var qa_regressions_default = defineCommand({
20
20
  ctx.ui?.success?.(`${section.header}`, { sections: [{ items: section.lines }] });
21
21
  }
22
22
  }
23
- return { exitCode: detection.hasRegressions ? 1 : 0 };
23
+ return detection.hasRegressions ? { ok: false, error: "Regressions found", result: detection } : { ok: true, result: detection };
24
24
  }
25
25
  }
26
26
  });
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/cli/commands/qa-regressions.ts"],"names":[],"mappings":";;;;AAcA,IAAO,yBAAQ,aAAA,CAA2E;AAAA,EACxF,EAAA,EAAI,gBAAA;AAAA,EACJ,WAAA,EAAa,mCAAA;AAAA,EAEb,OAAA,EAAS;AAAA,IACP,MAAM,OAAA,CAAQ,GAAA,EAAsB,KAAA,EAAoE;AACtG,MAAA,MAAM,EAAE,OAAM,GAAI,KAAA;AAClB,MAAA,MAAM,MAAA,GAAS,MAAM,SAAA,EAA0B;AAC/C,MAAA,MAAM,GAAA,GAAM,GAAA,CAAI,GAAA,IAAO,OAAA,CAAQ,GAAA,EAAI;AAEnC,MAAA,MAAM,KAAA,GAAQ,IAAI,aAAA,CAAc,GAAA,EAAK,QAAQ,iBAAiB,CAAA;AAC9D,MAAA,MAAM,OAAA,GAAU,MAAM,cAAA,EAAe;AACrC,MAAA,MAAM,SAAA,GAAY,kBAAkB,OAAO,CAAA;AAE3C,MAAA,IAAI,MAAM,IAAA,EAAM;AACd,QAAA,GAAA,CAAI,EAAA,EAAI,OAAO,SAAS,CAAA;AAAA,MAC1B,CAAA,MAAO;AACL,QAAA,KAAA,MAAW,OAAA,IAAW,sBAAA,CAAuB,SAAS,CAAA,EAAG;AACvD,UAAA,GAAA,CAAI,EAAA,EAAI,OAAA,GAAU,CAAA,EAAG,OAAA,CAAQ,MAAM,CAAA,CAAA,EAAI,EAAE,QAAA,EAAU,CAAC,EAAE,KAAA,EAAO,OAAA,CAAQ,KAAA,EAAO,GAAG,CAAA;AAAA,QACjF;AAAA,MACF;AAEA,MAAA,OAAO,EAAE,QAAA,EAAU,SAAA,CAAU,cAAA,GAAiB,IAAI,CAAA,EAAE;AAAA,IACtD;AAAA;AAEJ,CAAC","file":"qa-regressions.js","sourcesContent":["import {\n defineCommand,\n useConfig,\n type CLIInput,\n type PluginContextV3,\n} from '@kb-labs/sdk';\nimport {\n SnapshotStore,\n detectRegressions,\n buildRegressionsReport,\n} from '@kb-labs/qa-core';\nimport { type QAPluginConfig } from '@kb-labs/qa-contracts';\nimport type { QaRegressionsFlags } from './flags.js';\n\nexport default defineCommand<unknown, CLIInput<QaRegressionsFlags>, { exitCode: number }>({\n id: 'qa:regressions',\n description: 'Detect regressions since last run',\n\n handler: {\n async execute(ctx: PluginContextV3, input: CLIInput<QaRegressionsFlags>): Promise<{ exitCode: number }> {\n const { flags } = input;\n const config = await useConfig<QAPluginConfig>();\n const cwd = ctx.cwd ?? process.cwd();\n\n const store = new SnapshotStore(cwd, config?.historyMaxEntries);\n const history = store.loadRunHistory();\n const detection = detectRegressions(history);\n\n if (flags.json) {\n ctx.ui?.json?.(detection);\n } else {\n for (const section of buildRegressionsReport(detection)) {\n ctx.ui?.success?.(`${section.header}`, { sections: [{ items: section.lines }] });\n }\n }\n\n return { exitCode: detection.hasRegressions ? 1 : 0 };\n },\n },\n});\n"]}
1
+ {"version":3,"sources":["../../../src/cli/commands/qa-regressions.ts"],"names":[],"mappings":";;;;AAeA,IAAO,yBAAQ,aAAA,CAA8D;AAAA,EAC3E,EAAA,EAAI,gBAAA;AAAA,EACJ,WAAA,EAAa,mCAAA;AAAA,EAEb,OAAA,EAAS;AAAA,IACP,MAAM,OAAA,CAAQ,GAAA,EAAsB,KAAA,EAA6D;AAC/F,MAAA,MAAM,EAAE,OAAM,GAAI,KAAA;AAClB,MAAA,MAAM,MAAA,GAAS,MAAM,SAAA,EAA0B;AAC/C,MAAA,MAAM,GAAA,GAAM,GAAA,CAAI,GAAA,IAAO,OAAA,CAAQ,GAAA,EAAI;AAEnC,MAAA,MAAM,KAAA,GAAQ,IAAI,aAAA,CAAc,GAAA,EAAK,QAAQ,iBAAiB,CAAA;AAC9D,MAAA,MAAM,OAAA,GAAU,MAAM,cAAA,EAAe;AACrC,MAAA,MAAM,SAAA,GAAY,kBAAkB,OAAO,CAAA;AAE3C,MAAA,IAAI,MAAM,IAAA,EAAM;AACd,QAAA,GAAA,CAAI,EAAA,EAAI,OAAO,SAAS,CAAA;AAAA,MAC1B,CAAA,MAAO;AACL,QAAA,KAAA,MAAW,OAAA,IAAW,sBAAA,CAAuB,SAAS,CAAA,EAAG;AACvD,UAAA,GAAA,CAAI,EAAA,EAAI,OAAA,GAAU,CAAA,EAAG,OAAA,CAAQ,MAAM,CAAA,CAAA,EAAI,EAAE,QAAA,EAAU,CAAC,EAAE,KAAA,EAAO,OAAA,CAAQ,KAAA,EAAO,GAAG,CAAA;AAAA,QACjF;AAAA,MACF;AAEA,MAAA,OAAO,SAAA,CAAU,cAAA,GACb,EAAE,EAAA,EAAI,OAAO,KAAA,EAAO,mBAAA,EAAqB,MAAA,EAAQ,SAAA,EAAU,GAC3D,EAAE,EAAA,EAAI,IAAA,EAAM,QAAQ,SAAA,EAAU;AAAA,IACpC;AAAA;AAEJ,CAAC","file":"qa-regressions.js","sourcesContent":["import {\n defineCommand,\n useConfig,\n type CLIInput,\n type PluginContextV3,\n type CommandResult,\n} from '@kb-labs/sdk';\nimport {\n SnapshotStore,\n detectRegressions,\n buildRegressionsReport,\n} from '@kb-labs/qa-core';\nimport { type QAPluginConfig } from '@kb-labs/qa-contracts';\nimport type { QaRegressionsFlags } from './flags.js';\n\nexport default defineCommand<unknown, CLIInput<QaRegressionsFlags>, unknown>({\n id: 'qa:regressions',\n description: 'Detect regressions since last run',\n\n handler: {\n async execute(ctx: PluginContextV3, input: CLIInput<QaRegressionsFlags>): Promise<CommandResult> {\n const { flags } = input;\n const config = await useConfig<QAPluginConfig>();\n const cwd = ctx.cwd ?? process.cwd();\n\n const store = new SnapshotStore(cwd, config?.historyMaxEntries);\n const history = store.loadRunHistory();\n const detection = detectRegressions(history);\n\n if (flags.json) {\n ctx.ui?.json?.(detection);\n } else {\n for (const section of buildRegressionsReport(detection)) {\n ctx.ui?.success?.(`${section.header}`, { sections: [{ items: section.lines }] });\n }\n }\n\n return detection.hasRegressions\n ? { ok: false, error: 'Regressions found', result: detection }\n : { ok: true, result: detection };\n },\n },\n});\n"]}
@@ -16,8 +16,6 @@ declare const _default: _kb_labs_shared_command_kit.CommandHandlerV3<unknown, CL
16
16
  description: string;
17
17
  default: false;
18
18
  };
19
- }>>, {
20
- exitCode: number;
21
- }>;
19
+ }>>, unknown>;
22
20
 
23
21
  export { _default as default };
@@ -36,7 +36,7 @@ var qa_run_default = defineCommand({
36
36
  ctx.ui?.success?.(`${section.header}`, { sections: [{ items: section.lines }] });
37
37
  }
38
38
  }
39
- return { exitCode: raw.ok ? 0 : 1 };
39
+ return raw.ok ? { ok: true, result: raw } : { ok: false, error: "QA run failed", result: raw };
40
40
  }
41
41
  }
42
42
  });
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/cli/commands/qa-run.ts"],"names":[],"mappings":";;;;;AAiBA,IAAO,iBAAQ,aAAA,CAAmE;AAAA,EAChF,EAAA,EAAI,QAAA;AAAA,EACJ,WAAA,EAAa,qCAAA;AAAA,EAEb,OAAA,EAAS;AAAA,IACP,MAAM,OAAA,CAAQ,GAAA,EAAsB,KAAA,EAA4D;AAC9F,MAAA,MAAM,EAAE,OAAM,GAAI,KAAA;AAClB,MAAA,MAAM,MAAA,GAAS,MAAM,SAAA,EAA0B;AAC/C,MAAA,MAAM,GAAA,GAAM,GAAA,CAAI,GAAA,IAAO,OAAA,CAAQ,GAAA,EAAI;AAEnC,MAAA,MAAM,UAAA,GAAa,gBAAA,CAAiB,GAAA,EAAK,MAAA,EAAQ,UAAU,CAAA;AAC3D,MAAA,MAAM,OAAA,GAAU,IAAI,aAAA,CAAc,EAAE,UAAA,EAAY,KAAK,KAAA,EAAO,GAAA,CAAI,GAAA,CAAI,KAAA,EAAO,CAAA;AAC3E,MAAA,MAAM,KAAA,GAAQ,IAAI,aAAA,CAAc,GAAA,EAAK,QAAQ,iBAAiB,CAAA;AAE9D,MAAA,MAAM,KAAA,GAAkB,MAAM,KAAA,GAC1B,KAAA,CAAM,MAAM,KAAA,CAAM,GAAG,CAAA,CAAE,GAAA,CAAI,CAAA,CAAA,KAAK,CAAA,CAAE,MAAM,CAAA,CAAE,MAAA,CAAO,OAAO,CAAA,GACxD,MAAA,EAAQ,cAAc,KAAA,EAAM,IAAK,CAAC,GAAG,aAAa,CAAA;AACtD,MAAA,MAAM,IAAA,GAAO,MAAM,IAAA,KAAS,KAAA;AAE5B,MAAA,MAAM,MAAM,MAAM,UAAA,CAAW,GAAA,CAAI,GAAA,CAAI,OAAO,GAAG,CAAA;AAE/C,MAAA,MAAM,KAAA,GAAQ,KAAK,GAAA,EAAI;AACvB,MAAA,MAAM,GAAA,GAAM,MAAM,OAAA,CAAQ,GAAA,CAAI,KAAK,CAAA;AACnC,MAAA,MAAM,UAAA,GAAa,IAAA,CAAK,GAAA,EAAI,GAAI,KAAA;AAEhC,MAAA,MAAM,IAAA,GAAO,OAAO,KAAA,CAAM,OAAA,CAAQ,KAAK,KAAA,EAAO,UAAA,EAAY,GAAG,CAAA,GAAI,IAAA;AACjE,MAAA,MAAM,YAAyD,IAAA,IAAQ;AAAA,QACrE,IAAA,EAAM,KAAA;AAAA,QAAO,EAAA,EAAI,EAAA;AAAA,QAAI,SAAA,EAAA,iBAAW,IAAI,IAAA,EAAK,EAAE,WAAA,EAAY;AAAA,QAAG,UAAA;AAAA,QAAY,KAAA;AAAA,QAAO;AAAA,OAC/E;AAEA,MAAA,IAAI,MAAM,IAAA,EAAM;AACd,QAAA,GAAA,CAAI,EAAA,EAAI,IAAA,GAAO,kBAAA,CAAmB,SAAS,CAAC,CAAA;AAAA,MAC9C,CAAA,MAAO;AACL,QAAA,KAAA,MAAW,OAAA,IAAW,cAAA,CAAe,SAAS,CAAA,EAAG;AAC/C,UAAA,GAAA,CAAI,EAAA,EAAI,OAAA,GAAU,CAAA,EAAG,OAAA,CAAQ,MAAM,CAAA,CAAA,EAAI,EAAE,QAAA,EAAU,CAAC,EAAE,KAAA,EAAO,OAAA,CAAQ,KAAA,EAAO,GAAG,CAAA;AAAA,QACjF;AAAA,MACF;AAEA,MAAA,OAAO,EAAE,QAAA,EAAU,GAAA,CAAI,EAAA,GAAK,IAAI,CAAA,EAAE;AAAA,IACpC;AAAA;AAEJ,CAAC","file":"qa-run.js","sourcesContent":["import {\n defineCommand,\n useConfig,\n type CLIInput,\n type PluginContextV3,\n} from '@kb-labs/sdk';\nimport {\n DevkitAdapter,\n SnapshotStore,\n resolveDevkitBin,\n captureGit,\n buildRunReport,\n buildRunJsonReport,\n} from '@kb-labs/qa-core';\nimport { DEFAULT_TASKS, type QAPluginConfig } from '@kb-labs/qa-contracts';\nimport type { QaRunFlags } from './flags.js';\n\nexport default defineCommand<unknown, CLIInput<QaRunFlags>, { exitCode: number }>({\n id: 'qa:run',\n description: 'Run devkit tasks and record results',\n\n handler: {\n async execute(ctx: PluginContextV3, input: CLIInput<QaRunFlags>): Promise<{ exitCode: number }> {\n const { flags } = input;\n const config = await useConfig<QAPluginConfig>();\n const cwd = ctx.cwd ?? process.cwd();\n\n const binaryPath = resolveDevkitBin(cwd, config?.devkitPath);\n const adapter = new DevkitAdapter({ binaryPath, cwd, shell: ctx.api.shell });\n const store = new SnapshotStore(cwd, config?.historyMaxEntries);\n\n const tasks: string[] = flags.tasks\n ? flags.tasks.split(',').map(s => s.trim()).filter(Boolean)\n : config?.defaultTasks?.slice() ?? [...DEFAULT_TASKS];\n const save = flags.save !== false;\n\n const git = await captureGit(ctx.api.shell, cwd);\n\n const start = Date.now();\n const raw = await adapter.run(tasks);\n const durationMs = Date.now() - start;\n\n const snap = save ? store.saveRun(raw, tasks, durationMs, git) : null;\n const effective: import('@kb-labs/qa-contracts').RunSnapshot = snap ?? {\n kind: 'run', id: '', timestamp: new Date().toISOString(), durationMs, tasks, raw,\n };\n\n if (flags.json) {\n ctx.ui?.json?.(buildRunJsonReport(effective));\n } else {\n for (const section of buildRunReport(effective)) {\n ctx.ui?.success?.(`${section.header}`, { sections: [{ items: section.lines }] });\n }\n }\n\n return { exitCode: raw.ok ? 0 : 1 };\n },\n },\n});\n"]}
1
+ {"version":3,"sources":["../../../src/cli/commands/qa-run.ts"],"names":[],"mappings":";;;;;AAkBA,IAAO,iBAAQ,aAAA,CAAsD;AAAA,EACnE,EAAA,EAAI,QAAA;AAAA,EACJ,WAAA,EAAa,qCAAA;AAAA,EAEb,OAAA,EAAS;AAAA,IACP,MAAM,OAAA,CAAQ,GAAA,EAAsB,KAAA,EAAqD;AACvF,MAAA,MAAM,EAAE,OAAM,GAAI,KAAA;AAClB,MAAA,MAAM,MAAA,GAAS,MAAM,SAAA,EAA0B;AAC/C,MAAA,MAAM,GAAA,GAAM,GAAA,CAAI,GAAA,IAAO,OAAA,CAAQ,GAAA,EAAI;AAEnC,MAAA,MAAM,UAAA,GAAa,gBAAA,CAAiB,GAAA,EAAK,MAAA,EAAQ,UAAU,CAAA;AAC3D,MAAA,MAAM,OAAA,GAAU,IAAI,aAAA,CAAc,EAAE,UAAA,EAAY,KAAK,KAAA,EAAO,GAAA,CAAI,GAAA,CAAI,KAAA,EAAO,CAAA;AAC3E,MAAA,MAAM,KAAA,GAAQ,IAAI,aAAA,CAAc,GAAA,EAAK,QAAQ,iBAAiB,CAAA;AAE9D,MAAA,MAAM,KAAA,GAAkB,MAAM,KAAA,GAC1B,KAAA,CAAM,MAAM,KAAA,CAAM,GAAG,CAAA,CAAE,GAAA,CAAI,CAAA,CAAA,KAAK,CAAA,CAAE,MAAM,CAAA,CAAE,MAAA,CAAO,OAAO,CAAA,GACxD,MAAA,EAAQ,cAAc,KAAA,EAAM,IAAK,CAAC,GAAG,aAAa,CAAA;AACtD,MAAA,MAAM,IAAA,GAAO,MAAM,IAAA,KAAS,KAAA;AAE5B,MAAA,MAAM,MAAM,MAAM,UAAA,CAAW,GAAA,CAAI,GAAA,CAAI,OAAO,GAAG,CAAA;AAE/C,MAAA,MAAM,KAAA,GAAQ,KAAK,GAAA,EAAI;AACvB,MAAA,MAAM,GAAA,GAAM,MAAM,OAAA,CAAQ,GAAA,CAAI,KAAK,CAAA;AACnC,MAAA,MAAM,UAAA,GAAa,IAAA,CAAK,GAAA,EAAI,GAAI,KAAA;AAEhC,MAAA,MAAM,IAAA,GAAO,OAAO,KAAA,CAAM,OAAA,CAAQ,KAAK,KAAA,EAAO,UAAA,EAAY,GAAG,CAAA,GAAI,IAAA;AACjE,MAAA,MAAM,YAAyD,IAAA,IAAQ;AAAA,QACrE,IAAA,EAAM,KAAA;AAAA,QAAO,EAAA,EAAI,EAAA;AAAA,QAAI,SAAA,EAAA,iBAAW,IAAI,IAAA,EAAK,EAAE,WAAA,EAAY;AAAA,QAAG,UAAA;AAAA,QAAY,KAAA;AAAA,QAAO;AAAA,OAC/E;AAEA,MAAA,IAAI,MAAM,IAAA,EAAM;AACd,QAAA,GAAA,CAAI,EAAA,EAAI,IAAA,GAAO,kBAAA,CAAmB,SAAS,CAAC,CAAA;AAAA,MAC9C,CAAA,MAAO;AACL,QAAA,KAAA,MAAW,OAAA,IAAW,cAAA,CAAe,SAAS,CAAA,EAAG;AAC/C,UAAA,GAAA,CAAI,EAAA,EAAI,OAAA,GAAU,CAAA,EAAG,OAAA,CAAQ,MAAM,CAAA,CAAA,EAAI,EAAE,QAAA,EAAU,CAAC,EAAE,KAAA,EAAO,OAAA,CAAQ,KAAA,EAAO,GAAG,CAAA;AAAA,QACjF;AAAA,MACF;AAEA,MAAA,OAAO,GAAA,CAAI,EAAA,GAAK,EAAE,EAAA,EAAI,MAAM,MAAA,EAAQ,GAAA,EAAI,GAAI,EAAE,EAAA,EAAI,KAAA,EAAO,KAAA,EAAO,eAAA,EAAiB,QAAQ,GAAA,EAAI;AAAA,IAC/F;AAAA;AAEJ,CAAC","file":"qa-run.js","sourcesContent":["import {\n defineCommand,\n useConfig,\n type CLIInput,\n type PluginContextV3,\n type CommandResult,\n} from '@kb-labs/sdk';\nimport {\n DevkitAdapter,\n SnapshotStore,\n resolveDevkitBin,\n captureGit,\n buildRunReport,\n buildRunJsonReport,\n} from '@kb-labs/qa-core';\nimport { DEFAULT_TASKS, type QAPluginConfig } from '@kb-labs/qa-contracts';\nimport type { QaRunFlags } from './flags.js';\n\nexport default defineCommand<unknown, CLIInput<QaRunFlags>, unknown>({\n id: 'qa:run',\n description: 'Run devkit tasks and record results',\n\n handler: {\n async execute(ctx: PluginContextV3, input: CLIInput<QaRunFlags>): Promise<CommandResult> {\n const { flags } = input;\n const config = await useConfig<QAPluginConfig>();\n const cwd = ctx.cwd ?? process.cwd();\n\n const binaryPath = resolveDevkitBin(cwd, config?.devkitPath);\n const adapter = new DevkitAdapter({ binaryPath, cwd, shell: ctx.api.shell });\n const store = new SnapshotStore(cwd, config?.historyMaxEntries);\n\n const tasks: string[] = flags.tasks\n ? flags.tasks.split(',').map(s => s.trim()).filter(Boolean)\n : config?.defaultTasks?.slice() ?? [...DEFAULT_TASKS];\n const save = flags.save !== false;\n\n const git = await captureGit(ctx.api.shell, cwd);\n\n const start = Date.now();\n const raw = await adapter.run(tasks);\n const durationMs = Date.now() - start;\n\n const snap = save ? store.saveRun(raw, tasks, durationMs, git) : null;\n const effective: import('@kb-labs/qa-contracts').RunSnapshot = snap ?? {\n kind: 'run', id: '', timestamp: new Date().toISOString(), durationMs, tasks, raw,\n };\n\n if (flags.json) {\n ctx.ui?.json?.(buildRunJsonReport(effective));\n } else {\n for (const section of buildRunReport(effective)) {\n ctx.ui?.success?.(`${section.header}`, { sections: [{ items: section.lines }] });\n }\n }\n\n return raw.ok ? { ok: true, result: raw } : { ok: false, error: 'QA run failed', result: raw };\n },\n },\n});\n"]}
@@ -12,8 +12,6 @@ declare const _default: _kb_labs_shared_command_kit.CommandHandlerV3<unknown, CL
12
12
  description: string;
13
13
  default: false;
14
14
  };
15
- }>>, {
16
- exitCode: number;
17
- }>;
15
+ }>>, unknown>;
18
16
 
19
17
  export { _default as default };
@@ -33,7 +33,7 @@ var qa_stats_default = defineCommand({
33
33
  ctx.ui?.success?.(`${section.header}`, { sections: [{ items: section.lines }] });
34
34
  }
35
35
  }
36
- return { exitCode: 0 };
36
+ return { ok: true };
37
37
  }
38
38
  }
39
39
  });
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/cli/commands/qa-stats.ts"],"names":[],"mappings":";;;;AAiBA,IAAO,mBAAQ,aAAA,CAAqE;AAAA,EAClF,EAAA,EAAI,UAAA;AAAA,EACJ,WAAA,EAAa,iDAAA;AAAA,EAEb,OAAA,EAAS;AAAA,IACP,MAAM,OAAA,CAAQ,GAAA,EAAsB,KAAA,EAA8D;AAChG,MAAA,MAAM,EAAE,OAAM,GAAI,KAAA;AAClB,MAAA,MAAM,MAAA,GAAS,MAAM,SAAA,EAA0B;AAC/C,MAAA,MAAM,GAAA,GAAM,GAAA,CAAI,GAAA,IAAO,OAAA,CAAQ,GAAA,EAAI;AAEnC,MAAA,MAAM,UAAA,GAAa,gBAAA,CAAiB,GAAA,EAAK,MAAA,EAAQ,UAAU,CAAA;AAC3D,MAAA,MAAM,OAAA,GAAU,IAAI,aAAA,CAAc,EAAE,UAAA,EAAY,KAAK,KAAA,EAAO,GAAA,CAAI,GAAA,CAAI,KAAA,EAAO,CAAA;AAC3E,MAAA,MAAM,KAAA,GAAQ,IAAI,aAAA,CAAc,GAAA,EAAK,QAAQ,iBAAiB,CAAA;AAE9D,MAAA,MAAM,IAAA,GAAO,MAAM,IAAA,KAAS,KAAA;AAC5B,MAAA,MAAM,MAAM,MAAM,UAAA,CAAW,GAAA,CAAI,GAAA,CAAI,OAAO,GAAG,CAAA;AAE/C,MAAA,MAAM,KAAA,GAAQ,KAAK,GAAA,EAAI;AACvB,MAAA,MAAM,GAAA,GAAM,MAAM,OAAA,CAAQ,KAAA,EAAM;AAChC,MAAA,MAAM,UAAA,GAAa,IAAA,CAAK,GAAA,EAAI,GAAI,KAAA;AAEhC,MAAA,MAAM,OAAO,IAAA,GAAO,KAAA,CAAM,UAAU,GAAA,EAAK,UAAA,EAAY,GAAG,CAAA,GAAI,IAAA;AAC5D,MAAA,MAAM,YAA2D,IAAA,IAAQ;AAAA,QACvE,IAAA,EAAM,OAAA;AAAA,QAAS,EAAA,EAAI,EAAA;AAAA,QAAI,SAAA,EAAA,iBAAW,IAAI,IAAA,EAAK,EAAE,WAAA,EAAY;AAAA,QAAG,UAAA;AAAA,QAAY;AAAA,OAC1E;AAEA,MAAA,IAAI,MAAM,IAAA,EAAM;AACd,QAAA,GAAA,CAAI,EAAA,EAAI,IAAA,GAAO,oBAAA,CAAqB,SAAS,CAAC,CAAA;AAAA,MAChD,CAAA,MAAO;AACL,QAAA,KAAA,MAAW,OAAA,IAAW,gBAAA,CAAiB,SAAS,CAAA,EAAG;AACjD,UAAA,GAAA,CAAI,EAAA,EAAI,OAAA,GAAU,CAAA,EAAG,OAAA,CAAQ,MAAM,CAAA,CAAA,EAAI,EAAE,QAAA,EAAU,CAAC,EAAE,KAAA,EAAO,OAAA,CAAQ,KAAA,EAAO,GAAG,CAAA;AAAA,QACjF;AAAA,MACF;AAEA,MAAA,OAAO,EAAE,UAAU,CAAA,EAAE;AAAA,IACvB;AAAA;AAEJ,CAAC","file":"qa-stats.js","sourcesContent":["import {\n defineCommand,\n useConfig,\n type CLIInput,\n type PluginContextV3,\n} from '@kb-labs/sdk';\nimport {\n DevkitAdapter,\n SnapshotStore,\n resolveDevkitBin,\n captureGit,\n buildStatsReport,\n buildStatsJsonReport,\n} from '@kb-labs/qa-core';\nimport { type QAPluginConfig } from '@kb-labs/qa-contracts';\nimport type { QaStatsFlags } from './flags.js';\n\nexport default defineCommand<unknown, CLIInput<QaStatsFlags>, { exitCode: number }>({\n id: 'qa:stats',\n description: 'Show devkit health score and category breakdown',\n\n handler: {\n async execute(ctx: PluginContextV3, input: CLIInput<QaStatsFlags>): Promise<{ exitCode: number }> {\n const { flags } = input;\n const config = await useConfig<QAPluginConfig>();\n const cwd = ctx.cwd ?? process.cwd();\n\n const binaryPath = resolveDevkitBin(cwd, config?.devkitPath);\n const adapter = new DevkitAdapter({ binaryPath, cwd, shell: ctx.api.shell });\n const store = new SnapshotStore(cwd, config?.historyMaxEntries);\n\n const save = flags.save !== false;\n const git = await captureGit(ctx.api.shell, cwd);\n\n const start = Date.now();\n const raw = await adapter.stats();\n const durationMs = Date.now() - start;\n\n const snap = save ? store.saveStats(raw, durationMs, git) : null;\n const effective: import('@kb-labs/qa-contracts').StatsSnapshot = snap ?? {\n kind: 'stats', id: '', timestamp: new Date().toISOString(), durationMs, raw,\n };\n\n if (flags.json) {\n ctx.ui?.json?.(buildStatsJsonReport(effective));\n } else {\n for (const section of buildStatsReport(effective)) {\n ctx.ui?.success?.(`${section.header}`, { sections: [{ items: section.lines }] });\n }\n }\n\n return { exitCode: 0 };\n },\n },\n});\n"]}
1
+ {"version":3,"sources":["../../../src/cli/commands/qa-stats.ts"],"names":[],"mappings":";;;;AAkBA,IAAO,mBAAQ,aAAA,CAAwD;AAAA,EACrE,EAAA,EAAI,UAAA;AAAA,EACJ,WAAA,EAAa,iDAAA;AAAA,EAEb,OAAA,EAAS;AAAA,IACP,MAAM,OAAA,CAAQ,GAAA,EAAsB,KAAA,EAAuD;AACzF,MAAA,MAAM,EAAE,OAAM,GAAI,KAAA;AAClB,MAAA,MAAM,MAAA,GAAS,MAAM,SAAA,EAA0B;AAC/C,MAAA,MAAM,GAAA,GAAM,GAAA,CAAI,GAAA,IAAO,OAAA,CAAQ,GAAA,EAAI;AAEnC,MAAA,MAAM,UAAA,GAAa,gBAAA,CAAiB,GAAA,EAAK,MAAA,EAAQ,UAAU,CAAA;AAC3D,MAAA,MAAM,OAAA,GAAU,IAAI,aAAA,CAAc,EAAE,UAAA,EAAY,KAAK,KAAA,EAAO,GAAA,CAAI,GAAA,CAAI,KAAA,EAAO,CAAA;AAC3E,MAAA,MAAM,KAAA,GAAQ,IAAI,aAAA,CAAc,GAAA,EAAK,QAAQ,iBAAiB,CAAA;AAE9D,MAAA,MAAM,IAAA,GAAO,MAAM,IAAA,KAAS,KAAA;AAC5B,MAAA,MAAM,MAAM,MAAM,UAAA,CAAW,GAAA,CAAI,GAAA,CAAI,OAAO,GAAG,CAAA;AAE/C,MAAA,MAAM,KAAA,GAAQ,KAAK,GAAA,EAAI;AACvB,MAAA,MAAM,GAAA,GAAM,MAAM,OAAA,CAAQ,KAAA,EAAM;AAChC,MAAA,MAAM,UAAA,GAAa,IAAA,CAAK,GAAA,EAAI,GAAI,KAAA;AAEhC,MAAA,MAAM,OAAO,IAAA,GAAO,KAAA,CAAM,UAAU,GAAA,EAAK,UAAA,EAAY,GAAG,CAAA,GAAI,IAAA;AAC5D,MAAA,MAAM,YAA2D,IAAA,IAAQ;AAAA,QACvE,IAAA,EAAM,OAAA;AAAA,QAAS,EAAA,EAAI,EAAA;AAAA,QAAI,SAAA,EAAA,iBAAW,IAAI,IAAA,EAAK,EAAE,WAAA,EAAY;AAAA,QAAG,UAAA;AAAA,QAAY;AAAA,OAC1E;AAEA,MAAA,IAAI,MAAM,IAAA,EAAM;AACd,QAAA,GAAA,CAAI,EAAA,EAAI,IAAA,GAAO,oBAAA,CAAqB,SAAS,CAAC,CAAA;AAAA,MAChD,CAAA,MAAO;AACL,QAAA,KAAA,MAAW,OAAA,IAAW,gBAAA,CAAiB,SAAS,CAAA,EAAG;AACjD,UAAA,GAAA,CAAI,EAAA,EAAI,OAAA,GAAU,CAAA,EAAG,OAAA,CAAQ,MAAM,CAAA,CAAA,EAAI,EAAE,QAAA,EAAU,CAAC,EAAE,KAAA,EAAO,OAAA,CAAQ,KAAA,EAAO,GAAG,CAAA;AAAA,QACjF;AAAA,MACF;AAEA,MAAA,OAAO,EAAE,IAAI,IAAA,EAAK;AAAA,IACpB;AAAA;AAEJ,CAAC","file":"qa-stats.js","sourcesContent":["import {\n defineCommand,\n useConfig,\n type CLIInput,\n type PluginContextV3,\n type CommandResult,\n} from '@kb-labs/sdk';\nimport {\n DevkitAdapter,\n SnapshotStore,\n resolveDevkitBin,\n captureGit,\n buildStatsReport,\n buildStatsJsonReport,\n} from '@kb-labs/qa-core';\nimport { type QAPluginConfig } from '@kb-labs/qa-contracts';\nimport type { QaStatsFlags } from './flags.js';\n\nexport default defineCommand<unknown, CLIInput<QaStatsFlags>, unknown>({\n id: 'qa:stats',\n description: 'Show devkit health score and category breakdown',\n\n handler: {\n async execute(ctx: PluginContextV3, input: CLIInput<QaStatsFlags>): Promise<CommandResult> {\n const { flags } = input;\n const config = await useConfig<QAPluginConfig>();\n const cwd = ctx.cwd ?? process.cwd();\n\n const binaryPath = resolveDevkitBin(cwd, config?.devkitPath);\n const adapter = new DevkitAdapter({ binaryPath, cwd, shell: ctx.api.shell });\n const store = new SnapshotStore(cwd, config?.historyMaxEntries);\n\n const save = flags.save !== false;\n const git = await captureGit(ctx.api.shell, cwd);\n\n const start = Date.now();\n const raw = await adapter.stats();\n const durationMs = Date.now() - start;\n\n const snap = save ? store.saveStats(raw, durationMs, git) : null;\n const effective: import('@kb-labs/qa-contracts').StatsSnapshot = snap ?? {\n kind: 'stats', id: '', timestamp: new Date().toISOString(), durationMs, raw,\n };\n\n if (flags.json) {\n ctx.ui?.json?.(buildStatsJsonReport(effective));\n } else {\n for (const section of buildStatsReport(effective)) {\n ctx.ui?.success?.(`${section.header}`, { sections: [{ items: section.lines }] });\n }\n }\n\n return { ok: true };\n },\n },\n});\n"]}
@@ -12,8 +12,6 @@ declare const _default: _kb_labs_shared_command_kit.CommandHandlerV3<unknown, CL
12
12
  description: string;
13
13
  default: false;
14
14
  };
15
- }>>, {
16
- exitCode: number;
17
- }>;
15
+ }>>, unknown>;
18
16
 
19
17
  export { _default as default };
@@ -22,7 +22,7 @@ var qa_trends_default = defineCommand({
22
22
  ctx.ui?.success?.(`${section.header}`, { sections: [{ items: section.lines }] });
23
23
  }
24
24
  }
25
- return { exitCode: 0 };
25
+ return { ok: true };
26
26
  }
27
27
  }
28
28
  });
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/cli/commands/qa-trends.ts"],"names":[],"mappings":";;;;;AAcA,IAAO,oBAAQ,aAAA,CAAsE;AAAA,EACnF,EAAA,EAAI,WAAA;AAAA,EACJ,WAAA,EAAa,kCAAA;AAAA,EAEb,OAAA,EAAS;AAAA,IACP,MAAM,OAAA,CAAQ,GAAA,EAAsB,KAAA,EAA+D;AACjG,MAAA,MAAM,EAAE,OAAM,GAAI,KAAA;AAClB,MAAA,MAAM,MAAA,GAAS,MAAM,SAAA,EAA0B;AAC/C,MAAA,MAAM,GAAA,GAAM,GAAA,CAAI,GAAA,IAAO,OAAA,CAAQ,GAAA,EAAI;AAEnC,MAAA,MAAM,KAAA,GAAQ,IAAI,aAAA,CAAc,GAAA,EAAK,QAAQ,iBAAiB,CAAA;AAC9D,MAAA,MAAM,MAAA,GAAS,MAAM,MAAA,IAAU,aAAA;AAC/B,MAAA,MAAM,OAAA,GAAU,MAAM,cAAA,EAAe;AACrC,MAAA,MAAM,QAAA,GAAW,aAAA,CAAc,OAAA,EAAS,MAAM,CAAA;AAE9C,MAAA,IAAI,MAAM,IAAA,EAAM;AACd,QAAA,GAAA,CAAI,EAAA,EAAI,OAAO,QAAQ,CAAA;AAAA,MACzB,CAAA,MAAO;AACL,QAAA,KAAA,MAAW,OAAA,IAAW,iBAAA,CAAkB,QAAQ,CAAA,EAAG;AACjD,UAAA,GAAA,CAAI,EAAA,EAAI,OAAA,GAAU,CAAA,EAAG,OAAA,CAAQ,MAAM,CAAA,CAAA,EAAI,EAAE,QAAA,EAAU,CAAC,EAAE,KAAA,EAAO,OAAA,CAAQ,KAAA,EAAO,GAAG,CAAA;AAAA,QACjF;AAAA,MACF;AAEA,MAAA,OAAO,EAAE,UAAU,CAAA,EAAE;AAAA,IACvB;AAAA;AAEJ,CAAC","file":"qa-trends.js","sourcesContent":["import {\n defineCommand,\n useConfig,\n type CLIInput,\n type PluginContextV3,\n} from '@kb-labs/sdk';\nimport {\n SnapshotStore,\n analyzeTrends,\n buildTrendsReport,\n} from '@kb-labs/qa-core';\nimport { TRENDS_WINDOW, type QAPluginConfig } from '@kb-labs/qa-contracts';\nimport type { QaTrendsFlags } from './flags.js';\n\nexport default defineCommand<unknown, CLIInput<QaTrendsFlags>, { exitCode: number }>({\n id: 'qa:trends',\n description: 'Show QA quality trends over time',\n\n handler: {\n async execute(ctx: PluginContextV3, input: CLIInput<QaTrendsFlags>): Promise<{ exitCode: number }> {\n const { flags } = input;\n const config = await useConfig<QAPluginConfig>();\n const cwd = ctx.cwd ?? process.cwd();\n\n const store = new SnapshotStore(cwd, config?.historyMaxEntries);\n const window = flags.window ?? TRENDS_WINDOW;\n const history = store.loadRunHistory();\n const analysis = analyzeTrends(history, window);\n\n if (flags.json) {\n ctx.ui?.json?.(analysis);\n } else {\n for (const section of buildTrendsReport(analysis)) {\n ctx.ui?.success?.(`${section.header}`, { sections: [{ items: section.lines }] });\n }\n }\n\n return { exitCode: 0 };\n },\n },\n});\n"]}
1
+ {"version":3,"sources":["../../../src/cli/commands/qa-trends.ts"],"names":[],"mappings":";;;;;AAeA,IAAO,oBAAQ,aAAA,CAAyD;AAAA,EACtE,EAAA,EAAI,WAAA;AAAA,EACJ,WAAA,EAAa,kCAAA;AAAA,EAEb,OAAA,EAAS;AAAA,IACP,MAAM,OAAA,CAAQ,GAAA,EAAsB,KAAA,EAAwD;AAC1F,MAAA,MAAM,EAAE,OAAM,GAAI,KAAA;AAClB,MAAA,MAAM,MAAA,GAAS,MAAM,SAAA,EAA0B;AAC/C,MAAA,MAAM,GAAA,GAAM,GAAA,CAAI,GAAA,IAAO,OAAA,CAAQ,GAAA,EAAI;AAEnC,MAAA,MAAM,KAAA,GAAQ,IAAI,aAAA,CAAc,GAAA,EAAK,QAAQ,iBAAiB,CAAA;AAC9D,MAAA,MAAM,MAAA,GAAS,MAAM,MAAA,IAAU,aAAA;AAC/B,MAAA,MAAM,OAAA,GAAU,MAAM,cAAA,EAAe;AACrC,MAAA,MAAM,QAAA,GAAW,aAAA,CAAc,OAAA,EAAS,MAAM,CAAA;AAE9C,MAAA,IAAI,MAAM,IAAA,EAAM;AACd,QAAA,GAAA,CAAI,EAAA,EAAI,OAAO,QAAQ,CAAA;AAAA,MACzB,CAAA,MAAO;AACL,QAAA,KAAA,MAAW,OAAA,IAAW,iBAAA,CAAkB,QAAQ,CAAA,EAAG;AACjD,UAAA,GAAA,CAAI,EAAA,EAAI,OAAA,GAAU,CAAA,EAAG,OAAA,CAAQ,MAAM,CAAA,CAAA,EAAI,EAAE,QAAA,EAAU,CAAC,EAAE,KAAA,EAAO,OAAA,CAAQ,KAAA,EAAO,GAAG,CAAA;AAAA,QACjF;AAAA,MACF;AAEA,MAAA,OAAO,EAAE,IAAI,IAAA,EAAK;AAAA,IACpB;AAAA;AAEJ,CAAC","file":"qa-trends.js","sourcesContent":["import {\n defineCommand,\n useConfig,\n type CLIInput,\n type PluginContextV3,\n type CommandResult,\n} from '@kb-labs/sdk';\nimport {\n SnapshotStore,\n analyzeTrends,\n buildTrendsReport,\n} from '@kb-labs/qa-core';\nimport { TRENDS_WINDOW, type QAPluginConfig } from '@kb-labs/qa-contracts';\nimport type { QaTrendsFlags } from './flags.js';\n\nexport default defineCommand<unknown, CLIInput<QaTrendsFlags>, unknown>({\n id: 'qa:trends',\n description: 'Show QA quality trends over time',\n\n handler: {\n async execute(ctx: PluginContextV3, input: CLIInput<QaTrendsFlags>): Promise<CommandResult> {\n const { flags } = input;\n const config = await useConfig<QAPluginConfig>();\n const cwd = ctx.cwd ?? process.cwd();\n\n const store = new SnapshotStore(cwd, config?.historyMaxEntries);\n const window = flags.window ?? TRENDS_WINDOW;\n const history = store.loadRunHistory();\n const analysis = analyzeTrends(history, window);\n\n if (flags.json) {\n ctx.ui?.json?.(analysis);\n } else {\n for (const section of buildTrendsReport(analysis)) {\n ctx.ui?.success?.(`${section.header}`, { sections: [{ items: section.lines }] });\n }\n }\n\n return { ok: true };\n },\n },\n});\n"]}
package/dist/index.js CHANGED
@@ -108,6 +108,72 @@ var qaE2eFlakyFlags = defineFlags({
108
108
  description: "CI-only: directory of per-shard flaky-report.json files to merge and save as a new snapshot"
109
109
  }
110
110
  });
111
+ var qaCiEvidenceCaptureFlags = defineFlags({
112
+ runId: {
113
+ type: "string",
114
+ description: "GitHub Actions run ID (defaults to GITHUB_RUN_ID)"
115
+ },
116
+ repository: {
117
+ type: "string",
118
+ description: "GitHub repository in owner/name form (defaults to GITHUB_REPOSITORY)"
119
+ },
120
+ output: {
121
+ type: "string",
122
+ description: "Path for the immutable dossier JSON",
123
+ default: ".kb/qa/ci/dossier.json"
124
+ },
125
+ excludeJob: {
126
+ type: "string",
127
+ description: "Comma-separated job names to exclude from evidence (for example, the collector job itself)"
128
+ },
129
+ json: {
130
+ type: "boolean",
131
+ description: "Output the captured dossier as JSON",
132
+ default: false
133
+ }
134
+ });
135
+ var qaCiEvidenceSyncFlags = defineFlags({
136
+ repository: {
137
+ type: "string",
138
+ description: "GitHub repository in owner/name form (defaults to config or GITHUB_REPOSITORY)"
139
+ },
140
+ workflow: {
141
+ type: "string",
142
+ description: "GitHub Actions workflow file or name",
143
+ default: "e2e-platform.yml"
144
+ },
145
+ limit: {
146
+ type: "number",
147
+ description: "Recent workflow runs to inspect for evidence artifacts",
148
+ default: 50
149
+ },
150
+ output: {
151
+ type: "string",
152
+ description: "Local evidence cache directory",
153
+ default: ".kb/qa/ci/evidence"
154
+ },
155
+ json: {
156
+ type: "boolean",
157
+ description: "Output sync details as JSON",
158
+ default: false
159
+ }
160
+ });
161
+ var qaCiOverviewFlags = defineFlags({
162
+ input: {
163
+ type: "string",
164
+ description: "Dossier JSON file or directory containing dossier.json files",
165
+ default: ".kb/qa/ci"
166
+ },
167
+ output: {
168
+ type: "string",
169
+ description: "Optional file to receive the compact agent-ready JSON overview"
170
+ },
171
+ json: {
172
+ type: "boolean",
173
+ description: "Output the agent-ready reliability overview as JSON",
174
+ default: false
175
+ }
176
+ });
111
177
  var qaRegressionsFlags = defineFlags({
112
178
  json: {
113
179
  type: "boolean",
@@ -140,7 +206,7 @@ var pluginPermissions = combinePermissions().with(kbPlatformPreset).withFs({
140
206
  mode: "readWrite",
141
207
  allow: ["**"]
142
208
  }).withShell({
143
- allow: ["kb-devkit", "git"]
209
+ allow: ["kb-devkit", "git", "gh"]
144
210
  }).withPlatform({
145
211
  analytics: true
146
212
  }).withQuotas({
@@ -164,7 +230,9 @@ var manifest = {
164
230
  cli: {
165
231
  groupMeta: [
166
232
  { path: "qa", describe: "Quality assurance powered by kb-devkit" },
167
- { path: "qa baseline", describe: "Baseline management" }
233
+ { path: "qa baseline", describe: "Baseline management" },
234
+ { path: "qa ci", describe: "CI evidence and reliability analysis" },
235
+ { path: "qa ci evidence", describe: "Immutable CI evidence capture" }
168
236
  ],
169
237
  commands: [
170
238
  {
@@ -230,6 +298,33 @@ var manifest = {
230
298
  flags: defineCommandFlags(qaE2eFlakyFlags.schema),
231
299
  permissions: pluginPermissions
232
300
  },
301
+ {
302
+ path: "qa ci evidence capture",
303
+ category: "CI",
304
+ describe: "Capture a GitHub Actions run dossier (CI producer command)",
305
+ operationType: "execute",
306
+ handler: "./cli/commands/qa-ci-evidence-capture.js#default",
307
+ flags: defineCommandFlags(qaCiEvidenceCaptureFlags.schema),
308
+ permissions: pluginPermissions
309
+ },
310
+ {
311
+ path: "qa ci evidence sync",
312
+ category: "CI",
313
+ describe: "Download new CI evidence artifacts into a local cache",
314
+ operationType: "execute",
315
+ handler: "./cli/commands/qa-ci-evidence-sync.js#default",
316
+ flags: defineCommandFlags(qaCiEvidenceSyncFlags.schema),
317
+ permissions: pluginPermissions
318
+ },
319
+ {
320
+ path: "qa ci overview",
321
+ category: "CI",
322
+ describe: "Show a compact CI reliability overview",
323
+ operationType: "read",
324
+ handler: "./cli/commands/qa-ci-overview.js#default",
325
+ flags: defineCommandFlags(qaCiOverviewFlags.schema),
326
+ permissions: pluginPermissions
327
+ },
233
328
  {
234
329
  path: "qa regressions",
235
330
  category: "History",
@@ -283,7 +378,8 @@ var manifest = {
283
378
  { method: "POST", path: QA_ROUTES.BASELINE_UPDATE, handler: "./rest/handlers/baseline-update-handler.js#default" },
284
379
  { method: "GET", path: QA_ROUTES.BASELINE_DIFF, handler: "./rest/handlers/baseline-diff-handler.js#default" },
285
380
  { method: "GET", path: QA_ROUTES.PACKAGE_TIMELINE, handler: "./rest/handlers/package-timeline-handler.js#default" },
286
- { method: "GET", path: QA_ROUTES.TASKS, handler: "./rest/handlers/tasks-handler.js#default" }
381
+ { method: "GET", path: QA_ROUTES.TASKS, handler: "./rest/handlers/tasks-handler.js#default" },
382
+ { method: "GET", path: QA_ROUTES.CI_OVERVIEW, handler: "./rest/handlers/ci-overview-handler.js#default" }
287
383
  ]
288
384
  },
289
385
  studio: {