@sun-asterisk/sungen 3.0.0 → 3.1.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 (161) hide show
  1. package/dist/cli/commands/audit.d.ts.map +1 -1
  2. package/dist/cli/commands/audit.js +24 -0
  3. package/dist/cli/commands/audit.js.map +1 -1
  4. package/dist/cli/commands/delivery.d.ts.map +1 -1
  5. package/dist/cli/commands/delivery.js +30 -14
  6. package/dist/cli/commands/delivery.js.map +1 -1
  7. package/dist/cli/commands/eval.d.ts +3 -0
  8. package/dist/cli/commands/eval.d.ts.map +1 -0
  9. package/dist/cli/commands/eval.js +37 -0
  10. package/dist/cli/commands/eval.js.map +1 -0
  11. package/dist/cli/commands/ingest.d.ts +3 -0
  12. package/dist/cli/commands/ingest.d.ts.map +1 -0
  13. package/dist/cli/commands/ingest.js +179 -0
  14. package/dist/cli/commands/ingest.js.map +1 -0
  15. package/dist/cli/index.js +4 -0
  16. package/dist/cli/index.js.map +1 -1
  17. package/dist/dashboard/templates/index.html +108 -194
  18. package/dist/generators/test-generator/adapters/adapter-interface.d.ts +1 -0
  19. package/dist/generators/test-generator/adapters/adapter-interface.d.ts.map +1 -1
  20. package/dist/generators/test-generator/adapters/playwright/playwright-adapter.d.ts +1 -0
  21. package/dist/generators/test-generator/adapters/playwright/playwright-adapter.d.ts.map +1 -1
  22. package/dist/generators/test-generator/adapters/playwright/playwright-adapter.js.map +1 -1
  23. package/dist/generators/test-generator/adapters/playwright/templates/imports.hbs +3 -0
  24. package/dist/generators/test-generator/code-generator.d.ts +4 -0
  25. package/dist/generators/test-generator/code-generator.d.ts.map +1 -1
  26. package/dist/generators/test-generator/code-generator.js +31 -2
  27. package/dist/generators/test-generator/code-generator.js.map +1 -1
  28. package/dist/generators/test-generator/patterns/database-patterns.d.ts +5 -0
  29. package/dist/generators/test-generator/patterns/database-patterns.d.ts.map +1 -0
  30. package/dist/generators/test-generator/patterns/database-patterns.js +94 -0
  31. package/dist/generators/test-generator/patterns/database-patterns.js.map +1 -0
  32. package/dist/generators/test-generator/patterns/index.d.ts +1 -0
  33. package/dist/generators/test-generator/patterns/index.d.ts.map +1 -1
  34. package/dist/generators/test-generator/patterns/index.js +6 -1
  35. package/dist/generators/test-generator/patterns/index.js.map +1 -1
  36. package/dist/generators/test-generator/template-engine.d.ts +1 -0
  37. package/dist/generators/test-generator/template-engine.d.ts.map +1 -1
  38. package/dist/generators/test-generator/template-engine.js +1 -1
  39. package/dist/generators/test-generator/template-engine.js.map +1 -1
  40. package/dist/harness/audit.d.ts +16 -0
  41. package/dist/harness/audit.d.ts.map +1 -1
  42. package/dist/harness/audit.js +69 -5
  43. package/dist/harness/audit.js.map +1 -1
  44. package/dist/harness/capability-plan.d.ts +6 -0
  45. package/dist/harness/capability-plan.d.ts.map +1 -1
  46. package/dist/harness/capability-plan.js +14 -1
  47. package/dist/harness/capability-plan.js.map +1 -1
  48. package/dist/harness/catalog/drivers.yaml +1 -1
  49. package/dist/harness/catalog/universal-viewpoints.yaml +1 -1
  50. package/dist/harness/eval/skill-lint.d.ts +16 -0
  51. package/dist/harness/eval/skill-lint.d.ts.map +1 -0
  52. package/dist/harness/eval/skill-lint.js +129 -0
  53. package/dist/harness/eval/skill-lint.js.map +1 -0
  54. package/dist/harness/flow-plan.js +1 -1
  55. package/dist/harness/parse.d.ts +6 -0
  56. package/dist/harness/parse.d.ts.map +1 -1
  57. package/dist/harness/parse.js +18 -3
  58. package/dist/harness/parse.js.map +1 -1
  59. package/dist/harness/quality-gates.d.ts +29 -0
  60. package/dist/harness/quality-gates.d.ts.map +1 -0
  61. package/dist/harness/quality-gates.js +183 -0
  62. package/dist/harness/quality-gates.js.map +1 -0
  63. package/dist/harness/script-check.d.ts.map +1 -1
  64. package/dist/harness/script-check.js +4 -1
  65. package/dist/harness/script-check.js.map +1 -1
  66. package/dist/harness/sensors.d.ts.map +1 -1
  67. package/dist/harness/sensors.js +85 -6
  68. package/dist/harness/sensors.js.map +1 -1
  69. package/dist/harness/spec-coverage.d.ts +37 -0
  70. package/dist/harness/spec-coverage.d.ts.map +1 -0
  71. package/dist/harness/spec-coverage.js +159 -0
  72. package/dist/harness/spec-coverage.js.map +1 -0
  73. package/dist/harness/viewpoint-ledger.d.ts +23 -0
  74. package/dist/harness/viewpoint-ledger.d.ts.map +1 -0
  75. package/dist/harness/viewpoint-ledger.js +118 -0
  76. package/dist/harness/viewpoint-ledger.js.map +1 -0
  77. package/dist/ingest/baseline-audit.d.ts +38 -0
  78. package/dist/ingest/baseline-audit.d.ts.map +1 -0
  79. package/dist/ingest/baseline-audit.js +85 -0
  80. package/dist/ingest/baseline-audit.js.map +1 -0
  81. package/dist/ingest/gsheet-fetch.d.ts +9 -0
  82. package/dist/ingest/gsheet-fetch.d.ts.map +1 -0
  83. package/dist/ingest/gsheet-fetch.js +180 -0
  84. package/dist/ingest/gsheet-fetch.js.map +1 -0
  85. package/dist/ingest/index.d.ts +6 -0
  86. package/dist/ingest/index.d.ts.map +1 -0
  87. package/dist/ingest/index.js +22 -0
  88. package/dist/ingest/index.js.map +1 -0
  89. package/dist/ingest/legacy-parser.d.ts +39 -0
  90. package/dist/ingest/legacy-parser.d.ts.map +1 -0
  91. package/dist/ingest/legacy-parser.js +218 -0
  92. package/dist/ingest/legacy-parser.js.map +1 -0
  93. package/dist/ingest/reconcile.d.ts +30 -0
  94. package/dist/ingest/reconcile.d.ts.map +1 -0
  95. package/dist/ingest/reconcile.js +65 -0
  96. package/dist/ingest/reconcile.js.map +1 -0
  97. package/dist/ingest/to-gherkin.d.ts +33 -0
  98. package/dist/ingest/to-gherkin.d.ts.map +1 -0
  99. package/dist/ingest/to-gherkin.js +93 -0
  100. package/dist/ingest/to-gherkin.js.map +1 -0
  101. package/dist/orchestrator/ai-rules-updater.d.ts.map +1 -1
  102. package/dist/orchestrator/ai-rules-updater.js +2 -0
  103. package/dist/orchestrator/ai-rules-updater.js.map +1 -1
  104. package/dist/orchestrator/templates/ai-instructions/claude-agent-reviewer.md +1 -0
  105. package/dist/orchestrator/templates/ai-instructions/claude-skill-delivery.md +10 -0
  106. package/dist/orchestrator/templates/ai-instructions/claude-skill-harness-audit.md +1 -1
  107. package/dist/orchestrator/templates/ai-instructions/claude-skill-ingest-legacy.md +79 -0
  108. package/dist/orchestrator/templates/ai-instructions/claude-skill-tc-generation.md +25 -1
  109. package/dist/orchestrator/templates/ai-instructions/github-skill-sungen-delivery.md +10 -0
  110. package/dist/orchestrator/templates/ai-instructions/github-skill-sungen-harness-audit.md +1 -1
  111. package/dist/orchestrator/templates/ai-instructions/github-skill-sungen-ingest-legacy.md +79 -0
  112. package/dist/orchestrator/templates/ai-instructions/github-skill-sungen-tc-generation.md +44 -7
  113. package/dist/orchestrator/templates/specs-db.d.ts +18 -0
  114. package/dist/orchestrator/templates/specs-db.d.ts.map +1 -0
  115. package/dist/orchestrator/templates/specs-db.js +171 -0
  116. package/dist/orchestrator/templates/specs-db.js.map +1 -0
  117. package/dist/orchestrator/templates/specs-db.ts +147 -0
  118. package/docs/orchestration-spec.md +3 -3
  119. package/package.json +4 -4
  120. package/src/cli/commands/audit.ts +19 -0
  121. package/src/cli/commands/delivery.ts +31 -15
  122. package/src/cli/commands/eval.ts +28 -0
  123. package/src/cli/commands/ingest.ts +141 -0
  124. package/src/cli/index.ts +4 -0
  125. package/src/dashboard/templates/index.html +108 -194
  126. package/src/generators/test-generator/adapters/adapter-interface.ts +1 -1
  127. package/src/generators/test-generator/adapters/playwright/playwright-adapter.ts +1 -1
  128. package/src/generators/test-generator/adapters/playwright/templates/imports.hbs +3 -0
  129. package/src/generators/test-generator/code-generator.ts +29 -2
  130. package/src/generators/test-generator/patterns/database-patterns.ts +95 -0
  131. package/src/generators/test-generator/patterns/index.ts +3 -0
  132. package/src/generators/test-generator/template-engine.ts +2 -2
  133. package/src/harness/audit.ts +82 -5
  134. package/src/harness/capability-plan.ts +12 -1
  135. package/src/harness/catalog/drivers.yaml +1 -1
  136. package/src/harness/catalog/universal-viewpoints.yaml +1 -1
  137. package/src/harness/eval/skill-lint.ts +87 -0
  138. package/src/harness/flow-plan.ts +1 -1
  139. package/src/harness/parse.ts +19 -3
  140. package/src/harness/quality-gates.ts +152 -0
  141. package/src/harness/script-check.ts +4 -1
  142. package/src/harness/sensors.ts +84 -7
  143. package/src/harness/spec-coverage.ts +139 -0
  144. package/src/harness/viewpoint-ledger.ts +80 -0
  145. package/src/ingest/baseline-audit.ts +100 -0
  146. package/src/ingest/gsheet-fetch.ts +152 -0
  147. package/src/ingest/index.ts +5 -0
  148. package/src/ingest/legacy-parser.ts +184 -0
  149. package/src/ingest/reconcile.ts +80 -0
  150. package/src/ingest/to-gherkin.ts +108 -0
  151. package/src/orchestrator/ai-rules-updater.ts +2 -0
  152. package/src/orchestrator/templates/ai-instructions/claude-agent-reviewer.md +1 -0
  153. package/src/orchestrator/templates/ai-instructions/claude-skill-delivery.md +10 -0
  154. package/src/orchestrator/templates/ai-instructions/claude-skill-harness-audit.md +1 -1
  155. package/src/orchestrator/templates/ai-instructions/claude-skill-ingest-legacy.md +79 -0
  156. package/src/orchestrator/templates/ai-instructions/claude-skill-tc-generation.md +25 -1
  157. package/src/orchestrator/templates/ai-instructions/github-skill-sungen-delivery.md +10 -0
  158. package/src/orchestrator/templates/ai-instructions/github-skill-sungen-harness-audit.md +1 -1
  159. package/src/orchestrator/templates/ai-instructions/github-skill-sungen-ingest-legacy.md +79 -0
  160. package/src/orchestrator/templates/ai-instructions/github-skill-sungen-tc-generation.md +44 -7
  161. package/src/orchestrator/templates/specs-db.ts +147 -0
