@xera-ai/cli 0.12.0 → 0.12.2

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.
package/dist/index.js CHANGED
@@ -210,21 +210,34 @@ async function runChecks(cwd) {
210
210
  checks.push({ name: "xera skills present", ok: false, message: "run `xera init`" });
211
211
  } else {
212
212
  const required = [
213
- "xera-run.md",
214
- "xera-fetch.md",
215
- "xera-feature.md",
216
- "xera-script.md",
217
- "xera-exec.md",
218
- "xera-report.md",
219
- "xera-promote.md"
213
+ "xera-run",
214
+ "xera-fetch",
215
+ "xera-feature",
216
+ "xera-script",
217
+ "xera-exec",
218
+ "xera-report",
219
+ "xera-promote"
220
220
  ];
221
- const missing = required.filter((n) => !existsSync(join(skillsDir, n)));
221
+ const missing = [];
222
+ const legacyFlat = [];
223
+ for (const base of required) {
224
+ if (existsSync(join(skillsDir, base, "SKILL.md")))
225
+ continue;
226
+ if (existsSync(join(skillsDir, `${base}.md`))) {
227
+ legacyFlat.push(base);
228
+ } else {
229
+ missing.push(base);
230
+ }
231
+ }
222
232
  const skillsCheck = {
223
233
  name: "xera skills present",
224
- ok: missing.length === 0
234
+ ok: missing.length === 0 && legacyFlat.length === 0
225
235
  };
226
- if (missing.length)
227
- skillsCheck.message = `missing: ${missing.join(", ")}`;
236
+ if (missing.length) {
237
+ skillsCheck.message = `missing: ${missing.map((b) => `${b}/SKILL.md`).join(", ")}`;
238
+ } else if (legacyFlat.length) {
239
+ skillsCheck.message = `legacy flat layout in .claude/skills/ \u2014 run \`xera init --update\` to migrate to <name>/SKILL.md (Claude Code Skill tool requires the directory layout)`;
240
+ }
228
241
  checks.push(skillsCheck);
229
242
  }
230
243
  return checks;
@@ -261,9 +274,16 @@ async function doctorCommand(opts) {
261
274
  }
262
275
 
263
276
  // src/commands/init.ts
264
- import { appendFileSync, existsSync as existsSync3, readFileSync as readFileSync3, unlinkSync, writeFileSync as writeFileSync2 } from "fs";
277
+ import {
278
+ appendFileSync,
279
+ existsSync as existsSync3,
280
+ mkdirSync as mkdirSync2,
281
+ readdirSync as readdirSync2,
282
+ readFileSync as readFileSync3,
283
+ writeFileSync as writeFileSync2
284
+ } from "fs";
265
285
  import { createRequire } from "module";
266
- import { join as join3 } from "path";
286
+ import { dirname as dirname2, join as join3 } from "path";
267
287
  import * as p from "@clack/prompts";
268
288
  import { generateKey } from "@xera-ai/core";
269
289
  import pc2 from "picocolors";
@@ -293,17 +313,6 @@ function scaffoldFile(targetPath, templateName, vars) {
293
313
  mkdirSync(dirname(targetPath), { recursive: true });
294
314
  writeFileSync(targetPath, render(tmpl, vars));
295
315
  }
296
- function copyDir(src, dest) {
297
- mkdirSync(dest, { recursive: true });
298
- for (const entry of readdirSync(src, { withFileTypes: true })) {
299
- const s = join2(src, entry.name);
300
- const d = join2(dest, entry.name);
301
- if (entry.isDirectory())
302
- copyDir(s, d);
303
- else
304
- writeFileSync(d, readFileSync2(s));
305
- }
306
- }
307
316
 
308
317
  // src/commands/init.ts
309
318
  var require2 = createRequire(import.meta.url);
@@ -446,15 +455,22 @@ async function initCommand(opts) {
446
455
  writeFileSync2(gitignorePath, `${gitignoreAdditions.trim()}
447
456
  `);
448
457
  }
