@01.software/init 0.6.1 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/ai-docs.js CHANGED
@@ -3,7 +3,7 @@ import {
3
3
  fetchTenantContext,
4
4
  generateClaudeMd,
5
5
  getSkillFiles
6
- } from "./chunk-SRLZ5OIV.js";
6
+ } from "./chunk-T3A5SLEJ.js";
7
7
  export {
8
8
  fetchTenantContext,
9
9
  generateClaudeMd,
@@ -22,27 +22,23 @@ function setEnvValue(content, name, value) {
22
22
  return content + sep + `${name}=${value}
23
23
  `;
24
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, "\\");
25
+ var OWNED_MCP_TOML_SECTION = "mcp_servers.01software";
26
+ function tomlSectionName(line) {
27
+ const match = line.trim().match(/^\[([^\]]+)\]$/);
28
+ return match ? match[1] : null;
29
+ }
30
+ function isOwnedMcpTomlSection(sectionName) {
31
+ return sectionName === OWNED_MCP_TOML_SECTION || sectionName.startsWith(`${OWNED_MCP_TOML_SECTION}.`);
33
32
  }
34
33
  function replaceTomlMcpSection(content, newSection) {
35
34
  const lines = content.split("\n");
36
35
  const kept = [];
37
36
  let inOurSection = false;
38
37
  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;
38
+ const sectionName = tomlSectionName(line);
39
+ if (sectionName) {
40
+ inOurSection = isOwnedMcpTomlSection(sectionName);
41
+ if (inOurSection) continue;
46
42
  }
47
43
  if (!inOurSection) kept.push(line);
48
44
  }
