🚀 Socket Launch Week Day 5:Introducing Repository Access Permissions and Custom Roles.Learn more
Sign In

@01.software/init

Package Overview
Dependencies
Maintainers
1
Versions
22
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@01.software/init - npm Package Compare versions

Comparing version
0.6.1
to
0.7.0
+56
dist/chunk-JT3G6B66.js
#!/usr/bin/env node
// src/file-ops.ts
var envLineRegexCache = /* @__PURE__ */ new Map();
function envLineRegex(name) {
let re = envLineRegexCache.get(name);
if (!re) {
const escaped = name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
re = new RegExp(`^${escaped}=(.*)$`, "m");
envLineRegexCache.set(name, re);
}
return re;
}
function readEnvValue(content, name) {
const m = content.match(envLineRegex(name));
return m ? m[1] : null;
}
function setEnvValue(content, name, value) {
const re = envLineRegex(name);
if (re.test(content)) return content.replace(re, `${name}=${value}`);
const sep = content.length === 0 || content.endsWith("\n") ? "" : "\n";
return content + sep + `${name}=${value}
`;
}
var OWNED_MCP_TOML_SECTION = "mcp_servers.01software";
function tomlSectionName(line) {
const match = line.trim().match(/^\[([^\]]+)\]$/);
return match ? match[1] : null;
}
function isOwnedMcpTomlSection(sectionName) {
return sectionName === OWNED_MCP_TOML_SECTION || sectionName.startsWith(`${OWNED_MCP_TOML_SECTION}.`);
}
function replaceTomlMcpSection(content, newSection) {
const lines = content.split("\n");
const kept = [];
let inOurSection = false;
for (const line of lines) {
const sectionName = tomlSectionName(line);
if (sectionName) {
inOurSection = isOwnedMcpTomlSection(sectionName);
if (inOurSection) continue;
}
if (!inOurSection) kept.push(line);
}
let result = kept.join("\n").replace(/\n+$/, "");
if (result.length > 0) result += "\n";
result += newSection.startsWith("\n") ? newSection : "\n" + newSection;
return result;
}
export {
readEnvValue,
setEnvValue,
replaceTomlMcpSection
};
//# sourceMappingURL=chunk-JT3G6B66.js.map
{"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":[]}
#!/usr/bin/env node
// ../auth-contracts/dist/index.js
var MCP_RESOURCE_AUDIENCE = "https://mcp.01.software/mcp";
// src/templates.ts
function getClientTemplate(env, publishableKeyEnvVar) {
if (env === "nextjs") {
return `import { createClient } from '@01.software/sdk'
export const client = createClient({
publishableKey: process.env.${publishableKeyEnvVar}!,
})
`;
}
if (env === "react-cra") {
return `import { createClient } from '@01.software/sdk'
export const client = createClient({
publishableKey: process.env.${publishableKeyEnvVar}!,
})
`;
}
if (env === "vanilla") {
return `import { createClient } from '@01.software/sdk'
// Replace 'YOUR_PUBLISHABLE_KEY' with your actual publishable key from the 01.software console
export const client = createClient({
publishableKey: 'YOUR_PUBLISHABLE_KEY',
})
`;
}
return `import { createClient } from '@01.software/sdk'
export const client = createClient({
publishableKey: import.meta.env.${publishableKeyEnvVar},
})
`;
}
function getAnalyticsTemplate(env, publishableKeyEnvVar) {
if (env === "vanilla") {
return `import { createAnalytics } from '@01.software/sdk/analytics'
// Replace 'YOUR_PUBLISHABLE_KEY' with your actual publishable key from the 01.software console
export const analytics = createAnalytics({
publishableKey: 'YOUR_PUBLISHABLE_KEY',
})
`;
}
const publishableKeyExpression = env === "react-vite" ? `import.meta.env.${publishableKeyEnvVar}` : `process.env.${publishableKeyEnvVar}!`;
return `import { createAnalytics } from '@01.software/sdk/analytics'
export const analytics = createAnalytics({
publishableKey: ${publishableKeyExpression},
})
`;
}
function getQueryProviderTemplate(env) {
const useClientDirective = env === "nextjs" ? "'use client'\n\n" : "";
return `${useClientDirective}import { QueryClientProvider } from '@tanstack/react-query'
import { client } from './client'
export function QueryProvider({ children }: { children: React.ReactNode }) {
return (
<QueryClientProvider client={client.queryClient}>
{children}
</QueryClientProvider>
)
}
`;
}
function getServerTemplate(env, publishableKeyEnvVar, secretKeyEnvVar) {
if (env === "edge") {
return `import { createServerClient } from '@01.software/sdk'
// Edge runtime: pass your env bindings here
// e.g. Cloudflare Workers: use env.SOFTWARE_PUBLISHABLE_KEY from the handler context
// e.g. Vercel Edge: use process.env.${publishableKeyEnvVar}
export function createEdgeClient(publishableKey: string, secretKey: string) {
return createServerClient({ publishableKey, secretKey })
}
`;
}
return `import { createServerClient } from '@01.software/sdk'
/**
* Runtime guard: this module contains secret keys and must never be
* imported from client-side (browser) code. If the bundler accidentally
* includes it in a client bundle, this throws at module-evaluation time.
*/
if (typeof window !== 'undefined') {
throw new Error(
'lib/software/server.ts must not be imported in client-side code \u2014 it contains secret keys.',
)
}
type ServerClient = ReturnType<typeof createServerClient>
let cachedClient: ServerClient | null = null
function createConfiguredClient(): ServerClient {
const publishableKey = process.env.${publishableKeyEnvVar}
const secretKey = process.env.${secretKeyEnvVar}
if (!publishableKey || !secretKey) {
throw new Error(
'Server client requires ${publishableKeyEnvVar} and ${secretKeyEnvVar}.',
)
}
return createServerClient({ publishableKey, secretKey })
}
export function getServerClient(): ServerClient {
cachedClient ??= createConfiguredClient()
return cachedClient
}
/**
* Lazy Proxy: the underlying client is created only on first property access,
* so importing this file has no side effects until you actually call it.
*/
export const serverClient = new Proxy({} as ServerClient, {
get(_target, prop, receiver) {
const target = getServerClient()
const value = Reflect.get(target as object, prop, receiver)
return typeof value === 'function' ? value.bind(target) : value
},
})
`;
}
function getEnvContent(publishableKey, secretKey, publishableKeyEnvVar, secretKeyEnvVar) {
let content = `
# 01.software
${publishableKeyEnvVar}=${publishableKey}
`;
if (secretKeyEnvVar) {
content += `${secretKeyEnvVar}=${secretKey}
`;
}
return content;
}
function getMcpServerEntry(client = "generic") {
if (client === "windsurf") {
return {
serverUrl: MCP_RESOURCE_AUDIENCE
};
}
return {
type: "http",
url: MCP_RESOURCE_AUDIENCE
};
}
function getMcpConfigTemplate(client = "generic") {
return JSON.stringify(
{ mcpServers: { "01software": getMcpServerEntry(client) } },
null,
2
) + "\n";
}
function getCodexMcpTomlSection() {
return `
[mcp_servers.01software]
url = "${MCP_RESOURCE_AUDIENCE}"
`;
}
var CODEX_MCP_SECTION_MARKER = "[mcp_servers.01software]";
export {
getClientTemplate,
getAnalyticsTemplate,
getQueryProviderTemplate,
getServerTemplate,
getEnvContent,
getMcpServerEntry,
getMcpConfigTemplate,
getCodexMcpTomlSection,
CODEX_MCP_SECTION_MARKER
};
//# sourceMappingURL=chunk-S3KHPWCE.js.map
{"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":[]}
#!/usr/bin/env node
// src/ai-docs.ts
function normalizeActiveCollections(collections) {
if (Array.isArray(collections?.active)) return collections.active;
return [];
}
function generateClaudeMd(ctx) {
const featuresSection = ctx.features && ctx.features.length > 0 ? ctx.features.map((f) => `- ${f}`).join("\n") : "- See console";
const collectionsSection = ctx.collections && ctx.collections.length > 0 ? ctx.collections.join(", ") : "Run `01 schema list`";
return `# 01.software SDK \u2014 ${ctx.tenantName}
## Connection
- Publishable Key: \`NEXT_PUBLIC_SOFTWARE_PUBLISHABLE_KEY\` (env)
- Secret Key: \`SOFTWARE_SECRET_KEY\` (env)
- MCP: \`.mcp.json\`
## Active Features
${featuresSection}
## Active Collections
${collectionsSection}
## MCP Quick Reference
| Tool | Use |
|------|-----|
| \`query-collection\` | List/filter documents |
| \`create-collection\` | Create documents |
| \`update-field-config\` | Hide unused fields |
| \`get-tenant-context\` | Show active features & collections |
## CLI
- \`01 query <collection>\` \u2014 query data
- \`01 schema show <collection>\` \u2014 inspect fields
- \`01 schema list\` \u2014 list all collections
## Initial Setup
Run \`/01software-field-config\` in Claude Code to configure field visibility for your use case.
Use \`get-collection-schema\` or \`01 schema show <collection>\` for live field introspection instead of relying on this document as a schema snapshot.
`;
}
function getSkillFiles() {
return [
{
dirName: "01software-field-config",
content: `---
name: 01software-field-config
description: Configure field visibility for this tenant \u2014 hide unused collections and fields via MCP
disable-model-invocation: true
---
Steps:
1. Use \`list-configurable-fields\` to see current visibility settings
2. Identify fields/collections not needed for your use case
3. Use \`update-field-config\` to hide them
Common setups:
- Blog only: hide \`ecommerce\`, \`customers\`, \`videos\` collections
- Store: hide \`articles\`, \`documents\`, \`galleries\`, \`canvas\` collections
- Minimal: hide all except the collections you actively use
Ask me: "Show current field config" or "Hide ecommerce fields"
`
},
{
dirName: "01software-query",
content: `---
name: 01software-query
description: Query 01.software collections via MCP or CLI with filter, sort, and pagination examples
---
Query collections using the MCP \`query-collection\` tool or CLI.
MCP examples:
- List products: \`query-collection\` with collection="products", limit=10
- Filter by status: add where={"status":{"equals":"published"}}
- Sort by date: sort="-createdAt"
- Paginate: page=2, limit=20
CLI examples:
- \`01 query products --limit 10\`
- \`01 query orders --where '{"status":{"equals":"paid"}}'\`
- \`01 schema show products\` \u2014 inspect available fields
SDK (server):
\`\`\`typescript
const { docs } = await serverClient.collection('products').find({
where: { status: { equals: 'published' } },
sort: '-createdAt',
limit: 10,
})
\`\`\`
`
},
{
dirName: "01software-order-flow",
content: `---
name: 01software-order-flow
description: Order lifecycle reference \u2014 create, pay, fulfill, and return flows for 01.software
---
Complete order flow from creation to fulfillment.
States: pending \u2192 paid \u2192 preparing \u2192 shipped \u2192 delivered \u2192 confirmed
1. Create order: \`create-order\` with orderNumber, customerSnapshot, orderProducts, totalAmount
2. Mark paid: \`update-order\` with status="paid" (after payment gateway confirms)
3. Fulfill: \`create-fulfillment\` with items and carrier/trackingNumber
4. Returns: \`create-return\` or \`return-with-refund\` (atomic)
Free orders: omit paymentId, totalAmount=0 \u2192 auto-transitions to paid
CLI: \`01 order create --help\` for full options
`
},
{
dirName: "01software-schema",
content: `---
name: 01software-schema
description: Inspect 01.software collection schemas and available fields via MCP or CLI
---
Inspect collection schemas to understand available fields.
MCP: use \`get-collection-schema\` with collection
CLI:
- \`01 schema list\` \u2014 all available collections
- \`01 schema show <collection>\` \u2014 field names, types, required status
Common collections: products, orders, customers, articles, documents, images
Use \`get-tenant-context\` to see which collections are active for this tenant.
`
}
];
}
async function fetchTenantContext(publishableKey, secretKey) {
try {
const apiUrl = process.env.SOFTWARE_API_URL || "https://api.01.software";
const res = await fetch(`${apiUrl}/api/tenants/context`, {
headers: {
"X-Publishable-Key": publishableKey,
Authorization: `Bearer ${secretKey}`
}
});
if (!res.ok) return null;
const data = await res.json();
return {
tenantName: data.tenant?.name || "",
features: data.features || [],
collections: normalizeActiveCollections(data.collections)
};
} catch {
return null;
}
}
export {
generateClaudeMd,
getSkillFiles,
fetchTenantContext
};
//# sourceMappingURL=chunk-T3A5SLEJ.js.map
{"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":[]}
+1
-1

