@01.software/init 0.5.1 → 0.6.1

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.
@@ -0,0 +1,61 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/file-ops.ts
4
+ var envLineRegexCache = /* @__PURE__ */ new Map();
5
+ function envLineRegex(name) {
6
+ let re = envLineRegexCache.get(name);
7
+ if (!re) {
8
+ const escaped = name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
9
+ re = new RegExp(`^${escaped}=(.*)$`, "m");
10
+ envLineRegexCache.set(name, re);
11
+ }
12
+ return re;
13
+ }
14
+ function readEnvValue(content, name) {
15
+ const m = content.match(envLineRegex(name));
16
+ return m ? m[1] : null;
17
+ }
18
+ function setEnvValue(content, name, value) {
19
+ const re = envLineRegex(name);
20
+ if (re.test(content)) return content.replace(re, `${name}=${value}`);
21
+ const sep = content.length === 0 || content.endsWith("\n") ? "" : "\n";
22
+ return content + sep + `${name}=${value}
23
+ `;
24
+ }
25
+ var TOML_SECTION_PREFIX = "[mcp_servers.01software";
26
+ function extractTomlApiKey(content) {
27
+ const headerIdx = content.indexOf(`${TOML_SECTION_PREFIX}.headers]`);
28
+ if (headerIdx < 0) return null;
29
+ const slice = content.slice(headerIdx);
30
+ const m = slice.match(/^x-api-key\s*=\s*"((?:[^"\\]|\\.)*)"/m);
31
+ if (!m) return null;
32
+ return m[1].replace(/\\"/g, '"').replace(/\\\\/g, "\\");
33
+ }
34
+ function replaceTomlMcpSection(content, newSection) {
35
+ const lines = content.split("\n");
36
+ const kept = [];
37
+ let inOurSection = false;
38
+ for (const line of lines) {
39
+ const trimmed = line.trim();
40
+ if (trimmed.startsWith(TOML_SECTION_PREFIX)) {
41
+ inOurSection = true;
42
+ continue;
43
+ }
44
+ if (inOurSection && /^\[[^\[]/.test(trimmed)) {
45
+ inOurSection = false;
46
+ }
47
+ if (!inOurSection) kept.push(line);
48
+ }
49
+ let result = kept.join("\n").replace(/\n+$/, "");
50
+ if (result.length > 0) result += "\n";
51
+ result += newSection.startsWith("\n") ? newSection : "\n" + newSection;
52
+ return result;
53
+ }
54
+
55
+ export {
56
+ readEnvValue,
57
+ setEnvValue,
58
+ extractTomlApiKey,
59
+ replaceTomlMcpSection
60
+ };
61
+ //# sourceMappingURL=chunk-VOEXMD2S.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/file-ops.ts"],"sourcesContent":["// Pure helpers for in-place file content manipulation. Kept side-effect-free\n// so they can be unit-tested without touching the filesystem or prompts.\n\n// ── .env merge ───────────────────────────────────────────────────────\n\nconst envLineRegexCache = new Map<string, RegExp>()\n\nfunction envLineRegex(name: string): RegExp {\n let re = envLineRegexCache.get(name)\n if (!re) {\n const escaped = name.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')\n re = new RegExp(`^${escaped}=(.*)$`, 'm')\n envLineRegexCache.set(name, re)\n }\n return re\n}\n\nexport function readEnvValue(content: string, name: string): string | null {\n const m = content.match(envLineRegex(name))\n return m ? m[1] : null\n}\n\nexport function setEnvValue(content: string, name: string, value: string): string {\n const re = envLineRegex(name)\n if (re.test(content)) return content.replace(re, `${name}=${value}`)\n const sep = content.length === 0 || content.endsWith('\\n') ? '' : '\\n'\n return content + sep + `${name}=${value}\\n`\n}\n\n// ── Codex TOML manipulation ──────────────────────────────────────────\n\nconst TOML_SECTION_PREFIX = '[mcp_servers.01software'\n\n/** Pulls the current `x-api-key` value from `[mcp_servers.01software.headers]`.\n * Returns null if the section or key is absent. */\nexport function extractTomlApiKey(content: string): string | null {\n const headerIdx = content.indexOf(`${TOML_SECTION_PREFIX}.headers]`)\n if (headerIdx < 0) return null\n const slice = content.slice(headerIdx)\n const m = slice.match(/^x-api-key\\s*=\\s*\"((?:[^\"\\\\]|\\\\.)*)\"/m)\n if (!m) return null\n // Reverse the same escaping used when writing (escape backslash + quote)\n return m[1].replace(/\\\\\"/g, '\"').replace(/\\\\\\\\/g, '\\\\')\n}\n\n/** Removes the existing `[mcp_servers.01software]` block (and its `.headers`\n * sub-block) from a TOML document, then appends the provided section. */\nexport function replaceTomlMcpSection(content: string, newSection: string): string {\n const lines = content.split('\\n')\n const kept: string[] = []\n let inOurSection = false\n for (const line of lines) {\n const trimmed = line.trim()\n if (trimmed.startsWith(TOML_SECTION_PREFIX)) {\n inOurSection = true\n continue\n }\n // Any other top-level header ends our section\n if (inOurSection && /^\\[[^\\[]/.test(trimmed)) {\n inOurSection = false\n }\n if (!inOurSection) kept.push(line)\n }\n let result = kept.join('\\n').replace(/\\n+$/, '')\n if (result.length > 0) result += '\\n'\n // newSection already starts with a blank line; keep it that way\n result += newSection.startsWith('\\n') ? newSection : '\\n' + newSection\n return result\n}\n"],"mappings":";;;AAKA,IAAM,oBAAoB,oBAAI,IAAoB;AAElD,SAAS,aAAa,MAAsB;AAC1C,MAAI,KAAK,kBAAkB,IAAI,IAAI;AACnC,MAAI,CAAC,IAAI;AACP,UAAM,UAAU,KAAK,QAAQ,uBAAuB,MAAM;AAC1D,SAAK,IAAI,OAAO,IAAI,OAAO,UAAU,GAAG;AACxC,sBAAkB,IAAI,MAAM,EAAE;AAAA,EAChC;AACA,SAAO;AACT;AAEO,SAAS,aAAa,SAAiB,MAA6B;AACzE,QAAM,IAAI,QAAQ,MAAM,aAAa,IAAI,CAAC;AAC1C,SAAO,IAAI,EAAE,CAAC,IAAI;AACpB;AAEO,SAAS,YAAY,SAAiB,MAAc,OAAuB;AAChF,QAAM,KAAK,aAAa,IAAI;AAC5B,MAAI,GAAG,KAAK,OAAO,EAAG,QAAO,QAAQ,QAAQ,IAAI,GAAG,IAAI,IAAI,KAAK,EAAE;AACnE,QAAM,MAAM,QAAQ,WAAW,KAAK,QAAQ,SAAS,IAAI,IAAI,KAAK;AAClE,SAAO,UAAU,MAAM,GAAG,IAAI,IAAI,KAAK;AAAA;AACzC;AAIA,IAAM,sBAAsB;AAIrB,SAAS,kBAAkB,SAAgC;AAChE,QAAM,YAAY,QAAQ,QAAQ,GAAG,mBAAmB,WAAW;AACnE,MAAI,YAAY,EAAG,QAAO;AAC1B,QAAM,QAAQ,QAAQ,MAAM,SAAS;AACrC,QAAM,IAAI,MAAM,MAAM,uCAAuC;AAC7D,MAAI,CAAC,EAAG,QAAO;AAEf,SAAO,EAAE,CAAC,EAAE,QAAQ,QAAQ,GAAG,EAAE,QAAQ,SAAS,IAAI;AACxD;AAIO,SAAS,sBAAsB,SAAiB,YAA4B;AACjF,QAAM,QAAQ,QAAQ,MAAM,IAAI;AAChC,QAAM,OAAiB,CAAC;AACxB,MAAI,eAAe;AACnB,aAAW,QAAQ,OAAO;AACxB,UAAM,UAAU,KAAK,KAAK;AAC1B,QAAI,QAAQ,WAAW,mBAAmB,GAAG;AAC3C,qBAAe;AACf;AAAA,IACF;AAEA,QAAI,gBAAgB,WAAW,KAAK,OAAO,GAAG;AAC5C,qBAAe;AAAA,IACjB;AACA,QAAI,CAAC,aAAc,MAAK,KAAK,IAAI;AAAA,EACnC;AACA,MAAI,SAAS,KAAK,KAAK,IAAI,EAAE,QAAQ,QAAQ,EAAE;AAC/C,MAAI,OAAO,SAAS,EAAG,WAAU;AAEjC,YAAU,WAAW,WAAW,IAAI,IAAI,aAAa,OAAO;AAC5D,SAAO;AACT;","names":[]}
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ extractTomlApiKey,
4
+ readEnvValue,
5
+ replaceTomlMcpSection,
6
+ setEnvValue
7
+ } from "./chunk-VOEXMD2S.js";
8
+ export {
9
+ extractTomlApiKey,
10
+ readEnvValue,
11
+ replaceTomlMcpSection,
12
+ setEnvValue
13
+ };
14
+ //# sourceMappingURL=file-ops.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
package/dist/index.js CHANGED
@@ -4,6 +4,12 @@ import {
4
4
  generateClaudeMd,
5
5
  getSkillFiles
6
6
  } from "./chunk-SRLZ5OIV.js";
7
+ import {
8
+ extractTomlApiKey,
9
+ readEnvValue,
10
+ replaceTomlMcpSection,
11
+ setEnvValue
12
+ } from "./chunk-VOEXMD2S.js";
7
13
  import {
8
14
  CODEX_MCP_SECTION_MARKER,
9
15
  getClientTemplate,
@@ -26,19 +32,29 @@ function detectProject(cwd) {
26
32
  const hasPackageJson = fs.existsSync(pkgPath);
27
33
  let env = "node";
28
34
  let hasSdk = false;
35
+ let hasReactQuery = false;
29
36
  let parseError = false;
30
37
  if (hasPackageJson) {
31
38
  let pkg;
32
39
  try {
33
40
  pkg = JSON.parse(fs.readFileSync(pkgPath, "utf-8"));
34
41
  } catch {
35
- return { hasPackageJson: true, parseError: true, env: "node", packageManager: null, hasSdk: false, srcDir: false };
42
+ return {
43
+ hasPackageJson: true,
44
+ parseError: true,
45
+ env: "node",
46
+ packageManager: null,
47
+ hasSdk: false,
48
+ hasReactQuery: false,
49
+ srcDir: false
50
+ };
36
51
  }
37
52
  const deps = {
38
53
  ...pkg.dependencies || {},
39
54
  ...pkg.devDependencies || {}
40
55
  };
41
56
  hasSdk = "@01.software/sdk" in deps;
57
+ hasReactQuery = "@tanstack/react-query" in deps;
42
58
  if ("next" in deps) {
43
59
  env = "nextjs";
44
60
  } else if ("astro" in deps || "@astrojs/node" in deps) {
@@ -68,7 +84,7 @@ function detectProject(cwd) {
68
84
  packageManager = "npm";
69
85
  }
70
86
  const srcDir = env === "nextjs" ? fs.existsSync(path.join(cwd, "src", "app")) : fs.existsSync(path.join(cwd, "src"));
71
- return { hasPackageJson, parseError, env, packageManager, hasSdk, srcDir };
87
+ return { hasPackageJson, parseError, env, packageManager, hasSdk, hasReactQuery, srcDir };
72
88
  }
73
89
  function needsClient(env) {
74
90
  return env === "nextjs" || env === "react-vite" || env === "react-cra" || env === "vanilla";
@@ -259,6 +275,7 @@ import path2 from "path";
259
275
  import os from "os";
260
276
  import { execSync } from "child_process";
261
277
  import pc2 from "picocolors";
278
+ import prompts2 from "prompts";
262
279
 
263
280
  // src/browser-auth.ts
264
281
  import { randomBytes } from "crypto";
@@ -439,6 +456,7 @@ ${loginUrl}`));
439
456
 
440
457
  // src/init.ts
441
458
  var SECRET_KEY_ENV_VAR = "SOFTWARE_SECRET_KEY";
459
+ var API_KEY_PLACEHOLDER = "YOUR_API_KEY";
442
460
  async function init(cwd, info, answers) {
443
461
  const { packageManager, srcDir } = info;
444
462
  const env = answers.env;
@@ -447,56 +465,51 @@ async function init(cwd, info, answers) {
447
465
  const wantsClient = needsClient(env);
448
466
  const wantsServer = needsServer(env);
449
467
  const wantsReactQuery = needsReactQuery(env);
450
- const deps = ["@01.software/sdk"];
451
- if (wantsReactQuery) deps.push("@tanstack/react-query");
452
- const addCmd = buildAddCmd(packageManager, hasPnpmWorkspace(cwd), deps);
453
- let installFailed = false;
454
- console.log(pc2.dim(` Installing ${deps.join(" and ")}...`));
455
- const wsPatched = packageManager === "pnpm" && patchPnpmWorkspace(cwd);
456
- try {
457
- execSync(addCmd, { cwd, stdio: "pipe" });
458
- console.log(pc2.green(" Installed"), deps.join(", "));
459
- } catch (error) {
460
- installFailed = true;
461
- const err = error;
462
- const msg = String(err.stderr || "").trim() || String(err.stdout || "").trim() || String(error);
463
- console.log(pc2.yellow(" Install failed \u2014 continuing with scaffolding"));
464
- const firstLines = msg.split("\n").slice(0, 3).map((l) => ` ${l}`).join("\n");
465
- if (firstLines) console.log(pc2.dim(firstLines));
466
- console.log(pc2.dim(` Run manually: ${addCmd}`));
467
- } finally {
468
- if (wsPatched) restorePnpmWorkspace(cwd);
468
+ const plan = await planConflictsAndEnv(cwd, baseDir, env, answers);
469
+ const installResult = installDeps(
470
+ cwd,
471
+ packageManager,
472
+ info.hasSdk,
473
+ info.hasReactQuery,
474
+ wantsReactQuery
475
+ );
476
+ if (wantsClient || wantsReactQuery || wantsServer) {
477
+ fs2.mkdirSync(path2.join(baseDir, "lib", "software"), { recursive: true });
469
478
  }
470
479
  const libDir = path2.join(baseDir, "lib", "software");
471
- fs2.mkdirSync(libDir, { recursive: true });
472
480
  if (wantsClient) {
473
- writeFileIfAbsent(
481
+ await writeFileWithPolicy(
474
482
  cwd,
475
483
  path2.join(libDir, "client.ts"),
476
- getClientTemplate(env, publishableKeyEnvVar)
484
+ getClientTemplate(env, publishableKeyEnvVar),
485
+ plan.policy
477
486
  );
478
487
  }
479
488
  if (wantsReactQuery) {
480
- writeFileIfAbsent(
489
+ await writeFileWithPolicy(
481
490
  cwd,
482
491
  path2.join(libDir, "query-provider.tsx"),
483
- getQueryProviderTemplate(env)
492
+ getQueryProviderTemplate(env),
493
+ plan.policy
484
494
  );
485
495
  }
486
496
  if (wantsServer) {
487
- writeFileIfAbsent(
497
+ await writeFileWithPolicy(
488
498
  cwd,
489
499
  path2.join(libDir, "server.ts"),
490
- getServerTemplate(env, publishableKeyEnvVar, SECRET_KEY_ENV_VAR)
500
+ getServerTemplate(env, publishableKeyEnvVar, SECRET_KEY_ENV_VAR),
501
+ plan.policy
491
502
  );
492
503
  }
493
- if (env !== "vanilla" && env !== "edge" && answers.authMethod !== "browser") {
494
- writeEnv(
504
+ if (plan.envFile && answers.authMethod !== "browser") {
505
+ await writeEnv(
495
506
  cwd,
507
+ plan.envFile,
496
508
  answers.publishableKey || "",
497
509
  answers.secretKey || "",
498
510
  publishableKeyEnvVar,
499
- wantsServer ? SECRET_KEY_ENV_VAR : null
511
+ wantsServer ? SECRET_KEY_ENV_VAR : null,
512
+ plan.policy
500
513
  );
501
514
  }
502
515
  let publishableKey = answers.publishableKey;
@@ -509,13 +522,15 @@ async function init(cwd, info, answers) {
509
522
  publishableKey = creds.publishableKey;
510
523
  secretKey = creds.secretKey;
511
524
  tenantName = creds.tenantName;
512
- if (env !== "vanilla" && env !== "edge" && publishableKey) {
513
- writeEnv(
525
+ if (plan.envFile && publishableKey) {
526
+ await writeEnv(
514
527
  cwd,
528
+ plan.envFile,
515
529
  publishableKey,
516
530
  secretKey,
517
531
  publishableKeyEnvVar,
518
532
  wantsServer ? SECRET_KEY_ENV_VAR : null,
533
+ "overwrite",
519
534
  true
520
535
  );
521
536
  }
@@ -527,16 +542,48 @@ async function init(cwd, info, answers) {
527
542
  }
528
543
  }
529
544
  if (answers.aiTools.length > 0) {
530
- const apiKey = secretKey || "YOUR_API_KEY";
545
+ const apiKey = secretKey || API_KEY_PLACEHOLDER;
531
546
  for (const tool of answers.aiTools) {
532
- writeMcpConfig(tool, cwd, apiKey);
547
+ await writeMcpConfig(tool, cwd, apiKey, plan.policy);
533
548
  }
534
549
  addToGitignore(cwd, answers.aiTools);
535
550
  if (answers.aiTools.includes("claude")) {
536
- await writeClaudeDocs(cwd, publishableKey, secretKey, tenantName);
551
+ await writeClaudeDocs(cwd, publishableKey, secretKey, tenantName, plan.policy);
537
552
  }
538
553
  }
539
- return { installFailed, installCmd: addCmd };
554
+ return installResult;
555
+ }
556
+ function installDeps(cwd, pm, hasSdk, hasReactQuery, wantsReactQuery) {
557
+ const allDeps = [
558
+ { name: "@01.software/sdk", installed: hasSdk, needed: true },
559
+ { name: "@tanstack/react-query", installed: hasReactQuery, needed: wantsReactQuery }
560
+ ];
561
+ const fullList = allDeps.filter((d) => d.needed).map((d) => d.name);
562
+ const toInstall = allDeps.filter((d) => d.needed && !d.installed).map((d) => d.name);
563
+ const fullCmd = buildAddCmd(pm, hasPnpmWorkspace(cwd), fullList);
564
+ if (toInstall.length === 0) {
565
+ console.log(pc2.dim(` Dependencies already installed: ${fullList.join(", ")}`));
566
+ return { installFailed: false, installSkipped: true, installCmd: fullCmd };
567
+ }
568
+ const addCmd = buildAddCmd(pm, hasPnpmWorkspace(cwd), toInstall);
569
+ console.log(pc2.dim(` Installing ${toInstall.join(" and ")}...`));
570
+ const wsPatched = pm === "pnpm" && patchPnpmWorkspace(cwd);
571
+ let installFailed = false;
572
+ try {
573
+ execSync(addCmd, { cwd, stdio: "pipe" });
574
+ console.log(pc2.green(" Installed"), toInstall.join(", "));
575
+ } catch (error) {
576
+ installFailed = true;
577
+ const err = error;
578
+ const msg = String(err.stderr || "").trim() || String(err.stdout || "").trim() || String(error);
579
+ console.log(pc2.yellow(" Install failed \u2014 continuing with scaffolding"));
580
+ const firstLines = msg.split("\n").slice(0, 3).map((l) => ` ${l}`).join("\n");
581
+ if (firstLines) console.log(pc2.dim(firstLines));
582
+ console.log(pc2.dim(` Run manually: ${addCmd}`));
583
+ } finally {
584
+ if (wsPatched) restorePnpmWorkspace(cwd);
585
+ }
586
+ return { installFailed, installSkipped: false, installCmd: addCmd };
540
587
  }
541
588
  function buildAddCmd(pm, hasPnpmWs, deps) {
542
589
  const pkgs = deps.join(" ");
@@ -551,34 +598,155 @@ function buildAddCmd(pm, hasPnpmWs, deps) {
551
598
  return `npm install ${pkgs}`;
552
599
  }
553
600
  }
554
- function writeFileIfAbsent(cwd, filePath, content) {
555
- if (fs2.existsSync(filePath)) {
556
- console.log(pc2.yellow(" Skipped"), relativePath(cwd, filePath), pc2.dim("(already exists)"));
601
+ async function planConflictsAndEnv(cwd, baseDir, env, answers) {
602
+ const candidates = [];
603
+ const libDir = path2.join(baseDir, "lib", "software");
604
+ if (needsClient(env)) candidates.push(path2.join(libDir, "client.ts"));
605
+ if (needsReactQuery(env)) candidates.push(path2.join(libDir, "query-provider.tsx"));
606
+ if (needsServer(env)) candidates.push(path2.join(libDir, "server.ts"));
607
+ if (answers.aiTools.includes("claude")) {
608
+ for (const { dirName } of getSkillFiles()) {
609
+ candidates.push(path2.join(cwd, ".claude", "skills", dirName, "SKILL.md"));
610
+ }
611
+ }
612
+ const conflicts = candidates.filter((p) => fs2.existsSync(p));
613
+ let policy = "skip";
614
+ if (conflicts.length > 0) {
615
+ console.log(pc2.yellow(` ${conflicts.length} file(s) already exist:`));
616
+ for (const c of conflicts) console.log(pc2.dim(` ${path2.relative(cwd, c)}`));
617
+ const { selected } = await prompts2({
618
+ type: "select",
619
+ name: "selected",
620
+ message: "How should I handle existing files?",
621
+ choices: [
622
+ { title: "Keep existing (skip)", value: "skip" },
623
+ { title: "Overwrite all", value: "overwrite" },
624
+ { title: "Ask for each", value: "ask" }
625
+ ],
626
+ initial: 0
627
+ });
628
+ policy = selected ?? "skip";
629
+ }
630
+ const envFile = env === "vanilla" || env === "edge" ? "" : await pickEnvFile(cwd, env);
631
+ return { policy, envFile };
632
+ }
633
+ async function pickEnvFile(cwd, env) {
634
+ const candidates = [".env.local", ".env", ".env.development"];
635
+ const existing = candidates.filter((f) => fs2.existsSync(path2.join(cwd, f)));
636
+ const preferred = env === "nextjs" ? ".env.local" : ".env";
637
+ if (existing.length === 0) return preferred;
638
+ if (existing.length === 1 && existing[0] === preferred) return existing[0];
639
+ const options = Array.from(/* @__PURE__ */ new Set([...existing, preferred]));
640
+ const choices = options.map((f) => ({
641
+ title: f,
642
+ description: existing.includes(f) ? "exists" : "create",
643
+ value: f
644
+ }));
645
+ const initial = Math.max(
646
+ 0,
647
+ choices.findIndex((c) => c.value === preferred)
648
+ );
649
+ const { file } = await prompts2({
650
+ type: "select",
651
+ name: "file",
652
+ message: "Which env file should I write API keys to?",
653
+ choices,
654
+ initial
655
+ });
656
+ return file ?? preferred;
657
+ }
658
+ async function writeFileWithPolicy(cwd, filePath, content, policy) {
659
+ const rel = path2.relative(cwd, filePath);
660
+ if (!fs2.existsSync(filePath)) {
661
+ fs2.mkdirSync(path2.dirname(filePath), { recursive: true });
662
+ fs2.writeFileSync(filePath, content);
663
+ console.log(pc2.green(" Created"), rel);
664
+ return;
665
+ }
666
+ const existing = fs2.readFileSync(filePath, "utf-8");
667
+ if (existing === content) {
668
+ console.log(pc2.dim(" Unchanged"), rel);
557
669
  return;
558
670
  }
559
- fs2.writeFileSync(filePath, content);
560
- console.log(pc2.green(" Created"), relativePath(cwd, filePath));
671
+ let shouldWrite = false;
672
+ if (policy === "overwrite") {
673
+ shouldWrite = true;
674
+ } else if (policy === "ask") {
675
+ const { confirm } = await prompts2({
676
+ type: "confirm",
677
+ name: "confirm",
678
+ message: `Overwrite ${rel}?`,
679
+ initial: false
680
+ });
681
+ shouldWrite = !!confirm;
682
+ }
683
+ if (shouldWrite) {
684
+ fs2.writeFileSync(filePath, content);
685
+ console.log(pc2.green(" Overwrote"), rel);
686
+ } else {
687
+ console.log(pc2.yellow(" Skipped"), rel, pc2.dim("(already exists)"));
688
+ }
561
689
  }
562
- function writeEnv(cwd, publishableKey, secretKey, publishableKeyEnvVar, secretKeyEnvVar, afterBrowserAuth = false) {
563
- const envPath = path2.join(cwd, ".env");
564
- const envContent = getEnvContent(publishableKey, secretKey, publishableKeyEnvVar, secretKeyEnvVar);
565
- if (fs2.existsSync(envPath)) {
566
- const existing = fs2.readFileSync(envPath, "utf-8");
567
- if (existing.includes(publishableKeyEnvVar)) {
568
- if (!afterBrowserAuth) {
569
- console.log(pc2.yellow(" Skipped"), ".env", pc2.dim("(keys already present)"));
690
+ async function writeEnv(cwd, envFile, publishableKey, secretKey, publishableKeyEnvVar, secretKeyEnvVar, policy, fromBrowserAuth = false) {
691
+ const envPath = path2.join(cwd, envFile);
692
+ const targets = [
693
+ { name: publishableKeyEnvVar, value: publishableKey }
694
+ ];
695
+ if (secretKeyEnvVar) {
696
+ targets.push({ name: secretKeyEnvVar, value: secretKey });
697
+ }
698
+ if (!fs2.existsSync(envPath)) {
699
+ const initial = getEnvContent(publishableKey, secretKey, publishableKeyEnvVar, secretKeyEnvVar);
700
+ fs2.writeFileSync(envPath, initial.trimStart());
701
+ console.log(pc2.green(" Created"), envFile);
702
+ return;
703
+ }
704
+ let content = fs2.readFileSync(envPath, "utf-8");
705
+ let modified = false;
706
+ let appendedHeader = false;
707
+ const headerAlreadyPresent = targets.some(
708
+ (t) => readEnvValue(content, t.name) !== null
709
+ );
710
+ for (const { name, value } of targets) {
711
+ const existing = readEnvValue(content, name);
712
+ if (existing === null) {
713
+ if (!headerAlreadyPresent && !appendedHeader) {
714
+ if (content.length > 0 && !content.endsWith("\n")) content += "\n";
715
+ content += "\n# 01.software\n";
716
+ appendedHeader = true;
570
717
  }
571
- return;
718
+ content = setEnvValue(content, name, value);
719
+ modified = true;
720
+ continue;
721
+ }
722
+ if (existing === value) continue;
723
+ if (!value) continue;
724
+ let shouldOverwrite = false;
725
+ if (policy === "overwrite") {
726
+ shouldOverwrite = true;
727
+ } else if (policy === "ask") {
728
+ const { confirm } = await prompts2({
729
+ type: "confirm",
730
+ name: "confirm",
731
+ message: `${name} already set in ${envFile}. Overwrite?`,
732
+ initial: fromBrowserAuth
733
+ });
734
+ shouldOverwrite = !!confirm;
572
735
  }
573
- fs2.appendFileSync(envPath, envContent);
736
+ if (shouldOverwrite) {
737
+ content = setEnvValue(content, name, value);
738
+ modified = true;
739
+ }
740
+ }
741
+ if (modified) {
742
+ fs2.writeFileSync(envPath, content);
574
743
  console.log(
575
744
  pc2.green(" Updated"),
576
- ".env",
577
- afterBrowserAuth ? pc2.dim("(added API keys)") : ""
745
+ envFile,
746
+ fromBrowserAuth ? pc2.dim("(API keys)") : ""
578
747
  );
579
748
  } else {
580
- fs2.writeFileSync(envPath, envContent.trimStart());
581
- console.log(pc2.green(" Created"), ".env");
749
+ console.log(pc2.dim(" Unchanged"), envFile);
582
750
  }
583
751
  }
584
752
  function resolveMcpLocation(tool, cwd) {
@@ -622,7 +790,7 @@ function resolveMcpLocation(tool, cwd) {
622
790
  }
623
791
  }
624
792
  }
625
- function writeMcpConfig(tool, cwd, apiKey) {
793
+ async function writeMcpConfig(tool, cwd, apiKey, policy) {
626
794
  const loc = resolveMcpLocation(tool, cwd);
627
795
  if (!loc) {
628
796
  console.log(pc2.yellow(` Skipped ${tool}`), pc2.dim("(HOME not set)"));
@@ -630,46 +798,86 @@ function writeMcpConfig(tool, cwd, apiKey) {
630
798
  }
631
799
  fs2.mkdirSync(path2.dirname(loc.absolutePath), { recursive: true });
632
800
  if (loc.kind === "json") {
633
- writeJsonMcp(loc, apiKey);
801
+ await writeJsonMcp(loc, apiKey, policy);
634
802
  } else {
635
- writeTomlMcp(loc, apiKey);
803
+ await writeTomlMcp(loc, apiKey, policy);
636
804
  }
637
805
  }
638
- function writeJsonMcp(loc, apiKey) {
639
- if (fs2.existsSync(loc.absolutePath)) {
640
- try {
641
- const existing = JSON.parse(fs2.readFileSync(loc.absolutePath, "utf-8"));
642
- if (existing.mcpServers?.["01software"]) {
643
- console.log(pc2.yellow(" Skipped"), loc.displayPath, pc2.dim("(01software already configured)"));
644
- return;
645
- }
646
- existing.mcpServers = existing.mcpServers || {};
647
- existing.mcpServers["01software"] = getMcpServerEntry(apiKey);
648
- fs2.writeFileSync(loc.absolutePath, JSON.stringify(existing, null, 2) + "\n");
649
- console.log(pc2.green(" Updated"), loc.displayPath);
650
- } catch {
651
- console.log(pc2.yellow(" Skipped"), loc.displayPath, pc2.dim("(could not parse existing file)"));
652
- }
653
- } else {
806
+ async function writeJsonMcp(loc, apiKey, policy) {
807
+ if (!fs2.existsSync(loc.absolutePath)) {
654
808
  fs2.writeFileSync(loc.absolutePath, getMcpConfigTemplate(apiKey));
655
809
  console.log(pc2.green(" Created"), loc.displayPath);
810
+ return;
656
811
  }
657
- }
658
- function writeTomlMcp(loc, apiKey) {
659
- const section = getCodexMcpTomlSection(apiKey);
660
- if (fs2.existsSync(loc.absolutePath)) {
661
- const existing = fs2.readFileSync(loc.absolutePath, "utf-8");
662
- if (existing.includes(CODEX_MCP_SECTION_MARKER)) {
663
- console.log(pc2.yellow(" Skipped"), loc.displayPath, pc2.dim("(01software already configured)"));
812
+ let existing;
813
+ try {
814
+ existing = JSON.parse(fs2.readFileSync(loc.absolutePath, "utf-8"));
815
+ } catch {
816
+ console.log(pc2.yellow(" Skipped"), loc.displayPath, pc2.dim("(could not parse existing file)"));
817
+ return;
818
+ }
819
+ const existingApiKey = existing.mcpServers?.["01software"]?.headers?.["x-api-key"];
820
+ if (existingApiKey === apiKey) {
821
+ console.log(pc2.dim(" Unchanged"), loc.displayPath);
822
+ return;
823
+ }
824
+ if (apiKey === API_KEY_PLACEHOLDER && existingApiKey && existingApiKey !== API_KEY_PLACEHOLDER) {
825
+ console.log(pc2.dim(" Kept existing API key in"), loc.displayPath);
826
+ return;
827
+ }
828
+ if (existingApiKey) {
829
+ const shouldUpdate = await confirmKeyUpdate(loc.displayPath, policy);
830
+ if (!shouldUpdate) {
831
+ console.log(pc2.yellow(" Skipped"), loc.displayPath, pc2.dim("(kept existing API key)"));
664
832
  return;
665
833
  }
834
+ }
835
+ existing.mcpServers = existing.mcpServers || {};
836
+ existing.mcpServers["01software"] = getMcpServerEntry(apiKey);
837
+ fs2.writeFileSync(loc.absolutePath, JSON.stringify(existing, null, 2) + "\n");
838
+ console.log(pc2.green(" Updated"), loc.displayPath);
839
+ }
840
+ async function writeTomlMcp(loc, apiKey, policy) {
841
+ const section = getCodexMcpTomlSection(apiKey);
842
+ if (!fs2.existsSync(loc.absolutePath)) {
843
+ fs2.writeFileSync(loc.absolutePath, section.trimStart());
844
+ console.log(pc2.green(" Created"), loc.displayPath);
845
+ return;
846
+ }
847
+ const existing = fs2.readFileSync(loc.absolutePath, "utf-8");
848
+ if (!existing.includes(CODEX_MCP_SECTION_MARKER)) {
666
849
  const sep = existing.endsWith("\n") ? "" : "\n";
667
850
  fs2.appendFileSync(loc.absolutePath, sep + section);
668
851
  console.log(pc2.green(" Updated"), loc.displayPath);
669
- } else {
670
- fs2.writeFileSync(loc.absolutePath, section.trimStart());
671
- console.log(pc2.green(" Created"), loc.displayPath);
852
+ return;
853
+ }
854
+ const existingApiKey = extractTomlApiKey(existing);
855
+ if (existingApiKey === apiKey) {
856
+ console.log(pc2.dim(" Unchanged"), loc.displayPath);
857
+ return;
672
858
  }
859
+ if (apiKey === API_KEY_PLACEHOLDER && existingApiKey && existingApiKey !== API_KEY_PLACEHOLDER) {
860
+ console.log(pc2.dim(" Kept existing API key in"), loc.displayPath);
861
+ return;
862
+ }
863
+ const shouldUpdate = await confirmKeyUpdate(loc.displayPath, policy);
864
+ if (!shouldUpdate) {
865
+ console.log(pc2.yellow(" Skipped"), loc.displayPath, pc2.dim("(kept existing API key)"));
866
+ return;
867
+ }
868
+ const replaced = replaceTomlMcpSection(existing, section);
869
+ fs2.writeFileSync(loc.absolutePath, replaced);
870
+ console.log(pc2.green(" Updated"), loc.displayPath);
871
+ }
872
+ async function confirmKeyUpdate(displayPath, policy) {
873
+ if (policy === "overwrite") return true;
874
+ const { confirm } = await prompts2({
875
+ type: "confirm",
876
+ name: "confirm",
877
+ message: `${displayPath} has a different 01software API key. Update?`,
878
+ initial: true
879
+ });
880
+ return !!confirm;
673
881
  }
674
882
  function addToGitignore(cwd, tools) {
675
883
  const entries = [];
@@ -690,7 +898,7 @@ function addToGitignore(cwd, tools) {
690
898
  }
691
899
  console.log(pc2.green(" Updated"), ".gitignore", pc2.dim(`(added ${toAdd.join(", ")})`));
692
900
  }
693
- async function writeClaudeDocs(cwd, publishableKey, secretKey, tenantName) {
901
+ async function writeClaudeDocs(cwd, publishableKey, secretKey, tenantName, policy) {
694
902
  let ctx = {
695
903
  tenantName: tenantName || "Your Tenant",
696
904
  features: void 0,
@@ -727,24 +935,16 @@ async function writeClaudeDocs(cwd, publishableKey, secretKey, tenantName) {
727
935
  fs2.appendFileSync(claudeMdPath, prefix + importLine + "\n");
728
936
  console.log(pc2.green(" Updated"), ".claude/CLAUDE.md", pc2.dim("(added @import)"));
729
937
  } else {
730
- console.log(pc2.yellow(" Skipped"), ".claude/CLAUDE.md", pc2.dim("(@import already present)"));
938
+ console.log(pc2.dim(" Unchanged"), ".claude/CLAUDE.md");
731
939
  }
732
940
  }
733
941
  for (const { dirName, content } of getSkillFiles()) {
734
942
  const skillDir = path2.join(skillsDir, dirName);
735
943
  const skillPath = path2.join(skillDir, "SKILL.md");
736
- if (!fs2.existsSync(skillPath)) {
737
- fs2.mkdirSync(skillDir, { recursive: true });
738
- fs2.writeFileSync(skillPath, content);
739
- console.log(pc2.green(" Created"), `.claude/skills/${dirName}/SKILL.md`);
740
- } else {
741
- console.log(pc2.yellow(" Skipped"), `.claude/skills/${dirName}/SKILL.md`, pc2.dim("(already exists)"));
742
- }
944
+ fs2.mkdirSync(skillDir, { recursive: true });
945
+ await writeFileWithPolicy(cwd, skillPath, content, policy);
743
946
  }
744
947
  }
745
- function relativePath(cwd, filePath) {
746
- return path2.relative(cwd, filePath);
747
- }
748
948
  var WS_FILE = "pnpm-workspace.yaml";
749
949
  var WS_BACKUP = "pnpm-workspace.yaml.bak";
750
950
  function hasPnpmWorkspace(cwd) {
@@ -886,7 +1086,11 @@ async function main() {
886
1086
  console.log();
887
1087
  }
888
1088
  if (answers.aiTools.length > 0 && (!answers.publishableKey || !answers.secretKey)) {
889
- console.log(pc3.dim(" Update MCP config x-api-key with your sk01_... token"));
1089
+ console.log(
1090
+ pc3.dim(
1091
+ " Update MCP config x-api-key with your sk01_... or pat01_... bearer token"
1092
+ )
1093
+ );
890
1094
  console.log();
891
1095
  }
892
1096
  if (env !== "vanilla") {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/detect.ts","../src/prompts.ts","../src/init.ts","../src/browser-auth.ts"],"sourcesContent":["import pc from 'picocolors'\nimport { detectProject } from './detect'\nimport type { ProjectEnv } from './detect'\nimport { promptUser } from './prompts'\nimport { init } from './init'\n\nconst ENV_LABELS: Record<ProjectEnv, string> = {\n nextjs: 'Next.js',\n 'react-vite': 'React + Vite',\n 'react-cra': 'React + Webpack/CRA',\n vanilla: 'Vanilla JS',\n node: 'Node.js',\n edge: 'Edge runtime',\n other: 'Other framework',\n}\n\n// Manual setup guide for unsupported frameworks\nconst OTHER_FRAMEWORK_GUIDE = `\n Astro, Remix, SvelteKit, and other meta-frameworks have their own\n environment conventions. Manual setup:\n\n 1. Install the SDK:\n npm install @01.software/sdk\n\n 2. Browser client (client islands / RSC):\n import { createClient } from '@01.software/sdk'\n export const client = createClient({ publishableKey: 'YOUR_PUBLISHABLE_KEY' })\n\n 3. Server client (SSR / loaders / endpoints):\n import { createServerClient } from '@01.software/sdk'\n export const serverClient = createServerClient({\n publishableKey: process.env.PUBLIC_SOFTWARE_PUBLISHABLE_KEY!, // prefix varies by framework\n secretKey: process.env.SOFTWARE_SECRET_KEY!,\n })\n\n 4. Docs: https://01.software/docs/developers/sdk/client\n`\n\nasync function main() {\n const cwd = process.cwd()\n\n console.log()\n console.log(pc.bold(' @01.software/init'))\n console.log(pc.dim(' Initialize 01.software SDK in your project'))\n console.log()\n\n // 1. Detect project\n const info = detectProject(cwd)\n\n if (!info.hasPackageJson || info.parseError) {\n if (info.parseError) {\n console.log(pc.red(' Could not parse package.json (invalid JSON).'))\n console.log(pc.dim(' Fix the syntax error and try again.'))\n } else {\n console.log(pc.red(' No package.json found in the current directory.'))\n console.log(pc.dim(' Run this command inside an existing project.'))\n }\n console.log()\n process.exit(1)\n }\n\n // Show detected environment\n const detectedParts: string[] = [ENV_LABELS[info.env]]\n if (info.packageManager) detectedParts.push(info.packageManager)\n if (info.srcDir) detectedParts.push('src/')\n\n if (info.env !== 'node') {\n // Only show detected label when it's unambiguous\n console.log(pc.dim(` Detected: ${detectedParts.join(' / ')}`))\n console.log()\n }\n\n try {\n // 2. Prompt\n const answers = await promptUser(info.hasSdk, info.env, info.packageManager)\n if (!answers) {\n console.log(pc.yellow(' Cancelled.'))\n process.exit(0)\n }\n\n // \"Other\" framework — print guide and exit\n if (answers.env === 'other') {\n console.log(pc.yellow(' Manual setup required for your framework:'))\n console.log(OTHER_FRAMEWORK_GUIDE)\n process.exit(0)\n }\n\n // Resolve package manager from detection or user selection\n const resolvedPm = info.packageManager ?? answers.packageManager ?? 'npm'\n const resolvedInfo = { ...info, packageManager: resolvedPm }\n\n // 3. Init\n console.log()\n const result = await init(cwd, resolvedInfo, answers)\n\n // 4. Next steps\n const env = answers.env\n const run = resolvedPm === 'npm' ? 'npm run' : resolvedPm\n\n console.log()\n console.log(pc.green(' Done!'))\n console.log()\n console.log(' Next steps:')\n console.log()\n\n if (result.installFailed) {\n console.log(pc.yellow(' Install the SDK manually:'))\n console.log(pc.cyan(` ${result.installCmd}`))\n console.log()\n }\n\n if (env === 'nextjs') {\n console.log(pc.dim(' Add QueryProvider to your root layout:'))\n console.log()\n console.log(pc.cyan(\" import { QueryProvider } from '@/lib/software/query-provider'\"))\n console.log(pc.cyan(' <QueryProvider>{children}</QueryProvider>'))\n console.log()\n } else if (env === 'react-vite' || env === 'react-cra') {\n console.log(pc.dim(' Wrap your app entry with QueryProvider:'))\n console.log()\n console.log(pc.cyan(\" import { QueryProvider } from './lib/software/query-provider'\"))\n console.log(pc.cyan(' <QueryProvider><App /></QueryProvider>'))\n console.log()\n } else if (env === 'vanilla') {\n console.log(pc.dim(' Replace YOUR_PUBLISHABLE_KEY in lib/software/client.ts'))\n console.log()\n console.log(pc.cyan(\" import { client } from './lib/software/client'\"))\n console.log(pc.cyan(\" const posts = await client.from('posts').find()\"))\n console.log()\n } else if (env === 'node') {\n console.log(pc.dim(' Use the server client:'))\n console.log()\n console.log(pc.cyan(\" import { serverClient } from './lib/software/server'\"))\n console.log(pc.cyan(\" const posts = await serverClient.from('posts').find()\"))\n console.log()\n } else if (env === 'edge') {\n console.log(pc.dim(' Pass your env bindings to createEdgeClient():'))\n console.log()\n console.log(pc.cyan(\" import { createEdgeClient } from './lib/software/server'\"))\n console.log(pc.cyan(' const serverClient = createEdgeClient(env.PUBLISHABLE_KEY, env.SECRET_KEY)'))\n console.log()\n }\n\n const missingPublishableKey = env !== 'vanilla' && !answers.publishableKey\n const missingSecretKey = (env === 'nextjs' || env === 'node') && !answers.secretKey\n if (missingPublishableKey || missingSecretKey) {\n console.log(pc.dim(' Update .env with your API keys'))\n console.log()\n }\n if (answers.aiTools.length > 0 && (!answers.publishableKey || !answers.secretKey)) {\n console.log(pc.dim(' Update MCP config x-api-key with your sk01_... token'))\n console.log()\n }\n if (env !== 'vanilla') {\n console.log(pc.cyan(` ${run} dev`))\n console.log()\n }\n } catch (error) {\n if (error instanceof Error && error.message === 'cancelled') {\n console.log(pc.yellow(' Cancelled.'))\n process.exit(0)\n }\n console.error(pc.red(' Error:'), error)\n process.exit(1)\n }\n}\n\nmain()\n","import fs from 'node:fs'\nimport path from 'node:path'\n\nexport type PackageManager = 'pnpm' | 'npm' | 'yarn' | 'bun'\n\nexport type ProjectEnv =\n | 'nextjs'\n | 'react-vite'\n | 'react-cra'\n | 'vanilla'\n | 'node'\n | 'edge'\n | 'other' // Astro, Remix, SvelteKit, etc. — print guidance only\n\nexport interface ProjectInfo {\n hasPackageJson: boolean\n parseError: boolean\n env: ProjectEnv\n packageManager: PackageManager | null\n hasSdk: boolean\n srcDir: boolean\n}\n\nexport function detectProject(cwd: string): ProjectInfo {\n const pkgPath = path.join(cwd, 'package.json')\n const hasPackageJson = fs.existsSync(pkgPath)\n\n let env: ProjectEnv = 'node'\n let hasSdk = false\n let parseError = false\n\n if (hasPackageJson) {\n let pkg: Record<string, unknown>\n try {\n pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'))\n } catch {\n return { hasPackageJson: true, parseError: true, env: 'node', packageManager: null, hasSdk: false, srcDir: false }\n }\n\n const deps = {\n ...((pkg.dependencies as Record<string, string>) || {}),\n ...((pkg.devDependencies as Record<string, string>) || {}),\n }\n hasSdk = '@01.software/sdk' in deps\n\n if ('next' in deps) {\n env = 'nextjs'\n } else if ('astro' in deps || '@astrojs/node' in deps) {\n env = 'other'\n } else if ('@remix-run/node' in deps || '@remix-run/react' in deps) {\n env = 'other'\n } else if ('@sveltejs/kit' in deps) {\n env = 'other'\n } else if ('react' in deps) {\n if ('vite' in deps) {\n env = 'react-vite'\n } else if ('react-scripts' in deps) {\n env = 'react-cra'\n } else {\n // React + unknown bundler (Webpack, Parcel, etc.) — leave as 'node'\n // so the prompt selector is shown\n env = 'node'\n }\n }\n // else: no react/next → 'node' (covers real Node.js, Deno, Bun, etc.)\n }\n\n // Detect package manager from lockfile\n let packageManager: PackageManager | null = null\n if (fs.existsSync(path.join(cwd, 'pnpm-lock.yaml'))) {\n packageManager = 'pnpm'\n } else if (fs.existsSync(path.join(cwd, 'yarn.lock'))) {\n packageManager = 'yarn'\n } else if (\n fs.existsSync(path.join(cwd, 'bun.lockb')) ||\n fs.existsSync(path.join(cwd, 'bun.lock'))\n ) {\n packageManager = 'bun'\n } else if (fs.existsSync(path.join(cwd, 'package-lock.json'))) {\n packageManager = 'npm'\n }\n\n // Detect src directory structure\n const srcDir =\n env === 'nextjs'\n ? fs.existsSync(path.join(cwd, 'src', 'app'))\n : fs.existsSync(path.join(cwd, 'src'))\n\n return { hasPackageJson, parseError, env, packageManager, hasSdk, srcDir }\n}\n\n/** Environments that generate a browser client file */\nexport function needsClient(env: ProjectEnv): boolean {\n return env === 'nextjs' || env === 'react-vite' || env === 'react-cra' || env === 'vanilla'\n}\n\n/** Environments that generate a server client file */\nexport function needsServer(env: ProjectEnv): boolean {\n return env === 'nextjs' || env === 'node' || env === 'edge'\n}\n\n/** Environments that generate a query-provider file */\nexport function needsReactQuery(env: ProjectEnv): boolean {\n return env === 'nextjs' || env === 'react-vite' || env === 'react-cra'\n}\n\n/** Environments that support MCP setup (need both client + secret key) */\nexport function supportsMcp(env: ProjectEnv): boolean {\n return env === 'nextjs' || env === 'node' || env === 'edge'\n}\n\n/** Get the env var name for the public publishable key */\nexport function getPublishableKeyEnvVar(env: ProjectEnv): string {\n switch (env) {\n case 'nextjs':\n return 'NEXT_PUBLIC_SOFTWARE_PUBLISHABLE_KEY'\n case 'react-vite':\n return 'VITE_SOFTWARE_PUBLISHABLE_KEY'\n case 'react-cra':\n return 'REACT_APP_SOFTWARE_PUBLISHABLE_KEY'\n default:\n return 'SOFTWARE_PUBLISHABLE_KEY'\n }\n}\n","import prompts from 'prompts'\nimport type { PackageManager, ProjectEnv } from './detect'\n\nexport type AiTool =\n | 'claude'\n | 'cursor'\n | 'vscode'\n | 'windsurf'\n | 'codex'\n | 'gemini'\n\nexport type AuthMethod = 'browser' | 'manual' | 'skip'\n\nexport interface InitAnswers {\n env: ProjectEnv\n publishableKey: string\n secretKey: string\n aiTools: AiTool[]\n authMethod: AuthMethod\n packageManager?: PackageManager\n}\n\n// Envs that need the user to disambiguate (couldn't be auto-detected)\nconst AMBIGUOUS_ENVS: ProjectEnv[] = ['node']\n\nexport async function promptUser(\n hasSdk: boolean,\n detectedEnv: ProjectEnv,\n detectedPm: PackageManager | null,\n): Promise<InitAnswers | null> {\n const onCancel = () => {\n throw new Error('cancelled')\n }\n\n // Confirm re-init if SDK already installed\n if (hasSdk) {\n const { proceed } = await prompts(\n {\n type: 'confirm',\n name: 'proceed',\n message: '@01.software/sdk is already installed. Re-initialize?',\n initial: false,\n },\n { onCancel },\n )\n if (!proceed) return null\n }\n\n // Ask for environment when auto-detection is ambiguous\n let env = detectedEnv\n if (AMBIGUOUS_ENVS.includes(detectedEnv)) {\n const { selectedEnv } = await prompts(\n {\n type: 'select',\n name: 'selectedEnv',\n message: 'Which environment are you using?',\n choices: [\n {\n title: 'Next.js',\n description: 'Full-stack React (client + server)',\n value: 'nextjs',\n },\n {\n title: 'React + Vite',\n description: 'Client-only SPA with Vite',\n value: 'react-vite',\n },\n {\n title: 'React + Webpack / other',\n description: 'Client-only SPA, CRA or custom bundler',\n value: 'react-cra',\n },\n {\n title: 'Vanilla JS',\n description: 'Browser app without a framework',\n value: 'vanilla',\n },\n {\n title: 'Node.js / Bun / Deno',\n description: 'Server-only, no browser client',\n value: 'node',\n },\n {\n title: 'Edge runtime',\n description: 'Cloudflare Workers, Vercel Edge Functions',\n value: 'edge',\n },\n {\n title: 'Other (Astro / Remix / SvelteKit…)',\n description: 'Print manual setup guide for your framework',\n value: 'other',\n },\n ],\n },\n { onCancel },\n )\n env = selectedEnv as ProjectEnv\n }\n\n // \"Other\" frameworks — we can't scaffold correctly; exit with guidance\n if (env === 'other') {\n return { env, publishableKey: '', secretKey: '', aiTools: [], authMethod: 'skip', packageManager: undefined }\n }\n\n // Ask for package manager if no lockfile detected\n let packageManager: PackageManager | undefined\n if (!detectedPm) {\n const { pm } = await prompts(\n {\n type: 'select',\n name: 'pm',\n message: 'Which package manager do you use?',\n choices: [\n { title: 'npm', value: 'npm' },\n { title: 'pnpm', value: 'pnpm' },\n { title: 'yarn', value: 'yarn' },\n { title: 'bun', value: 'bun' },\n ],\n },\n { onCancel },\n )\n packageManager = pm\n }\n\n const needsSecretKey = env === 'nextjs' || env === 'node' || env === 'edge'\n\n const keyPrompts: prompts.PromptObject[] = []\n\n // Vanilla JS doesn't use env vars — no prompts for keys\n if (env !== 'vanilla') {\n keyPrompts.push({\n type: 'text',\n name: 'publishableKey',\n message: 'Publishable Key (optional, saved to .env)',\n initial: '',\n })\n }\n\n if (needsSecretKey) {\n keyPrompts.push({\n type: 'text',\n name: 'secretKey',\n message: 'Secret Key (optional, saved to .env)',\n initial: '',\n })\n }\n\n // AI tool multi-select (empty selection = skip)\n const { selectedTools } = await prompts(\n {\n type: 'multiselect',\n name: 'selectedTools',\n message: 'Connect AI tools (leave empty to skip):',\n choices: [\n { title: 'Claude Code', description: '.mcp.json + .claude/ docs', value: 'claude' },\n { title: 'Cursor', description: '.cursor/mcp.json', value: 'cursor' },\n { title: 'VS Code', description: '.vscode/mcp.json', value: 'vscode' },\n { title: 'Windsurf', description: '~/.codeium/windsurf/mcp_config.json', value: 'windsurf' },\n { title: 'Codex CLI', description: '~/.codex/config.toml', value: 'codex' },\n { title: 'Gemini CLI', description: '~/.gemini/settings.json', value: 'gemini' },\n ],\n hint: 'space to select, enter to confirm',\n },\n { onCancel },\n )\n\n const aiTools: AiTool[] = Array.isArray(selectedTools) ? (selectedTools as AiTool[]) : []\n\n // Auth method — only if tools selected and env supports secrets\n let authMethod: AuthMethod = 'skip'\n let keys: Record<string, string> = {}\n\n if (aiTools.length > 0 && env !== 'vanilla') {\n const { method } = await prompts(\n {\n type: 'select',\n name: 'method',\n message: 'API keys:',\n choices: [\n { title: 'Browser login (recommended)', value: 'browser' },\n { title: 'Enter manually', value: 'manual' },\n { title: 'Skip for now', value: 'skip' },\n ],\n },\n { onCancel },\n )\n authMethod = (method as AuthMethod) ?? 'skip'\n\n if (authMethod === 'manual') {\n keys = await prompts(keyPrompts, { onCancel })\n }\n } else if (env !== 'vanilla') {\n // No AI tools selected — still collect keys from the key prompts if any were defined\n if (keyPrompts.length > 0) {\n keys = await prompts(keyPrompts, { onCancel })\n }\n authMethod = 'skip'\n }\n\n return {\n env,\n publishableKey: authMethod === 'browser' ? '' : (keys.publishableKey ?? ''),\n secretKey: authMethod === 'browser' ? '' : (keys.secretKey ?? ''),\n aiTools,\n authMethod,\n packageManager,\n }\n}\n","import fs from 'node:fs'\nimport path from 'node:path'\nimport os from 'node:os'\nimport { execSync } from 'node:child_process'\nimport pc from 'picocolors'\nimport type { PackageManager, ProjectInfo } from './detect'\nimport {\n needsClient,\n needsServer,\n needsReactQuery,\n getPublishableKeyEnvVar,\n} from './detect'\nimport type { AiTool, InitAnswers } from './prompts'\nimport {\n getClientTemplate,\n getQueryProviderTemplate,\n getServerTemplate,\n getEnvContent,\n getMcpConfigTemplate,\n getMcpServerEntry,\n getCodexMcpTomlSection,\n CODEX_MCP_SECTION_MARKER,\n} from './templates'\nimport { startBrowserAuth } from './browser-auth'\nimport {\n generateClaudeMd,\n getSkillFiles,\n fetchTenantContext,\n} from './ai-docs'\n\ntype ResolvedProjectInfo = Omit<ProjectInfo, 'packageManager'> & {\n packageManager: PackageManager\n}\n\nconst SECRET_KEY_ENV_VAR = 'SOFTWARE_SECRET_KEY'\n\nexport interface InitResult {\n installFailed: boolean\n installCmd: string\n}\n\nexport async function init(\n cwd: string,\n info: ResolvedProjectInfo,\n answers: InitAnswers,\n): Promise<InitResult> {\n const { packageManager, srcDir } = info\n const env = answers.env\n const baseDir = srcDir ? path.join(cwd, 'src') : cwd\n\n const publishableKeyEnvVar = getPublishableKeyEnvVar(env)\n const wantsClient = needsClient(env)\n const wantsServer = needsServer(env)\n const wantsReactQuery = needsReactQuery(env)\n\n // 1. Install dependencies (best-effort — warn and continue on failure so\n // scaffolding, .env, and MCP config still happen)\n const deps = ['@01.software/sdk']\n if (wantsReactQuery) deps.push('@tanstack/react-query')\n\n const addCmd = buildAddCmd(packageManager, hasPnpmWorkspace(cwd), deps)\n let installFailed = false\n\n console.log(pc.dim(` Installing ${deps.join(' and ')}...`))\n\n // pnpm-workspace.yaml without packages: breaks pnpm add — patch temporarily\n const wsPatched = packageManager === 'pnpm' && patchPnpmWorkspace(cwd)\n\n try {\n execSync(addCmd, { cwd, stdio: 'pipe' })\n console.log(pc.green(' Installed'), deps.join(', '))\n } catch (error) {\n installFailed = true\n const err = error as { stdout?: Buffer; stderr?: Buffer }\n const msg =\n String(err.stderr || '').trim() ||\n String(err.stdout || '').trim() ||\n String(error)\n console.log(pc.yellow(' Install failed — continuing with scaffolding'))\n const firstLines = msg.split('\\n').slice(0, 3).map((l) => ` ${l}`).join('\\n')\n if (firstLines) console.log(pc.dim(firstLines))\n console.log(pc.dim(` Run manually: ${addCmd}`))\n } finally {\n if (wsPatched) restorePnpmWorkspace(cwd)\n }\n\n // 2. Write lib/software/ files\n const libDir = path.join(baseDir, 'lib', 'software')\n fs.mkdirSync(libDir, { recursive: true })\n\n // Client (browser)\n if (wantsClient) {\n writeFileIfAbsent(\n cwd,\n path.join(libDir, 'client.ts'),\n getClientTemplate(env, publishableKeyEnvVar),\n )\n }\n\n // Query Provider (React)\n if (wantsReactQuery) {\n writeFileIfAbsent(\n cwd,\n path.join(libDir, 'query-provider.tsx'),\n getQueryProviderTemplate(env),\n )\n }\n\n // Server\n if (wantsServer) {\n writeFileIfAbsent(\n cwd,\n path.join(libDir, 'server.ts'),\n getServerTemplate(env, publishableKeyEnvVar, SECRET_KEY_ENV_VAR),\n )\n }\n\n // 3. Append to .env (vanilla uses inline key; browser auth writes keys later in step 4)\n if (env !== 'vanilla' && env !== 'edge' && answers.authMethod !== 'browser') {\n writeEnv(\n cwd,\n answers.publishableKey || '',\n answers.secretKey || '',\n publishableKeyEnvVar,\n wantsServer ? SECRET_KEY_ENV_VAR : null,\n )\n }\n\n // 4. Browser auth — get real credentials if user chose browser login\n let publishableKey = answers.publishableKey\n let secretKey = answers.secretKey\n let tenantName = ''\n\n if (answers.authMethod === 'browser' && answers.aiTools.length > 0) {\n try {\n console.log()\n const creds = await startBrowserAuth()\n publishableKey = creds.publishableKey\n secretKey = creds.secretKey\n tenantName = creds.tenantName\n\n // Write .env with the real keys obtained from browser\n if (env !== 'vanilla' && env !== 'edge' && publishableKey) {\n writeEnv(\n cwd,\n publishableKey,\n secretKey,\n publishableKeyEnvVar,\n wantsServer ? SECRET_KEY_ENV_VAR : null,\n true,\n )\n }\n } catch (err) {\n console.log(\n pc.yellow(' Browser auth skipped:'),\n err instanceof Error ? err.message : String(err),\n )\n }\n }\n\n // 5. Write AI tool configs (MCP + Claude docs)\n if (answers.aiTools.length > 0) {\n // secretKey is an opaque sk01_/pat01_ bearer token — pass it as x-api-key directly.\n const apiKey = secretKey || 'YOUR_API_KEY'\n\n for (const tool of answers.aiTools) {\n writeMcpConfig(tool, cwd, apiKey)\n }\n\n addToGitignore(cwd, answers.aiTools)\n\n if (answers.aiTools.includes('claude')) {\n await writeClaudeDocs(cwd, publishableKey, secretKey, tenantName)\n }\n }\n\n return { installFailed, installCmd: addCmd }\n}\n\nfunction buildAddCmd(\n pm: PackageManager,\n hasPnpmWs: boolean,\n deps: string[],\n): string {\n const pkgs = deps.join(' ')\n switch (pm) {\n case 'pnpm':\n return hasPnpmWs ? `pnpm add -w ${pkgs}` : `pnpm add ${pkgs}`\n case 'yarn':\n return `yarn add ${pkgs}`\n case 'bun':\n return `bun add ${pkgs}`\n default:\n return `npm install ${pkgs}`\n }\n}\n\nfunction writeFileIfAbsent(cwd: string, filePath: string, content: string): void {\n if (fs.existsSync(filePath)) {\n console.log(pc.yellow(' Skipped'), relativePath(cwd, filePath), pc.dim('(already exists)'))\n return\n }\n fs.writeFileSync(filePath, content)\n console.log(pc.green(' Created'), relativePath(cwd, filePath))\n}\n\nfunction writeEnv(\n cwd: string,\n publishableKey: string,\n secretKey: string,\n publishableKeyEnvVar: string,\n secretKeyEnvVar: string | null,\n afterBrowserAuth = false,\n): void {\n const envPath = path.join(cwd, '.env')\n const envContent = getEnvContent(publishableKey, secretKey, publishableKeyEnvVar, secretKeyEnvVar)\n\n if (fs.existsSync(envPath)) {\n const existing = fs.readFileSync(envPath, 'utf-8')\n if (existing.includes(publishableKeyEnvVar)) {\n if (!afterBrowserAuth) {\n console.log(pc.yellow(' Skipped'), '.env', pc.dim('(keys already present)'))\n }\n return\n }\n fs.appendFileSync(envPath, envContent)\n console.log(\n pc.green(' Updated'),\n '.env',\n afterBrowserAuth ? pc.dim('(added API keys)') : '',\n )\n } else {\n fs.writeFileSync(envPath, envContent.trimStart())\n console.log(pc.green(' Created'), '.env')\n }\n}\n\n// ── MCP targets registry ─────────────────────────────────────────────\n\ntype McpFormat = 'json' | 'toml'\ninterface McpLocation {\n kind: McpFormat\n absolutePath: string\n displayPath: string\n gitignoreEntry: string | null // null = global path, not worth ignoring\n}\n\nfunction resolveMcpLocation(tool: AiTool, cwd: string): McpLocation | null {\n const home = os.homedir()\n\n switch (tool) {\n case 'claude':\n return {\n kind: 'json',\n absolutePath: path.join(cwd, '.mcp.json'),\n displayPath: '.mcp.json',\n gitignoreEntry: '.mcp.json',\n }\n case 'cursor':\n return {\n kind: 'json',\n absolutePath: path.join(cwd, '.cursor', 'mcp.json'),\n displayPath: '.cursor/mcp.json',\n gitignoreEntry: '.cursor/mcp.json',\n }\n case 'vscode':\n return {\n kind: 'json',\n absolutePath: path.join(cwd, '.vscode', 'mcp.json'),\n displayPath: '.vscode/mcp.json',\n gitignoreEntry: '.vscode/mcp.json',\n }\n case 'windsurf': {\n if (!home) return null\n const p = path.join(home, '.codeium', 'windsurf', 'mcp_config.json')\n return { kind: 'json', absolutePath: p, displayPath: p, gitignoreEntry: null }\n }\n case 'codex': {\n if (!home) return null\n const p = path.join(home, '.codex', 'config.toml')\n return { kind: 'toml', absolutePath: p, displayPath: p, gitignoreEntry: null }\n }\n case 'gemini': {\n if (!home) return null\n const p = path.join(home, '.gemini', 'settings.json')\n return { kind: 'json', absolutePath: p, displayPath: p, gitignoreEntry: null }\n }\n }\n}\n\nfunction writeMcpConfig(tool: AiTool, cwd: string, apiKey: string): void {\n const loc = resolveMcpLocation(tool, cwd)\n if (!loc) {\n console.log(pc.yellow(` Skipped ${tool}`), pc.dim('(HOME not set)'))\n return\n }\n\n fs.mkdirSync(path.dirname(loc.absolutePath), { recursive: true })\n\n if (loc.kind === 'json') {\n writeJsonMcp(loc, apiKey)\n } else {\n writeTomlMcp(loc, apiKey)\n }\n}\n\nfunction writeJsonMcp(loc: McpLocation, apiKey: string): void {\n if (fs.existsSync(loc.absolutePath)) {\n try {\n const existing = JSON.parse(fs.readFileSync(loc.absolutePath, 'utf-8'))\n if (existing.mcpServers?.['01software']) {\n console.log(pc.yellow(' Skipped'), loc.displayPath, pc.dim('(01software already configured)'))\n return\n }\n existing.mcpServers = existing.mcpServers || {}\n existing.mcpServers['01software'] = getMcpServerEntry(apiKey)\n fs.writeFileSync(loc.absolutePath, JSON.stringify(existing, null, 2) + '\\n')\n console.log(pc.green(' Updated'), loc.displayPath)\n } catch {\n console.log(pc.yellow(' Skipped'), loc.displayPath, pc.dim('(could not parse existing file)'))\n }\n } else {\n fs.writeFileSync(loc.absolutePath, getMcpConfigTemplate(apiKey))\n console.log(pc.green(' Created'), loc.displayPath)\n }\n}\n\nfunction writeTomlMcp(loc: McpLocation, apiKey: string): void {\n const section = getCodexMcpTomlSection(apiKey)\n if (fs.existsSync(loc.absolutePath)) {\n const existing = fs.readFileSync(loc.absolutePath, 'utf-8')\n if (existing.includes(CODEX_MCP_SECTION_MARKER)) {\n console.log(pc.yellow(' Skipped'), loc.displayPath, pc.dim('(01software already configured)'))\n return\n }\n const sep = existing.endsWith('\\n') ? '' : '\\n'\n fs.appendFileSync(loc.absolutePath, sep + section)\n console.log(pc.green(' Updated'), loc.displayPath)\n } else {\n fs.writeFileSync(loc.absolutePath, section.trimStart())\n console.log(pc.green(' Created'), loc.displayPath)\n }\n}\n\nfunction addToGitignore(cwd: string, tools: AiTool[]): void {\n const entries: string[] = []\n for (const tool of tools) {\n const loc = resolveMcpLocation(tool, cwd)\n if (loc?.gitignoreEntry) entries.push(loc.gitignoreEntry)\n }\n\n if (entries.length === 0) return\n\n const gitignorePath = path.join(cwd, '.gitignore')\n const existing = fs.existsSync(gitignorePath)\n ? fs.readFileSync(gitignorePath, 'utf-8')\n : ''\n const toAdd = entries.filter((e) => !existing.includes(e))\n if (toAdd.length === 0) return\n\n const content = '\\n# MCP configs (contain API key)\\n' + toAdd.join('\\n') + '\\n'\n if (fs.existsSync(gitignorePath)) {\n fs.appendFileSync(gitignorePath, content)\n } else {\n fs.writeFileSync(gitignorePath, content.trimStart())\n }\n console.log(pc.green(' Updated'), '.gitignore', pc.dim(`(added ${toAdd.join(', ')})`))\n}\n\nasync function writeClaudeDocs(\n cwd: string,\n publishableKey: string,\n secretKey: string,\n tenantName: string,\n): Promise<void> {\n let ctx = {\n tenantName: tenantName || 'Your Tenant',\n features: undefined as string[] | undefined,\n collections: undefined as string[] | undefined,\n }\n\n if (publishableKey && secretKey) {\n const fetched = await fetchTenantContext(publishableKey, secretKey)\n if (fetched) {\n ctx = {\n tenantName: fetched.tenantName || ctx.tenantName,\n features: fetched.features,\n collections: fetched.collections,\n }\n }\n }\n\n const claudeDir = path.join(cwd, '.claude')\n const softwareDir = path.join(claudeDir, '01software')\n const skillsDir = path.join(claudeDir, 'skills')\n fs.mkdirSync(softwareDir, { recursive: true })\n fs.mkdirSync(skillsDir, { recursive: true })\n\n // context.md — always overwrite so re-running init refreshes tenant data\n const contextPath = path.join(softwareDir, 'context.md')\n const contextExists = fs.existsSync(contextPath)\n fs.writeFileSync(contextPath, generateClaudeMd(ctx))\n console.log(pc.green(contextExists ? ' Updated' : ' Created'), '.claude/01software/context.md')\n\n // CLAUDE.md — append @import line (idempotent, never overwrites user content)\n const claudeMdPath = path.join(claudeDir, 'CLAUDE.md')\n const importLine = '@.claude/01software/context.md'\n if (!fs.existsSync(claudeMdPath)) {\n fs.writeFileSync(claudeMdPath, importLine + '\\n')\n console.log(pc.green(' Created'), '.claude/CLAUDE.md')\n } else {\n const existing = fs.readFileSync(claudeMdPath, 'utf-8')\n if (!existing.includes(importLine)) {\n const prefix = existing.endsWith('\\n') ? '\\n' : '\\n\\n'\n fs.appendFileSync(claudeMdPath, prefix + importLine + '\\n')\n console.log(pc.green(' Updated'), '.claude/CLAUDE.md', pc.dim('(added @import)'))\n } else {\n console.log(pc.yellow(' Skipped'), '.claude/CLAUDE.md', pc.dim('(@import already present)'))\n }\n }\n\n // Skill files — skip-if-exists\n for (const { dirName, content } of getSkillFiles()) {\n const skillDir = path.join(skillsDir, dirName)\n const skillPath = path.join(skillDir, 'SKILL.md')\n if (!fs.existsSync(skillPath)) {\n fs.mkdirSync(skillDir, { recursive: true })\n fs.writeFileSync(skillPath, content)\n console.log(pc.green(' Created'), `.claude/skills/${dirName}/SKILL.md`)\n } else {\n console.log(pc.yellow(' Skipped'), `.claude/skills/${dirName}/SKILL.md`, pc.dim('(already exists)'))\n }\n }\n}\n\nfunction relativePath(cwd: string, filePath: string): string {\n return path.relative(cwd, filePath)\n}\n\nconst WS_FILE = 'pnpm-workspace.yaml'\nconst WS_BACKUP = 'pnpm-workspace.yaml.bak'\n\nfunction hasPnpmWorkspace(cwd: string): boolean {\n return fs.existsSync(path.join(cwd, WS_FILE))\n}\n\nfunction patchPnpmWorkspace(cwd: string): boolean {\n const wsPath = path.join(cwd, WS_FILE)\n if (!fs.existsSync(wsPath)) return false\n const content = fs.readFileSync(wsPath, 'utf-8')\n if (content.includes('packages:')) return false\n fs.copyFileSync(wsPath, path.join(cwd, WS_BACKUP))\n fs.writeFileSync(wsPath, content.trimEnd() + '\\npackages: []\\n')\n return true\n}\n\nfunction restorePnpmWorkspace(cwd: string): void {\n const backupPath = path.join(cwd, WS_BACKUP)\n if (!fs.existsSync(backupPath)) return\n fs.copyFileSync(backupPath, path.join(cwd, WS_FILE))\n fs.unlinkSync(backupPath)\n}\n","import { randomBytes } from 'node:crypto'\nimport { createServer } from 'node:http'\nimport { execFile, exec } from 'node:child_process'\nimport { platform } from 'node:os'\nimport { URL } from 'node:url'\nimport pc from 'picocolors'\n\nconst DEFAULT_WEB_URL = process.env.SOFTWARE_WEB_URL || 'https://01.software'\nconst TIMEOUT_MS = 5 * 60 * 1000 // 5 minutes\n\nfunction escapeHtml(s: string): string {\n return s\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, '&quot;')\n}\n\nfunction openBrowser(url: string): void {\n const os = platform()\n\n const onError = () => {\n console.log(\n pc.yellow(\n `Could not open browser automatically. Open this URL manually:\\n${url}`,\n ),\n )\n }\n\n if (os === 'win32') {\n exec(`start \"\" \"${url}\"`, (err) => {\n if (err) onError()\n })\n } else {\n const cmd = os === 'darwin' ? 'open' : 'xdg-open'\n execFile(cmd, [url], (err) => {\n if (err) onError()\n })\n }\n}\n\nconst PAGE_STYLE = `*{margin:0;box-sizing:border-box}\nbody{font-family:system-ui,-apple-system,sans-serif;display:flex;justify-content:center;align-items:center;min-height:100vh;background:#fff;color:#252525}\n@media(prefers-color-scheme:dark){body{background:#252525;color:#f5f5f5}}\n.card{text-align:center;padding:2rem 2.5rem;border-radius:10px;max-width:380px;width:100%}\n.icon{width:40px;height:40px;margin:0 auto 1rem;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:1.25rem}\n.icon.ok{background:rgba(0,0,0,.05);color:#252525}\n.icon.err{background:rgba(220,38,38,.08);color:#dc2626}\n@media(prefers-color-scheme:dark){.icon.ok{background:rgba(255,255,255,.08);color:#f5f5f5}}\nh1{font-size:.875rem;font-weight:600;margin-bottom:.375rem}\np{font-size:.75rem;color:#737373;line-height:1.5}`\n\nconst SUCCESS_HTML = `<!DOCTYPE html>\n<html lang=\"en\"><head><meta charset=\"utf-8\"><meta name=\"viewport\" content=\"width=device-width\"><title>Login</title>\n<style>${PAGE_STYLE}</style>\n</head><body><div class=\"card\"><div class=\"icon ok\">\\u2713</div><h1>Authenticated</h1><p>You can close this tab and return to the terminal.</p></div></body></html>`\n\nconst ERROR_HTML = (msg: string) => `<!DOCTYPE html>\n<html lang=\"en\"><head><meta charset=\"utf-8\"><meta name=\"viewport\" content=\"width=device-width\"><title>Login Error</title>\n<style>${PAGE_STYLE}</style>\n</head><body><div class=\"card\"><div class=\"icon err\">!</div><h1>Authentication failed</h1><p>${escapeHtml(msg)}</p></div></body></html>`\n\ninterface ExchangeResponse {\n publishableKey: string\n secretKey: string\n tenantName: string\n tenantId: string\n}\n\nasync function exchangeCode(\n webUrl: string,\n code: string,\n): Promise<ExchangeResponse | null> {\n const url = `${webUrl}/api/cli/exchange`\n try {\n const res = await fetch(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ code }),\n })\n if (!res.ok) {\n const body = await res.text().catch(() => '')\n console.error(\n pc.red(\n `Exchange failed: HTTP ${res.status} from ${url}${body ? ` — ${body.slice(0, 200)}` : ''}`,\n ),\n )\n return null\n }\n const data = (await res.json()) as Partial<ExchangeResponse>\n if (\n typeof data.publishableKey !== 'string' ||\n typeof data.secretKey !== 'string' ||\n typeof data.tenantName !== 'string' ||\n typeof data.tenantId !== 'string'\n ) {\n console.error(pc.red(`Exchange failed: malformed response from ${url}`))\n return null\n }\n return {\n publishableKey: data.publishableKey,\n secretKey: data.secretKey,\n tenantName: data.tenantName,\n tenantId: data.tenantId,\n }\n } catch (err) {\n console.error(\n pc.red(\n `Exchange request to ${url} failed: ${err instanceof Error ? err.message : String(err)}`,\n ),\n )\n return null\n }\n}\n\nexport async function startBrowserAuth(options?: {\n webUrl?: string\n tenantId?: string\n}): Promise<{\n publishableKey: string\n secretKey: string\n tenantName: string\n tenantId?: string\n}> {\n const state = randomBytes(32).toString('hex')\n const webUrl = options?.webUrl ?? DEFAULT_WEB_URL\n\n return new Promise((resolve, reject) => {\n const server = createServer((req, res) => {\n if (!req.url) {\n res.writeHead(400).end()\n return\n }\n\n const url = new URL(req.url, `http://localhost`)\n\n if (url.pathname !== '/callback' || req.method !== 'GET') {\n res.writeHead(404).end()\n return\n }\n\n const error = url.searchParams.get('error')\n if (error) {\n res\n .writeHead(200, { 'Content-Type': 'text/html; charset=utf-8', Connection: 'close' })\n .end(ERROR_HTML(error))\n console.error(pc.red(`Login failed: ${error}`))\n cleanup(new Error(`Login failed: ${error}`))\n return\n }\n\n const code = url.searchParams.get('code')\n const receivedState = url.searchParams.get('state')\n\n if (!code || !receivedState) {\n res\n .writeHead(400, { 'Content-Type': 'text/html; charset=utf-8', Connection: 'close' })\n .end(ERROR_HTML('Missing code or state.'))\n cleanup(new Error('Login failed: missing code or state.'))\n return\n }\n\n if (receivedState !== state) {\n res\n .writeHead(403, { 'Content-Type': 'text/html; charset=utf-8', Connection: 'close' })\n .end(ERROR_HTML('State mismatch.'))\n console.error(pc.red('Login failed: state mismatch.'))\n cleanup(new Error('Login failed: state mismatch.'))\n return\n }\n\n exchangeCode(webUrl, code).then((creds) => {\n if (!creds) {\n res\n .writeHead(400, { 'Content-Type': 'text/html; charset=utf-8', Connection: 'close' })\n .end(ERROR_HTML('Invalid or expired code.'))\n cleanup(new Error('Login failed: code exchange failed.'))\n return\n }\n\n res\n .writeHead(200, { 'Content-Type': 'text/html; charset=utf-8', Connection: 'close' })\n .end(SUCCESS_HTML)\n\n console.log(pc.green(`\\nLogged in successfully!`))\n console.log(pc.dim(`Tenant: ${creds.tenantName}`))\n\n cleanup(null, creds)\n })\n })\n\n let timeout: ReturnType<typeof setTimeout>\n let completed = false\n\n function cleanup(err: Error | null, result?: ExchangeResponse) {\n if (completed) return\n completed = true\n clearTimeout(timeout)\n server.closeAllConnections?.()\n server.close(() => {\n if (err) {\n reject(err)\n } else {\n resolve(result!)\n }\n })\n }\n\n server.listen(0, '127.0.0.1', () => {\n const addr = server.address()\n if (!addr || typeof addr === 'string') {\n reject(new Error('Failed to start local server.'))\n return\n }\n\n const port = addr.port\n\n timeout = setTimeout(() => {\n console.error(pc.red('\\nLogin timed out (5 minutes). Please try again.'))\n cleanup(new Error('Login timed out'))\n }, TIMEOUT_MS)\n\n const params = new URLSearchParams({ port: String(port), state })\n if (options?.tenantId) {\n params.set('tenantId', options.tenantId)\n }\n const loginUrl = `${webUrl}/cli-auth?${params.toString()}`\n\n console.log(pc.dim('Opening browser for login...'))\n console.log(pc.dim(`If the browser does not open, visit:\\n${loginUrl}`))\n openBrowser(loginUrl)\n })\n\n server.on('error', (err) => {\n reject(err)\n })\n })\n}\n"],"mappings":"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","names":["pc","fs","path","pc","os","path","pc","fs","pc"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/detect.ts","../src/prompts.ts","../src/init.ts","../src/browser-auth.ts"],"sourcesContent":["import pc from 'picocolors'\nimport { detectProject } from './detect'\nimport type { ProjectEnv } from './detect'\nimport { promptUser } from './prompts'\nimport { init } from './init'\n\nconst ENV_LABELS: Record<ProjectEnv, string> = {\n nextjs: 'Next.js',\n 'react-vite': 'React + Vite',\n 'react-cra': 'React + Webpack/CRA',\n vanilla: 'Vanilla JS',\n node: 'Node.js',\n edge: 'Edge runtime',\n other: 'Other framework',\n}\n\n// Manual setup guide for unsupported frameworks\nconst OTHER_FRAMEWORK_GUIDE = `\n Astro, Remix, SvelteKit, and other meta-frameworks have their own\n environment conventions. Manual setup:\n\n 1. Install the SDK:\n npm install @01.software/sdk\n\n 2. Browser client (client islands / RSC):\n import { createClient } from '@01.software/sdk'\n export const client = createClient({ publishableKey: 'YOUR_PUBLISHABLE_KEY' })\n\n 3. Server client (SSR / loaders / endpoints):\n import { createServerClient } from '@01.software/sdk'\n export const serverClient = createServerClient({\n publishableKey: process.env.PUBLIC_SOFTWARE_PUBLISHABLE_KEY!, // prefix varies by framework\n secretKey: process.env.SOFTWARE_SECRET_KEY!,\n })\n\n 4. Docs: https://01.software/docs/developers/sdk/client\n`\n\nasync function main() {\n const cwd = process.cwd()\n\n console.log()\n console.log(pc.bold(' @01.software/init'))\n console.log(pc.dim(' Initialize 01.software SDK in your project'))\n console.log()\n\n // 1. Detect project\n const info = detectProject(cwd)\n\n if (!info.hasPackageJson || info.parseError) {\n if (info.parseError) {\n console.log(pc.red(' Could not parse package.json (invalid JSON).'))\n console.log(pc.dim(' Fix the syntax error and try again.'))\n } else {\n console.log(pc.red(' No package.json found in the current directory.'))\n console.log(pc.dim(' Run this command inside an existing project.'))\n }\n console.log()\n process.exit(1)\n }\n\n // Show detected environment\n const detectedParts: string[] = [ENV_LABELS[info.env]]\n if (info.packageManager) detectedParts.push(info.packageManager)\n if (info.srcDir) detectedParts.push('src/')\n\n if (info.env !== 'node') {\n // Only show detected label when it's unambiguous\n console.log(pc.dim(` Detected: ${detectedParts.join(' / ')}`))\n console.log()\n }\n\n try {\n // 2. Prompt\n const answers = await promptUser(info.hasSdk, info.env, info.packageManager)\n if (!answers) {\n console.log(pc.yellow(' Cancelled.'))\n process.exit(0)\n }\n\n // \"Other\" framework — print guide and exit\n if (answers.env === 'other') {\n console.log(pc.yellow(' Manual setup required for your framework:'))\n console.log(OTHER_FRAMEWORK_GUIDE)\n process.exit(0)\n }\n\n // Resolve package manager from detection or user selection\n const resolvedPm = info.packageManager ?? answers.packageManager ?? 'npm'\n const resolvedInfo = { ...info, packageManager: resolvedPm }\n\n // 3. Init\n console.log()\n const result = await init(cwd, resolvedInfo, answers)\n\n // 4. Next steps\n const env = answers.env\n const run = resolvedPm === 'npm' ? 'npm run' : resolvedPm\n\n console.log()\n console.log(pc.green(' Done!'))\n console.log()\n console.log(' Next steps:')\n console.log()\n\n if (result.installFailed) {\n console.log(pc.yellow(' Install the SDK manually:'))\n console.log(pc.cyan(` ${result.installCmd}`))\n console.log()\n }\n\n if (env === 'nextjs') {\n console.log(pc.dim(' Add QueryProvider to your root layout:'))\n console.log()\n console.log(pc.cyan(\" import { QueryProvider } from '@/lib/software/query-provider'\"))\n console.log(pc.cyan(' <QueryProvider>{children}</QueryProvider>'))\n console.log()\n } else if (env === 'react-vite' || env === 'react-cra') {\n console.log(pc.dim(' Wrap your app entry with QueryProvider:'))\n console.log()\n console.log(pc.cyan(\" import { QueryProvider } from './lib/software/query-provider'\"))\n console.log(pc.cyan(' <QueryProvider><App /></QueryProvider>'))\n console.log()\n } else if (env === 'vanilla') {\n console.log(pc.dim(' Replace YOUR_PUBLISHABLE_KEY in lib/software/client.ts'))\n console.log()\n console.log(pc.cyan(\" import { client } from './lib/software/client'\"))\n console.log(pc.cyan(\" const posts = await client.from('posts').find()\"))\n console.log()\n } else if (env === 'node') {\n console.log(pc.dim(' Use the server client:'))\n console.log()\n console.log(pc.cyan(\" import { serverClient } from './lib/software/server'\"))\n console.log(pc.cyan(\" const posts = await serverClient.from('posts').find()\"))\n console.log()\n } else if (env === 'edge') {\n console.log(pc.dim(' Pass your env bindings to createEdgeClient():'))\n console.log()\n console.log(pc.cyan(\" import { createEdgeClient } from './lib/software/server'\"))\n console.log(pc.cyan(' const serverClient = createEdgeClient(env.PUBLISHABLE_KEY, env.SECRET_KEY)'))\n console.log()\n }\n\n const missingPublishableKey = env !== 'vanilla' && !answers.publishableKey\n const missingSecretKey = (env === 'nextjs' || env === 'node') && !answers.secretKey\n if (missingPublishableKey || missingSecretKey) {\n console.log(pc.dim(' Update .env with your API keys'))\n console.log()\n }\n if (answers.aiTools.length > 0 && (!answers.publishableKey || !answers.secretKey)) {\n console.log(\n pc.dim(\n ' Update MCP config x-api-key with your sk01_... or pat01_... bearer token',\n ),\n )\n console.log()\n }\n if (env !== 'vanilla') {\n console.log(pc.cyan(` ${run} dev`))\n console.log()\n }\n } catch (error) {\n if (error instanceof Error && error.message === 'cancelled') {\n console.log(pc.yellow(' Cancelled.'))\n process.exit(0)\n }\n console.error(pc.red(' Error:'), error)\n process.exit(1)\n }\n}\n\nmain()\n","import fs from 'node:fs'\nimport path from 'node:path'\n\nexport type PackageManager = 'pnpm' | 'npm' | 'yarn' | 'bun'\n\nexport type ProjectEnv =\n | 'nextjs'\n | 'react-vite'\n | 'react-cra'\n | 'vanilla'\n | 'node'\n | 'edge'\n | 'other' // Astro, Remix, SvelteKit, etc. — print guidance only\n\nexport interface ProjectInfo {\n hasPackageJson: boolean\n parseError: boolean\n env: ProjectEnv\n packageManager: PackageManager | null\n hasSdk: boolean\n hasReactQuery: boolean\n srcDir: boolean\n}\n\nexport function detectProject(cwd: string): ProjectInfo {\n const pkgPath = path.join(cwd, 'package.json')\n const hasPackageJson = fs.existsSync(pkgPath)\n\n let env: ProjectEnv = 'node'\n let hasSdk = false\n let hasReactQuery = false\n let parseError = false\n\n if (hasPackageJson) {\n let pkg: Record<string, unknown>\n try {\n pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'))\n } catch {\n return {\n hasPackageJson: true,\n parseError: true,\n env: 'node',\n packageManager: null,\n hasSdk: false,\n hasReactQuery: false,\n srcDir: false,\n }\n }\n\n const deps = {\n ...((pkg.dependencies as Record<string, string>) || {}),\n ...((pkg.devDependencies as Record<string, string>) || {}),\n }\n hasSdk = '@01.software/sdk' in deps\n hasReactQuery = '@tanstack/react-query' in deps\n\n if ('next' in deps) {\n env = 'nextjs'\n } else if ('astro' in deps || '@astrojs/node' in deps) {\n env = 'other'\n } else if ('@remix-run/node' in deps || '@remix-run/react' in deps) {\n env = 'other'\n } else if ('@sveltejs/kit' in deps) {\n env = 'other'\n } else if ('react' in deps) {\n if ('vite' in deps) {\n env = 'react-vite'\n } else if ('react-scripts' in deps) {\n env = 'react-cra'\n } else {\n // React + unknown bundler (Webpack, Parcel, etc.) — leave as 'node'\n // so the prompt selector is shown\n env = 'node'\n }\n }\n // else: no react/next → 'node' (covers real Node.js, Deno, Bun, etc.)\n }\n\n // Detect package manager from lockfile\n let packageManager: PackageManager | null = null\n if (fs.existsSync(path.join(cwd, 'pnpm-lock.yaml'))) {\n packageManager = 'pnpm'\n } else if (fs.existsSync(path.join(cwd, 'yarn.lock'))) {\n packageManager = 'yarn'\n } else if (\n fs.existsSync(path.join(cwd, 'bun.lockb')) ||\n fs.existsSync(path.join(cwd, 'bun.lock'))\n ) {\n packageManager = 'bun'\n } else if (fs.existsSync(path.join(cwd, 'package-lock.json'))) {\n packageManager = 'npm'\n }\n\n // Detect src directory structure\n const srcDir =\n env === 'nextjs'\n ? fs.existsSync(path.join(cwd, 'src', 'app'))\n : fs.existsSync(path.join(cwd, 'src'))\n\n return { hasPackageJson, parseError, env, packageManager, hasSdk, hasReactQuery, srcDir }\n}\n\n/** Environments that generate a browser client file */\nexport function needsClient(env: ProjectEnv): boolean {\n return env === 'nextjs' || env === 'react-vite' || env === 'react-cra' || env === 'vanilla'\n}\n\n/** Environments that generate a server client file */\nexport function needsServer(env: ProjectEnv): boolean {\n return env === 'nextjs' || env === 'node' || env === 'edge'\n}\n\n/** Environments that generate a query-provider file */\nexport function needsReactQuery(env: ProjectEnv): boolean {\n return env === 'nextjs' || env === 'react-vite' || env === 'react-cra'\n}\n\n/** Environments that support MCP setup (need both client + secret key) */\nexport function supportsMcp(env: ProjectEnv): boolean {\n return env === 'nextjs' || env === 'node' || env === 'edge'\n}\n\n/** Get the env var name for the public publishable key */\nexport function getPublishableKeyEnvVar(env: ProjectEnv): string {\n switch (env) {\n case 'nextjs':\n return 'NEXT_PUBLIC_SOFTWARE_PUBLISHABLE_KEY'\n case 'react-vite':\n return 'VITE_SOFTWARE_PUBLISHABLE_KEY'\n case 'react-cra':\n return 'REACT_APP_SOFTWARE_PUBLISHABLE_KEY'\n default:\n return 'SOFTWARE_PUBLISHABLE_KEY'\n }\n}\n","import prompts from 'prompts'\nimport type { PackageManager, ProjectEnv } from './detect'\n\nexport type AiTool =\n | 'claude'\n | 'cursor'\n | 'vscode'\n | 'windsurf'\n | 'codex'\n | 'gemini'\n\nexport type AuthMethod = 'browser' | 'manual' | 'skip'\n\nexport interface InitAnswers {\n env: ProjectEnv\n publishableKey: string\n secretKey: string\n aiTools: AiTool[]\n authMethod: AuthMethod\n packageManager?: PackageManager\n}\n\n// Envs that need the user to disambiguate (couldn't be auto-detected)\nconst AMBIGUOUS_ENVS: ProjectEnv[] = ['node']\n\nexport async function promptUser(\n hasSdk: boolean,\n detectedEnv: ProjectEnv,\n detectedPm: PackageManager | null,\n): Promise<InitAnswers | null> {\n const onCancel = () => {\n throw new Error('cancelled')\n }\n\n // Confirm re-init if SDK already installed\n if (hasSdk) {\n const { proceed } = await prompts(\n {\n type: 'confirm',\n name: 'proceed',\n message: '@01.software/sdk is already installed. Re-initialize?',\n initial: false,\n },\n { onCancel },\n )\n if (!proceed) return null\n }\n\n // Ask for environment when auto-detection is ambiguous\n let env = detectedEnv\n if (AMBIGUOUS_ENVS.includes(detectedEnv)) {\n const { selectedEnv } = await prompts(\n {\n type: 'select',\n name: 'selectedEnv',\n message: 'Which environment are you using?',\n choices: [\n {\n title: 'Next.js',\n description: 'Full-stack React (client + server)',\n value: 'nextjs',\n },\n {\n title: 'React + Vite',\n description: 'Client-only SPA with Vite',\n value: 'react-vite',\n },\n {\n title: 'React + Webpack / other',\n description: 'Client-only SPA, CRA or custom bundler',\n value: 'react-cra',\n },\n {\n title: 'Vanilla JS',\n description: 'Browser app without a framework',\n value: 'vanilla',\n },\n {\n title: 'Node.js / Bun / Deno',\n description: 'Server-only, no browser client',\n value: 'node',\n },\n {\n title: 'Edge runtime',\n description: 'Cloudflare Workers, Vercel Edge Functions',\n value: 'edge',\n },\n {\n title: 'Other (Astro / Remix / SvelteKit…)',\n description: 'Print manual setup guide for your framework',\n value: 'other',\n },\n ],\n },\n { onCancel },\n )\n env = selectedEnv as ProjectEnv\n }\n\n // \"Other\" frameworks — we can't scaffold correctly; exit with guidance\n if (env === 'other') {\n return { env, publishableKey: '', secretKey: '', aiTools: [], authMethod: 'skip', packageManager: undefined }\n }\n\n // Ask for package manager if no lockfile detected\n let packageManager: PackageManager | undefined\n if (!detectedPm) {\n const { pm } = await prompts(\n {\n type: 'select',\n name: 'pm',\n message: 'Which package manager do you use?',\n choices: [\n { title: 'npm', value: 'npm' },\n { title: 'pnpm', value: 'pnpm' },\n { title: 'yarn', value: 'yarn' },\n { title: 'bun', value: 'bun' },\n ],\n },\n { onCancel },\n )\n packageManager = pm\n }\n\n const needsSecretKey = env === 'nextjs' || env === 'node' || env === 'edge'\n\n const keyPrompts: prompts.PromptObject[] = []\n\n // Vanilla JS doesn't use env vars — no prompts for keys\n if (env !== 'vanilla') {\n keyPrompts.push({\n type: 'text',\n name: 'publishableKey',\n message: 'Publishable Key (optional, saved to .env)',\n initial: '',\n })\n }\n\n if (needsSecretKey) {\n keyPrompts.push({\n type: 'text',\n name: 'secretKey',\n message: 'Secret Key (optional, saved to .env)',\n initial: '',\n })\n }\n\n // AI tool multi-select (empty selection = skip)\n const { selectedTools } = await prompts(\n {\n type: 'multiselect',\n name: 'selectedTools',\n message: 'Connect AI tools (leave empty to skip):',\n choices: [\n { title: 'Claude Code', description: '.mcp.json + .claude/ docs', value: 'claude' },\n { title: 'Cursor', description: '.cursor/mcp.json', value: 'cursor' },\n { title: 'VS Code', description: '.vscode/mcp.json', value: 'vscode' },\n { title: 'Windsurf', description: '~/.codeium/windsurf/mcp_config.json', value: 'windsurf' },\n { title: 'Codex CLI', description: '~/.codex/config.toml', value: 'codex' },\n { title: 'Gemini CLI', description: '~/.gemini/settings.json', value: 'gemini' },\n ],\n hint: 'space to select, enter to confirm',\n },\n { onCancel },\n )\n\n const aiTools: AiTool[] = Array.isArray(selectedTools) ? (selectedTools as AiTool[]) : []\n\n // Auth method — only if tools selected and env supports secrets\n let authMethod: AuthMethod = 'skip'\n let keys: Record<string, string> = {}\n\n if (aiTools.length > 0 && env !== 'vanilla') {\n const { method } = await prompts(\n {\n type: 'select',\n name: 'method',\n message: 'API keys:',\n choices: [\n { title: 'Browser login (recommended)', value: 'browser' },\n { title: 'Enter manually', value: 'manual' },\n { title: 'Skip for now', value: 'skip' },\n ],\n },\n { onCancel },\n )\n authMethod = (method as AuthMethod) ?? 'skip'\n\n if (authMethod === 'manual') {\n keys = await prompts(keyPrompts, { onCancel })\n }\n } else if (env !== 'vanilla') {\n // No AI tools selected — still collect keys from the key prompts if any were defined\n if (keyPrompts.length > 0) {\n keys = await prompts(keyPrompts, { onCancel })\n }\n authMethod = 'skip'\n }\n\n return {\n env,\n publishableKey: authMethod === 'browser' ? '' : (keys.publishableKey ?? ''),\n secretKey: authMethod === 'browser' ? '' : (keys.secretKey ?? ''),\n aiTools,\n authMethod,\n packageManager,\n }\n}\n","import fs from 'node:fs'\nimport path from 'node:path'\nimport os from 'node:os'\nimport { execSync } from 'node:child_process'\nimport pc from 'picocolors'\nimport prompts from 'prompts'\nimport type { PackageManager, ProjectEnv, ProjectInfo } from './detect'\nimport {\n needsClient,\n needsServer,\n needsReactQuery,\n getPublishableKeyEnvVar,\n} from './detect'\nimport type { AiTool, InitAnswers } from './prompts'\nimport {\n getClientTemplate,\n getQueryProviderTemplate,\n getServerTemplate,\n getEnvContent,\n getMcpConfigTemplate,\n getMcpServerEntry,\n getCodexMcpTomlSection,\n CODEX_MCP_SECTION_MARKER,\n} from './templates'\nimport { startBrowserAuth } from './browser-auth'\nimport {\n generateClaudeMd,\n getSkillFiles,\n fetchTenantContext,\n} from './ai-docs'\nimport {\n readEnvValue,\n setEnvValue,\n extractTomlApiKey,\n replaceTomlMcpSection,\n} from './file-ops'\n\ntype ResolvedProjectInfo = Omit<ProjectInfo, 'packageManager'> & {\n packageManager: PackageManager\n}\n\nconst SECRET_KEY_ENV_VAR = 'SOFTWARE_SECRET_KEY'\nconst API_KEY_PLACEHOLDER = 'YOUR_API_KEY'\n\nexport type ConflictPolicy = 'overwrite' | 'skip' | 'ask'\n\nexport interface InitResult {\n installFailed: boolean\n installSkipped: boolean\n installCmd: string\n}\n\nexport async function init(\n cwd: string,\n info: ResolvedProjectInfo,\n answers: InitAnswers,\n): Promise<InitResult> {\n const { packageManager, srcDir } = info\n const env = answers.env\n const baseDir = srcDir ? path.join(cwd, 'src') : cwd\n\n const publishableKeyEnvVar = getPublishableKeyEnvVar(env)\n const wantsClient = needsClient(env)\n const wantsServer = needsServer(env)\n const wantsReactQuery = needsReactQuery(env)\n\n // 0. Plan: scan for conflicts and pick the env file. Both prompts are\n // front-loaded so the rest of init() doesn't interleave I/O with prompts.\n const plan = await planConflictsAndEnv(cwd, baseDir, env, answers)\n\n // 1. Install dependencies — skip whatever's already in package.json\n const installResult = installDeps(\n cwd,\n packageManager,\n info.hasSdk,\n info.hasReactQuery,\n wantsReactQuery,\n )\n\n // 2. Write lib/software/ files\n if (wantsClient || wantsReactQuery || wantsServer) {\n fs.mkdirSync(path.join(baseDir, 'lib', 'software'), { recursive: true })\n }\n const libDir = path.join(baseDir, 'lib', 'software')\n\n if (wantsClient) {\n await writeFileWithPolicy(\n cwd,\n path.join(libDir, 'client.ts'),\n getClientTemplate(env, publishableKeyEnvVar),\n plan.policy,\n )\n }\n if (wantsReactQuery) {\n await writeFileWithPolicy(\n cwd,\n path.join(libDir, 'query-provider.tsx'),\n getQueryProviderTemplate(env),\n plan.policy,\n )\n }\n if (wantsServer) {\n await writeFileWithPolicy(\n cwd,\n path.join(libDir, 'server.ts'),\n getServerTemplate(env, publishableKeyEnvVar, SECRET_KEY_ENV_VAR),\n plan.policy,\n )\n }\n\n // 3. Append to env file (browser auth handles its own write in step 4)\n if (plan.envFile && answers.authMethod !== 'browser') {\n await writeEnv(\n cwd,\n plan.envFile,\n answers.publishableKey || '',\n answers.secretKey || '',\n publishableKeyEnvVar,\n wantsServer ? SECRET_KEY_ENV_VAR : null,\n plan.policy,\n )\n }\n\n // 4. Browser auth — get real credentials and force-write env\n let publishableKey = answers.publishableKey\n let secretKey = answers.secretKey\n let tenantName = ''\n\n if (answers.authMethod === 'browser' && answers.aiTools.length > 0) {\n try {\n console.log()\n const creds = await startBrowserAuth()\n publishableKey = creds.publishableKey\n secretKey = creds.secretKey\n tenantName = creds.tenantName\n\n // Browser auth just minted fresh credentials → policy is overwrite.\n if (plan.envFile && publishableKey) {\n await writeEnv(\n cwd,\n plan.envFile,\n publishableKey,\n secretKey,\n publishableKeyEnvVar,\n wantsServer ? SECRET_KEY_ENV_VAR : null,\n 'overwrite',\n true,\n )\n }\n } catch (err) {\n console.log(\n pc.yellow(' Browser auth skipped:'),\n err instanceof Error ? err.message : String(err),\n )\n }\n }\n\n // 5. AI tool configs (MCP + Claude docs)\n if (answers.aiTools.length > 0) {\n const apiKey = secretKey || API_KEY_PLACEHOLDER\n\n for (const tool of answers.aiTools) {\n await writeMcpConfig(tool, cwd, apiKey, plan.policy)\n }\n\n addToGitignore(cwd, answers.aiTools)\n\n if (answers.aiTools.includes('claude')) {\n await writeClaudeDocs(cwd, publishableKey, secretKey, tenantName, plan.policy)\n }\n }\n\n return installResult\n}\n\n// ── Install ──────────────────────────────────────────────────────────\n\ninterface DepSpec {\n name: string\n installed: boolean\n needed: boolean\n}\n\nfunction installDeps(\n cwd: string,\n pm: PackageManager,\n hasSdk: boolean,\n hasReactQuery: boolean,\n wantsReactQuery: boolean,\n): InitResult {\n const allDeps: DepSpec[] = [\n { name: '@01.software/sdk', installed: hasSdk, needed: true },\n { name: '@tanstack/react-query', installed: hasReactQuery, needed: wantsReactQuery },\n ]\n const fullList = allDeps.filter((d) => d.needed).map((d) => d.name)\n const toInstall = allDeps.filter((d) => d.needed && !d.installed).map((d) => d.name)\n const fullCmd = buildAddCmd(pm, hasPnpmWorkspace(cwd), fullList)\n\n if (toInstall.length === 0) {\n console.log(pc.dim(` Dependencies already installed: ${fullList.join(', ')}`))\n return { installFailed: false, installSkipped: true, installCmd: fullCmd }\n }\n\n const addCmd = buildAddCmd(pm, hasPnpmWorkspace(cwd), toInstall)\n console.log(pc.dim(` Installing ${toInstall.join(' and ')}...`))\n\n const wsPatched = pm === 'pnpm' && patchPnpmWorkspace(cwd)\n let installFailed = false\n\n try {\n execSync(addCmd, { cwd, stdio: 'pipe' })\n console.log(pc.green(' Installed'), toInstall.join(', '))\n } catch (error) {\n installFailed = true\n const err = error as { stdout?: Buffer; stderr?: Buffer }\n const msg =\n String(err.stderr || '').trim() ||\n String(err.stdout || '').trim() ||\n String(error)\n console.log(pc.yellow(' Install failed — continuing with scaffolding'))\n const firstLines = msg.split('\\n').slice(0, 3).map((l) => ` ${l}`).join('\\n')\n if (firstLines) console.log(pc.dim(firstLines))\n console.log(pc.dim(` Run manually: ${addCmd}`))\n } finally {\n if (wsPatched) restorePnpmWorkspace(cwd)\n }\n\n return { installFailed, installSkipped: false, installCmd: addCmd }\n}\n\nfunction buildAddCmd(\n pm: PackageManager,\n hasPnpmWs: boolean,\n deps: string[],\n): string {\n const pkgs = deps.join(' ')\n switch (pm) {\n case 'pnpm':\n return hasPnpmWs ? `pnpm add -w ${pkgs}` : `pnpm add ${pkgs}`\n case 'yarn':\n return `yarn add ${pkgs}`\n case 'bun':\n return `bun add ${pkgs}`\n default:\n return `npm install ${pkgs}`\n }\n}\n\n// ── Conflict planning ────────────────────────────────────────────────\n\ninterface PlanResult {\n policy: ConflictPolicy\n /** Empty string when env file is not used (vanilla / edge) */\n envFile: string\n}\n\nasync function planConflictsAndEnv(\n cwd: string,\n baseDir: string,\n env: ProjectEnv,\n answers: InitAnswers,\n): Promise<PlanResult> {\n const candidates: string[] = []\n const libDir = path.join(baseDir, 'lib', 'software')\n if (needsClient(env)) candidates.push(path.join(libDir, 'client.ts'))\n if (needsReactQuery(env)) candidates.push(path.join(libDir, 'query-provider.tsx'))\n if (needsServer(env)) candidates.push(path.join(libDir, 'server.ts'))\n if (answers.aiTools.includes('claude')) {\n for (const { dirName } of getSkillFiles()) {\n candidates.push(path.join(cwd, '.claude', 'skills', dirName, 'SKILL.md'))\n }\n }\n\n const conflicts = candidates.filter((p) => fs.existsSync(p))\n\n let policy: ConflictPolicy = 'skip'\n if (conflicts.length > 0) {\n console.log(pc.yellow(` ${conflicts.length} file(s) already exist:`))\n for (const c of conflicts) console.log(pc.dim(` ${path.relative(cwd, c)}`))\n const { selected } = await prompts({\n type: 'select',\n name: 'selected',\n message: 'How should I handle existing files?',\n choices: [\n { title: 'Keep existing (skip)', value: 'skip' },\n { title: 'Overwrite all', value: 'overwrite' },\n { title: 'Ask for each', value: 'ask' },\n ],\n initial: 0,\n })\n policy = (selected as ConflictPolicy) ?? 'skip'\n }\n\n const envFile =\n env === 'vanilla' || env === 'edge' ? '' : await pickEnvFile(cwd, env)\n\n return { policy, envFile }\n}\n\nasync function pickEnvFile(cwd: string, env: ProjectEnv): Promise<string> {\n // Order matters — `.env.local` first so it's the default selection on\n // Next.js, where it's the conventional secret store.\n const candidates = ['.env.local', '.env', '.env.development']\n const existing = candidates.filter((f) => fs.existsSync(path.join(cwd, f)))\n const preferred = env === 'nextjs' ? '.env.local' : '.env'\n\n if (existing.length === 0) return preferred\n if (existing.length === 1 && existing[0] === preferred) return existing[0]\n\n // Multiple files exist OR the only existing file isn't the preferred default.\n const options = Array.from(new Set([...existing, preferred]))\n const choices = options.map((f) => ({\n title: f,\n description: existing.includes(f) ? 'exists' : 'create',\n value: f,\n }))\n const initial = Math.max(\n 0,\n choices.findIndex((c) => c.value === preferred),\n )\n const { file } = await prompts({\n type: 'select',\n name: 'file',\n message: 'Which env file should I write API keys to?',\n choices,\n initial,\n })\n return file ?? preferred\n}\n\n// ── Generic file write ───────────────────────────────────────────────\n\nasync function writeFileWithPolicy(\n cwd: string,\n filePath: string,\n content: string,\n policy: ConflictPolicy,\n): Promise<void> {\n const rel = path.relative(cwd, filePath)\n if (!fs.existsSync(filePath)) {\n fs.mkdirSync(path.dirname(filePath), { recursive: true })\n fs.writeFileSync(filePath, content)\n console.log(pc.green(' Created'), rel)\n return\n }\n\n const existing = fs.readFileSync(filePath, 'utf-8')\n if (existing === content) {\n console.log(pc.dim(' Unchanged'), rel)\n return\n }\n\n let shouldWrite = false\n if (policy === 'overwrite') {\n shouldWrite = true\n } else if (policy === 'ask') {\n const { confirm } = await prompts({\n type: 'confirm',\n name: 'confirm',\n message: `Overwrite ${rel}?`,\n initial: false,\n })\n shouldWrite = !!confirm\n }\n\n if (shouldWrite) {\n fs.writeFileSync(filePath, content)\n console.log(pc.green(' Overwrote'), rel)\n } else {\n console.log(pc.yellow(' Skipped'), rel, pc.dim('(already exists)'))\n }\n}\n\n// ── Env file write ───────────────────────────────────────────────────\n\nasync function writeEnv(\n cwd: string,\n envFile: string,\n publishableKey: string,\n secretKey: string,\n publishableKeyEnvVar: string,\n secretKeyEnvVar: string | null,\n policy: ConflictPolicy,\n fromBrowserAuth = false,\n): Promise<void> {\n const envPath = path.join(cwd, envFile)\n\n const targets: { name: string; value: string }[] = [\n { name: publishableKeyEnvVar, value: publishableKey },\n ]\n if (secretKeyEnvVar) {\n targets.push({ name: secretKeyEnvVar, value: secretKey })\n }\n\n if (!fs.existsSync(envPath)) {\n const initial = getEnvContent(publishableKey, secretKey, publishableKeyEnvVar, secretKeyEnvVar)\n fs.writeFileSync(envPath, initial.trimStart())\n console.log(pc.green(' Created'), envFile)\n return\n }\n\n let content = fs.readFileSync(envPath, 'utf-8')\n let modified = false\n let appendedHeader = false\n const headerAlreadyPresent = targets.some(\n (t) => readEnvValue(content, t.name) !== null,\n )\n\n for (const { name, value } of targets) {\n const existing = readEnvValue(content, name)\n\n if (existing === null) {\n // Append. Add the `# 01.software` section header on first append, but\n // only if no other 01.software keys are already in the file.\n if (!headerAlreadyPresent && !appendedHeader) {\n if (content.length > 0 && !content.endsWith('\\n')) content += '\\n'\n content += '\\n# 01.software\\n'\n appendedHeader = true\n }\n content = setEnvValue(content, name, value)\n modified = true\n continue\n }\n\n if (existing === value) continue\n // Don't overwrite an existing real value with empty (e.g. user skipped key entry).\n if (!value) continue\n\n let shouldOverwrite = false\n if (policy === 'overwrite') {\n shouldOverwrite = true\n } else if (policy === 'ask') {\n const { confirm } = await prompts({\n type: 'confirm',\n name: 'confirm',\n message: `${name} already set in ${envFile}. Overwrite?`,\n initial: fromBrowserAuth,\n })\n shouldOverwrite = !!confirm\n }\n\n if (shouldOverwrite) {\n content = setEnvValue(content, name, value)\n modified = true\n }\n }\n\n if (modified) {\n fs.writeFileSync(envPath, content)\n console.log(\n pc.green(' Updated'),\n envFile,\n fromBrowserAuth ? pc.dim('(API keys)') : '',\n )\n } else {\n console.log(pc.dim(' Unchanged'), envFile)\n }\n}\n\n// ── MCP targets registry ─────────────────────────────────────────────\n\ntype McpFormat = 'json' | 'toml'\ninterface McpLocation {\n kind: McpFormat\n absolutePath: string\n displayPath: string\n gitignoreEntry: string | null // null = global path, not worth ignoring\n}\n\nfunction resolveMcpLocation(tool: AiTool, cwd: string): McpLocation | null {\n const home = os.homedir()\n\n switch (tool) {\n case 'claude':\n return {\n kind: 'json',\n absolutePath: path.join(cwd, '.mcp.json'),\n displayPath: '.mcp.json',\n gitignoreEntry: '.mcp.json',\n }\n case 'cursor':\n return {\n kind: 'json',\n absolutePath: path.join(cwd, '.cursor', 'mcp.json'),\n displayPath: '.cursor/mcp.json',\n gitignoreEntry: '.cursor/mcp.json',\n }\n case 'vscode':\n return {\n kind: 'json',\n absolutePath: path.join(cwd, '.vscode', 'mcp.json'),\n displayPath: '.vscode/mcp.json',\n gitignoreEntry: '.vscode/mcp.json',\n }\n case 'windsurf': {\n if (!home) return null\n const p = path.join(home, '.codeium', 'windsurf', 'mcp_config.json')\n return { kind: 'json', absolutePath: p, displayPath: p, gitignoreEntry: null }\n }\n case 'codex': {\n if (!home) return null\n const p = path.join(home, '.codex', 'config.toml')\n return { kind: 'toml', absolutePath: p, displayPath: p, gitignoreEntry: null }\n }\n case 'gemini': {\n if (!home) return null\n const p = path.join(home, '.gemini', 'settings.json')\n return { kind: 'json', absolutePath: p, displayPath: p, gitignoreEntry: null }\n }\n }\n}\n\nasync function writeMcpConfig(\n tool: AiTool,\n cwd: string,\n apiKey: string,\n policy: ConflictPolicy,\n): Promise<void> {\n const loc = resolveMcpLocation(tool, cwd)\n if (!loc) {\n console.log(pc.yellow(` Skipped ${tool}`), pc.dim('(HOME not set)'))\n return\n }\n\n fs.mkdirSync(path.dirname(loc.absolutePath), { recursive: true })\n\n if (loc.kind === 'json') {\n await writeJsonMcp(loc, apiKey, policy)\n } else {\n await writeTomlMcp(loc, apiKey, policy)\n }\n}\n\nasync function writeJsonMcp(\n loc: McpLocation,\n apiKey: string,\n policy: ConflictPolicy,\n): Promise<void> {\n if (!fs.existsSync(loc.absolutePath)) {\n fs.writeFileSync(loc.absolutePath, getMcpConfigTemplate(apiKey))\n console.log(pc.green(' Created'), loc.displayPath)\n return\n }\n\n let existing: { mcpServers?: Record<string, { headers?: Record<string, string> }> }\n try {\n existing = JSON.parse(fs.readFileSync(loc.absolutePath, 'utf-8'))\n } catch {\n console.log(pc.yellow(' Skipped'), loc.displayPath, pc.dim('(could not parse existing file)'))\n return\n }\n\n const existingApiKey = existing.mcpServers?.['01software']?.headers?.['x-api-key']\n if (existingApiKey === apiKey) {\n console.log(pc.dim(' Unchanged'), loc.displayPath)\n return\n }\n\n // Refuse to overwrite a real API key with the placeholder.\n if (\n apiKey === API_KEY_PLACEHOLDER &&\n existingApiKey &&\n existingApiKey !== API_KEY_PLACEHOLDER\n ) {\n console.log(pc.dim(' Kept existing API key in'), loc.displayPath)\n return\n }\n\n if (existingApiKey) {\n const shouldUpdate = await confirmKeyUpdate(loc.displayPath, policy)\n if (!shouldUpdate) {\n console.log(pc.yellow(' Skipped'), loc.displayPath, pc.dim('(kept existing API key)'))\n return\n }\n }\n\n existing.mcpServers = existing.mcpServers || {}\n existing.mcpServers['01software'] = getMcpServerEntry(apiKey)\n fs.writeFileSync(loc.absolutePath, JSON.stringify(existing, null, 2) + '\\n')\n console.log(pc.green(' Updated'), loc.displayPath)\n}\n\nasync function writeTomlMcp(\n loc: McpLocation,\n apiKey: string,\n policy: ConflictPolicy,\n): Promise<void> {\n const section = getCodexMcpTomlSection(apiKey)\n\n if (!fs.existsSync(loc.absolutePath)) {\n fs.writeFileSync(loc.absolutePath, section.trimStart())\n console.log(pc.green(' Created'), loc.displayPath)\n return\n }\n\n const existing = fs.readFileSync(loc.absolutePath, 'utf-8')\n\n if (!existing.includes(CODEX_MCP_SECTION_MARKER)) {\n const sep = existing.endsWith('\\n') ? '' : '\\n'\n fs.appendFileSync(loc.absolutePath, sep + section)\n console.log(pc.green(' Updated'), loc.displayPath)\n return\n }\n\n const existingApiKey = extractTomlApiKey(existing)\n if (existingApiKey === apiKey) {\n console.log(pc.dim(' Unchanged'), loc.displayPath)\n return\n }\n\n if (\n apiKey === API_KEY_PLACEHOLDER &&\n existingApiKey &&\n existingApiKey !== API_KEY_PLACEHOLDER\n ) {\n console.log(pc.dim(' Kept existing API key in'), loc.displayPath)\n return\n }\n\n const shouldUpdate = await confirmKeyUpdate(loc.displayPath, policy)\n if (!shouldUpdate) {\n console.log(pc.yellow(' Skipped'), loc.displayPath, pc.dim('(kept existing API key)'))\n return\n }\n\n const replaced = replaceTomlMcpSection(existing, section)\n fs.writeFileSync(loc.absolutePath, replaced)\n console.log(pc.green(' Updated'), loc.displayPath)\n}\n\nasync function confirmKeyUpdate(displayPath: string, policy: ConflictPolicy): Promise<boolean> {\n if (policy === 'overwrite') return true\n // For MCP we always confirm when the API key differs — silently keeping a\n // stale key would defeat the purpose of re-running init with new credentials.\n const { confirm } = await prompts({\n type: 'confirm',\n name: 'confirm',\n message: `${displayPath} has a different 01software API key. Update?`,\n initial: true,\n })\n return !!confirm\n}\n\nfunction addToGitignore(cwd: string, tools: AiTool[]): void {\n const entries: string[] = []\n for (const tool of tools) {\n const loc = resolveMcpLocation(tool, cwd)\n if (loc?.gitignoreEntry) entries.push(loc.gitignoreEntry)\n }\n\n if (entries.length === 0) return\n\n const gitignorePath = path.join(cwd, '.gitignore')\n const existing = fs.existsSync(gitignorePath)\n ? fs.readFileSync(gitignorePath, 'utf-8')\n : ''\n const toAdd = entries.filter((e) => !existing.includes(e))\n if (toAdd.length === 0) return\n\n const content = '\\n# MCP configs (contain API key)\\n' + toAdd.join('\\n') + '\\n'\n if (fs.existsSync(gitignorePath)) {\n fs.appendFileSync(gitignorePath, content)\n } else {\n fs.writeFileSync(gitignorePath, content.trimStart())\n }\n console.log(pc.green(' Updated'), '.gitignore', pc.dim(`(added ${toAdd.join(', ')})`))\n}\n\nasync function writeClaudeDocs(\n cwd: string,\n publishableKey: string,\n secretKey: string,\n tenantName: string,\n policy: ConflictPolicy,\n): Promise<void> {\n let ctx = {\n tenantName: tenantName || 'Your Tenant',\n features: undefined as string[] | undefined,\n collections: undefined as string[] | undefined,\n }\n\n if (publishableKey && secretKey) {\n const fetched = await fetchTenantContext(publishableKey, secretKey)\n if (fetched) {\n ctx = {\n tenantName: fetched.tenantName || ctx.tenantName,\n features: fetched.features,\n collections: fetched.collections,\n }\n }\n }\n\n const claudeDir = path.join(cwd, '.claude')\n const softwareDir = path.join(claudeDir, '01software')\n const skillsDir = path.join(claudeDir, 'skills')\n fs.mkdirSync(softwareDir, { recursive: true })\n fs.mkdirSync(skillsDir, { recursive: true })\n\n // context.md is intentionally always overwritten so re-running init\n // refreshes tenant data; users don't customize this file.\n const contextPath = path.join(softwareDir, 'context.md')\n const contextExists = fs.existsSync(contextPath)\n fs.writeFileSync(contextPath, generateClaudeMd(ctx))\n console.log(pc.green(contextExists ? ' Updated' : ' Created'), '.claude/01software/context.md')\n\n // CLAUDE.md — append @import line (idempotent, never overwrites user content)\n const claudeMdPath = path.join(claudeDir, 'CLAUDE.md')\n const importLine = '@.claude/01software/context.md'\n if (!fs.existsSync(claudeMdPath)) {\n fs.writeFileSync(claudeMdPath, importLine + '\\n')\n console.log(pc.green(' Created'), '.claude/CLAUDE.md')\n } else {\n const existing = fs.readFileSync(claudeMdPath, 'utf-8')\n if (!existing.includes(importLine)) {\n const prefix = existing.endsWith('\\n') ? '\\n' : '\\n\\n'\n fs.appendFileSync(claudeMdPath, prefix + importLine + '\\n')\n console.log(pc.green(' Updated'), '.claude/CLAUDE.md', pc.dim('(added @import)'))\n } else {\n console.log(pc.dim(' Unchanged'), '.claude/CLAUDE.md')\n }\n }\n\n // Skill files honour the user's conflict policy (templates the user may have\n // tuned to their workflow).\n for (const { dirName, content } of getSkillFiles()) {\n const skillDir = path.join(skillsDir, dirName)\n const skillPath = path.join(skillDir, 'SKILL.md')\n fs.mkdirSync(skillDir, { recursive: true })\n await writeFileWithPolicy(cwd, skillPath, content, policy)\n }\n}\n\nconst WS_FILE = 'pnpm-workspace.yaml'\nconst WS_BACKUP = 'pnpm-workspace.yaml.bak'\n\nfunction hasPnpmWorkspace(cwd: string): boolean {\n return fs.existsSync(path.join(cwd, WS_FILE))\n}\n\nfunction patchPnpmWorkspace(cwd: string): boolean {\n const wsPath = path.join(cwd, WS_FILE)\n if (!fs.existsSync(wsPath)) return false\n const content = fs.readFileSync(wsPath, 'utf-8')\n if (content.includes('packages:')) return false\n fs.copyFileSync(wsPath, path.join(cwd, WS_BACKUP))\n fs.writeFileSync(wsPath, content.trimEnd() + '\\npackages: []\\n')\n return true\n}\n\nfunction restorePnpmWorkspace(cwd: string): void {\n const backupPath = path.join(cwd, WS_BACKUP)\n if (!fs.existsSync(backupPath)) return\n fs.copyFileSync(backupPath, path.join(cwd, WS_FILE))\n fs.unlinkSync(backupPath)\n}\n","import { randomBytes } from 'node:crypto'\nimport { createServer } from 'node:http'\nimport { execFile, exec } from 'node:child_process'\nimport { platform } from 'node:os'\nimport { URL } from 'node:url'\nimport pc from 'picocolors'\n\nconst DEFAULT_WEB_URL = process.env.SOFTWARE_WEB_URL || 'https://01.software'\nconst TIMEOUT_MS = 5 * 60 * 1000 // 5 minutes\n\nfunction escapeHtml(s: string): string {\n return s\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, '&quot;')\n}\n\nfunction openBrowser(url: string): void {\n const os = platform()\n\n const onError = () => {\n console.log(\n pc.yellow(\n `Could not open browser automatically. Open this URL manually:\\n${url}`,\n ),\n )\n }\n\n if (os === 'win32') {\n exec(`start \"\" \"${url}\"`, (err) => {\n if (err) onError()\n })\n } else {\n const cmd = os === 'darwin' ? 'open' : 'xdg-open'\n execFile(cmd, [url], (err) => {\n if (err) onError()\n })\n }\n}\n\nconst PAGE_STYLE = `*{margin:0;box-sizing:border-box}\nbody{font-family:system-ui,-apple-system,sans-serif;display:flex;justify-content:center;align-items:center;min-height:100vh;background:#fff;color:#252525}\n@media(prefers-color-scheme:dark){body{background:#252525;color:#f5f5f5}}\n.card{text-align:center;padding:2rem 2.5rem;border-radius:10px;max-width:380px;width:100%}\n.icon{width:40px;height:40px;margin:0 auto 1rem;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:1.25rem}\n.icon.ok{background:rgba(0,0,0,.05);color:#252525}\n.icon.err{background:rgba(220,38,38,.08);color:#dc2626}\n@media(prefers-color-scheme:dark){.icon.ok{background:rgba(255,255,255,.08);color:#f5f5f5}}\nh1{font-size:.875rem;font-weight:600;margin-bottom:.375rem}\np{font-size:.75rem;color:#737373;line-height:1.5}`\n\nconst SUCCESS_HTML = `<!DOCTYPE html>\n<html lang=\"en\"><head><meta charset=\"utf-8\"><meta name=\"viewport\" content=\"width=device-width\"><title>Login</title>\n<style>${PAGE_STYLE}</style>\n</head><body><div class=\"card\"><div class=\"icon ok\">\\u2713</div><h1>Authenticated</h1><p>You can close this tab and return to the terminal.</p></div></body></html>`\n\nconst ERROR_HTML = (msg: string) => `<!DOCTYPE html>\n<html lang=\"en\"><head><meta charset=\"utf-8\"><meta name=\"viewport\" content=\"width=device-width\"><title>Login Error</title>\n<style>${PAGE_STYLE}</style>\n</head><body><div class=\"card\"><div class=\"icon err\">!</div><h1>Authentication failed</h1><p>${escapeHtml(msg)}</p></div></body></html>`\n\ninterface ExchangeResponse {\n publishableKey: string\n secretKey: string\n tenantName: string\n tenantId: string\n}\n\nasync function exchangeCode(\n webUrl: string,\n code: string,\n): Promise<ExchangeResponse | null> {\n const url = `${webUrl}/api/cli/exchange`\n try {\n const res = await fetch(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ code }),\n })\n if (!res.ok) {\n const body = await res.text().catch(() => '')\n console.error(\n pc.red(\n `Exchange failed: HTTP ${res.status} from ${url}${body ? ` — ${body.slice(0, 200)}` : ''}`,\n ),\n )\n return null\n }\n const data = (await res.json()) as Partial<ExchangeResponse>\n if (\n typeof data.publishableKey !== 'string' ||\n typeof data.secretKey !== 'string' ||\n typeof data.tenantName !== 'string' ||\n typeof data.tenantId !== 'string'\n ) {\n console.error(pc.red(`Exchange failed: malformed response from ${url}`))\n return null\n }\n return {\n publishableKey: data.publishableKey,\n secretKey: data.secretKey,\n tenantName: data.tenantName,\n tenantId: data.tenantId,\n }\n } catch (err) {\n console.error(\n pc.red(\n `Exchange request to ${url} failed: ${err instanceof Error ? err.message : String(err)}`,\n ),\n )\n return null\n }\n}\n\nexport async function startBrowserAuth(options?: {\n webUrl?: string\n tenantId?: string\n}): Promise<{\n publishableKey: string\n secretKey: string\n tenantName: string\n tenantId?: string\n}> {\n const state = randomBytes(32).toString('hex')\n const webUrl = options?.webUrl ?? DEFAULT_WEB_URL\n\n return new Promise((resolve, reject) => {\n const server = createServer((req, res) => {\n if (!req.url) {\n res.writeHead(400).end()\n return\n }\n\n const url = new URL(req.url, `http://localhost`)\n\n if (url.pathname !== '/callback' || req.method !== 'GET') {\n res.writeHead(404).end()\n return\n }\n\n const error = url.searchParams.get('error')\n if (error) {\n res\n .writeHead(200, { 'Content-Type': 'text/html; charset=utf-8', Connection: 'close' })\n .end(ERROR_HTML(error))\n console.error(pc.red(`Login failed: ${error}`))\n cleanup(new Error(`Login failed: ${error}`))\n return\n }\n\n const code = url.searchParams.get('code')\n const receivedState = url.searchParams.get('state')\n\n if (!code || !receivedState) {\n res\n .writeHead(400, { 'Content-Type': 'text/html; charset=utf-8', Connection: 'close' })\n .end(ERROR_HTML('Missing code or state.'))\n cleanup(new Error('Login failed: missing code or state.'))\n return\n }\n\n if (receivedState !== state) {\n res\n .writeHead(403, { 'Content-Type': 'text/html; charset=utf-8', Connection: 'close' })\n .end(ERROR_HTML('State mismatch.'))\n console.error(pc.red('Login failed: state mismatch.'))\n cleanup(new Error('Login failed: state mismatch.'))\n return\n }\n\n exchangeCode(webUrl, code).then((creds) => {\n if (!creds) {\n res\n .writeHead(400, { 'Content-Type': 'text/html; charset=utf-8', Connection: 'close' })\n .end(ERROR_HTML('Invalid or expired code.'))\n cleanup(new Error('Login failed: code exchange failed.'))\n return\n }\n\n res\n .writeHead(200, { 'Content-Type': 'text/html; charset=utf-8', Connection: 'close' })\n .end(SUCCESS_HTML)\n\n console.log(pc.green(`\\nLogged in successfully!`))\n console.log(pc.dim(`Tenant: ${creds.tenantName}`))\n\n cleanup(null, creds)\n })\n })\n\n let timeout: ReturnType<typeof setTimeout>\n let completed = false\n\n function cleanup(err: Error | null, result?: ExchangeResponse) {\n if (completed) return\n completed = true\n clearTimeout(timeout)\n server.closeAllConnections?.()\n server.close(() => {\n if (err) {\n reject(err)\n } else {\n resolve(result!)\n }\n })\n }\n\n server.listen(0, '127.0.0.1', () => {\n const addr = server.address()\n if (!addr || typeof addr === 'string') {\n reject(new Error('Failed to start local server.'))\n return\n }\n\n const port = addr.port\n\n timeout = setTimeout(() => {\n console.error(pc.red('\\nLogin timed out (5 minutes). Please try again.'))\n cleanup(new Error('Login timed out'))\n }, TIMEOUT_MS)\n\n const params = new URLSearchParams({ port: String(port), state })\n if (options?.tenantId) {\n params.set('tenantId', options.tenantId)\n }\n const loginUrl = `${webUrl}/cli-auth?${params.toString()}`\n\n console.log(pc.dim('Opening browser for login...'))\n console.log(pc.dim(`If the browser does not open, visit:\\n${loginUrl}`))\n openBrowser(loginUrl)\n })\n\n server.on('error', (err) => {\n reject(err)\n })\n })\n}\n"],"mappings":"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","names":["pc","fs","path","pc","prompts","os","path","fs","pc","prompts","pc"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@01.software/init",
3
- "version": "0.5.1",
3
+ "version": "0.6.1",
4
4
  "description": "Initialize 01.software SDK in your project (Next.js, React, Vanilla JS, Node.js, Edge)",
5
5
  "type": "module",
6
6
  "bin": {