@@ -55,7 +51,6 @@ function replaceTomlMcpSection(content, newSection) {
55
51
  export {
56
52
  readEnvValue,
57
53
  setEnvValue,
58
- extractTomlApiKey,
59
54
  replaceTomlMcpSection
60
55
  };
61
- //# sourceMappingURL=chunk-VOEXMD2S.js.map
56
+ //# sourceMappingURL=chunk-JT3G6B66.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 OWNED_MCP_TOML_SECTION = 'mcp_servers.01software'\n\nfunction tomlSectionName(line: string): string | null {\n const match = line.trim().match(/^\\[([^\\]]+)\\]$/)\n return match ? match[1] : null\n}\n\nfunction isOwnedMcpTomlSection(sectionName: string): boolean {\n return (\n sectionName === OWNED_MCP_TOML_SECTION ||\n sectionName.startsWith(`${OWNED_MCP_TOML_SECTION}.`)\n )\n}\n\n/** Removes the existing `[mcp_servers.01software]` block and sub-blocks from a\n * 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 sectionName = tomlSectionName(line)\n if (sectionName) {\n inOurSection = isOwnedMcpTomlSection(sectionName)\n if (inOurSection) continue\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,yBAAyB;AAE/B,SAAS,gBAAgB,MAA6B;AACpD,QAAM,QAAQ,KAAK,KAAK,EAAE,MAAM,gBAAgB;AAChD,SAAO,QAAQ,MAAM,CAAC,IAAI;AAC5B;AAEA,SAAS,sBAAsB,aAA8B;AAC3D,SACE,gBAAgB,0BAChB,YAAY,WAAW,GAAG,sBAAsB,GAAG;AAEvD;AAIO,SAAS,sBAAsB,SAAiB,YAA4B;AACjF,QAAM,QAAQ,QAAQ,MAAM,IAAI;AAChC,QAAM,OAAiB,CAAC;AACxB,MAAI,eAAe;AACnB,aAAW,QAAQ,OAAO;AACxB,UAAM,cAAc,gBAAgB,IAAI;AACxC,QAAI,aAAa;AACf,qBAAe,sBAAsB,WAAW;AAChD,UAAI,aAAc;AAAA,IACpB;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,180 @@
1
+ #!/usr/bin/env node
2
+
3
+ // ../auth-contracts/dist/index.js
4
+ var MCP_RESOURCE_AUDIENCE = "https://mcp.01.software/mcp";
5
+
6
+ // src/templates.ts
7
+ function getClientTemplate(env, publishableKeyEnvVar) {
8
+ if (env === "nextjs") {
9
+ return `import { createClient } from '@01.software/sdk'
10
+
11
+ export const client = createClient({
12
+ publishableKey: process.env.${publishableKeyEnvVar}!,
13
+ })
14
+ `;
15
+ }
16
+ if (env === "react-cra") {
17
+ return `import { createClient } from '@01.software/sdk'
18
+
19
+ export const client = createClient({
20
+ publishableKey: process.env.${publishableKeyEnvVar}!,
21
+ })
22
+ `;
23
+ }
24
+ if (env === "vanilla") {
25
+ return `import { createClient } from '@01.software/sdk'
26
+
27
+ // Replace 'YOUR_PUBLISHABLE_KEY' with your actual publishable key from the 01.software console
28
+ export const client = createClient({
29
+ publishableKey: 'YOUR_PUBLISHABLE_KEY',
30
+ })
31
+ `;
32
+ }
33
+ return `import { createClient } from '@01.software/sdk'
34
+
35
+ export const client = createClient({
36
+ publishableKey: import.meta.env.${publishableKeyEnvVar},
37
+ })
38
+ `;
39
+ }
40
+ function getAnalyticsTemplate(env, publishableKeyEnvVar) {
41
+ if (env === "vanilla") {
42
+ return `import { createAnalytics } from '@01.software/sdk/analytics'
43
+
44
+ // Replace 'YOUR_PUBLISHABLE_KEY' with your actual publishable key from the 01.software console
45
+ export const analytics = createAnalytics({
46
+ publishableKey: 'YOUR_PUBLISHABLE_KEY',
47
+ })
48
+ `;
49
+ }
50
+ const publishableKeyExpression = env === "react-vite" ? `import.meta.env.${publishableKeyEnvVar}` : `process.env.${publishableKeyEnvVar}!`;
51
+ return `import { createAnalytics } from '@01.software/sdk/analytics'
52
+
53
+ export const analytics = createAnalytics({
54
+ publishableKey: ${publishableKeyExpression},
55
+ })
56
+ `;
57
+ }
58
+ function getQueryProviderTemplate(env) {
59
+ const useClientDirective = env === "nextjs" ? "'use client'\n\n" : "";
60
+ return `${useClientDirective}import { QueryClientProvider } from '@tanstack/react-query'
61
+ import { client } from './client'
62
+
63
+ export function QueryProvider({ children }: { children: React.ReactNode }) {
64
+ return (
65
+ <QueryClientProvider client={client.queryClient}>
66
+ {children}
67
+ </QueryClientProvider>
68
+ )
69
+ }
70
+ `;
71
+ }
72
+ function getServerTemplate(env, publishableKeyEnvVar, secretKeyEnvVar) {
73
+ if (env === "edge") {
74
+ return `import { createServerClient } from '@01.software/sdk'
75
+
76
+ // Edge runtime: pass your env bindings here
77
+ // e.g. Cloudflare Workers: use env.SOFTWARE_PUBLISHABLE_KEY from the handler context
78
+ // e.g. Vercel Edge: use process.env.${publishableKeyEnvVar}
79
+ export function createEdgeClient(publishableKey: string, secretKey: string) {
80
+ return createServerClient({ publishableKey, secretKey })
81
+ }
82
+ `;
83
+ }
84
+ return `import { createServerClient } from '@01.software/sdk'
85
+
86
+ /**
87
+ * Runtime guard: this module contains secret keys and must never be
88
+ * imported from client-side (browser) code. If the bundler accidentally
89
+ * includes it in a client bundle, this throws at module-evaluation time.
90
+ */
91
+ if (typeof window !== 'undefined') {
92
+ throw new Error(
93
+ 'lib/software/server.ts must not be imported in client-side code \u2014 it contains secret keys.',
94
+ )
95
+ }
96
+
97
+ type ServerClient = ReturnType<typeof createServerClient>
98
+
99
+ let cachedClient: ServerClient | null = null
100
+
101
+ function createConfiguredClient(): ServerClient {
102
+ const publishableKey = process.env.${publishableKeyEnvVar}
103
+ const secretKey = process.env.${secretKeyEnvVar}
104
+
105
+ if (!publishableKey || !secretKey) {
106
+ throw new Error(
107
+ 'Server client requires ${publishableKeyEnvVar} and ${secretKeyEnvVar}.',
108
+ )
109
+ }
110
+
111
+ return createServerClient({ publishableKey, secretKey })
112
+ }
113
+
114
+ export function getServerClient(): ServerClient {
115
+ cachedClient ??= createConfiguredClient()
116
+ return cachedClient
117
+ }
118
+
119
+ /**
120
+ * Lazy Proxy: the underlying client is created only on first property access,
121
+ * so importing this file has no side effects until you actually call it.
122
+ */
123
+ export const serverClient = new Proxy({} as ServerClient, {
124
+ get(_target, prop, receiver) {
125
+ const target = getServerClient()
126
+ const value = Reflect.get(target as object, prop, receiver)
127
+ return typeof value === 'function' ? value.bind(target) : value
128
+ },
129
+ })
130
+ `;
131
+ }
132
+ function getEnvContent(publishableKey, secretKey, publishableKeyEnvVar, secretKeyEnvVar) {
133
+ let content = `
134
+ # 01.software
135
+ ${publishableKeyEnvVar}=${publishableKey}
136
+ `;
137
+ if (secretKeyEnvVar) {
138
+ content += `${secretKeyEnvVar}=${secretKey}
139
+ `;
140
+ }
141
+ return content;
142
+ }
143
+ function getMcpServerEntry(client = "generic") {
144
+ if (client === "windsurf") {
145
+ return {
146
+ serverUrl: MCP_RESOURCE_AUDIENCE
147
+ };
148
+ }
149
+ return {
150
+ type: "http",
151
+ url: MCP_RESOURCE_AUDIENCE
152
+ };
153
+ }
154
+ function getMcpConfigTemplate(client = "generic") {
155
+ return JSON.stringify(
156
+ { mcpServers: { "01software": getMcpServerEntry(client) } },
157
+ null,
158
+ 2
159
+ ) + "\n";
160
+ }
161
+ function getCodexMcpTomlSection() {
162
+ return `
163
+ [mcp_servers.01software]
164
+ url = "${MCP_RESOURCE_AUDIENCE}"
165
+ `;
166
+ }
167
+ var CODEX_MCP_SECTION_MARKER = "[mcp_servers.01software]";
168
+
169
+ export {
170
+ getClientTemplate,
171
+ getAnalyticsTemplate,
172
+ getQueryProviderTemplate,
173
+ getServerTemplate,
174
+ getEnvContent,
175
+ getMcpServerEntry,
176
+ getMcpConfigTemplate,
177
+ getCodexMcpTomlSection,
178
+ CODEX_MCP_SECTION_MARKER
179
+ };
180
+ //# sourceMappingURL=chunk-S3KHPWCE.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../auth-contracts/src/index.ts","../src/templates.ts"],"sourcesContent":["export const MCP_RESOURCE_AUDIENCE = 'https://mcp.01.software/mcp'\n\nexport const MCP_OAUTH_ISSUER = 'https://01.software'\n\nexport const MCP_PROTECTED_RESOURCE_METADATA_PATH =\n '/.well-known/oauth-protected-resource/mcp'\n\nexport const MCP_AUTHORIZATION_SERVER_METADATA_PATH =\n '/.well-known/oauth-authorization-server'\n\nexport const MCP_TENANT_CLAIM = 'tenant_id'\n\nexport const MCP_TENANT_ROLE_CLAIM = 'tenant_role'\n\nexport const MCP_SCOPES = {\n read: 'mcp:read',\n write: 'mcp:write',\n} as const\n\nexport const MCP_CONSOLE_SERVICE_AUDIENCE =\n 'https://api.01.software/internal/mcp'\n\nexport const MCP_CONSOLE_SERVICE_SCOPE = 'console:mcp_proxy'\n\nexport const MCP_SERVICE_TOKEN_LIFETIME_SECONDS = 60\n","import type { ProjectEnv } from './detect'\nimport { MCP_RESOURCE_AUDIENCE } from '@01.software/auth-contracts'\n\n// ── Client template (browser) ────────────────────────────────────────\n\nexport function getClientTemplate(env: ProjectEnv, publishableKeyEnvVar: string): string {\n if (env === 'nextjs') {\n return `import { createClient } from '@01.software/sdk'\n\nexport const client = createClient({\n publishableKey: process.env.${publishableKeyEnvVar}!,\n})\n`\n }\n\n if (env === 'react-cra') {\n return `import { createClient } from '@01.software/sdk'\n\nexport const client = createClient({\n publishableKey: process.env.${publishableKeyEnvVar}!,\n})\n`\n }\n\n if (env === 'vanilla') {\n return `import { createClient } from '@01.software/sdk'\n\n// Replace 'YOUR_PUBLISHABLE_KEY' with your actual publishable key from the 01.software console\nexport const client = createClient({\n publishableKey: 'YOUR_PUBLISHABLE_KEY',\n})\n`\n }\n\n // react-vite (import.meta.env)\n return `import { createClient } from '@01.software/sdk'\n\nexport const client = createClient({\n publishableKey: import.meta.env.${publishableKeyEnvVar},\n})\n`\n}\n\n// ── Analytics template (browser) ─────────────────────────────────────\n\nexport function getAnalyticsTemplate(\n env: ProjectEnv,\n publishableKeyEnvVar: string,\n): string {\n if (env === 'vanilla') {\n return `import { createAnalytics } from '@01.software/sdk/analytics'\n\n// Replace 'YOUR_PUBLISHABLE_KEY' with your actual publishable key from the 01.software console\nexport const analytics = createAnalytics({\n publishableKey: 'YOUR_PUBLISHABLE_KEY',\n})\n`\n }\n\n const publishableKeyExpression =\n env === 'react-vite'\n ? `import.meta.env.${publishableKeyEnvVar}`\n : `process.env.${publishableKeyEnvVar}!`\n\n return `import { createAnalytics } from '@01.software/sdk/analytics'\n\nexport const analytics = createAnalytics({\n publishableKey: ${publishableKeyExpression},\n})\n`\n}\n\n// ── Query Provider template ──────────────────────────────────────────\n\nexport function getQueryProviderTemplate(env: ProjectEnv): string {\n const useClientDirective = env === 'nextjs' ? \"'use client'\\n\\n\" : ''\n\n return `${useClientDirective}import { QueryClientProvider } from '@tanstack/react-query'\nimport { client } from './client'\n\nexport function QueryProvider({ children }: { children: React.ReactNode }) {\n return (\n <QueryClientProvider client={client.queryClient}>\n {children}\n </QueryClientProvider>\n )\n}\n`\n}\n\n// ── Server template ──────────────────────────────────────────────────\n\nexport function getServerTemplate(\n env: ProjectEnv,\n publishableKeyEnvVar: string,\n secretKeyEnvVar: string,\n): string {\n if (env === 'edge') {\n return `import { createServerClient } from '@01.software/sdk'\n\n// Edge runtime: pass your env bindings here\n// e.g. Cloudflare Workers: use env.SOFTWARE_PUBLISHABLE_KEY from the handler context\n// e.g. Vercel Edge: use process.env.${publishableKeyEnvVar}\nexport function createEdgeClient(publishableKey: string, secretKey: string) {\n return createServerClient({ publishableKey, secretKey })\n}\n`\n }\n\n return `import { createServerClient } from '@01.software/sdk'\n\n/**\n * Runtime guard: this module contains secret keys and must never be\n * imported from client-side (browser) code. If the bundler accidentally\n * includes it in a client bundle, this throws at module-evaluation time.\n */\nif (typeof window !== 'undefined') {\n throw new Error(\n 'lib/software/server.ts must not be imported in client-side code — it contains secret keys.',\n )\n}\n\ntype ServerClient = ReturnType<typeof createServerClient>\n\nlet cachedClient: ServerClient | null = null\n\nfunction createConfiguredClient(): ServerClient {\n const publishableKey = process.env.${publishableKeyEnvVar}\n const secretKey = process.env.${secretKeyEnvVar}\n\n if (!publishableKey || !secretKey) {\n throw new Error(\n 'Server client requires ${publishableKeyEnvVar} and ${secretKeyEnvVar}.',\n )\n }\n\n return createServerClient({ publishableKey, secretKey })\n}\n\nexport function getServerClient(): ServerClient {\n cachedClient ??= createConfiguredClient()\n return cachedClient\n}\n\n/**\n * Lazy Proxy: the underlying client is created only on first property access,\n * so importing this file has no side effects until you actually call it.\n */\nexport const serverClient = new Proxy({} as ServerClient, {\n get(_target, prop, receiver) {\n const target = getServerClient()\n const value = Reflect.get(target as object, prop, receiver)\n return typeof value === 'function' ? value.bind(target) : value\n },\n})\n`\n}\n\n// ── Env file content ─────────────────────────────────────────────────\n\nexport function getEnvContent(\n publishableKey: string,\n secretKey: string,\n publishableKeyEnvVar: string,\n secretKeyEnvVar: string | null,\n): string {\n let content = `\\n# 01.software\\n${publishableKeyEnvVar}=${publishableKey}\\n`\n if (secretKeyEnvVar) {\n content += `${secretKeyEnvVar}=${secretKey}\\n`\n }\n return content\n}\n\n// ── MCP config (JSON) ────────────────────────────────────────────────\n\nexport type McpJsonClient = 'generic' | 'windsurf'\n\nexport function getMcpServerEntry(client: McpJsonClient = 'generic') {\n if (client === 'windsurf') {\n return {\n serverUrl: MCP_RESOURCE_AUDIENCE,\n }\n }\n\n return {\n type: 'http' as const,\n url: MCP_RESOURCE_AUDIENCE,\n }\n}\n\nexport function getMcpConfigTemplate(client: McpJsonClient = 'generic'): string {\n return (\n JSON.stringify(\n { mcpServers: { '01software': getMcpServerEntry(client) } },\n null,\n 2,\n ) + '\\n'\n )\n}\n\n// ── MCP config (TOML — Codex CLI) ────────────────────────────────────\n\n/** Codex CLI `[mcp_servers.01software]` block. Idempotent marker: the header\n * line. Intended to be appended to `~/.codex/config.toml`. */\nexport function getCodexMcpTomlSection(): string {\n return `\n[mcp_servers.01software]\nurl = \"${MCP_RESOURCE_AUDIENCE}\"\n`\n}\n\nexport const CODEX_MCP_SECTION_MARKER = '[mcp_servers.01software]'\n"],"mappings":";;;AAAO,IAAM,wBAAwB;;;ACK9B,SAAS,kBAAkB,KAAiB,sBAAsC;AACvF,MAAI,QAAQ,UAAU;AACpB,WAAO;AAAA;AAAA;AAAA,gCAGqB,oBAAoB;AAAA;AAAA;AAAA,EAGlD;AAEA,MAAI,QAAQ,aAAa;AACvB,WAAO;AAAA;AAAA;AAAA,gCAGqB,oBAAoB;AAAA;AAAA;AAAA,EAGlD;AAEA,MAAI,QAAQ,WAAW;AACrB,WAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOT;AAGA,SAAO;AAAA;AAAA;AAAA,oCAG2B,oBAAoB;AAAA;AAAA;AAGxD;AAIO,SAAS,qBACd,KACA,sBACQ;AACR,MAAI,QAAQ,WAAW;AACrB,WAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOT;AAEA,QAAM,2BACJ,QAAQ,eACJ,mBAAmB,oBAAoB,KACvC,eAAe,oBAAoB;AAEzC,SAAO;AAAA;AAAA;AAAA,oBAGW,wBAAwB;AAAA;AAAA;AAG5C;AAIO,SAAS,yBAAyB,KAAyB;AAChE,QAAM,qBAAqB,QAAQ,WAAW,qBAAqB;AAEnE,SAAO,GAAG,kBAAkB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAW9B;AAIO,SAAS,kBACd,KACA,sBACA,iBACQ;AACR,MAAI,QAAQ,QAAQ;AAClB,WAAO;AAAA;AAAA;AAAA;AAAA,8CAImC,oBAAoB;AAAA;AAAA;AAAA;AAAA;AAAA,EAKhE;AAEA,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,uCAkB8B,oBAAoB;AAAA,kCACzB,eAAe;AAAA;AAAA;AAAA;AAAA,gCAIjB,oBAAoB,QAAQ,eAAe;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAwB3E;AAIO,SAAS,cACd,gBACA,WACA,sBACA,iBACQ;AACR,MAAI,UAAU;AAAA;AAAA,EAAoB,oBAAoB,IAAI,cAAc;AAAA;AACxE,MAAI,iBAAiB;AACnB,eAAW,GAAG,eAAe,IAAI,SAAS;AAAA;AAAA,EAC5C;AACA,SAAO;AACT;AAMO,SAAS,kBAAkB,SAAwB,WAAW;AACnE,MAAI,WAAW,YAAY;AACzB,WAAO;AAAA,MACL,WAAW;AAAA,IACb;AAAA,EACF;AAEA,SAAO;AAAA,IACL,MAAM;AAAA,IACN,KAAK;AAAA,EACP;AACF;AAEO,SAAS,qBAAqB,SAAwB,WAAmB;AAC9E,SACE,KAAK;AAAA,IACH,EAAE,YAAY,EAAE,cAAc,kBAAkB,MAAM,EAAE,EAAE;AAAA,IAC1D;AAAA,IACA;AAAA,EACF,IAAI;AAER;AAMO,SAAS,yBAAiC;AAC/C,SAAO;AAAA;AAAA,SAEA,qBAAqB;AAAA;AAE9B;AAEO,IAAM,2BAA2B;","names":[]}
@@ -56,7 +56,7 @@ Steps:
56
56
 
57
57
  Common setups:
58
58
  - Blog only: hide \`ecommerce\`, \`customers\`, \`videos\` collections
59
- - Store: hide \`posts\`, \`documents\`, \`galleries\`, \`canvas\` collections
59
+ - Store: hide \`articles\`, \`documents\`, \`galleries\`, \`canvas\` collections
60
60
  - Minimal: hide all except the collections you actively use
61
61
 
62
62
  Ask me: "Show current field config" or "Hide ecommerce fields"
@@ -128,7 +128,7 @@ CLI:
128
128
  - \`01 schema list\` \u2014 all available collections
129
129
  - \`01 schema show <collection>\` \u2014 field names, types, required status
130
130
 
131
- Common collections: products, orders, customers, posts, documents, images
131
+ Common collections: products, orders, customers, articles, documents, images
132
132
  Use \`get-tenant-context\` to see which collections are active for this tenant.
133
133
  `
134
134
  }
