@sun-asterisk/sungen 3.0.0-beta.71 → 3.0.0-beta.73

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 (86) hide show
  1. package/dist/cli/commands/capability.d.ts +3 -0
  2. package/dist/cli/commands/capability.d.ts.map +1 -0
  3. package/dist/cli/commands/capability.js +196 -0
  4. package/dist/cli/commands/capability.js.map +1 -0
  5. package/dist/cli/commands/flow-check.d.ts +3 -0
  6. package/dist/cli/commands/flow-check.d.ts.map +1 -0
  7. package/dist/cli/commands/flow-check.js +136 -0
  8. package/dist/cli/commands/flow-check.js.map +1 -0
  9. package/dist/cli/commands/generate.d.ts.map +1 -1
  10. package/dist/cli/commands/generate.js +28 -2
  11. package/dist/cli/commands/generate.js.map +1 -1
  12. package/dist/cli/commands/script-check.js +1 -1
  13. package/dist/cli/commands/script-check.js.map +1 -1
  14. package/dist/cli/index.js +4 -0
  15. package/dist/cli/index.js.map +1 -1
  16. package/dist/generators/test-generator/adapters/adapter-interface.d.ts +1 -0
  17. package/dist/generators/test-generator/adapters/adapter-interface.d.ts.map +1 -1
  18. package/dist/generators/test-generator/adapters/adapter-registry.d.ts +13 -0
  19. package/dist/generators/test-generator/adapters/adapter-registry.d.ts.map +1 -1
  20. package/dist/generators/test-generator/adapters/adapter-registry.js +73 -1
  21. package/dist/generators/test-generator/adapters/adapter-registry.js.map +1 -1
  22. package/dist/generators/test-generator/adapters/index.d.ts +1 -1
  23. package/dist/generators/test-generator/adapters/index.d.ts.map +1 -1
  24. package/dist/generators/test-generator/adapters/index.js +5 -1
  25. package/dist/generators/test-generator/adapters/index.js.map +1 -1
  26. package/dist/generators/test-generator/adapters/playwright/templates/test-file.hbs +6 -0
  27. package/dist/generators/test-generator/code-generator.d.ts.map +1 -1
  28. package/dist/generators/test-generator/code-generator.js +6 -2
  29. package/dist/generators/test-generator/code-generator.js.map +1 -1
  30. package/dist/generators/test-generator/patterns/form-patterns.d.ts.map +1 -1
  31. package/dist/generators/test-generator/patterns/form-patterns.js +3 -1
  32. package/dist/generators/test-generator/patterns/form-patterns.js.map +1 -1
  33. package/dist/generators/test-generator/utils/runtime-data-transformer.d.ts.map +1 -1
  34. package/dist/generators/test-generator/utils/runtime-data-transformer.js +4 -0
  35. package/dist/generators/test-generator/utils/runtime-data-transformer.js.map +1 -1
  36. package/dist/generators/test-generator/utils/selector-resolver.d.ts.map +1 -1
  37. package/dist/generators/test-generator/utils/selector-resolver.js +12 -6
  38. package/dist/generators/test-generator/utils/selector-resolver.js.map +1 -1
  39. package/dist/harness/capability-plan.d.ts +49 -0
  40. package/dist/harness/capability-plan.d.ts.map +1 -0
  41. package/dist/harness/capability-plan.js +215 -0
  42. package/dist/harness/capability-plan.js.map +1 -0
  43. package/dist/harness/capability.d.ts +23 -0
  44. package/dist/harness/capability.d.ts.map +1 -0
  45. package/dist/harness/capability.js +98 -0
  46. package/dist/harness/capability.js.map +1 -0
  47. package/dist/harness/catalog/drivers.yaml +57 -0
  48. package/dist/harness/flow-check.d.ts +23 -0
  49. package/dist/harness/flow-check.d.ts.map +1 -0
  50. package/dist/harness/flow-check.js +132 -0
  51. package/dist/harness/flow-check.js.map +1 -0
  52. package/dist/harness/flow-plan.d.ts +23 -0
  53. package/dist/harness/flow-plan.d.ts.map +1 -0
  54. package/dist/harness/flow-plan.js +166 -0
  55. package/dist/harness/flow-plan.js.map +1 -0
  56. package/dist/harness/script-check.d.ts +23 -0
  57. package/dist/harness/script-check.d.ts.map +1 -1
  58. package/dist/harness/script-check.js +88 -6
  59. package/dist/harness/script-check.js.map +1 -1
  60. package/dist/orchestrator/project-initializer.d.ts +5 -0
  61. package/dist/orchestrator/project-initializer.d.ts.map +1 -1
  62. package/dist/orchestrator/project-initializer.js +20 -0
  63. package/dist/orchestrator/project-initializer.js.map +1 -1
  64. package/dist/orchestrator/templates/specs-test-data.ts +11 -6
  65. package/package.json +3 -2
  66. package/src/cli/commands/capability.ts +160 -0
  67. package/src/cli/commands/flow-check.ts +97 -0
  68. package/src/cli/commands/generate.ts +28 -2
  69. package/src/cli/commands/script-check.ts +1 -1
  70. package/src/cli/index.ts +4 -0
  71. package/src/generators/test-generator/adapters/adapter-interface.ts +1 -0
  72. package/src/generators/test-generator/adapters/adapter-registry.ts +37 -0
  73. package/src/generators/test-generator/adapters/index.ts +4 -1
  74. package/src/generators/test-generator/adapters/playwright/templates/test-file.hbs +6 -0
  75. package/src/generators/test-generator/code-generator.ts +6 -2
  76. package/src/generators/test-generator/patterns/form-patterns.ts +3 -1
  77. package/src/generators/test-generator/utils/runtime-data-transformer.ts +8 -0
  78. package/src/generators/test-generator/utils/selector-resolver.ts +13 -6
  79. package/src/harness/capability-plan.ts +180 -0
  80. package/src/harness/capability.ts +75 -0
  81. package/src/harness/catalog/drivers.yaml +57 -0
  82. package/src/harness/flow-check.ts +99 -0
  83. package/src/harness/flow-plan.ts +135 -0
  84. package/src/harness/script-check.ts +79 -6
  85. package/src/orchestrator/project-initializer.ts +23 -0
  86. package/src/orchestrator/templates/specs-test-data.ts +11 -6
