swallowkit 1.0.0-beta.57 → 1.0.0-beta.59

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 (73) hide show
  1. package/README.ja.md +1 -0
  2. package/README.md +1 -0
  3. package/dist/cli/commands/add-auth.d.ts +3 -1
  4. package/dist/cli/commands/add-auth.d.ts.map +1 -1
  5. package/dist/cli/commands/add-auth.js +55 -21
  6. package/dist/cli/commands/add-auth.js.map +1 -1
  7. package/dist/cli/commands/init.d.ts.map +1 -1
  8. package/dist/cli/commands/init.js +12 -498
  9. package/dist/cli/commands/init.js.map +1 -1
  10. package/dist/cli/index.d.ts.map +1 -1
  11. package/dist/cli/index.js +2 -0
  12. package/dist/cli/index.js.map +1 -1
  13. package/dist/core/operations/auth-operations.d.ts +4 -0
  14. package/dist/core/operations/auth-operations.d.ts.map +1 -1
  15. package/dist/core/operations/auth-operations.js +5 -2
  16. package/dist/core/operations/auth-operations.js.map +1 -1
  17. package/dist/core/operations/create-model.d.ts.map +1 -1
  18. package/dist/core/operations/create-model.js +6 -2
  19. package/dist/core/operations/create-model.js.map +1 -1
  20. package/dist/core/project/agent-instructions.d.ts +29 -0
  21. package/dist/core/project/agent-instructions.d.ts.map +1 -0
  22. package/dist/core/project/agent-instructions.js +159 -0
  23. package/dist/core/project/agent-instructions.js.map +1 -0
  24. package/dist/core/project/capabilities.d.ts +58 -0
  25. package/dist/core/project/capabilities.d.ts.map +1 -0
  26. package/dist/core/project/capabilities.js +135 -0
  27. package/dist/core/project/capabilities.js.map +1 -0
  28. package/dist/core/project/validation.d.ts.map +1 -1
  29. package/dist/core/project/validation.js +48 -0
  30. package/dist/core/project/validation.js.map +1 -1
  31. package/dist/core/project/workflows.d.ts.map +1 -1
  32. package/dist/core/project/workflows.js +46 -2
  33. package/dist/core/project/workflows.js.map +1 -1
  34. package/dist/core/scaffold/auth-generator.d.ts.map +1 -1
  35. package/dist/core/scaffold/auth-generator.js +6 -2
  36. package/dist/core/scaffold/auth-generator.js.map +1 -1
  37. package/dist/core/verify/index.d.ts +7 -0
  38. package/dist/core/verify/index.d.ts.map +1 -1
  39. package/dist/core/verify/index.js +69 -0
  40. package/dist/core/verify/index.js.map +1 -1
  41. package/dist/machine/index.d.ts.map +1 -1
  42. package/dist/machine/index.js +117 -41
  43. package/dist/machine/index.js.map +1 -1
  44. package/dist/mcp/index.d.ts.map +1 -1
  45. package/dist/mcp/index.js +32 -10
  46. package/dist/mcp/index.js.map +1 -1
  47. package/package.json +1 -1
  48. package/src/__tests__/agent-instructions.test.ts +237 -0
  49. package/src/__tests__/agent-loop-phase34.test.ts +66 -2
  50. package/src/__tests__/auth.test.ts +9 -0
  51. package/src/__tests__/init.test.ts +2 -0
  52. package/src/__tests__/machine.test.ts +15 -0
  53. package/src/__tests__/multi-auth.test.ts +12 -0
  54. package/src/__tests__/plan-apply.test.ts +38 -0
  55. package/src/cli/commands/add-auth.ts +59 -21
  56. package/src/cli/commands/init.ts +19 -525
  57. package/src/cli/index.ts +2 -0
  58. package/src/core/operations/auth-operations.ts +9 -2
  59. package/src/core/operations/create-model.ts +7 -2
  60. package/src/core/project/agent-instructions.ts +167 -0
  61. package/src/core/project/agent-templates/AGENTS.md +502 -0
  62. package/src/core/project/agent-templates/CLAUDE.md +31 -0
  63. package/src/core/project/agent-templates/azure-functions.instructions.md +22 -0
  64. package/src/core/project/agent-templates/bff-routes.instructions.md +18 -0
  65. package/src/core/project/agent-templates/copilot-instructions.md +27 -0
  66. package/src/core/project/agent-templates/shared-models.instructions.md +72 -0
  67. package/src/core/project/capabilities.ts +193 -0
  68. package/src/core/project/validation.ts +50 -0
  69. package/src/core/project/workflows.ts +48 -2
  70. package/src/core/scaffold/auth-generator.ts +7 -2
  71. package/src/core/verify/index.ts +76 -0
  72. package/src/machine/index.ts +133 -45
  73. package/src/mcp/index.ts +28 -10