@@ -0,0 +1,141 @@
1
+ import { Command } from 'commander';
2
+ import * as path from 'path';
3
+ import * as fs from 'fs';
4
+ import { parseLegacyFile, listSheets, baselineAudit, BaselineReport, LegacyInventory, inventoryToGherkin, reconcileViewpoints, renderViewpointOverview, fetchGoogleSheet } from '../../ingest';
5
+
6
+ function renderInventoryMd(inv: LegacyInventory, r: BaselineReport): string {
7
+ const lines: string[] = [];
8
+ lines.push(`# Legacy Testcase Inventory — ${inv.source.file}`, '');
9
+ lines.push(`Total testcases: **${r.total}**`, '');
10
+ lines.push('## Sheets', '', '| Sheet | Type | Rows |', '|---|---|---|');
11
+ for (const s of r.sheets) lines.push(`| ${s.name} | ${s.type} | ${s.rows} |`);
12
+ lines.push('', '## By category', '');
13
+ for (const [k, v] of Object.entries(r.byCategory).sort((a, b) => b[1] - a[1])) lines.push(`- ${k}: ${v}`);
14
+ lines.push('', `Depth: **${(r.depthRatio * 100).toFixed(0)}%** (${r.deepCount}/${r.total} assert a concrete expected value)`, '');
15
+ return lines.join('\n');
16
+ }
17
+
18
+ function render(inv: LegacyInventory, r: BaselineReport): void {
19
+ const L = console.log;
20
+ const pct = (x: number) => (r.total ? Math.round((x / r.total) * 100) : 0);
21
+ L('');
22
+ L(`━━━ Legacy Ingest — ${inv.source.file} ━━━`);
23
+ L('');
24
+ L(` Sheets:`);
25
+ for (const s of r.sheets) L(` • ${s.name} — ${s.type} (${s.rows})`);
26
+ L('');
27
+ L(` TOTAL testcases: ${r.total}`);
28
+ L('');
29
+ L(' ── QA baseline ──');
30
+ L(` By category: ${Object.entries(r.byCategory).sort((a, b) => b[1] - a[1]).slice(0, 12).map(([k, v]) => `${k}=${v}`).join(' ')}`);
31
+ L(` By priority: ${Object.entries(r.byPriority).map(([k, v]) => `${k}=${v}`).join(' ')}`);
32
+ L(` By result: ${Object.entries(r.byResult).map(([k, v]) => `${k}=${v}`).join(' ')}`);
33
+ L(` Depth: ${r.deepCount}/${r.total} (${(r.depthRatio * 100).toFixed(0)}%) assert a concrete expected value → convert to DEEP Gherkin`);
34
+ L(` Duplicates: ${r.duplicateClusters} same-shape cluster(s), ${r.exactDuplicates} likely exact`);
35
+ L('');
36
+ L(' ── Capability Plan (which driver, if any) ──');
37
+ L(` UI automatable : ${r.reasons.ui} (${pct(r.reasons.ui)}%)`);
38
+ L(` cross-screen → flow : ${r.reasons.crossScreen} (${pct(r.reasons.crossScreen)}%)`);
39
+ L(` capability-manual : ${r.reasons.capabilityManual} (${pct(r.reasons.capabilityManual)}%)`);
40
+ L(` keep-manual : ${r.reasons.keepManual} (${pct(r.reasons.keepManual)}%)`);
41
+ if (r.reasons.driverCandidates.length)
42
+ L(` driver candidates : ${r.reasons.driverCandidates.map((d) => `${d.driver}×${d.count}`).join(' ')}`);
43
+ else
44
+ L(` driver candidates : none (no capability-manual at scale → no driver justified)`);
45
+ L('');
46
+ }
47
+
48
+ export function registerIngestCommand(program: Command): void {
49
+ program
50
+ .command('ingest')
51
+ .description('Ingest a legacy manual testcase workbook (CSV/XLSX/JSON-bundle) → normalized inventory + QA baseline audit')
52
+ .option('--legacy <file...>', 'Path(s) to the legacy testcase file(s): .csv, .xlsx, or a .json sheet-bundle')
53
+ .option('--gsheet <urlOrId>', 'Fetch a Google Sheet (all tabs) under YOUR Google identity (ADC, read-only) → bundle. Needs: npm i googleapis + gcloud auth application-default login')
54
+ .option('-s, --screen <name>', 'Screen name (output goes under qa/screens/<name>/requirements/legacy/)')
55
+ .option('--out <dir>', 'Output directory (overrides the default screen path)')
56
+ .option('--sheets <names>', 'Comma-separated tab names to ingest (default: all). Workbooks carry many tabs.')
57
+ .option('--list-sheets', 'List the tabs + detected type (testcase/viewpoint-matrix/ui-checklist) and exit')
58
+ .option('--emit-gherkin', 'Also emit a traceable Gherkin DRAFT (.legacy-draft.feature) + trace map (P-B)')
59
+ .option('--json', 'Print the raw inventory + baseline JSON')
60
+ .action(async (options) => {
61
+ try {
62
+ if (!options.legacy && !options.gsheet) throw new Error('Provide --legacy <file...> or --gsheet <url|id>');
63
+
64
+ const outDir = options.out
65
+ ? path.resolve(process.cwd(), options.out)
66
+ : options.screen
67
+ ? path.join(process.cwd(), 'qa', 'screens', options.screen, 'requirements', 'legacy')
68
+ : path.join(process.cwd(), '.sungen', 'legacy');
69
+ fs.mkdirSync(outDir, { recursive: true });
70
+
71
+ let files: string[];
72
+ if (options.gsheet) {
73
+ // Fetch as the user (not AI) — bypasses the AI-context DLP legitimately.
74
+ const bundle = await fetchGoogleSheet(String(options.gsheet));
75
+ const bundlePath = path.join(outDir, 'bundle.json');
76
+ fs.writeFileSync(bundlePath, JSON.stringify(bundle, null, 0));
77
+ console.log(` Fetched Google Sheet "${bundle.source}" → ${bundle.sheets.length} tab(s) → ${path.relative(process.cwd(), bundlePath)}`);
78
+ files = [bundlePath];
79
+ } else {
80
+ files = (Array.isArray(options.legacy) ? options.legacy : [options.legacy])
81
+ .map((f: string) => path.resolve(process.cwd(), f));
82
+ for (const f of files) if (!fs.existsSync(f)) throw new Error(`File not found: ${f}`);
83
+ }
84
+
85
+ if (options.listSheets) {
86
+ const sheets = await listSheets(files);
87
+ console.log('');
88
+ console.log(' Tabs found:');
89
+ for (const s of sheets) console.log(` • ${s.name} — ${s.type} (${s.rows} rows)`);
90
+ console.log('');
91
+ console.log(` Ingest the testcase tab(s) with: --sheets "${sheets.filter((s) => s.type === 'testcase').map((s) => s.name).join(',')}"`);
92
+ console.log('');
93
+ return;
94
+ }
95
+
96
+ const onlySheets: string[] | undefined = options.sheets ? String(options.sheets).split(',') : undefined;
97
+ const inv = await parseLegacyFile(files, onlySheets);
98
+ const report = baselineAudit(inv);
99
+ fs.writeFileSync(path.join(outDir, 'inventory.json'), JSON.stringify({ inventory: inv, baseline: report }, null, 2));
100
+ fs.writeFileSync(path.join(outDir, 'inventory.md'), renderInventoryMd(inv, report));
101
+
102
+ let convert;
103
+ let recon;
104
+ if (options.emitGherkin) {
105
+ const featureName = options.screen || (files.length === 1 ? path.basename(files[0]).replace(/\.[^.]+$/, '') : 'legacy');
106
+ convert = inventoryToGherkin(inv, featureName);
107
+ fs.writeFileSync(path.join(outDir, `${featureName}.legacy-draft.feature`), convert.feature);
108
+ fs.writeFileSync(path.join(outDir, 'legacy-trace.json'), JSON.stringify(convert.trace, null, 2));
109
+ // Viewpoint reconciliation: legacy coverage vs catalog → blind-spots (P-C)
110
+ recon = reconcileViewpoints(inv);
111
+ fs.writeFileSync(path.join(outDir, 'test-viewpoint.draft.md'), renderViewpointOverview(featureName, recon));
112
+ }
113
+
114
+ if (options.json) console.log(JSON.stringify({ inventory: inv, baseline: report, convert, reconciliation: recon }, null, 2));
115
+ else {
116
+ render(inv, report);
117
+ if (convert) {
118
+ const g = convert.gap;
119
+ console.log(' ── Gherkin draft (P-B) ──');
120
+ console.log(` ${g.total} scenario(s) drafted → ui=${g.ui} · cross-screen=${g.crossScreen} · @manual(capability)=${g.manualCapability} · @manual(keep)=${g.manualKeep}`);
121
+ if (g.noExpected) console.log(` ⚠ ${g.noExpected} testcase(s) without an Expected → needs review`);
122
+ console.log(` Draft: ${path.relative(process.cwd(), outDir)}/*.legacy-draft.feature (refine via /sungen:create-test)`);
123
+ }
124
+ if (recon) {
125
+ console.log(' ── Viewpoint reconciliation (legacy vs catalog) ──');
126
+ console.log(` page-type: ${recon.pageType ?? 'unknown'} · legacy covers ${recon.themesCovered}/${recon.themesTotal} catalog themes (${(recon.coverageRatio * 100).toFixed(0)}%)`);
127
+ if (recon.blindSpots.length)
128
+ console.log(` ⚠ BLIND-SPOTS (catalog expects, legacy lacks): ${recon.blindSpots.map((b) => `${b.theme}[${b.status}]`).join(', ')}`);
129
+ else
130
+ console.log(` ✓ no catalog blind-spots — legacy covers the expected themes`);
131
+ console.log(` Draft viewpoint: ${path.relative(process.cwd(), outDir)}/test-viewpoint.draft.md → seed /sungen:create-test`);
132
+ }
133
+ console.log(` Inventory: ${path.relative(process.cwd(), outDir)}/inventory.json`);
134
+ console.log('');
135
+ }
136
+ } catch (error) {
137
+ console.error('Error:', error instanceof Error ? error.message : error);
138
+ process.exit(1);
139
+ }
140
+ });
141
+ }
package/src/cli/index.ts CHANGED
@@ -15,6 +15,8 @@ import { registerFigmaCommand } from './commands/figma';
15
15
  import { registerAddFlowCommand } from './commands/add-flow';
16
16
  import { registerDashboardCommand } from './commands/dashboard';
17
17
  import { registerAuditCommand } from './commands/audit';
18
+ import { registerIngestCommand } from './commands/ingest';
19
+ import { registerEvalCommand } from './commands/eval';
18
20
  import { registerManifestCommand } from './commands/manifest';
19
21
  import { registerLedgerCommand } from './commands/ledger';
20
22
  import { registerFeedbackCommand } from './commands/feedback';
@@ -60,6 +62,8 @@ async function main() {
60
62
  registerBlindspotCommand(program);
61
63
  registerCapabilityCommand(program);
62
64
  registerFlowCheckCommand(program);
65
+ registerIngestCommand(program);
66
+ registerEvalCommand(program);
63
67
 
64
68
  await program.parseAsync(process.argv);
65
69
  }