@@ -6,3 +6,3 @@ #!/usr/bin/env node

getSkillFiles
} from "./chunk-SRLZ5OIV.js";
} from "./chunk-T3A5SLEJ.js";
export {

@@ -9,0 +9,0 @@ fetchTenantContext,

#!/usr/bin/env node
import {
extractTomlApiKey,
readEnvValue,
replaceTomlMcpSection,
setEnvValue
} from "./chunk-VOEXMD2S.js";
} from "./chunk-JT3G6B66.js";
export {
extractTomlApiKey,
readEnvValue,

@@ -11,0 +9,0 @@ replaceTomlMcpSection,

@@ -6,11 +6,11 @@ #!/usr/bin/env node

getSkillFiles
} from "./chunk-SRLZ5OIV.js";
} from "./chunk-T3A5SLEJ.js";
import {
extractTomlApiKey,
readEnvValue,
replaceTomlMcpSection,
setEnvValue
} from "./chunk-VOEXMD2S.js";
} from "./chunk-JT3G6B66.js";
import {
CODEX_MCP_SECTION_MARKER,
getAnalyticsTemplate,
getClientTemplate,

@@ -23,3 +23,3 @@ getCodexMcpTomlSection,

getServerTemplate
} from "./chunk-OEAQV63E.js";
} from "./chunk-S3KHPWCE.js";

