@sun-asterisk/sungen 3.2.3-beta.3 → 3.2.4

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 (160) hide show
  1. package/dist/cli/commands/feedback.d.ts +11 -0
  2. package/dist/cli/commands/feedback.d.ts.map +1 -1
  3. package/dist/cli/commands/feedback.js +154 -57
  4. package/dist/cli/commands/feedback.js.map +1 -1
  5. package/dist/cli/commands/login.d.ts +19 -0
  6. package/dist/cli/commands/login.d.ts.map +1 -0
  7. package/dist/cli/commands/login.js +76 -0
  8. package/dist/cli/commands/login.js.map +1 -0
  9. package/dist/cli/commands/qa-feedback.d.ts +14 -0
  10. package/dist/cli/commands/qa-feedback.d.ts.map +1 -0
  11. package/dist/cli/commands/qa-feedback.js +83 -0
  12. package/dist/cli/commands/qa-feedback.js.map +1 -0
  13. package/dist/cli/index.js +4 -0
  14. package/dist/cli/index.js.map +1 -1
  15. package/dist/dashboard/snapshot-builder.d.ts.map +1 -1
  16. package/dist/dashboard/snapshot-builder.js +108 -33
  17. package/dist/dashboard/snapshot-builder.js.map +1 -1
  18. package/dist/dashboard/templates/index.html +23 -23
  19. package/dist/dashboard/types.d.ts +4 -0
  20. package/dist/dashboard/types.d.ts.map +1 -1
  21. package/dist/exporters/csv-exporter.d.ts.map +1 -1
  22. package/dist/exporters/csv-exporter.js +11 -4
  23. package/dist/exporters/csv-exporter.js.map +1 -1
  24. package/dist/exporters/feature-parser.d.ts +4 -0
  25. package/dist/exporters/feature-parser.d.ts.map +1 -1
  26. package/dist/exporters/feature-parser.js +7 -2
  27. package/dist/exporters/feature-parser.js.map +1 -1
  28. package/dist/exporters/json-exporter.d.ts.map +1 -1
  29. package/dist/exporters/json-exporter.js +11 -3
  30. package/dist/exporters/json-exporter.js.map +1 -1
  31. package/dist/exporters/playwright-report-parser.d.ts +21 -2
  32. package/dist/exporters/playwright-report-parser.d.ts.map +1 -1
  33. package/dist/exporters/playwright-report-parser.js +52 -12
  34. package/dist/exporters/playwright-report-parser.js.map +1 -1
  35. package/dist/exporters/scenario-merger.d.ts.map +1 -1
  36. package/dist/exporters/scenario-merger.js +50 -2
  37. package/dist/exporters/scenario-merger.js.map +1 -1
  38. package/dist/exporters/spec-parser.js +1 -1
  39. package/dist/exporters/spec-parser.js.map +1 -1
  40. package/dist/exporters/test-data-resolver.d.ts +7 -0
  41. package/dist/exporters/test-data-resolver.d.ts.map +1 -1
  42. package/dist/exporters/test-data-resolver.js +13 -0
  43. package/dist/exporters/test-data-resolver.js.map +1 -1
  44. package/dist/exporters/types.d.ts +6 -0
  45. package/dist/exporters/types.d.ts.map +1 -1
  46. package/dist/exporters/xlsx-exporter.d.ts.map +1 -1
  47. package/dist/exporters/xlsx-exporter.js +131 -42
  48. package/dist/exporters/xlsx-exporter.js.map +1 -1
  49. package/dist/generators/gherkin-parser/index.d.ts +15 -0
  50. package/dist/generators/gherkin-parser/index.d.ts.map +1 -1
  51. package/dist/generators/gherkin-parser/index.js +33 -1
  52. package/dist/generators/gherkin-parser/index.js.map +1 -1
  53. package/dist/generators/test-generator/adapters/appium/templates/steps/actions/check-action.hbs +29 -8
  54. package/dist/generators/test-generator/adapters/appium/templates/steps/actions/scroll-action.hbs +21 -17
  55. package/dist/generators/test-generator/adapters/appium/templates/steps/actions/toggle-action.hbs +3 -0
  56. package/dist/generators/test-generator/adapters/appium/templates/steps/actions/uncheck-action.hbs +26 -6
  57. package/dist/generators/test-generator/adapters/appium/templates/steps/assertions/is-hidden-assertion.hbs +3 -1
  58. package/dist/generators/test-generator/adapters/appium/templates/steps/assertions/visible-assertion.hbs +14 -0
  59. package/dist/generators/test-generator/adapters/appium/templates/steps/gestures/tap-top-action.hbs +3 -0
  60. package/dist/generators/test-generator/adapters/appium/templates/steps/partials/locator.hbs +9 -2
  61. package/dist/generators/test-generator/adapters/appium/templates/test-file.hbs +115 -0
  62. package/dist/generators/test-generator/adapters/playwright/templates/steps/actions/table-action-in-row.hbs +1 -1
  63. package/dist/harness/script-check.d.ts.map +1 -1
  64. package/dist/harness/script-check.js +10 -5
  65. package/dist/harness/script-check.js.map +1 -1
  66. package/dist/orchestrator/ai-skills/writer.d.ts.map +1 -1
  67. package/dist/orchestrator/ai-skills/writer.js +46 -4
  68. package/dist/orchestrator/ai-skills/writer.js.map +1 -1
  69. package/dist/orchestrator/templates/ai-src/commands/add-flow.md +52 -5
  70. package/dist/orchestrator/templates/ai-src/commands/create-test.md +7 -0
  71. package/dist/orchestrator/templates/ai-src/commands/feedback.md +6 -6
  72. package/dist/orchestrator/templates/ai-src/commands/locale.md +26 -4
  73. package/dist/orchestrator/templates/ai-src/skills/sungen-delivery/SKILL.md +5 -4
  74. package/dist/orchestrator/templates/wdio.conf.ts +39 -3
  75. package/dist/tools/sungen-api/edit-in-editor.d.ts +15 -0
  76. package/dist/tools/sungen-api/edit-in-editor.d.ts.map +1 -0
  77. package/dist/tools/sungen-api/edit-in-editor.js +85 -0
  78. package/dist/tools/sungen-api/edit-in-editor.js.map +1 -0
  79. package/dist/tools/sungen-api/feedback-client.d.ts +24 -0
  80. package/dist/tools/sungen-api/feedback-client.d.ts.map +1 -0
  81. package/dist/tools/sungen-api/feedback-client.js +53 -0
  82. package/dist/tools/sungen-api/feedback-client.js.map +1 -0
  83. package/dist/tools/sungen-api/read-stdin.d.ts +6 -0
  84. package/dist/tools/sungen-api/read-stdin.d.ts.map +1 -0
  85. package/dist/tools/sungen-api/read-stdin.js +19 -0
  86. package/dist/tools/sungen-api/read-stdin.js.map +1 -0
  87. package/dist/tools/sungen-auth/api-base-url.d.ts +14 -0
  88. package/dist/tools/sungen-auth/api-base-url.d.ts.map +1 -0
  89. package/dist/tools/sungen-auth/api-base-url.js +28 -0
  90. package/dist/tools/sungen-auth/api-base-url.js.map +1 -0
  91. package/dist/tools/sungen-auth/credentials-store.d.ts +19 -0
  92. package/dist/tools/sungen-auth/credentials-store.d.ts.map +1 -0
  93. package/dist/tools/sungen-auth/credentials-store.js +94 -0
  94. package/dist/tools/sungen-auth/credentials-store.js.map +1 -0
  95. package/dist/tools/sungen-auth/login-flow.d.ts +33 -0
  96. package/dist/tools/sungen-auth/login-flow.d.ts.map +1 -0
  97. package/dist/tools/sungen-auth/login-flow.js +107 -0
  98. package/dist/tools/sungen-auth/login-flow.js.map +1 -0
  99. package/dist/tools/sungen-auth/loopback-server.d.ts +20 -0
  100. package/dist/tools/sungen-auth/loopback-server.d.ts.map +1 -0
  101. package/dist/tools/sungen-auth/loopback-server.js +132 -0
  102. package/dist/tools/sungen-auth/loopback-server.js.map +1 -0
  103. package/dist/tools/sungen-auth/open-browser.d.ts +10 -0
  104. package/dist/tools/sungen-auth/open-browser.d.ts.map +1 -0
  105. package/dist/tools/sungen-auth/open-browser.js +43 -0
  106. package/dist/tools/sungen-auth/open-browser.js.map +1 -0
  107. package/dist/tools/sungen-auth/pkce.d.ts +13 -0
  108. package/dist/tools/sungen-auth/pkce.d.ts.map +1 -0
  109. package/dist/tools/sungen-auth/pkce.js +27 -0
  110. package/dist/tools/sungen-auth/pkce.js.map +1 -0
  111. package/dist/tools/sungen-auth/sungen-auth-types.d.ts +41 -0
  112. package/dist/tools/sungen-auth/sungen-auth-types.d.ts.map +1 -0
  113. package/dist/tools/sungen-auth/sungen-auth-types.js +7 -0
  114. package/dist/tools/sungen-auth/sungen-auth-types.js.map +1 -0
  115. package/package.json +3 -3
  116. package/src/cli/commands/feedback.ts +123 -51
  117. package/src/cli/commands/login.ts +75 -0
  118. package/src/cli/commands/qa-feedback.ts +77 -0
  119. package/src/cli/index.ts +4 -0
  120. package/src/dashboard/snapshot-builder.ts +100 -27
  121. package/src/dashboard/templates/index.html +23 -23
  122. package/src/dashboard/types.ts +5 -1
  123. package/src/exporters/csv-exporter.ts +10 -4
  124. package/src/exporters/feature-parser.ts +7 -2
  125. package/src/exporters/json-exporter.ts +11 -3
  126. package/src/exporters/playwright-report-parser.ts +50 -11
  127. package/src/exporters/scenario-merger.ts +49 -3
  128. package/src/exporters/spec-parser.ts +1 -1
  129. package/src/exporters/test-data-resolver.ts +13 -0
  130. package/src/exporters/types.ts +6 -0
  131. package/src/exporters/xlsx-exporter.ts +155 -49
  132. package/src/generators/gherkin-parser/index.ts +44 -1
  133. package/src/generators/test-generator/adapters/appium/templates/steps/actions/check-action.hbs +29 -8
  134. package/src/generators/test-generator/adapters/appium/templates/steps/actions/scroll-action.hbs +21 -17
  135. package/src/generators/test-generator/adapters/appium/templates/steps/actions/toggle-action.hbs +3 -0
  136. package/src/generators/test-generator/adapters/appium/templates/steps/actions/uncheck-action.hbs +26 -6
  137. package/src/generators/test-generator/adapters/appium/templates/steps/assertions/is-hidden-assertion.hbs +3 -1
  138. package/src/generators/test-generator/adapters/appium/templates/steps/assertions/visible-assertion.hbs +14 -0
  139. package/src/generators/test-generator/adapters/appium/templates/steps/gestures/tap-top-action.hbs +3 -0
  140. package/src/generators/test-generator/adapters/appium/templates/steps/partials/locator.hbs +9 -2
  141. package/src/generators/test-generator/adapters/appium/templates/test-file.hbs +115 -0
  142. package/src/generators/test-generator/adapters/playwright/templates/steps/actions/table-action-in-row.hbs +1 -1
  143. package/src/harness/script-check.ts +10 -5
  144. package/src/orchestrator/ai-skills/writer.ts +39 -4
  145. package/src/orchestrator/templates/ai-src/commands/add-flow.md +52 -5
  146. package/src/orchestrator/templates/ai-src/commands/create-test.md +7 -0
  147. package/src/orchestrator/templates/ai-src/commands/feedback.md +6 -6
  148. package/src/orchestrator/templates/ai-src/commands/locale.md +26 -4
  149. package/src/orchestrator/templates/ai-src/skills/sungen-delivery/SKILL.md +5 -4
  150. package/src/orchestrator/templates/wdio.conf.ts +39 -3
  151. package/src/tools/sungen-api/edit-in-editor.ts +48 -0
  152. package/src/tools/sungen-api/feedback-client.ts +62 -0
  153. package/src/tools/sungen-api/read-stdin.ts +15 -0
  154. package/src/tools/sungen-auth/api-base-url.ts +23 -0
  155. package/src/tools/sungen-auth/credentials-store.ts +57 -0
  156. package/src/tools/sungen-auth/login-flow.ts +135 -0
  157. package/src/tools/sungen-auth/loopback-server.ts +113 -0
  158. package/src/tools/sungen-auth/open-browser.ts +42 -0
  159. package/src/tools/sungen-auth/pkce.ts +27 -0
  160. package/src/tools/sungen-auth/sungen-auth-types.ts +45 -0