@@ -160,4 +160,4 @@ export {
160
160
  getSkillFiles,
161
161
  fetchTenantContext
162
162
  };
163
- //# sourceMappingURL=chunk-SRLZ5OIV.js.map
163
+ //# sourceMappingURL=chunk-T3A5SLEJ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/ai-docs.ts"],"sourcesContent":["export interface TenantContext {\n tenantName: string\n features?: string[]\n collections?: string[]\n}\n\ninterface TenantContextApiResponse {\n tenant?: { name?: string }\n features?: string[]\n collections?: { active?: string[]; inactive?: string[] }\n}\n\nfunction normalizeActiveCollections(\n collections: TenantContextApiResponse['collections'],\n): string[] {\n if (Array.isArray(collections?.active)) return collections.active\n return []\n}\n\n// ── CLAUDE.md ────────────────────────────────────────────────────────\n\nexport function generateClaudeMd(ctx: TenantContext): string {\n const featuresSection =\n ctx.features && ctx.features.length > 0\n ? ctx.features.map((f) => `- ${f}`).join('\\n')\n : '- See console'\n\n const collectionsSection =\n ctx.collections && ctx.collections.length > 0\n ? ctx.collections.join(', ')\n : 'Run `01 schema list`'\n\n return `# 01.software SDK — ${ctx.tenantName}\n\n## Connection\n- Publishable Key: \\`NEXT_PUBLIC_SOFTWARE_PUBLISHABLE_KEY\\` (env)\n- Secret Key: \\`SOFTWARE_SECRET_KEY\\` (env)\n- MCP: \\`.mcp.json\\`\n\n## Active Features\n${featuresSection}\n\n## Active Collections\n${collectionsSection}\n\n## MCP Quick Reference\n| Tool | Use |\n|------|-----|\n| \\`query-collection\\` | List/filter documents |\n| \\`create-collection\\` | Create documents |\n| \\`update-field-config\\` | Hide unused fields |\n| \\`get-tenant-context\\` | Show active features & collections |\n\n## CLI\n- \\`01 query <collection>\\` — query data\n- \\`01 schema show <collection>\\` — inspect fields\n- \\`01 schema list\\` — list all collections\n\n## Initial Setup\nRun \\`/01software-field-config\\` in Claude Code to configure field visibility for your use case.\nUse \\`get-collection-schema\\` or \\`01 schema show <collection>\\` for live field introspection instead of relying on this document as a schema snapshot.\n`\n}\n\n// ── Skill files ──────────────────────────────────────────────────────\n\nexport function getSkillFiles(): Array<{ dirName: string; content: string }> {\n return [\n {\n dirName: '01software-field-config',\n content: `---\nname: 01software-field-config\ndescription: Configure field visibility for this tenant — hide unused collections and fields via MCP\ndisable-model-invocation: true\n---\n\nSteps:\n1. Use \\`list-configurable-fields\\` to see current visibility settings\n2. Identify fields/collections not needed for your use case\n3. Use \\`update-field-config\\` to hide them\n\nCommon setups:\n- Blog only: hide \\`ecommerce\\`, \\`customers\\`, \\`videos\\` collections\n- Store: hide \\`articles\\`, \\`documents\\`, \\`galleries\\`, \\`canvas\\` collections\n- Minimal: hide all except the collections you actively use\n\nAsk me: \"Show current field config\" or \"Hide ecommerce fields\"\n`,\n },\n {\n dirName: '01software-query',\n content: `---\nname: 01software-query\ndescription: Query 01.software collections via MCP or CLI with filter, sort, and pagination examples\n---\n\nQuery collections using the MCP \\`query-collection\\` tool or CLI.\n\nMCP examples:\n- List products: \\`query-collection\\` with collection=\"products\", limit=10\n- Filter by status: add where={\"status\":{\"equals\":\"published\"}}\n- Sort by date: sort=\"-createdAt\"\n- Paginate: page=2, limit=20\n\nCLI examples:\n- \\`01 query products --limit 10\\`\n- \\`01 query orders --where '{\"status\":{\"equals\":\"paid\"}}'\\`\n- \\`01 schema show products\\` — inspect available fields\n\nSDK (server):\n\\`\\`\\`typescript\nconst { docs } = await serverClient.collection('products').find({\n where: { status: { equals: 'published' } },\n sort: '-createdAt',\n limit: 10,\n})\n\\`\\`\\`\n`,\n },\n {\n dirName: '01software-order-flow',\n content: `---\nname: 01software-order-flow\ndescription: Order lifecycle reference — create, pay, fulfill, and return flows for 01.software\n---\n\nComplete order flow from creation to fulfillment.\n\nStates: pending → paid → preparing → shipped → delivered → confirmed\n\n1. Create order: \\`create-order\\` with orderNumber, customerSnapshot, orderProducts, totalAmount\n2. Mark paid: \\`update-order\\` with status=\"paid\" (after payment gateway confirms)\n3. Fulfill: \\`create-fulfillment\\` with items and carrier/trackingNumber\n4. Returns: \\`create-return\\` or \\`return-with-refund\\` (atomic)\n\nFree orders: omit paymentId, totalAmount=0 → auto-transitions to paid\n\nCLI: \\`01 order create --help\\` for full options\n`,\n },\n {\n dirName: '01software-schema',\n content: `---\nname: 01software-schema\ndescription: Inspect 01.software collection schemas and available fields via MCP or CLI\n---\n\nInspect collection schemas to understand available fields.\n\nMCP: use \\`get-collection-schema\\` with collection\n\nCLI:\n- \\`01 schema list\\` — all available collections\n- \\`01 schema show <collection>\\` — field names, types, required status\n\nCommon collections: products, orders, customers, articles, documents, images\nUse \\`get-tenant-context\\` to see which collections are active for this tenant.\n`,\n },\n ]\n}\n\n// ── Tenant context fetch ─────────────────────────────────────────────\n\nexport async function fetchTenantContext(\n publishableKey: string,\n secretKey: string,\n): Promise<TenantContext | null> {\n try {\n const apiUrl = process.env.SOFTWARE_API_URL || 'https://api.01.software'\n // secretKey is now an opaque sk01_/pat01_ bearer token — send it directly.\n const res = await fetch(`${apiUrl}/api/tenants/context`, {\n headers: {\n 'X-Publishable-Key': publishableKey,\n Authorization: `Bearer ${secretKey}`,\n },\n })\n if (!res.ok) return null\n const data = (await res.json()) as TenantContextApiResponse\n return {\n tenantName: data.tenant?.name || '',\n features: data.features || [],\n collections: normalizeActiveCollections(data.collections),\n }\n } catch {\n return null\n }\n}\n"],"mappings":";;;AAYA,SAAS,2BACP,aACU;AACV,MAAI,MAAM,QAAQ,aAAa,MAAM,EAAG,QAAO,YAAY;AAC3D,SAAO,CAAC;AACV;AAIO,SAAS,iBAAiB,KAA4B;AAC3D,QAAM,kBACJ,IAAI,YAAY,IAAI,SAAS,SAAS,IAClC,IAAI,SAAS,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,EAAE,KAAK,IAAI,IAC3C;AAEN,QAAM,qBACJ,IAAI,eAAe,IAAI,YAAY,SAAS,IACxC,IAAI,YAAY,KAAK,IAAI,IACzB;AAEN,SAAO,4BAAuB,IAAI,UAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQ5C,eAAe;AAAA;AAAA;AAAA,EAGf,kBAAkB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAmBpB;AAIO,SAAS,gBAA6D;AAC3E,SAAO;AAAA,IACL;AAAA,MACE,SAAS;AAAA,MACT,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAkBX;AAAA,IACA;AAAA,MACE,SAAS;AAAA,MACT,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IA2BX;AAAA,IACA;AAAA,MACE,SAAS;AAAA,MACT,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAkBX;AAAA,IACA;AAAA,MACE,SAAS;AAAA,MACT,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAgBX;AAAA,EACF;AACF;AAIA,eAAsB,mBACpB,gBACA,WAC+B;AAC/B,MAAI;AACF,UAAM,SAAS,QAAQ,IAAI,oBAAoB;AAE/C,UAAM,MAAM,MAAM,MAAM,GAAG,MAAM,wBAAwB;AAAA,MACvD,SAAS;AAAA,QACP,qBAAqB;AAAA,QACrB,eAAe,UAAU,SAAS;AAAA,MACpC;AAAA,IACF,CAAC;AACD,QAAI,CAAC,IAAI,GAAI,QAAO;AACpB,UAAM,OAAQ,MAAM,IAAI,KAAK;AAC7B,WAAO;AAAA,MACL,YAAY,KAAK,QAAQ,QAAQ;AAAA,MACjC,UAAU,KAAK,YAAY,CAAC;AAAA,MAC5B,aAAa,2BAA2B,KAAK,WAAW;AAAA,IAC1D;AAAA,EACF,QAAQ;AACN,WAAO;AAAA,EACT;AACF;","names":[]}
package/dist/file-ops.js CHANGED
@@ -1,12 +1,10 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
- extractTomlApiKey,
4
3
  readEnvValue,
