flowstride 1.0.6 → 1.0.7

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.
@@ -73,11 +73,11 @@ async function runAction(targetPath, options) {
73
73
  process.env.GITHUB_ACTIONS ||
74
74
  process.env.GITLAB_CI ||
75
75
  process.env.CIRCLECI ||
76
- process.env.JENKINS_URL);
76
+ process.env.JENKINS_URL ||
77
+ process.env.FLOWSTRIDE_API_KEY);
77
78
  if (isCI) {
78
79
  console.log("\n[CI/CD]: Environment detected. Engaging Smart Automation Behaviors...");
79
80
  }
80
- // The CLI (index.ts) now strictly guarantees targetPath is the absolute path to ./flows
81
81
  const resolvedPath = targetPath;
82
82
  if (!fs.existsSync(resolvedPath)) {
83
83
  console.error(`\n[Error]: Cannot find strict target path "${resolvedPath}".`);
@@ -135,12 +135,13 @@ async function runAction(targetPath, options) {
135
135
  let ActiveFlowWorker = flow_worker_1.FlowWorker;
136
136
  let ActiveFlowOrchestrator = flow_orchestrator_1.FlowOrchestrator;
137
137
  let engineMode = "Open Source";
138
- // Check the local node_modules for the Pro engine
139
138
  const proWorkerPath = path.join(process.cwd(), "node_modules", "@flowstride", "pro", "dist", "runner", "flow_worker.js");
140
139
  const proOrchPath = path.join(process.cwd(), "node_modules", "@flowstride", "pro", "dist", "runner", "flow_orchestrator.js");
141
- if (fs.existsSync(proWorkerPath) && fs.existsSync(proOrchPath)) {
140
+ // We only attempt to load the Pro Engine if the DRM Bouncer (index.ts) did NOT force OS Mode
141
+ if (!options.forceOS &&
142
+ fs.existsSync(proWorkerPath) &&
143
+ fs.existsSync(proOrchPath)) {
142
144
  try {
143
- // Dynamically load the Pro classes using native absolute URL resolution
144
145
  const proWorkerModule = await import((0, url_1.pathToFileURL)(proWorkerPath).href);
145
146
  const proOrchModule = await import((0, url_1.pathToFileURL)(proOrchPath).href);
146
147
  ActiveFlowWorker = proWorkerModule.FlowWorker;
@@ -153,7 +154,6 @@ async function runAction(targetPath, options) {
153
154
  }
154
155
  console.log(`\n[Engine]: Booting Flowstride in ${engineMode} mode...`);
155
156
  // ==========================================
156
- // Instantiate the chosen engine (OS or Pro)
157
157
  const worker = new ActiveFlowWorker(config, web, api, store, sessions, pluginManager);
158
158
  const orchestrator = new ActiveFlowOrchestrator(worker, workerCount, config);
159
159
  try {
package/dist/cli/index.js CHANGED
@@ -44,15 +44,16 @@ const init_1 = require("./commands/init");
44
44
  const fs = __importStar(require("fs"));
45
45
  const path = __importStar(require("path"));
46
46
  const os = __importStar(require("os"));
47
- const child_process_1 = require("child_process");
47
+ const tar = __importStar(require("tar"));
48
48
  const prompts_1 = require("@inquirer/prompts");
49
49
  const chalk_1 = __importDefault(require("chalk"));
50
50
  const ora_1 = __importDefault(require("ora"));
51
51
  const program = new commander_1.Command();
52
+ const API_BASE = process.env.FLOWSTRIDE_API_URL || "https://cloud.flowstride.io";
52
53
  program
53
54
  .name("flowstride")
54
55
  .description("Flowstride: The Enterprise Flow-First Automation CLI")
55
- .version("1.0.6");
56
+ .version("1.0.7");
56
57
  program
57
58
  .command("init")
58
59
  .description("Initialise a new Flowstride workspace in the current directory")
@@ -63,18 +64,41 @@ program
63
64
  .command("login")
64
65
  .description("Authenticate this machine with Flowstride Enterprise Cloud")
65
66
  .action(async () => {
67
+ const localPackageJsonPath = path.join(process.cwd(), "package.json");
68
+ if (!fs.existsSync(localPackageJsonPath)) {
69
+ console.error(chalk_1.default.red("✖ Error: Please navigate to a valid Flowstride project directory before logging in."));
70
+ process.exit(1);
71
+ }
72
+ const pkg = JSON.parse(fs.readFileSync(localPackageJsonPath, "utf8"));
73
+ const deps = {
74
+ ...(pkg.dependencies || {}),
75
+ ...(pkg.devDependencies || {}),
76
+ };
77
+ if (!deps["flowstride"] && !deps["flowstride-os"]) {
78
+ console.error(chalk_1.default.red("✖ Error: Please navigate to a valid Flowstride project directory before logging in."));
79
+ process.exit(1);
80
+ }
66
81
  console.log(chalk_1.default.bold.blue("\n🌐 Flowstride Enterprise Cloud Sync\n"));
67
- const userEmail = await (0, prompts_1.input)({ message: "Enter your Flowstride email:" });
68
- const userPass = await (0, prompts_1.password)({ message: "Enter your password:" });
82
+ let authHeader = "";
83
+ if (process.env.FLOWSTRIDE_API_KEY) {
84
+ console.log(chalk_1.default.yellow("🤖 CI/CD Environment Detected. Authenticating via API Key..."));
85
+ authHeader = `Bearer ${process.env.FLOWSTRIDE_API_KEY}`;
86
+ }
87
+ else {
88
+ const userEmail = await (0, prompts_1.input)({
89
+ message: "Enter your Flowstride email:",
90
+ });
91
+ const userPass = await (0, prompts_1.password)({ message: "Enter your password:" });
92
+ authHeader = `Basic ${Buffer.from(`${userEmail}:${userPass}`).toString("base64")}`;
93
+ }
69
94
  const deviceName = os.hostname();
70
95
  const spinner = (0, ora_1.default)("Authenticating with Cloud...").start();
71
96
  try {
72
- const authString = Buffer.from(`${userEmail}:${userPass}`).toString("base64");
73
- const response = await fetch("https://cloud.flowstride.io/api/auth/cli-sync", {
97
+ const response = await fetch(`${API_BASE}/api/auth/cli-sync`, {
74
98
  method: "POST",
75
99
  headers: {
76
100
  "Content-Type": "application/json",
77
- Authorization: `Basic ${authString}`,
101
+ Authorization: authHeader,
78
102
  },
79
103
  body: JSON.stringify({ deviceName }),
80
104
  });
@@ -84,56 +108,61 @@ program
84
108
  process.exit(1);
85
109
  }
86
110
  spinner.succeed(chalk_1.default.green("Authentication Successful!"));
87
- const configDir = path.join(os.homedir(), ".flowstride");
111
+ const configDir = path.join(process.cwd(), ".flowstride", "login");
88
112
  if (!fs.existsSync(configDir)) {
89
113
  fs.mkdirSync(configDir, { recursive: true });
90
114
  }
91
- const credentialsPath = path.join(configDir, "credentials.json");
115
+ const credentialsPath = path.join(configDir, "login.json");
92
116
  fs.writeFileSync(credentialsPath, JSON.stringify({
93
117
  machineToken: data.machineToken,
94
118
  workspaceId: data.workspaceId,
95
119
  deviceName: deviceName,
96
120
  syncedAt: new Date().toISOString(),
97
121
  }, null, 2));
98
- console.log(chalk_1.default.gray(`\nCredentials saved to ${credentialsPath}`));
122
+ console.log(chalk_1.default.gray(`\nCredentials securely scoped to ${credentialsPath}`));
99
123
  console.log(chalk_1.default.bold.green(`\n✅ Machine synchronized with Flowstride Enterprise.`));
100
- if (data.githubToken || data.isProEligible) {
124
+ if (data.isProEligible) {
101
125
  console.log(chalk_1.default.yellow(`\n⚙️ System Check: You have access to Enterprise features (AI Healing, Parallel Workers).`));
102
- const localPackageJsonPath = path.join(process.cwd(), "package.json");
103
- const nodeModulesPath = path.join(process.cwd(), "node_modules", "@heroamogs", "pro");
104
- if (fs.existsSync(localPackageJsonPath) &&
105
- !fs.existsSync(nodeModulesPath)) {
106
- const installPro = await (0, prompts_1.confirm)({
107
- message: "The Pro Engine is not installed in this project. Would you like Flowstride to automatically install it now?",
108
- default: true,
109
- });
126
+ const nodeModulesPath = path.join(process.cwd(), "node_modules", "@flowstride", "pro");
127
+ if (!fs.existsSync(nodeModulesPath)) {
128
+ let installPro = true;
129
+ if (!process.env.FLOWSTRIDE_API_KEY && !process.env.CI) {
130
+ installPro = await (0, prompts_1.confirm)({
131
+ message: "The Pro Engine is not installed in this project. Would you like Flowstride to automatically install it now?",
132
+ default: true,
133
+ });
134
+ }
110
135
  if (installPro) {
111
136
  const installSpinner = (0, ora_1.default)("Downloading Enterprise Engine via secure proxy...").start();
112
137
  const tarballPath = path.join(process.cwd(), "flowstride-pro.tgz");
113
138
  try {
114
- const tarballResponse = await fetch("https://cloud.flowstride.io/api/workspace/download-pro", {
139
+ const tarballResponse = await fetch(`${API_BASE}/api/workspace/download-pro`, {
115
140
  method: "GET",
116
- headers: {
117
- Authorization: `Bearer ${data.machineToken}`,
118
- },
141
+ headers: { Authorization: `Bearer ${data.machineToken}` },
119
142
  });
120
143
  if (!tarballResponse.ok) {
121
144
  throw new Error(`Secure proxy rejected request: ${tarballResponse.statusText}`);
122
145
  }
123
146
  const buffer = await tarballResponse.arrayBuffer();
124
147
  fs.writeFileSync(tarballPath, Buffer.from(buffer));
125
- installSpinner.stop();
126
- console.log(chalk_1.default.cyan("Starting secure local install..."));
127
- (0, child_process_1.execSync)("npm install ./flowstride-pro.tgz --save-dev", {
128
- stdio: "inherit",
129
- cwd: process.cwd(),
148
+ installSpinner.text = "Silently extracting Enterprise Engine...";
149
+ installSpinner.color = "cyan";
150
+ if (!fs.existsSync(nodeModulesPath)) {
151
+ fs.mkdirSync(nodeModulesPath, { recursive: true });
152
+ }
153
+ await tar.x({
154
+ file: tarballPath,
155
+ cwd: nodeModulesPath,
156
+ strip: 1,
130
157
  });
131
- console.log(chalk_1.default.green("\n✅ Enterprise Engine installed successfully!"));
158
+ installSpinner.succeed(chalk_1.default.green("Enterprise Engine installed successfully!"));
132
159
  }
133
160
  catch (installError) {
134
161
  installSpinner.stop();
135
- console.log(chalk_1.default.red("\n✖ Failed to install the Enterprise Engine automatically."));
136
- console.error(chalk_1.default.gray(String(installError)));
162
+ console.log(chalk_1.default.red("\n✖ Failed to install the Enterprise Engine. Please check your internet connection or verify your project configuration."));
163
+ if (fs.existsSync(nodeModulesPath)) {
164
+ fs.rmSync(nodeModulesPath, { recursive: true, force: true });
165
+ }
137
166
  }
138
167
  finally {
139
168
  if (fs.existsSync(tarballPath)) {
@@ -152,6 +181,51 @@ program
152
181
  process.exit(1);
153
182
  }
154
183
  });
184
+ program
185
+ .command("status")
186
+ .description("Display the current Flowstride CLI authentication and engine tier")
187
+ .action(async () => {
188
+ let token = process.env.FLOWSTRIDE_API_KEY || null;
189
+ const credentialsPath = path.join(process.cwd(), ".flowstride", "login", "login.json");
190
+ if (!token && fs.existsSync(credentialsPath)) {
191
+ try {
192
+ const credentials = JSON.parse(fs.readFileSync(credentialsPath, "utf8"));
193
+ token = credentials.machineToken;
194
+ }
195
+ catch (err) { }
196
+ }
197
+ if (!token) {
198
+ console.log(chalk_1.default.white("⚪ [OS]: (Local Mode / Not Logged In)"));
199
+ return;
200
+ }
201
+ try {
202
+ const response = await fetch(`${API_BASE}/api/auth/verify-cli`, {
203
+ method: "GET",
204
+ headers: { Authorization: `Bearer ${token}` },
205
+ });
206
+ if (response.status === 401) {
207
+ console.log(chalk_1.default.red("🔴 AUTH EXPIRED: Your device session was revoked or expired."));
208
+ if (fs.existsSync(credentialsPath))
209
+ fs.unlinkSync(credentialsPath);
210
+ }
211
+ else if (response.ok) {
212
+ const data = await response.json();
213
+ const tier = data.tier.toUpperCase();
214
+ if (tier === "PERSONAL") {
215
+ console.log(chalk_1.default.yellow(`🟡 [OS]: [${data.workspaceName}] (Tier: PERSONAL)`));
216
+ }
217
+ else {
218
+ console.log(chalk_1.default.green(`🟢 [PRO]: [${data.workspaceName}] (Tier: ${tier})`));
219
+ }
220
+ }
221
+ else {
222
+ console.log(chalk_1.default.yellow("🛜 OFFLINE: Unable to reach Flowstride Cloud. Enterprise Sync paused."));
223
+ }
224
+ }
225
+ catch (err) {
226
+ console.log(chalk_1.default.yellow("🛜 OFFLINE: Unable to reach Flowstride Cloud. Enterprise Sync paused."));
227
+ }
228
+ });
155
229
  program
156
230
  .command("run")
157
231
  .description("Execute all .flow automation journeys in the ./flows directory")
@@ -160,20 +234,49 @@ program
160
234
  .option("--headless <boolean>", "Run browser in headless mode", (val) => val === "true", true)
161
235
  .option("--workers <number>", "Number of parallel workers to spawn (Pro feature)")
162
236
  .action(async (options) => {
163
- const credentialsPath = path.join(os.homedir(), ".flowstride", "credentials.json");
164
- let isPro = false;
165
- if (fs.existsSync(credentialsPath)) {
237
+ let token = process.env.FLOWSTRIDE_API_KEY || null;
238
+ let forceOS = false;
239
+ const credentialsPath = path.join(process.cwd(), ".flowstride", "login", "login.json");
240
+ if (!token && fs.existsSync(credentialsPath)) {
166
241
  try {
167
242
  const credentials = JSON.parse(fs.readFileSync(credentialsPath, "utf8"));
168
- isPro = true;
169
- console.log(`[PRO]: Machine Synced to Enterprise Cloud`);
170
- }
171
- catch (err) {
172
- console.log(`[AUTH ERROR]: Invalid credentials file. Run 'flowstride login' to reconnect.`);
243
+ token = credentials.machineToken;
173
244
  }
245
+ catch (err) { }
246
+ }
247
+ if (!token) {
248
+ console.log(chalk_1.default.white("⚪ [OS]: (Local Mode / Not Logged In)"));
249
+ forceOS = true;
174
250
  }
175
251
  else {
176
- console.log(`[OS]: Local Mode (Run 'flowstride login' to sync to Enterprise Cloud)`);
252
+ try {
253
+ const response = await fetch(`${API_BASE}/api/auth/verify-cli`, {
254
+ method: "GET",
255
+ headers: { Authorization: `Bearer ${token}` },
256
+ });
257
+ if (response.status === 401) {
258
+ console.log(chalk_1.default.red("🔴 AUTH EXPIRED: Your device session was revoked or expired."));
259
+ if (fs.existsSync(credentialsPath))
260
+ fs.unlinkSync(credentialsPath);
261
+ forceOS = true;
262
+ }
263
+ else if (response.ok) {
264
+ const data = await response.json();
265
+ const tier = data.tier.toUpperCase();
266
+ if (tier === "PERSONAL") {
267
+ console.log(chalk_1.default.yellow(`🟡 [OS]: [${data.workspaceName}] (Tier: PERSONAL)`));
268
+ }
269
+ else {
270
+ console.log(chalk_1.default.green(`🟢 [PRO]: [${data.workspaceName}] (Tier: ${tier})`));
271
+ }
272
+ }
273
+ else {
274
+ forceOS = await handleOfflinePrompt();
275
+ }
276
+ }
277
+ catch (err) {
278
+ forceOS = await handleOfflinePrompt();
279
+ }
177
280
  }
178
281
  if (options.headed) {
179
282
  options.headless = false;
@@ -184,8 +287,25 @@ program
184
287
  console.error(`Flowstride requires all UI tests to be inside a './flows' directory.`);
185
288
  process.exit(1);
186
289
  }
290
+ // Inject our DRM state into options before passing to runner
291
+ options.forceOS = forceOS;
187
292
  await (0, run_1.runAction)(strictUiFlowsDir, options);
188
293
  });
294
+ async function handleOfflinePrompt() {
295
+ console.log(chalk_1.default.yellow("🛜 OFFLINE: Unable to reach Flowstride Cloud. Enterprise Sync paused."));
296
+ if (process.env.CI || process.env.FLOWSTRIDE_API_KEY) {
297
+ console.log(chalk_1.default.yellow("⚠️ CI/CD Environment: Automatically falling back to OS Engine."));
298
+ return true; // Force OS
299
+ }
300
+ const runAnyway = await (0, prompts_1.confirm)({
301
+ message: "⚠️ Execute a local OS run anyway? (Pro features are disabled on OS)",
302
+ default: true,
303
+ });
304
+ if (!runAnyway) {
305
+ process.exit(0);
306
+ }
307
+ return true; // User said yes, Force OS
308
+ }
189
309
  program
190
310
  .command("report")
191
311
  .description("Launch the interactive Debug Dashboard")
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "flowstride",
3
- "version": "1.0.6",
3
+ "version": "1.0.7",
4
4
  "description": "An opensource flowfirst test automation framework",
5
5
  "workspaces": [
6
6
  "packages/flowstride_report"
@@ -41,6 +41,7 @@
41
41
  "playwright": "^1.59.1",
42
42
  "playwright-extra": "^4.3.6",
43
43
  "puppeteer-extra-plugin-stealth": "^2.11.2",
44
+ "tar": "^7.5.16",
44
45
  "ts-node": "^10.9.2",
45
46
  "undici": "^7.25.0",
46
47
  "ws": "^8.20.1"
@@ -245,7 +245,7 @@ Error generating stack: `+o.message+`
245
245
  *
246
246
  * This source code is licensed under the ISC license.
247
247
  * See the LICENSE file in the root directory of this source tree.
248
- */const ih=O("X",[["path",{d:"M18 6 6 18",key:"1bl5f8"}],["path",{d:"m6 6 12 12",key:"d8bk6v"}]]),sh=""+new URL("flow_logo-CjiL4Lvy.png",import.meta.url).href,uh=({isTestFlowsOpen:e,setTestFlowsOpen:t})=>{const{activeView:n,setActiveView:r}=Se(),l=[{id:"Flows",icon:Qp,label:"Flows"},{id:"Logs",icon:th,label:"Logs"},{id:"Reports",icon:Pc,label:"Reports"},{id:"TestCase",icon:Lc,label:"TestCase"}];return s.jsxs("nav",{style:{width:"75px",backgroundColor:"#0d1117",borderRight:"1px solid #30363d",display:"flex",flexDirection:"column",alignItems:"center",flexShrink:0,height:"100%",overflow:"hidden"},children:[s.jsx("div",{style:{padding:"25px 0",cursor:"pointer"},onClick:()=>r("Flows"),children:s.jsx("img",{src:sh,alt:"Flowstride",style:{width:"42px",height:"auto"}})}),n==="Flows"&&s.jsxs("div",{onClick:()=>t(!e),style:{width:"100%",display:"flex",flexDirection:"column",alignItems:"center",padding:"12px 0",cursor:"pointer",color:e?"#a78bfa":"#8b949e",borderBottom:"1px solid #21262d",marginBottom:"10px"},children:[s.jsx(Yp,{size:22}),s.jsx("span",{style:{fontSize:"10px",marginTop:"4px",fontWeight:"bold"},children:e?"Hide":"Show"})]}),s.jsx("div",{style:{flex:1,width:"100%"},children:l.map(o=>{const i=n===o.id;return s.jsxs("div",{onClick:()=>r(o.id),style:{width:"100%",display:"flex",flexDirection:"column",alignItems:"center",padding:"18px 0",cursor:"pointer",backgroundColor:i?"rgba(124, 58, 237, 0.08)":"transparent",borderLeft:i?"3px solid #7c3aed":"3px solid transparent",color:i?"#a78bfa":"#8b949e",transition:"color 0.2s ease"},children:[s.jsx(o.icon,{size:22,strokeWidth:i?2.5:2}),s.jsx("span",{style:{fontSize:"10px",marginTop:"6px",fontWeight:i?"600":"400"},children:o.label})]},o.id)})}),s.jsxs("div",{style:{padding:"25px 0",width:"100%",borderTop:"1px solid #30363d",display:"flex",flexDirection:"column",alignItems:"center"},children:[s.jsx("div",{style:{width:"38px",height:"38px",borderRadius:"50%",border:"2px solid #30363d",backgroundColor:"#1f2937",display:"flex",alignItems:"center",justifyContent:"center",color:"#a78bfa",fontWeight:"bold",fontSize:"14px"},children:"OS"}),s.jsx("span",{style:{fontSize:"11px",marginTop:"10px",fontWeight:"bold",color:"#ffffff"},children:"Open Source"}),s.jsx("span",{style:{fontSize:"9px",color:"#8b949e",marginTop:"2px",textAlign:"center",padding:"0 4px"},children:"COMMUNITY EDITION"})]})]})},ah=()=>{const{currentUrls:e,pageTitles:t,browserFrames:n,testScenarios:r,activeStepId:l,setActiveStepId:o,isRunning:i,activeTestFile:u,setActiveTestFile:a}=Se();F.useEffect(()=>{if(i){const c=r.find(p=>p.steps.some(g=>g.status==="running"));c&&c.fileName!==u&&a(c.fileName)}},[r,i,u,a]);let d=i?u:null,m=l;if(l&&l.includes(":::")){const c=l.split(":::");d=c[0],m=c[1]}const y=r.filter(c=>!d||c.fileName===d).flatMap(c=>c.steps).find(c=>c.id===m),h=!i&&!!(y&&y.screenshot),x=e[u]||"about:blank",v=t[u]||"New Tab",w=n[u]||null,_=h?y.screenshot:w,f=Array.from(new Set(r.map(c=>c.fileName)));return s.jsxs("div",{style:{height:"100%",display:"flex",flexDirection:"column",backgroundColor:"#1c2128"},children:[s.jsxs("div",{onWheel:c=>{c.currentTarget.scrollLeft+=c.deltaY},style:{display:"flex",alignItems:"center",padding:"8px 8px 0 8px",gap:"4px",overflowX:"auto",overflowY:"hidden",scrollbarWidth:"none",msOverflowStyle:"none"},children:[s.jsx("style",{children:`
248
+ */const ih=O("X",[["path",{d:"M18 6 6 18",key:"1bl5f8"}],["path",{d:"m6 6 12 12",key:"d8bk6v"}]]),sh=""+new URL("flow_logo-CjiL4Lvy.png",import.meta.url).href,uh=({isTestFlowsOpen:e,setTestFlowsOpen:t})=>{const{activeView:n,setActiveView:r}=Se(),l=[{id:"Flows",icon:Qp,label:"Flows"},{id:"Logs",icon:th,label:"Logs"},{id:"Reports",icon:Pc,label:"Reports"},{id:"TestCase",icon:Lc,label:"TestCase"}];return s.jsxs("nav",{style:{width:"75px",backgroundColor:"#0d1117",borderRight:"1px solid #30363d",display:"flex",flexDirection:"column",alignItems:"center",flexShrink:0,height:"100%",overflow:"hidden"},children:[s.jsx("div",{style:{padding:"25px 0",cursor:"pointer"},onClick:()=>r("Flows"),children:s.jsx("img",{src:sh,alt:"Flowstride",style:{width:"42px",height:"auto"}})}),n==="Flows"&&s.jsxs("div",{onClick:()=>t(!e),style:{width:"100%",display:"flex",flexDirection:"column",alignItems:"center",padding:"12px 0",cursor:"pointer",color:e?"#a78bfa":"#8b949e",borderBottom:"1px solid #21262d",marginBottom:"10px"},children:[s.jsx(Yp,{size:22}),s.jsx("span",{style:{fontSize:"10px",marginTop:"4px",fontWeight:"bold"},children:e?"Hide":"Show"})]}),s.jsx("div",{style:{flex:1,width:"100%"},children:l.map(o=>{const i=n===o.id;return s.jsxs("div",{onClick:()=>r(o.id),style:{width:"100%",display:"flex",flexDirection:"column",alignItems:"center",padding:"18px 0",cursor:"pointer",backgroundColor:i?"rgba(124, 58, 237, 0.08)":"transparent",borderLeft:i?"3px solid #7c3aed":"3px solid transparent",color:i?"#a78bfa":"#8b949e",transition:"color 0.2s ease"},children:[s.jsx(o.icon,{size:22,strokeWidth:i?2.5:2}),s.jsx("span",{style:{fontSize:"10px",marginTop:"6px",fontWeight:i?"600":"400"},children:o.label})]},o.id)})}),s.jsxs("a",{href:"https://cloud.flowstride.io/register",target:"_blank",rel:"noopener noreferrer",style:{padding:"25px 0",width:"100%",borderTop:"1px solid #30363d",display:"flex",flexDirection:"column",alignItems:"center",textDecoration:"none"},children:[s.jsx("div",{style:{width:"38px",height:"38px",borderRadius:"50%",border:"2px solid #30363d",backgroundColor:"#1f2937",display:"flex",alignItems:"center",justifyContent:"center",color:"#a78bfa",fontWeight:"bold",fontSize:"14px"},children:"OS"}),s.jsx("span",{style:{fontSize:"11px",marginTop:"10px",fontWeight:"bold",color:"#ffffff"},children:"Open Source"}),s.jsx("span",{style:{fontSize:"9px",color:"#8b949e",marginTop:"2px",textAlign:"center",padding:"0 4px"},children:"COMMUNITY EDITION"})]})]})},ah=()=>{const{currentUrls:e,pageTitles:t,browserFrames:n,testScenarios:r,activeStepId:l,setActiveStepId:o,isRunning:i,activeTestFile:u,setActiveTestFile:a}=Se();F.useEffect(()=>{if(i){const c=r.find(p=>p.steps.some(g=>g.status==="running"));c&&c.fileName!==u&&a(c.fileName)}},[r,i,u,a]);let d=i?u:null,m=l;if(l&&l.includes(":::")){const c=l.split(":::");d=c[0],m=c[1]}const y=r.filter(c=>!d||c.fileName===d).flatMap(c=>c.steps).find(c=>c.id===m),h=!i&&!!(y&&y.screenshot),x=e[u]||"about:blank",v=t[u]||"New Tab",w=n[u]||null,_=h?y.screenshot:w,f=Array.from(new Set(r.map(c=>c.fileName)));return s.jsxs("div",{style:{height:"100%",display:"flex",flexDirection:"column",backgroundColor:"#1c2128"},children:[s.jsxs("div",{onWheel:c=>{c.currentTarget.scrollLeft+=c.deltaY},style:{display:"flex",alignItems:"center",padding:"8px 8px 0 8px",gap:"4px",overflowX:"auto",overflowY:"hidden",scrollbarWidth:"none",msOverflowStyle:"none"},children:[s.jsx("style",{children:`
249
249
  div::-webkit-scrollbar { display: none; }
250
250
  `}),f.length>0?f.map((c,p)=>{const g=u===c;return s.jsxs("div",{onClick:()=>a(c),style:{backgroundColor:g?"var(--fs-bg-base)":"rgba(255,255,255,0.05)",padding:"6px 15px",borderRadius:"8px 8px 0 0",display:"flex",alignItems:"center",gap:"8px",border:g?"1px solid var(--fs-border)":"1px solid transparent",borderBottom:"none",minWidth:"130px",maxWidth:"200px",flexShrink:0,cursor:"pointer",opacity:g?1:.6},children:[s.jsx(no,{size:12,color:g?"var(--fs-accent-purple)":"#8b949e",style:{flexShrink:0}}),s.jsx("span",{style:{fontSize:"10px",color:g?"white":"#8b949e",whiteSpace:"nowrap",overflow:"hidden",textOverflow:"ellipsis",fontWeight:g?"bold":"normal"},children:c})]},p)}):s.jsxs("div",{style:{backgroundColor:"var(--fs-bg-base)",padding:"6px 15px",borderRadius:"8px 8px 0 0",display:"flex",alignItems:"center",gap:"8px",border:"1px solid var(--fs-border)",borderBottom:"none",minWidth:"140px",flexShrink:0},children:[s.jsx(no,{size:12,color:"var(--fs-accent-purple)"}),s.jsx("span",{style:{fontSize:"10px",color:"white"},children:v})]})]}),s.jsxs("div",{style:{backgroundColor:"var(--fs-bg-base)",borderTop:"1px solid var(--fs-border)",padding:"6px 12px",display:"flex",alignItems:"center",gap:"12px"},children:[s.jsxs("div",{style:{display:"flex",gap:"8px",color:"#8b949e"},children:[s.jsx(Bp,{size:14}),s.jsx(or,{size:14}),s.jsx(Mc,{size:14}),s.jsx(Gp,{size:14})]}),s.jsxs("div",{style:{flex:1,backgroundColor:"#05070a",border:"1px solid var(--fs-border)",borderRadius:"15px",padding:"3px 12px",display:"flex",alignItems:"center",gap:"8px"},children:[s.jsx(Xp,{size:10,color:"#22c55e"}),s.jsx("span",{style:{fontSize:"10px",color:"#8b949e",whiteSpace:"nowrap",overflow:"hidden"},children:x})]}),s.jsxs("div",{style:{display:"flex",gap:"10px",color:"#444",borderLeft:"1px solid #333",paddingLeft:"12px"},children:[s.jsx(Zp,{size:14,color:"var(--fs-accent-purple)"}),s.jsx(lh,{size:14}),s.jsx(nh,{size:14}),s.jsx($p,{size:14})]})]}),s.jsxs("div",{style:{flex:1,margin:"10px",backgroundColor:"white",borderRadius:"4px",boxShadow:"0 4px 12px rgba(0,0,0,0.5)",display:"flex",alignItems:"center",justifyContent:"center",overflow:"hidden",position:"relative"},children:[h&&s.jsxs("div",{style:{position:"absolute",top:"12px",left:"12px",right:"12px",backgroundColor:"rgba(15, 23, 42, 0.95)",border:"1px solid rgba(167, 139, 250, 0.3)",padding:"10px 16px",borderRadius:"6px",display:"flex",justifyContent:"space-between",alignItems:"center",zIndex:30,boxShadow:"0 4px 20px rgba(0,0,0,0.4)",backdropFilter:"blur(4px)"},children:[s.jsxs("div",{style:{display:"flex",alignItems:"center",gap:"10px"},children:[s.jsx("div",{style:{backgroundColor:"rgba(167, 139, 250, 0.1)",padding:"6px",borderRadius:"4px"},children:s.jsx(Hp,{size:14,color:"#a78bfa"})}),s.jsxs("div",{children:[s.jsx("div",{style:{fontSize:"11px",fontWeight:"bold",color:"#a78bfa",textTransform:"uppercase",letterSpacing:"0.05em"},children:"Viewing Historical State"}),s.jsx("div",{style:{fontSize:"12px",color:"#e2e8f0",fontFamily:"monospace",marginTop:"2px"},children:y==null?void 0:y.command})]})]}),s.jsx("button",{onClick:()=>o(null),style:{backgroundColor:"#7c3aed",color:"white",border:"none",padding:"6px 14px",borderRadius:"4px",fontSize:"11px",fontWeight:"bold",cursor:"pointer",transition:"background 0.2s"},onMouseEnter:c=>c.currentTarget.style.backgroundColor="#6d28d9",onMouseLeave:c=>c.currentTarget.style.backgroundColor="#7c3aed",children:"Return to Live"})]}),_?s.jsx("img",{src:`data:image/png;base64,${_}`,style:{width:"100%",height:"100%",objectFit:"contain",opacity:h?.95:1},alt:"Browser frame"}):s.jsxs("div",{style:{textAlign:"center",color:"#ccc"},children:[s.jsx(no,{size:40,style:{marginBottom:"8px",opacity:.1}}),s.jsx("div",{style:{fontSize:"11px",fontWeight:500,opacity:.3},children:"WAITING FOR RENDER..."})]})]})]})},ch=()=>{const{networkLogs:e,activeNetworkTab:t,setNetworkTab:n,setSelectedLogId:r,setActiveView:l}=Se(),o=["REST","GraphQL","Network","WS"],i=e.filter(a=>t==="GraphQL"?a.url.includes("graphql"):t==="REST"?!a.url.includes("graphql")&&!a.url.includes("ws"):!0),u=a=>{r(a),l("Logs")};return s.jsxs("div",{style:{height:"100%",display:"flex",flexDirection:"column",backgroundColor:"#0d1117"},children:[s.jsx("div",{style:{display:"flex",borderBottom:"1px solid var(--fs-border)",backgroundColor:"#05070a"},children:o.map(a=>s.jsx("button",{onClick:()=>n(a),style:{padding:"10px 16px",fontSize:"11px",fontWeight:"600",background:"none",border:"none",color:t===a?"#a78bfa":"#444",borderBottom:t===a?"2px solid #7c3aed":"2px solid transparent",cursor:"pointer",transition:"all 0.2s"},children:a},a))}),s.jsxs("div",{style:{padding:"8px 12px",display:"flex",gap:"10px",alignItems:"center",borderBottom:"1px solid #161b22"},children:[s.jsxs("div",{style:{flex:1,position:"relative"},children:[s.jsx(Gi,{size:12,style:{position:"absolute",left:"8px",top:"50%",transform:"translateY(-50%)",color:"#444"}}),s.jsx("input",{type:"text",placeholder:`Filter ${t}...`,style:{width:"100%",background:"#05070a",border:"1px solid #30363d",borderRadius:"4px",padding:"4px 8px 4px 28px",fontSize:"10px",color:"white"}})]}),s.jsx(bp,{size:14,color:"#444"})]}),s.jsx("div",{style:{flex:1,overflowY:"auto"},children:i.length===0?s.jsxs("div",{style:{padding:"40px",textAlign:"center",color:"#444",fontSize:"11px"},children:["No ",t," traffic detected"]}):i.map((a,d)=>s.jsx("div",{onClick:()=>u(a.id),style:{borderBottom:"1px solid #161b22",cursor:"pointer",transition:"background 0.2s"},onMouseEnter:m=>m.currentTarget.style.backgroundColor="#161b22",onMouseLeave:m=>m.currentTarget.style.backgroundColor="transparent",children:s.jsxs("div",{style:{display:"flex",alignItems:"center",padding:"8px 12px",fontSize:"11px",gap:"10px"},children:[s.jsx("span",{style:{color:a.status<400?"#34d399":"#f87171",fontWeight:"bold",width:"25px"},children:a.status}),s.jsx("span",{style:{fontWeight:"bold",width:"35px",color:"#8b949e"},children:a.method}),s.jsx("span",{style:{flex:1,color:"white",overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"},children:a.name||a.url}),s.jsx("span",{style:{color:"#444",fontSize:"10px"},children:a.time})]})},d))})]})},dh=()=>{const{logs:e}=Se(),t=F.useRef(null);return F.useEffect(()=>{t.current&&(t.current.scrollTop=t.current.scrollHeight)},[e]),s.jsxs("div",{ref:t,style:{flex:1,backgroundColor:"#0d1117",padding:"10px 15px",fontFamily:"monospace",fontSize:"12px",overflowY:"auto",color:"#d1d5db",lineHeight:"1.5"},children:[e.length===0&&s.jsx("div",{style:{color:"#4b5563",fontStyle:"italic"},children:"System ready. Awaiting execution..."}),e.map((n,r)=>{const l=(n.type||n.status||"INFO").toUpperCase();let o="#34d399";return(n.status==="error"||n.type==="ERROR")&&(o="#f87171"),n.status==="warning"&&(o="#fbbf24"),n.type==="ACTION"&&(o="#60a5fa"),s.jsxs("div",{style:{marginBottom:"4px",display:"flex",gap:"8px"},children:[s.jsxs("span",{style:{color:"#6e7681",flexShrink:0},children:["[",n.timestamp||"--:--:--","]"]}),s.jsx("span",{style:{color:o,fontWeight:"bold",flexShrink:0,width:"55px"},children:l}),s.jsx("span",{style:{color:"#c9d1d9",wordBreak:"break-all"},children:n.summary})]},n.id||r)})]})},fh=({isRightPanelOpen:e})=>{const{logs:t,pageTitles:n,activeTestFile:r}=Se(),l=t[t.length-1],o=n[r]||"New Tab";return s.jsxs("div",{style:{position:"absolute",top:0,left:0,right:0,bottom:0,display:"flex",flexDirection:"column",backgroundColor:"var(--fs-bg-base)",overflow:"hidden"},children:[s.jsxs("div",{style:{height:"35px",backgroundColor:"#161b22",borderBottom:"1px solid var(--fs-border)",display:"flex",alignItems:"center",padding:"0 15px",fontSize:"11px",color:"#8b949e",flexShrink:0},children:[s.jsxs("div",{style:{display:"flex",alignItems:"center",gap:"8px",flex:1},children:[s.jsx("span",{style:{color:"#a78bfa",fontWeight:"bold"},children:"LOG:"}),s.jsx("span",{style:{color:"#c9d1d9",fontFamily:"monospace",overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"},children:(l==null?void 0:l.summary)||"System ready. Awaiting connection..."})]}),s.jsx("div",{style:{opacity:.5,fontStyle:"italic"},children:o})]}),s.jsxs("div",{style:{flex:1,display:"flex",overflow:"hidden"},children:[s.jsx("div",{style:{flex:1,borderRight:"1px solid var(--fs-border)",height:"100%",overflow:"hidden"},children:s.jsx(ah,{})}),s.jsxs("div",{style:{width:e?"400px":"0px",transition:"width 0.2s ease",display:"flex",flexDirection:"column",height:"100%",backgroundColor:"#0d1117",overflow:"hidden",flexShrink:0},children:[s.jsx("div",{style:{flex:1,overflow:"hidden",display:"flex",flexDirection:"column"},children:s.jsx(ch,{})}),s.jsxs("div",{style:{flex:1,borderTop:"1px solid var(--fs-border)",backgroundColor:"#0d1117",overflow:"hidden",display:"flex",flexDirection:"column"},children:[s.jsx("div",{style:{padding:"8px 15px",fontSize:"11px",fontWeight:"bold",color:"#8b949e",borderBottom:"1px solid var(--fs-border)",flexShrink:0},children:"LIVE INFO"}),s.jsx("div",{style:{flex:1,overflow:"hidden",position:"relative"},children:s.jsx(dh,{})})]})]})]})]})},ph=()=>{var h,x;const[e,t]=F.useState(null),{testScenarios:n,logs:r}=Se(),l=n.reduce((v,w)=>v+w.steps.length,0),o=n.reduce((v,w)=>v+w.steps.filter(_=>["pass","passed","success"].includes(_.status)).length,0),i=n.reduce((v,w)=>v+w.steps.filter(_=>_.status==="failed").length,0),u=n.reduce((v,w)=>{const _=w.fileName||"General";return v[_]||(v[_]=[]),v[_].push(w),v},{});let a="Verified.",d=null,m=null,y=null;if(e){const v=e.status==="failed",w=["pass","passed","success"].includes(e.status);if(m=e.screenshot,v){const f=`${e.type} ${e.description}`,c=r.slice().reverse().find(p=>p.type==="ERROR"&&p.fileName===e.fileName&&p.stepContext===f);a=c?c.summary:"Validation Failed.",!m&&((h=c==null?void 0:c.details)!=null&&h.screenshot)&&(m=c.details.screenshot),(x=c==null?void 0:c.details)!=null&&x.boundingBox&&(y=c.details.boundingBox)}else e.status==="running"?a="Executing...":w&&(a="Action verified successfully.");const _=r.slice().reverse().find(f=>(f.type==="REST"||f.type==="GRAPHQL")&&f.fileName===e.fileName);d=_?_.details:null}return s.jsxs("div",{style:{height:"100%",width:"100%",backgroundColor:"#f8fafc",overflowY:"auto",position:"relative",color:"#0f172a"},children:[s.jsxs("div",{style:{maxWidth:"1200px",margin:"0 auto",padding:"40px 20px",marginRight:e?"450px":"auto",transition:"margin-right 0.3s"},children:[s.jsxs("header",{style:{display:"flex",justifyContent:"space-between",alignItems:"flex-end",borderBottom:"1px solid #e2e8f0",paddingBottom:"24px",marginBottom:"40px"},children:[s.jsxs("div",{children:[s.jsx("h1",{style:{fontSize:"30px",fontWeight:"800",margin:0,color:"#1e293b"},children:"Flowstride Reports"}),s.jsx("p",{style:{color:"#64748b",margin:"4px 0 0 0",fontWeight:"500"},children:"Multi-Flow Execution Analysis"})]}),s.jsxs("div",{style:{display:"flex",gap:"16px"},children:[s.jsx(ro,{label:"PASSED",value:o,color:"#10b981",icon:s.jsx(Tc,{size:20})}),s.jsx(ro,{label:"FAILED",value:i,color:"#ef4444",icon:s.jsx(_c,{size:20})}),s.jsx(ro,{label:"TOTAL",value:l,color:"#3b82f6",icon:s.jsx(Pc,{size:20})})]})]}),Object.keys(u).map(v=>s.jsxs("div",{style:{marginBottom:"60px"},children:[s.jsxs("div",{style:{display:"flex",alignItems:"center",gap:"20px",marginBottom:"24px"},children:[s.jsx("div",{style:{height:"2px",flex:1,backgroundColor:"#7c3aed",opacity:.15}}),s.jsxs("div",{style:{display:"flex",alignItems:"center",gap:"10px",color:"#7c3aed",fontWeight:"900",fontSize:"11px",textTransform:"uppercase",letterSpacing:"0.1em",backgroundColor:"rgba(124, 58, 237, 0.05)",padding:"6px 16px",borderRadius:"20px",border:"1px solid rgba(124, 58, 237, 0.1)"},children:[s.jsx(Nc,{size:14})," ",v]}),s.jsx("div",{style:{height:"2px",flex:1,backgroundColor:"#7c3aed",opacity:.15}})]}),s.jsx("div",{style:{backgroundColor:"white",borderRadius:"12px",border:"1px solid #e2e8f0",boxShadow:"0 1px 3px rgba(0,0,0,0.05)",overflow:"hidden"},children:s.jsxs("table",{style:{width:"100%",borderCollapse:"collapse",textAlign:"left"},children:[s.jsx("thead",{style:{backgroundColor:"#f1f5f9",borderBottom:"1px solid #e2e8f0"},children:s.jsx("tr",{children:["S/N","Scenario","Action","Status",""].map((w,_)=>s.jsx("th",{style:{padding:"16px 24px",fontSize:"10px",fontWeight:"800",color:"#64748b",textTransform:"uppercase"},children:w},_))})}),s.jsx("tbody",{children:u[v].flatMap(w=>w.steps.map((_,f)=>s.jsxs("tr",{onClick:()=>t({..._,scenarioName:w.name,fileName:v}),style:{cursor:"pointer",borderBottom:"1px solid #f1f5f9",backgroundColor:(e==null?void 0:e.id)===_.id?"#eff6ff":"transparent"},children:[s.jsx("td",{style:{padding:"18px 24px",fontSize:"12px",color:"#94a3b8",fontFamily:"monospace",fontWeight:"bold"},children:f+1}),s.jsx("td",{style:{padding:"18px 24px",fontWeight:"600",color:"#334155"},children:w.name}),s.jsxs("td",{style:{padding:"18px 24px",fontSize:"14px",color:"#475569"},children:[s.jsx("b",{style:{color:"#7c3aed",marginRight:"8px"},children:_.type})," ",_.description]}),s.jsx("td",{style:{padding:"18px 24px"},children:s.jsx(yh,{status:_.status})}),s.jsx("td",{style:{padding:"18px 24px",textAlign:"right"},children:s.jsx(or,{size:16,color:(e==null?void 0:e.id)===_.id?"#3b82f6":"#cbd5e1",style:{transform:(e==null?void 0:e.id)===_.id?"rotate(90deg)":"none",transition:"0.2s"}})})]},_.id)))})]})})]},v))]}),s.jsx("aside",{style:{position:"fixed",top:0,right:0,height:"100%",width:"450px",backgroundColor:"white",boxShadow:"-10px 0 40px rgba(0,0,0,0.1)",borderLeft:"1px solid #e2e8f0",zIndex:100,transform:e?"translateX(0)":"translateX(100%)",transition:"transform 0.3s cubic-bezier(0.4, 0, 0.2, 1)",padding:"30px",overflowY:"auto"},children:e&&s.jsxs(s.Fragment,{children:[s.jsxs("div",{style:{display:"flex",justifyContent:"space-between",alignItems:"center",marginBottom:"32px"},children:[s.jsxs("h2",{style:{fontSize:"18px",fontWeight:"700",display:"flex",alignItems:"center",gap:"10px"},children:[s.jsx(oh,{size:18,color:"#3b82f6"})," Step Diagnostics"]}),s.jsx(ih,{onClick:()=>t(null),style:{cursor:"pointer",color:"#94a3b8"}})]}),m&&s.jsx(Rn,{label:`Visual State (${(e.status||"").toUpperCase()})`,children:s.jsx(hh,{screenshot:m,boundingBox:y})}),s.jsx(Rn,{label:"Context",children:s.jsx("div",{style:{fontWeight:"bold",color:"#1e293b"},children:e.scenarioName})}),s.jsx(Rn,{label:"Requirement Proof",children:s.jsxs("div",{style:{padding:"16px",backgroundColor:"#f8fafc",borderRadius:"8px",fontSize:"14px",fontStyle:"italic",color:"#475569",border:"1px solid #f1f5f9"},children:['"',e.type," ",e.description,'"']})}),s.jsx(Rn,{label:"Runtime Outcome",children:s.jsx("div",{style:{padding:"16px",borderRadius:"8px",fontSize:"14px",fontWeight:"500",backgroundColor:["pass","success","passed"].includes(e.status)?"#ecfdf5":"#fef2f2",color:["pass","success","passed"].includes(e.status)?"#065f46":"#991b1b",border:`1px solid ${["pass","success","passed"].includes(e.status)?"#d1fae5":"#fee2e2"}`},children:a})}),d&&s.jsx(Rn,{label:"Network Activity",children:s.jsx("div",{style:{backgroundColor:"#0f172a",padding:"16px",borderRadius:"8px",color:"#7dd3fc",fontFamily:"monospace",fontSize:"11px",overflowX:"auto"},children:s.jsx("pre",{children:JSON.stringify({status:d.responseStatus,url:d.url},null,2)})})})]})})]})},hh=({screenshot:e,boundingBox:t})=>{const[n,r]=F.useState({w:0,h:0}),[l,o]=F.useState(!1),i=()=>{const u=window.open();u&&(u.document.write(`
251
251
  <html>
@@ -5,7 +5,7 @@
5
5
  <link rel="icon" type="image/png" href="./favicon.png" />
6
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
7
  <title>Flowstride</title>
8
- <script type="module" crossorigin src="./assets/index-Brl3nrIZ.js"></script>
8
+ <script type="module" crossorigin src="./assets/index-BrbAbAha.js"></script>
9
9
  <link rel="stylesheet" crossorigin href="./assets/index-DXTn_ThB.css">
10
10
  </head>
11
11
  <body>