@@ -0,0 +1,215 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.MANUAL_REASONS = void 0;
37
+ exports.parseScenarios = parseScenarios;
38
+ exports.inferReasonCode = inferReasonCode;
39
+ exports.buildPlan = buildPlan;
40
+ /**
41
+ * Capability Planner (Phase 2b) — deterministic, recommend-only.
42
+ *
43
+ * Classifies each scenario's execution mode + each @manual case by reason code
44
+ * (M1–M9), maps capability-reasons to drivers, and emits the manual-reason KPI.
45
+ * Never installs anything (that's `sungen capability add`). See
46
+ * reports/sungen_phase2b_spec.md.
47
+ */
48
+ const fs = __importStar(require("fs"));
49
+ const path = __importStar(require("path"));
50
+ const capability_1 = require("./capability");
51
+ exports.MANUAL_REASONS = {
52
+ M1: { code: 'M1', label: 'Missing data setup', cls: 'capability', drivers: ['data-factory'] },
53
+ M2: { code: 'M2', label: 'Missing API/DB assertion', cls: 'capability', drivers: ['api', 'db'] },
54
+ M3: { code: 'M3', label: 'Missing mock/network control', cls: 'capability', drivers: ['mock'] },
55
+ M4: { code: 'M4', label: 'Missing stable selector/test-id', cls: 'capability', drivers: [] }, // locator contract, no driver
56
+ M5: { code: 'M5', label: 'External dependency', cls: 'capability', drivers: ['mail-file', 'contract'] },
57
+ M6: { code: 'M6', label: 'Visual / UX judgment', cls: 'keep', drivers: ['specialized'] },
58
+ M7: { code: 'M7', label: 'Environment limitation', cls: 'capability', drivers: [] }, // testability, no driver
59
+ M8: { code: 'M8', label: 'Not worth automating', cls: 'keep', drivers: [] },
60
+ M9: { code: 'M9', label: 'True human judgment', cls: 'keep', drivers: [] },
61
+ // Not a single-screen driver gap: automatable cross-screen via a flow (/sungen:add-flow).
62
+ XS: { code: 'XS', label: 'Cross-screen (automate via flow)', cls: 'flow', drivers: [] },
63
+ };
64
+ // Keyword inference (best-effort retrofit). Order matters — first match wins.
65
+ // Cross-screen "deferred to a flow" is checked FIRST: it is not a driver gap on
66
+ // this screen, it is handled by a flow — so it must not recommend a driver.
67
+ const INFER = [
68
+ { code: 'XS', re: /\b(deferred to a flow|cross[-\s]?screen|in a flow|via a flow)\b/i },
69
+ { code: 'M4', re: /\b(selector|test[-\s]?id|locator|data-testid)\b/i },
70
+ { code: 'M3', re: /\b(mock|stub|network|offline|slow network|intercept)\b/i },
71
+ { code: 'M2', re: /\b(api|endpoint|backend|db|database|server[-\s]?side|via api)\b/i },
72
+ { code: 'M1', re: /\b(data setup|dataset|seed|test data|empty (category|product|dataset|state)|zero products|forcing an empty|backend\/test data)\b/i },
73
+ { code: 'M5', re: /\b(external|third[-\s]?party|sandbox|email|mail|payment gateway|invoice|download)\b/i },
74
+ { code: 'M6', re: /\b(visual|responsive|layout|accessibilit|a11y|keyboard|screen reader|ux|breakpoint)\b/i },
75
+ { code: 'M7', re: /\b(environment|staging[-\s]?only|infra|env limitation)\b/i },
76
+ { code: 'M8', re: /\b(not worth|exploratory|one[-\s]?off)\b/i },
77
+ { code: 'M9', re: /\b(judgment|human|subjective|manual review)\b/i },
78
+ ];
79
+ /** Parse scenarios with their tags + the reason comment line above (for @manual). */
80
+ function parseScenarios(featurePath) {
81
+ if (!fs.existsSync(featurePath))
82
+ return [];
83
+ const lines = fs.readFileSync(featurePath, 'utf-8').split('\n');
84
+ const out = [];
85
+ for (let i = 0; i < lines.length; i++) {
86
+ const m = lines[i].match(/^\s*Scenario:\s*(.+)$/);
87
+ if (!m)
88
+ continue;
89
+ const tags = [];
90
+ let reason = '';
91
+ // Scan UP over the ADJACENT block (tag line + a directly-above reason comment).
92
+ // Stop at a blank line so section-divider comments further up aren't captured.
93
+ for (let j = i - 1; j >= 0 && j >= i - 6; j--) {
94
+ const l = lines[j].trim();
95
+ if (l === '')
96
+ break;
97
+ if (/^@/.test(l))
98
+ tags.unshift(...l.split(/\s+/).filter((t) => t.startsWith('@')));
99
+ else if (/^#/.test(l)) {
100
+ if (!reason)
101
+ reason = l.replace(/^#+\s*/, '');
102
+ }
103
+ else
104
+ break;
105
+ }
106
+ // Scan DOWN for the reason comment placed as the first line inside the body.
107
+ for (let k = i + 1; k < lines.length && k <= i + 4; k++) {
108
+ const l = lines[k].trim();
109
+ if (/^#/.test(l)) {
110
+ if (!reason)
111
+ reason = l.replace(/^#+\s*/, '');
112
+ break;
113
+ }
114
+ else if (l === '')
115
+ continue;
116
+ else
117
+ break; // a real step → stop
118
+ }
119
+ out.push({ name: m[1].trim(), tags, manual: tags.some((t) => /^@manual\b/i.test(t)), reason });
120
+ }
121
+ return out;
122
+ }
123
+ function explicitCode(tags) {
124
+ for (const t of tags) {
125
+ const m = t.match(/^@(?:manual|reason):(M[1-9])$/i);
126
+ if (m)
127
+ return m[1].toUpperCase();
128
+ }
129
+ return undefined;
130
+ }
131
+ function inferReasonCode(tags, reason) {
132
+ const ex = explicitCode(tags);
133
+ if (ex)
134
+ return { code: ex, explicit: true, unclassified: false };
135
+ for (const r of INFER)
136
+ if (r.re.test(reason))
137
+ return { code: r.code, explicit: false, unclassified: false };
138
+ return { code: 'M9', explicit: false, unclassified: true };
139
+ }
140
+ function classifyMode(tags) {
141
+ const has = (re) => tags.some((t) => re.test(t));
142
+ if (has(/^@manual\b/i))
143
+ return 'manual';
144
+ if (has(/^@hybrid$/i))
145
+ return 'hybrid';
146
+ if (has(/^@(api|apiassert)$/i))
147
+ return 'api';
148
+ if (has(/^@(mock|network)$/i))
149
+ return 'mock';
150
+ if (has(/^@dbassert$/i))
151
+ return 'dbAssert';
152
+ return 'ui';
153
+ }
154
+ function buildPlan(screenDir, screenName) {
155
+ const featurePath = path.join(screenDir, 'features', `${screenName}.feature`);
156
+ const scenarios = parseScenarios(featurePath);
157
+ const catalog = (0, capability_1.loadDriverCatalog)();
158
+ const modes = {};
159
+ const byReason = {};
160
+ const unclassified = [];
161
+ // driver → {reasonCode, scenarios}
162
+ const recByDriver = new Map();
163
+ const keepCount = {};
164
+ let capabilityManual = 0, judgmentManual = 0, crossScreen = 0;
165
+ for (const s of scenarios) {
166
+ const mode = classifyMode(s.tags);
167
+ modes[mode] = (modes[mode] || 0) + 1;
168
+ if (mode !== 'manual')
169
+ continue;
170
+ const { code, unclassified: unc } = inferReasonCode(s.tags, s.reason);
171
+ byReason[code] = (byReason[code] || 0) + 1;
172
+ if (unc)
173
+ unclassified.push({ name: s.name, reason: s.reason || '(no reason comment)' });
174
+ const def = exports.MANUAL_REASONS[code];
175
+ if (def.cls === 'flow') {
176
+ crossScreen++;
177
+ }
178
+ else if (def.cls === 'capability') {
179
+ capabilityManual++;
180
+ for (const d of def.drivers) {
181
+ const cur = recByDriver.get(d) || { reason: code, scenarios: [] };
182
+ cur.scenarios.push(s.name);
183
+ recByDriver.set(d, cur);
184
+ }
185
+ }
186
+ else {
187
+ judgmentManual++;
188
+ keepCount[code] = (keepCount[code] || 0) + 1;
189
+ }
190
+ }
191
+ const recommendations = [...recByDriver.entries()]
192
+ .map(([driver, v]) => ({
193
+ driver,
194
+ pkg: catalog[driver]?.package || `@sungen/driver-${driver}`,
195
+ reason: v.reason,
196
+ count: v.scenarios.length,
197
+ scenarios: v.scenarios,
198
+ }))
199
+ .sort((a, b) => b.count - a.count);
200
+ const manualTotal = modes['manual'] || 0;
201
+ return {
202
+ screen: screenName,
203
+ total: scenarios.length,
204
+ modes,
205
+ byReason,
206
+ unclassified,
207
+ capabilityManual,
208
+ judgmentManual,
209
+ crossScreen,
210
+ capabilityManualPct: manualTotal ? Math.round((capabilityManual / manualTotal) * 100) : 0,
211
+ recommendations,
212
+ keep: Object.entries(keepCount).map(([code, count]) => ({ code, count })).sort((a, b) => b.count - a.count),
213
+ };
214
+ }
215
+ //# sourceMappingURL=capability-plan.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capability-plan.js","sourceRoot":"","sources":["../../src/harness/capability-plan.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ export interface CapabilityProfile {
2
+ platform?: string;
3
+ enabled: string[];
4
+ source: 'capabilities.yaml' | 'absent';
5
+ }
6
+ export interface DriverMeta {
7
+ id: string;
8
+ kind: 'platform' | 'capability';
9
+ package: string;
10
+ runtime?: string;
11
+ adapter?: string;
12
+ capabilities: string[];
13
+ unblocks?: string[];
14
+ }
15
+ export declare function capabilitiesPath(cwd: string): string;
16
+ export declare function readCapabilities(cwd: string): CapabilityProfile;
17
+ export declare function writeCapabilities(cwd: string, profile: {
18
+ platform?: string;
19
+ enabled: string[];
20
+ }): string;
21
+ export declare function loadDriverCatalog(): Record<string, DriverMeta>;
22
+ export declare function driverMeta(id: string): DriverMeta | undefined;
23
+ //# sourceMappingURL=capability.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capability.d.ts","sourceRoot":"","sources":["../../src/harness/capability.ts"],"names":[],"mappings":"AAcA,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,MAAM,EAAE,mBAAmB,GAAG,QAAQ,CAAC;CACxC;AAED,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,UAAU,GAAG,YAAY,CAAC;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;CACrB;AAED,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAEpD;AAED,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,iBAAiB,CAa/D;AAED,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,EAAE,CAAA;CAAE,GAAG,MAAM,CAUxG;AAGD,wBAAgB,iBAAiB,IAAI,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAQ9D;AAED,wBAAgB,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS,CAE7D"}
@@ -0,0 +1,98 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.capabilitiesPath = capabilitiesPath;
37
+ exports.readCapabilities = readCapabilities;
38
+ exports.writeCapabilities = writeCapabilities;
39
+ exports.loadDriverCatalog = loadDriverCatalog;
40
+ exports.driverMeta = driverMeta;
41
+ /**
42
+ * Capability profile + driver catalog (harness-roadmap Phase 2a).
43
+ *
44
+ * Sungen core is runtime-agnostic: a project declares its PLATFORM driver (web →
45
+ * Playwright, mobile → Appium) + any capability drivers in qa/capabilities.yaml.
46
+ * There is no default runtime — but for back-compat, an ABSENT profile is treated
47
+ * as `web` (the bundled adapter) with a one-time notice + scaffold.
48
+ *
49
+ * This module is metadata + profile I/O only. It never installs or imports a driver.
50
+ */
51
+ const fs = __importStar(require("fs"));
52
+ const path = __importStar(require("path"));
53
+ const yaml_1 = require("yaml");
54
+ function capabilitiesPath(cwd) {
55
+ return path.join(cwd, 'qa', 'capabilities.yaml');
56
+ }
57
+ function readCapabilities(cwd) {
58
+ const p = capabilitiesPath(cwd);
59
+ if (!fs.existsSync(p))
60
+ return { platform: undefined, enabled: [], source: 'absent' };
61
+ try {
62
+ const y = (0, yaml_1.parse)(fs.readFileSync(p, 'utf-8')) || {};
63
+ return {
64
+ platform: typeof y.platform === 'string' ? y.platform : undefined,
65
+ enabled: Array.isArray(y.enabled) ? y.enabled.map(String) : [],
66
+ source: 'capabilities.yaml',
67
+ };
68
+ }
69
+ catch {
70
+ return { platform: undefined, enabled: [], source: 'absent' };
71
+ }
72
+ }
73
+ function writeCapabilities(cwd, profile) {
74
+ const p = capabilitiesPath(cwd);
75
+ fs.mkdirSync(path.dirname(p), { recursive: true });
76
+ const body = '# Sungen capability profile — which runtime/drivers this project uses.\n' +
77
+ '# platform: the runtime adapter (web → Playwright, mobile → Appium). No default.\n' +
78
+ '# enabled: drivers turned on (added via `sungen capability add <driver>`).\n\n' +
79
+ (0, yaml_1.stringify)({ platform: profile.platform, enabled: profile.enabled });
80
+ fs.writeFileSync(p, body, 'utf-8');
81
+ return p;
82
+ }
83
+ let _catalog = null;
84
+ function loadDriverCatalog() {
85
+ if (_catalog)
86
+ return _catalog;
87
+ const p = path.join(__dirname, 'catalog', 'drivers.yaml');
88
+ const y = (0, yaml_1.parse)(fs.readFileSync(p, 'utf-8'));
89
+ const out = {};
90
+ for (const [id, meta] of Object.entries(y.drivers))
91
+ out[id] = { id, ...meta };
92
+ _catalog = out;
93
+ return out;
94
+ }
95
+ function driverMeta(id) {
96
+ return loadDriverCatalog()[id];
97
+ }
98
+ //# sourceMappingURL=capability.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capability.js","sourceRoot":"","sources":["../../src/harness/capability.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8BA,4CAEC;AAED,4CAaC;AAED,8CAUC;AAGD,8CAQC;AAED,gCAEC;AA1ED;;;;;;;;;GASG;AACH,uCAAyB;AACzB,2CAA6B;AAC7B,+BAAsE;AAkBtE,SAAgB,gBAAgB,CAAC,GAAW;IAC1C,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,EAAE,mBAAmB,CAAC,CAAC;AACnD,CAAC;AAED,SAAgB,gBAAgB,CAAC,GAAW;IAC1C,MAAM,CAAC,GAAG,gBAAgB,CAAC,GAAG,CAAC,CAAC;IAChC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC;QAAE,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC;IACrF,IAAI,CAAC;QACH,MAAM,CAAC,GAAG,IAAA,YAAS,EAAC,EAAE,CAAC,YAAY,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC;QACvD,OAAO;YACL,QAAQ,EAAE,OAAO,CAAC,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS;YACjE,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE;YAC9D,MAAM,EAAE,mBAAmB;SAC5B,CAAC;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC;IAChE,CAAC;AACH,CAAC;AAED,SAAgB,iBAAiB,CAAC,GAAW,EAAE,OAAiD;IAC9F,MAAM,CAAC,GAAG,gBAAgB,CAAC,GAAG,CAAC,CAAC;IAChC,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACnD,MAAM,IAAI,GACR,0EAA0E;QAC1E,oFAAoF;QACpF,gFAAgF;QAChF,IAAA,gBAAa,EAAC,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;IAC1E,EAAE,CAAC,aAAa,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;IACnC,OAAO,CAAC,CAAC;AACX,CAAC;AAED,IAAI,QAAQ,GAAsC,IAAI,CAAC;AACvD,SAAgB,iBAAiB;IAC/B,IAAI,QAAQ;QAAE,OAAO,QAAQ,CAAC;IAC9B,MAAM,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,SAAS,EAAE,cAAc,CAAC,CAAC;IAC1D,MAAM,CAAC,GAAG,IAAA,YAAS,EAAC,EAAE,CAAC,YAAY,CAAC,CAAC,EAAE,OAAO,CAAC,CAAwD,CAAC;IACxG,MAAM,GAAG,GAA+B,EAAE,CAAC;IAC3C,KAAK,MAAM,CAAC,EAAE,EAAE,IAAI,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC;QAAE,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,EAAE,EAAE,GAAG,IAAI,EAAE,CAAC;IAC9E,QAAQ,GAAG,GAAG,CAAC;IACf,OAAO,GAAG,CAAC;AACb,CAAC;AAED,SAAgB,UAAU,CAAC,EAAU;IACnC,OAAO,iBAAiB,EAAE,CAAC,EAAE,CAAC,CAAC;AACjC,CAAC"}
@@ -0,0 +1,57 @@
1
+ # Driver Catalog (metadata only — NO driver code is bundled here).
2
+ # Lets Sungen RECOMMEND/RESOLVE a driver that may not be installed yet, and tells
3
+ # `sungen capability add` which package to install. See reports/sungen_phase2a_spec.md.
4
+ #
5
+ # kind: platform → the runtime/codegen adapter for a target (pick ONE per project)
6
+ # kind: capability → an extra ability added on top of a platform (Phase 3)
7
+ # unblocks: manual-reason codes (M1–M9) this driver can resolve (Phase 2b taxonomy)
8
+
9
+ drivers:
10
+ web:
11
+ kind: platform
12
+ package: "@sungen/driver-web" # Phase 2a: bundled Playwright adapter serves this (back-compat)
13
+ runtime: playwright
14
+ adapter: web # registry adapter name
15
+ capabilities: ["@ui"]
16
+ mobile:
17
+ kind: platform
18
+ package: "@sungen/driver-mobile"
19
+ runtime: appium
20
+ adapter: mobile
21
+ capabilities: ["@ui"]
22
+
23
+ api:
24
+ kind: capability
25
+ package: "@sungen/driver-api"
26
+ capabilities: ["@api", "@apiAssert", "@hybrid"]
27
+ unblocks: [M2]
28
+ data-factory:
29
+ kind: capability
30
+ package: "@sungen/driver-data-factory"
31
+ capabilities: ["@dataFactory"]
32
+ unblocks: [M1]
33
+ db:
34
+ kind: capability
35
+ package: "@sungen/driver-db"
36
+ capabilities: ["@dbAssert"]
37
+ unblocks: [M2]
38
+ mock:
39
+ kind: capability
40
+ package: "@sungen/driver-mock"
41
+ capabilities: ["@mock", "@network"]
42
+ unblocks: [M3]
43
+ mail-file:
44
+ kind: capability
45
+ package: "@sungen/driver-mail-file"
46
+ capabilities: ["@mail", "@file"]
47
+ unblocks: [M5]
48
+ contract:
49
+ kind: capability
50
+ package: "@sungen/driver-contract"
51
+ capabilities: ["@contract"]
52
+ unblocks: [M5]
53
+ specialized:
54
+ kind: capability
55
+ package: "@sungen/driver-specialized"
56
+ capabilities: ["@specialized"]
57
+ unblocks: [M6]
@@ -0,0 +1,23 @@
1
+ export interface Deferral {
2
+ screen: string;
3
+ scenario: string;
4
+ hint: string;
5
+ targets: string[];
6
+ verdict: 'covered' | 'shallow' | 'missing';
7
+ via?: string;
8
+ }
9
+ export interface Contract {
10
+ flow: string;
11
+ kind: 'SAME-CARD' | 'ISOLATION';
12
+ scenario?: string;
13
+ message: string;
14
+ }
15
+ export interface FlowCheckReport {
16
+ screens: string[];
17
+ flows: string[];
18
+ deferrals: Deferral[];
19
+ contracts: Contract[];
20
+ missing: number;
21
+ }
22
+ export declare function buildFlowCheck(cwd: string, onlyFlow?: string): FlowCheckReport;
23
+ //# sourceMappingURL=flow-check.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"flow-check.d.ts","sourceRoot":"","sources":["../../src/harness/flow-check.ts"],"names":[],"mappings":"AAkBA,MAAM,WAAW,QAAQ;IAAG,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,EAAE,CAAC;IAAC,OAAO,EAAE,SAAS,GAAG,SAAS,GAAG,SAAS,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE;AACzJ,MAAM,WAAW,QAAQ;IAAG,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,WAAW,GAAG,WAAW,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE;AAC/G,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,EAAE,CAAC;IAAC,KAAK,EAAE,MAAM,EAAE,CAAC;IACnC,SAAS,EAAE,QAAQ,EAAE,CAAC;IACtB,SAAS,EAAE,QAAQ,EAAE,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;CACjB;AA0BD,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,eAAe,CA+C9E"}
@@ -0,0 +1,132 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.buildFlowCheck = buildFlowCheck;
37
+ /**
38
+ * Flow first-class checks (flow_firstclass_spec).
39
+ *
40
+ * A. Deferral integrity — every screen `@manual` "deferred to a flow (X -> Y)" must
41
+ * be backed by a real flow scenario that covers Y (deeply). Otherwise the
42
+ * cross-screen (XS) manual is a hidden gap, not "flow-covered".
43
+ * B. Run-test contract — surface the fragile cross-screen patterns (same-card
44
+ * identity scope, shared-state isolation under @parallel) as explicit checks.
45
+ *
46
+ * Deterministic + read-only. No test execution, no selector resolution.
47
+ */
48
+ const fs = __importStar(require("fs"));
49
+ const path = __importStar(require("path"));
50
+ const parse_1 = require("./parse");
51
+ const capability_plan_1 = require("./capability-plan");
52
+ const KNOWN_TARGETS = ['cart', 'category', 'brand', 'detail', 'checkout', 'wishlist', 'order', 'payment', 'login'];
53
+ function listDirs(p) {
54
+ return fs.existsSync(p) ? fs.readdirSync(p, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name) : [];
55
+ }
56
+ function featurePath(base, kind, name) {
57
+ return path.join(base, 'qa', kind, name, 'features', `${name}.feature`);
58
+ }
59
+ function featureTags(fp) {
60
+ if (!fs.existsSync(fp))
61
+ return [];
62
+ for (const line of fs.readFileSync(fp, 'utf-8').split('\n')) {
63
+ const t = line.trim();
64
+ if (t.startsWith('Feature:'))
65
+ break;
66
+ if (t.startsWith('@'))
67
+ return t.split(/\s+/).filter((x) => x.startsWith('@'));
68
+ }
69
+ return [];
70
+ }
71
+ function targetsFromHint(hint) {
72
+ const h = hint.toLowerCase();
73
+ const hits = KNOWN_TARGETS.filter((k) => h.includes(k));
74
+ if (hits.length)
75
+ return hits;
76
+ // fallback: significant words after "->"
77
+ const after = h.split('->').pop() || h;
78
+ return after.split(/[^a-z]+/).filter((w) => w.length > 3 && !['home', 'page', 'flow', 'products', 'product', 'result'].includes(w));
79
+ }
80
+ function buildFlowCheck(cwd, onlyFlow) {
81
+ const screens = listDirs(path.join(cwd, 'qa', 'screens'));
82
+ const flows = (onlyFlow ? [onlyFlow] : listDirs(path.join(cwd, 'qa', 'flows')));
83
+ // Index flow scenarios (name + haystack + depth).
84
+ const flowScenarios = [];
85
+ for (const f of listDirs(path.join(cwd, 'qa', 'flows'))) {
86
+ for (const s of (0, parse_1.loadScenarios)(featurePath(cwd, 'flows', f))) {
87
+ flowScenarios.push({ flow: f, name: s.name, haystack: s.haystack, deep: s.hasDataAssertion });
88
+ }
89
+ }
90
+ // A. Deferral integrity (screens).
91
+ const deferrals = [];
92
+ for (const sc of screens) {
93
+ for (const s of (0, capability_plan_1.parseScenarios)(featurePath(cwd, 'screens', sc))) {
94
+ if (!s.manual || !/deferred to a flow/i.test(s.reason))
95
+ continue;
96
+ const targets = targetsFromHint(s.reason);
97
+ const matches = flowScenarios.filter((fs2) => targets.some((t) => fs2.haystack.includes(t)));
98
+ let verdict = 'missing';
99
+ let via;
100
+ if (matches.some((m) => m.deep)) {
101
+ verdict = 'covered';
102
+ via = matches.find((m) => m.deep).flow;
103
+ }
104
+ else if (matches.length) {
105
+ verdict = 'shallow';
106
+ via = matches[0].flow;
107
+ }
108
+ deferrals.push({ screen: sc, scenario: s.name, hint: s.reason, targets, verdict, via });
109
+ }
110
+ }
111
+ // B. Run-test contract (per flow).
112
+ const contracts = [];
113
+ for (const f of flows) {
114
+ const fp = featurePath(cwd, 'flows', f);
115
+ const parallel = featureTags(fp).some((t) => /^@parallel$/i.test(t));
116
+ const scs = (0, parse_1.loadScenarios)(fp);
117
+ let cartStateCount = 0;
118
+ for (const s of scs) {
119
+ const h = s.haystack;
120
+ if (/\bremember\b/.test(h) && /(add to cart|view product)/.test(h)) {
121
+ contracts.push({ flow: f, kind: 'SAME-CARD', scenario: s.name, message: 'remember + Add To Cart/View Product → scope to ONE card at run-test, else the identity proof is hollow.' });
122
+ }
123
+ if (/(add to cart|remove|\bcart\b|quantity)/.test(h))
124
+ cartStateCount++;
125
+ }
126
+ if (parallel && cartStateCount >= 2) {
127
+ contracts.push({ flow: f, kind: 'ISOLATION', message: `@parallel + ${cartStateCount} cart/state scenarios → give each a fresh browser context, else count/quantity asserts are flaky.` });
128
+ }
129
+ }
130
+ return { screens, flows, deferrals, contracts, missing: deferrals.filter((d) => d.verdict === 'missing').length };
131
+ }
132
+ //# sourceMappingURL=flow-check.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"flow-check.js","sourceRoot":"","sources":["../../src/harness/flow-check.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ import { Contract } from './flow-check';
2
+ export interface LegPlan {
3
+ screen: string;
4
+ scenarios: number;
5
+ refs: string[];
6
+ haveKeys: number;
7
+ readiness: 'ready' | 'partial' | 'missing';
8
+ touchedByAutomated: boolean;
9
+ }
10
+ export interface FlowPlan {
11
+ flow: string;
12
+ total: number;
13
+ legs: LegPlan[];
14
+ byReason: Record<string, number>;
15
+ capabilityManual: number;
16
+ judgmentManual: number;
17
+ contracts: Contract[];
18
+ readiness: 'ready' | 'not-ready';
19
+ missingLegs: string[];
20
+ plan: string[];
21
+ }
22
+ export declare function buildFlowPlan(cwd: string, flow: string): FlowPlan;
23
+ //# sourceMappingURL=flow-plan.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"flow-plan.d.ts","sourceRoot":"","sources":["../../src/harness/flow-plan.ts"],"names":[],"mappings":"AAaA,OAAO,EAAkB,QAAQ,EAAE,MAAM,cAAc,CAAC;AA4CxD,MAAM,WAAW,OAAO;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,OAAO,GAAG,SAAS,GAAG,SAAS,CAAC;IAC3C,kBAAkB,EAAE,OAAO,CAAC;CAC7B;AACD,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,OAAO,EAAE,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,gBAAgB,EAAE,MAAM,CAAC;IACzB,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,QAAQ,EAAE,CAAC;IACtB,SAAS,EAAE,OAAO,GAAG,WAAW,CAAC;IACjC,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,IAAI,EAAE,MAAM,EAAE,CAAC;CAChB;AAED,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,QAAQ,CAwDjE"}