5
4
  replaceTomlMcpSection,
6
5
  setEnvValue
7
- } from "./chunk-VOEXMD2S.js";
6
+ } from "./chunk-JT3G6B66.js";
8
7
  export {
9
- extractTomlApiKey,
10
8
  readEnvValue,
11
9
  replaceTomlMcpSection,
12
10
  setEnvValue
package/dist/index.js CHANGED
@@ -3,15 +3,15 @@ import {
3
3
  fetchTenantContext,
4
4
  generateClaudeMd,
5
5
  getSkillFiles
6
- } from "./chunk-SRLZ5OIV.js";
6
+ } from "./chunk-T3A5SLEJ.js";
7
7
  import {
8
- extractTomlApiKey,
9
8
  readEnvValue,
10
9
  replaceTomlMcpSection,
11
10
  setEnvValue
12
- } from "./chunk-VOEXMD2S.js";
11
+ } from "./chunk-JT3G6B66.js";
13
12
  import {
14
13
  CODEX_MCP_SECTION_MARKER,
14
+ getAnalyticsTemplate,
15
15
  getClientTemplate,
16
16
  getCodexMcpTomlSection,
17
17
  getEnvContent,
@@ -19,7 +19,7 @@ import {
19
19
  getMcpServerEntry,
20
20
  getQueryProviderTemplate,
21
21
  getServerTemplate
22
- } from "./chunk-OEAQV63E.js";
22
+ } from "./chunk-S3KHPWCE.js";
23
23
 
24
24
  // src/index.ts
25
25
  import pc3 from "picocolors";