@@ -245,3 +245,3 @@ // src/index.ts

name: "method",
message: "API keys:",
message: "SDK credentials:",
choices: [

@@ -462,3 +462,2 @@ { title: "Browser login (recommended)", value: "browser" },

var SECRET_KEY_ENV_VAR = "SOFTWARE_SECRET_KEY";
var API_KEY_PLACEHOLDER = "YOUR_API_KEY";
async function init(cwd, info, answers) {

@@ -491,2 +490,8 @@ const { packageManager, srcDir } = info;

);
await writeFileWithPolicy(
cwd,
path2.join(libDir, "analytics.ts"),
getAnalyticsTemplate(env, publishableKeyEnvVar),
plan.policy
);
}

@@ -550,5 +555,4 @@ if (wantsReactQuery) {

if (answers.aiTools.length > 0) {
const apiKey = secretKey || API_KEY_PLACEHOLDER;
for (const tool of answers.aiTools) {
await writeMcpConfig(tool, cwd, apiKey, plan.policy);
await writeMcpConfig(tool, cwd);
}

@@ -658,3 +662,3 @@ addToGitignore(cwd, answers.aiTools);

name: "file",
message: "Which env file should I write API keys to?",
message: "Which env file should I write SDK credentials to?",
choices,

@@ -753,3 +757,3 @@ initial

envFile,
fromBrowserAuth ? pc2.dim("(API keys)") : ""
fromBrowserAuth ? pc2.dim("(SDK credentials)") : ""
);

@@ -787,3 +791,9 @@ } else {

const p = path2.join(home, ".codeium", "windsurf", "mcp_config.json");
return { kind: "json", absolutePath: p, displayPath: p, gitignoreEntry: null };
return {
kind: "json",
absolutePath: p,
jsonClient: "windsurf",
displayPath: p,
gitignoreEntry: null
};
}