@@ -0,0 +1,33 @@
1
+ /**
2
+ * The 6-call RFC 8252 CLI login flow against FastSchema v0.13.0.
3
+ *
4
+ * Base path is /api/auth (verified live against the running v0.13.0 server;
5
+ * the earlier /api/user/auth contract was wrong). PKCE-S256 + single-use
6
+ * one-time code; the JWT is minted server-side
7
+ * and only delivered via the server-to-server `exchange` — it never appears in
8
+ * the browser. This module does NO disk I/O so it stays unit-testable.
9
+ */
10
+ import type { PkceMaterial } from './sungen-auth-types';
11
+ export interface LoginFlowDeps {
12
+ apiBaseUrl: string;
13
+ pkce: PkceMaterial;
14
+ correlation: string;
15
+ redirectUri: string;
16
+ /** Open the authorize URL; return false to trigger the manual-paste fallback. */
17
+ openBrowser: (url: string) => boolean;
18
+ /** Resolve with the one-time code once the loopback callback fires. */
19
+ waitForCode: (correlation: string, timeoutMs?: number) => Promise<string>;
20
+ /** Optional sink for user-facing progress lines (defaults to console.log). */
21
+ log?: (msg: string) => void;
22
+ }
23
+ export interface LoginResult {
24
+ token: string;
25
+ email: string;
26
+ expires_at?: number;
27
+ }
28
+ /**
29
+ * Run the full login flow. Throws with a clear, distinct message for each
30
+ * failure mode (feature-off, missing challenge, exchange-401, etc.).
31
+ */
32
+ export declare function runLoginFlow(deps: LoginFlowDeps): Promise<LoginResult>;
33
+ //# sourceMappingURL=login-flow.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"login-flow.d.ts","sourceRoot":"","sources":["../../../src/tools/sungen-auth/login-flow.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAIV,YAAY,EACb,MAAM,qBAAqB,CAAC;AAE7B,MAAM,WAAW,aAAa;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,YAAY,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,iFAAiF;IACjF,WAAW,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC;IACtC,uEAAuE;IACvE,WAAW,EAAE,CAAC,WAAW,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IAC1E,8EAA8E;IAC9E,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;CAC7B;AAED,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AA6BD;;;GAGG;AACH,wBAAsB,YAAY,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,WAAW,CAAC,CAmE5E"}
@@ -0,0 +1,107 @@
1
+ "use strict";
2
+ /**
3
+ * The 6-call RFC 8252 CLI login flow against FastSchema v0.13.0.
4
+ *
5
+ * Base path is /api/auth (verified live against the running v0.13.0 server;
6
+ * the earlier /api/user/auth contract was wrong). PKCE-S256 + single-use
7
+ * one-time code; the JWT is minted server-side
8
+ * and only delivered via the server-to-server `exchange` — it never appears in
9
+ * the browser. This module does NO disk I/O so it stays unit-testable.
10
+ */
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.runLoginFlow = runLoginFlow;
13
+ /** Strip a trailing slash so path joins never double up. */
14
+ function normalizeBase(url) {
15
+ return url.replace(/\/+$/, '');
16
+ }
17
+ async function postJson(url, body) {
18
+ let res;
19
+ try {
20
+ res = await fetch(url, {
21
+ method: 'POST',
22
+ headers: { 'Content-Type': 'application/json' },
23
+ body: JSON.stringify(body),
24
+ });
25
+ }
26
+ catch (err) {
27
+ throw new Error(`Network error reaching ${url}: ${err?.message ?? 'unknown'}`);
28
+ }
29
+ let data = null;
30
+ try {
31
+ const json = await res.json();
32
+ // FastSchema wraps success payloads in { data: ... } and errors in { error: ... }.
33
+ data = (json && json.data !== undefined ? json.data : json);
34
+ }
35
+ catch {
36
+ /* non-JSON body */
37
+ }
38
+ return { ok: res.ok, status: res.status, data };
39
+ }
40
+ /**
41
+ * Run the full login flow. Throws with a clear, distinct message for each
42
+ * failure mode (feature-off, missing challenge, exchange-401, etc.).
43
+ */
44
+ async function runLoginFlow(deps) {
45
+ const base = normalizeBase(deps.apiBaseUrl);
46
+ const log = deps.log ?? ((m) => console.log(m));
47
+ // 1. initiate — exchange PKCE challenge + loopback redirect for a carrier.
48
+ const init = await postJson(`${base}/api/auth/cli/initiate`, {
49
+ redirect_uri: deps.redirectUri,
50
+ correlation: deps.correlation,
51
+ code_challenge: deps.pkce.challenge,
52
+ });
53
+ if (init.status === 403) {
54
+ throw new Error('CLI login is disabled on the server (AUTH_CLI_LOGIN_ENABLED=false).');
55
+ }
56
+ if (init.status === 400) {
57
+ throw new Error('Server rejected the login request (missing/invalid PKCE challenge or redirect).');
58
+ }
59
+ if (!init.ok || !init.data?.authorize_url) {
60
+ throw new Error(`Login initiate failed (HTTP ${init.status}).`);
61
+ }
62
+ // 2. open the dashboard login page (authorize_url is a path → join with base).
63
+ const authorizeUrl = `${base}${init.data.authorize_url}`;
64
+ // Always print the URL: openBrowser reports success even when the launcher
65
+ // fails asynchronously (e.g. headless box with no xdg-open), so the paste
66
+ // path must stay visible regardless.
67
+ const opened = deps.openBrowser(authorizeUrl);
68
+ if (opened) {
69
+ log(`Opened your browser to complete login. Waiting…\nIf it didn't open, visit:\n ${authorizeUrl}`);
70
+ }
71
+ else {
72
+ log(`Open this URL in your browser to continue login:\n ${authorizeUrl}`);
73
+ }
74
+ // 3. wait for the loopback callback (asserts state===correlation inside).
75
+ const code = await deps.waitForCode(deps.correlation);
76
+ // 4. exchange the one-time code + verifier for the JWT.
77
+ const exch = await postJson(`${base}/api/auth/exchange`, {
78
+ code,
79
+ code_verifier: deps.pkce.verifier,
80
+ });
81
+ if (exch.status === 401) {
82
+ throw new Error('Token exchange rejected (code expired or verifier mismatch). Try `sungen login` again.');
83
+ }
84
+ if (!exch.ok || !exch.data?.token) {
85
+ throw new Error(`Token exchange failed (HTTP ${exch.status}).`);
86
+ }
87
+ const token = exch.data.token;
88
+ // Backend reports expiry as an ISO `expires` string; accept a numeric
89
+ // `expires_at` epoch too. Absent → rely on 401-on-expiry (single token, no refresh).
90
+ const expires_at = exch.data.expires_at ??
91
+ (exch.data.expires ? Math.floor(Date.parse(exch.data.expires) / 1000) : undefined);
92
+ // 5. confirm identity (Bearer) and capture the email.
93
+ let me;
94
+ try {
95
+ me = await fetch(`${base}/api/auth/me`, { headers: { Authorization: `Bearer ${token}` } });
96
+ }
97
+ catch (err) {
98
+ throw new Error(`Network error confirming identity: ${err?.message ?? 'unknown'}`);
99
+ }
100
+ if (!me.ok) {
101
+ throw new Error(`Logged in but identity check failed (HTTP ${me.status}).`);
102
+ }
103
+ const meJson = await me.json();
104
+ const meBody = (meJson && meJson.data !== undefined ? meJson.data : meJson);
105
+ return { token, email: meBody.email, expires_at };
106
+ }
107
+ //# sourceMappingURL=login-flow.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"login-flow.js","sourceRoot":"","sources":["../../../src/tools/sungen-auth/login-flow.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Single-shot loopback HTTP listener for the CLI login redirect.
3
+ *
4
+ * Binds 127.0.0.1 on an ephemeral port, waits for exactly one
5
+ * GET /callback?code=<otc>&state=<correlation>, asserts state===correlation
6
+ * (CSRF guard), shows a "you may close this tab" page, then closes.
7
+ */
8
+ export interface Loopback {
9
+ /** The ephemeral port the listener bound to. */
10
+ port: number;
11
+ /** Full redirect_uri to hand to the backend (http://127.0.0.1:<port>/callback). */
12
+ redirectUri: string;
13
+ /** Resolve with the one-time code once the browser hits /callback; reject on timeout/mismatch. */
14
+ waitForCode(correlation: string, timeoutMs?: number): Promise<string>;
15
+ /** Force-close the listener (idempotent). */
16
+ close(): void;
17
+ }
18
+ /** Start the loopback listener. Resolves once it is bound and ready. */
19
+ export declare function startLoopback(): Promise<Loopback>;
20
+ //# sourceMappingURL=loopback-server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loopback-server.d.ts","sourceRoot":"","sources":["../../../src/tools/sungen-auth/loopback-server.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAKH,MAAM,WAAW,QAAQ;IACvB,gDAAgD;IAChD,IAAI,EAAE,MAAM,CAAC;IACb,mFAAmF;IACnF,WAAW,EAAE,MAAM,CAAC;IACpB,kGAAkG;IAClG,WAAW,CAAC,WAAW,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACtE,6CAA6C;IAC7C,KAAK,IAAI,IAAI,CAAC;CACf;AASD,wEAAwE;AACxE,wBAAgB,aAAa,IAAI,OAAO,CAAC,QAAQ,CAAC,CAkFjD"}
@@ -0,0 +1,132 @@
1
+ "use strict";
2
+ /**
3
+ * Single-shot loopback HTTP listener for the CLI login redirect.
4
+ *
5
+ * Binds 127.0.0.1 on an ephemeral port, waits for exactly one
6
+ * GET /callback?code=<otc>&state=<correlation>, asserts state===correlation
7
+ * (CSRF guard), shows a "you may close this tab" page, then closes.
8
+ */
9
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ var desc = Object.getOwnPropertyDescriptor(m, k);
12
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
13
+ desc = { enumerable: true, get: function() { return m[k]; } };
14
+ }
15
+ Object.defineProperty(o, k2, desc);
16
+ }) : (function(o, m, k, k2) {
17
+ if (k2 === undefined) k2 = k;
18
+ o[k2] = m[k];
19
+ }));
20
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
21
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
22
+ }) : function(o, v) {
23
+ o["default"] = v;
24
+ });
25
+ var __importStar = (this && this.__importStar) || (function () {
26
+ var ownKeys = function(o) {
27
+ ownKeys = Object.getOwnPropertyNames || function (o) {
28
+ var ar = [];
29
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
30
+ return ar;
31
+ };
32
+ return ownKeys(o);
33
+ };
34
+ return function (mod) {
35
+ if (mod && mod.__esModule) return mod;
36
+ var result = {};
37
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
38
+ __setModuleDefault(result, mod);
39
+ return result;
40
+ };
41
+ })();
42
+ Object.defineProperty(exports, "__esModule", { value: true });
43
+ exports.startLoopback = startLoopback;
44
+ const http = __importStar(require("http"));
45
+ const CLOSE_PAGE = '<!doctype html><meta charset="utf-8"><title>sungen login</title>' +
46
+ '<body style="font-family:system-ui;padding:3rem;text-align:center">' +
47
+ '<h2>Login complete</h2><p>You may close this tab and return to the terminal.</p></body>';
48
+ const DEFAULT_TIMEOUT_MS = 180000;
49
+ /** Start the loopback listener. Resolves once it is bound and ready. */
50
+ function startLoopback() {
51
+ return new Promise((resolve, reject) => {
52
+ let resolveCode = null;
53
+ let rejectCode = null;
54
+ const server = http.createServer((req, res) => {
55
+ const url = new URL(req.url ?? '/', 'http://127.0.0.1');
56
+ if (url.pathname !== '/callback') {
57
+ res.writeHead(404, { Connection: 'close' }).end('not found');
58
+ return;
59
+ }
60
+ // Connection: close so the browser doesn't hold a keep-alive socket open —
61
+ // otherwise server.close() would never fire and the CLI would hang after login.
62
+ res.writeHead(200, { 'Content-Type': 'text/html', Connection: 'close' }).end(CLOSE_PAGE);
63
+ const code = url.searchParams.get('code');
64
+ const state = url.searchParams.get('state');
65
+ // Hand the parsed values to the pending waitForCode promise.
66
+ pending = { code, state };
67
+ drain();
68
+ });
69
+ // Track live sockets so shutdown() can destroy any keep-alive stragglers.
70
+ const sockets = new Set();
71
+ server.on('connection', (s) => {
72
+ sockets.add(s);
73
+ s.on('close', () => sockets.delete(s));
74
+ });
75
+ /** Close the server AND destroy lingering sockets so the event loop can drain. */
76
+ function shutdown() {
77
+ if (server.listening)
78
+ server.close();
79
+ for (const s of sockets)
80
+ s.destroy();
81
+ sockets.clear();
82
+ }
83
+ // Buffer the callback result until a waiter (with its correlation) arrives.
84
+ let pending = null;
85
+ let expectedCorrelation = null;
86
+ function drain() {
87
+ if (!pending || !resolveCode || !rejectCode || expectedCorrelation == null)
88
+ return;
89
+ const { code, state } = pending;
90
+ if (state !== expectedCorrelation) {
91
+ rejectCode(new Error('Login state mismatch — possible CSRF; aborting.'));
92
+ }
93
+ else if (!code) {
94
+ rejectCode(new Error('Login callback missing authorization code.'));
95
+ }
96
+ else {
97
+ resolveCode(code);
98
+ }
99
+ // Let the response flush first, then tear everything down.
100
+ setImmediate(shutdown);
101
+ }
102
+ server.on('error', reject);
103
+ server.listen(0, '127.0.0.1', () => {
104
+ const port = server.address().port;
105
+ resolve({
106
+ port,
107
+ redirectUri: `http://127.0.0.1:${port}/callback`,
108
+ waitForCode(correlation, timeoutMs = DEFAULT_TIMEOUT_MS) {
109
+ expectedCorrelation = correlation;
110
+ return new Promise((res, rej) => {
111
+ resolveCode = res;
112
+ rejectCode = rej;
113
+ const timer = setTimeout(() => {
114
+ shutdown();
115
+ rej(new Error(`Timed out after ${Math.round(timeoutMs / 1000)}s waiting for browser login.`));
116
+ }, timeoutMs);
117
+ timer.unref?.();
118
+ // Wrap to always clear the timer.
119
+ const origRes = resolveCode, origRej = rejectCode;
120
+ resolveCode = (c) => { clearTimeout(timer); origRes(c); };
121
+ rejectCode = (e) => { clearTimeout(timer); origRej(e); };
122
+ drain();
123
+ });
124
+ },
125
+ close() {
126
+ shutdown();
127
+ },
128
+ });
129
+ });
130
+ });
131
+ }
132
+ //# sourceMappingURL=loopback-server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loopback-server.js","sourceRoot":"","sources":["../../../src/tools/sungen-auth/loopback-server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Cross-platform "open this URL in the default browser" helper.
3
+ *
4
+ * Deliberately dependency-free — a small platform switch instead of pulling in
5
+ * the `open` npm package. Returns false on failure so the caller can fall back
6
+ * to printing the URL for manual paste.
7
+ */
8
+ /** Attempt to open `url` in the system browser. Returns true if a launcher was spawned. */
9
+ export declare function openBrowser(url: string): boolean;
10
+ //# sourceMappingURL=open-browser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"open-browser.d.ts","sourceRoot":"","sources":["../../../src/tools/sungen-auth/open-browser.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,2FAA2F;AAC3F,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CA8BhD"}
@@ -0,0 +1,43 @@
1
+ "use strict";
2
+ /**
3
+ * Cross-platform "open this URL in the default browser" helper.
4
+ *
5
+ * Deliberately dependency-free — a small platform switch instead of pulling in
6
+ * the `open` npm package. Returns false on failure so the caller can fall back
7
+ * to printing the URL for manual paste.
8
+ */
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.openBrowser = openBrowser;
11
+ const child_process_1 = require("child_process");
12
+ /** Attempt to open `url` in the system browser. Returns true if a launcher was spawned. */
13
+ function openBrowser(url) {
14
+ let command;
15
+ let args;
16
+ switch (process.platform) {
17
+ case 'darwin':
18
+ command = 'open';
19
+ args = [url];
20
+ break;
21
+ case 'win32':
22
+ // `start` is a cmd builtin; the empty "" is the window-title placeholder.
23
+ command = 'cmd';
24
+ args = ['/c', 'start', '', url];
25
+ break;
26
+ default:
27
+ command = 'xdg-open';
28
+ args = [url];
29
+ break;
30
+ }
31
+ try {
32
+ const child = (0, child_process_1.spawn)(command, args, { detached: true, stdio: 'ignore' });
33
+ // A missing launcher fails asynchronously here, after we've already returned
34
+ // true; that's why callers also print the URL rather than relying on this.
35
+ child.on('error', () => { });
36
+ child.unref();
37
+ return true;
38
+ }
39
+ catch {
40
+ return false;
41
+ }
42
+ }
43
+ //# sourceMappingURL=open-browser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"open-browser.js","sourceRoot":"","sources":["../../../src/tools/sungen-auth/open-browser.ts"],"names":[],"mappings":";AAAA;;;;;;GAMG;;AAKH,kCA8BC;AAjCD,iDAAsC;AAEtC,2FAA2F;AAC3F,SAAgB,WAAW,CAAC,GAAW;IACrC,IAAI,OAAe,CAAC;IACpB,IAAI,IAAc,CAAC;IAEnB,QAAQ,OAAO,CAAC,QAAQ,EAAE,CAAC;QACzB,KAAK,QAAQ;YACX,OAAO,GAAG,MAAM,CAAC;YACjB,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;YACb,MAAM;QACR,KAAK,OAAO;YACV,0EAA0E;YAC1E,OAAO,GAAG,KAAK,CAAC;YAChB,IAAI,GAAG,CAAC,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE,GAAG,CAAC,CAAC;YAChC,MAAM;QACR;YACE,OAAO,GAAG,UAAU,CAAC;YACrB,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;YACb,MAAM;IACV,CAAC;IAED,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,IAAA,qBAAK,EAAC,OAAO,EAAE,IAAI,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC;QACxE,6EAA6E;QAC7E,2EAA2E;QAC3E,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,GAA4B,CAAC,CAAC,CAAC;QACtD,KAAK,CAAC,KAAK,EAAE,CAAC;QACd,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * PKCE-S256 + correlation generation for the CLI login flow.
3
+ *
4
+ * The backend mandates S256 (plain is rejected). The verifier never leaves the
5
+ * process except inside the server-to-server `exchange` POST; the challenge is
6
+ * what travels to the browser side.
7
+ */
8
+ import type { PkceMaterial } from './sungen-auth-types';
9
+ /** Generate a fresh PKCE verifier + S256 challenge pair. */
10
+ export declare function generatePkce(): PkceMaterial;
11
+ /** Random opaque value used to bind the loopback callback to this attempt (CSRF guard). */
12
+ export declare function randomCorrelation(): string;
13
+ //# sourceMappingURL=pkce.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pkce.d.ts","sourceRoot":"","sources":["../../../src/tools/sungen-auth/pkce.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAOxD,4DAA4D;AAC5D,wBAAgB,YAAY,IAAI,YAAY,CAI3C;AAED,2FAA2F;AAC3F,wBAAgB,iBAAiB,IAAI,MAAM,CAE1C"}
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ /**
3
+ * PKCE-S256 + correlation generation for the CLI login flow.
4
+ *
5
+ * The backend mandates S256 (plain is rejected). The verifier never leaves the
6
+ * process except inside the server-to-server `exchange` POST; the challenge is
7
+ * what travels to the browser side.
8
+ */
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.generatePkce = generatePkce;
11
+ exports.randomCorrelation = randomCorrelation;
12
+ const crypto_1 = require("crypto");
13
+ /** base64url with padding stripped, per RFC 7636 §A. */
14
+ function base64url(buf) {
15
+ return buf.toString('base64').replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
16
+ }
17
+ /** Generate a fresh PKCE verifier + S256 challenge pair. */
18
+ function generatePkce() {
19
+ const verifier = base64url((0, crypto_1.randomBytes)(32));
20
+ const challenge = base64url((0, crypto_1.createHash)('sha256').update(verifier).digest());
21
+ return { verifier, challenge };
22
+ }
23
+ /** Random opaque value used to bind the loopback callback to this attempt (CSRF guard). */
24
+ function randomCorrelation() {
25
+ return (0, crypto_1.randomBytes)(16).toString('hex');
26
+ }
27
+ //# sourceMappingURL=pkce.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pkce.js","sourceRoot":"","sources":["../../../src/tools/sungen-auth/pkce.ts"],"names":[],"mappings":";AAAA;;;;;;GAMG;;AAWH,oCAIC;AAGD,8CAEC;AAlBD,mCAAiD;AAGjD,wDAAwD;AACxD,SAAS,SAAS,CAAC,GAAW;IAC5B,OAAO,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;AAC3F,CAAC;AAED,4DAA4D;AAC5D,SAAgB,YAAY;IAC1B,MAAM,QAAQ,GAAG,SAAS,CAAC,IAAA,oBAAW,EAAC,EAAE,CAAC,CAAC,CAAC;IAC5C,MAAM,SAAS,GAAG,SAAS,CAAC,IAAA,mBAAU,EAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC;IAC5E,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC;AACjC,CAAC;AAED,2FAA2F;AAC3F,SAAgB,iBAAiB;IAC/B,OAAO,IAAA,oBAAW,EAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;AACzC,CAAC"}
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Shared types for the sungen CLI login flow (RFC 8252 native-app login against
3
+ * a FastSchema v0.13.0 backend: PKCE-S256 + loopback redirect + one-time code).
4
+ */
5
+ /** Persisted, user-level credentials at ~/.sungen/credentials.json (mode 0600). */
6
+ export interface Credentials {
7
+ /** Bearer JWT minted by the backend exchange step. */
8
+ token: string;
9
+ /** Authenticated account email (from /api/auth/me). */
10
+ email: string;
11
+ /** Backend base URL the token was issued against (so `feedback` knows where to POST). */
12
+ api_base_url: string;
13
+ /** Unix epoch seconds when the token expires, if the backend reports it (single token, no refresh). */
14
+ expires_at?: number;
15
+ }
16
+ /** Response of POST /api/auth/cli/initiate (unwrapped from the {data} envelope). */
17
+ export interface InitiateResponse {
18
+ /** Signed carrier the dashboard login page consumes. */
19
+ carrier: string;
20
+ /** Path (not absolute) to open in the browser, e.g. /dash/login?cli=<carrier>. */
21
+ authorize_url: string;
22
+ }
23
+ /** Response of POST /api/auth/exchange (unwrapped from the {data} envelope). */
24
+ export interface ExchangeResponse {
25
+ /** Bearer JWT. */
26
+ token: string;
27
+ /** ISO expiry string the backend returns (e.g. "2026-07-08T06:42:30Z"). */
28
+ expires?: string;
29
+ /** Numeric epoch-seconds expiry, if a build reports it instead. */
30
+ expires_at?: number;
31
+ }
32
+ /** Response of GET /api/auth/me (subset we rely on, unwrapped from {data}). */
33
+ export interface MeResponse {
34
+ email: string;
35
+ }
36
+ /** PKCE material generated per login attempt; never persisted to disk. */
37
+ export interface PkceMaterial {
38
+ verifier: string;
39
+ challenge: string;
40
+ }
41
+ //# sourceMappingURL=sungen-auth-types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sungen-auth-types.d.ts","sourceRoot":"","sources":["../../../src/tools/sungen-auth/sungen-auth-types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,mFAAmF;AACnF,MAAM,WAAW,WAAW;IAC1B,sDAAsD;IACtD,KAAK,EAAE,MAAM,CAAC;IACd,uDAAuD;IACvD,KAAK,EAAE,MAAM,CAAC;IACd,yFAAyF;IACzF,YAAY,EAAE,MAAM,CAAC;IACrB,uGAAuG;IACvG,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,oFAAoF;AACpF,MAAM,WAAW,gBAAgB;IAC/B,wDAAwD;IACxD,OAAO,EAAE,MAAM,CAAC;IAChB,kFAAkF;IAClF,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,gFAAgF;AAChF,MAAM,WAAW,gBAAgB;IAC/B,kBAAkB;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,2EAA2E;IAC3E,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,mEAAmE;IACnE,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,+EAA+E;AAC/E,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,0EAA0E;AAC1E,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;CACnB"}
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ /**
3
+ * Shared types for the sungen CLI login flow (RFC 8252 native-app login against
4
+ * a FastSchema v0.13.0 backend: PKCE-S256 + loopback redirect + one-time code).
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ //# sourceMappingURL=sungen-auth-types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sungen-auth-types.js","sourceRoot":"","sources":["../../../src/tools/sungen-auth/sungen-auth-types.ts"],"names":[],"mappings":";AAAA;;;GAGG"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sun-asterisk/sungen",
3
- "version": "3.2.3-beta.3",
3
+ "version": "3.2.4",
4
4
  "description": "Deterministic E2E Test Compiler - Gherkin + Selectors → Playwright tests",
5
5
  "main": "src/index.ts",
6
6
  "types": "src/index.ts",
@@ -12,7 +12,7 @@
12
12
  "copy-templates": "mkdir -p dist/generators/test-generator/adapters/playwright/templates/steps && mkdir -p dist/generators/test-generator/templates && mkdir -p dist/orchestrator/templates && mkdir -p dist/dashboard/templates && cp -r src/generators/test-generator/adapters/playwright/templates/*.hbs dist/generators/test-generator/adapters/playwright/templates/ 2>/dev/null || true && cp -r src/generators/test-generator/adapters/playwright/templates/steps dist/generators/test-generator/adapters/playwright/templates/ && mkdir -p dist/generators/test-generator/adapters/appium/templates/steps && cp -r src/generators/test-generator/adapters/appium/templates/*.hbs dist/generators/test-generator/adapters/appium/templates/ 2>/dev/null || true && cp -r src/generators/test-generator/adapters/appium/templates/steps dist/generators/test-generator/adapters/appium/templates/ && cp src/generators/test-generator/templates/*.hbs dist/generators/test-generator/templates/ 2>/dev/null || true && cp -r src/orchestrator/templates/* dist/orchestrator/templates/ && cp src/dashboard/templates/index.html dist/dashboard/templates/index.html && mkdir -p dist/harness/catalog && cp src/harness/catalog/*.yaml dist/harness/catalog/",
13
13
  "build:dashboard": "cd ../../dashboard && npm install --silent && npm run build && cd - && cp ../../dashboard/dist/index.html src/dashboard/templates/index.html",
14
14
  "dev": "tsx src/cli/index.ts",
15
- "test": "tsx tests/golden/run.ts && tsx tests/audit/run.ts && tsx tests/ingest/run.ts && tsx tests/eval/run.ts && tsx tests/exporter/run.ts && tsx tests/exporter/feature-parser-category.run.ts && tsx tests/exporter/api-detail-sheet.run.ts && tsx tests/exporter/mobile-app-id.run.ts && tsx tests/api-runtime/base-path-url-join.run.ts && tsx tests/capabilities/run.ts && tsx tests/openapi/run.ts && tsx tests/packaging/run.ts && tsx tests/generate-hint/run.ts && tsx tests/template-assertion/run.ts && tsx tests/journey/run.ts && tsx tests/harness/serial-cascade.run.ts && tsx src/orchestrator/ai-skills/golden-skills.test.ts",
15
+ "test": "tsx tests/golden/run.ts && tsx tests/audit/run.ts && tsx tests/ingest/run.ts && tsx tests/eval/run.ts && tsx tests/exporter/run.ts && tsx tests/exporter/feature-parser-category.run.ts && tsx tests/exporter/api-detail-sheet.run.ts && tsx tests/exporter/overview-sheet.run.ts && tsx tests/exporter/delivery-divider-tcid.run.ts && tsx tests/exporter/note-expected-actual.run.ts && tsx tests/exporter/test-data-vars.run.ts && tsx tests/exporter/mobile-app-id.run.ts && tsx tests/api-runtime/base-path-url-join.run.ts && tsx tests/capabilities/run.ts && tsx tests/openapi/run.ts && tsx tests/packaging/run.ts && tsx tests/generate-hint/run.ts && tsx tests/template-assertion/run.ts && tsx tests/journey/run.ts && tsx tests/harness/serial-cascade.run.ts && tsx tests/ai-skills/cross-assistant-orphan.run.ts && tsx src/orchestrator/ai-skills/golden-skills.test.ts",
16
16
  "test:update": "tsx tests/golden/run.ts --update && tsx tests/audit/run.ts --update && tsx tests/ingest/run.ts --update",
17
17
  "prepublishOnly": "npm run build:dashboard && npm run build"
18
18
  },
@@ -33,7 +33,7 @@
33
33
  "node": ">=18.0.0"
34
34
  },
35
35
  "dependencies": {
36
- "@sungen/driver-ui": "3.2.3-beta.3",
36
+ "@sungen/driver-ui": "3.2.4",
37
37
  "@anthropic-ai/sdk": "^0.71.0",
38
38
  "@babel/parser": "^7.28.5",
39
39
  "@babel/traverse": "^7.28.5",