@@ -10,11 +10,12 @@ import { runMachineScaffoldOperation } from "../core/operations/scaffold-machine
10
10
  import { planScaffoldOperation } from "../core/operations/scaffold-plan";
11
11
  import { inspectArtifacts } from "../core/project/artifacts";
12
12
  import { inspectBoundaries } from "../core/project/boundaries";
13
+ import { inspectCapabilities } from "../core/project/capabilities";
13
14
  import { detectDrift } from "../core/project/drift";
14
15
  import { loadProjectManifest } from "../core/project/manifest";
15
16
  import { loadLastVerifyState } from "../core/project/state";
16
17
  import { validateProject } from "../core/project/validation";
17
- import { explainVerifyFailure, runVerify, VerifyResult } from "../core/verify";
18
+ import { explainVerifyFailure, compactVerifyResult, runVerify, VerifyResult } from "../core/verify";
18
19
  import {
19
20
  MachineErrorResponse,
20
21
  MachineNextAction,
@@ -24,8 +25,16 @@ import {
24
25
  } from "./contracts";
25
26
  import { MachineCommandError, resolveMachineErrorStatus, toMachineError } from "./errors";
26
27
 
28
+ /** 最終 JSON envelope 専用の stdout writer。runMachineCli 実行中はこれ以外の stdout 書き込みを stderr へ逃がす。 */
29
+ let machineEnvelopeWrite: ((chunk: string) => void) | null = null;
30
+
27
31
  function writeMachineResponse<TData>(response: MachineResponse<TData>): void {
28
- process.stdout.write(`${JSON.stringify(response, null, 2)}\n`);
32
+ const payload = `${JSON.stringify(response, null, 2)}\n`;
33
+ if (machineEnvelopeWrite) {
34
+ machineEnvelopeWrite(payload);
35
+ } else {
36
+ process.stdout.write(payload);
37
+ }
29
38
  }
30
39
 
31
40
  interface MachineResponseMeta {
@@ -187,6 +196,13 @@ function createMachineProgram(): Command {
187
196
  await handleMachineAction("inspect-boundaries", async () => inspectBoundaries());
188
197
  });
189
198
 
199
+ inspect
200
+ .command("capabilities")
201
+ .description("Return SwallowKit's machine-readable capability contract: model declarations, auth workflow, generated-CRUD scope, seeding, and available commands")
202
+ .action(async () => {
203
+ await handleMachineAction("inspect-capabilities", async () => inspectCapabilities());
204
+ });
205
+
190
206
  inspect
191
207
  .command("infra")
192
208
  .description("Inspect Bicep infrastructure assets (params, modules, outputs, container wiring) without calling Azure")
@@ -273,34 +289,41 @@ function createMachineProgram(): Command {
273
289
  const plan = new Command("plan");
274
290
  plan
275
291
  .command("scaffold")
276
- .description("Compute the scaffold change plan without writing any files")
277
- .argument("<model>", "Model file or model name")
292
+ .description("Compute the scaffold change plan without writing any files (accepts multiple models)")
293
+ .argument("<models...>", "Model files or model names")
278
294
  .option("--functions-dir <dir>", "Functions directory", "functions")
279
295
  .option("--api-dir <dir>", "API routes directory", "app/api")
280
296
  .option("--api-only", "Skip UI components in the plan", false)
281
- .action(async (model: string, options: { functionsDir?: string; apiDir?: string; apiOnly?: boolean }) => {
297
+ .action(async (models: string[], options: { functionsDir?: string; apiDir?: string; apiOnly?: boolean }) => {
282
298
  await handleMachineAction(
283
299
  "plan-scaffold",
284
300
  async () => {
285
301
  ensureProjectForMachine();
286
- return planScaffoldOperation({
287
- model,
288
- functionsDir: options.functionsDir,
289
- apiDir: options.apiDir,
290
- apiOnly: options.apiOnly,
291
- });
302
+ const plans = [];
303
+ for (const model of models) {
304
+ plans.push(
305
+ await planScaffoldOperation({
306
+ model,
307
+ functionsDir: options.functionsDir,
308
+ apiDir: options.apiDir,
309
+ apiOnly: options.apiOnly,
310
+ })
311
+ );
312
+ }
313
+ return plans.length === 1 ? plans[0] : { planType: "scaffold-batch" as const, plans };
292
314
  },
293
- (planData) => ({
294
- status: planData.requiresApproval ? "requires-human" : "complete",
295
- nextActions: [
296
- {
315
+ (data) => {
316
+ const plans = "plans" in data ? data.plans : [data];
317
+ return {
318
+ status: plans.some((planData) => planData.requiresApproval) ? "requires-human" : "complete",
319
+ nextActions: plans.map((planData) => ({
297
320
  command: `swallowkit machine apply scaffold --plan ${planData.planId}${planData.requiresApproval ? " --approve" : ""}`,
298
321
  description: planData.requiresApproval
299
- ? "Apply the plan after reviewing the listed conflicts (requires --approve)."
300
- : "Apply the plan.",
301
- },
302
- ],
303
- })
322
+ ? `Apply the plan for ${planData.model} after reviewing the listed conflicts (requires --approve).`
323
+ : `Apply the plan for ${planData.model}.`,
324
+ })),
325
+ };
326
+ }
304
327
  );
305
328
  });
306
329
 
@@ -309,12 +332,17 @@ function createMachineProgram(): Command {
309
332
  .description("Compute the add-auth change plan without writing any files")
310
333
  .requiredOption("--provider <provider>", "Auth provider: custom-jwt | swa | external-token | none")
311
334
  .option("--scheme <name>", "Add as a named authentication scheme")
312
- .action(async (options: { provider: string; scheme?: string }) => {
335
+ .option("--allowed-providers <list>", "Comma-separated SWA identity providers to allow (e.g. github,aad); defaults to aad")
336
+ .action(async (options: { provider: string; scheme?: string; allowedProviders?: string }) => {
313
337
  await handleMachineAction(
314
338
  "plan-auth",
315
339
  async () => {
316
340
  ensureProjectForMachine();
317
- return planAuthOperation({ provider: options.provider, scheme: options.scheme });
341
+ return planAuthOperation({
342
+ provider: options.provider,
343
+ scheme: options.scheme,
344
+ allowedProviders: options.allowedProviders ? options.allowedProviders.split(",") : undefined,
345
+ });
318
346
  },
319
347
  (planData) => ({
320
348
  status: planData.requiresApproval ? "requires-human" : "complete",
@@ -367,8 +395,8 @@ function createMachineProgram(): Command {
367
395
  const apply = new Command("apply");
368
396
  apply
369
397
  .command("scaffold")
370
- .description("Apply scaffold changes, verifying plan freshness and overwrite approval")
371
- .argument("[model]", "Model file or model name (optional when --plan is given)")
398
+ .description("Apply scaffold changes, verifying plan freshness and overwrite approval (accepts multiple models)")
399
+ .argument("[models...]", "Model files or model names (optional when --plan is given)")
372
400
  .option("--plan <planId>", "Apply a previously computed plan")
373
401
  .option("--approve", "Approve overwriting files that were modified after generation", false)
374
402
  .option("--functions-dir <dir>", "Functions directory")
@@ -376,21 +404,44 @@ function createMachineProgram(): Command {
376
404
  .option("--api-only", "Skip UI components; still update Functions, BFF routes, OpenAPI, and native schema assets")
377
405
  .action(
378
406
  async (
379
- model: string | undefined,
407
+ models: string[],
380
408
  options: { plan?: string; approve?: boolean; functionsDir?: string; apiDir?: string; apiOnly?: boolean }
381
409
  ) => {
382
410
  await handleMachineAction(
383
411
  "apply-scaffold",
384
412
  async () => {
385
413
  ensureProjectForMachine();
386
- return applyScaffoldOperation({
387
- model,
388
- planId: options.plan,
389
- approve: options.approve,
390
- functionsDir: options.functionsDir,
391
- apiDir: options.apiDir,
392
- apiOnly: options.apiOnly,
393
- });
414
+ if (models.length > 1 && options.plan) {
415
+ throw new MachineCommandError(
416
+ "invalid-arguments",
417
+ "--plan applies to a single model. Pass multiple models without --plan (each apply re-plans internally), or apply each plan separately.",
418
+ undefined,
419
+ "failed"
420
+ );
421
+ }
422
+ if (models.length <= 1) {
423
+ return applyScaffoldOperation({
424
+ model: models[0],
425
+ planId: options.plan,
426
+ approve: options.approve,
427
+ functionsDir: options.functionsDir,
428
+ apiDir: options.apiDir,
429
+ apiOnly: options.apiOnly,
430
+ });
431
+ }
432
+ const results = [];
433
+ for (const model of models) {
434
+ results.push(
435
+ await applyScaffoldOperation({
436
+ model,
437
+ approve: options.approve,
438
+ functionsDir: options.functionsDir,
439
+ apiDir: options.apiDir,
440
+ apiOnly: options.apiOnly,
441
+ })
442
+ );
443
+ }
444
+ return { applyType: "scaffold-batch" as const, results };
394
445
  },
395
446
  () => ({
396
447
  status: "complete",
@@ -411,8 +462,9 @@ function createMachineProgram(): Command {
411
462
  .option("--plan <planId>", "Apply a previously computed plan")
412
463
  .option("--provider <provider>", "Auth provider (optional when --plan is given)")
413
464
  .option("--scheme <name>", "Add as a named authentication scheme")
465
+ .option("--allowed-providers <list>", "Comma-separated SWA identity providers to allow (e.g. github,aad); defaults to aad")
414
466
  .option("--approve", "Approve overwriting files that were modified after generation", false)
415
- .action(async (options: { plan?: string; provider?: string; scheme?: string; approve?: boolean }) => {
467
+ .action(async (options: { plan?: string; provider?: string; scheme?: string; allowedProviders?: string; approve?: boolean }) => {
416
468
  await handleMachineAction(
417
469
  "apply-auth",
418
470
  async () => {
@@ -420,19 +472,41 @@ function createMachineProgram(): Command {
420
472
  return applyAuthOperation({
421
473
  provider: options.provider,
422
474
  scheme: options.scheme,
475
+ allowedProviders: options.allowedProviders ? options.allowedProviders.split(",") : undefined,
423
476
  planId: options.plan,
424
477
  approve: options.approve,
425
478
  });
426
479
  },
427
- () => ({
428
- status: "complete",
429
- nextActions: [
430
- {
431
- command: "swallowkit machine verify project",
432
- description: "Verify the project after applying auth changes.",
433
- },
434
- ],
435
- })
480
+ (result) => {
481
+ const configTarget = result.scheme
482
+ ? `auth.authorization.policies (reference scheme "${result.scheme}")`
483
+ : "auth.authorization.policies";
484
+ const nextActions: MachineNextAction[] = [];
485
+ if (result.provider !== "none") {
486
+ nextActions.push({
487
+ command: "edit swallowkit.config.js",
488
+ description: `Define ${configTarget}. The config is an extension point: hand-editing policies is the expected workflow. Do NOT hand-write auth.schemes entries; only plan/apply auth may add schemes.`,
489
+ });
490
+ }
491
+ if (result.provider === "swa") {
492
+ nextActions.push({
493
+ command: "edit swallowkit.config.js",
494
+ description: `Confirm swa.allowedProviders${result.scheme ? ` for scheme "${result.scheme}"` : ""} lists the identity providers you use (e.g. ['github']). Generated login URLs and provider checks use this list; it can also be set at plan time with --allowed-providers.`,
495
+ });
496
+ }
497
+ if (result.provider === "external-token") {
498
+ nextActions.push({
499
+ command: "edit the generated external token verifier",
500
+ description:
501
+ "Implement the verifier stub (it fails closed until implemented). typecheck and verify pass with the stub in place, so a passing verify does NOT mean external-token auth works.",
502
+ });
503
+ }
504
+ nextActions.push({
505
+ command: "swallowkit machine verify project",
506
+ description: "Verify the project after applying auth changes.",
507
+ });
508
+ return { status: "complete", nextActions };
509
+ }
436
510
  );
437
511
  });
438
512
 
@@ -468,10 +542,14 @@ function createMachineProgram(): Command {
468
542
  "--checks <ids>",
469
543
  "Comma-separated check ids to run (structure,drift,typecheck,build,lint,test, plus custom ids from swallowkit.config verify.checks)"
470
544
  )
471
- .action(async (options: { checks?: string }) => {
545
+ .option("--compact", "Suppress info-severity findings/violations from evidence to keep agent-facing output small", false)
546
+ .action(async (options: { checks?: string; compact?: boolean }) => {
472
547
  await handleMachineAction(
473
548
  "verify-project",
474
- async () => runVerify(options.checks ? options.checks.split(",") : undefined),
549
+ async () => {
550
+ const result = await runVerify(options.checks ? options.checks.split(",") : undefined);
551
+ return options.compact ? compactVerifyResult(result) : result;
552
+ },
475
553
  (result) => ({
476
554
  status: result.summary.done ? "complete" : "in-progress",
477
555
  nextActions: result.summary.done
@@ -560,9 +638,17 @@ export async function runMachineCli(argv: string[] = process.argv): Promise<void
560
638
 
561
639
  // Keep stdout reserved for the single JSON envelope: any console output
562
640
  // produced by underlying operations (e.g. config-load logs) goes to stderr.
641
+ // A hard guard on process.stdout.write catches direct writes that bypass console.
563
642
  const originalLog = console.log;
564
643
  const originalInfo = console.info;
565
644
  const originalWarn = console.warn;
645
+ const previousStdoutWrite = process.stdout.write;
646
+ const boundStdoutWrite = previousStdoutWrite.bind(process.stdout);
647
+ machineEnvelopeWrite = (chunk) => {
648
+ boundStdoutWrite(chunk);
649
+ };
650
+ process.stdout.write = ((chunk: string | Uint8Array, ...rest: unknown[]) =>
651
+ (process.stderr.write as (...args: unknown[]) => boolean)(chunk, ...rest)) as typeof process.stdout.write;
566
652
  const toStderr = (...args: unknown[]) => {
567
653
  process.stderr.write(`${args.map((arg) => (typeof arg === "string" ? arg : JSON.stringify(arg))).join(" ")}\n`);
568
654
  };
@@ -598,5 +684,7 @@ export async function runMachineCli(argv: string[] = process.argv): Promise<void
598
684
  console.log = originalLog;
599
685
  console.info = originalInfo;
600
686
  console.warn = originalWarn;
687
+ process.stdout.write = previousStdoutWrite;
688
+ machineEnvelopeWrite = null;
601
689
  }
602
690
  }
package/src/mcp/index.ts CHANGED
@@ -188,15 +188,18 @@ export function buildSwallowKitToolDefinitions(
188
188
  },
189
189
  {
190
190
  name: "swallowkit_plan_scaffold",
191
- description: "Compute the scaffold change plan (files to create/update/overwrite, conflicts, warnings) without writing any files. Returns a planId usable with swallowkit_apply_scaffold.",
191
+ description: "Compute the scaffold change plan (files to create/update/overwrite, conflicts, warnings) without writing any files. Accepts one or more models; returns a planId per model usable with swallowkit_apply_scaffold.",
192
192
  inputSchema: z.object({
193
- model: z.string(),
193
+ model: z.string().optional(),
194
+ models: z.array(z.string()).optional(),
194
195
  functionsDir: z.string().optional(),
195
196
  apiDir: z.string().optional(),
196
197
  apiOnly: z.boolean().optional(),
197
198
  }),
198
- handler: async ({ model, functionsDir, apiDir, apiOnly }: { model: string; functionsDir?: string; apiDir?: string; apiOnly?: boolean }) => {
199
- const args = ["plan", "scaffold", model];
199
+ handler: async ({ model, models, functionsDir, apiDir, apiOnly }: { model?: string; models?: string[]; functionsDir?: string; apiDir?: string; apiOnly?: boolean }) => {
200
+ const targets = models && models.length > 0 ? models : model ? [model] : [];
201
+ if (targets.length === 0) throw new Error("Provide model or models.");
202
+ const args = ["plan", "scaffold", ...targets];
200
203
  if (functionsDir) args.push("--functions-dir", functionsDir);
201
204
  if (apiDir) args.push("--api-dir", apiDir);
202
205
  if (apiOnly) args.push("--api-only");
@@ -249,15 +252,17 @@ export function buildSwallowKitToolDefinitions(
249
252
  },
250
253
  {
251
254
  name: "swallowkit_verify_project",
252
- description: "Run verification checks (structure, drift, typecheck by default; build, lint, test and custom checks from swallowkit.config verify.checks are also available) and return machine-readable evidence. summary.done=true means the project passed all checks.",
255
+ description: "Run verification checks (structure, drift, typecheck by default; build, lint, test and custom checks from swallowkit.config verify.checks are also available) and return machine-readable evidence. summary.done=true means the project passed all checks. Set compact=true to suppress info-severity findings and keep the output small.",
253
256
  inputSchema: z.object({
254
257
  checks: z.array(z.string()).optional(),
258
+ compact: z.boolean().optional(),
255
259
  }),
256
- handler: async ({ checks }: { checks?: string[] }) => {
260
+ handler: async ({ checks, compact }: { checks?: string[]; compact?: boolean }) => {
257
261
  const args = ["verify", "project"];
258
262
  if (checks && checks.length > 0) {
259
263
  args.push("--checks", checks.join(","));
260
264
  }
265
+ if (compact) args.push("--compact");
261
266
 
262
267
  const response = await executeMachineCommand(args, runMachineCli);
263
268
  return jsonTextContent(withOperationStatus(response));
@@ -288,16 +293,27 @@ export function buildSwallowKitToolDefinitions(
288
293
  return jsonTextContent(withSwallowKitMetadata(response.data));
289
294
  },
290
295
  },
296
+ {
297
+ name: "swallowkit_inspect_capabilities",
298
+ description: "Return SwallowKit's capability contract: which declarations models support (partitionKey, authPolicy, displayName, connectorConfig, with format examples), the correct auth-introduction workflow, what generated CRUD does and does NOT guarantee (no owner scoping), how dev seeds are applied, and every machine command. Consult this before assuming SwallowKit can or cannot do something.",
299
+ inputSchema: z.object({}),
300
+ handler: async () => {
301
+ const response = await executeMachineCommand(["inspect", "capabilities"], runMachineCli);
302
+ return jsonTextContent(withSwallowKitMetadata(response.data));
303
+ },
304
+ },
291
305
  {
292
306
  name: "swallowkit_plan_auth",
293
- description: "Compute the add-auth change plan (files to create/update/overwrite, conflicts, warnings) without writing any files. Returns a planId usable with swallowkit_apply_auth.",
307
+ description: "Compute the add-auth change plan (files to create/update/overwrite, conflicts, warnings) without writing any files. Returns a planId usable with swallowkit_apply_auth. Never hand-write auth.schemes in swallowkit.config; this operation owns them.",
294
308
  inputSchema: z.object({
295
309
  provider: z.enum(["custom-jwt", "swa", "external-token", "none"]),
296
310
  scheme: z.string().optional(),
311
+ allowedProviders: z.array(z.string()).optional(),
297
312
  }),
298
- handler: async ({ provider, scheme }: { provider: string; scheme?: string }) => {
313
+ handler: async ({ provider, scheme, allowedProviders }: { provider: string; scheme?: string; allowedProviders?: string[] }) => {
299
314
  const args = ["plan", "auth", "--provider", provider];
300
315
  if (scheme) args.push("--scheme", scheme);
316
+ if (allowedProviders && allowedProviders.length > 0) args.push("--allowed-providers", allowedProviders.join(","));
301
317
 
302
318
  const response = await executeMachineCommand(args, runMachineCli);
303
319
  return jsonTextContent(withOperationStatus(response));
@@ -305,18 +321,20 @@ export function buildSwallowKitToolDefinitions(
305
321
  },
306
322
  {
307
323
  name: "swallowkit_apply_auth",
308
- description: "Apply add-auth changes. Rejects stale plans and requires approve=true when user-modified files would be overwritten.",
324
+ description: "Apply add-auth changes. Rejects stale plans and requires approve=true when user-modified files would be overwritten. Follow the returned nextActions: policies and swa.allowedProviders are hand-edited afterwards, and external-token verifier stubs must be implemented.",
309
325
  inputSchema: z.object({
310
326
  provider: z.enum(["custom-jwt", "swa", "external-token", "none"]).optional(),
311
327
  scheme: z.string().optional(),
328
+ allowedProviders: z.array(z.string()).optional(),
312
329
  planId: z.string().optional(),
313
330
  approve: z.boolean().optional(),
314
331
  }),
315
- handler: async ({ provider, scheme, planId, approve }: { provider?: string; scheme?: string; planId?: string; approve?: boolean }) => {
332
+ handler: async ({ provider, scheme, allowedProviders, planId, approve }: { provider?: string; scheme?: string; allowedProviders?: string[]; planId?: string; approve?: boolean }) => {
316
333
  const args = ["apply", "auth"];
317
334
  if (planId) args.push("--plan", planId);
318
335
  if (provider) args.push("--provider", provider);
319
336
  if (scheme) args.push("--scheme", scheme);
337
+ if (allowedProviders && allowedProviders.length > 0) args.push("--allowed-providers", allowedProviders.join(","));
320
338
  if (approve) args.push("--approve");
321
339
 
322
340
  const response = await executeMachineCommand(args, runMachineCli);