stuntdouble 0.1.2 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +37 -9
- package/dist/{chunk-VWTYG7G4.js → chunk-BFI6P5DO.js} +65 -25
- package/dist/chunk-BFI6P5DO.js.map +1 -0
- package/dist/chunk-DFXASIGV.js +431 -0
- package/dist/chunk-DFXASIGV.js.map +1 -0
- package/dist/{chunk-JAB46QV7.js → chunk-F3R3QL7V.js} +64 -8
- package/dist/chunk-F3R3QL7V.js.map +1 -0
- package/dist/{mcp-CYPMT37O.js → chunk-FMZTT2MC.js} +72 -1059
- package/dist/chunk-FMZTT2MC.js.map +1 -0
- package/dist/chunk-MSV5OLSY.js +117 -0
- package/dist/chunk-MSV5OLSY.js.map +1 -0
- package/dist/chunk-P3CI4FTE.js +469 -0
- package/dist/chunk-P3CI4FTE.js.map +1 -0
- package/dist/chunk-QDA5FTUH.js +79 -0
- package/dist/chunk-QDA5FTUH.js.map +1 -0
- package/dist/chunk-XHSDRB3X.js +996 -0
- package/dist/chunk-XHSDRB3X.js.map +1 -0
- package/dist/cli.js +180 -68
- package/dist/cli.js.map +1 -1
- package/dist/cloud-DLLNKYND.js +34 -0
- package/dist/credentials-QHESDY4K.js +27 -0
- package/dist/credentials-QHESDY4K.js.map +1 -0
- package/dist/doctor-ZAYOOCPT.js +13 -0
- package/dist/doctor-ZAYOOCPT.js.map +1 -0
- package/dist/files-UBPF7PKW.js +45 -0
- package/dist/files-UBPF7PKW.js.map +1 -0
- package/dist/mcp-HFIAQ6HP.js +133 -0
- package/dist/mcp-HFIAQ6HP.js.map +1 -0
- package/dist/open-browser-CTOGH5HQ.js +17 -0
- package/dist/open-browser-CTOGH5HQ.js.map +1 -0
- package/dist/run-MPIAR3LQ.js +20 -0
- package/dist/run-MPIAR3LQ.js.map +1 -0
- package/dist/runner-E45EJ76B.js +17 -0
- package/dist/runner-E45EJ76B.js.map +1 -0
- package/dist/studio-FBC66BER.js +360 -0
- package/dist/studio-FBC66BER.js.map +1 -0
- package/dist/studio.js +1621 -0
- package/dist/ui-server-C7CFJWRD.js +12 -0
- package/dist/ui-server-C7CFJWRD.js.map +1 -0
- package/dist/ui.html +210 -103
- package/package.json +2 -2
- package/dist/chunk-JAB46QV7.js.map +0 -1
- package/dist/chunk-VWTYG7G4.js.map +0 -1
- package/dist/mcp-CYPMT37O.js.map +0 -1
- package/dist/ui-server-AYIR7DTN.js +0 -10
- /package/dist/{ui-server-AYIR7DTN.js.map → cloud-DLLNKYND.js.map} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/studio.ts"],"sourcesContent":["// Stunt Double Studio: the viewer grown into a local app (`stuntdouble\n// studio`). It adds editing actors and checklists, starting a run on the\n// person's own model connection or in the cloud, and settings for both.\n//\n// Policy line: a Studio run uses only a connection the person configures (an\n// Anthropic API key or an OpenAI-compatible endpoint), never a Claude\n// subscription. Keys stay in ~/.stuntdouble/credentials.json (credentials.ts):\n// the page is told only whether one is set and where from. The MCP server\n// never imports this module, so inside Claude Code nothing here runs.\n//\n// The security model is the viewer's (ui-server.ts): loopback only, the\n// per-start key cookie, the Host check on every request, no CORS. Every write\n// here also needs this server's own Origin and a JSON body, so neither another\n// site nor a plain form can make one.\n\nimport { readFile, stat } from 'node:fs/promises';\nimport type { IncomingMessage, ServerResponse } from 'node:http';\nimport { join } from 'node:path';\nimport { z } from 'zod';\n\nimport {\n beginLogin,\n chooseWorkspace,\n CloudRefusal,\n cloudStatus,\n completeLogin,\n listWorkspaces,\n logout,\n startCloudRun,\n} from './cloud.ts';\nimport {\n connectionStatus,\n PROVIDERS,\n resolveConnection,\n saveConnection,\n type Connection,\n} from './credentials.ts';\nimport { ActorSchema, ChecklistSchema, sdDir, writeFileAtomic, writeJsonAtomic } from './files.ts';\nimport { LocalSession, type Launch } from './run.ts';\nimport { DEFAULT_LIMITS, startStandaloneRun, testConnection, type RunUsage } from './runner.ts';\nimport { send, startUi, type UiServer } from './ui-server.ts';\n\nconst SLUG = /^[a-z0-9][a-z0-9-]*$/;\nconst MAX_BODY = 1_000_000;\n\ntype Job = {\n kind: 'local' | 'cloud';\n run_id: string;\n checklist: string;\n model: { provider: string; id: string } | null;\n usage: RunUsage | null;\n last: string;\n};\n\nexport type Studio = {\n ui: UiServer;\n link(path?: string): string;\n close(): Promise<void>;\n};\n\nconst json = (res: ServerResponse, status: number, data: unknown) =>\n send(res, status, JSON.stringify(data), 'application/json');\nconst problem = (res: ServerResponse, status: number, message: string) =>\n json(res, status, { error: message });\n\ntype Issue = { path: string; message: string };\nconst issuesOf = (error: z.ZodError): Issue[] =>\n error.issues.map((i) => ({ path: i.path.join('.'), message: i.message }));\n\nasync function readBody(req: IncomingMessage): Promise<unknown> {\n let body = '';\n for await (const chunk of req) {\n body += chunk;\n if (body.length > MAX_BODY) throw new Error('Body too large');\n }\n return body ? JSON.parse(body) : {};\n}\n\nconst exists = (path: string) =>\n stat(path).then(\n () => true,\n () => false\n );\n\n/** A connection that can make a call: a key, unless the endpoint is on this machine. */\nfunction usable(connection: Connection | null): connection is Connection {\n if (!connection) return false;\n if (connection.apiKey) return true;\n const host = new URL(connection.baseUrl).hostname;\n return connection.provider === 'openai' && /^(localhost|127\\.0\\.0\\.1|\\[::1\\])$/.test(host);\n}\n\n/** The starter files for a project with no `.stuntdouble/` yet. */\nexport async function createStarter(project: string, url: string): Promise<void> {\n const root = sdDir(project);\n await writeJsonAtomic(join(root, 'stuntdouble.json'), {\n format: 'stuntdouble/1',\n local_base_url: null,\n headless: false,\n model_screenshots: 'on_request',\n safety: 'third_party',\n });\n await writeFileAtomic(join(root, '.gitignore'), '.live/\\n');\n const actor = join(root, 'actors', 'first-time-visitor.json');\n if (!(await exists(actor))) {\n await writeJsonAtomic(actor, {\n name: 'First-time visitor',\n description:\n 'Has never used the product, arrives from a search result and decides within a minute whether it is worth their time',\n knowledge: [],\n persist_login: false,\n });\n }\n const checklist = join(root, 'checklists', 'first-look.json');\n if (!(await exists(checklist))) {\n await writeJsonAtomic(checklist, {\n name: 'First look',\n actor: 'first-time-visitor',\n url,\n instructions:\n 'Arrive at the home page as someone who has never heard of the product. Work out what it is, try the main next step without paying or signing up, and follow the main navigation.',\n checks: [\n {\n key: 'says-what-it-is',\n description: 'The first screen says plainly what the product is and who it is for',\n },\n {\n key: 'clear-next-step',\n description: 'There is one clear next step, such as a sign-up button, without scrolling',\n },\n {\n key: 'navigation-works',\n description: 'The main navigation links open working pages, with no error or empty page',\n },\n {\n key: 'first-impression',\n description: 'Record what a new visitor would read or do first',\n type: 'informational',\n },\n ],\n });\n }\n}\n\nconst InitInput = z.object({ url: z.url({ protocol: /^https?$/ }) });\nconst RunInput = z.object({\n checklist: z.string().regex(SLUG),\n where: z.enum(['local', 'cloud']).default('local'),\n resume: z.boolean().optional(),\n});\nconst ConnectionInput = z.object({\n provider: z.enum(PROVIDERS),\n model: z.string().trim().min(1, 'Name the model').max(200),\n base_url: z.union([z.url({ protocol: /^https?$/ }), z.literal('')]).nullish(),\n api_key: z.string().max(500).nullish(),\n clear_key: z.boolean().optional(),\n});\n\nexport async function startStudio(options: {\n project: string;\n port?: number;\n launch?: Launch;\n fetch?: typeof fetch;\n cloudPollMs?: number;\n}): Promise<Studio> {\n const project = options.project;\n const root = sdDir(project);\n let job: Job | null = null;\n let session: LocalSession | null = null;\n const cloudJobs = new Map<string, Job>();\n\n async function status() {\n return {\n project,\n initialised: await exists(join(root, 'stuntdouble.json')),\n connection: await connectionStatus(),\n cloud: await cloudStatus(),\n jobs: [...(job ? [job] : []), ...cloudJobs.values()],\n limits: DEFAULT_LIMITS,\n };\n }\n\n /** Write one actor or checklist, validated by the schema `start_run` reads it with. */\n async function saveDefinition(\n res: ServerResponse,\n folder: 'actors' | 'checklists',\n slug: string,\n body: unknown\n ): Promise<void> {\n const input = z\n .object({ data: z.record(z.string(), z.unknown()), create: z.boolean().optional() })\n .safeParse(body);\n if (!input.success) return problem(res, 400, 'Send {\"data\": {...}}.');\n if (!SLUG.test(slug)) {\n return json(res, 422, {\n issues: [{ path: 'slug', message: 'Use lowercase letters, digits and hyphens' }],\n });\n }\n const path = join(root, folder, `${slug}.json`);\n const existing = await readFile(path, 'utf8')\n .then((t) => JSON.parse(t) as Record<string, unknown>)\n .catch(() => null);\n if (input.data.create && existing) {\n return json(res, 409, {\n issues: [\n { path: 'slug', message: `There is already a ${folder.slice(0, -1)} called ${slug}` },\n ],\n });\n }\n // Cloud ids are written by a push, never by the form.\n const { cloud: _ignored, ...fields } = input.data.data;\n const data = existing?.cloud ? { ...fields, cloud: existing.cloud } : fields;\n const schema = folder === 'actors' ? ActorSchema : ChecklistSchema;\n const parsed = schema.safeParse(data);\n const issues = parsed.success ? [] : issuesOf(parsed.error);\n if (folder === 'checklists' && typeof data.actor === 'string' && SLUG.test(data.actor)) {\n if (!(await exists(join(root, 'actors', `${data.actor}.json`)))) {\n issues.push({ path: 'actor', message: `There is no actor called ${data.actor}` });\n }\n }\n if (issues.length) return json(res, 422, { issues });\n await writeJsonAtomic(path, data);\n return json(res, 200, { slug });\n }\n\n async function startRun(res: ServerResponse, body: unknown): Promise<void> {\n const input = RunInput.safeParse(body);\n if (!input.success) return problem(res, 400, 'Name a checklist to run.');\n const { checklist, where, resume } = input.data;\n if (where === 'cloud') {\n const run = await startCloudRun({ project, checklist, pollMs: options.cloudPollMs });\n const entry: Job = {\n kind: 'cloud',\n run_id: run.runId,\n checklist,\n model: null,\n usage: null,\n last: 'Running in the cloud',\n };\n cloudJobs.set(run.runId, entry);\n run.done.catch(() => {}).finally(() => cloudJobs.delete(run.runId));\n return json(res, 200, { run_id: run.runId });\n }\n if (job) return problem(res, 409, `A run of ${job.checklist} is still going.`);\n const connection = await resolveConnection();\n if (!usable(connection)) {\n return problem(res, 400, 'Connect a model first: Settings, then Connection.');\n }\n const model = { provider: connection.provider, id: connection.model };\n session = new LocalSession({ project, ui, launch: options.launch, runner: { model } });\n const current: Job = { kind: 'local', run_id: '', checklist, model, usage: null, last: '' };\n job = current;\n try {\n const run = await startStandaloneRun({\n session,\n connection,\n checklist,\n resume,\n fetch: options.fetch,\n onProgress: (p) => {\n current.usage = p.usage;\n current.last = p.last;\n },\n });\n current.run_id = run.runId;\n const ended = session;\n run.done\n .catch(() => {})\n .finally(() => {\n if (job === current) job = null;\n void ended.close();\n });\n return json(res, 200, { run_id: run.runId });\n } catch (err) {\n job = null;\n await session.close().catch(() => {});\n throw err;\n }\n }\n\n async function handle(req: IncomingMessage, res: ServerResponse, url: URL): Promise<boolean> {\n const path = url.pathname;\n if (path === '/studio.js' && req.method === 'GET') {\n const script = await readFile(new URL('./studio.js', import.meta.url));\n send(res, 200, script, 'text/javascript; charset=utf-8');\n return true;\n }\n if (!path.startsWith('/api/studio')) return false;\n if (req.method === 'GET') {\n if (path === '/api/studio') json(res, 200, await status());\n else if (path === '/api/studio/cloud/workspaces') {\n json(res, 200, { workspaces: await listWorkspaces() });\n } else problem(res, 404, 'Not found');\n return true;\n }\n // Writes: only from this server's own page.\n if (req.headers.origin !== `http://${req.headers.host}`) {\n problem(res, 403, 'Forbidden');\n return true;\n }\n if (!/^application\\/json\\b/.test(req.headers['content-type'] ?? '')) {\n problem(res, 415, 'Send JSON.');\n return true;\n }\n let body: unknown;\n try {\n body = await readBody(req);\n } catch {\n problem(res, 400, 'That was not JSON.');\n return true;\n }\n const definition = path.match(/^\\/api\\/studio\\/(actors|checklists)\\/([^/]+)$/);\n try {\n if (definition && req.method === 'PUT') {\n await saveDefinition(\n res,\n definition[1] as 'actors' | 'checklists',\n decodeURIComponent(definition[2]!),\n body\n );\n } else if (req.method !== 'POST') {\n problem(res, 405, 'Method not allowed');\n } else if (path === '/api/studio/init') {\n const input = InitInput.safeParse(body);\n if (!input.success) {\n json(res, 422, {\n issues: [{ path: 'url', message: 'Enter a web address, http or https' }],\n });\n } else if (await exists(join(root, 'stuntdouble.json'))) {\n problem(res, 409, 'This project is already set up.');\n } else {\n await createStarter(project, input.data.url);\n json(res, 200, { checklist: 'first-look' });\n }\n } else if (path === '/api/studio/run') {\n await startRun(res, body);\n } else if (path === '/api/studio/connection') {\n const input = ConnectionInput.safeParse(body);\n if (!input.success) json(res, 422, { issues: issuesOf(input.error) });\n else {\n await saveConnection(input.data);\n json(res, 200, await connectionStatus());\n }\n } else if (path === '/api/studio/connection/test') {\n const connection = await resolveConnection();\n json(\n res,\n 200,\n usable(connection)\n ? await testConnection(connection, options.fetch)\n : { ok: false, message: 'There is no key for this connection yet.' }\n );\n } else if (path === '/api/studio/cloud/login') {\n json(res, 200, { url: await beginLogin(`http://127.0.0.1:${ui.port}/oauth/callback`) });\n } else if (path === '/api/studio/cloud/logout') {\n await logout();\n json(res, 200, await cloudStatus());\n } else if (path === '/api/studio/cloud/workspace') {\n const id = (body as { id?: unknown }).id;\n if (typeof id !== 'string') problem(res, 400, 'Name a workspace.');\n else json(res, 200, { workspace: await chooseWorkspace(id) });\n } else {\n problem(res, 404, 'Not found');\n }\n } catch (err) {\n // Our own errors say what to fix (a file, a refusal from Stunt Double); the page shows them as text.\n problem(res, err instanceof CloudRefusal ? 403 : 400, (err as Error).message);\n }\n return true;\n }\n\n async function oauthCallback(_req: IncomingMessage, res: ServerResponse, url: URL) {\n const state = url.searchParams.get('state') ?? '';\n const code = url.searchParams.get('code');\n let message = 'Signed in to Stunt Double.';\n let ok = true;\n try {\n if (!code)\n throw new Error(url.searchParams.get('error_description') ?? 'Sign-in was cancelled.');\n await completeLogin(state, code);\n } catch (err) {\n ok = false;\n message = (err as Error).message;\n }\n const escape = (s: string) => s.replace(/[&<>\"']/g, (c) => `&#${c.charCodeAt(0)};`);\n // A same-origin navigation from here carries the Strict cookie again.\n send(\n res,\n ok ? 200 : 400,\n `<!doctype html><meta charset=\"utf-8\"><title>Stunt Double Studio</title>${ok ? '<meta http-equiv=\"refresh\" content=\"1;url=/settings\">' : ''}<body style=\"font:15px system-ui;padding:3rem;max-width:32rem\"><p>${escape(message)}</p><p><a href=\"/settings\">Back to the Studio</a></p></body>`,\n 'text/html; charset=utf-8',\n { 'Content-Security-Policy': \"default-src 'none'; style-src 'unsafe-inline'\" }\n );\n }\n\n const ui = await startUi({\n root,\n port: options.port,\n extension: {\n pages: /^\\/(checklists|actors|settings)(\\/[^/]+(\\/run)?)?$/,\n script: '/studio.js',\n handle,\n oauthCallback,\n },\n });\n\n return {\n ui,\n link: (path) => ui.link(path),\n close: async () => {\n await session?.close().catch(() => {});\n await ui.close();\n },\n };\n}\n"],"mappings":"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","names":[]}
|