@@ -802,3 +812,3 @@ case "codex": {

}
async function writeMcpConfig(tool, cwd, apiKey, policy) {
async function writeMcpConfig(tool, cwd) {
const loc = resolveMcpLocation(tool, cwd);

@@ -811,10 +821,10 @@ if (!loc) {

if (loc.kind === "json") {
await writeJsonMcp(loc, apiKey, policy);
writeJsonMcp(loc);
} else {
await writeTomlMcp(loc, apiKey, policy);
writeTomlMcp(loc);
}
}
async function writeJsonMcp(loc, apiKey, policy) {
function writeJsonMcp(loc) {
if (!fs2.existsSync(loc.absolutePath)) {
fs2.writeFileSync(loc.absolutePath, getMcpConfigTemplate(apiKey));
fs2.writeFileSync(loc.absolutePath, getMcpConfigTemplate(loc.jsonClient));
console.log(pc2.green(" Created"), loc.displayPath);

@@ -830,25 +840,14 @@ return;

}
const existingApiKey = existing.mcpServers?.["01software"]?.headers?.["x-api-key"];
if (existingApiKey === apiKey) {
const nextEntry = getMcpServerEntry(loc.jsonClient);
if (existing.mcpServers?.["01software"] && JSON.stringify(existing.mcpServers["01software"]) === JSON.stringify(nextEntry)) {
console.log(pc2.dim(" Unchanged"), loc.displayPath);
return;
}
if (apiKey === API_KEY_PLACEHOLDER && existingApiKey && existingApiKey !== API_KEY_PLACEHOLDER) {
console.log(pc2.dim(" Kept existing API key in"), loc.displayPath);
return;
}
if (existingApiKey) {
const shouldUpdate = await confirmKeyUpdate(loc.displayPath, policy);
if (!shouldUpdate) {
console.log(pc2.yellow(" Skipped"), loc.displayPath, pc2.dim("(kept existing API key)"));
return;
}
}
existing.mcpServers = existing.mcpServers || {};
existing.mcpServers["01software"] = getMcpServerEntry(apiKey);
existing.mcpServers["01software"] = nextEntry;
fs2.writeFileSync(loc.absolutePath, JSON.stringify(existing, null, 2) + "\n");
console.log(pc2.green(" Updated"), loc.displayPath);
}
async function writeTomlMcp(loc, apiKey, policy) {
const section = getCodexMcpTomlSection(apiKey);
function writeTomlMcp(loc) {
const section = getCodexMcpTomlSection();
if (!fs2.existsSync(loc.absolutePath)) {

@@ -866,30 +865,10 @@ fs2.writeFileSync(loc.absolutePath, section.trimStart());

}
const existingApiKey = extractTomlApiKey(existing);
if (existingApiKey === apiKey) {
const replaced = replaceTomlMcpSection(existing, section);
if (replaced === existing) {
console.log(pc2.dim(" Unchanged"), loc.displayPath);
return;
}
if (apiKey === API_KEY_PLACEHOLDER && existingApiKey && existingApiKey !== API_KEY_PLACEHOLDER) {
console.log(pc2.dim(" Kept existing API key in"), loc.displayPath);
return;
}
const shouldUpdate = await confirmKeyUpdate(loc.displayPath, policy);
if (!shouldUpdate) {
console.log(pc2.yellow(" Skipped"), loc.displayPath, pc2.dim("(kept existing API key)"));
return;
}
const replaced = replaceTomlMcpSection(existing, section);
fs2.writeFileSync(loc.absolutePath, replaced);
console.log(pc2.green(" Updated"), loc.displayPath);
}
async function confirmKeyUpdate(displayPath, policy) {
if (policy === "overwrite") return true;
const { confirm } = await prompts2({
type: "confirm",
name: "confirm",
message: `${displayPath} has a different 01software API key. Update?`,
initial: true
});
return !!confirm;
}
function addToGitignore(cwd, tools) {

@@ -906,3 +885,3 @@ const entries = [];

if (toAdd.length === 0) return;
const content = "\n# MCP configs (contain API key)\n" + toAdd.join("\n") + "\n";
const content = "\n# MCP configs\n" + toAdd.join("\n") + "\n";
if (fs2.existsSync(gitignorePath)) {

@@ -1071,2 +1050,7 @@ fs2.appendFileSync(gitignorePath, content);

console.log();
console.log(pc3.dim(" Optional: start browser analytics with the generated helper:"));
console.log();
console.log(pc3.cyan(" import { analytics } from '@/lib/software/analytics'"));
console.log(pc3.cyan(" analytics.track('signup')"));
console.log();
} else if (env === "react-vite" || env === "react-cra") {

@@ -1078,2 +1062,7 @@ console.log(pc3.dim(" Wrap your app entry with QueryProvider:"));

console.log();
console.log(pc3.dim(" Optional: start browser analytics with the generated helper:"));
console.log();
console.log(pc3.cyan(" import { analytics } from './lib/software/analytics'"));
console.log(pc3.cyan(" analytics.track('signup')"));
console.log();
} else if (env === "vanilla") {

@@ -1083,4 +1072,6 @@ console.log(pc3.dim(" Replace YOUR_PUBLISHABLE_KEY in lib/software/client.ts"));

console.log(pc3.cyan(" import { client } from './lib/software/client'"));
console.log(pc3.cyan(" const posts = await client.from('posts').find()"));
console.log(pc3.cyan(" const articles = await client.from('articles').find()"));
console.log();
console.log(pc3.dim(" Optional: wire the analytics helper in lib/software/analytics.ts"));
console.log();
} else if (env === "node") {

@@ -1090,3 +1081,3 @@ console.log(pc3.dim(" Use the server client:"));

console.log(pc3.cyan(" import { serverClient } from './lib/software/server'"));
console.log(pc3.cyan(" const posts = await serverClient.from('posts').find()"));
console.log(pc3.cyan(" const articles = await serverClient.from('articles').find()"));
console.log();

@@ -1103,11 +1094,7 @@ } else if (env === "edge") {

if (missingPublishableKey || missingSecretKey) {
console.log(pc3.dim(" Update .env with your API keys"));
console.log(pc3.dim(" Update .env with your SDK credentials"));
console.log();
}
if (answers.aiTools.length > 0 && (!answers.publishableKey || !answers.secretKey)) {
console.log(
pc3.dim(
" Update MCP config x-api-key with your sk01_... or pat01_... bearer token"
)
);
if (answers.aiTools.length > 0) {
console.log(pc3.dim(" MCP config uses OAuth discovery."));
console.log();

@@ -1114,0 +1101,0 @@ }

#!/usr/bin/env node
import {
CODEX_MCP_SECTION_MARKER,
getAnalyticsTemplate,
getClientTemplate,

@@ -11,5 +12,6 @@ getCodexMcpTomlSection,

getServerTemplate
} from "./chunk-OEAQV63E.js";
} from "./chunk-S3KHPWCE.js";
export {
CODEX_MCP_SECTION_MARKER,
getAnalyticsTemplate,
getClientTemplate,

@@ -16,0 +18,0 @@ getCodexMcpTomlSection,

{
"name": "@01.software/init",
"version": "0.6.1",
"version": "0.7.0",
"description": "Initialize 01.software SDK in your project (Next.js, React, Vanilla JS, Node.js, Edge)",

@@ -17,3 +17,4 @@ "type": "module",

"picocolors": "^1.1.1",
"prompts": "^2.4.2"
"prompts": "^2.4.2",
"@01.software/auth-contracts": "0.1.0"
},

@@ -20,0 +21,0 @@ "devDependencies": {

#!/usr/bin/env node
// src/templates.ts
function getClientTemplate(env, publishableKeyEnvVar) {
if (env === "nextjs") {
return `import { createClient } from '@01.software/sdk'
export const client = createClient({
publishableKey: process.env.${publishableKeyEnvVar}!,
})
`;
}
if (env === "react-cra") {
return `import { createClient } from '@01.software/sdk'
export const client = createClient({
publishableKey: process.env.${publishableKeyEnvVar}!,
})
`;
}
if (env === "vanilla") {
return `import { createClient } from '@01.software/sdk'
// Replace 'YOUR_PUBLISHABLE_KEY' with your actual publishable key from the 01.software console
export const client = createClient({
publishableKey: 'YOUR_PUBLISHABLE_KEY',
})
`;
}
return `import { createClient } from '@01.software/sdk'
export const client = createClient({
publishableKey: import.meta.env.${publishableKeyEnvVar},
})
`;
}
function getQueryProviderTemplate(env) {
const useClientDirective = env === "nextjs" ? "'use client'\n\n" : "";
return `${useClientDirective}import { QueryClientProvider } from '@tanstack/react-query'
import { client } from './client'
export function QueryProvider({ children }: { children: React.ReactNode }) {
return (
<QueryClientProvider client={client.queryClient}>
{children}
</QueryClientProvider>
)
}
`;
}
function getServerTemplate(env, publishableKeyEnvVar, secretKeyEnvVar) {
if (env === "edge") {
return `import { createServerClient } from '@01.software/sdk'
// Edge runtime: pass your env bindings here
// e.g. Cloudflare Workers: use env.SOFTWARE_PUBLISHABLE_KEY from the handler context
// e.g. Vercel Edge: use process.env.${publishableKeyEnvVar}
export function createEdgeClient(publishableKey: string, secretKey: string) {
return createServerClient({ publishableKey, secretKey })
}
`;
}
return `import { createServerClient } from '@01.software/sdk'
export const serverClient = createServerClient({
publishableKey: process.env.${publishableKeyEnvVar}!,
secretKey: process.env.${secretKeyEnvVar}!,
})
`;
}
function getEnvContent(publishableKey, secretKey, publishableKeyEnvVar, secretKeyEnvVar) {
let content = `
# 01.software
${publishableKeyEnvVar}=${publishableKey}
`;
if (secretKeyEnvVar) {
content += `${secretKeyEnvVar}=${secretKey}
`;
}
return content;
}
function getMcpServerEntry(apiKey) {
return {
type: "http",
url: "https://mcp.01.software/mcp",
headers: { "x-api-key": apiKey }
};
}
function getMcpConfigTemplate(apiKey) {
return JSON.stringify(
{ mcpServers: { "01software": getMcpServerEntry(apiKey) } },
null,
2
) + "\n";
}
function escapeTomlString(s) {
return s.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
}
function getCodexMcpTomlSection(apiKey) {
return `
[mcp_servers.01software]
url = "https://mcp.01.software/mcp"
[mcp_servers.01software.headers]
x-api-key = "${escapeTomlString(apiKey)}"
`;
}
var CODEX_MCP_SECTION_MARKER = "[mcp_servers.01software]";
export {
getClientTemplate,
getQueryProviderTemplate,
getServerTemplate,
getEnvContent,
getMcpServerEntry,
getMcpConfigTemplate,
getCodexMcpTomlSection,
CODEX_MCP_SECTION_MARKER
};
//# sourceMappingURL=chunk-OEAQV63E.js.map
{"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":[]}
#!/usr/bin/env node
// src/ai-docs.ts
function normalizeActiveCollections(collections) {
if (Array.isArray(collections?.active)) return collections.active;
return [];
}
function generateClaudeMd(ctx) {
const featuresSection = ctx.features && ctx.features.length > 0 ? ctx.features.map((f) => `- ${f}`).join("\n") : "- See console";
const collectionsSection = ctx.collections && ctx.collections.length > 0 ? ctx.collections.join(", ") : "Run `01 schema list`";
return `# 01.software SDK \u2014 ${ctx.tenantName}
## Connection
- Publishable Key: \`NEXT_PUBLIC_SOFTWARE_PUBLISHABLE_KEY\` (env)
- Secret Key: \`SOFTWARE_SECRET_KEY\` (env)
- MCP: \`.mcp.json\`
## Active Features
${featuresSection}
## Active Collections
${collectionsSection}
## MCP Quick Reference
| Tool | Use |
|------|-----|
| \`query-collection\` | List/filter documents |
| \`create-collection\` | Create documents |
| \`update-field-config\` | Hide unused fields |
| \`get-tenant-context\` | Show active features & collections |
## CLI
- \`01 query <collection>\` \u2014 query data
- \`01 schema show <collection>\` \u2014 inspect fields
- \`01 schema list\` \u2014 list all collections
## Initial Setup
Run \`/01software-field-config\` in Claude Code to configure field visibility for your use case.
Use \`get-collection-schema\` or \`01 schema show <collection>\` for live field introspection instead of relying on this document as a schema snapshot.
`;
}
function getSkillFiles() {
return [
{
dirName: "01software-field-config",
content: `---
name: 01software-field-config
description: Configure field visibility for this tenant \u2014 hide unused collections and fields via MCP
disable-model-invocation: true
---
Steps:
1. Use \`list-configurable-fields\` to see current visibility settings
2. Identify fields/collections not needed for your use case
3. Use \`update-field-config\` to hide them
Common setups:
- Blog only: hide \`ecommerce\`, \`customers\`, \`videos\` collections
- Store: hide \`posts\`, \`documents\`, \`galleries\`, \`canvas\` collections
- Minimal: hide all except the collections you actively use
Ask me: "Show current field config" or "Hide ecommerce fields"
`
},
{
dirName: "01software-query",
content: `---
name: 01software-query
description: Query 01.software collections via MCP or CLI with filter, sort, and pagination examples
---
Query collections using the MCP \`query-collection\` tool or CLI.
MCP examples:
- List products: \`query-collection\` with collection="products", limit=10
- Filter by status: add where={"status":{"equals":"published"}}
- Sort by date: sort="-createdAt"
- Paginate: page=2, limit=20
CLI examples:
- \`01 query products --limit 10\`
- \`01 query orders --where '{"status":{"equals":"paid"}}'\`
- \`01 schema show products\` \u2014 inspect available fields
SDK (server):
\`\`\`typescript
const { docs } = await serverClient.collection('products').find({
where: { status: { equals: 'published' } },
sort: '-createdAt',
limit: 10,
})
\`\`\`
`
},
{
dirName: "01software-order-flow",
content: `---
name: 01software-order-flow
description: Order lifecycle reference \u2014 create, pay, fulfill, and return flows for 01.software
---
Complete order flow from creation to fulfillment.
States: pending \u2192 paid \u2192 preparing \u2192 shipped \u2192 delivered \u2192 confirmed
1. Create order: \`create-order\` with orderNumber, customerSnapshot, orderProducts, totalAmount
2. Mark paid: \`update-order\` with status="paid" (after payment gateway confirms)
3. Fulfill: \`create-fulfillment\` with items and carrier/trackingNumber
4. Returns: \`create-return\` or \`return-with-refund\` (atomic)
Free orders: omit paymentId, totalAmount=0 \u2192 auto-transitions to paid
CLI: \`01 order create --help\` for full options
`
},
{
dirName: "01software-schema",
content: `---
name: 01software-schema
description: Inspect 01.software collection schemas and available fields via MCP or CLI
---
Inspect collection schemas to understand available fields.
MCP: use \`get-collection-schema\` with collection
CLI:
- \`01 schema list\` \u2014 all available collections
- \`01 schema show <collection>\` \u2014 field names, types, required status
Common collections: products, orders, customers, posts, documents, images
Use \`get-tenant-context\` to see which collections are active for this tenant.
`
}
];
}
async function fetchTenantContext(publishableKey, secretKey) {
try {
const apiUrl = process.env.SOFTWARE_API_URL || "https://api.01.software";
const res = await fetch(`${apiUrl}/api/tenants/context`, {
headers: {
"X-Publishable-Key": publishableKey,
Authorization: `Bearer ${secretKey}`
}
});
if (!res.ok) return null;
const data = await res.json();
return {
tenantName: data.tenant?.name || "",
features: data.features || [],
collections: normalizeActiveCollections(data.collections)
};
} catch {
return null;
}
}
export {
generateClaudeMd,
getSkillFiles,
fetchTenantContext
};
//# sourceMappingURL=chunk-SRLZ5OIV.js.map
{"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":[]}
#!/usr/bin/env node
// src/file-ops.ts
var envLineRegexCache = /* @__PURE__ */ new Map();
function envLineRegex(name) {
let re = envLineRegexCache.get(name);
if (!re) {
const escaped = name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
re = new RegExp(`^${escaped}=(.*)$`, "m");
envLineRegexCache.set(name, re);
}
return re;
}
function readEnvValue(content, name) {
const m = content.match(envLineRegex(name));
return m ? m[1] : null;
}
function setEnvValue(content, name, value) {
const re = envLineRegex(name);
if (re.test(content)) return content.replace(re, `${name}=${value}`);
const sep = content.length === 0 || content.endsWith("\n") ? "" : "\n";
return content + sep + `${name}=${value}
`;
}
var TOML_SECTION_PREFIX = "[mcp_servers.01software";
function extractTomlApiKey(content) {
const headerIdx = content.indexOf(`${TOML_SECTION_PREFIX}.headers]`);
if (headerIdx < 0) return null;
const slice = content.slice(headerIdx);
const m = slice.match(/^x-api-key\s*=\s*"((?:[^"\\]|\\.)*)"/m);
if (!m) return null;
return m[1].replace(/\\"/g, '"').replace(/\\\\/g, "\\");
}
function replaceTomlMcpSection(content, newSection) {
const lines = content.split("\n");
const kept = [];
let inOurSection = false;
for (const line of lines) {
const trimmed = line.trim();
if (trimmed.startsWith(TOML_SECTION_PREFIX)) {
inOurSection = true;
continue;
}
if (inOurSection && /^\[[^\[]/.test(trimmed)) {
inOurSection = false;
}
if (!inOurSection) kept.push(line);
}
let result = kept.join("\n").replace(/\n+$/, "");
if (result.length > 0) result += "\n";
result += newSection.startsWith("\n") ? newSection : "\n" + newSection;
return result;
}
export {
readEnvValue,
setEnvValue,
extractTomlApiKey,
replaceTomlMcpSection
};
//# sourceMappingURL=chunk-VOEXMD2S.js.map
{"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":[]}

Sorry, the diff of this file is too big to display