@@ -240,7 +240,7 @@ async function promptUser(hasSdk, detectedEnv, detectedPm) {
240
240
  {
241
241
  type: "select",
242
242
  name: "method",
243
- message: "API keys:",
243
+ message: "SDK credentials:",
244
244
  choices: [
245
245
  { title: "Browser login (recommended)", value: "browser" },
246
246
  { title: "Enter manually", value: "manual" },
@@ -456,7 +456,6 @@ ${loginUrl}`));
456
456
 
457
457
  // src/init.ts
458
458
  var SECRET_KEY_ENV_VAR = "SOFTWARE_SECRET_KEY";
459
- var API_KEY_PLACEHOLDER = "YOUR_API_KEY";
460
459
  async function init(cwd, info, answers) {
461
460
  const { packageManager, srcDir } = info;
462
461
  const env = answers.env;
@@ -484,6 +483,12 @@ async function init(cwd, info, answers) {
484
483
  getClientTemplate(env, publishableKeyEnvVar),
485
484
  plan.policy
486
485
  );
486
+ await writeFileWithPolicy(
487
+ cwd,
488
+ path2.join(libDir, "analytics.ts"),
489
+ getAnalyticsTemplate(env, publishableKeyEnvVar),
490
+ plan.policy
491
+ );
487
492
  }
488
493
  if (wantsReactQuery) {
489
494
  await writeFileWithPolicy(
@@ -542,9 +547,8 @@ async function init(cwd, info, answers) {
542
547
  }
543
548
  }
544
549
  if (answers.aiTools.length > 0) {
545
- const apiKey = secretKey || API_KEY_PLACEHOLDER;
546
550
  for (const tool of answers.aiTools) {
547
- await writeMcpConfig(tool, cwd, apiKey, plan.policy);
551
+ await writeMcpConfig(tool, cwd);
548
552
  }
549
553
  addToGitignore(cwd, answers.aiTools);
550
554
  if (answers.aiTools.includes("claude")) {
@@ -649,7 +653,7 @@ async function pickEnvFile(cwd, env) {
649
653
  const { file } = await prompts2({
650
654
  type: "select",
651
655
  name: "file",
652
- message: "Which env file should I write API keys to?",
656
+ message: "Which env file should I write SDK credentials to?",
653
657
  choices,
654
658
  initial
655
659
  });
@@ -743,7 +747,7 @@ async function writeEnv(cwd, envFile, publishableKey, secretKey, publishableKeyE
743
747
  console.log(
744
748
  pc2.green(" Updated"),
745
749
  envFile,
746
- fromBrowserAuth ? pc2.dim("(API keys)") : ""
750
+ fromBrowserAuth ? pc2.dim("(SDK credentials)") : ""
747
751
  );
748
752
  } else {
749
753
  console.log(pc2.dim(" Unchanged"), envFile);
@@ -776,7 +780,13 @@ function resolveMcpLocation(tool, cwd) {
776
780
  case "windsurf": {
777
781
  if (!home) return null;
778
782
  const p = path2.join(home, ".codeium", "windsurf", "mcp_config.json");
779
- return { kind: "json", absolutePath: p, displayPath: p, gitignoreEntry: null };
783
+ return {
784
+ kind: "json",
785
+ absolutePath: p,
786
+ jsonClient: "windsurf",
787
+ displayPath: p,
788
+ gitignoreEntry: null
789
+ };
780
790
  }
781
791
  case "codex": {
782
792
  if (!home) return null;
@@ -790,7 +800,7 @@ function resolveMcpLocation(tool, cwd) {
790
800
  }
791
801
  }
792
802
  }
793
- async function writeMcpConfig(tool, cwd, apiKey, policy) {
803
+ async function writeMcpConfig(tool, cwd) {
794
804
  const loc = resolveMcpLocation(tool, cwd);
795
805
  if (!loc) {
796
806
  console.log(pc2.yellow(` Skipped ${tool}`), pc2.dim("(HOME not set)"));
@@ -798,14 +808,14 @@ async function writeMcpConfig(tool, cwd, apiKey, policy) {
798
808
  }
799
809
  fs2.mkdirSync(path2.dirname(loc.absolutePath), { recursive: true });
800
810
  if (loc.kind === "json") {
801
- await writeJsonMcp(loc, apiKey, policy);
811
+ writeJsonMcp(loc);
802
812
  } else {
803
- await writeTomlMcp(loc, apiKey, policy);
813
+ writeTomlMcp(loc);
804
814
  }
805
815
  }
806
- async function writeJsonMcp(loc, apiKey, policy) {
816
+ function writeJsonMcp(loc) {
807
817
  if (!fs2.existsSync(loc.absolutePath)) {
808
- fs2.writeFileSync(loc.absolutePath, getMcpConfigTemplate(apiKey));
818
+ fs2.writeFileSync(loc.absolutePath, getMcpConfigTemplate(loc.jsonClient));
809
819
  console.log(pc2.green(" Created"), loc.displayPath);
810
820
  return;
811
821
  }
@@ -816,29 +826,18 @@ async function writeJsonMcp(loc, apiKey, policy) {
816
826
  console.log(pc2.yellow(" Skipped"), loc.displayPath, pc2.dim("(could not parse existing file)"));
817
827
  return;
818
828
  }
819
- const existingApiKey = existing.mcpServers?.["01software"]?.headers?.["x-api-key"];
820
- if (existingApiKey === apiKey) {
829
+ const nextEntry = getMcpServerEntry(loc.jsonClient);
830
+ if (existing.mcpServers?.["01software"] && JSON.stringify(existing.mcpServers["01software"]) === JSON.stringify(nextEntry)) {
821
831
  console.log(pc2.dim(" Unchanged"), loc.displayPath);
822
832
  return;
823
833
  }
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)"));
832
- return;
833
- }
834
- }
835
834
  existing.mcpServers = existing.mcpServers || {};
836
- existing.mcpServers["01software"] = getMcpServerEntry(apiKey);
835
+ existing.mcpServers["01software"] = nextEntry;
837
836
  fs2.writeFileSync(loc.absolutePath, JSON.stringify(existing, null, 2) + "\n");
838
837
  console.log(pc2.green(" Updated"), loc.displayPath);
839
838
  }
840
- async function writeTomlMcp(loc, apiKey, policy) {
841
- const section = getCodexMcpTomlSection(apiKey);
839
+ function writeTomlMcp(loc) {
840
+ const section = getCodexMcpTomlSection();
842
841
  if (!fs2.existsSync(loc.absolutePath)) {
843
842
  fs2.writeFileSync(loc.absolutePath, section.trimStart());
844
843
  console.log(pc2.green(" Created"), loc.displayPath);
@@ -851,34 +850,14 @@ async function writeTomlMcp(loc, apiKey, policy) {
851
850
  console.log(pc2.green(" Updated"), loc.displayPath);
852
851
  return;
853
852
  }
854
- const existingApiKey = extractTomlApiKey(existing);
855
- if (existingApiKey === apiKey) {
853
+ const replaced = replaceTomlMcpSection(existing, section);
854
+ if (replaced === existing) {
856
855
  console.log(pc2.dim(" Unchanged"), loc.displayPath);
857
856
  return;
858
857
  }
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
858
  fs2.writeFileSync(loc.absolutePath, replaced);
870
859
  console.log(pc2.green(" Updated"), loc.displayPath);
871
860
  }
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;
881
- }
882
861
  function addToGitignore(cwd, tools) {
883
862
  const entries = [];
884
863
  for (const tool of tools) {
@@ -890,7 +869,7 @@ function addToGitignore(cwd, tools) {
890
869
  const existing = fs2.existsSync(gitignorePath) ? fs2.readFileSync(gitignorePath, "utf-8") : "";
891
870
  const toAdd = entries.filter((e) => !existing.includes(e));
892
871
  if (toAdd.length === 0) return;
893
- const content = "\n# MCP configs (contain API key)\n" + toAdd.join("\n") + "\n";
872
+ const content = "\n# MCP configs\n" + toAdd.join("\n") + "\n";
894
873
  if (fs2.existsSync(gitignorePath)) {
895
874
  fs2.appendFileSync(gitignorePath, content);
896
875
  } else {
@@ -1054,23 +1033,35 @@ async function main() {
1054
1033
  console.log(pc3.cyan(" import { QueryProvider } from '@/lib/software/query-provider'"));
1055
1034
  console.log(pc3.cyan(" <QueryProvider>{children}</QueryProvider>"));
1056
1035
  console.log();
1036
+ console.log(pc3.dim(" Optional: start browser analytics with the generated helper:"));
1037
+ console.log();
1038
+ console.log(pc3.cyan(" import { analytics } from '@/lib/software/analytics'"));
1039
+ console.log(pc3.cyan(" analytics.track('signup')"));
1040
+ console.log();
1057
1041
  } else if (env === "react-vite" || env === "react-cra") {
1058
1042
  console.log(pc3.dim(" Wrap your app entry with QueryProvider:"));
1059
1043
  console.log();
1060
1044
  console.log(pc3.cyan(" import { QueryProvider } from './lib/software/query-provider'"));
1061
1045
  console.log(pc3.cyan(" <QueryProvider><App /></QueryProvider>"));
1062
1046
  console.log();
1047
+ console.log(pc3.dim(" Optional: start browser analytics with the generated helper:"));
1048
+ console.log();
1049
+ console.log(pc3.cyan(" import { analytics } from './lib/software/analytics'"));
1050
+ console.log(pc3.cyan(" analytics.track('signup')"));
1051
+ console.log();
1063
1052
  } else if (env === "vanilla") {
1064
1053
  console.log(pc3.dim(" Replace YOUR_PUBLISHABLE_KEY in lib/software/client.ts"));
1065
1054
  console.log();
1066
1055
  console.log(pc3.cyan(" import { client } from './lib/software/client'"));
1067
- console.log(pc3.cyan(" const posts = await client.from('posts').find()"));
1056
+ console.log(pc3.cyan(" const articles = await client.from('articles').find()"));
1057
+ console.log();
1058
+ console.log(pc3.dim(" Optional: wire the analytics helper in lib/software/analytics.ts"));
1068
1059
  console.log();
1069
1060
  } else if (env === "node") {
1070
1061
  console.log(pc3.dim(" Use the server client:"));
1071
1062
  console.log();
1072
1063
  console.log(pc3.cyan(" import { serverClient } from './lib/software/server'"));
1073
- console.log(pc3.cyan(" const posts = await serverClient.from('posts').find()"));
1064
+ console.log(pc3.cyan(" const articles = await serverClient.from('articles').find()"));
1074
1065
  console.log();
1075
1066
  } else if (env === "edge") {
1076
1067
  console.log(pc3.dim(" Pass your env bindings to createEdgeClient():"));
@@ -1082,15 +1073,11 @@ async function main() {
1082
1073
  const missingPublishableKey = env !== "vanilla" && !answers.publishableKey;
1083
1074
  const missingSecretKey = (env === "nextjs" || env === "node") && !answers.secretKey;
1084
1075
  if (missingPublishableKey || missingSecretKey) {
1085
- console.log(pc3.dim(" Update .env with your API keys"));
1076
+ console.log(pc3.dim(" Update .env with your SDK credentials"));
1086
1077
  console.log();
1087
1078
  }
1088
- if (answers.aiTools.length > 0 && (!answers.publishableKey || !answers.secretKey)) {
1089
- console.log(
1090
- pc3.dim(
1091
- " Update MCP config x-api-key with your sk01_... or pat01_... bearer token"
1092
- )
1093
- );
1079
+ if (answers.aiTools.length > 0) {
1080
+ console.log(pc3.dim(" MCP config uses OAuth discovery."));
1094
1081
  console.log();
1095
1082
  }
1096
1083
  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(\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"]}
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 console.log(pc.dim(' Optional: start browser analytics with the generated helper:'))\n console.log()\n console.log(pc.cyan(\" import { analytics } from '@/lib/software/analytics'\"))\n console.log(pc.cyan(\" analytics.track('signup')\"))\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 console.log(pc.dim(' Optional: start browser analytics with the generated helper:'))\n console.log()\n console.log(pc.cyan(\" import { analytics } from './lib/software/analytics'\"))\n console.log(pc.cyan(\" analytics.track('signup')\"))\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 articles = await client.from('articles').find()\"))\n console.log()\n console.log(pc.dim(' Optional: wire the analytics helper in lib/software/analytics.ts'))\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 articles = await serverClient.from('articles').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 SDK credentials'))\n console.log()\n }\n if (answers.aiTools.length > 0) {\n console.log(pc.dim(' MCP config uses OAuth discovery.'))\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: 'SDK credentials:',\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 getAnalyticsTemplate,\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 replaceTomlMcpSection,\n} from './file-ops'\n\ntype ResolvedProjectInfo = Omit<ProjectInfo, 'packageManager'> & {\n packageManager: PackageManager\n}\n\nconst SECRET_KEY_ENV_VAR = 'SOFTWARE_SECRET_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 await writeFileWithPolicy(\n cwd,\n path.join(libDir, 'analytics.ts'),\n getAnalyticsTemplate(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 for (const tool of answers.aiTools) {\n await writeMcpConfig(tool, cwd)\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 SDK credentials 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('(SDK credentials)') : '',\n )\n } else {\n console.log(pc.dim(' Unchanged'), envFile)\n }\n}\n\n// ── MCP targets registry ─────────────────────────────────────────────\n\ntype McpFormat = 'json' | 'toml'\ntype McpJsonClient = 'generic' | 'windsurf'\ninterface McpLocation {\n kind: McpFormat\n absolutePath: string\n jsonClient?: McpJsonClient\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 {\n kind: 'json',\n absolutePath: p,\n jsonClient: 'windsurf',\n displayPath: p,\n gitignoreEntry: null,\n }\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): 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 writeJsonMcp(loc)\n } else {\n writeTomlMcp(loc)\n }\n}\n\nfunction writeJsonMcp(loc: McpLocation): void {\n if (!fs.existsSync(loc.absolutePath)) {\n fs.writeFileSync(loc.absolutePath, getMcpConfigTemplate(loc.jsonClient))\n console.log(pc.green(' Created'), loc.displayPath)\n return\n }\n\n let existing: { mcpServers?: Record<string, unknown> }\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 nextEntry = getMcpServerEntry(loc.jsonClient)\n if (\n existing.mcpServers?.['01software'] &&\n JSON.stringify(existing.mcpServers['01software']) === JSON.stringify(nextEntry)\n ) {\n console.log(pc.dim(' Unchanged'), loc.displayPath)\n return\n }\n\n existing.mcpServers = existing.mcpServers || {}\n existing.mcpServers['01software'] = nextEntry\n fs.writeFileSync(loc.absolutePath, JSON.stringify(existing, null, 2) + '\\n')\n console.log(pc.green(' Updated'), loc.displayPath)\n}\n\nfunction writeTomlMcp(loc: McpLocation): void {\n const section = getCodexMcpTomlSection()\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 replaced = replaceTomlMcpSection(existing, section)\n if (replaced === existing) {\n console.log(pc.dim(' Unchanged'), loc.displayPath)\n return\n }\n\n fs.writeFileSync(loc.absolutePath, replaced)\n console.log(pc.green(' Updated'), loc.displayPath)\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\\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/dist/templates.js CHANGED
@@ -1,6 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  CODEX_MCP_SECTION_MARKER,
4
+ getAnalyticsTemplate,
4
5
  getClientTemplate,
5
6
  getCodexMcpTomlSection,
6
7
  getEnvContent,
@@ -8,9 +9,10 @@ import {
8
9
  getMcpServerEntry,
9
10
  getQueryProviderTemplate,
10
11
  getServerTemplate
11
- } from "./chunk-OEAQV63E.js";
12
+ } from "./chunk-S3KHPWCE.js";
12
13
  export {
13
14
  CODEX_MCP_SECTION_MARKER,
15
+ getAnalyticsTemplate,
14
16
  getClientTemplate,
15
17
  getCodexMcpTomlSection,
16
18
  getEnvContent,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@01.software/init",
3
- "version": "0.6.1",
3
+ "version": "0.7.0",
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": {
@@ -14,7 +14,8 @@
14
14
  },
15
15
  "dependencies": {
16
16
  "picocolors": "^1.1.1",
17
- "prompts": "^2.4.2"
17
+ "prompts": "^2.4.2",
18
+ "@01.software/auth-contracts": "0.1.0"
18
19
  },
19
20
  "devDependencies": {
20
21
  "@types/node": "^22.19.3",
@@ -1,120 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- // src/templates.ts
4
- function getClientTemplate(env, publishableKeyEnvVar) {
5
- if (env === "nextjs") {
6
- return `import { createClient } from '@01.software/sdk'
7
-
8
- export const client = createClient({
9
- publishableKey: process.env.${publishableKeyEnvVar}!,
10
- })
11
- `;
12
- }
13
- if (env === "react-cra") {
14
- return `import { createClient } from '@01.software/sdk'
15
-
16
- export const client = createClient({
17
- publishableKey: process.env.${publishableKeyEnvVar}!,
18
- })
19
- `;
20
- }
21
- if (env === "vanilla") {
22
- return `import { createClient } from '@01.software/sdk'
23
-
24
- // Replace 'YOUR_PUBLISHABLE_KEY' with your actual publishable key from the 01.software console
25
- export const client = createClient({
26
- publishableKey: 'YOUR_PUBLISHABLE_KEY',
27
- })
28
- `;
29
- }
30
- return `import { createClient } from '@01.software/sdk'
31
-
32
- export const client = createClient({
33
- publishableKey: import.meta.env.${publishableKeyEnvVar},
34
- })
35
- `;
36
- }
37
- function getQueryProviderTemplate(env) {
38
- const useClientDirective = env === "nextjs" ? "'use client'\n\n" : "";
39
- return `${useClientDirective}import { QueryClientProvider } from '@tanstack/react-query'
40
- import { client } from './client'
41
-
42
- export function QueryProvider({ children }: { children: React.ReactNode }) {
43
- return (
44
- <QueryClientProvider client={client.queryClient}>
45
- {children}
46
- </QueryClientProvider>
47
- )
48
- }
49
- `;
50
- }
51
- function getServerTemplate(env, publishableKeyEnvVar, secretKeyEnvVar) {
52
- if (env === "edge") {
53
- return `import { createServerClient } from '@01.software/sdk'
54
-
55
- // Edge runtime: pass your env bindings here
56
- // e.g. Cloudflare Workers: use env.SOFTWARE_PUBLISHABLE_KEY from the handler context
57
- // e.g. Vercel Edge: use process.env.${publishableKeyEnvVar}
58
- export function createEdgeClient(publishableKey: string, secretKey: string) {
59
- return createServerClient({ publishableKey, secretKey })
60
- }
61
- `;
62
- }
63
- return `import { createServerClient } from '@01.software/sdk'
64
-
65
- export const serverClient = createServerClient({
66
- publishableKey: process.env.${publishableKeyEnvVar}!,
67
- secretKey: process.env.${secretKeyEnvVar}!,
68
- })
69
- `;
70
- }
71
- function getEnvContent(publishableKey, secretKey, publishableKeyEnvVar, secretKeyEnvVar) {
72
- let content = `
73
- # 01.software
74
- ${publishableKeyEnvVar}=${publishableKey}
75
- `;
76
- if (secretKeyEnvVar) {
77
- content += `${secretKeyEnvVar}=${secretKey}
78
- `;
79
- }
80
- return content;
81
- }
82
- function getMcpServerEntry(apiKey) {
83
- return {
84
- type: "http",
85
- url: "https://mcp.01.software/mcp",
86
- headers: { "x-api-key": apiKey }
87
- };
88
- }
89
- function getMcpConfigTemplate(apiKey) {
90
- return JSON.stringify(
91
- { mcpServers: { "01software": getMcpServerEntry(apiKey) } },
92
- null,
93
- 2
94
- ) + "\n";
95
- }
96
- function escapeTomlString(s) {
97
- return s.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
98
- }
99
- function getCodexMcpTomlSection(apiKey) {
100
- return `
101
- [mcp_servers.01software]
102
- url = "https://mcp.01.software/mcp"
103
-
104
- [mcp_servers.01software.headers]
105
- x-api-key = "${escapeTomlString(apiKey)}"
106
- `;
107
- }
108
- var CODEX_MCP_SECTION_MARKER = "[mcp_servers.01software]";
109
-
110
- export {
111
- getClientTemplate,
112
- getQueryProviderTemplate,
113
- getServerTemplate,
114
- getEnvContent,
115
- getMcpServerEntry,
116
- getMcpConfigTemplate,
117
- getCodexMcpTomlSection,
118
- CODEX_MCP_SECTION_MARKER
119
- };
120
- //# sourceMappingURL=chunk-OEAQV63E.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/templates.ts"],"sourcesContent":["import type { ProjectEnv } from './detect'\n\n// ── Client template (browser) ────────────────────────────────────────\n\nexport function getClientTemplate(env: ProjectEnv, publishableKeyEnvVar: string): string {\n if (env === 'nextjs') {\n return `import { createClient } from '@01.software/sdk'\n\nexport const client = createClient({\n publishableKey: process.env.${publishableKeyEnvVar}!,\n})\n`\n }\n\n if (env === 'react-cra') {\n return `import { createClient } from '@01.software/sdk'\n\nexport const client = createClient({\n publishableKey: process.env.${publishableKeyEnvVar}!,\n})\n`\n }\n\n if (env === 'vanilla') {\n return `import { createClient } from '@01.software/sdk'\n\n// Replace 'YOUR_PUBLISHABLE_KEY' with your actual publishable key from the 01.software console\nexport const client = createClient({\n publishableKey: 'YOUR_PUBLISHABLE_KEY',\n})\n`\n }\n\n // react-vite (import.meta.env)\n return `import { createClient } from '@01.software/sdk'\n\nexport const client = createClient({\n publishableKey: import.meta.env.${publishableKeyEnvVar},\n})\n`\n}\n\n// ── Query Provider template ──────────────────────────────────────────\n\nexport function getQueryProviderTemplate(env: ProjectEnv): string {\n const useClientDirective = env === 'nextjs' ? \"'use client'\\n\\n\" : ''\n\n return `${useClientDirective}import { QueryClientProvider } from '@tanstack/react-query'\nimport { client } from './client'\n\nexport function QueryProvider({ children }: { children: React.ReactNode }) {\n return (\n <QueryClientProvider client={client.queryClient}>\n {children}\n </QueryClientProvider>\n )\n}\n`\n}\n\n// ── Server template ──────────────────────────────────────────────────\n\nexport function getServerTemplate(\n env: ProjectEnv,\n publishableKeyEnvVar: string,\n secretKeyEnvVar: string,\n): string {\n if (env === 'edge') {\n return `import { createServerClient } from '@01.software/sdk'\n\n// Edge runtime: pass your env bindings here\n// e.g. Cloudflare Workers: use env.SOFTWARE_PUBLISHABLE_KEY from the handler context\n// e.g. Vercel Edge: use process.env.${publishableKeyEnvVar}\nexport function createEdgeClient(publishableKey: string, secretKey: string) {\n return createServerClient({ publishableKey, secretKey })\n}\n`\n }\n\n return `import { createServerClient } from '@01.software/sdk'\n\nexport const serverClient = createServerClient({\n publishableKey: process.env.${publishableKeyEnvVar}!,\n secretKey: process.env.${secretKeyEnvVar}!,\n})\n`\n}\n\n// ── Env file content ─────────────────────────────────────────────────\n\nexport function getEnvContent(\n publishableKey: string,\n secretKey: string,\n publishableKeyEnvVar: string,\n secretKeyEnvVar: string | null,\n): string {\n let content = `\\n# 01.software\\n${publishableKeyEnvVar}=${publishableKey}\\n`\n if (secretKeyEnvVar) {\n content += `${secretKeyEnvVar}=${secretKey}\\n`\n }\n return content\n}\n\n// ── MCP config (JSON) ────────────────────────────────────────────────\n\nexport function getMcpServerEntry(apiKey: string) {\n return {\n type: 'http' as const,\n url: 'https://mcp.01.software/mcp',\n headers: { 'x-api-key': apiKey },\n }\n}\n\nexport function getMcpConfigTemplate(apiKey: string): string {\n return (\n JSON.stringify(\n { mcpServers: { '01software': getMcpServerEntry(apiKey) } },\n null,\n 2,\n ) + '\\n'\n )\n}\n\n// ── MCP config (TOML — Codex CLI) ────────────────────────────────────\n\nfunction escapeTomlString(s: string): string {\n return s.replace(/\\\\/g, '\\\\\\\\').replace(/\"/g, '\\\\\"')\n}\n\n/** Codex CLI `[mcp_servers.01software]` block. Idempotent marker: the header\n * line. Intended to be appended to `~/.codex/config.toml`. */\nexport function getCodexMcpTomlSection(apiKey: string): string {\n return `\n[mcp_servers.01software]\nurl = \"https://mcp.01.software/mcp\"\n\n[mcp_servers.01software.headers]\nx-api-key = \"${escapeTomlString(apiKey)}\"\n`\n}\n\nexport const CODEX_MCP_SECTION_MARKER = '[mcp_servers.01software]'\n"],"mappings":";;;AAIO,SAAS,kBAAkB,KAAiB,sBAAsC;AACvF,MAAI,QAAQ,UAAU;AACpB,WAAO;AAAA;AAAA;AAAA,gCAGqB,oBAAoB;AAAA;AAAA;AAAA,EAGlD;AAEA,MAAI,QAAQ,aAAa;AACvB,WAAO;AAAA;AAAA;AAAA,gCAGqB,oBAAoB;AAAA;AAAA;AAAA,EAGlD;AAEA,MAAI,QAAQ,WAAW;AACrB,WAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOT;AAGA,SAAO;AAAA;AAAA;AAAA,oCAG2B,oBAAoB;AAAA;AAAA;AAGxD;AAIO,SAAS,yBAAyB,KAAyB;AAChE,QAAM,qBAAqB,QAAQ,WAAW,qBAAqB;AAEnE,SAAO,GAAG,kBAAkB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAW9B;AAIO,SAAS,kBACd,KACA,sBACA,iBACQ;AACR,MAAI,QAAQ,QAAQ;AAClB,WAAO;AAAA;AAAA;AAAA;AAAA,8CAImC,oBAAoB;AAAA;AAAA;AAAA;AAAA;AAAA,EAKhE;AAEA,SAAO;AAAA;AAAA;AAAA,gCAGuB,oBAAoB;AAAA,2BACzB,eAAe;AAAA;AAAA;AAG1C;AAIO,SAAS,cACd,gBACA,WACA,sBACA,iBACQ;AACR,MAAI,UAAU;AAAA;AAAA,EAAoB,oBAAoB,IAAI,cAAc;AAAA;AACxE,MAAI,iBAAiB;AACnB,eAAW,GAAG,eAAe,IAAI,SAAS;AAAA;AAAA,EAC5C;AACA,SAAO;AACT;AAIO,SAAS,kBAAkB,QAAgB;AAChD,SAAO;AAAA,IACL,MAAM;AAAA,IACN,KAAK;AAAA,IACL,SAAS,EAAE,aAAa,OAAO;AAAA,EACjC;AACF;AAEO,SAAS,qBAAqB,QAAwB;AAC3D,SACE,KAAK;AAAA,IACH,EAAE,YAAY,EAAE,cAAc,kBAAkB,MAAM,EAAE,EAAE;AAAA,IAC1D;AAAA,IACA;AAAA,EACF,IAAI;AAER;AAIA,SAAS,iBAAiB,GAAmB;AAC3C,SAAO,EAAE,QAAQ,OAAO,MAAM,EAAE,QAAQ,MAAM,KAAK;AACrD;AAIO,SAAS,uBAAuB,QAAwB;AAC7D,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA,eAKM,iBAAiB,MAAM,CAAC;AAAA;AAEvC;AAEO,IAAM,2BAA2B;","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/ai-docs.ts"],"sourcesContent":["export interface TenantContext {\n tenantName: string\n features?: string[]\n collections?: string[]\n}\n\ninterface TenantContextApiResponse {\n tenant?: { name?: string }\n features?: string[]\n collections?: { active?: string[]; inactive?: string[] }\n}\n\nfunction normalizeActiveCollections(\n collections: TenantContextApiResponse['collections'],\n): string[] {\n if (Array.isArray(collections?.active)) return collections.active\n return []\n}\n\n// ── CLAUDE.md ────────────────────────────────────────────────────────\n\nexport function generateClaudeMd(ctx: TenantContext): string {\n const featuresSection =\n ctx.features && ctx.features.length > 0\n ? ctx.features.map((f) => `- ${f}`).join('\\n')\n : '- See console'\n\n const collectionsSection =\n ctx.collections && ctx.collections.length > 0\n ? ctx.collections.join(', ')\n : 'Run `01 schema list`'\n\n return `# 01.software SDK — ${ctx.tenantName}\n\n## Connection\n- Publishable Key: \\`NEXT_PUBLIC_SOFTWARE_PUBLISHABLE_KEY\\` (env)\n- Secret Key: \\`SOFTWARE_SECRET_KEY\\` (env)\n- MCP: \\`.mcp.json\\`\n\n## Active Features\n${featuresSection}\n\n## Active Collections\n${collectionsSection}\n\n## MCP Quick Reference\n| Tool | Use |\n|------|-----|\n| \\`query-collection\\` | List/filter documents |\n| \\`create-collection\\` | Create documents |\n| \\`update-field-config\\` | Hide unused fields |\n| \\`get-tenant-context\\` | Show active features & collections |\n\n## CLI\n- \\`01 query <collection>\\` — query data\n- \\`01 schema show <collection>\\` — inspect fields\n- \\`01 schema list\\` — list all collections\n\n## Initial Setup\nRun \\`/01software-field-config\\` in Claude Code to configure field visibility for your use case.\nUse \\`get-collection-schema\\` or \\`01 schema show <collection>\\` for live field introspection instead of relying on this document as a schema snapshot.\n`\n}\n\n// ── Skill files ──────────────────────────────────────────────────────\n\nexport function getSkillFiles(): Array<{ dirName: string; content: string }> {\n return [\n {\n dirName: '01software-field-config',\n content: `---\nname: 01software-field-config\ndescription: Configure field visibility for this tenant — hide unused collections and fields via MCP\ndisable-model-invocation: true\n---\n\nSteps:\n1. Use \\`list-configurable-fields\\` to see current visibility settings\n2. Identify fields/collections not needed for your use case\n3. Use \\`update-field-config\\` to hide them\n\nCommon setups:\n- Blog only: hide \\`ecommerce\\`, \\`customers\\`, \\`videos\\` collections\n- Store: hide \\`posts\\`, \\`documents\\`, \\`galleries\\`, \\`canvas\\` collections\n- Minimal: hide all except the collections you actively use\n\nAsk me: \"Show current field config\" or \"Hide ecommerce fields\"\n`,\n },\n {\n dirName: '01software-query',\n content: `---\nname: 01software-query\ndescription: Query 01.software collections via MCP or CLI with filter, sort, and pagination examples\n---\n\nQuery collections using the MCP \\`query-collection\\` tool or CLI.\n\nMCP examples:\n- List products: \\`query-collection\\` with collection=\"products\", limit=10\n- Filter by status: add where={\"status\":{\"equals\":\"published\"}}\n- Sort by date: sort=\"-createdAt\"\n- Paginate: page=2, limit=20\n\nCLI examples:\n- \\`01 query products --limit 10\\`\n- \\`01 query orders --where '{\"status\":{\"equals\":\"paid\"}}'\\`\n- \\`01 schema show products\\` — inspect available fields\n\nSDK (server):\n\\`\\`\\`typescript\nconst { docs } = await serverClient.collection('products').find({\n where: { status: { equals: 'published' } },\n sort: '-createdAt',\n limit: 10,\n})\n\\`\\`\\`\n`,\n },\n {\n dirName: '01software-order-flow',\n content: `---\nname: 01software-order-flow\ndescription: Order lifecycle reference — create, pay, fulfill, and return flows for 01.software\n---\n\nComplete order flow from creation to fulfillment.\n\nStates: pending → paid → preparing → shipped → delivered → confirmed\n\n1. Create order: \\`create-order\\` with orderNumber, customerSnapshot, orderProducts, totalAmount\n2. Mark paid: \\`update-order\\` with status=\"paid\" (after payment gateway confirms)\n3. Fulfill: \\`create-fulfillment\\` with items and carrier/trackingNumber\n4. Returns: \\`create-return\\` or \\`return-with-refund\\` (atomic)\n\nFree orders: omit paymentId, totalAmount=0 → auto-transitions to paid\n\nCLI: \\`01 order create --help\\` for full options\n`,\n },\n {\n dirName: '01software-schema',\n content: `---\nname: 01software-schema\ndescription: Inspect 01.software collection schemas and available fields via MCP or CLI\n---\n\nInspect collection schemas to understand available fields.\n\nMCP: use \\`get-collection-schema\\` with collection\n\nCLI:\n- \\`01 schema list\\` — all available collections\n- \\`01 schema show <collection>\\` — field names, types, required status\n\nCommon collections: products, orders, customers, posts, documents, images\nUse \\`get-tenant-context\\` to see which collections are active for this tenant.\n`,\n },\n ]\n}\n\n// ── Tenant context fetch ─────────────────────────────────────────────\n\nexport async function fetchTenantContext(\n publishableKey: string,\n secretKey: string,\n): Promise<TenantContext | null> {\n try {\n const apiUrl = process.env.SOFTWARE_API_URL || 'https://api.01.software'\n // secretKey is now an opaque sk01_/pat01_ bearer token — send it directly.\n const res = await fetch(`${apiUrl}/api/tenants/context`, {\n headers: {\n 'X-Publishable-Key': publishableKey,\n Authorization: `Bearer ${secretKey}`,\n },\n })\n if (!res.ok) return null\n const data = (await res.json()) as TenantContextApiResponse\n return {\n tenantName: data.tenant?.name || '',\n features: data.features || [],\n collections: normalizeActiveCollections(data.collections),\n }\n } catch {\n return null\n }\n}\n"],"mappings":";;;AAYA,SAAS,2BACP,aACU;AACV,MAAI,MAAM,QAAQ,aAAa,MAAM,EAAG,QAAO,YAAY;AAC3D,SAAO,CAAC;AACV;AAIO,SAAS,iBAAiB,KAA4B;AAC3D,QAAM,kBACJ,IAAI,YAAY,IAAI,SAAS,SAAS,IAClC,IAAI,SAAS,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,EAAE,KAAK,IAAI,IAC3C;AAEN,QAAM,qBACJ,IAAI,eAAe,IAAI,YAAY,SAAS,IACxC,IAAI,YAAY,KAAK,IAAI,IACzB;AAEN,SAAO,4BAAuB,IAAI,UAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQ5C,eAAe;AAAA;AAAA;AAAA,EAGf,kBAAkB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAmBpB;AAIO,SAAS,gBAA6D;AAC3E,SAAO;AAAA,IACL;AAAA,MACE,SAAS;AAAA,MACT,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAkBX;AAAA,IACA;AAAA,MACE,SAAS;AAAA,MACT,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IA2BX;AAAA,IACA;AAAA,MACE,SAAS;AAAA,MACT,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAkBX;AAAA,IACA;AAAA,MACE,SAAS;AAAA,MACT,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAgBX;AAAA,EACF;AACF;AAIA,eAAsB,mBACpB,gBACA,WAC+B;AAC/B,MAAI;AACF,UAAM,SAAS,QAAQ,IAAI,oBAAoB;AAE/C,UAAM,MAAM,MAAM,MAAM,GAAG,MAAM,wBAAwB;AAAA,MACvD,SAAS;AAAA,QACP,qBAAqB;AAAA,QACrB,eAAe,UAAU,SAAS;AAAA,MACpC;AAAA,IACF,CAAC;AACD,QAAI,CAAC,IAAI,GAAI,QAAO;AACpB,UAAM,OAAQ,MAAM,IAAI,KAAK;AAC7B,WAAO;AAAA,MACL,YAAY,KAAK,QAAQ,QAAQ;AAAA,MACjC,UAAU,KAAK,YAAY,CAAC;AAAA,MAC5B,aAAa,2BAA2B,KAAK,WAAW;AAAA,IAC1D;AAAA,EACF,QAAQ;AACN,WAAO;AAAA,EACT;AACF;","names":[]}
@@ -1 +0,0 @@
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":[]}