449
- const skillsSrc = require2.resolve("@xera-ai/skills/package.json");
450
- const skillsDir = join3(skillsSrc, "..");
451
- for (const target of [".claude/skills", ".claude/commands"]) {
452
- copyDir(skillsDir, join3(cwd, target));
453
- for (const name of ["package.json", "version.json", "CHANGELOG.md"]) {
454
- const f = join3(cwd, target, name);
455
- if (existsSync3(f))
456
- unlinkSync(f);
457
- }
458
+ const skillsPkgPath = require2.resolve("@xera-ai/skills/package.json");
459
+ const skillsSrcDir = join3(skillsPkgPath, "..");
460
+ const SKILL_IGNORE = new Set(["package.json", "version.json", "CHANGELOG.md"]);
461
+ for (const name of readdirSync2(skillsSrcDir)) {
462
+ if (SKILL_IGNORE.has(name))
463
+ continue;
464
+ if (!name.endsWith(".md"))
465
+ continue;
466
+ const content = readFileSync3(join3(skillsSrcDir, name));
467
+ const base = name.replace(/\.md$/, "");
468
+ const skillFile = join3(cwd, ".claude/skills", base, "SKILL.md");
469
+ mkdirSync2(dirname2(skillFile), { recursive: true });
470
+ writeFileSync2(skillFile, content);
471
+ const cmdFile = join3(cwd, ".claude/commands", name);
472
+ mkdirSync2(dirname2(cmdFile), { recursive: true });
473
+ writeFileSync2(cmdFile, content);
458
474
  }
459
475
  const pkgPath = join3(cwd, "package.json");
460
476
  const pkg = existsSync3(pkgPath) ? JSON.parse(readFileSync3(pkgPath, "utf8")) : { name: "xera-project", private: true, type: "module" };
@@ -496,22 +512,25 @@ async function initCommand(opts) {
496
512
  writeFileSync2(pkgPath, JSON.stringify(pkg, null, 2));
497
513
  const nextSteps = shape === "api" ? `
498
514
  Next:
499
- 1) Set your auth credentials in .env.local:
500
- USER_BEARER_TOKEN=...
515
+ 1) Copy .env.example to .env and set your auth credentials:
516
+ cp .env.example .env
517
+ # then edit .env to set USER_BEARER_TOKEN=...
501
518
  2) Run pre-authentication:
502
519
  bun run xera:auth-setup
503
520
  3) Start testing:
504
521
  Open Claude Code in this directory and run: /xera-run <TICKET>
505
522
  ` : shape === "mixed" ? `
506
523
  Next:
507
- 1) Set credentials in .env.local (both web logins and API tokens)
524
+ 1) Copy .env.example to .env and set credentials (both web logins and API tokens):
525
+ cp .env.example .env
508
526
  2) Run pre-authentication:
509
527
  bun run xera:auth-setup
510
528
  3) Start testing:
511
529
  Open Claude Code in this directory and run: /xera-run <TICKET>
512
530
  ` : `
513
531
  Next:
514
- 1) Set your Jira credentials in .env.local
532
+ 1) Copy .env.example to .env and set your Jira credentials:
533
+ cp .env.example .env
515
534
  2) Run pre-authentication:
516
535
  bun run xera:auth-setup
517
536
  3) Start testing:
@@ -525,18 +544,97 @@ Next:
525
544
  import {
526
545
  copyFileSync,
527
546
  existsSync as existsSync4,
528
- mkdirSync as mkdirSync2,
529
- readdirSync as readdirSync2,
547
+ mkdirSync as mkdirSync3,
548
+ readdirSync as readdirSync3,
530
549
  readFileSync as readFileSync4,
550
+ unlinkSync,
531
551
  writeFileSync as writeFileSync3
532
552
  } from "fs";
533
553
  import { createRequire as createRequire2 } from "module";
534
- import { dirname as dirname2, join as join4 } from "path";
554
+ import { dirname as dirname3, join as join4 } from "path";
535
555
  import * as p2 from "@clack/prompts";
536
556
  import pc3 from "picocolors";
537
557
  var require3 = createRequire2(import.meta.url);
538
558
  var CLI_VERSION2 = require3("../package.json").version;
539
- async function initUpdateCommand(_opts) {
559
+ function detectAdaptersFromConfig(cwd) {
560
+ const configPath = join4(cwd, "xera.config.ts");
561
+ if (!existsSync4(configPath))
562
+ return null;
563
+ const cfg = readFileSync4(configPath, "utf8");
564
+ const m = cfg.match(/adapters:\s*\[([^\]]+)\]/);
565
+ if (!m)
566
+ return null;
567
+ return (m[1].match(/'(\w+)'/g) ?? []).map((s) => s.slice(1, -1));
568
+ }
569
+ function adaptersForShape(shape) {
570
+ if (shape === "web")
571
+ return ["web"];
572
+ if (shape === "api")
573
+ return ["http"];
574
+ return ["web", "http"];
575
+ }
576
+ function renderHttpConfigSnippet(opts) {
577
+ const baseUrl = opts.apiBaseUrl ?? "https://api.staging.example.com";
578
+ const strategy = opts.authStrategy ?? "bearer";
579
+ const roles = (opts.httpRoles ?? "user").split(",").map((s) => s.trim()).filter(Boolean);
580
+ const rolesBlock = roles.map((r) => ` ${r}: { tokenEnv: '${r.toUpperCase().replace(/-/g, "_")}_BEARER_TOKEN' },`).join(`
581
+ `);
582
+ const specLine = opts.openapiPath ? ` spec: '${opts.openapiPath}',
583
+ ` : "";
584
+ return [
585
+ ` http: {`,
586
+ ` baseUrl: { staging: '${baseUrl}' },`,
587
+ ` defaultEnv: 'staging',`,
588
+ `${specLine} auth: {`,
589
+ ` strategy: '${strategy}',`,
590
+ ` roles: {`,
591
+ rolesBlock,
592
+ ` },`,
593
+ ` },`,
594
+ ` },`
595
+ ].join(`
596
+ `);
597
+ }
598
+ function renderWebConfigSnippet(opts) {
599
+ const baseUrl = opts.stagingUrl ?? "https://staging.example.com";
600
+ const roles = (opts.roles ?? "admin,regular").split(",").map((s) => s.trim()).filter(Boolean);
601
+ const authBlock = opts.authEnabled === false ? "" : ` auth: {
602
+ strategy: 'storageState',
603
+ setupScript: './shared/auth-setup.ts',
604
+ roles: {
605
+ ${roles.map((r) => ` ${r}: { envEmail: 'TEST_${r.toUpperCase().replace(/-/g, "_")}_EMAIL', envPassword: 'TEST_${r.toUpperCase().replace(/-/g, "_")}_PWD' },`).join(`
606
+ `)}
607
+ },
608
+ },
609
+ `;
610
+ return [
611
+ ` web: {`,
612
+ ` baseUrl: { staging: '${baseUrl}' },`,
613
+ ` defaultEnv: 'staging',`,
614
+ authBlock + ` },`
615
+ ].join(`
616
+ `);
617
+ }
618
+ var HTTP_AUTH_SETUP_SNIPPET = `import { defineHttpAuthSetup, presetHttpAuth } from '@xera-ai/http';
619
+
620
+ export const http = defineHttpAuthSetup(async (request, role, creds) => {
621
+ return presetHttpAuth({
622
+ request,
623
+ role,
624
+ config: (globalThis as Record<string, unknown>).__XERA_HTTP_CONFIG__ as never,
625
+ });
626
+ });`;
627
+ var WEB_AUTH_SETUP_SNIPPET = `import { defineAuthSetup } from '@xera-ai/web';
628
+
629
+ export const web = defineAuthSetup(async (page, _role, creds) => {
630
+ await page.goto('/login');
631
+ await page.getByLabel('Email').fill(creds.email);
632
+ await page.getByLabel('Password').fill(creds.password);
633
+ await page.getByRole('button', { name: 'Sign in' }).click();
634
+ await page.waitForURL(/.*\\/dashboard/);
635
+ return { expiresAt: Date.now() + 8 * 3600 * 1000 };
636
+ });`;
637
+ async function initUpdateCommand(opts) {
540
638
  const cwd = process.cwd();
541
639
  p2.intro(pc3.cyan("xera init --update"));
542
640
  const pkgPath = join4(cwd, "package.json");
@@ -566,7 +664,7 @@ async function initUpdateCommand(_opts) {
566
664
  pkg.scripts["xera:disputes"] = "xera-internal disputes";
567
665
  writeFileSync3(pkgPath, JSON.stringify(pkg, null, 2));
568
666
  const wfDir = join4(cwd, ".github/workflows");
569
- mkdirSync2(wfDir, { recursive: true });
667
+ mkdirSync3(wfDir, { recursive: true });
570
668
  try {
571
669
  const cliPkgPath = require3.resolve("@xera-ai/cli/package.json");
572
670
  const cliTplPath = join4(cliPkgPath, "..", "templates/xera-graph.yml.template");
@@ -577,28 +675,47 @@ async function initUpdateCommand(_opts) {
577
675
  }
578
676
  const skillsSrc = require3.resolve("@xera-ai/skills/package.json");
579
677
  const newSkillsDir = join4(skillsSrc, "..");
580
- const targetDirs = [join4(cwd, ".claude/skills"), join4(cwd, ".claude/commands")];
581
- for (const name of readdirSync2(newSkillsDir)) {
678
+ const SKILL_IGNORE = new Set(["package.json", "version.json", "CHANGELOG.md"]);
679
+ for (const name of readdirSync3(newSkillsDir)) {
680
+ if (SKILL_IGNORE.has(name))
681
+ continue;
582
682
  if (!name.endsWith(".md"))
583
683
  continue;
584
684
  const newContent = readFileSync4(join4(newSkillsDir, name), "utf8");
585
- const localStates = targetDirs.map((dir) => {
586
- const path = join4(dir, name);
587
- if (!existsSync4(path))
588
- return { path, state: "missing" };
589
- const content = readFileSync4(path, "utf8");
590
- return { path, state: content === newContent ? "same" : "diff" };
591
- });
592
- if (localStates.every((s) => s.state === "missing")) {
593
- for (const { path } of localStates) {
594
- mkdirSync2(dirname2(path), { recursive: true });
685
+ const base = name.replace(/\.md$/, "");
686
+ const skillPath = join4(cwd, ".claude/skills", base, "SKILL.md");
687
+ const legacyFlatSkillPath = join4(cwd, ".claude/skills", name);
688
+ const cmdPath = join4(cwd, ".claude/commands", name);
689
+ let migratedLegacy = false;
690
+ if (existsSync4(legacyFlatSkillPath) && !existsSync4(skillPath)) {
691
+ const legacyContent = readFileSync4(legacyFlatSkillPath, "utf8");
692
+ mkdirSync3(dirname3(skillPath), { recursive: true });
693
+ writeFileSync3(skillPath, legacyContent);
694
+ unlinkSync(legacyFlatSkillPath);
695
+ migratedLegacy = true;
696
+ }
697
+ const targets = [];
698
+ for (const path of [skillPath, cmdPath]) {
699
+ if (!existsSync4(path)) {
700
+ targets.push({ path, state: "missing" });
701
+ } else {
702
+ const content = readFileSync4(path, "utf8");
703
+ targets.push({ path, state: content === newContent ? "same" : "diff" });
704
+ }
705
+ }
706
+ if (targets.every((s) => s.state === "missing")) {
707
+ for (const { path } of targets) {
708
+ mkdirSync3(dirname3(path), { recursive: true });
595
709
  writeFileSync3(path, newContent);
596
710
  }
597
711
  p2.log.info(`+ ${name}`);
598
712
  continue;
599
713
  }
600
- if (localStates.every((s) => s.state === "same")) {
601
- p2.log.info(`= ${name}`);
714
+ if (targets.every((s) => s.state === "same")) {
715
+ if (migratedLegacy)
716
+ p2.log.success(`migrated ${name} to .claude/skills/${base}/SKILL.md`);
717
+ else
718
+ p2.log.info(`= ${name}`);
602
719
  continue;
603
720
  }
604
721
  const choice = await p2.select({
@@ -609,15 +726,62 @@ async function initUpdateCommand(_opts) {
609
726
  ]
610
727
  });
611
728
  if (choice === "overwrite") {
612
- for (const { path } of localStates) {
613
- mkdirSync2(dirname2(path), { recursive: true });
729
+ for (const { path } of targets) {
730
+ mkdirSync3(dirname3(path), { recursive: true });
614
731
  writeFileSync3(path, newContent);
615
732
  }
616
733
  p2.log.success(`overwrote ${name}`);
617
734
  } else {
735
+ if (migratedLegacy)
736
+ p2.log.success(`migrated ${name} to .claude/skills/${base}/SKILL.md`);
618
737
  p2.log.warn(`kept local ${name}`);
619
738
  }
620
739
  }
740
+ const hasShapeFlags = opts.apiBaseUrl !== undefined || opts.openapiPath !== undefined || opts.authStrategy !== undefined || opts.httpRoles !== undefined || opts.stagingUrl !== undefined || opts.authEnabled !== undefined || opts.roles !== undefined;
741
+ if (opts.shape !== undefined) {
742
+ const current = detectAdaptersFromConfig(cwd);
743
+ if (current === null) {
744
+ p2.log.warn("--shape was provided but could not detect existing adapters in xera.config.ts. Skipping shape check.");
745
+ } else {
746
+ const requested = adaptersForShape(opts.shape);
747
+ const missing = requested.filter((a) => !current.includes(a));
748
+ const extra = current.filter((a) => !requested.includes(a));
749
+ if (missing.length === 0 && extra.length === 0) {
750
+ p2.log.info(`shape '${opts.shape}' already matches existing adapters [${current.join(", ")}]`);
751
+ } else {
752
+ if (missing.length > 0) {
753
+ const lines = [
754
+ `--shape ${opts.shape} requested but xera.config.ts has adapters: [${current.join(", ")}]`,
755
+ `Missing adapter(s): ${missing.join(", ")}`,
756
+ ``,
757
+ `init --update is non-destructive \u2014 it will NOT modify xera.config.ts or shared/auth-setup.ts.`,
758
+ `To complete the upgrade, hand-edit both files:`,
759
+ ``,
760
+ `1. In xera.config.ts, change \`adapters: [${current.map((a) => `'${a}'`).join(", ")}]\` to \`adapters: [${requested.map((a) => `'${a}'`).join(", ")}]\` and add this block inside defineConfig({...}):`,
761
+ ``
762
+ ];
763
+ for (const a of missing) {
764
+ lines.push(a === "http" ? renderHttpConfigSnippet(opts) : renderWebConfigSnippet(opts));
765
+ lines.push("");
766
+ }
767
+ lines.push(`2. In shared/auth-setup.ts, add this export:`);
768
+ lines.push("");
769
+ for (const a of missing) {
770
+ lines.push(a === "http" ? HTTP_AUTH_SETUP_SNIPPET : WEB_AUTH_SETUP_SNIPPET);
771
+ lines.push("");
772
+ }
773
+ lines.push(`3. Add ${missing.includes("http") ? `\`@xera-ai/http\`` : ""}${missing.includes("http") && missing.includes("web") ? " and " : ""}${missing.includes("web") ? `\`@xera-ai/web\`` : ""} to dependencies (re-run \`xera init --update\` after editing to bump versions), then run \`xera doctor\` to verify.`);
774
+ p2.log.warn(lines.join(`
775
+ `));
776
+ }
777
+ if (extra.length > 0) {
778
+ p2.log.warn(`--shape ${opts.shape} would remove adapter(s) [${extra.join(", ")}] from xera.config.ts, but init --update never removes config. Remove the block(s) by hand if intended.`);
779
+ }
780
+ }
781
+ }
782
+ } else if (hasShapeFlags) {
783
+ p2.log.warn("Shape-related flags (--au/--as/--hr/--su/--ro/--op/--auth-enabled) are ignored by init --update without --shape. To change shape, pass --shape <web|api|mixed> alongside.");
784
+ }
621
785
  p2.outro(pc3.green("Update complete. Run `xera doctor` to verify."));
