@stackframe/stack-cli 2.8.75 → 2.8.76
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 +459 -9
- package/dist/index.js.map +1 -1
- package/package.json +4 -1
package/dist/index.js
CHANGED
|
@@ -7,7 +7,9 @@ import * as path from "path";
|
|
|
7
7
|
import { dirname, join } from "path";
|
|
8
8
|
import { StackClientApp } from "@stackframe/js";
|
|
9
9
|
import * as os from "os";
|
|
10
|
-
import {
|
|
10
|
+
import { checkbox, confirm, input, select } from "@inquirer/prompts";
|
|
11
|
+
import { ALL_APPS } from "@stackframe/stack-shared/dist/apps/apps-config";
|
|
12
|
+
import { query } from "@anthropic-ai/claude-agent-sdk";
|
|
11
13
|
import * as readline from "readline";
|
|
12
14
|
|
|
13
15
|
//#region src/lib/errors.ts
|
|
@@ -213,19 +215,467 @@ function registerConfigCommand(program) {
|
|
|
213
215
|
});
|
|
214
216
|
}
|
|
215
217
|
|
|
218
|
+
//#endregion
|
|
219
|
+
//#region src/lib/interactive.ts
|
|
220
|
+
function isNonInteractiveEnv() {
|
|
221
|
+
return !!(process.env.CI || process.env.GITHUB_ACTIONS || process.env.NONINTERACTIVE || !process.stdin.isTTY);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
//#endregion
|
|
225
|
+
//#region src/lib/init-prompt.ts
|
|
226
|
+
const createInitPrompt = (web, configPath) => `=============================
|
|
227
|
+
STACK AUTH SETUP INSTRUCTIONS
|
|
228
|
+
=============================
|
|
229
|
+
|
|
230
|
+
These instructions describe how to set up Stack Auth.
|
|
231
|
+
${web ? `
|
|
232
|
+
First of all, if you have access to a terminal, it is better to use the \`npx @stackframe/stack-cli init\`` : ""}
|
|
233
|
+
|
|
234
|
+
Install mcp server from https://mcp.stack-auth.com if not already installed
|
|
235
|
+
|
|
236
|
+
For reference, questions, or information on Stack Auth, you can query the docs on https://docs.stack-auth.com via curl or any tools that you have
|
|
237
|
+
|
|
238
|
+
## Setup
|
|
239
|
+
|
|
240
|
+
### 1) Install the package
|
|
241
|
+
|
|
242
|
+
Run the install command using whatever package manager the project uses (npm, yarn, pnpm, bun):
|
|
243
|
+
|
|
244
|
+
| Framework | Package |
|
|
245
|
+
|-----------|---------|
|
|
246
|
+
| Next.js | \`@stackframe/stack\` |
|
|
247
|
+
| React | \`@stackframe/react\` |
|
|
248
|
+
| Vanilla JS | \`@stackframe/js\` |
|
|
249
|
+
|
|
250
|
+
### 2) Create the Stack apps
|
|
251
|
+
|
|
252
|
+
Depending on whether you're on a client or a server, you will want to create stackClientApp or stackServerApp. Some environments, like Next.js, have both, so create both files.
|
|
253
|
+
|
|
254
|
+
The stack client app has client-level permissions. It contains most of the useful methods and hooks for your client-side code.
|
|
255
|
+
The stack server app has full read and write access to all users. It requires STACK_SECRET_SERVER_KEY env variable and should only be used in secure context
|
|
256
|
+
|
|
257
|
+
In Next.js, env vars are auto-detected (NEXT_PUBLIC_STACK_PROJECT_ID etc.), so the constructor needs no explicit config. For other frameworks, you must pass projectId and publishableClientKey explicitly using the framework's env var access method.
|
|
258
|
+
|
|
259
|
+
The tokenStore should be "nextjs-cookie" for Next.js, or "cookie" for all other frameworks.
|
|
260
|
+
|
|
261
|
+
\`\`\`ts
|
|
262
|
+
// src/stack/client.ts
|
|
263
|
+
import { StackClientApp } from "@stackframe/stack"; // or "@stackframe/react" or "@stackframe/js"
|
|
264
|
+
|
|
265
|
+
export const stackClientApp = new StackClientApp({
|
|
266
|
+
// Next.js: omit projectId/publishableClientKey (auto-detected from NEXT_PUBLIC_ env vars)
|
|
267
|
+
// Other frameworks: pass explicitly, e.g. for Vite:
|
|
268
|
+
// projectId: import.meta.env.VITE_STACK_PROJECT_ID,
|
|
269
|
+
// publishableClientKey: import.meta.env.VITE_STACK_PUBLISHABLE_CLIENT_KEY,
|
|
270
|
+
tokenStore: "nextjs-cookie", // or "cookie" for non-Next.js
|
|
271
|
+
});
|
|
272
|
+
\`\`\`
|
|
273
|
+
|
|
274
|
+
If the framework has server-side support (e.g. Next.js), also create a server app:
|
|
275
|
+
|
|
276
|
+
\`\`\`ts
|
|
277
|
+
// src/stack/server.ts
|
|
278
|
+
import "server-only";
|
|
279
|
+
import { StackServerApp } from "@stackframe/stack";
|
|
280
|
+
import { stackClientApp } from "./client";
|
|
281
|
+
|
|
282
|
+
export const stackServerApp = new StackServerApp({
|
|
283
|
+
inheritsFrom: stackClientApp,
|
|
284
|
+
});
|
|
285
|
+
\`\`\`
|
|
286
|
+
|
|
287
|
+
### 3) Create the Stack handler (if available in framework)
|
|
288
|
+
|
|
289
|
+
This sets up pages for sign in, sign up, password reset, etc.
|
|
290
|
+
|
|
291
|
+
\`\`\`tsx
|
|
292
|
+
import { StackHandler } from "@stackframe/stack"; // Next.js
|
|
293
|
+
// import { StackHandler } from "@stackframe/react"; // React
|
|
294
|
+
|
|
295
|
+
export default function Handler() {
|
|
296
|
+
return <StackHandler fullPage />;
|
|
297
|
+
}
|
|
298
|
+
\`\`\`
|
|
299
|
+
|
|
300
|
+
### 4) Create a Suspense boundary
|
|
301
|
+
|
|
302
|
+
Suspense is necessary for many stack auth hooks such as useUser to function. Add a loading component with a custom loading indicator for the current project. Don't add if one already exists
|
|
303
|
+
|
|
304
|
+
For example:
|
|
305
|
+
\`\`\`tsx
|
|
306
|
+
//src/loading.tsx
|
|
307
|
+
|
|
308
|
+
export default function Loading() {
|
|
309
|
+
return <p>Loading...</p>
|
|
310
|
+
}
|
|
311
|
+
\`\`\`
|
|
312
|
+
|
|
313
|
+
### 5) Link environment variables
|
|
314
|
+
|
|
315
|
+
This is only necessary if not using local emulator. Ensure these are ignored by git.
|
|
316
|
+
|
|
317
|
+
Rename the env var keys in .env to match the framework's convention for client-exposed variables. For example, Vite requires VITE_ prefix, Next.js uses NEXT_PUBLIC_, etc. The values should stay the same — only rename the keys.
|
|
318
|
+
|
|
319
|
+
The required variables are:
|
|
320
|
+
- Project ID (e.g. NEXT_PUBLIC_STACK_PROJECT_ID, VITE_STACK_PROJECT_ID, etc.)
|
|
321
|
+
- Publishable client key (e.g. NEXT_PUBLIC_STACK_PUBLISHABLE_CLIENT_KEY, VITE_STACK_PUBLISHABLE_CLIENT_KEY, etc.)
|
|
322
|
+
- Secret server key: STACK_SECRET_SERVER_KEY (only for frameworks with server-side support, no prefix needed)
|
|
323
|
+
|
|
324
|
+
### 6) React only: Wrap the entire page in a Stack provider
|
|
325
|
+
|
|
326
|
+
This is used for the useUser and useStackApp hooks.
|
|
327
|
+
|
|
328
|
+
\`\`\`tsx
|
|
329
|
+
import { StackProvider, StackTheme } from "@stackframe/stack";
|
|
330
|
+
import { stackClientApp } from "../stack/client"; // adjust relative path
|
|
331
|
+
\`\`\`
|
|
332
|
+
|
|
333
|
+
Then wrap the body content:
|
|
334
|
+
|
|
335
|
+
\`\`\`tsx
|
|
336
|
+
return (
|
|
337
|
+
<body>
|
|
338
|
+
<StackProvider app={stackClientApp}>
|
|
339
|
+
<StackTheme>{children}</StackTheme>
|
|
340
|
+
</StackProvider>
|
|
341
|
+
</body>
|
|
342
|
+
);
|
|
343
|
+
\`\`\`
|
|
344
|
+
`;
|
|
345
|
+
|
|
346
|
+
//#endregion
|
|
347
|
+
//#region src/lib/claude-agent.ts
|
|
348
|
+
const ANTHROPIC_PROXY_BASE_URL = process.env.STACK_CLAUDE_PROXY_URL ?? "https://api.stack-auth.com/api/v1/integrations/ai-proxy";
|
|
349
|
+
const SPINNER_FRAMES = [
|
|
350
|
+
"⠋",
|
|
351
|
+
"⠙",
|
|
352
|
+
"⠹",
|
|
353
|
+
"⠸",
|
|
354
|
+
"⠼",
|
|
355
|
+
"⠴",
|
|
356
|
+
"⠦",
|
|
357
|
+
"⠧",
|
|
358
|
+
"⠇",
|
|
359
|
+
"⠏"
|
|
360
|
+
];
|
|
361
|
+
var AgentProgressUI = class {
|
|
362
|
+
constructor(mainLabel) {
|
|
363
|
+
this.spinnerFrame = 0;
|
|
364
|
+
this.spinnerTimer = null;
|
|
365
|
+
this.activeSpinners = /* @__PURE__ */ new Map();
|
|
366
|
+
this.flushedCount = 0;
|
|
367
|
+
this.pendingCompleted = [];
|
|
368
|
+
this.lastLineCount = 0;
|
|
369
|
+
this.mainLabel = mainLabel;
|
|
370
|
+
}
|
|
371
|
+
start() {
|
|
372
|
+
this.spinnerTimer = setInterval(() => {
|
|
373
|
+
this.spinnerFrame = (this.spinnerFrame + 1) % SPINNER_FRAMES.length;
|
|
374
|
+
this.render();
|
|
375
|
+
}, 80);
|
|
376
|
+
this.render();
|
|
377
|
+
}
|
|
378
|
+
stop(success) {
|
|
379
|
+
if (this.spinnerTimer) {
|
|
380
|
+
clearInterval(this.spinnerTimer);
|
|
381
|
+
this.spinnerTimer = null;
|
|
382
|
+
}
|
|
383
|
+
this.completeAllActive();
|
|
384
|
+
this.clearLines();
|
|
385
|
+
const icon = success ? "\x1B[32m✔\x1B[0m" : "\x1B[31m✖\x1B[0m";
|
|
386
|
+
console.log(`${icon} ${this.mainLabel}`);
|
|
387
|
+
for (const label of this.pendingCompleted) console.log(` \x1b[32m✔\x1b[0m ${label}`);
|
|
388
|
+
this.pendingCompleted = [];
|
|
389
|
+
}
|
|
390
|
+
setSpinner(id, label) {
|
|
391
|
+
this.activeSpinners.set(id, label);
|
|
392
|
+
}
|
|
393
|
+
complete(id, label) {
|
|
394
|
+
const existing = this.activeSpinners.get(id);
|
|
395
|
+
this.activeSpinners.delete(id);
|
|
396
|
+
const finalLabel = label ?? existing;
|
|
397
|
+
if (finalLabel) this.pendingCompleted.push(finalLabel);
|
|
398
|
+
}
|
|
399
|
+
completeAllActive() {
|
|
400
|
+
for (const label of this.activeSpinners.values()) this.pendingCompleted.push(label);
|
|
401
|
+
this.activeSpinners.clear();
|
|
402
|
+
}
|
|
403
|
+
clearLines() {
|
|
404
|
+
if (this.lastLineCount > 0) process.stdout.write(`\x1b[${this.lastLineCount}A\x1b[J`);
|
|
405
|
+
}
|
|
406
|
+
flushCompleted() {
|
|
407
|
+
if (this.pendingCompleted.length === 0) return;
|
|
408
|
+
this.clearLines();
|
|
409
|
+
if (this.flushedCount === 0) {
|
|
410
|
+
const frame = SPINNER_FRAMES[this.spinnerFrame];
|
|
411
|
+
process.stdout.write(`\x1b[36m${frame}\x1b[0m ${this.mainLabel}\n`);
|
|
412
|
+
}
|
|
413
|
+
for (const label of this.pendingCompleted) process.stdout.write(` \x1b[32m✔\x1b[0m ${label}\n`);
|
|
414
|
+
this.flushedCount += this.pendingCompleted.length;
|
|
415
|
+
this.pendingCompleted = [];
|
|
416
|
+
this.lastLineCount = 0;
|
|
417
|
+
}
|
|
418
|
+
render() {
|
|
419
|
+
this.flushCompleted();
|
|
420
|
+
this.clearLines();
|
|
421
|
+
const frame = SPINNER_FRAMES[this.spinnerFrame];
|
|
422
|
+
const lines = [];
|
|
423
|
+
if (this.flushedCount === 0) lines.push(`\x1b[36m${frame}\x1b[0m ${this.mainLabel}`);
|
|
424
|
+
for (const label of this.activeSpinners.values()) lines.push(` \x1b[36m${frame}\x1b[0m ${label}`);
|
|
425
|
+
if (lines.length > 0) {
|
|
426
|
+
const output = lines.join("\n") + "\n";
|
|
427
|
+
process.stdout.write(output);
|
|
428
|
+
}
|
|
429
|
+
this.lastLineCount = lines.length;
|
|
430
|
+
}
|
|
431
|
+
};
|
|
432
|
+
function getToolLabel(toolName, input) {
|
|
433
|
+
switch (toolName) {
|
|
434
|
+
case "Read": return `Reading ${input.file_path ?? "file"}`;
|
|
435
|
+
case "Write": return `Writing ${input.file_path ?? "file"}`;
|
|
436
|
+
case "Edit": return `Editing ${input.file_path ?? "file"}`;
|
|
437
|
+
case "Bash": return `Running \`${truncate(String(input.command ?? ""), 40)}\``;
|
|
438
|
+
case "Glob": return `Searching for ${input.pattern ?? "files"}`;
|
|
439
|
+
case "Grep": return `Searching for "${truncate(String(input.pattern ?? ""), 30)}"`;
|
|
440
|
+
default: return toolName;
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
function truncate(str, maxLen) {
|
|
444
|
+
return str.length > maxLen ? str.slice(0, maxLen - 1) + "…" : str;
|
|
445
|
+
}
|
|
446
|
+
function stripClaudeCodeEnv() {
|
|
447
|
+
const env = { ...process.env };
|
|
448
|
+
delete env.CLAUDECODE;
|
|
449
|
+
return env;
|
|
450
|
+
}
|
|
451
|
+
async function runClaudeAgent(options) {
|
|
452
|
+
const ui = new AgentProgressUI("Setting up Stack Auth...");
|
|
453
|
+
ui.start();
|
|
454
|
+
try {
|
|
455
|
+
let resultText = "";
|
|
456
|
+
for await (const message of query({
|
|
457
|
+
prompt: options.prompt,
|
|
458
|
+
options: {
|
|
459
|
+
allowedTools: [
|
|
460
|
+
"Read",
|
|
461
|
+
"Write",
|
|
462
|
+
"Edit",
|
|
463
|
+
"Bash",
|
|
464
|
+
"Glob",
|
|
465
|
+
"Grep"
|
|
466
|
+
],
|
|
467
|
+
permissionMode: "dontAsk",
|
|
468
|
+
cwd: options.cwd,
|
|
469
|
+
env: {
|
|
470
|
+
...stripClaudeCodeEnv(),
|
|
471
|
+
ANTHROPIC_BASE_URL: ANTHROPIC_PROXY_BASE_URL,
|
|
472
|
+
ANTHROPIC_API_KEY: ""
|
|
473
|
+
},
|
|
474
|
+
stderr: (data) => {
|
|
475
|
+
process.stderr.write(data);
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
})) if ("result" in message) resultText = message.result;
|
|
479
|
+
else if (message.type === "assistant" && message.parent_tool_use_id === null) {
|
|
480
|
+
ui.completeAllActive();
|
|
481
|
+
for (const block of message.message.content) if (block.type === "tool_use") ui.setSpinner(block.id, getToolLabel(block.name, block.input));
|
|
482
|
+
} else if (message.type === "system") {
|
|
483
|
+
const msg = message;
|
|
484
|
+
const taskId = msg.task_id;
|
|
485
|
+
if (msg.subtype === "task_started" && taskId) ui.setSpinner(taskId, String(msg.description ?? "Working..."));
|
|
486
|
+
else if (msg.subtype === "task_progress" && taskId) ui.setSpinner(taskId, String(msg.description ?? "Working..."));
|
|
487
|
+
else if (msg.subtype === "task_notification" && taskId) ui.complete(taskId, String(msg.summary ?? msg.description ?? "Done"));
|
|
488
|
+
}
|
|
489
|
+
ui.stop(true);
|
|
490
|
+
if (resultText) console.log(`\n${resultText}`);
|
|
491
|
+
return true;
|
|
492
|
+
} catch (error) {
|
|
493
|
+
ui.stop(false);
|
|
494
|
+
console.error("\nClaude agent encountered an error:", error instanceof Error ? error.message : error);
|
|
495
|
+
return false;
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
|
|
216
499
|
//#endregion
|
|
217
500
|
//#region src/commands/init.ts
|
|
218
501
|
function registerInitCommand(program) {
|
|
219
|
-
program.command("init").description("Initialize Stack Auth in your project (
|
|
220
|
-
|
|
221
|
-
|
|
502
|
+
program.command("init").description("Initialize Stack Auth in your project").option("--mode <mode>", "Mode: create, link-config, or link-cloud (skips interactive prompts)").option("--apps <apps>", "Comma-separated app IDs to enable (for create mode)").option("--config-file <path>", "Path to existing config file (for link-config mode)").option("--select-project-id <id>", "Project ID to link (for link-cloud mode)").option("--output-dir <dir>", "Directory to write output files (defaults to cwd)").option("--no-agent", "Skip Claude agent and print setup instructions instead").action(async (opts) => {
|
|
503
|
+
if (!(opts.mode != null) && isNonInteractiveEnv()) throw new CliError("stack init requires an interactive terminal. Use --mode flag for non-interactive usage.");
|
|
504
|
+
try {
|
|
505
|
+
await runInit(program, opts);
|
|
506
|
+
} catch (error) {
|
|
507
|
+
if (error != null && typeof error === "object" && "name" in error && error.name === "ExitPromptError") {
|
|
508
|
+
console.log("\nAborted.");
|
|
509
|
+
process.exit(0);
|
|
510
|
+
}
|
|
511
|
+
throw error;
|
|
512
|
+
}
|
|
222
513
|
});
|
|
223
514
|
}
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
515
|
+
async function runInit(program, opts) {
|
|
516
|
+
const flags = program.opts();
|
|
517
|
+
const outputDir = opts.outputDir ? path.resolve(opts.outputDir) : process.cwd();
|
|
518
|
+
console.log("Welcome to Stack Auth!\n");
|
|
519
|
+
const mode = opts.mode ?? await select({
|
|
520
|
+
message: "Would you like to link to an existing project, or create a new one?",
|
|
521
|
+
choices: [{
|
|
522
|
+
name: "Create a new project (local emulator)",
|
|
523
|
+
value: "create"
|
|
524
|
+
}, {
|
|
525
|
+
name: "Link an existing project",
|
|
526
|
+
value: "link"
|
|
527
|
+
}]
|
|
528
|
+
});
|
|
529
|
+
let configPath;
|
|
530
|
+
if (mode === "link" || mode === "link-config" || mode === "link-cloud") configPath = (await handleLink(flags, opts, outputDir)).configPath;
|
|
531
|
+
else if (mode === "create") configPath = (await handleCreate(opts, outputDir)).configPath;
|
|
532
|
+
else throw new CliError(`Unknown mode: ${mode}`);
|
|
533
|
+
const initPrompt = createInitPrompt(false, configPath);
|
|
534
|
+
if (opts.agent !== false && !isNonInteractiveEnv()) {
|
|
535
|
+
if (!await runClaudeAgent({
|
|
536
|
+
prompt: `Execute ALL of the following setup steps in my project now. Do not ask questions — just detect the framework and package manager from existing files and proceed.\n\n${initPrompt}`,
|
|
537
|
+
cwd: outputDir
|
|
538
|
+
})) {
|
|
539
|
+
console.log("\nFalling back to manual instructions:\n");
|
|
540
|
+
console.log(initPrompt);
|
|
541
|
+
}
|
|
542
|
+
} else console.log("\n" + initPrompt);
|
|
543
|
+
}
|
|
544
|
+
async function handleLink(flags, opts, outputDir) {
|
|
545
|
+
let source;
|
|
546
|
+
if (opts.mode === "link-config") source = "config-file";
|
|
547
|
+
else if (opts.mode === "link-cloud") source = "cloud";
|
|
548
|
+
else source = await select({
|
|
549
|
+
message: "How would you like to link your project?",
|
|
550
|
+
choices: [{
|
|
551
|
+
name: "Link from config file",
|
|
552
|
+
value: "config-file"
|
|
553
|
+
}, {
|
|
554
|
+
name: "Link from app.stack-auth.com",
|
|
555
|
+
value: "cloud"
|
|
556
|
+
}]
|
|
557
|
+
});
|
|
558
|
+
if (source === "config-file") return await handleLinkFromConfigFile(opts);
|
|
559
|
+
return await handleLinkFromCloud(flags, opts, outputDir);
|
|
560
|
+
}
|
|
561
|
+
async function handleLinkFromConfigFile(opts) {
|
|
562
|
+
const filePath = opts.configFile ?? await input({
|
|
563
|
+
message: "Path to your existing stack.config.ts:",
|
|
564
|
+
validate: (value) => {
|
|
565
|
+
const resolved = path.resolve(value);
|
|
566
|
+
if (!fs.existsSync(resolved)) return `File not found: ${resolved}`;
|
|
567
|
+
return true;
|
|
568
|
+
}
|
|
569
|
+
});
|
|
570
|
+
const configPath = path.resolve(filePath);
|
|
571
|
+
if (!fs.existsSync(configPath)) throw new CliError(`File not found: ${configPath}`);
|
|
572
|
+
console.log(`\nLinked to config file: ${configPath}`);
|
|
573
|
+
return { configPath };
|
|
574
|
+
}
|
|
575
|
+
async function handleLinkFromCloud(flags, opts, outputDir) {
|
|
576
|
+
let sessionAuth;
|
|
577
|
+
try {
|
|
578
|
+
sessionAuth = resolveSessionAuth(flags);
|
|
579
|
+
} catch (e) {
|
|
580
|
+
if (e instanceof AuthError) {
|
|
581
|
+
if (isNonInteractiveEnv()) throw new CliError("Not logged in. Run `stack login` first or set STACK_CLI_REFRESH_TOKEN.");
|
|
582
|
+
console.log("You need to log in first.\n");
|
|
583
|
+
await performLogin(flags);
|
|
584
|
+
sessionAuth = resolveSessionAuth(flags);
|
|
585
|
+
} else throw e;
|
|
586
|
+
}
|
|
587
|
+
const projects = await (await getInternalUser(sessionAuth)).listOwnedProjects();
|
|
588
|
+
if (projects.length === 0) throw new CliError("You don't own any projects. Create one at app.stack-auth.com first.");
|
|
589
|
+
let projectId;
|
|
590
|
+
if (opts.selectProjectId) {
|
|
591
|
+
if (!projects.find((p) => p.id === opts.selectProjectId)) throw new CliError(`Project '${opts.selectProjectId}' not found among your owned projects.`);
|
|
592
|
+
projectId = opts.selectProjectId;
|
|
593
|
+
} else projectId = await select({
|
|
594
|
+
message: "Select a project:",
|
|
595
|
+
choices: projects.map((p) => ({
|
|
596
|
+
name: `${p.displayName} (${p.id})`,
|
|
597
|
+
value: p.id
|
|
598
|
+
}))
|
|
599
|
+
});
|
|
600
|
+
const apiKey = await projects.find((p) => p.id === projectId).app.createInternalApiKey({
|
|
601
|
+
description: "Created by CLI init script",
|
|
602
|
+
expiresAt: new Date(Date.now() + 1e3 * 60 * 60 * 24 * 365 * 200),
|
|
603
|
+
hasPublishableClientKey: true,
|
|
604
|
+
hasSecretServerKey: true,
|
|
605
|
+
hasSuperSecretAdminKey: false
|
|
606
|
+
});
|
|
607
|
+
const envLines = [
|
|
608
|
+
"# Stack Auth",
|
|
609
|
+
`NEXT_PUBLIC_STACK_PROJECT_ID=${projectId}`,
|
|
610
|
+
`NEXT_PUBLIC_STACK_PUBLISHABLE_CLIENT_KEY=${apiKey.publishableClientKey ?? ""}`,
|
|
611
|
+
`STACK_SECRET_SERVER_KEY=${apiKey.secretServerKey ?? ""}`
|
|
612
|
+
].join("\n");
|
|
613
|
+
const envPath = path.resolve(outputDir, ".env");
|
|
614
|
+
if (fs.existsSync(envPath)) {
|
|
615
|
+
const separator = fs.readFileSync(envPath, "utf-8").endsWith("\n") ? "\n" : "\n\n";
|
|
616
|
+
if (isNonInteractiveEnv()) {
|
|
617
|
+
fs.appendFileSync(envPath, separator + envLines + "\n");
|
|
618
|
+
console.log("\nAppended Stack Auth keys to .env");
|
|
619
|
+
} else if (await confirm({
|
|
620
|
+
message: `.env file already exists. Append Stack Auth keys?`,
|
|
621
|
+
default: true
|
|
622
|
+
})) {
|
|
623
|
+
fs.appendFileSync(envPath, separator + envLines + "\n");
|
|
624
|
+
console.log("\nAppended Stack Auth keys to .env");
|
|
625
|
+
} else {
|
|
626
|
+
console.log("\nHere are your environment variables:\n");
|
|
627
|
+
console.log(envLines);
|
|
628
|
+
}
|
|
629
|
+
} else {
|
|
630
|
+
fs.writeFileSync(envPath, envLines + "\n");
|
|
631
|
+
console.log("\nCreated .env with Stack Auth keys");
|
|
632
|
+
}
|
|
633
|
+
return {};
|
|
634
|
+
}
|
|
635
|
+
async function performLogin(flags) {
|
|
636
|
+
const config = resolveLoginConfig(flags);
|
|
637
|
+
const app = new StackClientApp({
|
|
638
|
+
projectId: "internal",
|
|
639
|
+
publishableClientKey: DEFAULT_PUBLISHABLE_CLIENT_KEY,
|
|
640
|
+
baseUrl: config.apiUrl,
|
|
641
|
+
tokenStore: "memory",
|
|
642
|
+
noAutomaticPrefetch: true
|
|
643
|
+
});
|
|
644
|
+
console.log("Waiting for browser authentication...");
|
|
645
|
+
const result = await app.promptCliLogin({ appUrl: config.dashboardUrl });
|
|
646
|
+
if (result.status === "error") throw new CliError(`Login failed: ${result.error.message}`);
|
|
647
|
+
writeConfigValue("STACK_CLI_REFRESH_TOKEN", result.data);
|
|
648
|
+
console.log("Login successful!\n");
|
|
649
|
+
}
|
|
650
|
+
async function handleCreate(opts, outputDir) {
|
|
651
|
+
const configPath = path.resolve(outputDir, "stack.config.ts");
|
|
652
|
+
console.log(`\nCreating a new config file at ${configPath}!\n`);
|
|
653
|
+
let selectedApps;
|
|
654
|
+
if (opts.apps) {
|
|
655
|
+
selectedApps = opts.apps.split(",").map((s) => s.trim()).filter(Boolean);
|
|
656
|
+
const validAppIds = Object.keys(ALL_APPS);
|
|
657
|
+
const invalidApps = selectedApps.filter((id) => !validAppIds.includes(id));
|
|
658
|
+
if (invalidApps.length > 0) throw new CliError(`Unknown app IDs: ${invalidApps.join(", ")}. Valid IDs: ${validAppIds.join(", ")}`);
|
|
659
|
+
} else {
|
|
660
|
+
const stageOrder = {
|
|
661
|
+
stable: 0,
|
|
662
|
+
beta: 1
|
|
663
|
+
};
|
|
664
|
+
selectedApps = await checkbox({
|
|
665
|
+
message: "Select apps to enable:",
|
|
666
|
+
choices: Object.entries(ALL_APPS).filter(([, app]) => app.stage !== "alpha").sort((a, b) => stageOrder[a[1].stage] - stageOrder[b[1].stage]).map(([id, app]) => ({
|
|
667
|
+
name: `${app.displayName} - ${app.subtitle}${app.stage !== "stable" ? ` (${app.stage})` : ""}`,
|
|
668
|
+
value: id,
|
|
669
|
+
checked: id === "authentication"
|
|
670
|
+
}))
|
|
671
|
+
});
|
|
672
|
+
}
|
|
673
|
+
const config = { apps: { installed: Object.fromEntries(selectedApps.map((appId) => [appId, { enabled: true }])) } };
|
|
674
|
+
const content = `export const config = ${JSON.stringify(config, null, 2)};\n`;
|
|
675
|
+
fs.mkdirSync(path.dirname(configPath), { recursive: true });
|
|
676
|
+
fs.writeFileSync(configPath, content);
|
|
677
|
+
console.log(`\nConfig file written to ${configPath}`);
|
|
678
|
+
return { configPath };
|
|
229
679
|
}
|
|
230
680
|
|
|
231
681
|
//#endregion
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../src/lib/errors.ts","../src/lib/config.ts","../src/lib/auth.ts","../src/commands/login.ts","../src/commands/logout.ts","../src/lib/app.ts","../src/commands/exec.ts","../src/commands/config-file.ts","../src/commands/init.ts","../src/lib/interactive.ts","../src/commands/project.ts","../src/index.ts"],"sourcesContent":["export class CliError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"CliError\";\n }\n}\n\nexport class AuthError extends CliError {\n constructor(message: string) {\n super(message);\n this.name = \"AuthError\";\n }\n}\n","import * as fs from \"fs\";\nimport * as path from \"path\";\nimport * as os from \"os\";\n\nconst CONFIG_PATH = process.env.STACK_CLI_CONFIG_PATH ?? path.join(os.homedir(), \".config\", \"stack-auth\", \"credentials.json\");\n\ntype ConfigKey = \"STACK_CLI_REFRESH_TOKEN\" | \"STACK_API_URL\" | \"STACK_DASHBOARD_URL\";\n\nfunction readConfigJson(): Record<string, string> {\n try {\n return JSON.parse(fs.readFileSync(CONFIG_PATH, \"utf-8\"));\n } catch {\n return {};\n }\n}\n\nfunction writeConfigJson(data: Record<string, string>): void {\n fs.mkdirSync(path.dirname(CONFIG_PATH), { recursive: true });\n fs.writeFileSync(CONFIG_PATH, JSON.stringify(data, null, 2) + \"\\n\", { mode: 0o600 });\n}\n\nexport function readConfigValue(key: ConfigKey): string | undefined {\n const config = readConfigJson();\n return config[key];\n}\n\nexport function writeConfigValue(key: ConfigKey, value: string): void {\n const config = readConfigJson();\n config[key] = value;\n writeConfigJson(config);\n}\n\nexport function removeConfigValue(key: ConfigKey): void {\n const config = readConfigJson();\n delete config[key];\n writeConfigJson(config);\n}\n","import { readConfigValue } from \"./config.js\";\nimport { AuthError } from \"./errors.js\";\n\nexport const DEFAULT_API_URL = \"https://api.stack-auth.com\";\nexport const DEFAULT_DASHBOARD_URL = \"https://app.stack-auth.com\";\nexport const DEFAULT_PUBLISHABLE_CLIENT_KEY = process.env.STACK_CLI_PUBLISHABLE_CLIENT_KEY ?? \"pck_6ypt981excjnk24dmgx5703my25k2f3y2z3qjhbykz3q0\";\n\ntype Flags = {\n projectId?: string,\n};\n\nexport type LoginConfig = {\n apiUrl: string,\n dashboardUrl: string,\n};\n\nexport type SessionAuth = LoginConfig & {\n refreshToken: string,\n};\n\nexport type ProjectAuth = SessionAuth & {\n projectId: string,\n};\n\nfunction resolveApiUrl(): string {\n return process.env.STACK_API_URL\n ?? readConfigValue(\"STACK_API_URL\")\n ?? DEFAULT_API_URL;\n}\n\nfunction resolveDashboardUrl(): string {\n return process.env.STACK_DASHBOARD_URL\n ?? readConfigValue(\"STACK_DASHBOARD_URL\")\n ?? DEFAULT_DASHBOARD_URL;\n}\n\nfunction resolveRefreshToken(): string {\n const token = process.env.STACK_CLI_REFRESH_TOKEN\n ?? readConfigValue(\"STACK_CLI_REFRESH_TOKEN\");\n if (!token) {\n throw new AuthError(\"Not logged in. Run `stack login` first.\");\n }\n return token;\n}\n\nfunction resolveProjectId(flags: Flags): string {\n const projectId = flags.projectId ?? process.env.STACK_PROJECT_ID;\n if (!projectId) {\n throw new AuthError(\"No project ID specified. Use --project-id or set STACK_PROJECT_ID.\");\n }\n return projectId;\n}\n\nexport function resolveLoginConfig(flags: Flags): LoginConfig {\n return {\n apiUrl: resolveApiUrl(),\n dashboardUrl: resolveDashboardUrl(),\n };\n}\n\nexport function resolveSessionAuth(flags: Flags): SessionAuth {\n return {\n ...resolveLoginConfig(flags),\n refreshToken: resolveRefreshToken(),\n };\n}\n\nexport function resolveAuth(flags: Flags): ProjectAuth {\n return {\n ...resolveSessionAuth(flags),\n projectId: resolveProjectId(flags),\n };\n}\n","import { Command } from \"commander\";\nimport { StackClientApp } from \"@stackframe/js\";\nimport { resolveLoginConfig, DEFAULT_PUBLISHABLE_CLIENT_KEY } from \"../lib/auth.js\";\nimport { writeConfigValue } from \"../lib/config.js\";\nimport { CliError } from \"../lib/errors.js\";\n\nexport function registerLoginCommand(program: Command) {\n program\n .command(\"login\")\n .description(\"Log in to Stack Auth via browser\")\n .action(async () => {\n const flags = program.opts();\n const config = resolveLoginConfig(flags);\n\n const app = new StackClientApp({\n projectId: \"internal\",\n publishableClientKey: DEFAULT_PUBLISHABLE_CLIENT_KEY,\n baseUrl: config.apiUrl,\n tokenStore: \"memory\",\n noAutomaticPrefetch: true,\n });\n\n console.log(\"Waiting for browser authentication...\");\n\n const result = await app.promptCliLogin({\n appUrl: config.dashboardUrl,\n });\n\n if (result.status === \"error\") {\n throw new CliError(`Login failed: ${result.error.message}`);\n }\n\n writeConfigValue(\"STACK_CLI_REFRESH_TOKEN\", result.data);\n console.log(\"Login successful!\");\n });\n}\n","import { Command } from \"commander\";\nimport { removeConfigValue } from \"../lib/config.js\";\n\nexport function registerLogoutCommand(program: Command) {\n program\n .command(\"logout\")\n .description(\"Log out of Stack Auth\")\n .action(() => {\n removeConfigValue(\"STACK_CLI_REFRESH_TOKEN\");\n console.log(\"Logged out successfully.\");\n });\n}\n","import { StackClientApp } from \"@stackframe/js\";\nimport type { CurrentInternalUser, AdminOwnedProject } from \"@stackframe/js\";\nimport { AuthError } from \"./errors.js\";\nimport { DEFAULT_PUBLISHABLE_CLIENT_KEY } from \"./auth.js\";\nimport type { SessionAuth, ProjectAuth } from \"./auth.js\";\n\nexport function getInternalApp(auth: SessionAuth): StackClientApp<true, \"internal\"> {\n return new StackClientApp({\n projectId: \"internal\",\n publishableClientKey: DEFAULT_PUBLISHABLE_CLIENT_KEY,\n baseUrl: auth.apiUrl,\n tokenStore: {\n accessToken: \"\",\n refreshToken: auth.refreshToken,\n },\n noAutomaticPrefetch: true,\n });\n}\n\nexport async function getInternalUser(auth: SessionAuth): Promise<CurrentInternalUser> {\n const app = getInternalApp(auth);\n const user = await app.getUser({ or: \"throw\" });\n return user as CurrentInternalUser;\n}\n\nexport async function getAdminProject(auth: ProjectAuth): Promise<AdminOwnedProject> {\n const user = await getInternalUser(auth);\n const projects = await user.listOwnedProjects();\n const project = projects.find((p) => p.id === auth.projectId);\n if (!project) {\n throw new AuthError(`Project '${auth.projectId}' not found. Make sure you own this project.`);\n }\n return project;\n}\n","import { Command } from \"commander\";\nimport { resolveAuth } from \"../lib/auth.js\";\nimport { getAdminProject } from \"../lib/app.js\";\nimport { CliError } from \"../lib/errors.js\";\n\nfunction getErrorMessage(err: unknown): string {\n if (err instanceof Error) {\n return err.message;\n }\n if (typeof err === \"string\") {\n return err;\n }\n try {\n return JSON.stringify(err);\n } catch {\n return String(err);\n }\n}\n\nexport function registerExecCommand(program: Command) {\n program\n .command(\"exec [javascript]\")\n .description(\"Execute JavaScript with a pre-configured StackServerApp as `stackServerApp`\")\n .addHelpText(\"after\", \"\\nFor available API methods, see: https://docs.stack-auth.com/docs/sdk\")\n .action(async (javascript: string | undefined) => {\n if (javascript === undefined) {\n throw new CliError(\"Missing JavaScript argument. Use `stack exec \\\"<javascript>\\\"` or `stack exec --help`.\");\n }\n\n const flags = program.opts();\n const auth = resolveAuth(flags);\n const project = await getAdminProject(auth);\n\n // eslint-disable-next-line @typescript-eslint/no-implied-eval\n const AsyncFunction = Object.getPrototypeOf(async function(){}).constructor;\n let fn;\n try {\n fn = new AsyncFunction(\"stackServerApp\", javascript);\n } catch (err: unknown) {\n throw new CliError(`Syntax error in exec code: ${getErrorMessage(err)}`);\n }\n let result;\n try {\n result = await fn(project.app);\n } catch (err: unknown) {\n throw new CliError(`Exec error: ${getErrorMessage(err)}`);\n }\n\n if (result !== undefined) {\n console.log(JSON.stringify(result, null, 2));\n }\n });\n}\n","import { Command } from \"commander\";\nimport * as path from \"path\";\nimport * as fs from \"fs\";\nimport { resolveAuth } from \"../lib/auth.js\";\nimport { getAdminProject } from \"../lib/app.js\";\nimport { CliError } from \"../lib/errors.js\";\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n if (value === null || typeof value !== \"object\" || Array.isArray(value)) {\n return false;\n }\n const prototype = Object.getPrototypeOf(value);\n return prototype === Object.prototype || prototype === null;\n}\n\nexport function registerConfigCommand(program: Command) {\n const config = program\n .command(\"config\")\n .description(\"Manage project configuration files\");\n\n config\n .command(\"pull\")\n .description(\"Pull branch config to a local file\")\n .requiredOption(\"--config-file <path>\", \"Path to write config file (.js or .ts)\")\n .action(async (opts) => {\n const flags = program.opts();\n const auth = resolveAuth(flags);\n const project = await getAdminProject(auth);\n\n const configOverride = await project.getConfigOverride(\"branch\");\n const filePath = path.resolve(opts.configFile);\n const ext = path.extname(filePath);\n\n if (ext !== \".js\" && ext !== \".ts\") {\n throw new CliError(\"Config file must have a .js or .ts extension.\");\n }\n\n const json = JSON.stringify(configOverride, null, 2);\n const content = ext === \".ts\"\n ? `export const config = ${json} as const;\\n`\n : `export const config = ${json};\\n`;\n\n fs.writeFileSync(filePath, content);\n console.log(`Config written to ${filePath}`);\n });\n\n config\n .command(\"push\")\n .description(\"Push a local config file to branch config\")\n .requiredOption(\"--config-file <path>\", \"Path to config file (.js or .ts)\")\n .action(async (opts) => {\n const flags = program.opts();\n const auth = resolveAuth(flags);\n const project = await getAdminProject(auth);\n\n const filePath = path.resolve(opts.configFile);\n const ext = path.extname(filePath);\n\n if (ext !== \".js\" && ext !== \".ts\") {\n throw new CliError(\"Config file must have a .js or .ts extension.\");\n }\n\n if (!fs.existsSync(filePath)) {\n throw new CliError(`Config file not found: ${filePath}`);\n }\n\n let configModule: { config?: unknown };\n if (ext === \".ts\") {\n const { createJiti } = await import(\"jiti\");\n const jiti = createJiti(import.meta.url);\n configModule = await jiti.import(filePath);\n } else {\n configModule = await import(filePath);\n }\n\n const config = configModule.config;\n if (!isPlainObject(config)) {\n throw new CliError(\"Config file must export a plain `config` object. Example: export const config = { ... };\");\n }\n\n await project.replaceConfigOverride(\"branch\", config);\n console.log(\"Config pushed successfully.\");\n });\n}\n","import { Command } from \"commander\";\nimport { execFileSync } from \"child_process\";\n\nexport function registerInitCommand(program: Command) {\n program\n .command(\"init\")\n .description(\"Initialize Stack Auth in your project (delegates to @stackframe/init-stack)\")\n .allowUnknownOption(true)\n .helpOption(false)\n .action((_opts, cmd) => {\n const args = cmd.args as string[];\n execFileSync(\"npx\", [\"@stackframe/init-stack@latest\", ...args], {\n stdio: \"inherit\",\n });\n });\n}\n","export function isNonInteractiveEnv(): boolean {\n return !!(\n process.env.CI\n || process.env.GITHUB_ACTIONS\n || process.env.NONINTERACTIVE\n || !process.stdin.isTTY\n );\n}\n","import { Command } from \"commander\";\nimport * as readline from \"readline\";\nimport { resolveSessionAuth } from \"../lib/auth.js\";\nimport { getInternalUser } from \"../lib/app.js\";\nimport { isNonInteractiveEnv } from \"../lib/interactive.js\";\nimport { CliError } from \"../lib/errors.js\";\n\nfunction prompt(question: string): Promise<string> {\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n return new Promise((resolve) => {\n rl.question(question, (answer) => {\n rl.close();\n resolve(answer);\n });\n });\n}\n\nexport function registerProjectCommand(program: Command) {\n const project = program\n .command(\"project\")\n .description(\"Manage projects\");\n\n project\n .command(\"list\")\n .description(\"List your owned projects\")\n .action(async () => {\n const flags = program.opts();\n const auth = resolveSessionAuth(flags);\n const user = await getInternalUser(auth);\n const projects = await user.listOwnedProjects();\n\n if (program.opts().json) {\n console.log(JSON.stringify(projects.map((p) => ({ id: p.id, displayName: p.displayName })), null, 2));\n } else {\n if (projects.length === 0) {\n console.log(\"No projects found.\");\n return;\n }\n for (const p of projects) {\n console.log(`${p.id}\\t${p.displayName}`);\n }\n }\n });\n\n project\n .command(\"create\")\n .description(\"Create a new project\")\n .option(\"--display-name <name>\", \"Project display name\")\n .action(async (opts) => {\n const flags = program.opts();\n const auth = resolveSessionAuth(flags);\n const user = await getInternalUser(auth);\n\n let displayName: string = opts.displayName;\n if (!displayName) {\n if (isNonInteractiveEnv()) {\n throw new CliError(\"--display-name is required in non-interactive environments (CI).\");\n }\n displayName = await prompt(\"Project display name: \");\n if (!displayName.trim()) {\n throw new CliError(\"Display name cannot be empty.\");\n }\n }\n\n const teams = await user.listTeams();\n if (teams.length === 0) {\n throw new CliError(\"No teams found. You need a team to create a project.\");\n }\n\n const newProject = await user.createProject({\n displayName,\n teamId: teams[0].id,\n });\n\n if (program.opts().json) {\n console.log(JSON.stringify({ id: newProject.id, displayName: newProject.displayName }, null, 2));\n } else {\n console.log(`Project created: ${newProject.id} (${newProject.displayName})`);\n }\n });\n}\n","import { Command } from \"commander\";\nimport { readFileSync } from \"fs\";\nimport { fileURLToPath } from \"url\";\nimport { dirname, join } from \"path\";\nimport { AuthError, CliError } from \"./lib/errors.js\";\nimport { registerLoginCommand } from \"./commands/login.js\";\nimport { registerLogoutCommand } from \"./commands/logout.js\";\nimport { registerExecCommand } from \"./commands/exec.js\";\nimport { registerConfigCommand } from \"./commands/config-file.js\";\nimport { registerInitCommand } from \"./commands/init.js\";\nimport { registerProjectCommand } from \"./commands/project.js\";\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = dirname(__filename);\nconst pkg = JSON.parse(readFileSync(join(__dirname, \"..\", \"package.json\"), \"utf-8\"));\n\nconst program = new Command();\n\nprogram\n .name(\"stack\")\n .description(\"Stack Auth CLI\")\n .version(pkg.version)\n .option(\"--project-id <id>\", \"Project ID\")\n .option(\"--json\", \"Output in JSON format\");\n\nregisterLoginCommand(program);\nregisterLogoutCommand(program);\nregisterExecCommand(program);\nregisterConfigCommand(program);\nregisterInitCommand(program);\nregisterProjectCommand(program);\n\nasync function main() {\n try {\n await program.parseAsync(process.argv);\n } catch (err) {\n if (err instanceof AuthError) {\n console.error(`Auth error: ${err.message}`);\n process.exit(1);\n }\n if (err instanceof CliError) {\n console.error(`Error: ${err.message}`);\n process.exit(1);\n }\n throw err;\n }\n}\n\n// eslint-disable-next-line @typescript-eslint/no-floating-promises\nmain();\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/lib/errors.ts","../src/lib/config.ts","../src/lib/auth.ts","../src/commands/login.ts","../src/commands/logout.ts","../src/lib/app.ts","../src/commands/exec.ts","../src/commands/config-file.ts","../src/lib/interactive.ts","../src/lib/init-prompt.ts","../src/lib/claude-agent.ts","../src/commands/init.ts","../src/commands/project.ts","../src/index.ts"],"sourcesContent":["export class CliError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"CliError\";\n }\n}\n\nexport class AuthError extends CliError {\n constructor(message: string) {\n super(message);\n this.name = \"AuthError\";\n }\n}\n","import * as fs from \"fs\";\nimport * as path from \"path\";\nimport * as os from \"os\";\n\nconst CONFIG_PATH = process.env.STACK_CLI_CONFIG_PATH ?? path.join(os.homedir(), \".config\", \"stack-auth\", \"credentials.json\");\n\ntype ConfigKey = \"STACK_CLI_REFRESH_TOKEN\" | \"STACK_API_URL\" | \"STACK_DASHBOARD_URL\";\n\nfunction readConfigJson(): Record<string, string> {\n try {\n return JSON.parse(fs.readFileSync(CONFIG_PATH, \"utf-8\"));\n } catch {\n return {};\n }\n}\n\nfunction writeConfigJson(data: Record<string, string>): void {\n fs.mkdirSync(path.dirname(CONFIG_PATH), { recursive: true });\n fs.writeFileSync(CONFIG_PATH, JSON.stringify(data, null, 2) + \"\\n\", { mode: 0o600 });\n}\n\nexport function readConfigValue(key: ConfigKey): string | undefined {\n const config = readConfigJson();\n return config[key];\n}\n\nexport function writeConfigValue(key: ConfigKey, value: string): void {\n const config = readConfigJson();\n config[key] = value;\n writeConfigJson(config);\n}\n\nexport function removeConfigValue(key: ConfigKey): void {\n const config = readConfigJson();\n delete config[key];\n writeConfigJson(config);\n}\n","import { readConfigValue } from \"./config.js\";\nimport { AuthError } from \"./errors.js\";\n\nexport const DEFAULT_API_URL = \"https://api.stack-auth.com\";\nexport const DEFAULT_DASHBOARD_URL = \"https://app.stack-auth.com\";\nexport const DEFAULT_PUBLISHABLE_CLIENT_KEY = process.env.STACK_CLI_PUBLISHABLE_CLIENT_KEY ?? \"pck_6ypt981excjnk24dmgx5703my25k2f3y2z3qjhbykz3q0\";\n\ntype Flags = {\n projectId?: string,\n};\n\nexport type LoginConfig = {\n apiUrl: string,\n dashboardUrl: string,\n};\n\nexport type SessionAuth = LoginConfig & {\n refreshToken: string,\n};\n\nexport type ProjectAuth = SessionAuth & {\n projectId: string,\n};\n\nfunction resolveApiUrl(): string {\n return process.env.STACK_API_URL\n ?? readConfigValue(\"STACK_API_URL\")\n ?? DEFAULT_API_URL;\n}\n\nfunction resolveDashboardUrl(): string {\n return process.env.STACK_DASHBOARD_URL\n ?? readConfigValue(\"STACK_DASHBOARD_URL\")\n ?? DEFAULT_DASHBOARD_URL;\n}\n\nfunction resolveRefreshToken(): string {\n const token = process.env.STACK_CLI_REFRESH_TOKEN\n ?? readConfigValue(\"STACK_CLI_REFRESH_TOKEN\");\n if (!token) {\n throw new AuthError(\"Not logged in. Run `stack login` first.\");\n }\n return token;\n}\n\nfunction resolveProjectId(flags: Flags): string {\n const projectId = flags.projectId ?? process.env.STACK_PROJECT_ID;\n if (!projectId) {\n throw new AuthError(\"No project ID specified. Use --project-id or set STACK_PROJECT_ID.\");\n }\n return projectId;\n}\n\nexport function resolveLoginConfig(flags: Flags): LoginConfig {\n return {\n apiUrl: resolveApiUrl(),\n dashboardUrl: resolveDashboardUrl(),\n };\n}\n\nexport function resolveSessionAuth(flags: Flags): SessionAuth {\n return {\n ...resolveLoginConfig(flags),\n refreshToken: resolveRefreshToken(),\n };\n}\n\nexport function resolveAuth(flags: Flags): ProjectAuth {\n return {\n ...resolveSessionAuth(flags),\n projectId: resolveProjectId(flags),\n };\n}\n","import { Command } from \"commander\";\nimport { StackClientApp } from \"@stackframe/js\";\nimport { resolveLoginConfig, DEFAULT_PUBLISHABLE_CLIENT_KEY } from \"../lib/auth.js\";\nimport { writeConfigValue } from \"../lib/config.js\";\nimport { CliError } from \"../lib/errors.js\";\n\nexport function registerLoginCommand(program: Command) {\n program\n .command(\"login\")\n .description(\"Log in to Stack Auth via browser\")\n .action(async () => {\n const flags = program.opts();\n const config = resolveLoginConfig(flags);\n\n const app = new StackClientApp({\n projectId: \"internal\",\n publishableClientKey: DEFAULT_PUBLISHABLE_CLIENT_KEY,\n baseUrl: config.apiUrl,\n tokenStore: \"memory\",\n noAutomaticPrefetch: true,\n });\n\n console.log(\"Waiting for browser authentication...\");\n\n const result = await app.promptCliLogin({\n appUrl: config.dashboardUrl,\n });\n\n if (result.status === \"error\") {\n throw new CliError(`Login failed: ${result.error.message}`);\n }\n\n writeConfigValue(\"STACK_CLI_REFRESH_TOKEN\", result.data);\n console.log(\"Login successful!\");\n });\n}\n","import { Command } from \"commander\";\nimport { removeConfigValue } from \"../lib/config.js\";\n\nexport function registerLogoutCommand(program: Command) {\n program\n .command(\"logout\")\n .description(\"Log out of Stack Auth\")\n .action(() => {\n removeConfigValue(\"STACK_CLI_REFRESH_TOKEN\");\n console.log(\"Logged out successfully.\");\n });\n}\n","import { StackClientApp } from \"@stackframe/js\";\nimport type { CurrentInternalUser, AdminOwnedProject } from \"@stackframe/js\";\nimport { AuthError } from \"./errors.js\";\nimport { DEFAULT_PUBLISHABLE_CLIENT_KEY } from \"./auth.js\";\nimport type { SessionAuth, ProjectAuth } from \"./auth.js\";\n\nexport function getInternalApp(auth: SessionAuth): StackClientApp<true, \"internal\"> {\n return new StackClientApp({\n projectId: \"internal\",\n publishableClientKey: DEFAULT_PUBLISHABLE_CLIENT_KEY,\n baseUrl: auth.apiUrl,\n tokenStore: {\n accessToken: \"\",\n refreshToken: auth.refreshToken,\n },\n noAutomaticPrefetch: true,\n });\n}\n\nexport async function getInternalUser(auth: SessionAuth): Promise<CurrentInternalUser> {\n const app = getInternalApp(auth);\n const user = await app.getUser({ or: \"throw\" });\n return user as CurrentInternalUser;\n}\n\nexport async function getAdminProject(auth: ProjectAuth): Promise<AdminOwnedProject> {\n const user = await getInternalUser(auth);\n const projects = await user.listOwnedProjects();\n const project = projects.find((p) => p.id === auth.projectId);\n if (!project) {\n throw new AuthError(`Project '${auth.projectId}' not found. Make sure you own this project.`);\n }\n return project;\n}\n","import { Command } from \"commander\";\nimport { resolveAuth } from \"../lib/auth.js\";\nimport { getAdminProject } from \"../lib/app.js\";\nimport { CliError } from \"../lib/errors.js\";\n\nfunction getErrorMessage(err: unknown): string {\n if (err instanceof Error) {\n return err.message;\n }\n if (typeof err === \"string\") {\n return err;\n }\n try {\n return JSON.stringify(err);\n } catch {\n return String(err);\n }\n}\n\nexport function registerExecCommand(program: Command) {\n program\n .command(\"exec [javascript]\")\n .description(\"Execute JavaScript with a pre-configured StackServerApp as `stackServerApp`\")\n .addHelpText(\"after\", \"\\nFor available API methods, see: https://docs.stack-auth.com/docs/sdk\")\n .action(async (javascript: string | undefined) => {\n if (javascript === undefined) {\n throw new CliError(\"Missing JavaScript argument. Use `stack exec \\\"<javascript>\\\"` or `stack exec --help`.\");\n }\n\n const flags = program.opts();\n const auth = resolveAuth(flags);\n const project = await getAdminProject(auth);\n\n // eslint-disable-next-line @typescript-eslint/no-implied-eval\n const AsyncFunction = Object.getPrototypeOf(async function(){}).constructor;\n let fn;\n try {\n fn = new AsyncFunction(\"stackServerApp\", javascript);\n } catch (err: unknown) {\n throw new CliError(`Syntax error in exec code: ${getErrorMessage(err)}`);\n }\n let result;\n try {\n result = await fn(project.app);\n } catch (err: unknown) {\n throw new CliError(`Exec error: ${getErrorMessage(err)}`);\n }\n\n if (result !== undefined) {\n console.log(JSON.stringify(result, null, 2));\n }\n });\n}\n","import { Command } from \"commander\";\nimport * as path from \"path\";\nimport * as fs from \"fs\";\nimport { resolveAuth } from \"../lib/auth.js\";\nimport { getAdminProject } from \"../lib/app.js\";\nimport { CliError } from \"../lib/errors.js\";\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n if (value === null || typeof value !== \"object\" || Array.isArray(value)) {\n return false;\n }\n const prototype = Object.getPrototypeOf(value);\n return prototype === Object.prototype || prototype === null;\n}\n\nexport function registerConfigCommand(program: Command) {\n const config = program\n .command(\"config\")\n .description(\"Manage project configuration files\");\n\n config\n .command(\"pull\")\n .description(\"Pull branch config to a local file\")\n .requiredOption(\"--config-file <path>\", \"Path to write config file (.js or .ts)\")\n .action(async (opts) => {\n const flags = program.opts();\n const auth = resolveAuth(flags);\n const project = await getAdminProject(auth);\n\n const configOverride = await project.getConfigOverride(\"branch\");\n const filePath = path.resolve(opts.configFile);\n const ext = path.extname(filePath);\n\n if (ext !== \".js\" && ext !== \".ts\") {\n throw new CliError(\"Config file must have a .js or .ts extension.\");\n }\n\n const json = JSON.stringify(configOverride, null, 2);\n const content = ext === \".ts\"\n ? `export const config = ${json} as const;\\n`\n : `export const config = ${json};\\n`;\n\n fs.writeFileSync(filePath, content);\n console.log(`Config written to ${filePath}`);\n });\n\n config\n .command(\"push\")\n .description(\"Push a local config file to branch config\")\n .requiredOption(\"--config-file <path>\", \"Path to config file (.js or .ts)\")\n .action(async (opts) => {\n const flags = program.opts();\n const auth = resolveAuth(flags);\n const project = await getAdminProject(auth);\n\n const filePath = path.resolve(opts.configFile);\n const ext = path.extname(filePath);\n\n if (ext !== \".js\" && ext !== \".ts\") {\n throw new CliError(\"Config file must have a .js or .ts extension.\");\n }\n\n if (!fs.existsSync(filePath)) {\n throw new CliError(`Config file not found: ${filePath}`);\n }\n\n let configModule: { config?: unknown };\n if (ext === \".ts\") {\n const { createJiti } = await import(\"jiti\");\n const jiti = createJiti(import.meta.url);\n configModule = await jiti.import(filePath);\n } else {\n configModule = await import(filePath);\n }\n\n const config = configModule.config;\n if (!isPlainObject(config)) {\n throw new CliError(\"Config file must export a plain `config` object. Example: export const config = { ... };\");\n }\n\n await project.replaceConfigOverride(\"branch\", config);\n console.log(\"Config pushed successfully.\");\n });\n}\n","export function isNonInteractiveEnv(): boolean {\n return !!(\n process.env.CI\n || process.env.GITHUB_ACTIONS\n || process.env.NONINTERACTIVE\n || !process.stdin.isTTY\n );\n}\n","// TODO: Use configPath in the prompt once local emulator is set up:\n// Add \"npx @stackframe/stack-cli emulator run --config-file ${configPath}\" to project dev command\nexport const createInitPrompt = (web: boolean, configPath?: string) => `=============================\nSTACK AUTH SETUP INSTRUCTIONS\n=============================\n\nThese instructions describe how to set up Stack Auth.\n${web ? `\nFirst of all, if you have access to a terminal, it is better to use the \\`npx @stackframe/stack-cli init\\`` : \"\"}\n\nInstall mcp server from https://mcp.stack-auth.com if not already installed\n\nFor reference, questions, or information on Stack Auth, you can query the docs on https://docs.stack-auth.com via curl or any tools that you have\n\n## Setup\n\n### 1) Install the package\n\nRun the install command using whatever package manager the project uses (npm, yarn, pnpm, bun):\n\n| Framework | Package |\n|-----------|---------|\n| Next.js | \\`@stackframe/stack\\` |\n| React | \\`@stackframe/react\\` |\n| Vanilla JS | \\`@stackframe/js\\` |\n\n### 2) Create the Stack apps\n\nDepending on whether you're on a client or a server, you will want to create stackClientApp or stackServerApp. Some environments, like Next.js, have both, so create both files.\n\nThe stack client app has client-level permissions. It contains most of the useful methods and hooks for your client-side code.\nThe stack server app has full read and write access to all users. It requires STACK_SECRET_SERVER_KEY env variable and should only be used in secure context\n\nIn Next.js, env vars are auto-detected (NEXT_PUBLIC_STACK_PROJECT_ID etc.), so the constructor needs no explicit config. For other frameworks, you must pass projectId and publishableClientKey explicitly using the framework's env var access method.\n\nThe tokenStore should be \"nextjs-cookie\" for Next.js, or \"cookie\" for all other frameworks.\n\n\\`\\`\\`ts\n// src/stack/client.ts\nimport { StackClientApp } from \"@stackframe/stack\"; // or \"@stackframe/react\" or \"@stackframe/js\"\n\nexport const stackClientApp = new StackClientApp({\n // Next.js: omit projectId/publishableClientKey (auto-detected from NEXT_PUBLIC_ env vars)\n // Other frameworks: pass explicitly, e.g. for Vite:\n // projectId: import.meta.env.VITE_STACK_PROJECT_ID,\n // publishableClientKey: import.meta.env.VITE_STACK_PUBLISHABLE_CLIENT_KEY,\n tokenStore: \"nextjs-cookie\", // or \"cookie\" for non-Next.js\n});\n\\`\\`\\`\n\nIf the framework has server-side support (e.g. Next.js), also create a server app:\n\n\\`\\`\\`ts\n// src/stack/server.ts\nimport \"server-only\";\nimport { StackServerApp } from \"@stackframe/stack\";\nimport { stackClientApp } from \"./client\";\n\nexport const stackServerApp = new StackServerApp({\n inheritsFrom: stackClientApp,\n});\n\\`\\`\\`\n\n### 3) Create the Stack handler (if available in framework)\n\nThis sets up pages for sign in, sign up, password reset, etc.\n\n\\`\\`\\`tsx\nimport { StackHandler } from \"@stackframe/stack\"; // Next.js\n// import { StackHandler } from \"@stackframe/react\"; // React\n\nexport default function Handler() {\n return <StackHandler fullPage />;\n}\n\\`\\`\\`\n\n### 4) Create a Suspense boundary\n\nSuspense is necessary for many stack auth hooks such as useUser to function. Add a loading component with a custom loading indicator for the current project. Don't add if one already exists\n\nFor example:\n\\`\\`\\`tsx\n//src/loading.tsx\n\nexport default function Loading() {\n return <p>Loading...</p>\n}\n\\`\\`\\`\n\n### 5) Link environment variables\n\nThis is only necessary if not using local emulator. Ensure these are ignored by git.\n\nRename the env var keys in .env to match the framework's convention for client-exposed variables. For example, Vite requires VITE_ prefix, Next.js uses NEXT_PUBLIC_, etc. The values should stay the same — only rename the keys.\n\nThe required variables are:\n- Project ID (e.g. NEXT_PUBLIC_STACK_PROJECT_ID, VITE_STACK_PROJECT_ID, etc.)\n- Publishable client key (e.g. NEXT_PUBLIC_STACK_PUBLISHABLE_CLIENT_KEY, VITE_STACK_PUBLISHABLE_CLIENT_KEY, etc.)\n- Secret server key: STACK_SECRET_SERVER_KEY (only for frameworks with server-side support, no prefix needed)\n\n### 6) React only: Wrap the entire page in a Stack provider\n\nThis is used for the useUser and useStackApp hooks.\n\n\\`\\`\\`tsx\nimport { StackProvider, StackTheme } from \"@stackframe/stack\";\nimport { stackClientApp } from \"../stack/client\"; // adjust relative path\n\\`\\`\\`\n\nThen wrap the body content: \n\n\\`\\`\\`tsx\nreturn (\n <body>\n <StackProvider app={stackClientApp}>\n <StackTheme>{children}</StackTheme>\n </StackProvider>\n </body>\n);\n\\`\\`\\`\n`;\n\n","import { query } from \"@anthropic-ai/claude-agent-sdk\";\n\nconst DEFAULT_PROXY_URL = \"https://api.stack-auth.com/api/v1/integrations/ai-proxy\";\nconst ANTHROPIC_PROXY_BASE_URL: string = process.env.STACK_CLAUDE_PROXY_URL ?? DEFAULT_PROXY_URL;\n\nconst SPINNER_FRAMES = [\"⠋\", \"⠙\", \"⠹\", \"⠸\", \"⠼\", \"⠴\", \"⠦\", \"⠧\", \"⠇\", \"⠏\"];\n\nclass AgentProgressUI {\n private mainLabel: string;\n private spinnerFrame = 0;\n private spinnerTimer: ReturnType<typeof setInterval> | null = null;\n private activeSpinners = new Map<string, string>(); // id -> label\n private flushedCount = 0; // number of completed items already printed above the spinner area\n private pendingCompleted: string[] = []; // completed items not yet flushed\n private lastLineCount = 0;\n\n constructor(mainLabel: string) {\n this.mainLabel = mainLabel;\n }\n\n start() {\n this.spinnerTimer = setInterval(() => {\n this.spinnerFrame = (this.spinnerFrame + 1) % SPINNER_FRAMES.length;\n this.render();\n }, 80);\n this.render();\n }\n\n stop(success: boolean) {\n if (this.spinnerTimer) {\n clearInterval(this.spinnerTimer);\n this.spinnerTimer = null;\n }\n this.completeAllActive();\n this.clearLines();\n const icon = success ? \"\\x1b[32m✔\\x1b[0m\" : \"\\x1b[31m✖\\x1b[0m\";\n // Re-print header + all completed items as final output\n console.log(`${icon} ${this.mainLabel}`);\n for (const label of this.pendingCompleted) {\n console.log(` \\x1b[32m✔\\x1b[0m ${label}`);\n }\n this.pendingCompleted = [];\n }\n\n setSpinner(id: string, label: string) {\n this.activeSpinners.set(id, label);\n }\n\n complete(id: string, label?: string) {\n const existing = this.activeSpinners.get(id);\n this.activeSpinners.delete(id);\n const finalLabel = label ?? existing;\n if (finalLabel) {\n this.pendingCompleted.push(finalLabel);\n }\n }\n\n completeAllActive() {\n for (const label of this.activeSpinners.values()) {\n this.pendingCompleted.push(label);\n }\n this.activeSpinners.clear();\n }\n\n private clearLines() {\n if (this.lastLineCount > 0) {\n process.stdout.write(`\\x1b[${this.lastLineCount}A\\x1b[J`);\n }\n }\n\n private flushCompleted() {\n if (this.pendingCompleted.length === 0) {\n return;\n }\n // Clear the spinner area, print completed items permanently, then re-render spinner below\n this.clearLines();\n // Re-print the header line if this is the first flush\n if (this.flushedCount === 0) {\n const frame = SPINNER_FRAMES[this.spinnerFrame];\n process.stdout.write(`\\x1b[36m${frame}\\x1b[0m ${this.mainLabel}\\n`);\n }\n for (const label of this.pendingCompleted) {\n process.stdout.write(` \\x1b[32m✔\\x1b[0m ${label}\\n`);\n }\n this.flushedCount += this.pendingCompleted.length;\n this.pendingCompleted = [];\n this.lastLineCount = 0; // reset since we printed permanent lines\n }\n\n private render() {\n this.flushCompleted();\n this.clearLines();\n\n const frame = SPINNER_FRAMES[this.spinnerFrame];\n const lines: string[] = [];\n\n // Only show header in spinner area if nothing has been flushed yet\n if (this.flushedCount === 0) {\n lines.push(`\\x1b[36m${frame}\\x1b[0m ${this.mainLabel}`);\n }\n\n for (const label of this.activeSpinners.values()) {\n lines.push(` \\x1b[36m${frame}\\x1b[0m ${label}`);\n }\n\n if (lines.length > 0) {\n const output = lines.join(\"\\n\") + \"\\n\";\n process.stdout.write(output);\n }\n this.lastLineCount = lines.length;\n }\n}\n\nfunction getToolLabel(toolName: string, input: Record<string, unknown>): string {\n switch (toolName) {\n case \"Read\": {\n return `Reading ${input.file_path ?? \"file\"}`;\n }\n case \"Write\": {\n return `Writing ${input.file_path ?? \"file\"}`;\n }\n case \"Edit\": {\n return `Editing ${input.file_path ?? \"file\"}`;\n }\n case \"Bash\": {\n return `Running \\`${truncate(String(input.command ?? \"\"), 40)}\\``;\n }\n case \"Glob\": {\n return `Searching for ${input.pattern ?? \"files\"}`;\n }\n case \"Grep\": {\n return `Searching for \"${truncate(String(input.pattern ?? \"\"), 30)}\"`;\n }\n default: {\n return toolName;\n }\n }\n}\n\nfunction truncate(str: string, maxLen: number): string {\n return str.length > maxLen ? str.slice(0, maxLen - 1) + \"…\" : str;\n}\n\nfunction stripClaudeCodeEnv(): Record<string, string> {\n const env = { ...process.env };\n delete env.CLAUDECODE;\n return env as Record<string, string>;\n}\n\nexport async function runClaudeAgent(options: {\n prompt: string,\n cwd: string,\n}): Promise<boolean> {\n const ui = new AgentProgressUI(\"Setting up Stack Auth...\");\n ui.start();\n\n try {\n let resultText = \"\";\n\n for await (const message of query({\n prompt: options.prompt,\n options: {\n allowedTools: [\"Read\", \"Write\", \"Edit\", \"Bash\", \"Glob\", \"Grep\"],\n permissionMode: \"dontAsk\",\n cwd: options.cwd,\n // stripClaudeCodeEnv removes CLAUDECODE env var to prevent nested agent detection\n env: { ...stripClaudeCodeEnv(), ANTHROPIC_BASE_URL: ANTHROPIC_PROXY_BASE_URL, ANTHROPIC_API_KEY: \"\" },\n stderr: (data: string) => { process.stderr.write(data); },\n },\n })) {\n if (\"result\" in message) {\n resultText = message.result;\n } else if (message.type === \"assistant\" && message.parent_tool_use_id === null) {\n // New parent assistant turn — previous tools are done\n ui.completeAllActive();\n // Register new tool calls from this turn\n for (const block of message.message.content) {\n if (block.type === \"tool_use\") {\n ui.setSpinner(block.id, getToolLabel(block.name, block.input as Record<string, unknown>));\n }\n }\n } else if (message.type === \"system\") {\n // Subagent task lifecycle\n const msg = message as Record<string, unknown>;\n const taskId = msg.task_id as string | undefined;\n\n if (msg.subtype === \"task_started\" && taskId) {\n ui.setSpinner(taskId, String(msg.description ?? \"Working...\"));\n } else if (msg.subtype === \"task_progress\" && taskId) {\n ui.setSpinner(taskId, String(msg.description ?? \"Working...\"));\n } else if (msg.subtype === \"task_notification\" && taskId) {\n ui.complete(taskId, String(msg.summary ?? msg.description ?? \"Done\"));\n }\n }\n }\n\n ui.stop(true);\n if (resultText) {\n console.log(`\\n${resultText}`);\n }\n return true;\n } catch (error) {\n ui.stop(false);\n console.error(\"\\nClaude agent encountered an error:\", error instanceof Error ? error.message : error);\n return false;\n }\n}\n","import { Command } from \"commander\";\nimport { select, input, checkbox, confirm } from \"@inquirer/prompts\";\nimport * as fs from \"fs\";\nimport * as path from \"path\";\nimport { StackClientApp } from \"@stackframe/js\";\nimport { ALL_APPS } from \"@stackframe/stack-shared/dist/apps/apps-config\";\nimport { resolveLoginConfig, resolveSessionAuth, DEFAULT_PUBLISHABLE_CLIENT_KEY } from \"../lib/auth.js\";\nimport { getInternalUser } from \"../lib/app.js\";\nimport { writeConfigValue } from \"../lib/config.js\";\nimport { CliError, AuthError } from \"../lib/errors.js\";\nimport { isNonInteractiveEnv } from \"../lib/interactive.js\";\nimport { createInitPrompt } from \"../lib/init-prompt.js\";\nimport { runClaudeAgent } from \"../lib/claude-agent.js\";\n\ntype InitOptions = {\n mode?: \"create\" | \"link-config\" | \"link-cloud\",\n apps?: string,\n configFile?: string,\n selectProjectId?: string,\n outputDir?: string,\n agent?: boolean,\n};\n\nexport function registerInitCommand(program: Command) {\n program\n .command(\"init\")\n .description(\"Initialize Stack Auth in your project\")\n .option(\"--mode <mode>\", \"Mode: create, link-config, or link-cloud (skips interactive prompts)\")\n .option(\"--apps <apps>\", \"Comma-separated app IDs to enable (for create mode)\")\n .option(\"--config-file <path>\", \"Path to existing config file (for link-config mode)\")\n .option(\"--select-project-id <id>\", \"Project ID to link (for link-cloud mode)\")\n .option(\"--output-dir <dir>\", \"Directory to write output files (defaults to cwd)\")\n .option(\"--no-agent\", \"Skip Claude agent and print setup instructions instead\")\n .action(async (opts: InitOptions) => {\n const hasFlags = opts.mode != null;\n\n if (!hasFlags && isNonInteractiveEnv()) {\n throw new CliError(\"stack init requires an interactive terminal. Use --mode flag for non-interactive usage.\");\n }\n\n try {\n await runInit(program, opts);\n } catch (error: unknown) {\n if (error != null && typeof error === \"object\" && \"name\" in error && error.name === \"ExitPromptError\") {\n console.log(\"\\nAborted.\");\n process.exit(0);\n }\n throw error;\n }\n });\n}\n\nasync function runInit(program: Command, opts: InitOptions) {\n const flags = program.opts();\n const outputDir = opts.outputDir ? path.resolve(opts.outputDir) : process.cwd();\n\n console.log(\"Welcome to Stack Auth!\\n\");\n\n const mode: string = opts.mode ?? await select({\n message: \"Would you like to link to an existing project, or create a new one?\",\n choices: [\n { name: \"Create a new project (local emulator)\", value: \"create\" as const },\n { name: \"Link an existing project\", value: \"link\" as const },\n ],\n });\n\n let configPath: string | undefined;\n\n if (mode === \"link\" || mode === \"link-config\" || mode === \"link-cloud\") {\n const result = await handleLink(flags, opts, outputDir);\n configPath = result.configPath;\n } else if (mode === \"create\") {\n const result = await handleCreate(opts, outputDir);\n configPath = result.configPath;\n } else {\n throw new CliError(`Unknown mode: ${mode}`);\n }\n\n const initPrompt = createInitPrompt(false, configPath);\n const useAgent = opts.agent !== false && !isNonInteractiveEnv();\n\n if (useAgent) {\n const success = await runClaudeAgent({\n prompt: `Execute ALL of the following setup steps in my project now. Do not ask questions — just detect the framework and package manager from existing files and proceed.\\n\\n${initPrompt}`,\n cwd: outputDir,\n });\n if (!success) {\n console.log(\"\\nFalling back to manual instructions:\\n\");\n console.log(initPrompt);\n }\n } else {\n console.log(\"\\n\" + initPrompt);\n }\n}\n\nasync function handleLink(flags: Record<string, unknown>, opts: InitOptions, outputDir: string): Promise<{ configPath?: string }> {\n let source: \"config-file\" | \"cloud\";\n\n if (opts.mode === \"link-config\") {\n source = \"config-file\";\n } else if (opts.mode === \"link-cloud\") {\n source = \"cloud\";\n } else {\n source = await select({\n message: \"How would you like to link your project?\",\n choices: [\n { name: \"Link from config file\", value: \"config-file\" as const },\n { name: \"Link from app.stack-auth.com\", value: \"cloud\" as const },\n ],\n });\n }\n\n if (source === \"config-file\") {\n return await handleLinkFromConfigFile(opts);\n }\n return await handleLinkFromCloud(flags, opts, outputDir);\n}\n\nasync function handleLinkFromConfigFile(opts: InitOptions): Promise<{ configPath: string }> {\n const filePath = opts.configFile ?? await input({\n message: \"Path to your existing stack.config.ts:\",\n validate: (value) => {\n const resolved = path.resolve(value);\n if (!fs.existsSync(resolved)) {\n return `File not found: ${resolved}`;\n }\n return true;\n },\n });\n\n const configPath = path.resolve(filePath);\n if (!fs.existsSync(configPath)) {\n throw new CliError(`File not found: ${configPath}`);\n }\n\n console.log(`\\nLinked to config file: ${configPath}`);\n return { configPath };\n}\n\nasync function handleLinkFromCloud(flags: Record<string, unknown>, opts: InitOptions, outputDir: string): Promise<{ configPath?: string }> {\n let sessionAuth;\n try {\n sessionAuth = resolveSessionAuth(flags as { projectId?: string });\n } catch (e) {\n if (e instanceof AuthError) {\n if (isNonInteractiveEnv()) {\n throw new CliError(\"Not logged in. Run `stack login` first or set STACK_CLI_REFRESH_TOKEN.\");\n }\n console.log(\"You need to log in first.\\n\");\n await performLogin(flags);\n sessionAuth = resolveSessionAuth(flags as { projectId?: string });\n } else {\n throw e;\n }\n }\n\n const user = await getInternalUser(sessionAuth);\n const projects = await user.listOwnedProjects();\n\n if (projects.length === 0) {\n throw new CliError(\"You don't own any projects. Create one at app.stack-auth.com first.\");\n }\n\n let projectId: string;\n if (opts.selectProjectId) {\n const found = projects.find((p) => p.id === opts.selectProjectId);\n if (!found) {\n throw new CliError(`Project '${opts.selectProjectId}' not found among your owned projects.`);\n }\n projectId = opts.selectProjectId;\n } else {\n projectId = await select({\n message: \"Select a project:\",\n choices: projects.map((p) => ({\n name: `${p.displayName} (${p.id})`,\n value: p.id,\n })),\n });\n }\n\n const project = projects.find((p) => p.id === projectId)!;\n const apiKey = await project.app.createInternalApiKey({\n description: \"Created by CLI init script\",\n expiresAt: new Date(Date.now() + 1000 * 60 * 60 * 24 * 365 * 200), // 200 years\n hasPublishableClientKey: true,\n hasSecretServerKey: true,\n hasSuperSecretAdminKey: false,\n });\n\n const envLines = [\n \"# Stack Auth\",\n `NEXT_PUBLIC_STACK_PROJECT_ID=${projectId}`,\n `NEXT_PUBLIC_STACK_PUBLISHABLE_CLIENT_KEY=${apiKey.publishableClientKey ?? \"\"}`,\n `STACK_SECRET_SERVER_KEY=${apiKey.secretServerKey ?? \"\"}`,\n ].join(\"\\n\");\n\n const envPath = path.resolve(outputDir, \".env\");\n\n if (fs.existsSync(envPath)) {\n const existing = fs.readFileSync(envPath, \"utf-8\");\n const separator = existing.endsWith(\"\\n\") ? \"\\n\" : \"\\n\\n\";\n\n if (isNonInteractiveEnv()) {\n fs.appendFileSync(envPath, separator + envLines + \"\\n\");\n console.log(\"\\nAppended Stack Auth keys to .env\");\n } else {\n const shouldAppend = await confirm({\n message: `.env file already exists. Append Stack Auth keys?`,\n default: true,\n });\n\n if (shouldAppend) {\n fs.appendFileSync(envPath, separator + envLines + \"\\n\");\n console.log(\"\\nAppended Stack Auth keys to .env\");\n } else {\n console.log(\"\\nHere are your environment variables:\\n\");\n console.log(envLines);\n }\n }\n } else {\n fs.writeFileSync(envPath, envLines + \"\\n\");\n console.log(\"\\nCreated .env with Stack Auth keys\");\n }\n\n return {};\n}\n\nasync function performLogin(flags: Record<string, unknown>) {\n const config = resolveLoginConfig(flags as { projectId?: string });\n\n const app = new StackClientApp({\n projectId: \"internal\",\n publishableClientKey: DEFAULT_PUBLISHABLE_CLIENT_KEY,\n baseUrl: config.apiUrl,\n tokenStore: \"memory\",\n noAutomaticPrefetch: true,\n });\n\n console.log(\"Waiting for browser authentication...\");\n\n const result = await app.promptCliLogin({\n appUrl: config.dashboardUrl,\n });\n\n if (result.status === \"error\") {\n throw new CliError(`Login failed: ${result.error.message}`);\n }\n\n writeConfigValue(\"STACK_CLI_REFRESH_TOKEN\", result.data);\n console.log(\"Login successful!\\n\");\n}\n\nasync function handleCreate(opts: InitOptions, outputDir: string): Promise<{ configPath: string }> {\n const configPath = path.resolve(outputDir, \"stack.config.ts\");\n\n console.log(`\\nCreating a new config file at ${configPath}!\\n`);\n\n let selectedApps: string[];\n\n if (opts.apps) {\n selectedApps = opts.apps.split(\",\").map((s) => s.trim()).filter(Boolean);\n const validAppIds = Object.keys(ALL_APPS);\n const invalidApps = selectedApps.filter((id) => !validAppIds.includes(id));\n if (invalidApps.length > 0) {\n throw new CliError(`Unknown app IDs: ${invalidApps.join(\", \")}. Valid IDs: ${validAppIds.join(\", \")}`);\n }\n } else {\n const stageOrder = { stable: 0, beta: 1 } as const;\n const appEntries = Object.entries(ALL_APPS)\n .filter(([, app]) => app.stage !== \"alpha\")\n .sort((a, b) => stageOrder[a[1].stage as keyof typeof stageOrder] - stageOrder[b[1].stage as keyof typeof stageOrder]);\n\n selectedApps = await checkbox({\n message: \"Select apps to enable:\",\n choices: appEntries.map(([id, app]) => ({\n name: `${app.displayName} - ${app.subtitle}${app.stage !== \"stable\" ? ` (${app.stage})` : \"\"}`,\n value: id,\n checked: id === \"authentication\",\n })),\n });\n }\n\n const installed = Object.fromEntries(\n selectedApps.map((appId) => [appId, { enabled: true }])\n );\n\n const config = {\n apps: {\n installed,\n },\n };\n\n const content = `export const config = ${JSON.stringify(config, null, 2)};\\n`;\n fs.mkdirSync(path.dirname(configPath), { recursive: true });\n fs.writeFileSync(configPath, content);\n\n console.log(`\\nConfig file written to ${configPath}`);\n return { configPath };\n}\n","import { Command } from \"commander\";\nimport * as readline from \"readline\";\nimport { resolveSessionAuth } from \"../lib/auth.js\";\nimport { getInternalUser } from \"../lib/app.js\";\nimport { isNonInteractiveEnv } from \"../lib/interactive.js\";\nimport { CliError } from \"../lib/errors.js\";\n\nfunction prompt(question: string): Promise<string> {\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n return new Promise((resolve) => {\n rl.question(question, (answer) => {\n rl.close();\n resolve(answer);\n });\n });\n}\n\nexport function registerProjectCommand(program: Command) {\n const project = program\n .command(\"project\")\n .description(\"Manage projects\");\n\n project\n .command(\"list\")\n .description(\"List your owned projects\")\n .action(async () => {\n const flags = program.opts();\n const auth = resolveSessionAuth(flags);\n const user = await getInternalUser(auth);\n const projects = await user.listOwnedProjects();\n\n if (program.opts().json) {\n console.log(JSON.stringify(projects.map((p) => ({ id: p.id, displayName: p.displayName })), null, 2));\n } else {\n if (projects.length === 0) {\n console.log(\"No projects found.\");\n return;\n }\n for (const p of projects) {\n console.log(`${p.id}\\t${p.displayName}`);\n }\n }\n });\n\n project\n .command(\"create\")\n .description(\"Create a new project\")\n .option(\"--display-name <name>\", \"Project display name\")\n .action(async (opts) => {\n const flags = program.opts();\n const auth = resolveSessionAuth(flags);\n const user = await getInternalUser(auth);\n\n let displayName: string = opts.displayName;\n if (!displayName) {\n if (isNonInteractiveEnv()) {\n throw new CliError(\"--display-name is required in non-interactive environments (CI).\");\n }\n displayName = await prompt(\"Project display name: \");\n if (!displayName.trim()) {\n throw new CliError(\"Display name cannot be empty.\");\n }\n }\n\n const teams = await user.listTeams();\n if (teams.length === 0) {\n throw new CliError(\"No teams found. You need a team to create a project.\");\n }\n\n const newProject = await user.createProject({\n displayName,\n teamId: teams[0].id,\n });\n\n if (program.opts().json) {\n console.log(JSON.stringify({ id: newProject.id, displayName: newProject.displayName }, null, 2));\n } else {\n console.log(`Project created: ${newProject.id} (${newProject.displayName})`);\n }\n });\n}\n","import { Command } from \"commander\";\nimport { readFileSync } from \"fs\";\nimport { fileURLToPath } from \"url\";\nimport { dirname, join } from \"path\";\nimport { AuthError, CliError } from \"./lib/errors.js\";\nimport { registerLoginCommand } from \"./commands/login.js\";\nimport { registerLogoutCommand } from \"./commands/logout.js\";\nimport { registerExecCommand } from \"./commands/exec.js\";\nimport { registerConfigCommand } from \"./commands/config-file.js\";\nimport { registerInitCommand } from \"./commands/init.js\";\nimport { registerProjectCommand } from \"./commands/project.js\";\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = dirname(__filename);\nconst pkg = JSON.parse(readFileSync(join(__dirname, \"..\", \"package.json\"), \"utf-8\"));\n\nconst program = new Command();\n\nprogram\n .name(\"stack\")\n .description(\"Stack Auth CLI\")\n .version(pkg.version)\n .option(\"--project-id <id>\", \"Project ID\")\n .option(\"--json\", \"Output in JSON format\");\n\nregisterLoginCommand(program);\nregisterLogoutCommand(program);\nregisterExecCommand(program);\nregisterConfigCommand(program);\nregisterInitCommand(program);\nregisterProjectCommand(program);\n\nasync function main() {\n try {\n await program.parseAsync(process.argv);\n } catch (err) {\n if (err instanceof AuthError) {\n console.error(`Auth error: ${err.message}`);\n process.exit(1);\n }\n if (err instanceof CliError) {\n console.error(`Error: ${err.message}`);\n process.exit(1);\n }\n throw err;\n }\n}\n\n// eslint-disable-next-line @typescript-eslint/no-floating-promises\nmain();\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stackframe/stack-cli",
|
|
3
|
-
"version": "2.8.
|
|
3
|
+
"version": "2.8.76",
|
|
4
4
|
"repository": "https://github.com/stack-auth/stack-auth",
|
|
5
5
|
"description": "The CLI for Stack Auth. https://stack-auth.com",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -19,8 +19,11 @@
|
|
|
19
19
|
"author": "",
|
|
20
20
|
"license": "MIT",
|
|
21
21
|
"dependencies": {
|
|
22
|
+
"@anthropic-ai/claude-agent-sdk": "^0.2.73",
|
|
23
|
+
"@inquirer/prompts": "^7.0.0",
|
|
22
24
|
"commander": "^13.1.0",
|
|
23
25
|
"jiti": "^2.4.2",
|
|
26
|
+
"@stackframe/stack-shared": "2.8.74",
|
|
24
27
|
"@stackframe/js": "2.8.74"
|
|
25
28
|
},
|
|
26
29
|
"devDependencies": {
|