@stackwright-pro/mcp 0.2.0-alpha.61 → 0.2.0-alpha.66

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/server.js CHANGED
@@ -1702,6 +1702,14 @@ function handleSavePhaseAnswers(input) {
1702
1702
  let answers;
1703
1703
  if (input.questions && input.questions.length > 0) {
1704
1704
  answers = answersToManifestFormat(input.rawAnswers, input.questions);
1705
+ if (Object.keys(answers).length === 0 && input.rawAnswers.length > 0) {
1706
+ answers = Object.fromEntries(
1707
+ input.rawAnswers.map((a) => [
1708
+ a.question_header,
1709
+ a.selected_options.length > 1 ? a.selected_options : a.selected_options[0] ?? ""
1710
+ ])
1711
+ );
1712
+ }
1705
1713
  } else {
1706
1714
  answers = Object.fromEntries(
1707
1715
  input.rawAnswers.map((a) => [a.question_header, a.selected_options[0] ?? ""])
@@ -2285,12 +2293,13 @@ var PHASE_DEPENDENCIES = {
2285
2293
  // workflow states as trigger sources. Produces OpenAPI specs consumed
2286
2294
  // by pages and dashboard for typed data wiring.
2287
2295
  services: ["api", "workflow"],
2288
- // pages/dashboard: now also depend on services for typed endpoint wiring
2289
- // via the OpenAPI specs that services produces.
2290
- // 'api' is still transitive through 'data'; auth removed page-otter has
2291
- // graceful fallback and reads role names from workflow artifacts instead
2292
- pages: ["designer", "theme", "data", "services"],
2293
- dashboard: ["designer", "theme", "data", "services"],
2296
+ // pages/dashboard: depend on services for typed endpoint wiring (OpenAPI
2297
+ // specs) and on geo so the specialist prompt includes geo-manifest.json
2298
+ // page/dashboard otters see which page slugs are already claimed and
2299
+ // won't attempt to overwrite them (swp-73c). 'api' is still transitive
2300
+ // through 'data'; auth removed — page-otter has graceful fallback.
2301
+ pages: ["designer", "theme", "data", "services", "geo"],
2302
+ dashboard: ["designer", "theme", "data", "services", "geo"],
2294
2303
  // auth is the penultimate phase — runs after all content-producing phases
2295
2304
  // so it can read pages, dashboard, workflow, and geo artifacts for route
2296
2305
  // protection and RBAC wiring. Skipped upstream phases still satisfy deps
@@ -3347,6 +3356,16 @@ var OTTER_WRITE_ALLOWLISTS = {
3347
3356
  prefix: ".env",
3348
3357
  suffix: "",
3349
3358
  description: "Dotenv files (.env, .env.local, .env.production, etc.)"
3359
+ },
3360
+ {
3361
+ prefix: "lib/mock-auth",
3362
+ suffix: ".ts",
3363
+ description: "Mock auth module (DEV_ONLY_MODE role updates)"
3364
+ },
3365
+ {
3366
+ prefix: "package.json",
3367
+ suffix: ".json",
3368
+ description: "Project package.json (DEV_ONLY_MODE script cleanup)"
3350
3369
  }
3351
3370
  ],
3352
3371
  "stackwright-pro-data-otter": [
@@ -3404,7 +3423,9 @@ var PROTECTED_PATH_PREFIXES = [
3404
3423
  ".stackwright/artifacts/signatures.json",
3405
3424
  // artifact signature manifest
3406
3425
  ".stackwright/questions/",
3407
- ".stackwright/answers/"
3426
+ ".stackwright/answers/",
3427
+ ".stackwright/page-registry.json"
3428
+ // page ownership — managed by safe_write internally
3408
3429
  ];
3409
3430
  var MAX_SAFE_WRITE_BYTES_JSON = 512 * 1024;
3410
3431
  var MAX_SAFE_WRITE_BYTES_YAML = 256 * 1024;
@@ -3418,6 +3439,58 @@ function getMaxBytesForPath(filePath) {
3418
3439
  return { limit: MAX_SAFE_WRITE_BYTES_ENV, label: "env" };
3419
3440
  return { limit: MAX_SAFE_WRITE_BYTES_DEFAULT, label: "default" };
3420
3441
  }
3442
+ var PAGE_REGISTRY_FILE = ".stackwright/page-registry.json";
3443
+ function extractPageSlug(filePath) {
3444
+ const match = (0, import_path6.normalize)(filePath).match(/^pages\/(.+?)\/content\.ya?ml$/);
3445
+ return match?.[1] ?? null;
3446
+ }
3447
+ function extractContentTypes(yamlContent) {
3448
+ const typePattern = /^\s*-?\s*type:\s*(\S+)/gm;
3449
+ const types = [];
3450
+ let m;
3451
+ while ((m = typePattern.exec(yamlContent)) !== null) {
3452
+ const typeName = m[1];
3453
+ if (typeName && !types.includes(typeName)) {
3454
+ types.push(typeName);
3455
+ }
3456
+ }
3457
+ return types.length > 0 ? types : ["unknown"];
3458
+ }
3459
+ function readPageRegistry(cwd) {
3460
+ const regPath = (0, import_path6.join)(cwd, PAGE_REGISTRY_FILE);
3461
+ if (!(0, import_fs6.existsSync)(regPath)) return {};
3462
+ try {
3463
+ const stat = (0, import_fs6.lstatSync)(regPath);
3464
+ if (stat.isSymbolicLink()) return {};
3465
+ return JSON.parse((0, import_fs6.readFileSync)(regPath, "utf-8"));
3466
+ } catch {
3467
+ return {};
3468
+ }
3469
+ }
3470
+ function writePageRegistry(cwd, registry) {
3471
+ const dir = (0, import_path6.join)(cwd, ".stackwright");
3472
+ (0, import_fs6.mkdirSync)(dir, { recursive: true });
3473
+ const regPath = (0, import_path6.join)(cwd, PAGE_REGISTRY_FILE);
3474
+ if ((0, import_fs6.existsSync)(regPath)) {
3475
+ const stat = (0, import_fs6.lstatSync)(regPath);
3476
+ if (stat.isSymbolicLink()) {
3477
+ throw new Error("Refusing to write page registry through symlink");
3478
+ }
3479
+ }
3480
+ (0, import_fs6.writeFileSync)(regPath, JSON.stringify(registry, null, 2) + "\n", { encoding: "utf-8" });
3481
+ }
3482
+ function checkPageOwnership(cwd, slug, callerOtter) {
3483
+ const registry = readPageRegistry(cwd);
3484
+ const existing = registry[slug];
3485
+ if (!existing || existing.claimedBy === callerOtter) {
3486
+ return { allowed: true };
3487
+ }
3488
+ return {
3489
+ allowed: false,
3490
+ owner: existing.claimedBy,
3491
+ contentTypes: existing.contentTypes
3492
+ };
3493
+ }
3421
3494
  function checkPathAllowed(callerOtter, filePath) {
3422
3495
  const normalized = (0, import_path6.normalize)(filePath);
3423
3496
  if (normalized.includes("..")) {
@@ -3459,6 +3532,16 @@ function checkPathAllowed(callerOtter, filePath) {
3459
3532
  continue;
3460
3533
  }
3461
3534
  }
3535
+ if (rule.prefix === "lib/mock-auth" && rule.suffix === ".ts") {
3536
+ if (normalized !== "lib/mock-auth.ts") {
3537
+ continue;
3538
+ }
3539
+ }
3540
+ if (rule.prefix === "package.json" && rule.suffix === ".json") {
3541
+ if (normalized !== "package.json") {
3542
+ continue;
3543
+ }
3544
+ }
3462
3545
  return { allowed: true, rule: rule.description };
3463
3546
  }
3464
3547
  }
@@ -3584,11 +3667,38 @@ function handleSafeWrite(input) {
3584
3667
  };
3585
3668
  return { text: JSON.stringify(result), isError: true };
3586
3669
  }
3670
+ const pageSlug = extractPageSlug(normalized);
3671
+ if (pageSlug) {
3672
+ const ownership = checkPageOwnership(cwd, pageSlug, callerOtter);
3673
+ if (!ownership.allowed) {
3674
+ const result = {
3675
+ success: false,
3676
+ error: `Page slug "${pageSlug}" is already claimed by ${ownership.owner} (content types: ${ownership.contentTypes.join(", ")}). Use a different slug or coordinate with the owning otter.`,
3677
+ callerOtter,
3678
+ attemptedPath: filePath,
3679
+ allowedPaths: []
3680
+ };
3681
+ return { text: JSON.stringify(result), isError: true };
3682
+ }
3683
+ }
3587
3684
  try {
3588
3685
  if (createDirectories) {
3589
3686
  (0, import_fs6.mkdirSync)((0, import_path6.dirname)(fullPath), { recursive: true });
3590
3687
  }
3591
3688
  (0, import_fs6.writeFileSync)(fullPath, content, { encoding: "utf-8" });
3689
+ if (pageSlug) {
3690
+ try {
3691
+ const registry = readPageRegistry(cwd);
3692
+ registry[pageSlug] = {
3693
+ slug: pageSlug,
3694
+ claimedBy: callerOtter,
3695
+ contentTypes: extractContentTypes(content),
3696
+ writtenAt: (/* @__PURE__ */ new Date()).toISOString()
3697
+ };
3698
+ writePageRegistry(cwd, registry);
3699
+ } catch {
3700
+ }
3701
+ }
3592
3702
  const result = {
3593
3703
  success: true,
3594
3704
  path: normalized,
@@ -3855,10 +3965,232 @@ ${routeLines}
3855
3965
  ${auditSection}
3856
3966
  `;
3857
3967
  }
3968
+ function generateDevOnlyMiddlewareContent(method, params, roles, defaultRole, hierarchy, auditEnabled, auditRetentionDays, protectedRoutes) {
3969
+ const rbacBlock = ` rbac: {
3970
+ roles: ${JSON.stringify(roles)},
3971
+ defaultRole: '${defaultRole}',
3972
+ hierarchy: ${JSON.stringify(hierarchy, null, 4)},
3973
+ },`;
3974
+ const auditBlock = ` audit: {
3975
+ enabled: ${auditEnabled},
3976
+ retentionDays: ${auditRetentionDays},
3977
+ },`;
3978
+ const routesBlock = ` protectedRoutes: ${JSON.stringify(protectedRoutes)},`;
3979
+ const configBlock = `export const config = {
3980
+ matcher: ${JSON.stringify(protectedRoutes)},
3981
+ };`;
3982
+ const devHeader = [
3983
+ "// middleware.ts \u2014 generated by @stackwright-pro/auth-nextjs (dev-only mock)",
3984
+ "// DEV ONLY \u2014 uses mock authentication from lib/mock-auth.ts",
3985
+ "// Do NOT deploy to production.",
3986
+ "import { createProMiddleware } from '@stackwright-pro/auth-nextjs';",
3987
+ "import { mockAuthProvider } from './lib/mock-auth';"
3988
+ ].join("\n");
3989
+ if (method === "cac") {
3990
+ const caBundle = params.cacCaBundle ?? "./certs/dod-ca-bundle.pem";
3991
+ const edipiLookup = params.cacEdipiLookup ?? "./config/edipi-lookup.json";
3992
+ const ocspEndpoint = params.cacOcspEndpoint ?? "https://ocsp.disa.mil";
3993
+ const certHeader = params.cacCertHeader ?? "X-SSL-Client-Cert";
3994
+ return `${devHeader}
3995
+
3996
+ export const middleware = createProMiddleware({
3997
+ method: 'cac',
3998
+ cac: {
3999
+ caBundle: '${caBundle}',
4000
+ edipiLookup: '${edipiLookup}',
4001
+ ocspEndpoint: '${ocspEndpoint}',
4002
+ certHeader: '${certHeader}',
4003
+ provider: mockAuthProvider,
4004
+ },
4005
+ ${rbacBlock}
4006
+ ${auditBlock}
4007
+ ${routesBlock}
4008
+ });
4009
+
4010
+ ${configBlock}
4011
+ `;
4012
+ }
4013
+ if (method === "oidc") {
4014
+ const scopes2 = params.oidcScopes ?? "openid profile email";
4015
+ const roleClaim = params.oidcRoleClaim ?? "roles";
4016
+ return `${devHeader}
4017
+
4018
+ export const middleware = createProMiddleware({
4019
+ method: 'oidc',
4020
+ oidc: {
4021
+ discoveryUrl: 'https://dev-mock-oidc/.well-known/openid-configuration',
4022
+ clientId: 'dev-mock-client',
4023
+ clientSecret: 'dev-mock-secret',
4024
+ scopes: '${scopes2}',
4025
+ roleClaim: '${roleClaim}',
4026
+ provider: mockAuthProvider,
4027
+ },
4028
+ ${rbacBlock}
4029
+ ${auditBlock}
4030
+ ${routesBlock}
4031
+ });
4032
+
4033
+ ${configBlock}
4034
+ `;
4035
+ }
4036
+ const scopes = params.oauth2Scopes ?? "read write";
4037
+ return `${devHeader}
4038
+
4039
+ export const middleware = createProMiddleware({
4040
+ method: 'oauth2',
4041
+ oauth2: {
4042
+ authorizationUrl: 'https://dev-mock-oauth2/authorize',
4043
+ tokenUrl: 'https://dev-mock-oauth2/token',
4044
+ clientId: 'dev-mock-client',
4045
+ clientSecret: 'dev-mock-secret',
4046
+ scopes: '${scopes}',
4047
+ provider: mockAuthProvider,
4048
+ },
4049
+ ${rbacBlock}
4050
+ ${auditBlock}
4051
+ ${routesBlock}
4052
+ });
4053
+
4054
+ ${configBlock}
4055
+ `;
4056
+ }
4057
+ function generateDevOnlyYamlBlock(method, params, roles, defaultRole, hierarchy, auditEnabled, auditRetentionDays, protectedRoutes) {
4058
+ const rbacSection = ` rbac:
4059
+ roles:
4060
+ ${rolesToYaml(roles, " ")}
4061
+ defaultRole: ${defaultRole}
4062
+ hierarchy:
4063
+ ${hierarchyToYaml(hierarchy, " ")}`;
4064
+ const auditSection = ` audit:
4065
+ enabled: ${auditEnabled}
4066
+ retentionDays: ${auditRetentionDays}`;
4067
+ const routeLines = protectedRoutes.map((r) => ` - pattern: ${r}
4068
+ requiredRole: ${defaultRole}`).join("\n");
4069
+ const providerLine = params.provider ? ` provider: ${params.provider}
4070
+ ` : "";
4071
+ if (method === "cac") {
4072
+ const caBundle = params.cacCaBundle ?? "./certs/dod-ca-bundle.pem";
4073
+ const edipiLookup = params.cacEdipiLookup ?? "./config/edipi-lookup.json";
4074
+ const ocspEndpoint = params.cacOcspEndpoint ?? "https://ocsp.disa.mil";
4075
+ const certHeader = params.cacCertHeader ?? "X-SSL-Client-Cert";
4076
+ return `auth:
4077
+ method: cac
4078
+ devOnly: true
4079
+ ${providerLine} middleware: ./middleware.ts
4080
+ cac:
4081
+ caBundle: ${caBundle}
4082
+ edipiLookup: ${edipiLookup}
4083
+ ocspEndpoint: ${ocspEndpoint}
4084
+ certHeader: ${certHeader}
4085
+ ${rbacSection}
4086
+ protectedRoutes:
4087
+ ${routeLines}
4088
+ ${auditSection}
4089
+ `;
4090
+ }
4091
+ if (method === "oidc") {
4092
+ const scopes2 = params.oidcScopes ?? "openid profile email";
4093
+ const roleClaim = params.oidcRoleClaim ?? "roles";
4094
+ return `auth:
4095
+ method: oidc
4096
+ devOnly: true
4097
+ ${providerLine} middleware: ./middleware.ts
4098
+ oidc:
4099
+ discoveryUrl: https://dev-mock-oidc/.well-known/openid-configuration
4100
+ clientId: dev-mock-client
4101
+ clientSecret: dev-mock-secret
4102
+ scopes: ${scopes2}
4103
+ roleClaim: ${roleClaim}
4104
+ ${rbacSection}
4105
+ protectedRoutes:
4106
+ ${routeLines}
4107
+ ${auditSection}
4108
+ `;
4109
+ }
4110
+ const scopes = params.oauth2Scopes ?? "read write";
4111
+ return `auth:
4112
+ method: oauth2
4113
+ devOnly: true
4114
+ ${providerLine} middleware: ./middleware.ts
4115
+ oauth2:
4116
+ authorizationUrl: https://dev-mock-oauth2/authorize
4117
+ tokenUrl: https://dev-mock-oauth2/token
4118
+ clientId: dev-mock-client
4119
+ clientSecret: dev-mock-secret
4120
+ scopes: ${scopes}
4121
+ ${rbacSection}
4122
+ protectedRoutes:
4123
+ ${routeLines}
4124
+ ${auditSection}
4125
+ `;
4126
+ }
4127
+ function deriveDevKey(roleName) {
4128
+ const segment = roleName.split("_")[0];
4129
+ return (segment ?? roleName).toLowerCase();
4130
+ }
4131
+ function generateMockAuthContent(roles, mockUsers) {
4132
+ const entries = [];
4133
+ const scriptLines = [];
4134
+ for (let i = 0; i < roles.length; i++) {
4135
+ const role = roles[i];
4136
+ const devKey = deriveDevKey(role);
4137
+ const persona = mockUsers?.[i];
4138
+ const name = persona?.name ?? `Dev ${role}`;
4139
+ const email = persona?.email ?? `dev-${devKey}@example.mil`;
4140
+ const edipi = String(i + 1).padStart(10, "0");
4141
+ entries.push(` ${devKey}: {
4142
+ id: 'mock-${devKey}-${String(i + 1).padStart(3, "0")}',
4143
+ name: '${name}',
4144
+ email: '${email}',
4145
+ roles: ['${role}'],
4146
+ edipi: '${edipi}',
4147
+ }`);
4148
+ scriptLines.push(` * pnpm dev:${devKey} \u2014 ${name}`);
4149
+ }
4150
+ return `/**
4151
+ * Mock authentication for development mode.
4152
+ *
4153
+ * DEV_ONLY_MODE \u2014 no real auth provider. Select a persona via MOCK_USER env var
4154
+ * or use the convenience scripts in package.json:
4155
+ ${scriptLines.join("\n")}
4156
+ */
4157
+
4158
+ export const MOCK_USERS = {
4159
+ ${entries.join(",\n")}
4160
+ } as const;
4161
+
4162
+ export type MockRole = keyof typeof MOCK_USERS;
4163
+
4164
+ export function getMockUser(role?: string) {
4165
+ const key = (role ?? process.env.MOCK_USER) as MockRole | undefined;
4166
+ if (!key) return null;
4167
+ return MOCK_USERS[key] ?? null;
4168
+ }
4169
+
4170
+ export function mockAuthProvider() {
4171
+ return getMockUser();
4172
+ }
4173
+ `;
4174
+ }
4175
+ function updatePackageJsonScripts(existingJson, roles, mockUsers) {
4176
+ const pkg = JSON.parse(existingJson);
4177
+ const scripts = pkg.scripts ?? {};
4178
+ delete scripts["dev:admin"];
4179
+ delete scripts["dev:analyst"];
4180
+ delete scripts["dev:viewer"];
4181
+ for (let i = 0; i < roles.length; i++) {
4182
+ const devKey = deriveDevKey(roles[i]);
4183
+ scripts[`dev:${devKey}`] = `MOCK_USER=${devKey} next dev`;
4184
+ }
4185
+ pkg.scripts = scripts;
4186
+ return JSON.stringify(pkg, null, 2) + "\n";
4187
+ }
3858
4188
  async function configureAuthHandler(params, cwd) {
3859
4189
  const {
3860
4190
  method,
3861
4191
  provider,
4192
+ devOnly = false,
4193
+ mockUsers,
3862
4194
  rbacRoles = ["SUPER_ADMIN", "ADMIN", "ANALYST"],
3863
4195
  auditEnabled = true,
3864
4196
  auditRetentionDays = 90,
@@ -3888,7 +4220,16 @@ async function configureAuthHandler(params, cwd) {
3888
4220
  }
3889
4221
  const filesWritten = [];
3890
4222
  try {
3891
- const middlewareContent = generateMiddlewareContent(
4223
+ const middlewareContent = devOnly ? generateDevOnlyMiddlewareContent(
4224
+ method,
4225
+ params,
4226
+ roles,
4227
+ defaultRole,
4228
+ hierarchy,
4229
+ auditEnabled,
4230
+ auditRetentionDays,
4231
+ protectedRoutes
4232
+ ) : generateMiddlewareContent(
3892
4233
  method,
3893
4234
  params,
3894
4235
  roles,
@@ -3912,30 +4253,87 @@ async function configureAuthHandler(params, cwd) {
3912
4253
  isError: true
3913
4254
  };
3914
4255
  }
3915
- try {
3916
- const envBlock = generateEnvBlock(method, params);
3917
- const envPath = (0, import_path7.join)(cwd, ".env.example");
3918
- if ((0, import_fs7.existsSync)(envPath)) {
3919
- const existing = (0, import_fs7.readFileSync)(envPath, "utf8");
3920
- (0, import_fs7.writeFileSync)(envPath, existing.trimEnd() + "\n\n" + envBlock, "utf8");
3921
- } else {
3922
- (0, import_fs7.writeFileSync)(envPath, envBlock, "utf8");
4256
+ if (!devOnly) {
4257
+ try {
4258
+ const envBlock = generateEnvBlock(method, params);
4259
+ const envPath = (0, import_path7.join)(cwd, ".env.example");
4260
+ if ((0, import_fs7.existsSync)(envPath)) {
4261
+ const existing = (0, import_fs7.readFileSync)(envPath, "utf8");
4262
+ (0, import_fs7.writeFileSync)(envPath, existing.trimEnd() + "\n\n" + envBlock, "utf8");
4263
+ } else {
4264
+ (0, import_fs7.writeFileSync)(envPath, envBlock, "utf8");
4265
+ }
4266
+ filesWritten.push(".env.example");
4267
+ } catch (err) {
4268
+ const msg = err instanceof Error ? err.message : String(err);
4269
+ return {
4270
+ content: [
4271
+ {
4272
+ type: "text",
4273
+ text: JSON.stringify({ success: false, error: `Failed writing .env.example: ${msg}` })
4274
+ }
4275
+ ],
4276
+ isError: true
4277
+ };
4278
+ }
4279
+ }
4280
+ if (devOnly) {
4281
+ try {
4282
+ const mockAuthDir = (0, import_path7.join)(cwd, "lib");
4283
+ (0, import_fs7.mkdirSync)(mockAuthDir, { recursive: true });
4284
+ const mockAuthContent = generateMockAuthContent(roles, mockUsers);
4285
+ (0, import_fs7.writeFileSync)((0, import_path7.join)(mockAuthDir, "mock-auth.ts"), mockAuthContent, "utf8");
4286
+ filesWritten.push("lib/mock-auth.ts");
4287
+ } catch (err) {
4288
+ const msg = err instanceof Error ? err.message : String(err);
4289
+ return {
4290
+ content: [
4291
+ {
4292
+ type: "text",
4293
+ text: JSON.stringify({
4294
+ success: false,
4295
+ error: `Failed writing lib/mock-auth.ts: ${msg}`
4296
+ })
4297
+ }
4298
+ ],
4299
+ isError: true
4300
+ };
4301
+ }
4302
+ try {
4303
+ const pkgPath = (0, import_path7.join)(cwd, "package.json");
4304
+ if ((0, import_fs7.existsSync)(pkgPath)) {
4305
+ const existingPkg = (0, import_fs7.readFileSync)(pkgPath, "utf8");
4306
+ const updatedPkg = updatePackageJsonScripts(existingPkg, roles, mockUsers);
4307
+ (0, import_fs7.writeFileSync)(pkgPath, updatedPkg, "utf8");
4308
+ filesWritten.push("package.json");
4309
+ }
4310
+ } catch (err) {
4311
+ const msg = err instanceof Error ? err.message : String(err);
4312
+ return {
4313
+ content: [
4314
+ {
4315
+ type: "text",
4316
+ text: JSON.stringify({
4317
+ success: false,
4318
+ error: `Failed updating package.json: ${msg}`
4319
+ })
4320
+ }
4321
+ ],
4322
+ isError: true
4323
+ };
3923
4324
  }
3924
- filesWritten.push(".env.example");
3925
- } catch (err) {
3926
- const msg = err instanceof Error ? err.message : String(err);
3927
- return {
3928
- content: [
3929
- {
3930
- type: "text",
3931
- text: JSON.stringify({ success: false, error: `Failed writing .env.example: ${msg}` })
3932
- }
3933
- ],
3934
- isError: true
3935
- };
3936
4325
  }
3937
4326
  try {
3938
- const authYaml = generateYamlBlock(
4327
+ const authYaml = devOnly ? generateDevOnlyYamlBlock(
4328
+ method,
4329
+ params,
4330
+ roles,
4331
+ defaultRole,
4332
+ hierarchy,
4333
+ auditEnabled,
4334
+ auditRetentionDays,
4335
+ protectedRoutes
4336
+ ) : generateYamlBlock(
3939
4337
  method,
3940
4338
  params,
3941
4339
  roles,
@@ -4017,7 +4415,9 @@ function registerAuthTools(server2) {
4017
4415
  // Routes
4018
4416
  protectedRoutes: jsonCoerce(import_zod13.z.array(import_zod13.z.string()).optional()),
4019
4417
  // Injection for tests
4020
- _cwd: import_zod13.z.string().optional()
4418
+ _cwd: import_zod13.z.string().optional(),
4419
+ devOnly: boolCoerce(import_zod13.z.boolean().optional()),
4420
+ mockUsers: jsonCoerce(import_zod13.z.array(import_zod13.z.object({ name: import_zod13.z.string(), email: import_zod13.z.string() })).optional())
4021
4421
  },
4022
4422
  async (params) => {
4023
4423
  const cwd = params._cwd ?? process.cwd();
@@ -4037,15 +4437,15 @@ var _checksums = /* @__PURE__ */ new Map([
4037
4437
  ],
4038
4438
  [
4039
4439
  "stackwright-pro-auth-otter.json",
4040
- "8a6ee02cfe7fede3ca708d05b8b46824eb71f60c7f474b6edf9599da77f779b2"
4440
+ "4bf6beba7150d08c74c5f6fbbeb20e988aba52a2029ff2892615e71f6ab12ed1"
4041
4441
  ],
4042
4442
  [
4043
4443
  "stackwright-pro-dashboard-otter.json",
4044
- "f5a83b74ad7c44edc6f39b45a568fa122d82aa4788f741ce14614da56d4e29a4"
4444
+ "9c319d311801730e8dc9bc142eebb8fc5a7f48da48fa0b8d8c3b7431652447be"
4045
4445
  ],
4046
4446
  [
4047
4447
  "stackwright-pro-data-otter.json",
4048
- "c406e1c775bcb1f2b038b40a92d9bd23172b40d774fc0fa50bad4c9714f53445"
4448
+ "4d9369277685a4acc484116920c9622ad8a1838012a493fcfe42a6ae5abe53cf"
4049
4449
  ],
4050
4450
  [
4051
4451
  "stackwright-pro-designer-otter.json",
@@ -4053,7 +4453,7 @@ var _checksums = /* @__PURE__ */ new Map([
4053
4453
  ],
4054
4454
  [
4055
4455
  "stackwright-pro-domain-expert-otter.json",
4056
- "bfe5c167d73fef3f2ef280fff56dcb552073c218e1394a43ecf983a03169ed55"
4456
+ "6055a2efc78f54a8393f628839e2a2563bf0c6de3ad32de00c82779a53381efd"
4057
4457
  ],
4058
4458
  [
4059
4459
  "stackwright-pro-foreman-otter.json",
@@ -4061,15 +4461,15 @@ var _checksums = /* @__PURE__ */ new Map([
4061
4461
  ],
4062
4462
  [
4063
4463
  "stackwright-pro-geo-otter.json",
4064
- "6eb7ecf97254dbd79c09ad24348bf16001423cce9585c14bef81afd67b7b901b"
4464
+ "9e09aaf2bb10197c6d1c05d0fd5f5f9380acc0cb697a410fcae839ffba648561"
4065
4465
  ],
4066
4466
  [
4067
4467
  "stackwright-pro-page-otter.json",
4068
- "9a5672f0758c81539337d86955e2892cd412547b4f111c2aa098eed1e62d7626"
4468
+ "532bb7e9a25a5c832edd1ff1ea0886dd4453905d86e6f9331eb957ae5e121833"
4069
4469
  ],
4070
4470
  [
4071
4471
  "stackwright-pro-polish-otter.json",
4072
- "d31116995fdb417798af6056efd03bb1c71e0891371aba1774d283c03c9d77e8"
4472
+ "8f284d4d6a204137cd786824fc584d5bddac1bc757204769b99ca5412cf2cea2"
4073
4473
  ],
4074
4474
  [
4075
4475
  "stackwright-pro-theme-otter.json",