622
786
  }
623
787
 
@@ -670,7 +834,38 @@ async function main() {
670
834
  cli.usage("<command> [options]");
671
835
  cli.command("init", "Scaffold a new xera project in the current directory").option("--update", "Non-destructive refresh of an existing project").option("-y, --yes", "Accept all defaults (non-interactive)").option("--shape <shape>", "Project shape: web | api | mixed").option("--ju, --jira-base-url <url>", "Jira workspace URL").option("--pk, --project-keys <keys>", "Jira project key(s), comma-separated").option("--sf, --story-field <field>", "Jira field id for user story (default: description)").option("--ac, --ac-field <field>", "Jira field id for acceptance criteria").option("--su, --staging-url <url>", "Web app staging URL").option("--auth-enabled", "App requires login to test most pages").option("--no-auth-enabled", "App does not require login").option("--ro, --roles <roles>", "Test user roles, comma-separated (default: admin,regular)").option("--au, --api-base-url <url>", "API base URL").option("--op, --openapi-path <path>", "OpenAPI spec path or URL").option("--as, --auth-strategy <strategy>", `API auth strategy: ${VALID_AUTH_STRATEGIES.join(" | ")}`).option("--hr, --http-roles <roles>", "HTTP test roles, comma-separated (default: user)").example("xera init").example("xera init -y --shape web").example("xera init -y --shape api --pk MYPROJ --ju https://myco.atlassian.net --au https://api.staging.example.com --as bearer").example("xera init -y --shape mixed --pk PROJ --ju https://myco.atlassian.net --su https://staging.example.com --au https://api.staging.example.com").action(async (opts) => {
672
836
  if (opts.update) {
673
- await initUpdateCommand({ yes: !!opts.yes });
837
+ const updateOpts = { yes: !!opts.yes };
838
+ if (opts.shape !== undefined) {
839
+ if (!VALID_SHAPES.includes(opts.shape)) {
840
+ console.error(pc4.red(`
841
+ error: --shape must be one of: ${VALID_SHAPES.join(", ")}
842
+ `));
843
+ process.exit(1);
844
+ }
845
+ updateOpts.shape = opts.shape;
846
+ }
847
+ if (opts.authStrategy !== undefined) {
848
+ if (!VALID_AUTH_STRATEGIES.includes(opts.authStrategy)) {
849
+ console.error(pc4.red(`
850
+ error: --auth-strategy must be one of: ${VALID_AUTH_STRATEGIES.join(", ")}
851
+ `));
852
+ process.exit(1);
853
+ }
854
+ updateOpts.authStrategy = opts.authStrategy;
855
+ }
856
+ if (opts.apiBaseUrl !== undefined)
857
+ updateOpts.apiBaseUrl = opts.apiBaseUrl;
858
+ if (opts.openapiPath !== undefined)
859
+ updateOpts.openapiPath = opts.openapiPath;
860
+ if (opts.httpRoles !== undefined)
861
+ updateOpts.httpRoles = opts.httpRoles;
862
+ if (opts.stagingUrl !== undefined)
863
+ updateOpts.stagingUrl = opts.stagingUrl;
864
+ if (opts.authEnabled !== undefined)
865
+ updateOpts.authEnabled = opts.authEnabled;
866
+ if (opts.roles !== undefined)
867
+ updateOpts.roles = opts.roles;
868
+ await initUpdateCommand(updateOpts);
674
869
  return;
675
870
  }
676
871
  const initOpts = { yes: !!opts.yes };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xera-ai/cli",
3
- "version": "0.12.0",
3
+ "version": "0.12.2",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "xera": "./bin/xera"
@@ -15,8 +15,8 @@
15
15
  "typecheck": "tsc --noEmit"
16
16
  },
17
17
  "dependencies": {
18
- "@xera-ai/core": "^0.12.0",
19
- "@xera-ai/skills": "^0.12.0",
18
+ "@xera-ai/core": "^0.12.2",
19
+ "@xera-ai/skills": "^0.12.2",
20
20
  "@clack/prompts": "1.4.0",
21
21
  "cac": "7.0.0",
22
22
  "picocolors": "1.1.1"
@@ -2,6 +2,6 @@
2
2
  JIRA_EMAIL=
3
3
  JIRA_API_TOKEN=
4
4
 
5
- # Auth tokens for HTTP roles - set in .env.local (gitignored)
5
+ # Auth tokens for HTTP roles - set in .env (gitignored)
6
6
  {{#each httpRoles}}{{upper this}}_BEARER_TOKEN=
7
7
  {{/each}}
@@ -11,8 +11,8 @@ export default defineConfig({
11
11
  },
12
12
  },
13
13
  http: {
14
- baseUrl: { dev: '{{apiBaseUrl}}' },
15
- defaultEnv: 'dev',
14
+ baseUrl: { staging: '{{apiBaseUrl}}' },
15
+ defaultEnv: 'staging',
16
16
  {{#if openapiPath}}spec: '{{openapiPath}}',{{/if}}
17
17
  auth: {
18
18
  strategy: '{{authStrategy}}',
@@ -11,8 +11,8 @@ export default defineConfig({
11
11
  },
12
12
  },
13
13
  web: {
14
- baseUrl: { dev: '{{stagingUrl}}' },
15
- defaultEnv: 'dev',
14
+ baseUrl: { staging: '{{stagingUrl}}' },
15
+ defaultEnv: 'staging',
16
16
  {{#if authEnabled}}auth: {
17
17
  strategy: 'storageState',
18
18
  setupScript: './shared/auth-setup.ts',
@@ -23,8 +23,8 @@ export default defineConfig({
23
23
  },{{/if}}
24
24
  },
25
25
  http: {
26
- baseUrl: { dev: '{{apiBaseUrl}}' },
27
- defaultEnv: 'dev',
26
+ baseUrl: { staging: '{{apiBaseUrl}}' },
27
+ defaultEnv: 'staging',
28
28
  {{#if openapiPath}}spec: '{{openapiPath}}',{{/if}}
29
29
  auth: {
30
30
  strategy: '{{authStrategy}}',