@apicircle/cli 1.0.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.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/commands/mock.ts","../src/commands/mcp.ts","../src/util/loadWorkspace.ts","../src/commands/import.ts","../src/commands/run.ts","../src/util/secrets.ts"],"sourcesContent":["import { Command } from 'commander';\nimport { registerMockCommand } from './commands/mock';\nimport { registerMcpCommand } from './commands/mcp';\nimport { registerImportCommand } from './commands/import';\nimport { registerRunCommand } from './commands/run';\n\n// =============================================================================\n// `apicircle` — root CLI binary. Sub-commands live under ./commands.\n//\n// Designed for two audiences:\n// • Power users who want a no-Electron way to run mocks, drive the MCP\n// stdio server, or execute saved plans against a workspace folder.\n// • CI / automation that imports specs into a workspace.json checked into\n// git, or runs an execution plan as a review gate.\n// =============================================================================\n\nexport function buildProgram(): Command {\n const program = new Command();\n program\n .name('apicircle')\n .description('Command-line companion to APICircle Studio.')\n .version('1.0.0');\n\n registerMockCommand(program);\n registerMcpCommand(program);\n registerImportCommand(program);\n registerRunCommand(program);\n\n return program;\n}\n\nexport async function runCli(argv: readonly string[] = process.argv): Promise<void> {\n await buildProgram().parseAsync(argv);\n}\n\n// Run when this file is executed as a script. tsup wraps the CJS output\n// with a node shebang so this branch is what handles `apicircle <args>`.\n// We deliberately do *not* check require.main — works in both CJS and ESM.\n// `.ts` is also accepted so the E2E suite can run the source under tsx\n// without going through the dist bundle.\nconst entry = process.argv[1] ?? '';\nif (entry.endsWith('apicircle') || entry.endsWith('index.cjs') || entry.endsWith('index.ts')) {\n void runCli();\n}\n","import { promises as fs } from 'node:fs';\nimport * as path from 'node:path';\nimport type { Command } from 'commander';\nimport kleur from 'kleur';\nimport {\n parseSourceToEndpoints,\n startMockServer,\n type MockServerHandle,\n} from '@apicircle/mock-server-core';\nimport { generateId, type MockServer } from '@apicircle/shared';\n\n// =============================================================================\n// `apicircle mock <spec>` — boot a mock server from an OpenAPI / Postman /\n// Insomnia file. The path's extension chooses the parser; user can override\n// with `--type {openapi,postman,insomnia}`.\n// =============================================================================\n\ninterface MockOptions {\n port?: string;\n host?: string;\n type?: 'openapi' | 'postman' | 'insomnia' | 'auto';\n format?: 'json' | 'yaml' | 'auto';\n cors?: boolean;\n}\n\nexport function registerMockCommand(program: Command): void {\n program\n .command('mock')\n .description('Run a mock server from an OpenAPI / Postman / Insomnia file')\n .argument('<spec>', 'Path to the spec file')\n .option('-p, --port <number>', 'TCP port to bind (defaults to a free port)')\n .option('-h, --host <host>', 'Hostname to bind', '127.0.0.1')\n .option('-t, --type <type>', 'Source type: openapi | postman | insomnia | auto', 'auto')\n .option('-f, --format <format>', 'OpenAPI format: json | yaml | auto', 'auto')\n .option('--cors', 'Enable permissive CORS', true)\n .action(async (spec: string, opts: MockOptions) => {\n const absolute = path.resolve(spec);\n const raw = await fs.readFile(absolute, 'utf-8');\n const type = inferType(absolute, opts.type ?? 'auto');\n const format = type === 'openapi' ? inferFormat(absolute, opts.format ?? 'auto') : 'json';\n\n const source = makeSource(type, format, raw);\n const parsed = await parseSourceToEndpoints(source);\n const mock: MockServer = {\n id: generateId(),\n name: path.basename(absolute),\n source,\n endpoints: parsed.endpoints,\n defaultPort: opts.port ? Number(opts.port) : null,\n cors: { enabled: opts.cors !== false, origins: ['*'] },\n createdAt: new Date().toISOString(),\n updatedAt: new Date().toISOString(),\n };\n\n const handle = await startMockServer(mock, {\n port: opts.port ? Number(opts.port) : undefined,\n host: opts.host,\n });\n process.stdout.write(\n `${kleur.green('Mock server')} listening on ${kleur.cyan(`http://${opts.host}:${handle.port}`)} ` +\n `with ${parsed.endpoints.length} endpoints (type=${type}). Press Ctrl-C to stop.\\n`,\n );\n if (parsed.warnings.length) {\n for (const w of parsed.warnings) {\n process.stderr.write(`${kleur.yellow('warn')}: ${w}\\n`);\n }\n }\n installShutdown(handle);\n });\n}\n\nexport function inferType(\n filePath: string,\n hint: NonNullable<MockOptions['type']>,\n): 'openapi' | 'postman' | 'insomnia' {\n if (hint && hint !== 'auto') return hint;\n const lower = filePath.toLowerCase();\n if (lower.includes('postman')) return 'postman';\n if (lower.includes('insomnia')) return 'insomnia';\n return 'openapi';\n}\n\nexport function inferFormat(\n filePath: string,\n hint: NonNullable<MockOptions['format']>,\n): 'json' | 'yaml' {\n if (hint && hint !== 'auto') return hint;\n const lower = filePath.toLowerCase();\n return lower.endsWith('.yaml') || lower.endsWith('.yml') ? 'yaml' : 'json';\n}\n\nexport function makeSource(\n type: 'openapi' | 'postman' | 'insomnia',\n format: 'json' | 'yaml',\n raw: string,\n): MockServer['source'] {\n switch (type) {\n case 'openapi':\n return { kind: 'openapi', spec: raw, format };\n case 'postman':\n return { kind: 'postman', collection: raw };\n case 'insomnia':\n return { kind: 'insomnia', export: raw };\n }\n}\n\nfunction installShutdown(handle: MockServerHandle): void {\n let closing = false;\n const shutdown = async () => {\n if (closing) return;\n closing = true;\n await handle.close();\n process.exit(0);\n };\n process.on('SIGINT', () => void shutdown());\n process.on('SIGTERM', () => void shutdown());\n}\n","import * as path from 'node:path';\nimport type { Command } from 'commander';\nimport kleur from 'kleur';\nimport {\n createMcpServer,\n FileBackedWorkspaceProvider,\n InProcessMockController,\n} from '@apicircle/mcp-server';\nimport { ensureWorkspace } from '../util/loadWorkspace';\n\n// =============================================================================\n// `apicircle mcp` — boot the MCP stdio server against a workspace directory.\n// Mirrors `@apicircle/mcp-server`'s `bin/mcp-server.ts` but with friendlier\n// CLI ergonomics (default workspace = cwd, friendly error messages, etc).\n// =============================================================================\n\ninterface McpOptions {\n workspace?: string;\n}\n\nexport function registerMcpCommand(program: Command): void {\n program\n .command('mcp')\n .description('Run the APICircle MCP server (stdio transport)')\n .option('-w, --workspace <dir>', 'Workspace directory (defaults to current directory)')\n .action(async (opts: McpOptions) => {\n const dir = path.resolve(opts.workspace ?? process.cwd());\n // Touch the workspace so subsequent reads don't fail. Errors here\n // surface to stderr and exit non-zero — the AI client wouldn't be\n // able to use a half-initialised workspace anyway.\n try {\n await ensureWorkspace(dir);\n } catch (err) {\n process.stderr.write(\n `${kleur.red('failed to initialise workspace')} at ${dir}: ${\n err instanceof Error ? err.message : String(err)\n }\\n`,\n );\n process.exit(1);\n }\n\n const workspace = new FileBackedWorkspaceProvider(dir);\n const mock = new InProcessMockController();\n const host = createMcpServer({ workspace, mock });\n process.stderr.write(`${kleur.green('apicircle-mcp')} ready · workspace=${dir}\\n`);\n await host.connect();\n });\n}\n","import * as path from 'node:path';\nimport { promises as fs } from 'node:fs';\nimport { loadFromFile, saveToFile } from '@apicircle/core/workspace/file-backed';\nimport type { WorkspaceState } from '@apicircle/core';\nimport { FONT_SIZE_PERCENT_DEFAULT, generateId } from '@apicircle/shared';\n\n// =============================================================================\n// loadWorkspace — small wrapper around `@apicircle/core`'s file-backed\n// helpers that auto-creates an empty workspace on first run so users don't\n// have to seed a workspace.synced.json by hand before invoking commands.\n// =============================================================================\n\nexport async function ensureWorkspace(dir: string): Promise<WorkspaceState> {\n const resolved = path.resolve(dir);\n await fs.mkdir(resolved, { recursive: true });\n const existing = await loadFromFile(resolved, { allowMissing: true });\n if (existing) return existing;\n\n const now = new Date().toISOString();\n const workspaceId = generateId();\n const fresh: WorkspaceState = {\n synced: {\n schemaVersion: 1,\n workspaceId,\n collections: {\n tree: { id: generateId(), type: 'root', children: [] },\n requests: {},\n folders: {},\n },\n environments: { items: {}, activeName: null, priorityOrder: [] },\n linkedWorkspaces: {},\n linkedOverrides: { requests: {}, environmentVars: {} },\n releases: { self: null, perLink: {} },\n globalAssets: { schemas: {}, graphql: {} },\n mockServers: {},\n meta: { createdAt: now, updatedAt: now, appVersion: '1.0.0' },\n },\n local: {\n schemaVersion: 1,\n workspaceId,\n executionPlans: {},\n history: { requestRuns: [], planRuns: [] },\n secretIndex: { entries: {} },\n sessions: { github: { workspace: null, links: {} } },\n connectedRepo: null,\n workingBranch: null,\n seededWorkspaceSha: null,\n retiredBranch: null,\n sync: { lastPulledSnapshot: null, lastPulledSha: null, lastPulledAt: null, dirtyKeys: [] },\n linkedCollections: {},\n globalContext: {},\n mockRuntime: { active: {} },\n ui: {\n activeRequestId: null,\n sidebarExpandedSections: [],\n themeId: 'studio-dark',\n fontId: 'system-mono',\n fontSizePercent: FONT_SIZE_PERCENT_DEFAULT,\n },\n settings: { validateOnSend: true, monacoConsumesWheel: false },\n snapshots: { entries: [], maxBytes: 50 * 1024 * 1024 },\n },\n };\n await saveToFile(resolved, fresh);\n return fresh;\n}\n","import { promises as fs } from 'node:fs';\nimport * as path from 'node:path';\nimport type { Command } from 'commander';\nimport kleur from 'kleur';\nimport { applyMutation } from '@apicircle/core';\nimport { saveToFile } from '@apicircle/core/workspace/file-backed';\nimport {\n parseInsomniaToEndpoints,\n parseOpenApiToEndpoints,\n parsePostmanToEndpoints,\n} from '@apicircle/mock-server-core';\nimport { generateId, type Request as ApiRequest } from '@apicircle/shared';\nimport { ensureWorkspace } from '../util/loadWorkspace';\n\n// =============================================================================\n// `apicircle import <type> <spec>` — read an external spec, persist one\n// request per operation into `<workspace>/workspace.synced.json`.\n// =============================================================================\n\ntype ImportType = 'curl' | 'openapi' | 'postman' | 'insomnia';\n\ninterface ImportOptions {\n workspace?: string;\n format?: 'json' | 'yaml';\n}\n\nexport function registerImportCommand(program: Command): void {\n program\n .command('import')\n .description('Import a spec into a workspace folder')\n .argument('<type>', 'Source type: openapi | postman | insomnia | curl')\n .argument('<input>', 'Path to a spec file, or `-` to read from stdin')\n .option('-w, --workspace <dir>', 'Workspace directory (defaults to current directory)')\n .option('-f, --format <format>', 'OpenAPI format: json | yaml', 'json')\n .action(async (type: ImportType, input: string, opts: ImportOptions) => {\n const dir = path.resolve(opts.workspace ?? process.cwd());\n const raw = await readInput(input);\n const state = await ensureWorkspace(dir);\n let nextSynced = state.synced;\n let nextLocal = state.local;\n const created: string[] = [];\n\n const append = (req: ApiRequest) => {\n const out = applyMutation(\n { synced: nextSynced, local: nextLocal },\n { kind: 'request.create', request: req },\n );\n nextSynced = out.next.synced;\n nextLocal = out.next.local;\n created.push(req.id);\n };\n\n if (type === 'curl') {\n const { parseCurl } = await import('@apicircle/core');\n const parsed = parseCurl(raw);\n append(\n blankRequest({\n name: `cURL ${parsed.method} ${parsed.url}`.slice(0, 80),\n method: parsed.method,\n url: parsed.url,\n headers: parsed.headers,\n query: parsed.query,\n body: parsed.body,\n auth: parsed.auth,\n }),\n );\n } else if (type === 'openapi') {\n const parsed = await parseOpenApiToEndpoints(raw, opts.format ?? 'json');\n for (const ep of parsed.endpoints) {\n append(\n blankRequest({\n name: ep.example ?? `${ep.method} ${ep.pathPattern}`,\n method: ep.method,\n url: ep.pathPattern,\n }),\n );\n }\n } else if (type === 'postman') {\n const parsed = parsePostmanToEndpoints(raw);\n for (const ep of parsed.endpoints) {\n append(\n blankRequest({\n name: ep.example ?? `${ep.method} ${ep.pathPattern}`,\n method: ep.method,\n url: ep.pathPattern,\n }),\n );\n }\n } else if (type === 'insomnia') {\n const parsed = parseInsomniaToEndpoints(raw);\n for (const ep of parsed.endpoints) {\n append(\n blankRequest({\n name: ep.example ?? `${ep.method} ${ep.pathPattern}`,\n method: ep.method,\n url: ep.pathPattern,\n }),\n );\n }\n } else {\n // The four-branch chain above is exhaustive at the type level, so\n // `type` narrows to `never` here. Cast to string for the error\n // message — at runtime this only fires if a caller bypasses the\n // commander enum and passes garbage like `apicircle import xml ...`.\n process.stderr.write(`${kleur.red('error')}: unknown type '${String(type)}'\\n`);\n process.exit(2);\n }\n\n await saveToFile(dir, { synced: nextSynced, local: nextLocal });\n process.stdout.write(\n `${kleur.green('imported')} ${created.length} request${created.length === 1 ? '' : 's'} into ${dir}\\n`,\n );\n });\n}\n\nasync function readInput(p: string): Promise<string> {\n if (p === '-') {\n return new Promise<string>((resolve, reject) => {\n let data = '';\n process.stdin.setEncoding('utf-8');\n // setEncoding('utf-8') causes `chunk` to arrive as a string at runtime,\n // but Node's types still surface it as `string | Buffer`. Coerce to\n // satisfy `restrict-plus-operands` without changing behaviour.\n process.stdin.on('data', (chunk: string | Buffer) => {\n data += typeof chunk === 'string' ? chunk : chunk.toString('utf-8');\n });\n process.stdin.on('end', () => resolve(data));\n process.stdin.on('error', reject);\n });\n }\n return fs.readFile(path.resolve(p), 'utf-8');\n}\n\nfunction blankRequest(\n partial: Partial<ApiRequest> & {\n name: string;\n method: ApiRequest['method'];\n url: string;\n },\n): ApiRequest {\n const now = new Date().toISOString();\n return {\n id: generateId(),\n folderId: null,\n headers: [],\n query: [],\n body: { type: 'none', content: '' },\n auth: { type: 'none' },\n contextVars: [],\n extractions: [],\n assertions: [],\n createdAt: now,\n updatedAt: now,\n ...partial,\n };\n}\n","import * as os from 'node:os';\nimport * as path from 'node:path';\nimport type { Command } from 'commander';\nimport kleur from 'kleur';\nimport {\n ANONYMOUS_ACTOR,\n PlanRunDeniedError,\n resolvePlanRef,\n runPlan,\n type PlanRunAuthorizationContext,\n type PlanStepResult,\n type RunActor,\n type RunPlanResult,\n} from '@apicircle/core';\nimport { loadFromFile, saveToFile } from '@apicircle/core/workspace/file-backed';\nimport type { ExecutionPlan, WorkspaceLocal } from '@apicircle/shared';\nimport { buildSecretsFromCli } from '../util/secrets';\n\n// =============================================================================\n// `apicircle run <plan>` — execute a saved execution plan headlessly and print\n// a pass/fail report. Sits alongside `apicircle mock` and `apicircle mcp` as\n// the third runtime entry point. Drives the runtime-agnostic engine in\n// `@apicircle/core` (`runPlan`), so the CLI owns only argument parsing,\n// workspace IO, runner-identity resolution, and report formatting.\n//\n// Exit codes:\n// 0 every executed step passed\n// 1 the plan ran but a step failed (or the run was aborted)\n// 2 usage error — no workspace, unknown plan, bad option\n// 3 the run was denied by the authorization gate\n// =============================================================================\n\nconst REPORTERS = ['text', 'json', 'junit'] as const;\ntype Reporter = (typeof REPORTERS)[number];\n\ninterface RunOptions {\n workspace?: string;\n /** Commander sets this `false` when `--no-assertions` is passed. */\n assertions?: boolean;\n secrets?: string;\n /** Commander sets this `false` when `--no-save` is passed. */\n save?: boolean;\n reporter?: string;\n bail?: boolean;\n env?: string;\n as?: string;\n}\n\nexport function registerRunCommand(program: Command): void {\n program\n .command('run')\n .description('Run a saved execution plan from a workspace and report the result')\n .argument('<plan>', 'Plan name or id to run')\n .option('-w, --workspace <dir>', 'Workspace directory (defaults to current directory)')\n .option('--no-assertions', 'Run requests without evaluating their assertions')\n .option('-s, --secrets <file>', 'JSON file mapping secretKeyId → plaintext value')\n .option('--no-save', 'Do not write the plan run to workspace history')\n .option('--reporter <format>', 'Report format: text | json | junit', 'text')\n .option('--bail', 'Stop the run at the first failed step')\n .option('-e, --env <name>', 'Layer a local environment on top of the run')\n .option('--as <actor>', 'Override the recorded runner identity')\n .action(async (planRef: string, opts: RunOptions) => {\n const dir = path.resolve(opts.workspace ?? process.cwd());\n\n const reporter = opts.reporter ?? 'text';\n if (!isReporter(reporter)) {\n fail(`unknown --reporter \"${reporter}\" (expected: ${REPORTERS.join(', ')})`);\n return;\n }\n\n const state = await loadFromFile(dir, { allowMissing: true });\n if (!state) {\n fail(`no workspace found at ${dir} (expected workspace.synced.json)`);\n return;\n }\n\n const ref = resolvePlanRef(state.synced, planRef);\n if (!ref.ok) {\n fail(ref.error);\n if (ref.available.length > 0) {\n process.stderr.write(`Available plans: ${ref.available.join(', ')}\\n`);\n }\n return;\n }\n\n if (opts.env && !state.synced.environments.items[opts.env]) {\n const names = Object.keys(state.synced.environments.items);\n fail(`no environment named \"${opts.env}\" in this workspace`);\n if (names.length > 0) {\n process.stderr.write(`Available environments: ${names.join(', ')}\\n`);\n }\n return;\n }\n\n let secretsById: Record<string, string>;\n try {\n secretsById = (await buildSecretsFromCli({ secretsFile: opts.secrets })).byId;\n } catch (err) {\n fail(err instanceof Error ? err.message : String(err));\n return;\n }\n\n const actor = resolveActor(state.local, opts.as);\n const withAssertions = opts.assertions !== false;\n const text = reporter === 'text';\n\n // Ctrl+C aborts gracefully between steps (and the in-flight request)\n // rather than killing the process — the partial run is still reported.\n const controller = new AbortController();\n const onSigint = (): void => controller.abort(new Error('aborted by SIGINT'));\n process.on('SIGINT', onSigint);\n\n if (text) process.stdout.write(formatHeader(ref.plan, actor, withAssertions, opts));\n\n let result: RunPlanResult;\n try {\n result = await runPlan(state, ref.id, {\n withAssertions,\n bail: opts.bail === true,\n env: opts.env,\n secretsById,\n actor,\n signal: controller.signal,\n authorize: checkRunPermission,\n onStep: text ? (step) => process.stdout.write(formatStepLine(step)) : undefined,\n });\n } catch (err) {\n process.off('SIGINT', onSigint);\n if (err instanceof PlanRunDeniedError) {\n fail(err.message, 3, 'denied');\n return;\n }\n throw err;\n }\n process.off('SIGINT', onSigint);\n\n const aborted = controller.signal.aborted;\n const saved = opts.save !== false;\n if (saved) await saveToFile(dir, result.nextState);\n\n if (reporter === 'json') {\n process.stdout.write(\n JSON.stringify(\n buildJsonReport(dir, ref.id, ref.plan, actor, result, saved, aborted),\n null,\n 2,\n ) + '\\n',\n );\n } else if (reporter === 'junit') {\n process.stdout.write(buildJunitReport(ref.plan, result));\n } else {\n process.stdout.write(formatSummary(result, saved, aborted));\n }\n\n // An aborted run is never a pass, even if the steps that ran all passed.\n process.exitCode = result.passed && !aborted ? 0 : 1;\n });\n}\n\nfunction isReporter(value: string): value is Reporter {\n return (REPORTERS as readonly string[]).includes(value);\n}\n\n/**\n * Best-effort identity of whoever launched the run. Precedence: an explicit\n * `--as` override, then the workspace's GitHub session login, then the OS\n * username. Recorded for display and handed to {@link checkRunPermission}.\n */\nexport function resolveActor(local: WorkspaceLocal, override?: string): RunActor {\n const explicit = override?.trim();\n if (explicit) return { kind: 'unknown', name: explicit };\n\n const login = local.sessions.github.workspace?.accountLogin;\n if (login) return { kind: 'github', name: login };\n\n try {\n const username = os.userInfo().username;\n if (username) return { kind: 'os', name: username };\n } catch {\n // os.userInfo() throws when the uid has no passwd entry (some containers).\n }\n return ANONYMOUS_ACTOR;\n}\n\n/**\n * Authorization gate for `apicircle run`. Today every actor may run every\n * plan — this is intentionally permissive. When per-user run restrictions\n * land, enforce them here: inspect `ctx.actor` + `ctx.plan` and throw a\n * `PlanRunDeniedError` to block the run before any HTTP request fires. It is\n * wired into `runPlan` via the `authorize` option, so a denial is caught and\n * reported with exit code 3.\n */\nfunction checkRunPermission(_ctx: PlanRunAuthorizationContext): void {\n // FUTURE: per-user run authorization. Throw PlanRunDeniedError to deny.\n}\n\n// ---------------------------------------------------------------------------\n// reporting\n// ---------------------------------------------------------------------------\n\nfunction formatHeader(\n plan: ExecutionPlan,\n actor: RunActor,\n withAssertions: boolean,\n opts: RunOptions,\n): string {\n const enabled = plan.steps.filter((s) => s.enabled !== false).length;\n const flags = [\n withAssertions ? 'assertions on' : 'assertions off',\n opts.bail ? 'bail' : null,\n opts.env ? `env=${opts.env}` : null,\n ].filter((f): f is string => f !== null);\n return (\n `${kleur.bold('Plan')} ${plan.name} ${kleur.dim(\n `(${enabled}/${plan.steps.length} steps · ${flags.join(' · ')})`,\n )}\\n` + `${kleur.dim('Run by')} ${actor.name} ${kleur.dim(`(${actor.kind})`)}\\n\\n`\n );\n}\n\nexport function formatStepLine(step: PlanStepResult): string {\n const n = `${step.stepIndex + 1}.`.padEnd(3);\n const method = (step.requestMethod || '—').padEnd(7);\n\n if (step.skipped) {\n return ` ${kleur.dim('–')} ${kleur.dim(n)} ${kleur.dim(method)} ${kleur.dim(\n `${step.requestName} skipped`,\n )}\\n`;\n }\n\n const mark = step.passed ? kleur.green('✓') : kleur.red('✗');\n const status = step.result?.status != null ? String(step.result.status) : '—';\n const duration = step.result ? `${step.result.durationMs}ms` : '';\n const name = step.requestName.padEnd(28);\n\n let line = ` ${mark} ${n} ${method} ${name} ${status.padEnd(4)} ${kleur.dim(duration)}`;\n\n if (step.assertionResults.length > 0) {\n const passed = step.assertionResults.filter((a) => a.passed).length;\n line += ` ${kleur.dim(`${passed}/${step.assertionResults.length} assertions`)}`;\n }\n line += '\\n';\n\n if (step.error) {\n line += ` ${kleur.red(step.error)}\\n`;\n }\n for (const a of step.assertionResults) {\n if (!a.passed) line += ` ${kleur.red('✗')} ${a.detail ?? `${a.kind} ${a.op}`}\\n`;\n }\n if (step.missingVariables.length > 0) {\n line += ` ${kleur.yellow('⚠')} unresolved: ${step.missingVariables\n .map((v) => `{{${v}}}`)\n .join(', ')}\\n`;\n }\n return line;\n}\n\nfunction tally(result: RunPlanResult): { passed: number; failed: number; skipped: number } {\n let passed = 0;\n let failed = 0;\n let skipped = 0;\n for (const s of result.steps) {\n if (s.skipped) skipped++;\n else if (s.passed) passed++;\n else failed++;\n }\n return { passed, failed, skipped };\n}\n\nfunction formatSummary(result: RunPlanResult, saved: boolean, aborted: boolean): string {\n if (result.steps.length === 0) {\n return `\\n${kleur.yellow('Plan has no steps.')}\\n`;\n }\n const { passed, failed, skipped } = tally(result);\n const parts = [\n kleur.green(`${passed} passed`),\n failed > 0 ? kleur.red(`${failed} failed`) : kleur.dim(`${failed} failed`),\n kleur.dim(`${skipped} skipped`),\n ];\n const verdict = result.passed && !aborted ? kleur.green('PASS') : kleur.red('FAIL');\n let out = `\\n${verdict} ${parts.join(kleur.dim(' · '))} ${kleur.dim(\n `· ${result.planRun.durationMs}ms`,\n )}\\n`;\n if (aborted) out += `${kleur.yellow('Run aborted before every step finished.')}\\n`;\n out += saved\n ? kleur.dim('Plan run saved to workspace history.\\n')\n : kleur.dim('Plan run not saved (--no-save).\\n');\n return out;\n}\n\nfunction buildJsonReport(\n workspace: string,\n planId: string,\n plan: ExecutionPlan,\n actor: RunActor,\n result: RunPlanResult,\n saved: boolean,\n aborted: boolean,\n): unknown {\n return {\n workspace,\n plan: { id: planId, name: plan.name },\n actor,\n withAssertions: result.planRun.withAssertions,\n passed: result.passed && !aborted,\n aborted,\n durationMs: result.planRun.durationMs,\n saved,\n counts: tally(result),\n steps: result.steps.map((s) => ({\n step: s.stepIndex + 1,\n request: s.requestName,\n method: s.requestMethod,\n skipped: s.skipped,\n status: s.result?.status ?? null,\n ok: s.result?.ok ?? false,\n durationMs: s.result?.durationMs ?? 0,\n passed: s.passed,\n error: s.error ?? null,\n missingVariables: s.missingVariables,\n assertions: s.assertionResults.map((a) => ({\n kind: a.kind,\n op: a.op,\n target: a.target,\n expected: a.expected,\n passed: a.passed,\n detail: a.detail,\n })),\n })),\n };\n}\n\nfunction xmlEscape(value: string): string {\n return value\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, '&quot;');\n}\n\n/** JUnit XML — consumable by CI dashboards as a plan-run review gate. */\nexport function buildJunitReport(plan: ExecutionPlan, result: RunPlanResult): string {\n const { failed, skipped } = tally(result);\n const total = result.steps.length;\n const suite = xmlEscape(plan.name);\n const suiteTime = (result.planRun.durationMs / 1000).toFixed(3);\n\n const cases = result.steps.map((s) => {\n const name = xmlEscape(`${s.stepIndex + 1}. ${s.requestName}`);\n const time = ((s.result?.durationMs ?? 0) / 1000).toFixed(3);\n const open = ` <testcase name=\"${name}\" classname=\"${suite}\" time=\"${time}\"`;\n if (s.skipped) return `${open}>\\n <skipped/>\\n </testcase>`;\n if (s.passed) return `${open}/>`;\n\n const reasons: string[] = [];\n if (s.error) reasons.push(s.error);\n for (const a of s.assertionResults) {\n if (!a.passed) reasons.push(a.detail ?? `assertion ${a.kind} ${a.op} failed`);\n }\n if (s.result && !s.result.ok && s.result.status != null) {\n reasons.push(`HTTP ${s.result.status}`);\n }\n const detail = xmlEscape(reasons.join('\\n') || 'step failed');\n const summary = detail.split('\\n')[0];\n return `${open}>\\n <failure message=\"${summary}\">${detail}</failure>\\n </testcase>`;\n });\n\n return (\n '<?xml version=\"1.0\" encoding=\"UTF-8\"?>\\n' +\n `<testsuites name=\"${suite}\" tests=\"${total}\" failures=\"${failed}\" skipped=\"${skipped}\" time=\"${suiteTime}\">\\n` +\n ` <testsuite name=\"${suite}\" tests=\"${total}\" failures=\"${failed}\" skipped=\"${skipped}\" time=\"${suiteTime}\">\\n` +\n `${cases.join('\\n')}\\n` +\n ' </testsuite>\\n' +\n '</testsuites>\\n'\n );\n}\n\n/** Write a CLI error to stderr and set the exit code. `kind` colours the prefix. */\nfunction fail(message: string, code = 2, kind = 'error'): void {\n process.stderr.write(`${kleur.red(kind)}: ${message}\\n`);\n process.exitCode = code;\n}\n","import * as path from 'node:path';\nimport { promises as fs } from 'node:fs';\nimport type { WorkspaceState } from '@apicircle/core';\n\n// =============================================================================\n// CLI secret provisioning\n//\n// Secret values aren't synced to Git. Workspaces synced from a teammate carry\n// only `secretKeyId` references and a synced labels map (`secretKeys`). The\n// CLI must source the actual values from the runtime environment.\n//\n// Resolution order (later sources override earlier ones):\n// 1. `--secrets <file>.json` — `{ \"<id>\": \"<value>\" }`\n// 2. `APICIRCLE_SECRET_<id>=value` — env vars (prefix configurable)\n//\n// Resolved values feed `buildScope` as the `secrets` layer so `{{NAME}}`\n// references in environment variables (with `secretKeyId`) get expanded\n// at send time. Missing required ids surface as a single-block error before\n// any HTTP request goes out.\n// =============================================================================\n\nexport interface SecretRequirement {\n /** secretKeyId referenced by an env-variable in the workspace. */\n id: string;\n /** Best-known label (from `synced.secretKeys[id].label`) for display. */\n label: string;\n /** Where in the workspace the id is referenced (env name + var key). */\n references: Array<{ envName: string; varKey: string }>;\n}\n\nconst DEFAULT_PREFIX = 'APICIRCLE_SECRET_';\n\nexport interface BuildSecretsOptions {\n secretsFile?: string;\n envPrefix?: string;\n env?: NodeJS.ProcessEnv;\n}\n\nexport interface BuildSecretsResult {\n /** id → plaintext value, ready for buildScope. */\n byId: Record<string, string>;\n}\n\nexport async function buildSecretsFromCli(\n options: BuildSecretsOptions = {},\n): Promise<BuildSecretsResult> {\n const env = options.env ?? process.env;\n const prefix = options.envPrefix ?? DEFAULT_PREFIX;\n const byId: Record<string, string> = {};\n\n if (options.secretsFile) {\n const resolved = path.resolve(options.secretsFile);\n const raw = await fs.readFile(resolved, 'utf8');\n const parsed: unknown = JSON.parse(raw);\n if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {\n throw new Error(\n `--secrets ${options.secretsFile}: expected an object mapping secretKeyId → value`,\n );\n }\n for (const [id, value] of Object.entries(parsed as Record<string, unknown>)) {\n if (typeof value !== 'string') {\n throw new Error(`--secrets ${options.secretsFile}: value for \"${id}\" must be a string`);\n }\n byId[id] = value;\n }\n }\n\n for (const [name, value] of Object.entries(env)) {\n if (!name.startsWith(prefix) || typeof value !== 'string') continue;\n const id = name.slice(prefix.length);\n if (id) byId[id] = value;\n }\n\n return { byId };\n}\n\n/**\n * Walk a workspace and collect every `secretKeyId` referenced by an env\n * variable. Used to validate that the CLI received values for every\n * required id before executing a request.\n */\nexport function collectSecretRequirements(workspace: WorkspaceState): SecretRequirement[] {\n const labels = workspace.synced.secretKeys ?? {};\n const refs = new Map<string, SecretRequirement>();\n for (const [envName, env] of Object.entries(workspace.synced.environments.items)) {\n for (const v of env.variables) {\n if (!v.encrypted || !v.secretKeyId) continue;\n const id = v.secretKeyId;\n const requirement = refs.get(id) ?? {\n id,\n label: labels[id]?.label ?? `(unlabelled ${id.slice(0, 6)}…)`,\n references: [],\n };\n requirement.references.push({ envName, varKey: v.key });\n refs.set(id, requirement);\n }\n }\n return [...refs.values()];\n}\n\n/**\n * Format a missing-secrets error for the CLI. Returns a multi-line string\n * suitable for stderr; callers exit with code 2.\n */\nexport function formatMissingSecretsError(missing: SecretRequirement[]): string {\n const lines = ['Missing secret values for the following keys:'];\n for (const req of missing) {\n const refs = req.references.map((r) => `env \"${r.envName}\" var \"${r.varKey}\"`).join('; ');\n lines.push(` - id \"${req.id}\" (label \"${req.label}\") — referenced by ${refs}`);\n }\n lines.push('');\n lines.push(\n 'Provide values via APICIRCLE_SECRET_<id>=<value> environment variables or --secrets <file>.json.',\n );\n return lines.join('\\n');\n}\n\n/**\n * Convenience: assert every required secret has a value. Throws a CLI-formatted\n * error when anything is missing, otherwise returns the resolved id→value map.\n */\nexport async function resolveSecretsForWorkspace(\n workspace: WorkspaceState,\n options: BuildSecretsOptions = {},\n): Promise<Record<string, string>> {\n const { byId } = await buildSecretsFromCli(options);\n const missing = collectSecretRequirements(workspace).filter((r) => !(r.id in byId));\n if (missing.length > 0) {\n const err = new Error(formatMissingSecretsError(missing));\n (err as Error & { code?: string }).code = 'APICIRCLE_MISSING_SECRETS';\n throw err;\n }\n return byId;\n}\n"],"mappings":"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","names":["path","kleur","path","fs","generateId","kleur","fs","path","kleur","saveToFile","generateId","kleur","saveToFile","resolve","fs","generateId","path","kleur","loadFromFile","saveToFile","path","fs","loadFromFile","saveToFile","kleur"]}
package/package.json ADDED
@@ -0,0 +1,59 @@
1
+ {
2
+ "name": "@apicircle/cli",
3
+ "version": "1.0.0",
4
+ "private": false,
5
+ "type": "module",
6
+ "description": "Command-line interface for APICircle Studio. Run mock servers, drive the MCP server, and import OpenAPI / Postman / Insomnia collections from any terminal.",
7
+ "license": "SEE LICENSE IN LICENSE",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/apicircle/studio.git",
11
+ "directory": "packages/cli"
12
+ },
13
+ "homepage": "https://github.com/apicircle/studio#readme",
14
+ "bugs": "https://github.com/apicircle/studio/issues",
15
+ "engines": {
16
+ "node": ">=20"
17
+ },
18
+ "main": "./dist/index.cjs",
19
+ "types": "./dist/index.d.cts",
20
+ "bin": {
21
+ "apicircle": "./dist/index.cjs"
22
+ },
23
+ "exports": {
24
+ ".": {
25
+ "import": {
26
+ "types": "./dist/index.d.ts",
27
+ "default": "./dist/index.js"
28
+ },
29
+ "require": {
30
+ "types": "./dist/index.d.cts",
31
+ "default": "./dist/index.cjs"
32
+ }
33
+ }
34
+ },
35
+ "files": [
36
+ "dist"
37
+ ],
38
+ "dependencies": {
39
+ "commander": "^12.0.0",
40
+ "kleur": "^4.1.5",
41
+ "@apicircle/core": "1.0.0",
42
+ "@apicircle/mcp-server": "1.0.0",
43
+ "@apicircle/shared": "1.0.0",
44
+ "@apicircle/mock-server-core": "1.0.0"
45
+ },
46
+ "devDependencies": {
47
+ "@types/node": "^20.0.0",
48
+ "tsup": "^8.3.0",
49
+ "typescript": "^5.4.0",
50
+ "vitest": "^2.0.0"
51
+ },
52
+ "scripts": {
53
+ "build": "tsup",
54
+ "check": "tsc --noEmit",
55
+ "test": "vitest run",
56
+ "clean": "rm -rf dist node_modules"
57
+ },
58
+ "module": "./dist/index.js"
59
+ }