@tuttiai/cli 0.8.0 → 0.10.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 +100 -0
- package/dist/index.js +661 -226
- package/dist/index.js.map +1 -1
- package/package.json +2 -1
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/commands/init.ts","../src/templates/index.ts","../src/commands/run.ts","../src/commands/add.ts","../src/commands/check.ts","../src/commands/studio.ts","../src/commands/search.ts","../src/commands/publish.ts","../src/commands/eval.ts"],"sourcesContent":["import { config } from \"dotenv\";\nconfig();\n\nimport { createLogger } from \"@tuttiai/core\";\nconst logger = createLogger(\"tutti-cli\");\n\nprocess.on(\"unhandledRejection\", (reason) => {\n logger.error({ error: reason instanceof Error ? reason.message : String(reason) }, \"Unhandled rejection\");\n process.exit(1);\n});\n\nprocess.on(\"uncaughtException\", (err) => {\n logger.error({ error: err.message }, \"Fatal error\");\n process.exit(1);\n});\n\nimport { Command } from \"commander\";\nimport { initCommand, templatesCommand } from \"./commands/init.js\";\nimport { runCommand } from \"./commands/run.js\";\nimport { addCommand } from \"./commands/add.js\";\nimport { checkCommand } from \"./commands/check.js\";\nimport { studioCommand } from \"./commands/studio.js\";\nimport { searchCommand, voicesCommand } from \"./commands/search.js\";\nimport { publishCommand } from \"./commands/publish.js\";\nimport { evalCommand } from \"./commands/eval.js\";\n\nconst program = new Command();\n\nprogram\n .name(\"tutti-ai\")\n .description(\"Tutti — multi-agent orchestration. All agents. All together.\")\n .version(\"0.8.0\");\n\nprogram\n .command(\"init [project-name]\")\n .description(\"Create a new Tutti project\")\n .option(\"-t, --template <id>\", \"Project template to use\")\n .action(async (projectName: string | undefined, opts: { template?: string }) => {\n await initCommand(projectName, opts.template);\n });\n\nprogram\n .command(\"templates\")\n .description(\"List all available project templates\")\n .action(() => {\n templatesCommand();\n });\n\nprogram\n .command(\"run [score]\")\n .description(\"Run a Tutti score interactively\")\n .action(async (score?: string) => {\n await runCommand(score);\n });\n\nprogram\n .command(\"add <voice>\")\n .description(\"Add a voice to your project\")\n .action((voice: string) => {\n addCommand(voice);\n });\n\nprogram\n .command(\"check [score]\")\n .description(\"Validate a score file without running it\")\n .action(async (score?: string) => {\n await checkCommand(score);\n });\n\nprogram\n .command(\"doctor [score]\")\n .description(\"Alias for check — validate a score file\")\n .action(async (score?: string) => {\n await checkCommand(score);\n });\n\nprogram\n .command(\"studio [score]\")\n .description(\"Launch Tutti Studio — local web UI for inspecting agent runs\")\n .action(async (score?: string) => {\n await studioCommand(score);\n });\n\nprogram\n .command(\"search <query>\")\n .description(\"Search the voice registry for voices matching a query\")\n .action(async (query: string) => {\n await searchCommand(query);\n });\n\nprogram\n .command(\"voices\")\n .description(\"List all available official voices and install status\")\n .action(async () => {\n await voicesCommand();\n });\n\nprogram\n .command(\"publish\")\n .description(\"Publish the current voice to npm and the voice registry\")\n .option(\"--dry-run\", \"Run all checks without publishing\")\n .action(async (opts: { dryRun?: boolean }) => {\n await publishCommand(opts);\n });\n\nprogram\n .command(\"eval <suite-file>\")\n .description(\"Run an evaluation suite against a score\")\n .option(\"--ci\", \"Exit with code 1 if any case fails\")\n .option(\"-s, --score <path>\", \"Path to score file (default: ./tutti.score.ts)\")\n .action(async (suitePath: string, opts: { ci?: boolean; score?: string }) => {\n await evalCommand(suitePath, opts);\n });\n\nprogram.parse();\n","import { mkdirSync, writeFileSync, existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport chalk from \"chalk\";\nimport Enquirer from \"enquirer\";\nimport { createLogger } from \"@tuttiai/core\";\nimport { TEMPLATES, getTemplate } from \"../templates/index.js\";\nimport type { Template } from \"../templates/index.js\";\n\nconst logger = createLogger(\"tutti-cli\");\n\nconst { prompt } = Enquirer;\n\nexport async function initCommand(projectName?: string, templateId?: string): Promise<void> {\n if (!projectName) {\n const response = await prompt<{ projectName: string }>({\n type: \"input\",\n name: \"projectName\",\n message: \"Project name?\",\n });\n projectName = response.projectName;\n }\n\n if (!projectName) {\n logger.error(\"Project name is required\");\n process.exit(1);\n }\n\n const dir = join(process.cwd(), projectName);\n\n if (existsSync(dir)) {\n logger.error({ dir: `${projectName}/` }, \"Directory already exists\");\n process.exit(1);\n }\n\n // Resolve template\n let template: Template | undefined;\n if (templateId) {\n template = getTemplate(templateId);\n if (!template) {\n logger.error({ template: templateId }, \"Unknown template\");\n console.error(chalk.dim(\" Available: \" + TEMPLATES.map((t) => t.id).join(\", \")));\n process.exit(1);\n }\n } else {\n // Interactive picker\n const response = await prompt<{ templateId: string }>({\n type: \"select\",\n name: \"templateId\",\n message: \"Which template?\",\n choices: TEMPLATES.map((t) => ({\n name: t.id,\n message: t.name + chalk.dim(\" — \" + t.description),\n })),\n });\n template = getTemplate(response.templateId);\n if (!template) template = TEMPLATES[0];\n }\n\n mkdirSync(dir, { recursive: true });\n\n const deps: Record<string, string> = {\n \"@tuttiai/core\": \"*\",\n \"@tuttiai/types\": \"*\",\n ...template.deps,\n };\n\n const envLines = [\n \"ANTHROPIC_API_KEY=your_key_here\",\n ...template.envVars,\n \"\",\n \"# Log level: debug | info | warn | error (default: info)\",\n \"TUTTI_LOG_LEVEL=info\",\n \"\",\n \"# OpenTelemetry (optional)\",\n \"# OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318\",\n \"# OTEL_SERVICE_NAME=tutti\",\n ];\n\n const files: Record<string, string> = {\n \"package.json\": JSON.stringify(\n {\n name: projectName,\n version: \"0.0.1\",\n type: \"module\",\n scripts: {\n dev: \"tsx watch tutti.score.ts\",\n start: \"tsx tutti.score.ts\",\n },\n dependencies: deps,\n devDependencies: {\n tsx: \"^4.0.0\",\n typescript: \"^5.7.0\",\n },\n },\n null,\n 2,\n ),\n\n \".env.example\": envLines.join(\"\\n\") + \"\\n\",\n\n \".gitignore\": \"node_modules\\ndist\\n.env\\n\",\n\n \"tsconfig.json\": JSON.stringify(\n {\n compilerOptions: {\n strict: true,\n target: \"ES2022\",\n module: \"ES2022\",\n moduleResolution: \"bundler\",\n esModuleInterop: true,\n skipLibCheck: true,\n outDir: \"dist\",\n rootDir: \".\",\n },\n include: [\".\"],\n },\n null,\n 2,\n ),\n\n \"tutti.score.ts\": template.score,\n\n \"README.md\": `# ${projectName}\n\nA Tutti agent project. All agents. All together.\n\n**Template:** ${template.name} — ${template.description}\n\n## Setup\n\n\\`\\`\\`bash\ncp .env.example .env\n# Add your API keys to .env\nnpm install\n\\`\\`\\`\n\n## Run\n\n\\`\\`\\`bash\nnpm run dev\n\\`\\`\\`\n`,\n };\n\n for (const [filename, content] of Object.entries(files)) {\n writeFileSync(join(dir, filename), content);\n }\n\n console.log();\n console.log(chalk.green(` ✔ Created ${projectName}/`) + chalk.dim(` (${template.name})`));\n console.log();\n console.log(\" Next steps:\");\n console.log(chalk.cyan(` cd ${projectName}`));\n console.log(chalk.cyan(\" cp .env.example .env\"));\n console.log(chalk.cyan(\" npm install\"));\n console.log(chalk.cyan(\" npm run dev\"));\n console.log();\n}\n\nexport function templatesCommand(): void {\n console.log();\n console.log(chalk.bold(\" Available Templates\"));\n console.log();\n for (const t of TEMPLATES) {\n console.log(\" \" + chalk.cyan(t.id.padEnd(18)) + t.description);\n }\n console.log();\n console.log(chalk.dim(\" Use: tutti-ai init my-project --template \" + TEMPLATES[0].id));\n console.log();\n}\n","export interface Template {\n id: string;\n name: string;\n description: string;\n deps: Record<string, string>;\n envVars: string[];\n score: string;\n}\n\nconst minimal: Template = {\n id: \"minimal\",\n name: \"Minimal\",\n description: \"One agent, no voices — the simplest starting point\",\n deps: {},\n envVars: [],\n score: `import { defineScore, AnthropicProvider } from \"@tuttiai/core\"\n\nexport default defineScore({\n provider: new AnthropicProvider(),\n default_model: \"claude-sonnet-4-20250514\",\n agents: {\n assistant: {\n name: \"Assistant\",\n system_prompt: \"You are a helpful assistant.\",\n voices: [],\n }\n }\n})\n`,\n};\n\nconst codingAgent: Template = {\n id: \"coding-agent\",\n name: \"Coding Agent\",\n description: \"TypeScript developer with filesystem + GitHub access\",\n deps: { \"@tuttiai/filesystem\": \"*\", \"@tuttiai/github\": \"*\" },\n envVars: [\"GITHUB_TOKEN=ghp_your_token_here\"],\n score: `import { defineScore, AnthropicProvider } from \"@tuttiai/core\"\nimport { FilesystemVoice } from \"@tuttiai/filesystem\"\nimport { GitHubVoice } from \"@tuttiai/github\"\n\nexport default defineScore({\n provider: new AnthropicProvider(),\n default_model: \"claude-sonnet-4-20250514\",\n agents: {\n coder: {\n name: \"Coder\",\n system_prompt:\n \"You are an expert TypeScript developer. \" +\n \"You read and write code using the filesystem voice, \" +\n \"and manage issues and PRs via the GitHub voice. \" +\n \"Write clean, tested, well-documented code.\",\n voices: [new FilesystemVoice(), new GitHubVoice()],\n permissions: [\"filesystem\", \"network\"],\n streaming: true,\n }\n }\n})\n`,\n};\n\nconst researchAgent: Template = {\n id: \"research-agent\",\n name: \"Research Agent\",\n description: \"Researcher that saves structured notes to files\",\n deps: { \"@tuttiai/filesystem\": \"*\" },\n envVars: [],\n score: `import { defineScore, AnthropicProvider } from \"@tuttiai/core\"\nimport { FilesystemVoice } from \"@tuttiai/filesystem\"\n\nexport default defineScore({\n provider: new AnthropicProvider(),\n default_model: \"claude-sonnet-4-20250514\",\n agents: {\n researcher: {\n name: \"Researcher\",\n system_prompt:\n \"You are an expert researcher. \" +\n \"Analyze topics thoroughly, cite sources, and save \" +\n \"structured notes as markdown files using the filesystem voice. \" +\n \"Organize findings with clear headings and bullet points.\",\n voices: [new FilesystemVoice()],\n permissions: [\"filesystem\"],\n streaming: true,\n }\n }\n})\n`,\n};\n\nconst qaPipeline: Template = {\n id: \"qa-pipeline\",\n name: \"QA Pipeline\",\n description: \"Orchestrator + QA specialist with browser testing and HITL\",\n deps: { \"@tuttiai/playwright\": \"*\" },\n envVars: [],\n score: `import { defineScore, AnthropicProvider } from \"@tuttiai/core\"\nimport { PlaywrightVoice } from \"@tuttiai/playwright\"\n\nexport default defineScore({\n provider: new AnthropicProvider(),\n default_model: \"claude-sonnet-4-20250514\",\n entry: \"orchestrator\",\n agents: {\n orchestrator: {\n name: \"QA Lead\",\n system_prompt:\n \"You are a QA lead. Triage incoming bugs by delegating \" +\n \"browser testing to the QA specialist. Use human-in-the-loop \" +\n \"to ask for approval before marking bugs as verified.\",\n voices: [],\n role: \"orchestrator\",\n delegates: [\"qa\"],\n allow_human_input: true,\n streaming: true,\n },\n qa: {\n name: \"QA Specialist\",\n system_prompt:\n \"You are a QA engineer. Navigate to URLs, check elements, \" +\n \"take screenshots, and verify bug reports using the browser.\",\n voices: [new PlaywrightVoice()],\n permissions: [\"network\", \"browser\"],\n role: \"specialist\",\n budget: { max_cost_usd: 0.50, warn_at_percent: 80 },\n streaming: true,\n }\n }\n})\n`,\n};\n\nconst devTeam: Template = {\n id: \"dev-team\",\n name: \"Dev Team\",\n description: \"Full team: orchestrator + coder + PM + QA with all voices\",\n deps: {\n \"@tuttiai/filesystem\": \"*\",\n \"@tuttiai/github\": \"*\",\n \"@tuttiai/playwright\": \"*\",\n },\n envVars: [\"GITHUB_TOKEN=ghp_your_token_here\"],\n score: `import { defineScore, AnthropicProvider, createLoggingHook, createBlocklistHook, createLogger } from \"@tuttiai/core\"\nimport { FilesystemVoice } from \"@tuttiai/filesystem\"\nimport { GitHubVoice } from \"@tuttiai/github\"\nimport { PlaywrightVoice } from \"@tuttiai/playwright\"\n\nconst logger = createLogger(\"dev-team\")\n\nexport default defineScore({\n provider: new AnthropicProvider(),\n default_model: \"claude-sonnet-4-20250514\",\n entry: \"orchestrator\",\n hooks: {\n ...createLoggingHook(logger),\n ...createBlocklistHook([\"delete_file\"]),\n },\n agents: {\n orchestrator: {\n name: \"Tech Lead\",\n system_prompt:\n \"You are the tech lead. Break tasks into subtasks and delegate: \" +\n \"code tasks to Coder, documentation to PM, testing to QA. \" +\n \"Review outputs before presenting to the user.\",\n voices: [],\n role: \"orchestrator\",\n delegates: [\"coder\", \"pm\", \"qa\"],\n allow_human_input: true,\n streaming: true,\n },\n coder: {\n name: \"Coder\",\n system_prompt:\n \"You are a senior TypeScript developer. Write clean, tested code. \" +\n \"Use the filesystem voice to read/write files and GitHub to manage PRs.\",\n voices: [new FilesystemVoice(), new GitHubVoice()],\n permissions: [\"filesystem\", \"network\"],\n role: \"specialist\",\n streaming: true,\n },\n pm: {\n name: \"PM\",\n system_prompt:\n \"You are a product manager. Write specs, update documentation, \" +\n \"and create GitHub issues for tracking. Focus on clarity and completeness.\",\n voices: [new FilesystemVoice(), new GitHubVoice()],\n permissions: [\"filesystem\", \"network\"],\n role: \"specialist\",\n streaming: true,\n },\n qa: {\n name: \"QA\",\n system_prompt:\n \"You are a QA engineer. Test features in the browser, verify bugs, \" +\n \"and write test reports. Screenshot evidence for every finding.\",\n voices: [new PlaywrightVoice()],\n permissions: [\"network\", \"browser\"],\n role: \"specialist\",\n budget: { max_cost_usd: 1.00 },\n streaming: true,\n }\n }\n})\n`,\n};\n\nexport const TEMPLATES: Template[] = [minimal, codingAgent, researchAgent, qaPipeline, devTeam];\n\nexport function getTemplate(id: string): Template | undefined {\n return TEMPLATES.find((t) => t.id === id);\n}\n","import { existsSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport { createInterface } from \"node:readline/promises\";\nimport chalk from \"chalk\";\nimport ora from \"ora\";\nimport {\n TuttiRuntime,\n ScoreLoader,\n AnthropicProvider,\n OpenAIProvider,\n GeminiProvider,\n SecretsManager,\n createLogger,\n} from \"@tuttiai/core\";\n\nconst logger = createLogger(\"tutti-cli\");\n\nexport async function runCommand(scorePath?: string): Promise<void> {\n const file = resolve(scorePath ?? \"./tutti.score.ts\");\n\n if (!existsSync(file)) {\n logger.error({ file }, \"Score file not found\");\n console.error(chalk.dim('Run \"tutti-ai init\" to create a new project.'));\n process.exit(1);\n }\n\n let score;\n try {\n score = await ScoreLoader.load(file);\n } catch (err) {\n logger.error(\n { error: err instanceof Error ? err.message : String(err) },\n \"Failed to load score\",\n );\n process.exit(1);\n }\n\n // Validate that the provider has a valid API key\n const providerKeyMap: [unknown, string][] = [\n [AnthropicProvider, \"ANTHROPIC_API_KEY\"],\n [OpenAIProvider, \"OPENAI_API_KEY\"],\n [GeminiProvider, \"GEMINI_API_KEY\"],\n ];\n\n for (const [ProviderClass, envVar] of providerKeyMap) {\n if (score.provider instanceof (ProviderClass as new (...args: unknown[]) => unknown)) {\n const key = SecretsManager.optional(envVar);\n if (!key) {\n logger.error({ envVar }, \"Missing API key\");\n process.exit(1);\n }\n }\n }\n\n // Enable streaming on all agents\n for (const agent of Object.values(score.agents)) {\n agent.streaming = true;\n }\n\n const runtime = new TuttiRuntime(score);\n const spinner = ora({ color: \"cyan\" });\n\n // Streaming state — reset per run\n let streaming = false;\n\n runtime.events.on(\"agent:start\", (e) => {\n logger.info({ agent: e.agent_name }, \"Running agent\");\n });\n\n runtime.events.on(\"llm:request\", () => {\n spinner.start(\"Thinking...\");\n });\n\n // Token-by-token streaming\n runtime.events.on(\"token:stream\", (e) => {\n if (!streaming) {\n // First token — kill spinner, switch to streaming mode\n spinner.stop();\n streaming = true;\n }\n process.stdout.write(e.text);\n });\n\n runtime.events.on(\"llm:response\", () => {\n if (streaming) {\n // End of a streamed turn — newline after the streamed text\n process.stdout.write(\"\\n\");\n } else {\n // Non-streaming fallback — just stop spinner\n spinner.stop();\n }\n });\n\n // Tool calls during streaming\n runtime.events.on(\"tool:start\", (e) => {\n if (streaming) {\n process.stdout.write(chalk.dim(\"\\n [using: \" + e.tool_name + \"]\"));\n } else {\n spinner.stop();\n console.log(chalk.dim(\" [using: \" + e.tool_name + \"]\"));\n }\n });\n\n runtime.events.on(\"tool:end\", (e) => {\n if (streaming) {\n process.stdout.write(chalk.dim(\" [done: \" + e.tool_name + \"]\\n\"));\n }\n });\n\n runtime.events.on(\"tool:error\", (e) => {\n spinner.stop();\n logger.error({ tool: e.tool_name }, \"Tool error\");\n });\n\n runtime.events.on(\"security:injection_detected\", (e) => {\n logger.warn({ tool: e.tool_name }, \"Potential prompt injection detected\");\n });\n\n runtime.events.on(\"budget:warning\", () => {\n logger.warn(\"Approaching token budget (80%)\");\n });\n\n runtime.events.on(\"budget:exceeded\", () => {\n logger.error(\"Token budget exceeded — stopping\");\n });\n\n // REPL readline — created early so HITL handler can use it\n const rl = createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n\n // Human-in-the-loop — agent pauses and asks the user a question\n runtime.events.on(\"hitl:requested\", (e) => {\n spinner.stop();\n if (streaming) {\n process.stdout.write(\"\\n\");\n streaming = false;\n }\n console.log();\n console.log(chalk.yellow(\" \" + chalk.bold(\"[Agent needs input]\") + \" \" + e.question));\n if (e.options) {\n e.options.forEach((opt, i) => {\n console.log(chalk.yellow(\" \" + (i + 1) + \". \" + opt));\n });\n }\n void rl.question(chalk.yellow(\" > \")).then((answer) => {\n runtime.answer(e.session_id, answer.trim());\n });\n });\n\n // REPL\n console.log(chalk.dim('Tutti REPL — type \"exit\" to quit\\n'));\n\n let sessionId: string | undefined;\n\n // Handle Ctrl+C cleanly\n process.on(\"SIGINT\", () => {\n if (streaming) process.stdout.write(\"\\n\");\n spinner.stop();\n console.log(chalk.dim(\"Goodbye!\"));\n rl.close();\n process.exit(0);\n });\n\n try {\n while (true) {\n const input = await rl.question(chalk.cyan(\"> \"));\n const trimmed = input.trim();\n\n if (!trimmed) continue;\n if (trimmed === \"exit\" || trimmed === \"quit\") break;\n\n // Reset streaming state for this run\n streaming = false;\n\n try {\n const result = await runtime.run(\"assistant\", trimmed, sessionId);\n sessionId = result.session_id;\n\n if (!streaming) {\n // Non-streaming fallback — print the full response\n console.log(\"\\n\" + result.output + \"\\n\");\n } else {\n // Streaming already printed tokens; just add a blank line\n console.log();\n }\n } catch (err) {\n if (streaming) process.stdout.write(\"\\n\");\n spinner.stop();\n logger.error(\n { error: err instanceof Error ? err.message : String(err) },\n \"Something went wrong\",\n );\n }\n }\n } catch {\n // readline closed\n }\n\n console.log(chalk.dim(\"Goodbye!\"));\n rl.close();\n process.exit(0);\n}\n","import { existsSync, readFileSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport { execSync } from \"node:child_process\";\nimport chalk from \"chalk\";\nimport ora from \"ora\";\nimport { createLogger } from \"@tuttiai/core\";\n\nconst logger = createLogger(\"tutti-cli\");\n\nconst OFFICIAL_VOICES: Record<string, { package: string; setup: string }> = {\n filesystem: {\n package: \"@tuttiai/filesystem\",\n setup: ` Add to your score:\n ${chalk.cyan('import { FilesystemVoice } from \"@tuttiai/filesystem\"')}\n ${chalk.cyan(\"voices: [new FilesystemVoice()]\")}`,\n },\n github: {\n package: \"@tuttiai/github\",\n setup: ` Add ${chalk.bold(\"GITHUB_TOKEN\")} to your .env file:\n ${chalk.cyan(\"GITHUB_TOKEN=ghp_your_token_here\")}\n\n Add to your score:\n ${chalk.cyan('import { GitHubVoice } from \"@tuttiai/github\"')}\n ${chalk.cyan(\"voices: [new GitHubVoice()]\")}`,\n },\n playwright: {\n package: \"@tuttiai/playwright\",\n setup: ` Install the browser:\n ${chalk.cyan(\"npx playwright install chromium\")}\n\n Add to your score:\n ${chalk.cyan('import { PlaywrightVoice } from \"@tuttiai/playwright\"')}\n ${chalk.cyan(\"voices: [new PlaywrightVoice()]\")}`,\n },\n postgres: {\n package: \"pg\",\n setup: ` Add ${chalk.bold(\"DATABASE_URL\")} to your .env file:\n ${chalk.cyan(\"DATABASE_URL=postgres://user:pass@localhost:5432/tutti\")}\n\n Add to your score:\n ${chalk.cyan(\"memory: { provider: 'postgres' }\")}\n\n Or with an explicit URL:\n ${chalk.cyan(\"memory: { provider: 'postgres', url: process.env.DATABASE_URL }\")}\n\n Use the async factory for initialization:\n ${chalk.cyan(\"const tutti = await TuttiRuntime.create(score)\")}`,\n },\n};\n\nfunction resolvePackageName(input: string): string {\n // Known official voice\n if (OFFICIAL_VOICES[input]) {\n return OFFICIAL_VOICES[input].package;\n }\n // Already a scoped package\n if (input.startsWith(\"@\")) {\n return input;\n }\n // Try @tuttiai/<name> convention\n return `@tuttiai/${input}`;\n}\n\nfunction isAlreadyInstalled(packageName: string): boolean {\n const pkgPath = resolve(process.cwd(), \"package.json\");\n if (!existsSync(pkgPath)) return false;\n\n try {\n const pkg = JSON.parse(readFileSync(pkgPath, \"utf-8\")) as { dependencies?: Record<string, string>; devDependencies?: Record<string, string> };\n const deps: Record<string, string> = { ...pkg.dependencies, ...pkg.devDependencies };\n return packageName in deps;\n } catch {\n return false;\n }\n}\n\nexport function addCommand(voiceName: string): void {\n const packageName = resolvePackageName(voiceName);\n\n // Check if package.json exists in cwd\n const pkgPath = resolve(process.cwd(), \"package.json\");\n if (!existsSync(pkgPath)) {\n logger.error(\"No package.json found in the current directory\");\n console.error(chalk.dim('Run \"tutti-ai init\" to create a new project first.'));\n process.exit(1);\n }\n\n // Check if already installed\n if (isAlreadyInstalled(packageName)) {\n console.log(chalk.green(` ✔ ${packageName} is already installed`));\n return;\n }\n\n // Install\n const spinner = ora(`Installing ${packageName}...`).start();\n\n try {\n execSync(`npm install ${packageName}`, {\n cwd: process.cwd(),\n stdio: \"pipe\",\n });\n spinner.succeed(`Installed ${packageName}`);\n } catch (error) {\n spinner.fail(`Failed to install ${packageName}`);\n const message = error instanceof Error ? error.message : String(error);\n logger.error({ error: message, package: packageName }, \"Installation failed\");\n process.exit(1);\n }\n\n // Print setup instructions\n const official = OFFICIAL_VOICES[voiceName];\n if (official) {\n console.log();\n console.log(\" Setup:\");\n console.log(official.setup);\n console.log();\n } else {\n console.log();\n console.log(\n chalk.dim(\" Check the package README for setup instructions.\"),\n );\n console.log();\n }\n}\n","import { existsSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport chalk from \"chalk\";\nimport {\n ScoreLoader,\n AnthropicProvider,\n OpenAIProvider,\n GeminiProvider,\n SecretsManager,\n createLogger,\n} from \"@tuttiai/core\";\n\nconst logger = createLogger(\"tutti-cli\");\n\nconst ok = (msg: string) => console.log(chalk.green(\" \\u2714 \" + msg));\nconst fail = (msg: string) => console.log(chalk.red(\" \\u2718 \" + msg));\n\nexport async function checkCommand(scorePath?: string): Promise<void> {\n const file = resolve(scorePath ?? \"./tutti.score.ts\");\n\n console.log(chalk.cyan(`\\nChecking ${file}...\\n`));\n\n if (!existsSync(file)) {\n fail(\"Score file not found: \" + file);\n process.exit(1);\n }\n\n // 1. Load and validate\n let score;\n try {\n score = await ScoreLoader.load(file);\n ok(\"Score file is valid\");\n } catch (err) {\n fail(\"Score validation failed\");\n logger.error(\n { error: err instanceof Error ? err.message : String(err) },\n \"Score validation failed\",\n );\n process.exit(1);\n }\n\n let hasErrors = false;\n\n // 2. Check provider and API key\n const providerChecks: [unknown, string, string][] = [\n [AnthropicProvider, \"AnthropicProvider\", \"ANTHROPIC_API_KEY\"],\n [OpenAIProvider, \"OpenAIProvider\", \"OPENAI_API_KEY\"],\n [GeminiProvider, \"GeminiProvider\", \"GEMINI_API_KEY\"],\n ];\n\n let providerDetected = false;\n for (const [ProviderClass, name, envVar] of providerChecks) {\n if (\n score.provider instanceof\n (ProviderClass as new (...args: unknown[]) => unknown)\n ) {\n providerDetected = true;\n const key = SecretsManager.optional(envVar);\n if (key) {\n ok(\"Provider: \" + name + \" (\" + envVar + \" is set)\");\n } else {\n fail(\"Provider: \" + name + \" (\" + envVar + \" is NOT set)\");\n hasErrors = true;\n }\n }\n }\n\n if (!providerDetected) {\n ok(\"Provider: custom LLMProvider\");\n }\n\n // 3. Count agents\n const agentKeys = Object.keys(score.agents);\n ok(agentKeys.length + \" agent\" + (agentKeys.length === 1 ? \"\" : \"s\") + \" configured\");\n\n // 4. Check voices\n for (const [agentKey, agent] of Object.entries(score.agents)) {\n for (const voice of agent.voices) {\n const voiceName = voice.name;\n\n // Check for known voices and their env vars\n const voiceEnvMap: Record<string, string> = {\n github: \"GITHUB_TOKEN\",\n };\n\n const envVar = voiceEnvMap[voiceName];\n if (envVar) {\n const key = SecretsManager.optional(envVar);\n if (key) {\n ok(\n \"Voice: \" + voiceName + \" on \" + agentKey + \" (\" + envVar + \" is set)\",\n );\n } else {\n fail(\n \"Voice: \" + voiceName + \" on \" + agentKey + \" (\" + envVar + \" is NOT set)\",\n );\n hasErrors = true;\n }\n } else {\n ok(\"Voice: \" + voiceName + \" on \" + agentKey + \" (installed)\");\n }\n }\n }\n\n // Final summary\n console.log(\"\");\n if (hasErrors) {\n console.log(\n chalk.yellow(\"Some checks failed. Fix the issues above and re-run.\"),\n );\n process.exit(1);\n } else {\n console.log(\n chalk.green(\"All checks passed.\") +\n chalk.dim(\" Run tutti-ai run to start.\"),\n );\n }\n}\n","import { existsSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport { execFile } from \"node:child_process\";\nimport express from \"express\";\nimport chalk from \"chalk\";\nimport {\n TuttiRuntime,\n ScoreLoader,\n createLogger,\n} from \"@tuttiai/core\";\nimport type { Response as ExpressResponse } from \"express\";\n\nconst logger = createLogger(\"tutti-studio\");\nconst envPort = Number.parseInt(process.env.PORT ?? \"\", 10);\nconst PORT = Number.isInteger(envPort) && envPort > 0 && envPort <= 65535 ? envPort : 4747;\n\nfunction safeStringify(obj: unknown): string {\n return JSON.stringify(obj, (_key, value: unknown) => {\n if (value instanceof Error) return { message: value.message, name: value.name };\n if (typeof value === \"function\") return undefined;\n return value;\n });\n}\n\nfunction openBrowser(url: string): void {\n if (process.platform === \"win32\") {\n execFile(\"cmd.exe\", [\"/c\", \"start\", \"\", url]);\n return;\n }\n const cmd = process.platform === \"darwin\" ? \"open\" : \"xdg-open\";\n execFile(cmd, [url]);\n}\n\nexport async function studioCommand(scorePath?: string): Promise<void> {\n const file = resolve(scorePath ?? \"./tutti.score.ts\");\n\n if (!existsSync(file)) {\n logger.error({ file }, \"Score file not found\");\n console.error(chalk.dim('Run \"tutti-ai init\" to create a new project.'));\n process.exit(1);\n }\n\n let score;\n try {\n score = await ScoreLoader.load(file);\n } catch (err) {\n logger.error({ error: err instanceof Error ? err.message : String(err) }, \"Failed to load score\");\n process.exit(1);\n }\n\n const runtime = new TuttiRuntime(score);\n\n // Track sessions via events\n const sessionRegistry = new Map<string, { agent_name: string; created_at: Date }>();\n runtime.events.on(\"agent:start\", (e) => {\n if (!sessionRegistry.has(e.session_id)) {\n sessionRegistry.set(e.session_id, { agent_name: e.agent_name, created_at: new Date() });\n }\n });\n\n // SSE clients\n const sseClients = new Set<ExpressResponse>();\n runtime.events.onAny((event) => {\n const data = safeStringify(event);\n for (const client of sseClients) {\n client.write(\"event: tutti\\ndata: \" + data + \"\\n\\n\");\n }\n });\n\n // Express\n const app = express();\n app.use(express.json());\n\n // SSE endpoint\n app.get(\"/events\", (_req, res) => {\n res.writeHead(200, {\n \"Content-Type\": \"text/event-stream\",\n \"Cache-Control\": \"no-cache\",\n Connection: \"keep-alive\",\n });\n res.write(\":\\n\\n\");\n sseClients.add(res);\n _req.on(\"close\", () => sseClients.delete(res));\n });\n\n // REST API\n app.get(\"/api/score\", (_req, res) => {\n const agents = Object.fromEntries(\n Object.entries(runtime.score.agents).map(([id, agent]) => [\n id,\n {\n name: agent.name,\n description: agent.description,\n model: agent.model,\n role: agent.role,\n delegates: agent.delegates,\n voice_count: agent.voices.length,\n voices: agent.voices.map((v) => v.name),\n },\n ]),\n );\n res.json({\n name: runtime.score.name,\n description: runtime.score.description,\n default_model: runtime.score.default_model,\n entry: runtime.score.entry,\n agents,\n });\n });\n\n app.get(\"/api/sessions\", (_req, res) => {\n const sessions = Array.from(sessionRegistry.entries()).map(([id, meta]) => {\n const session = runtime.getSession(id);\n return {\n id,\n agent_name: meta.agent_name,\n message_count: session?.messages.length ?? 0,\n created_at: meta.created_at,\n };\n });\n res.json(sessions.reverse());\n });\n\n app.get(\"/api/sessions/:id\", (req, res) => {\n const session = runtime.getSession(req.params.id);\n if (!session) {\n res.status(404).json({ error: \"Session not found\" });\n return;\n }\n res.json(session);\n });\n\n app.post(\"/api/run\", async (req, res) => {\n const body: unknown = req.body;\n if (typeof body !== \"object\" || body === null) {\n res.status(400).json({ error: \"Invalid request body\" });\n return;\n }\n const agent = (body as Record<string, unknown>).agent;\n const input = (body as Record<string, unknown>).input;\n const session_id = (body as Record<string, unknown>).session_id;\n if (typeof agent !== \"string\" || agent.trim().length === 0) {\n res.status(400).json({ error: \"agent must be a non-empty string\" });\n return;\n }\n if (typeof input !== \"string\" || input.trim().length === 0) {\n res.status(400).json({ error: \"input must be a non-empty string\" });\n return;\n }\n if (session_id !== undefined && (typeof session_id !== \"string\" || session_id.trim().length === 0)) {\n res.status(400).json({ error: \"session_id must be a non-empty string when provided\" });\n return;\n }\n try {\n const result = await runtime.run(agent, input, session_id);\n res.json(result);\n } catch (err) {\n res.status(500).json({ error: err instanceof Error ? err.message : String(err) });\n }\n });\n\n // Serve UI\n app.get(\"/\", (_req, res) => {\n res.type(\"html\").send(getStudioHtml());\n });\n\n app.listen(PORT, () => {\n const url = \"http://localhost:\" + PORT;\n console.log();\n console.log(chalk.bold(\" Tutti Studio\"));\n console.log(chalk.dim(\" \" + url));\n console.log();\n console.log(chalk.dim(\" Score: \") + (runtime.score.name ?? file));\n console.log(chalk.dim(\" Agents: \") + Object.keys(runtime.score.agents).join(\", \"));\n console.log();\n openBrowser(url);\n });\n\n process.on(\"SIGINT\", () => {\n console.log(chalk.dim(\"\\nShutting down Tutti Studio...\"));\n process.exit(0);\n });\n}\n\n// ---------------------------------------------------------------------------\n// Inline HTML UI\n// ---------------------------------------------------------------------------\n\nfunction getStudioHtml(): string {\n return '<!DOCTYPE html>\\\n<html lang=\"en\">\\\n<head>\\\n<meta charset=\"utf-8\">\\\n<meta name=\"viewport\" content=\"width=device-width,initial-scale=1\">\\\n<title>Tutti Studio</title>\\\n<style>\\\n*{margin:0;padding:0;box-sizing:border-box}\\\n:root{\\\n--bg:#0a0a0f;--panel:#12121a;--card:#1a1a26;--input:#0f0f17;\\\n--border:#2a2a3a;--text:#e2e8f0;--muted:#64748b;\\\n--purple:#8b5cf6;--teal:#14b8a6;--blue:#3b82f6;--green:#10b981;\\\n--red:#ef4444;--orange:#f97316;--amber:#f59e0b;--indigo:#6366f1;\\\n}\\\nhtml,body{height:100%;font-family:system-ui,-apple-system,sans-serif;background:var(--bg);color:var(--text);font-size:13px}\\\n#app{display:flex;flex-direction:column;height:100vh}\\\n\\\nheader{display:flex;align-items:center;justify-content:space-between;padding:10px 20px;border-bottom:1px solid var(--border);background:var(--panel)}\\\nheader .logo{font-weight:700;font-size:15px;letter-spacing:.5px}\\\nheader .logo span{color:var(--purple)}\\\nheader .meta{color:var(--muted);font-size:12px}\\\nheader .status{display:flex;align-items:center;gap:6px;font-size:11px;color:var(--muted)}\\\nheader .dot{width:7px;height:7px;border-radius:50%;background:var(--green)}\\\nheader .dot.off{background:var(--red)}\\\n\\\nmain{display:grid;grid-template-columns:260px 1fr 280px;flex:1;overflow:hidden;border-bottom:1px solid var(--border)}\\\n\\\n.panel{display:flex;flex-direction:column;border-right:1px solid var(--border);overflow:hidden}\\\n.panel:last-child{border-right:none}\\\n.panel-title{padding:10px 14px;font-size:11px;font-weight:600;text-transform:uppercase;letter-spacing:.8px;color:var(--muted);border-bottom:1px solid var(--border);background:var(--panel);flex-shrink:0}\\\n.panel-body{flex:1;overflow-y:auto;padding:10px}\\\n.panel-body::-webkit-scrollbar{width:5px}\\\n.panel-body::-webkit-scrollbar-track{background:transparent}\\\n.panel-body::-webkit-scrollbar-thumb{background:var(--border);border-radius:3px}\\\n\\\n#graph-panel .panel-body{padding:0;display:flex;align-items:center;justify-content:center}\\\n#graph-panel svg text{font-family:system-ui,-apple-system,sans-serif}\\\n\\\n#events-panel{display:flex;flex-direction:column}\\\n#event-stream{flex:1;overflow-y:auto;padding:10px}\\\n#event-stream::-webkit-scrollbar{width:5px}\\\n#event-stream::-webkit-scrollbar-track{background:transparent}\\\n#event-stream::-webkit-scrollbar-thumb{background:var(--border);border-radius:3px}\\\n\\\n.ev{padding:7px 10px;margin-bottom:6px;border-radius:6px;background:var(--card);border-left:3px solid var(--muted);font-size:12px;line-height:1.5}\\\n.ev .ev-head{display:flex;justify-content:space-between;align-items:center}\\\n.ev .ev-type{font-weight:600;font-family:\"SF Mono\",Menlo,monospace;font-size:11px}\\\n.ev .ev-time{color:var(--muted);font-size:10px;font-family:\"SF Mono\",Menlo,monospace}\\\n.ev .ev-detail{color:var(--muted);margin-top:3px;font-size:11px;word-break:break-all}\\\n.ev.agent{border-left-color:var(--purple)}.ev.agent .ev-type{color:var(--purple)}\\\n.ev.turn{border-left-color:var(--blue)}.ev.turn .ev-type{color:var(--blue)}\\\n.ev.llm{border-left-color:var(--green)}.ev.llm .ev-type{color:var(--green)}\\\n.ev.tool{border-left-color:var(--teal)}.ev.tool .ev-type{color:var(--teal)}\\\n.ev.tool-error{border-left-color:var(--red)}.ev.tool-error .ev-type{color:var(--red)}\\\n.ev.security{border-left-color:var(--orange)}.ev.security .ev-type{color:var(--orange)}\\\n.ev.budget-warn{border-left-color:var(--amber)}.ev.budget-warn .ev-type{color:var(--amber)}\\\n.ev.budget-exceed{border-left-color:var(--red)}.ev.budget-exceed .ev-type{color:var(--red)}\\\n.ev.delegate{border-left-color:var(--indigo)}.ev.delegate .ev-type{color:var(--indigo)}\\\n\\\n#input-bar{display:flex;gap:8px;padding:10px 12px;border-top:1px solid var(--border);background:var(--panel);flex-shrink:0}\\\n#agent-select{background:var(--input);color:var(--text);border:1px solid var(--border);border-radius:6px;padding:6px 10px;font-size:12px;outline:none;cursor:pointer;min-width:110px}\\\n#user-input{flex:1;background:var(--input);color:var(--text);border:1px solid var(--border);border-radius:6px;padding:6px 12px;font-size:13px;outline:none}\\\n#user-input:focus{border-color:var(--purple)}\\\n#send-btn{background:var(--purple);color:#fff;border:none;border-radius:6px;padding:6px 16px;font-size:12px;font-weight:600;cursor:pointer;white-space:nowrap}\\\n#send-btn:hover{opacity:.9}\\\n#send-btn:disabled{opacity:.4;cursor:default}\\\n\\\n.session-item{padding:8px 10px;margin-bottom:4px;border-radius:6px;background:var(--card);cursor:pointer;transition:background .15s}\\\n.session-item:hover{background:#22223a}\\\n.session-item.active{background:#22223a;border:1px solid var(--purple)}\\\n.session-id{font-family:\"SF Mono\",Menlo,monospace;font-size:11px;color:var(--purple)}\\\n.session-meta{font-size:11px;color:var(--muted);margin-top:2px}\\\n\\\n#session-detail{margin-top:10px;border-top:1px solid var(--border);padding-top:10px}\\\n.msg{padding:6px 8px;margin-bottom:4px;border-radius:5px;font-size:12px;line-height:1.5;word-break:break-word}\\\n.msg.user{background:#1c1c3a;border-left:2px solid var(--blue)}\\\n.msg.assistant{background:#1a2a1a;border-left:2px solid var(--green)}\\\n.msg .msg-role{font-size:10px;font-weight:600;text-transform:uppercase;letter-spacing:.5px;margin-bottom:2px}\\\n.msg.user .msg-role{color:var(--blue)}\\\n.msg.assistant .msg-role{color:var(--green)}\\\n\\\nfooter{display:flex;align-items:center;gap:32px;padding:8px 20px;background:var(--panel);font-size:12px}\\\n.token-item{display:flex;align-items:center;gap:6px}\\\n.token-label{color:var(--muted)}\\\n.token-val{font-family:\"SF Mono\",Menlo,monospace;font-weight:600}\\\n.token-val.input{color:var(--blue)}\\\n.token-val.output{color:var(--green)}\\\n.token-val.cost{color:var(--amber)}\\\n\\\n.empty{color:var(--muted);text-align:center;padding:30px 10px;font-size:12px}\\\n</style>\\\n</head>\\\n<body>\\\n<div id=\"app\">\\\n\\\n<header>\\\n <div class=\"logo\"><span>♫</span> Tutti Studio</div>\\\n <div class=\"meta\" id=\"score-name\"></div>\\\n <div class=\"status\"><div class=\"dot\" id=\"sse-dot\"></div><span id=\"sse-label\">connecting</span></div>\\\n</header>\\\n\\\n<main>\\\n <div class=\"panel\" id=\"graph-panel\">\\\n <div class=\"panel-title\">Agent Graph</div>\\\n <div class=\"panel-body\" id=\"graph-body\"></div>\\\n </div>\\\n\\\n <div class=\"panel\" id=\"events-panel\">\\\n <div class=\"panel-title\">Live Event Stream</div>\\\n <div id=\"event-stream\"><div class=\"empty\">Waiting for events…<br>Send a message below to start an agent run.</div></div>\\\n <div id=\"input-bar\">\\\n <select id=\"agent-select\"></select>\\\n <input id=\"user-input\" placeholder=\"Type a message…\" autocomplete=\"off\">\\\n <button id=\"send-btn\">Send</button>\\\n </div>\\\n </div>\\\n\\\n <div class=\"panel\" id=\"sessions-panel\">\\\n <div class=\"panel-title\">Sessions</div>\\\n <div class=\"panel-body\" id=\"sessions-body\"><div class=\"empty\">No sessions yet</div></div>\\\n </div>\\\n</main>\\\n\\\n<footer>\\\n <div class=\"token-item\"><span class=\"token-label\">↓ Input</span><span class=\"token-val input\" id=\"tok-in\">0</span></div>\\\n <div class=\"token-item\"><span class=\"token-label\">↑ Output</span><span class=\"token-val output\" id=\"tok-out\">0</span></div>\\\n <div class=\"token-item\"><span class=\"token-label\">$ Est. cost</span><span class=\"token-val cost\" id=\"tok-cost\">0.0000</span></div>\\\n</footer>\\\n\\\n</div>\\\n\\\n<script>\\\n(function(){\\\n\\\nvar tokIn=0,tokOut=0;\\\nvar sessionMap={};\\\nvar activeSession=null;\\\n\\\n/* ---- helpers ---- */\\\nfunction esc(s){var d=document.createElement(\"div\");d.textContent=s;return d.innerHTML}\\\nfunction fmt(n){return n.toLocaleString()}\\\nfunction timeStr(){var d=new Date();return (\"0\"+d.getHours()).slice(-2)+\":\"+(\"0\"+d.getMinutes()).slice(-2)+\":\"+(\"0\"+d.getSeconds()).slice(-2)}\\\nfunction truncId(id){return id.slice(0,8)}\\\n\\\n/* ---- score + graph ---- */\\\nfunction loadScore(){\\\n fetch(\"/api/score\").then(function(r){return r.json()}).then(function(s){\\\n document.getElementById(\"score-name\").textContent=s.name||\"tutti.score.ts\";\\\n var sel=document.getElementById(\"agent-select\");\\\n sel.innerHTML=\"\";\\\n Object.keys(s.agents).forEach(function(id){\\\n var o=document.createElement(\"option\");o.value=id;o.textContent=s.agents[id].name;sel.appendChild(o);\\\n });\\\n renderGraph(s);\\\n });\\\n}\\\n\\\nfunction renderGraph(score){\\\n var body=document.getElementById(\"graph-body\");\\\n var W=260,ids=Object.keys(score.agents),N=ids.length;\\\n if(N===0){body.innerHTML=\"<div class=\\\\\"empty\\\\\">No agents</div>\";return}\\\n var hasDelegate=false;\\\n ids.forEach(function(id){if(score.agents[id].delegates&&score.agents[id].delegates.length)hasDelegate=true});\\\n var nodeR=26,padY=90,padTop=50;\\\n var leftIds=[],rightIds=[];\\\n if(hasDelegate){\\\n ids.forEach(function(id){var a=score.agents[id];if(a.delegates&&a.delegates.length)leftIds.push(id);else rightIds.push(id)});\\\n }else{leftIds=ids}\\\n var cols=hasDelegate?2:1;\\\n var cx1=cols===1?W/2:72,cx2=W-72;\\\n var H=Math.max(leftIds.length,rightIds.length)*padY+padTop*2;\\\n if(H<200)H=200;\\\n var pos={};\\\n var svg=\\'<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"\\'+W+\\'\" height=\"\\'+H+\\'\" viewBox=\"0 0 \\'+W+\" \"+H+\\'\">\\';\\\n svg+=\\'<defs><marker id=\"ah\" viewBox=\"0 0 10 10\" refX=\"10\" refY=\"5\" markerWidth=\"5\" markerHeight=\"5\" orient=\"auto\"><path d=\"M0 0L10 5L0 10z\" fill=\"#64748b\"/></marker></defs>\\';\\\n function drawNode(id,cx,cy){\\\n var a=score.agents[id];\\\n var col=a.role===\"orchestrator\"?\"#8b5cf6\":\"#14b8a6\";\\\n pos[id]={x:cx,y:cy};\\\n svg+=\\'<circle cx=\"\\'+cx+\\'\" cy=\"\\'+cy+\\'\" r=\"\\'+nodeR+\\'\" fill=\"\\'+col+\\'\" fill-opacity=\"0.15\" stroke=\"\\'+col+\\'\" stroke-width=\"2\"/>\\';\\\n svg+=\\'<text x=\"\\'+cx+\\'\" y=\"\\'+(cy+4)+\\'\" text-anchor=\"middle\" fill=\"#e2e8f0\" font-size=\"10\" font-weight=\"600\">\\'+esc(a.name)+\\'</text>\\';\\\n var model=a.model||score.default_model||\"\";\\\n if(model){var sh=model.replace(/-\\\\d{8}$/,\"\");if(sh.length>18)sh=sh.slice(0,18)+\"\\\\u2026\";svg+=\\'<text x=\"\\'+cx+\\'\" y=\"\\'+(cy+nodeR+14)+\\'\" text-anchor=\"middle\" fill=\"#64748b\" font-size=\"9\">\\'+esc(sh)+\\'</text>\\'}\\\n svg+=\\'<text x=\"\\'+cx+\\'\" y=\"\\'+(cy+nodeR+26)+\\'\" text-anchor=\"middle\" fill=\"#64748b\" font-size=\"9\">\\'+a.voice_count+\" voice\"+(a.voice_count!==1?\"s\":\"\")+\\'</text>\\';\\\n }\\\n leftIds.forEach(function(id,i){drawNode(id,cx1,padTop+i*padY)});\\\n rightIds.forEach(function(id,i){drawNode(id,cx2,padTop+i*padY)});\\\n ids.forEach(function(id){\\\n var a=score.agents[id];\\\n if(a.delegates)a.delegates.forEach(function(did){\\\n if(pos[id]&&pos[did]){\\\n var x1=pos[id].x+nodeR,y1=pos[id].y,x2=pos[did].x-nodeR,y2=pos[did].y;\\\n var mx=(x1+x2)/2;\\\n svg+=\\'<path d=\"M\\'+x1+\" \"+y1+\" C\"+mx+\" \"+y1+\" \"+mx+\" \"+y2+\" \"+x2+\" \"+y2+\\'\" fill=\"none\" stroke=\"#64748b\" stroke-width=\"1.5\" stroke-dasharray=\"4 3\" marker-end=\"url(#ah)\"/>\\';\\\n }\\\n });\\\n });\\\n svg+=\"</svg>\";\\\n body.innerHTML=svg;\\\n}\\\n\\\n/* ---- SSE ---- */\\\nfunction connectSSE(){\\\n var es=new EventSource(\"/events\");\\\n es.addEventListener(\"tutti\",function(e){\\\n var ev=JSON.parse(e.data);\\\n addEvent(ev);\\\n if(ev.type===\"llm:response\"&&ev.response&&ev.response.usage){\\\n tokIn+=ev.response.usage.input_tokens||0;\\\n tokOut+=ev.response.usage.output_tokens||0;\\\n document.getElementById(\"tok-in\").textContent=fmt(tokIn);\\\n document.getElementById(\"tok-out\").textContent=fmt(tokOut);\\\n document.getElementById(\"tok-cost\").textContent=estimateCost(tokIn,tokOut);\\\n }\\\n if(ev.type===\"agent:start\"||ev.type===\"agent:end\")refreshSessions();\\\n });\\\n es.onopen=function(){document.getElementById(\"sse-dot\").className=\"dot\";document.getElementById(\"sse-label\").textContent=\"connected\"};\\\n es.onerror=function(){document.getElementById(\"sse-dot\").className=\"dot off\";document.getElementById(\"sse-label\").textContent=\"disconnected\"};\\\n}\\\n\\\n/* Pricing: USD per 1M tokens (Sonnet-class default) */\\\nvar INPUT_PRICE_PER_MILLION=3;\\\nvar OUTPUT_PRICE_PER_MILLION=15;\\\nfunction estimateCost(inp,out){\\\n var c=(inp/1e6)*INPUT_PRICE_PER_MILLION+(out/1e6)*OUTPUT_PRICE_PER_MILLION;\\\n return c.toFixed(4);\\\n}\\\n\\\nfunction evClass(t){\\\n if(t.indexOf(\"agent\")===0)return \"agent\";\\\n if(t.indexOf(\"turn\")===0)return \"turn\";\\\n if(t===\"llm:request\"||t===\"llm:response\")return \"llm\";\\\n if(t===\"tool:error\")return \"tool-error\";\\\n if(t.indexOf(\"tool\")===0)return \"tool\";\\\n if(t.indexOf(\"security\")===0)return \"security\";\\\n if(t===\"budget:warning\")return \"budget-warn\";\\\n if(t===\"budget:exceeded\")return \"budget-exceed\";\\\n if(t.indexOf(\"delegate\")===0)return \"delegate\";\\\n return \"\";\\\n}\\\n\\\nfunction evDetail(ev){\\\n var parts=[];\\\n if(ev.agent_name)parts.push(\"agent: \"+ev.agent_name);\\\n if(ev.session_id)parts.push(\"session: \"+truncId(ev.session_id));\\\n if(ev.turn!==undefined)parts.push(\"turn: \"+ev.turn);\\\n if(ev.tool_name)parts.push(\"tool: \"+ev.tool_name);\\\n if(ev.from)parts.push(\"from: \"+ev.from);\\\n if(ev.to)parts.push(\"to: \"+ev.to);\\\n if(ev.tokens!==undefined)parts.push(\"tokens: \"+fmt(ev.tokens));\\\n if(ev.cost_usd!==undefined)parts.push(\"cost: $\"+ev.cost_usd.toFixed(4));\\\n if(ev.response&&ev.response.usage)parts.push(\"tokens: \"+fmt(ev.response.usage.input_tokens)+\" in / \"+fmt(ev.response.usage.output_tokens)+\" out\");\\\n if(ev.error){var em=typeof ev.error===\"object\"?ev.error.message||\"\":ev.error;if(em)parts.push(\"error: \"+em)}\\\n if(ev.patterns)parts.push(\"patterns: \"+ev.patterns.join(\", \"));\\\n return parts.join(\" · \");\\\n}\\\n\\\nvar firstEvent=true;\\\nfunction addEvent(ev){\\\n var stream=document.getElementById(\"event-stream\");\\\n if(firstEvent){stream.innerHTML=\"\";firstEvent=false}\\\n var div=document.createElement(\"div\");\\\n div.className=\"ev \"+evClass(ev.type);\\\n div.innerHTML=\\'<div class=\"ev-head\"><span class=\"ev-type\">\\'+esc(ev.type)+\\'</span><span class=\"ev-time\">\\'+timeStr()+\\'</span></div>\\';\\\n var det=evDetail(ev);\\\n if(det)div.innerHTML+=\\'<div class=\"ev-detail\">\\'+det+\"</div>\";\\\n stream.appendChild(div);\\\n stream.scrollTop=stream.scrollHeight;\\\n}\\\n\\\n/* ---- sessions ---- */\\\nfunction refreshSessions(){\\\n fetch(\"/api/sessions\").then(function(r){return r.json()}).then(function(list){\\\n var body=document.getElementById(\"sessions-body\");\\\n if(!list.length){body.innerHTML=\\'<div class=\"empty\">No sessions yet</div>\\';return}\\\n var html=\"\";\\\n list.forEach(function(s){\\\n var cls=\"session-item\"+(activeSession===s.id?\" active\":\"\");\\\n html+=\\'<div class=\"\\'+cls+\\'\" data-id=\"\\'+s.id+\\'\">\\';\\\n html+=\\'<div class=\"session-id\">\\'+truncId(s.id)+\"</div>\";\\\n html+=\\'<div class=\"session-meta\">\\'+esc(s.agent_name)+\" · \"+s.message_count+\" msgs</div>\";\\\n html+=\"</div>\";\\\n });\\\n if(activeSession)html+=\\'<div id=\"session-detail\"></div>\\';\\\n body.innerHTML=html;\\\n body.querySelectorAll(\".session-item\").forEach(function(el){\\\n el.addEventListener(\"click\",function(){selectSession(el.getAttribute(\"data-id\"))});\\\n });\\\n if(activeSession)loadSessionDetail(activeSession);\\\n });\\\n}\\\n\\\nfunction selectSession(id){\\\n activeSession=activeSession===id?null:id;\\\n refreshSessions();\\\n}\\\n\\\nfunction loadSessionDetail(id){\\\n var det=document.getElementById(\"session-detail\");\\\n if(!det)return;\\\n fetch(\"/api/sessions/\"+id).then(function(r){return r.json()}).then(function(session){\\\n if(!session||session.error){det.innerHTML=\\'<div class=\"empty\">Session not found</div>\\';return}\\\n var html=\"\";\\\n (session.messages||[]).forEach(function(m){\\\n var role=m.role;\\\n var text=\"\";\\\n if(typeof m.content===\"string\")text=m.content;\\\n else if(Array.isArray(m.content)){\\\n m.content.forEach(function(b){\\\n if(b.type===\"text\")text+=b.text+\"\\\\n\";\\\n else if(b.type===\"tool_use\")text+=\"[tool_use: \"+b.name+\"]\\\\n\";\\\n else if(b.type===\"tool_result\")text+=\"[tool_result]\\\\n\";\\\n });\\\n }\\\n html+=\\'<div class=\"msg \\'+role+\\'\"><div class=\"msg-role\">\\'+role+\"</div>\"+esc(text.trim())+\"</div>\";\\\n });\\\n det.innerHTML=html;\\\n });\\\n}\\\n\\\n/* ---- send ---- */\\\nfunction sendMessage(){\\\n var agentSel=document.getElementById(\"agent-select\");\\\n var inputEl=document.getElementById(\"user-input\");\\\n var btn=document.getElementById(\"send-btn\");\\\n var agent=agentSel.value;\\\n var input=inputEl.value.trim();\\\n if(!input)return;\\\n btn.disabled=true;btn.textContent=\"Running\\\\u2026\";\\\n inputEl.value=\"\";\\\n var sid=sessionMap[agent]||undefined;\\\n fetch(\"/api/run\",{method:\"POST\",headers:{\"Content-Type\":\"application/json\"},body:JSON.stringify({agent:agent,input:input,session_id:sid})})\\\n .then(function(r){return r.json()})\\\n .then(function(result){\\\n if(result.session_id)sessionMap[agent]=result.session_id;\\\n if(result.output){\\\n addEvent({type:\"__output\",agent_name:agent,output:result.output});\\\n }\\\n refreshSessions();\\\n })\\\n .catch(function(err){addEvent({type:\"__error\",error:err.message||String(err)})})\\\n .finally(function(){btn.disabled=false;btn.textContent=\"Send\"});\\\n}\\\n\\\ndocument.getElementById(\"send-btn\").addEventListener(\"click\",sendMessage);\\\ndocument.getElementById(\"user-input\").addEventListener(\"keydown\",function(e){if(e.key===\"Enter\"&&!e.shiftKey){e.preventDefault();sendMessage()}});\\\n\\\n/* ---- init ---- */\\\nloadScore();\\\nconnectSSE();\\\n\\\n})();\\\n</script>\\\n</body>\\\n</html>';\n}\n","import { existsSync, readFileSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport chalk from \"chalk\";\nimport ora from \"ora\";\nimport { createLogger } from \"@tuttiai/core\";\n\nconst logger = createLogger(\"tutti-cli\");\n\nconst REGISTRY_URL =\n \"https://raw.githubusercontent.com/tuttiai/voices/main/voices.json\";\n\ninterface VoiceEntry {\n name: string;\n package: string;\n description: string;\n tags: string[];\n official: boolean;\n tools: number;\n}\n\n// Built-in fallback when the remote registry is unreachable\nconst BUILTIN_VOICES: VoiceEntry[] = [\n {\n name: \"filesystem\",\n package: \"@tuttiai/filesystem\",\n description: \"Read, write, search, and manage files and directories\",\n tags: [\"filesystem\", \"files\", \"io\", \"read\", \"write\"],\n official: true,\n tools: 7,\n },\n {\n name: \"github\",\n package: \"@tuttiai/github\",\n description: \"Interact with GitHub repos, issues, PRs, and code search\",\n tags: [\"github\", \"git\", \"code\", \"issues\", \"pull-requests\", \"api\"],\n official: true,\n tools: 10,\n },\n {\n name: \"playwright\",\n package: \"@tuttiai/playwright\",\n description: \"Control a browser like a human — navigate, click, type, screenshot\",\n tags: [\"browser\", \"playwright\", \"web\", \"qa\", \"testing\", \"automation\", \"scraping\"],\n official: true,\n tools: 12,\n },\n {\n name: \"postgres\",\n package: \"pg\",\n description: \"PostgreSQL session persistence and database access\",\n tags: [\"database\", \"postgres\", \"sql\", \"persistence\", \"sessions\"],\n official: true,\n tools: 0,\n },\n];\n\ninterface RegistryEntry {\n name: string;\n package: string;\n description: string;\n tags: string[];\n}\n\nasync function fetchRegistry(): Promise<VoiceEntry[]> {\n try {\n const res = await fetch(REGISTRY_URL);\n if (!res.ok) throw new Error(\"HTTP \" + res.status);\n const data = (await res.json()) as { official?: RegistryEntry[]; community?: RegistryEntry[] };\n\n const voices: VoiceEntry[] = [];\n for (const entry of data.official ?? []) {\n voices.push({ ...entry, official: true, tools: toolCount(entry.name) });\n }\n for (const entry of data.community ?? []) {\n voices.push({ ...entry, official: false, tools: 0 });\n }\n if (voices.length === 0) throw new Error(\"Empty registry\");\n return voices;\n } catch {\n logger.debug(\"Registry unreachable, using built-in voice list\");\n return BUILTIN_VOICES;\n }\n}\n\nfunction toolCount(name: string): number {\n const counts: Record<string, number> = { filesystem: 7, github: 10, playwright: 12 };\n return counts[name] ?? 0;\n}\n\nfunction matchesQuery(voice: VoiceEntry, query: string): boolean {\n const q = query.toLowerCase();\n if (voice.name.toLowerCase().includes(q)) return true;\n if (voice.description.toLowerCase().includes(q)) return true;\n if (voice.tags.some((t) => t.toLowerCase().includes(q))) return true;\n return false;\n}\n\nfunction isInstalled(packageName: string): boolean {\n const pkgPath = resolve(process.cwd(), \"package.json\");\n if (!existsSync(pkgPath)) return false;\n try {\n const pkg = JSON.parse(readFileSync(pkgPath, \"utf-8\")) as { dependencies?: Record<string, string>; devDependencies?: Record<string, string> };\n const deps: Record<string, string> = { ...pkg.dependencies, ...pkg.devDependencies };\n return packageName in deps;\n } catch {\n return false;\n }\n}\n\nfunction printVoice(voice: VoiceEntry, showInstallStatus: boolean): void {\n const badge = voice.official\n ? chalk.green(\" [official]\")\n : chalk.blue(\" [community]\");\n const installed = showInstallStatus && isInstalled(voice.package);\n const status = showInstallStatus\n ? installed\n ? chalk.green(\" ✔ installed\")\n : chalk.dim(\" not installed\")\n : \"\";\n\n console.log();\n console.log(\" \" + chalk.bold(voice.package) + badge + status);\n console.log(\" \" + voice.description);\n\n const installCmd = voice.official && voice.name !== \"postgres\"\n ? \"tutti-ai add \" + voice.name\n : \"npm install \" + voice.package;\n console.log(\" \" + chalk.dim(\"Install: \") + chalk.cyan(installCmd));\n\n if (voice.tags.length > 0) {\n console.log(\" \" + chalk.dim(\"Tags: \") + voice.tags.join(\", \"));\n }\n}\n\nexport async function searchCommand(query: string): Promise<void> {\n const spinner = ora(\"Searching the Repertoire...\").start();\n\n const voices = await fetchRegistry();\n const results = voices.filter((v) => matchesQuery(v, query));\n\n spinner.stop();\n\n if (results.length === 0) {\n console.log();\n console.log(chalk.yellow(' No voices found for \"' + query + '\"'));\n console.log();\n console.log(chalk.dim(\" Browse all: https://tutti-ai.com/voices\"));\n console.log(chalk.dim(\" Build your own: tutti-ai create voice <name>\"));\n console.log();\n return;\n }\n\n console.log();\n console.log(\n \" Found \" +\n chalk.bold(String(results.length)) +\n \" voice\" +\n (results.length !== 1 ? \"s\" : \"\") +\n \" matching \" +\n chalk.cyan(\"'\" + query + \"'\") +\n \":\",\n );\n\n for (const voice of results) {\n printVoice(voice, false);\n }\n console.log();\n}\n\nexport async function voicesCommand(): Promise<void> {\n const spinner = ora(\"Loading voices...\").start();\n\n const voices = await fetchRegistry();\n const official = voices.filter((v) => v.official);\n\n spinner.stop();\n\n console.log();\n console.log(\" \" + chalk.bold(\"Official Tutti Voices\"));\n console.log();\n\n for (const voice of official) {\n printVoice(voice, true);\n }\n\n const community = voices.filter((v) => !v.official);\n if (community.length > 0) {\n console.log();\n console.log(\" \" + chalk.bold(\"Community Voices\"));\n for (const voice of community) {\n printVoice(voice, true);\n }\n }\n\n console.log();\n console.log(chalk.dim(\" Search: tutti-ai search <query>\"));\n console.log(chalk.dim(\" Browse: https://tutti-ai.com/voices\"));\n console.log();\n}\n","import { existsSync, readFileSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport { execSync } from \"node:child_process\";\nimport chalk from \"chalk\";\nimport ora from \"ora\";\nimport Enquirer from \"enquirer\";\nimport { createLogger, SecretsManager } from \"@tuttiai/core\";\n\nconst { prompt } = Enquirer;\nconst logger = createLogger(\"tutti-cli\");\n\ninterface PkgJson {\n name?: string;\n version?: string;\n description?: string;\n license?: string;\n exports?: unknown;\n}\n\nfunction readPkg(dir: string): PkgJson | undefined {\n const p = resolve(dir, \"package.json\");\n if (!existsSync(p)) return undefined;\n return JSON.parse(readFileSync(p, \"utf-8\")) as PkgJson;\n}\n\nfunction run(cmd: string, cwd: string): string {\n return execSync(cmd, { cwd, stdio: \"pipe\", encoding: \"utf-8\" });\n}\n\nfunction fail(msg: string): never {\n console.error(chalk.red(\" \" + msg));\n process.exit(1);\n}\n\nconst ok = (msg: string) => console.log(chalk.green(\" ✔ \" + msg));\n\nexport async function publishCommand(opts: { dryRun?: boolean }): Promise<void> {\n const cwd = process.cwd();\n const pkg = readPkg(cwd);\n\n console.log();\n console.log(chalk.bold(\" Tutti Voice Publisher\"));\n console.log();\n\n // ── Step 1: Pre-flight checks ──\n\n const spinner = ora(\"Running pre-flight checks...\").start();\n\n // 1a. Must be a voice directory\n if (!pkg) fail(\"No package.json found in the current directory.\");\n if (!existsSync(resolve(cwd, \"src/index.ts\"))) fail(\"No src/index.ts found — are you inside a voice directory?\");\n\n // 1b. Required fields\n const missing: string[] = [];\n if (!pkg.name) missing.push(\"name\");\n if (!pkg.version) missing.push(\"version\");\n if (!pkg.description) missing.push(\"description\");\n if (!pkg.license) missing.push(\"license\");\n if (!pkg.exports) missing.push(\"exports\");\n if (missing.length > 0) fail(\"package.json is missing: \" + missing.join(\", \"));\n\n const name = pkg.name!;\n const version = pkg.version!;\n\n // 1c. Name convention\n const validName = name.startsWith(\"@tuttiai/\") || name.startsWith(\"tutti\");\n if (!validName) fail(\"Package name must start with @tuttiai/ or tutti — got: \" + name);\n\n // 1d. Check required_permissions is declared in source\n const src = readFileSync(resolve(cwd, \"src/index.ts\"), \"utf-8\");\n if (!src.includes(\"required_permissions\")) {\n fail(\"Voice class must declare required_permissions in src/index.ts\");\n }\n\n spinner.succeed(\"Pre-flight checks passed\");\n\n // 1e. Build\n const buildSpinner = ora(\"Building...\").start();\n try {\n run(\"npm run build\", cwd);\n buildSpinner.succeed(\"Build succeeded\");\n } catch (err) {\n buildSpinner.fail(\"Build failed\");\n const msg = err instanceof Error ? err.message : String(err);\n console.error(chalk.dim(\" \" + msg.split(\"\\n\").slice(0, 5).join(\"\\n \")));\n process.exit(1);\n }\n\n // 1f. Tests\n const testSpinner = ora(\"Running tests...\").start();\n try {\n run(\"npx vitest run\", cwd);\n testSpinner.succeed(\"Tests passed\");\n } catch {\n testSpinner.fail(\"Tests failed\");\n process.exit(1);\n }\n\n // 1g. Audit\n const auditSpinner = ora(\"Checking vulnerabilities...\").start();\n try {\n run(\"npm audit --audit-level=high\", cwd);\n auditSpinner.succeed(\"No high/critical vulnerabilities\");\n } catch {\n auditSpinner.stopAndPersist({ symbol: chalk.yellow(\"⚠\"), text: \"Vulnerabilities found (npm audit)\" });\n }\n\n // ── Step 2: Dry run ──\n\n console.log();\n const drySpinner = ora(\"Packing (dry run)...\").start();\n let packOutput: string;\n try {\n packOutput = run(\"npm pack --dry-run 2>&1\", cwd);\n drySpinner.succeed(\"Pack dry-run complete\");\n } catch (err) {\n drySpinner.fail(\"Pack dry-run failed\");\n const msg = err instanceof Error ? err.message : String(err);\n console.error(chalk.dim(\" \" + msg));\n process.exit(1);\n }\n\n // Show files from the pack output\n const fileLines = packOutput\n .split(\"\\n\")\n .filter((l) => l.includes(\"npm notice\") && /\\d+(\\.\\d+)?\\s*[kM]?B\\s/.test(l))\n .map((l) => l.replace(/npm notice\\s*/, \"\"));\n\n if (fileLines.length > 0) {\n console.log(chalk.dim(\" Files:\"));\n for (const line of fileLines) {\n console.log(chalk.dim(\" \" + line.trim()));\n }\n }\n\n // Show totals\n const sizeLine = packOutput.split(\"\\n\").find((l) => l.includes(\"package size\"));\n const totalLine = packOutput.split(\"\\n\").find((l) => l.includes(\"total files\"));\n if (sizeLine) console.log(chalk.dim(\" \" + sizeLine.replace(/npm notice\\s*/, \"\").trim()));\n if (totalLine) console.log(chalk.dim(\" \" + totalLine.replace(/npm notice\\s*/, \"\").trim()));\n\n if (opts.dryRun) {\n console.log();\n ok(\"Dry run complete — no packages were published\");\n console.log(chalk.dim(\" Run without --dry-run to publish for real.\"));\n console.log();\n return;\n }\n\n // Prompt for confirmation\n console.log();\n const { confirm } = await prompt<{ confirm: boolean }>({\n type: \"confirm\",\n name: \"confirm\",\n message: \"Publish \" + chalk.cyan(name + \"@\" + version) + \"?\",\n });\n\n if (!confirm) {\n console.log(chalk.dim(\" Cancelled.\"));\n return;\n }\n\n // ── Step 3: Publish ──\n\n const pubSpinner = ora(\"Publishing to npm...\").start();\n try {\n run(\"npm publish --access public\", cwd);\n pubSpinner.succeed(\"Published \" + chalk.cyan(name + \"@\" + version));\n } catch (err) {\n pubSpinner.fail(\"Publish failed\");\n const msg = err instanceof Error ? err.message : String(err);\n logger.error({ error: msg }, \"npm publish failed\");\n process.exit(1);\n }\n\n // ── Step 4: Open PR to voice registry ──\n\n const ghToken = SecretsManager.optional(\"GITHUB_TOKEN\");\n let prUrl: string | undefined;\n\n if (ghToken) {\n const prSpinner = ora(\"Opening PR to voice registry...\").start();\n try {\n prUrl = await openRegistryPR(name, version, pkg.description ?? \"\", ghToken);\n prSpinner.succeed(\"PR opened: \" + prUrl);\n } catch (err) {\n prSpinner.fail(\"Failed to open PR\");\n const msg = err instanceof Error ? err.message : String(err);\n logger.error({ error: msg }, \"Registry PR failed\");\n }\n } else {\n console.log();\n console.log(chalk.dim(\" To list in the Repertoire, set GITHUB_TOKEN and re-run\"));\n console.log(chalk.dim(\" Or open a PR manually: github.com/tuttiai/voices\"));\n }\n\n // ── Step 5: Summary ──\n\n console.log();\n ok(name + \"@\" + version + \" published to npm\");\n if (prUrl) ok(\"PR opened to tuttiai/voices\");\n const shortName = name.replace(\"@tuttiai/\", \"\").replace(/^tutti-?/, \"\");\n ok(\"Install: tutti-ai add \" + shortName);\n ok(\"View: https://www.npmjs.com/package/\" + name);\n console.log();\n}\n\nasync function openRegistryPR(\n packageName: string,\n version: string,\n description: string,\n token: string,\n): Promise<string> {\n const owner = \"tuttiai\";\n const repo = \"voices\";\n const branch = \"add-\" + packageName.replace(/[@/]/g, \"-\").replace(/^-/, \"\");\n const shortName = packageName.replace(\"@tuttiai/\", \"\").replace(/^tutti-?/, \"\");\n const isOfficial = packageName.startsWith(\"@tuttiai/\");\n\n // 1. Get current voices.json content and SHA\n const fileRes = await fetch(\n \"https://api.github.com/repos/\" + owner + \"/\" + repo + \"/contents/voices.json\",\n { headers: { Authorization: \"Bearer \" + token, Accept: \"application/vnd.github.v3+json\" } },\n );\n if (!fileRes.ok) throw new Error(\"Failed to fetch voices.json: \" + fileRes.status);\n const fileData = (await fileRes.json()) as { content: string; sha: string };\n\n interface RegistryVoice { name: string; package: string; description: string; version: string; author: string; tags: string[]; repo?: string }\n interface Registry { official: RegistryVoice[]; community: RegistryVoice[] }\n\n const registry = JSON.parse(Buffer.from(fileData.content, \"base64\").toString(\"utf-8\")) as Registry;\n\n // 2. Add the new voice entry\n const section: keyof Registry = isOfficial ? \"official\" : \"community\";\n const entry: RegistryVoice = {\n name: shortName,\n package: packageName,\n description,\n repo: \"https://github.com/tuttiai/tutti/tree/main/voices/\" + shortName,\n version,\n author: isOfficial ? \"tuttiai\" : packageName.split(\"/\")[0]?.replace(\"@\", \"\") ?? \"community\",\n tags: [shortName],\n };\n\n if (!registry[section]) registry[section] = [];\n const exists = registry[section].some((v) => v.package === packageName);\n if (exists) {\n const idx = registry[section].findIndex((v) => v.package === packageName);\n registry[section][idx] = { ...registry[section][idx], ...entry };\n } else {\n registry[section].push(entry);\n }\n\n const updatedContent = Buffer.from(JSON.stringify(registry, null, 2) + \"\\n\").toString(\"base64\");\n\n // 3. Get default branch SHA\n const mainRes = await fetch(\n \"https://api.github.com/repos/\" + owner + \"/\" + repo + \"/git/ref/heads/main\",\n { headers: { Authorization: \"Bearer \" + token, Accept: \"application/vnd.github.v3+json\" } },\n );\n if (!mainRes.ok) throw new Error(\"Failed to get main ref: \" + mainRes.status);\n const mainData = (await mainRes.json()) as { object: { sha: string } };\n\n // 4. Create branch\n await fetch(\"https://api.github.com/repos/\" + owner + \"/\" + repo + \"/git/refs\", {\n method: \"POST\",\n headers: { Authorization: \"Bearer \" + token, \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ ref: \"refs/heads/\" + branch, sha: mainData.object.sha }),\n });\n\n // 5. Update voices.json on the new branch\n await fetch(\n \"https://api.github.com/repos/\" + owner + \"/\" + repo + \"/contents/voices.json\",\n {\n method: \"PUT\",\n headers: { Authorization: \"Bearer \" + token, \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n message: \"feat: add \" + packageName + \" to the Repertoire\",\n content: updatedContent,\n sha: fileData.sha,\n branch,\n }),\n },\n );\n\n // 6. Create PR\n const prRes = await fetch(\"https://api.github.com/repos/\" + owner + \"/\" + repo + \"/pulls\", {\n method: \"POST\",\n headers: { Authorization: \"Bearer \" + token, \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n title: \"feat: add \" + packageName + \" to the Repertoire\",\n head: branch,\n base: \"main\",\n body: \"## New voice: \" + packageName + \"@\" + version + \"\\n\\n\" + description + \"\\n\\nPublished via `tutti-ai publish`.\",\n }),\n });\n\n if (!prRes.ok) {\n const err = await prRes.text();\n throw new Error(\"Failed to create PR: \" + prRes.status + \" \" + err);\n }\n\n const prData = (await prRes.json()) as { html_url: string };\n return prData.html_url;\n}\n","import { existsSync, readFileSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport chalk from \"chalk\";\nimport ora from \"ora\";\nimport {\n ScoreLoader,\n EvalRunner,\n printEvalTable,\n createLogger,\n} from \"@tuttiai/core\";\nimport type { EvalSuite } from \"@tuttiai/core\";\n\nconst logger = createLogger(\"tutti-cli\");\n\nexport async function evalCommand(suitePath: string, opts: { ci?: boolean; score?: string }): Promise<void> {\n const suiteFile = resolve(suitePath);\n if (!existsSync(suiteFile)) {\n logger.error({ file: suiteFile }, \"Suite file not found\");\n process.exit(1);\n }\n\n // Load the eval suite JSON\n let suite: EvalSuite;\n try {\n suite = JSON.parse(readFileSync(suiteFile, \"utf-8\")) as EvalSuite;\n } catch (err) {\n logger.error({ error: err instanceof Error ? err.message : String(err) }, \"Failed to parse suite file\");\n process.exit(1);\n }\n\n // Load score\n const scoreFile = resolve(opts.score ?? \"./tutti.score.ts\");\n if (!existsSync(scoreFile)) {\n logger.error({ file: scoreFile }, \"Score file not found\");\n process.exit(1);\n }\n\n const spinner = ora(\"Loading score...\").start();\n let score;\n try {\n score = await ScoreLoader.load(scoreFile);\n } catch (err) {\n spinner.fail(\"Failed to load score\");\n logger.error({ error: err instanceof Error ? err.message : String(err) }, \"Score load failed\");\n process.exit(1);\n }\n spinner.succeed(\"Score loaded\");\n\n // Run eval\n const evalSpinner = ora(\"Running \" + suite.cases.length + \" eval cases...\").start();\n const runner = new EvalRunner(score);\n const report = await runner.run(suite);\n evalSpinner.stop();\n\n // Print results\n printEvalTable(report);\n\n // CI mode: exit 1 if any failed\n if (opts.ci && report.summary.failed > 0) {\n console.error(chalk.red(\" CI mode: \" + report.summary.failed + \" case(s) failed\"));\n process.exit(1);\n }\n}\n"],"mappings":"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","names":["createLogger","existsSync","chalk","createLogger","logger","existsSync","resolve","chalk","ora","createLogger","logger","existsSync","resolve","chalk","ScoreLoader","AnthropicProvider","OpenAIProvider","GeminiProvider","SecretsManager","createLogger","logger","existsSync","resolve","chalk","TuttiRuntime","ScoreLoader","createLogger","logger","existsSync","readFileSync","resolve","chalk","ora","createLogger","logger","existsSync","readFileSync","resolve","execSync","chalk","ora","Enquirer","createLogger","SecretsManager","prompt","logger","fail","ok","existsSync","readFileSync","resolve","chalk","ora","ScoreLoader","createLogger","logger","logger","createLogger"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/commands/init.ts","../src/templates/index.ts","../src/commands/run.ts","../src/watch/score-watcher.ts","../src/commands/resume.ts","../src/commands/add.ts","../src/commands/check.ts","../src/commands/studio.ts","../src/commands/search.ts","../src/commands/publish.ts","../src/commands/eval.ts"],"sourcesContent":["import { config } from \"dotenv\";\nconfig();\n\nimport { createLogger } from \"@tuttiai/core\";\nconst logger = createLogger(\"tutti-cli\");\n\nprocess.on(\"unhandledRejection\", (reason) => {\n logger.error({ error: reason instanceof Error ? reason.message : String(reason) }, \"Unhandled rejection\");\n process.exit(1);\n});\n\nprocess.on(\"uncaughtException\", (err) => {\n logger.error({ error: err.message }, \"Fatal error\");\n process.exit(1);\n});\n\nimport { Command } from \"commander\";\nimport { initCommand, templatesCommand } from \"./commands/init.js\";\nimport { runCommand } from \"./commands/run.js\";\nimport { resumeCommand, type ResumeOptions } from \"./commands/resume.js\";\nimport { addCommand } from \"./commands/add.js\";\nimport { checkCommand } from \"./commands/check.js\";\nimport { studioCommand } from \"./commands/studio.js\";\nimport { searchCommand, voicesCommand } from \"./commands/search.js\";\nimport { publishCommand } from \"./commands/publish.js\";\nimport { evalCommand } from \"./commands/eval.js\";\n\nconst program = new Command();\n\nprogram\n .name(\"tutti-ai\")\n .description(\"Tutti — multi-agent orchestration. All agents. All together.\")\n .version(\"0.10.0\");\n\nprogram\n .command(\"init [project-name]\")\n .description(\"Create a new Tutti project\")\n .option(\"-t, --template <id>\", \"Project template to use\")\n .action(async (projectName: string | undefined, opts: { template?: string }) => {\n await initCommand(projectName, opts.template);\n });\n\nprogram\n .command(\"templates\")\n .description(\"List all available project templates\")\n .action(() => {\n templatesCommand();\n });\n\nprogram\n .command(\"run [score]\")\n .description(\"Run a Tutti score interactively\")\n .option(\"-w, --watch\", \"Reload the score on file changes\")\n .action(async (score: string | undefined, opts: { watch?: boolean }) => {\n await runCommand(score, { watch: opts.watch });\n });\n\nprogram\n .command(\"resume <session-id>\")\n .description(\"Resume a crashed or interrupted run from its last checkpoint\")\n .option(\n \"--store <backend>\",\n \"Durable store the checkpoint was written to (redis | postgres)\",\n \"redis\",\n )\n .option(\"-s, --score <path>\", \"Path to score file (default: ./tutti.score.ts)\")\n .option(\"-a, --agent <name>\", \"Agent key to resume (default: score.entry or the first agent)\")\n .option(\"-y, --yes\", \"Skip the confirmation prompt\")\n .action(\n async (\n sessionId: string,\n opts: { store?: string; score?: string; agent?: string; yes?: boolean },\n ) => {\n if (opts.store !== \"redis\" && opts.store !== \"postgres\") {\n console.error(\"--store must be 'redis' or 'postgres'\");\n process.exit(1);\n }\n const resolved: ResumeOptions = {\n store: opts.store,\n ...(opts.score !== undefined ? { score: opts.score } : {}),\n ...(opts.agent !== undefined ? { agent: opts.agent } : {}),\n ...(opts.yes !== undefined ? { yes: opts.yes } : {}),\n };\n await resumeCommand(sessionId, resolved);\n },\n );\n\nprogram\n .command(\"add <voice>\")\n .description(\"Add a voice to your project\")\n .action((voice: string) => {\n addCommand(voice);\n });\n\nprogram\n .command(\"check [score]\")\n .description(\"Validate a score file without running it\")\n .action(async (score?: string) => {\n await checkCommand(score);\n });\n\nprogram\n .command(\"doctor [score]\")\n .description(\"Alias for check — validate a score file\")\n .action(async (score?: string) => {\n await checkCommand(score);\n });\n\nprogram\n .command(\"studio [score]\")\n .description(\"Launch Tutti Studio — local web UI for inspecting agent runs\")\n .action(async (score?: string) => {\n await studioCommand(score);\n });\n\nprogram\n .command(\"search <query>\")\n .description(\"Search the voice registry for voices matching a query\")\n .action(async (query: string) => {\n await searchCommand(query);\n });\n\nprogram\n .command(\"voices\")\n .description(\"List all available official voices and install status\")\n .action(async () => {\n await voicesCommand();\n });\n\nprogram\n .command(\"publish\")\n .description(\"Publish the current voice to npm and the voice registry\")\n .option(\"--dry-run\", \"Run all checks without publishing\")\n .action(async (opts: { dryRun?: boolean }) => {\n await publishCommand(opts);\n });\n\nprogram\n .command(\"eval <suite-file>\")\n .description(\"Run an evaluation suite against a score\")\n .option(\"--ci\", \"Exit with code 1 if any case fails\")\n .option(\"-s, --score <path>\", \"Path to score file (default: ./tutti.score.ts)\")\n .action(async (suitePath: string, opts: { ci?: boolean; score?: string }) => {\n await evalCommand(suitePath, opts);\n });\n\nprogram.parse();\n","import { mkdirSync, writeFileSync, existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport chalk from \"chalk\";\nimport Enquirer from \"enquirer\";\nimport { createLogger } from \"@tuttiai/core\";\nimport { TEMPLATES, getTemplate } from \"../templates/index.js\";\nimport type { Template } from \"../templates/index.js\";\n\nconst logger = createLogger(\"tutti-cli\");\n\nconst { prompt } = Enquirer;\n\nexport async function initCommand(projectName?: string, templateId?: string): Promise<void> {\n if (!projectName) {\n const response = await prompt<{ projectName: string }>({\n type: \"input\",\n name: \"projectName\",\n message: \"Project name?\",\n });\n projectName = response.projectName;\n }\n\n if (!projectName) {\n logger.error(\"Project name is required\");\n process.exit(1);\n }\n\n const dir = join(process.cwd(), projectName);\n\n if (existsSync(dir)) {\n logger.error({ dir: `${projectName}/` }, \"Directory already exists\");\n process.exit(1);\n }\n\n // Resolve template\n let template: Template | undefined;\n if (templateId) {\n template = getTemplate(templateId);\n if (!template) {\n logger.error({ template: templateId }, \"Unknown template\");\n console.error(chalk.dim(\" Available: \" + TEMPLATES.map((t) => t.id).join(\", \")));\n process.exit(1);\n }\n } else {\n // Interactive picker\n const response = await prompt<{ templateId: string }>({\n type: \"select\",\n name: \"templateId\",\n message: \"Which template?\",\n choices: TEMPLATES.map((t) => ({\n name: t.id,\n message: t.name + chalk.dim(\" — \" + t.description),\n })),\n });\n template = getTemplate(response.templateId);\n if (!template) template = TEMPLATES[0];\n }\n\n mkdirSync(dir, { recursive: true });\n\n const deps: Record<string, string> = {\n \"@tuttiai/core\": \"*\",\n \"@tuttiai/types\": \"*\",\n ...template.deps,\n };\n\n const envLines = [\n \"ANTHROPIC_API_KEY=your_key_here\",\n ...template.envVars,\n \"\",\n \"# Log level: debug | info | warn | error (default: info)\",\n \"TUTTI_LOG_LEVEL=info\",\n \"\",\n \"# OpenTelemetry (optional)\",\n \"# OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318\",\n \"# OTEL_SERVICE_NAME=tutti\",\n ];\n\n const files: Record<string, string> = {\n \"package.json\": JSON.stringify(\n {\n name: projectName,\n version: \"0.0.1\",\n type: \"module\",\n scripts: {\n dev: \"tsx watch tutti.score.ts\",\n start: \"tsx tutti.score.ts\",\n },\n dependencies: deps,\n devDependencies: {\n tsx: \"^4.0.0\",\n typescript: \"^5.7.0\",\n },\n },\n null,\n 2,\n ),\n\n \".env.example\": envLines.join(\"\\n\") + \"\\n\",\n\n \".gitignore\": \"node_modules\\ndist\\n.env\\n\",\n\n \"tsconfig.json\": JSON.stringify(\n {\n compilerOptions: {\n strict: true,\n target: \"ES2022\",\n module: \"ES2022\",\n moduleResolution: \"bundler\",\n esModuleInterop: true,\n skipLibCheck: true,\n outDir: \"dist\",\n rootDir: \".\",\n },\n include: [\".\"],\n },\n null,\n 2,\n ),\n\n \"tutti.score.ts\": template.score,\n\n \"README.md\": `# ${projectName}\n\nA Tutti agent project. All agents. All together.\n\n**Template:** ${template.name} — ${template.description}\n\n## Setup\n\n\\`\\`\\`bash\ncp .env.example .env\n# Add your API keys to .env\nnpm install\n\\`\\`\\`\n\n## Run\n\n\\`\\`\\`bash\nnpm run dev\n\\`\\`\\`\n`,\n };\n\n for (const [filename, content] of Object.entries(files)) {\n writeFileSync(join(dir, filename), content);\n }\n\n console.log();\n console.log(chalk.green(` ✔ Created ${projectName}/`) + chalk.dim(` (${template.name})`));\n console.log();\n console.log(\" Next steps:\");\n console.log(chalk.cyan(` cd ${projectName}`));\n console.log(chalk.cyan(\" cp .env.example .env\"));\n console.log(chalk.cyan(\" npm install\"));\n console.log(chalk.cyan(\" npm run dev\"));\n console.log();\n}\n\nexport function templatesCommand(): void {\n console.log();\n console.log(chalk.bold(\" Available Templates\"));\n console.log();\n for (const t of TEMPLATES) {\n console.log(\" \" + chalk.cyan(t.id.padEnd(18)) + t.description);\n }\n console.log();\n console.log(chalk.dim(\" Use: tutti-ai init my-project --template \" + TEMPLATES[0].id));\n console.log();\n}\n","export interface Template {\n id: string;\n name: string;\n description: string;\n deps: Record<string, string>;\n envVars: string[];\n score: string;\n}\n\nconst minimal: Template = {\n id: \"minimal\",\n name: \"Minimal\",\n description: \"One agent, no voices — the simplest starting point\",\n deps: {},\n envVars: [],\n score: `import { defineScore, AnthropicProvider } from \"@tuttiai/core\"\n\nexport default defineScore({\n provider: new AnthropicProvider(),\n default_model: \"claude-sonnet-4-20250514\",\n agents: {\n assistant: {\n name: \"Assistant\",\n system_prompt: \"You are a helpful assistant.\",\n voices: [],\n }\n }\n})\n`,\n};\n\nconst codingAgent: Template = {\n id: \"coding-agent\",\n name: \"Coding Agent\",\n description: \"TypeScript developer with filesystem + GitHub access\",\n deps: { \"@tuttiai/filesystem\": \"*\", \"@tuttiai/github\": \"*\" },\n envVars: [\"GITHUB_TOKEN=ghp_your_token_here\"],\n score: `import { defineScore, AnthropicProvider } from \"@tuttiai/core\"\nimport { FilesystemVoice } from \"@tuttiai/filesystem\"\nimport { GitHubVoice } from \"@tuttiai/github\"\n\nexport default defineScore({\n provider: new AnthropicProvider(),\n default_model: \"claude-sonnet-4-20250514\",\n agents: {\n coder: {\n name: \"Coder\",\n system_prompt:\n \"You are an expert TypeScript developer. \" +\n \"You read and write code using the filesystem voice, \" +\n \"and manage issues and PRs via the GitHub voice. \" +\n \"Write clean, tested, well-documented code.\",\n voices: [new FilesystemVoice(), new GitHubVoice()],\n permissions: [\"filesystem\", \"network\"],\n streaming: true,\n }\n }\n})\n`,\n};\n\nconst researchAgent: Template = {\n id: \"research-agent\",\n name: \"Research Agent\",\n description: \"Researcher that saves structured notes to files\",\n deps: { \"@tuttiai/filesystem\": \"*\" },\n envVars: [],\n score: `import { defineScore, AnthropicProvider } from \"@tuttiai/core\"\nimport { FilesystemVoice } from \"@tuttiai/filesystem\"\n\nexport default defineScore({\n provider: new AnthropicProvider(),\n default_model: \"claude-sonnet-4-20250514\",\n agents: {\n researcher: {\n name: \"Researcher\",\n system_prompt:\n \"You are an expert researcher. \" +\n \"Analyze topics thoroughly, cite sources, and save \" +\n \"structured notes as markdown files using the filesystem voice. \" +\n \"Organize findings with clear headings and bullet points.\",\n voices: [new FilesystemVoice()],\n permissions: [\"filesystem\"],\n streaming: true,\n }\n }\n})\n`,\n};\n\nconst qaPipeline: Template = {\n id: \"qa-pipeline\",\n name: \"QA Pipeline\",\n description: \"Orchestrator + QA specialist with browser testing and HITL\",\n deps: { \"@tuttiai/playwright\": \"*\" },\n envVars: [],\n score: `import { defineScore, AnthropicProvider } from \"@tuttiai/core\"\nimport { PlaywrightVoice } from \"@tuttiai/playwright\"\n\nexport default defineScore({\n provider: new AnthropicProvider(),\n default_model: \"claude-sonnet-4-20250514\",\n entry: \"orchestrator\",\n agents: {\n orchestrator: {\n name: \"QA Lead\",\n system_prompt:\n \"You are a QA lead. Triage incoming bugs by delegating \" +\n \"browser testing to the QA specialist. Use human-in-the-loop \" +\n \"to ask for approval before marking bugs as verified.\",\n voices: [],\n role: \"orchestrator\",\n delegates: [\"qa\"],\n allow_human_input: true,\n streaming: true,\n },\n qa: {\n name: \"QA Specialist\",\n system_prompt:\n \"You are a QA engineer. Navigate to URLs, check elements, \" +\n \"take screenshots, and verify bug reports using the browser.\",\n voices: [new PlaywrightVoice()],\n permissions: [\"network\", \"browser\"],\n role: \"specialist\",\n budget: { max_cost_usd: 0.50, warn_at_percent: 80 },\n streaming: true,\n }\n }\n})\n`,\n};\n\nconst devTeam: Template = {\n id: \"dev-team\",\n name: \"Dev Team\",\n description: \"Full team: orchestrator + coder + PM + QA with all voices\",\n deps: {\n \"@tuttiai/filesystem\": \"*\",\n \"@tuttiai/github\": \"*\",\n \"@tuttiai/playwright\": \"*\",\n },\n envVars: [\"GITHUB_TOKEN=ghp_your_token_here\"],\n score: `import { defineScore, AnthropicProvider, createLoggingHook, createBlocklistHook, createLogger } from \"@tuttiai/core\"\nimport { FilesystemVoice } from \"@tuttiai/filesystem\"\nimport { GitHubVoice } from \"@tuttiai/github\"\nimport { PlaywrightVoice } from \"@tuttiai/playwright\"\n\nconst logger = createLogger(\"dev-team\")\n\nexport default defineScore({\n provider: new AnthropicProvider(),\n default_model: \"claude-sonnet-4-20250514\",\n entry: \"orchestrator\",\n hooks: {\n ...createLoggingHook(logger),\n ...createBlocklistHook([\"delete_file\"]),\n },\n agents: {\n orchestrator: {\n name: \"Tech Lead\",\n system_prompt:\n \"You are the tech lead. Break tasks into subtasks and delegate: \" +\n \"code tasks to Coder, documentation to PM, testing to QA. \" +\n \"Review outputs before presenting to the user.\",\n voices: [],\n role: \"orchestrator\",\n delegates: [\"coder\", \"pm\", \"qa\"],\n allow_human_input: true,\n streaming: true,\n },\n coder: {\n name: \"Coder\",\n system_prompt:\n \"You are a senior TypeScript developer. Write clean, tested code. \" +\n \"Use the filesystem voice to read/write files and GitHub to manage PRs.\",\n voices: [new FilesystemVoice(), new GitHubVoice()],\n permissions: [\"filesystem\", \"network\"],\n role: \"specialist\",\n streaming: true,\n },\n pm: {\n name: \"PM\",\n system_prompt:\n \"You are a product manager. Write specs, update documentation, \" +\n \"and create GitHub issues for tracking. Focus on clarity and completeness.\",\n voices: [new FilesystemVoice(), new GitHubVoice()],\n permissions: [\"filesystem\", \"network\"],\n role: \"specialist\",\n streaming: true,\n },\n qa: {\n name: \"QA\",\n system_prompt:\n \"You are a QA engineer. Test features in the browser, verify bugs, \" +\n \"and write test reports. Screenshot evidence for every finding.\",\n voices: [new PlaywrightVoice()],\n permissions: [\"network\", \"browser\"],\n role: \"specialist\",\n budget: { max_cost_usd: 1.00 },\n streaming: true,\n }\n }\n})\n`,\n};\n\nexport const TEMPLATES: Template[] = [minimal, codingAgent, researchAgent, qaPipeline, devTeam];\n\nexport function getTemplate(id: string): Template | undefined {\n return TEMPLATES.find((t) => t.id === id);\n}\n","import { existsSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport { createInterface } from \"node:readline/promises\";\nimport chalk from \"chalk\";\nimport ora from \"ora\";\nimport {\n TuttiRuntime,\n ScoreLoader,\n AnthropicProvider,\n OpenAIProvider,\n GeminiProvider,\n SecretsManager,\n InMemorySessionStore,\n createLogger,\n} from \"@tuttiai/core\";\nimport type { ScoreConfig, SessionStore } from \"@tuttiai/types\";\nimport { ReactiveScore } from \"../watch/score-watcher.js\";\n\nconst logger = createLogger(\"tutti-cli\");\n\nexport interface RunOptions {\n /** Reload the score on file changes. */\n watch?: boolean;\n}\n\nexport async function runCommand(\n scorePath?: string,\n options: RunOptions = {},\n): Promise<void> {\n const file = resolve(scorePath ?? \"./tutti.score.ts\");\n\n if (!existsSync(file)) {\n logger.error({ file }, \"Score file not found\");\n console.error(chalk.dim('Run \"tutti-ai init\" to create a new project.'));\n process.exit(1);\n }\n\n let score;\n try {\n score = await ScoreLoader.load(file);\n } catch (err) {\n logger.error(\n { error: err instanceof Error ? err.message : String(err) },\n \"Failed to load score\",\n );\n process.exit(1);\n }\n\n // Validate that the provider has a valid API key\n const providerKeyMap: [unknown, string][] = [\n [AnthropicProvider, \"ANTHROPIC_API_KEY\"],\n [OpenAIProvider, \"OPENAI_API_KEY\"],\n [GeminiProvider, \"GEMINI_API_KEY\"],\n ];\n\n for (const [ProviderClass, envVar] of providerKeyMap) {\n if (score.provider instanceof (ProviderClass as new (...args: unknown[]) => unknown)) {\n const key = SecretsManager.optional(envVar);\n if (!key) {\n logger.error({ envVar }, \"Missing API key\");\n process.exit(1);\n }\n }\n }\n\n // Enable streaming on every agent in the score. Factored out so we can\n // reapply it after a hot-reload in watch mode.\n const applyRunDefaults = (cfg: ScoreConfig): void => {\n for (const agent of Object.values(cfg.agents)) {\n agent.streaming = true;\n }\n };\n applyRunDefaults(score);\n\n // Build a single session store up front in watch mode so the\n // conversation history survives runtime swaps. Non-watch runs can let\n // TuttiRuntime provision its own store from score.memory as usual.\n const sharedSessions: SessionStore | undefined = options.watch\n ? new InMemorySessionStore()\n : undefined;\n\n const spinner = ora({ color: \"cyan\" });\n\n // REPL-level state. `streaming` resets per turn; `runtime` may be\n // swapped by the hot-reload path below.\n let streaming = false;\n let runtime = buildRuntime(score, sharedSessions);\n\n attachListeners(runtime);\n\n // REPL readline — created early so the HITL handler below can use it.\n const rl = createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n\n // Wire per-runtime listeners. Separated from the REPL so a hot-reload\n // can swap the runtime and re-wire without touching the outer loop.\n function attachListeners(r: TuttiRuntime): void {\n r.events.on(\"agent:start\", (e) => {\n logger.info({ agent: e.agent_name }, \"Running agent\");\n });\n\n r.events.on(\"llm:request\", () => {\n spinner.start(\"Thinking...\");\n });\n\n r.events.on(\"token:stream\", (e) => {\n if (!streaming) {\n spinner.stop();\n streaming = true;\n }\n process.stdout.write(e.text);\n });\n\n r.events.on(\"llm:response\", () => {\n if (streaming) {\n process.stdout.write(\"\\n\");\n } else {\n spinner.stop();\n }\n });\n\n r.events.on(\"tool:start\", (e) => {\n if (streaming) {\n process.stdout.write(chalk.dim(\"\\n [using: \" + e.tool_name + \"]\"));\n } else {\n spinner.stop();\n console.log(chalk.dim(\" [using: \" + e.tool_name + \"]\"));\n }\n });\n\n r.events.on(\"tool:end\", (e) => {\n if (streaming) {\n process.stdout.write(chalk.dim(\" [done: \" + e.tool_name + \"]\\n\"));\n }\n });\n\n r.events.on(\"tool:error\", (e) => {\n spinner.stop();\n logger.error({ tool: e.tool_name }, \"Tool error\");\n });\n\n r.events.on(\"security:injection_detected\", (e) => {\n logger.warn({ tool: e.tool_name }, \"Potential prompt injection detected\");\n });\n\n r.events.on(\"budget:warning\", () => {\n logger.warn(\"Approaching token budget (80%)\");\n });\n\n r.events.on(\"budget:exceeded\", () => {\n logger.error(\"Token budget exceeded — stopping\");\n });\n\n r.events.on(\"hitl:requested\", (e) => {\n spinner.stop();\n if (streaming) {\n process.stdout.write(\"\\n\");\n streaming = false;\n }\n console.log();\n console.log(\n chalk.yellow(\n \" \" + chalk.bold(\"[Agent needs input]\") + \" \" + e.question,\n ),\n );\n if (e.options) {\n e.options.forEach((opt, i) => {\n console.log(chalk.yellow(\" \" + (i + 1) + \". \" + opt));\n });\n }\n void rl.question(chalk.yellow(\" > \")).then((answer) => {\n runtime.answer(e.session_id, answer.trim());\n });\n });\n }\n\n // --- Watch mode wiring ---------------------------------------------------\n // Scope: set up a ReactiveScore that reloads the score file on change\n // and surfaces status to the REPL. The REPL checks `pendingReload`\n // between turns (so we never interrupt a mid-turn call) and swaps\n // `runtime` when appropriate.\n let reactive: ReactiveScore | undefined;\n if (options.watch) {\n reactive = new ReactiveScore(score, file);\n reactive.on(\"file-change\", () => {\n console.log(chalk.cyan(\"\\n[tutti] Score changed, reloading...\"));\n });\n reactive.on(\"reloaded\", () => {\n // Defer the actual swap to the next turn boundary — the REPL loop\n // checks `pendingReload` before each iteration. Applying mid-turn\n // would either interrupt a tool call or strand events listeners\n // pointing at the old runtime instance.\n console.log(chalk.green(\"[tutti] Score reloaded. Changes applied.\"));\n });\n reactive.on(\"reload-failed\", (err) => {\n logger.error(\n { error: err instanceof Error ? err.message : String(err) },\n \"[tutti] Reload failed — using previous config\",\n );\n });\n }\n\n // REPL\n console.log(chalk.dim('Tutti REPL — type \"exit\" to quit\\n'));\n if (options.watch) {\n console.log(chalk.dim(\"Watching \" + file + \" for changes…\\n\"));\n }\n\n let sessionId: string | undefined;\n\n // Handle Ctrl+C cleanly\n process.on(\"SIGINT\", () => {\n if (streaming) process.stdout.write(\"\\n\");\n spinner.stop();\n console.log(chalk.dim(\"Goodbye!\"));\n rl.close();\n if (reactive) void reactive.close();\n process.exit(0);\n });\n\n try {\n while (true) {\n // Apply any pending hot-reload before we start the next turn. This\n // is the \"don't interrupt mid-tool-call\" guarantee — we only swap\n // at a REPL-loop boundary, after the previous `run()` resolved.\n if (reactive?.pendingReload) {\n const nextScore = reactive.current;\n applyRunDefaults(nextScore);\n runtime = buildRuntime(nextScore, sharedSessions);\n attachListeners(runtime);\n reactive.consumePendingReload();\n }\n\n const input = await rl.question(chalk.cyan(\"> \"));\n const trimmed = input.trim();\n\n if (!trimmed) continue;\n if (trimmed === \"exit\" || trimmed === \"quit\") break;\n\n // Reset streaming state for this run\n streaming = false;\n\n try {\n const result = await runtime.run(\"assistant\", trimmed, sessionId);\n sessionId = result.session_id;\n\n if (!streaming) {\n console.log(\"\\n\" + result.output + \"\\n\");\n } else {\n console.log();\n }\n } catch (err) {\n if (streaming) process.stdout.write(\"\\n\");\n spinner.stop();\n logger.error(\n { error: err instanceof Error ? err.message : String(err) },\n \"Something went wrong\",\n );\n }\n }\n } catch {\n // readline closed\n }\n\n console.log(chalk.dim(\"Goodbye!\"));\n rl.close();\n if (reactive) await reactive.close();\n process.exit(0);\n}\n\nfunction buildRuntime(\n score: ScoreConfig,\n sessionStore: SessionStore | undefined,\n): TuttiRuntime {\n return new TuttiRuntime(\n score,\n sessionStore ? { sessionStore } : {},\n );\n}\n","import { dirname, resolve } from \"node:path\";\nimport { EventEmitter } from \"node:events\";\nimport chokidar, { type FSWatcher } from \"chokidar\";\nimport type { ScoreConfig } from \"@tuttiai/types\";\nimport { validateScore } from \"@tuttiai/core\";\n\n/** How long to wait after the last change event before reloading. */\nconst DEFAULT_DEBOUNCE_MS = 200;\n\n/** Default ignore-patterns for the directory-tree watch. */\nconst DEFAULT_IGNORED = [\n /(^|[/\\\\])\\../, // dotfiles (.git, .env, etc.)\n /node_modules/,\n /[/\\\\]dist[/\\\\]/,\n /[/\\\\]coverage[/\\\\]/,\n];\n\n/**\n * Load a score module with ESM cache-busting. Node's ESM cache is per-URL\n * and cannot be invalidated, so we append a unique query parameter on\n * each reload to force a fresh module instance. The old instance stays in\n * memory — acceptable leak for a development-only watch loop.\n */\nasync function defaultLoadScore(path: string): Promise<ScoreConfig> {\n const absolute = resolve(path);\n // Node's ESM cache is per-URL and can't be invalidated — append a\n // unique query parameter so each reload gets a fresh module instance.\n // The previous instance stays in memory (small leak, acceptable for a\n // development-only watch loop).\n const { pathToFileURL } = await import(\"node:url\");\n const url = pathToFileURL(absolute).href + \"?t=\" + Date.now().toString(36);\n const mod = (await import(url)) as { default?: ScoreConfig };\n if (!mod.default) {\n throw new Error(\n \"Score file has no default export: \" + path +\n \" — your score must export `defineScore({ ... })` as its default.\",\n );\n }\n // Validate the freshly-loaded score. `ScoreLoader.load` would have run\n // the same validator but on a stale cache entry, so we inline it.\n validateScore(mod.default);\n return mod.default;\n}\n\nexport interface ReactiveScoreEvents {\n /** Emitted immediately when a watched file changes (before debounce settles). */\n \"file-change\": (changedPath: string) => void;\n /** Emitted when a reload attempt starts (after debounce). */\n reloading: () => void;\n /** Emitted when a reload succeeds — `current` now returns the new score. */\n reloaded: (score: ScoreConfig) => void;\n /**\n * Emitted when a reload fails. The previous `current` score is kept so\n * the REPL can continue with the last-known-good config.\n */\n \"reload-failed\": (error: Error) => void;\n}\n\nexport interface ReactiveScoreOptions {\n /**\n * Additional paths or glob patterns to watch beyond the score file and\n * its parent directory. Useful when voices live elsewhere.\n */\n extraPaths?: string[];\n /** Debounce window in ms. Default 200. */\n debounceMs?: number;\n /**\n * Override the score loader. Primarily a test seam — production code\n * uses the default cache-busting ESM importer.\n */\n load?: (path: string) => Promise<ScoreConfig>;\n}\n\n/**\n * A {@link ScoreConfig} that refreshes itself when the underlying file\n * (or any file in its directory) changes on disk.\n *\n * Consumers read `reactive.current` before each turn and get the most\n * recent successfully-loaded score. On a reload failure (syntax error in\n * the score file, schema validation, etc.), `current` keeps returning the\n * previous value — callers can listen for `reload-failed` to surface the\n * error in their UI.\n */\nexport class ReactiveScore extends EventEmitter {\n private _current: ScoreConfig;\n private readonly scorePath: string;\n private readonly load: (path: string) => Promise<ScoreConfig>;\n private readonly debounceMs: number;\n private readonly watcher: FSWatcher;\n private debounceTimer: ReturnType<typeof setTimeout> | undefined;\n private closed = false;\n private _pendingReload = false;\n\n constructor(\n initialScore: ScoreConfig,\n scorePath: string,\n options: ReactiveScoreOptions = {},\n ) {\n super();\n this._current = initialScore;\n this.scorePath = resolve(scorePath);\n this.load = options.load ?? defaultLoadScore;\n this.debounceMs = options.debounceMs ?? DEFAULT_DEBOUNCE_MS;\n\n // Watch the score file, its parent directory tree, and any extras.\n // Directory-tree watching catches voice files and local utility\n // modules without needing a proper import-graph resolver; the\n // trade-off is that unrelated files in the tree also trigger reloads.\n const watchTargets = [\n this.scorePath,\n dirname(this.scorePath),\n ...(options.extraPaths ?? []),\n ];\n this.watcher = chokidar.watch(watchTargets, {\n ignored: DEFAULT_IGNORED,\n ignoreInitial: true,\n // awaitWriteFinish: guard against partial writes from editors that\n // save atomically via rename/move.\n awaitWriteFinish: {\n stabilityThreshold: 50,\n pollInterval: 20,\n },\n });\n\n this.watcher.on(\"change\", (path) => this.handleChange(path));\n this.watcher.on(\"add\", (path) => this.handleChange(path));\n }\n\n /** The most recent successfully-loaded score. Never stale. */\n get current(): ScoreConfig {\n return this._current;\n }\n\n /**\n * True when a file change has been observed and a reload is pending\n * (or just completed and not yet consumed). Readers call\n * {@link consumePendingReload} to clear the flag when they've taken\n * action on the new config.\n */\n get pendingReload(): boolean {\n return this._pendingReload;\n }\n\n consumePendingReload(): void {\n this._pendingReload = false;\n }\n\n /** Release the underlying filesystem watchers. */\n async close(): Promise<void> {\n this.closed = true;\n if (this.debounceTimer) clearTimeout(this.debounceTimer);\n await this.watcher.close();\n }\n\n /**\n * Force an immediate reload without waiting for a filesystem event.\n * Exposed for tests and for the `reload` REPL command.\n */\n async reloadNow(): Promise<void> {\n if (this.closed) return;\n this.emit(\"reloading\");\n try {\n const next = await this.load(this.scorePath);\n this._current = next;\n this._pendingReload = true;\n this.emit(\"reloaded\", next);\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n this.emit(\"reload-failed\", error);\n }\n }\n\n private handleChange(path: string): void {\n if (this.closed) return;\n this.emit(\"file-change\", path);\n if (this.debounceTimer) clearTimeout(this.debounceTimer);\n this.debounceTimer = setTimeout(() => {\n void this.reloadNow();\n }, this.debounceMs);\n }\n}\n","import { existsSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport { createInterface } from \"node:readline/promises\";\nimport chalk from \"chalk\";\nimport ora from \"ora\";\nimport {\n AnthropicProvider,\n GeminiProvider,\n OpenAIProvider,\n ScoreLoader,\n SecretsManager,\n TuttiRuntime,\n createCheckpointStore,\n createLogger,\n type Checkpoint,\n type ChatMessage,\n} from \"@tuttiai/core\";\nconst logger = createLogger(\"tutti-cli\");\n\nexport interface ResumeOptions {\n /** Which durable store the checkpoint was written to. */\n store: \"redis\" | \"postgres\";\n /** Path to the score file (defaults to ./tutti.score.ts). */\n score?: string;\n /** Agent key to resume; defaults to the score's entry agent. */\n agent?: string;\n /** Skip the confirmation prompt — for scripted use. */\n yes?: boolean;\n}\n\nexport async function resumeCommand(\n sessionId: string,\n opts: ResumeOptions,\n): Promise<void> {\n // --- Score loading (same flow as `run`) -------------------------------\n const scoreFile = resolve(opts.score ?? \"./tutti.score.ts\");\n if (!existsSync(scoreFile)) {\n logger.error({ file: scoreFile }, \"Score file not found\");\n console.error(chalk.dim('Run \"tutti-ai init\" to create a new project.'));\n process.exit(1);\n }\n\n let score;\n try {\n score = await ScoreLoader.load(scoreFile);\n } catch (err) {\n logger.error(\n { error: err instanceof Error ? err.message : String(err) },\n \"Failed to load score\",\n );\n process.exit(1);\n }\n\n // --- Provider API-key check (same shortlist as `run`) -----------------\n const providerKeyMap: [unknown, string][] = [\n [AnthropicProvider, \"ANTHROPIC_API_KEY\"],\n [OpenAIProvider, \"OPENAI_API_KEY\"],\n [GeminiProvider, \"GEMINI_API_KEY\"],\n ];\n for (const [ProviderClass, envVar] of providerKeyMap) {\n if (\n score.provider instanceof\n (ProviderClass as new (...args: unknown[]) => unknown)\n ) {\n if (!SecretsManager.optional(envVar)) {\n logger.error({ envVar }, \"Missing API key\");\n process.exit(1);\n }\n }\n }\n\n // --- Resolve the target agent -----------------------------------------\n const agentName = resolveAgentName(score, opts.agent);\n const agent = score.agents[agentName];\n if (!agent) {\n logger.error(\n { agent: agentName, available: Object.keys(score.agents) },\n \"Agent not found in score\",\n );\n process.exit(1);\n }\n if (!agent.durable) {\n console.error(\n chalk.yellow(\n \"Agent '\" +\n agentName +\n \"' does not have `durable: true` set — resume has nothing to restore.\",\n ),\n );\n console.error(\n chalk.dim(\n \"Enable durable checkpointing on the agent before the run that created this session.\",\n ),\n );\n process.exit(1);\n }\n\n // --- Load the checkpoint ----------------------------------------------\n const spinner = ora({ color: \"cyan\" }).start(\"Loading checkpoint...\");\n let checkpointStore;\n let checkpoint: Checkpoint | null;\n try {\n checkpointStore = createCheckpointStore({ store: opts.store });\n checkpoint = await checkpointStore.loadLatest(sessionId);\n } catch (err) {\n spinner.fail(\"Failed to load checkpoint\");\n logger.error(\n { error: err instanceof Error ? err.message : String(err), store: opts.store },\n \"Checkpoint store error\",\n );\n process.exit(1);\n }\n spinner.stop();\n\n if (!checkpoint) {\n console.error(\n chalk.red(\"No checkpoint found for session \" + sessionId + \".\"),\n );\n console.error(\n chalk.dim(\n \"Verify TUTTI_\" +\n (opts.store === \"redis\" ? \"REDIS\" : \"PG\") +\n \"_URL points to the same \" +\n opts.store +\n \" the original run used.\",\n ),\n );\n process.exit(1);\n }\n\n // --- Render the summary -----------------------------------------------\n printSummary(checkpoint);\n\n // --- Confirm (unless --yes) -------------------------------------------\n if (!opts.yes && !(await confirmResume(checkpoint.turn))) {\n console.log(chalk.dim(\"Cancelled.\"));\n process.exit(0);\n }\n\n // --- Build the runtime and hand off to AgentRunner --------------------\n const runtime = new TuttiRuntime(score, { checkpointStore });\n\n // Seed the session store with a synthetic Session so the runner's\n // `sessions.get(id)` lookup succeeds. The agent loop immediately\n // overwrites `messages` from the checkpoint — the seeded messages\n // array only exists so the initial get() call doesn't miss.\n const sessions = runtime.sessions;\n if (\"save\" in sessions && typeof sessions.save === \"function\") {\n (sessions.save as (s: { id: string; agent_name: string; messages: ChatMessage[]; created_at: Date; updated_at: Date }) => void)({\n id: sessionId,\n agent_name: agentName,\n messages: [...checkpoint.messages],\n created_at: checkpoint.saved_at,\n updated_at: new Date(),\n });\n } else {\n console.error(\n chalk.red(\n \"Session store does not support resume seeding. Use the default InMemorySessionStore or PostgresSessionStore.\",\n ),\n );\n process.exit(1);\n }\n\n wireProgress(runtime);\n\n try {\n // Input is ignored when the runner sees a mid-cycle checkpoint, but\n // we still need a non-empty value to satisfy the method signature.\n const result = await runtime.run(agentName, \"[resume]\", sessionId);\n console.log();\n console.log(chalk.green(\"✓ Resumed run complete.\"));\n console.log(chalk.dim(\" Final turn: \" + result.turns));\n console.log(chalk.dim(\" Session ID: \" + result.session_id));\n console.log(\n chalk.dim(\n \" Token usage: \" +\n result.usage.input_tokens +\n \" in / \" +\n result.usage.output_tokens +\n \" out\",\n ),\n );\n console.log();\n console.log(result.output);\n } catch (err) {\n logger.error(\n { error: err instanceof Error ? err.message : String(err) },\n \"Resume failed\",\n );\n process.exit(1);\n }\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction resolveAgentName(\n score: { entry?: string | { agents: string[] }; agents: Record<string, unknown> },\n override?: string,\n): string {\n if (override) return override;\n if (typeof score.entry === \"string\") return score.entry;\n const first = Object.keys(score.agents)[0];\n if (!first) {\n console.error(chalk.red(\"Score has no agents defined.\"));\n process.exit(1);\n }\n return first;\n}\n\nfunction printSummary(checkpoint: Checkpoint): void {\n console.log();\n console.log(chalk.cyan.bold(\"Checkpoint summary\"));\n console.log(\n chalk.dim(\" Session ID: \") + checkpoint.session_id,\n );\n console.log(\n chalk.dim(\" Last turn: \") + String(checkpoint.turn),\n );\n console.log(\n chalk.dim(\" Saved at: \") +\n checkpoint.saved_at.toISOString(),\n );\n console.log(\n chalk.dim(\" Messages: \") +\n String(checkpoint.messages.length) +\n \" total\",\n );\n console.log();\n console.log(chalk.cyan(\"First messages\"));\n const preview = checkpoint.messages.slice(0, 3);\n for (const msg of preview) {\n const text = excerpt(messageToText(msg), 200);\n console.log(chalk.dim(\" [\" + msg.role + \"] \") + text);\n }\n if (checkpoint.messages.length > preview.length) {\n console.log(\n chalk.dim(\n \" … \" +\n String(checkpoint.messages.length - preview.length) +\n \" more\",\n ),\n );\n }\n console.log();\n}\n\nfunction messageToText(msg: ChatMessage): string {\n if (typeof msg.content === \"string\") return msg.content;\n const parts: string[] = [];\n for (const block of msg.content) {\n if (block.type === \"text\") {\n parts.push(block.text);\n } else if (block.type === \"tool_use\") {\n parts.push(\"[tool_use \" + block.name + \"]\");\n } else if (block.type === \"tool_result\") {\n parts.push(\"[tool_result \" + excerpt(block.content, 80) + \"]\");\n }\n }\n return parts.join(\" \");\n}\n\nfunction excerpt(text: string, max: number): string {\n const oneLine = text.replace(/\\s+/g, \" \").trim();\n return oneLine.length > max ? oneLine.slice(0, max - 1) + \"…\" : oneLine;\n}\n\nasync function confirmResume(turn: number): Promise<boolean> {\n const rl = createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n try {\n const answer = (\n await rl.question(\n chalk.cyan(\"Resume from turn \" + turn + \"? \") + chalk.dim(\"(y/n) \"),\n )\n )\n .trim()\n .toLowerCase();\n return answer === \"y\" || answer === \"yes\";\n } finally {\n rl.close();\n }\n}\n\nfunction wireProgress(runtime: TuttiRuntime): void {\n const spinner = ora({ color: \"cyan\" });\n let streaming = false;\n\n runtime.events.on(\"checkpoint:restored\", (e) => {\n console.log(\n chalk.dim(\"↻ Restored from turn \" + e.turn) +\n chalk.dim(\" (session \" + e.session_id.slice(0, 8) + \"…)\"),\n );\n });\n runtime.events.on(\"checkpoint:saved\", (e) => {\n console.log(chalk.dim(\"· Checkpoint saved at turn \" + e.turn));\n });\n runtime.events.on(\"llm:request\", () => {\n spinner.start(\"Thinking...\");\n });\n runtime.events.on(\"token:stream\", (e) => {\n if (!streaming) {\n spinner.stop();\n streaming = true;\n }\n process.stdout.write(e.text);\n });\n runtime.events.on(\"llm:response\", () => {\n if (streaming) {\n process.stdout.write(\"\\n\");\n } else {\n spinner.stop();\n }\n });\n runtime.events.on(\"tool:start\", (e) => {\n if (streaming) {\n process.stdout.write(chalk.dim(\"\\n [using: \" + e.tool_name + \"]\"));\n } else {\n spinner.stop();\n console.log(chalk.dim(\" [using: \" + e.tool_name + \"]\"));\n }\n });\n runtime.events.on(\"tool:end\", (e) => {\n if (streaming) {\n process.stdout.write(chalk.dim(\" [done: \" + e.tool_name + \"]\\n\"));\n }\n });\n runtime.events.on(\"tool:error\", (e) => {\n spinner.stop();\n logger.error({ tool: e.tool_name }, \"Tool error\");\n });\n}\n","import { existsSync, readFileSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport { execSync } from \"node:child_process\";\nimport chalk from \"chalk\";\nimport ora from \"ora\";\nimport { createLogger } from \"@tuttiai/core\";\n\nconst logger = createLogger(\"tutti-cli\");\n\nconst OFFICIAL_VOICES: Record<string, { package: string; setup: string }> = {\n filesystem: {\n package: \"@tuttiai/filesystem\",\n setup: ` Add to your score:\n ${chalk.cyan('import { FilesystemVoice } from \"@tuttiai/filesystem\"')}\n ${chalk.cyan(\"voices: [new FilesystemVoice()]\")}`,\n },\n github: {\n package: \"@tuttiai/github\",\n setup: ` Add ${chalk.bold(\"GITHUB_TOKEN\")} to your .env file:\n ${chalk.cyan(\"GITHUB_TOKEN=ghp_your_token_here\")}\n\n Add to your score:\n ${chalk.cyan('import { GitHubVoice } from \"@tuttiai/github\"')}\n ${chalk.cyan(\"voices: [new GitHubVoice()]\")}`,\n },\n playwright: {\n package: \"@tuttiai/playwright\",\n setup: ` Install the browser:\n ${chalk.cyan(\"npx playwright install chromium\")}\n\n Add to your score:\n ${chalk.cyan('import { PlaywrightVoice } from \"@tuttiai/playwright\"')}\n ${chalk.cyan(\"voices: [new PlaywrightVoice()]\")}`,\n },\n postgres: {\n package: \"pg\",\n setup: ` Add ${chalk.bold(\"DATABASE_URL\")} to your .env file:\n ${chalk.cyan(\"DATABASE_URL=postgres://user:pass@localhost:5432/tutti\")}\n\n Add to your score:\n ${chalk.cyan(\"memory: { provider: 'postgres' }\")}\n\n Or with an explicit URL:\n ${chalk.cyan(\"memory: { provider: 'postgres', url: process.env.DATABASE_URL }\")}\n\n Use the async factory for initialization:\n ${chalk.cyan(\"const tutti = await TuttiRuntime.create(score)\")}`,\n },\n};\n\nfunction resolvePackageName(input: string): string {\n // Known official voice\n if (OFFICIAL_VOICES[input]) {\n return OFFICIAL_VOICES[input].package;\n }\n // Already a scoped package\n if (input.startsWith(\"@\")) {\n return input;\n }\n // Try @tuttiai/<name> convention\n return `@tuttiai/${input}`;\n}\n\nfunction isAlreadyInstalled(packageName: string): boolean {\n const pkgPath = resolve(process.cwd(), \"package.json\");\n if (!existsSync(pkgPath)) return false;\n\n try {\n const pkg = JSON.parse(readFileSync(pkgPath, \"utf-8\")) as { dependencies?: Record<string, string>; devDependencies?: Record<string, string> };\n const deps: Record<string, string> = { ...pkg.dependencies, ...pkg.devDependencies };\n return packageName in deps;\n } catch {\n return false;\n }\n}\n\nexport function addCommand(voiceName: string): void {\n const packageName = resolvePackageName(voiceName);\n\n // Check if package.json exists in cwd\n const pkgPath = resolve(process.cwd(), \"package.json\");\n if (!existsSync(pkgPath)) {\n logger.error(\"No package.json found in the current directory\");\n console.error(chalk.dim('Run \"tutti-ai init\" to create a new project first.'));\n process.exit(1);\n }\n\n // Check if already installed\n if (isAlreadyInstalled(packageName)) {\n console.log(chalk.green(` ✔ ${packageName} is already installed`));\n return;\n }\n\n // Install\n const spinner = ora(`Installing ${packageName}...`).start();\n\n try {\n execSync(`npm install ${packageName}`, {\n cwd: process.cwd(),\n stdio: \"pipe\",\n });\n spinner.succeed(`Installed ${packageName}`);\n } catch (error) {\n spinner.fail(`Failed to install ${packageName}`);\n const message = error instanceof Error ? error.message : String(error);\n logger.error({ error: message, package: packageName }, \"Installation failed\");\n process.exit(1);\n }\n\n // Print setup instructions\n const official = OFFICIAL_VOICES[voiceName];\n if (official) {\n console.log();\n console.log(\" Setup:\");\n console.log(official.setup);\n console.log();\n } else {\n console.log();\n console.log(\n chalk.dim(\" Check the package README for setup instructions.\"),\n );\n console.log();\n }\n}\n","import { existsSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport chalk from \"chalk\";\nimport {\n ScoreLoader,\n AnthropicProvider,\n OpenAIProvider,\n GeminiProvider,\n SecretsManager,\n createLogger,\n} from \"@tuttiai/core\";\n\nconst logger = createLogger(\"tutti-cli\");\n\nconst ok = (msg: string) => console.log(chalk.green(\" \\u2714 \" + msg));\nconst fail = (msg: string) => console.log(chalk.red(\" \\u2718 \" + msg));\n\nexport async function checkCommand(scorePath?: string): Promise<void> {\n const file = resolve(scorePath ?? \"./tutti.score.ts\");\n\n console.log(chalk.cyan(`\\nChecking ${file}...\\n`));\n\n if (!existsSync(file)) {\n fail(\"Score file not found: \" + file);\n process.exit(1);\n }\n\n // 1. Load and validate\n let score;\n try {\n score = await ScoreLoader.load(file);\n ok(\"Score file is valid\");\n } catch (err) {\n fail(\"Score validation failed\");\n logger.error(\n { error: err instanceof Error ? err.message : String(err) },\n \"Score validation failed\",\n );\n process.exit(1);\n }\n\n let hasErrors = false;\n\n // 2. Check provider and API key\n const providerChecks: [unknown, string, string][] = [\n [AnthropicProvider, \"AnthropicProvider\", \"ANTHROPIC_API_KEY\"],\n [OpenAIProvider, \"OpenAIProvider\", \"OPENAI_API_KEY\"],\n [GeminiProvider, \"GeminiProvider\", \"GEMINI_API_KEY\"],\n ];\n\n let providerDetected = false;\n for (const [ProviderClass, name, envVar] of providerChecks) {\n if (\n score.provider instanceof\n (ProviderClass as new (...args: unknown[]) => unknown)\n ) {\n providerDetected = true;\n const key = SecretsManager.optional(envVar);\n if (key) {\n ok(\"Provider: \" + name + \" (\" + envVar + \" is set)\");\n } else {\n fail(\"Provider: \" + name + \" (\" + envVar + \" is NOT set)\");\n hasErrors = true;\n }\n }\n }\n\n if (!providerDetected) {\n ok(\"Provider: custom LLMProvider\");\n }\n\n // 3. Count agents\n const agentKeys = Object.keys(score.agents);\n ok(agentKeys.length + \" agent\" + (agentKeys.length === 1 ? \"\" : \"s\") + \" configured\");\n\n // 4. Check voices\n for (const [agentKey, agent] of Object.entries(score.agents)) {\n for (const voice of agent.voices) {\n const voiceName = voice.name;\n\n // Check for known voices and their env vars\n const voiceEnvMap: Record<string, string> = {\n github: \"GITHUB_TOKEN\",\n };\n\n const envVar = voiceEnvMap[voiceName];\n if (envVar) {\n const key = SecretsManager.optional(envVar);\n if (key) {\n ok(\n \"Voice: \" + voiceName + \" on \" + agentKey + \" (\" + envVar + \" is set)\",\n );\n } else {\n fail(\n \"Voice: \" + voiceName + \" on \" + agentKey + \" (\" + envVar + \" is NOT set)\",\n );\n hasErrors = true;\n }\n } else {\n ok(\"Voice: \" + voiceName + \" on \" + agentKey + \" (installed)\");\n }\n }\n }\n\n // Final summary\n console.log(\"\");\n if (hasErrors) {\n console.log(\n chalk.yellow(\"Some checks failed. Fix the issues above and re-run.\"),\n );\n process.exit(1);\n } else {\n console.log(\n chalk.green(\"All checks passed.\") +\n chalk.dim(\" Run tutti-ai run to start.\"),\n );\n }\n}\n","import { existsSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport { execFile } from \"node:child_process\";\nimport express from \"express\";\nimport chalk from \"chalk\";\nimport {\n TuttiRuntime,\n ScoreLoader,\n createLogger,\n} from \"@tuttiai/core\";\nimport type { Response as ExpressResponse } from \"express\";\n\nconst logger = createLogger(\"tutti-studio\");\nconst envPort = Number.parseInt(process.env.PORT ?? \"\", 10);\nconst PORT = Number.isInteger(envPort) && envPort > 0 && envPort <= 65535 ? envPort : 4747;\n\nfunction safeStringify(obj: unknown): string {\n return JSON.stringify(obj, (_key, value: unknown) => {\n if (value instanceof Error) return { message: value.message, name: value.name };\n if (typeof value === \"function\") return undefined;\n return value;\n });\n}\n\nfunction openBrowser(url: string): void {\n if (process.platform === \"win32\") {\n execFile(\"cmd.exe\", [\"/c\", \"start\", \"\", url]);\n return;\n }\n const cmd = process.platform === \"darwin\" ? \"open\" : \"xdg-open\";\n execFile(cmd, [url]);\n}\n\nexport async function studioCommand(scorePath?: string): Promise<void> {\n const file = resolve(scorePath ?? \"./tutti.score.ts\");\n\n if (!existsSync(file)) {\n logger.error({ file }, \"Score file not found\");\n console.error(chalk.dim('Run \"tutti-ai init\" to create a new project.'));\n process.exit(1);\n }\n\n let score;\n try {\n score = await ScoreLoader.load(file);\n } catch (err) {\n logger.error({ error: err instanceof Error ? err.message : String(err) }, \"Failed to load score\");\n process.exit(1);\n }\n\n const runtime = new TuttiRuntime(score);\n\n // Track sessions via events\n const sessionRegistry = new Map<string, { agent_name: string; created_at: Date }>();\n runtime.events.on(\"agent:start\", (e) => {\n if (!sessionRegistry.has(e.session_id)) {\n sessionRegistry.set(e.session_id, { agent_name: e.agent_name, created_at: new Date() });\n }\n });\n\n // SSE clients\n const sseClients = new Set<ExpressResponse>();\n runtime.events.onAny((event) => {\n const data = safeStringify(event);\n for (const client of sseClients) {\n client.write(\"event: tutti\\ndata: \" + data + \"\\n\\n\");\n }\n });\n\n // Express\n const app = express();\n app.use(express.json());\n\n // SSE endpoint\n app.get(\"/events\", (_req, res) => {\n res.writeHead(200, {\n \"Content-Type\": \"text/event-stream\",\n \"Cache-Control\": \"no-cache\",\n Connection: \"keep-alive\",\n });\n res.write(\":\\n\\n\");\n sseClients.add(res);\n _req.on(\"close\", () => sseClients.delete(res));\n });\n\n // REST API\n app.get(\"/api/score\", (_req, res) => {\n const agents = Object.fromEntries(\n Object.entries(runtime.score.agents).map(([id, agent]) => [\n id,\n {\n name: agent.name,\n description: agent.description,\n model: agent.model,\n role: agent.role,\n delegates: agent.delegates,\n voice_count: agent.voices.length,\n voices: agent.voices.map((v) => v.name),\n },\n ]),\n );\n res.json({\n name: runtime.score.name,\n description: runtime.score.description,\n default_model: runtime.score.default_model,\n entry: runtime.score.entry,\n agents,\n });\n });\n\n app.get(\"/api/sessions\", (_req, res) => {\n const sessions = Array.from(sessionRegistry.entries()).map(([id, meta]) => {\n const session = runtime.getSession(id);\n return {\n id,\n agent_name: meta.agent_name,\n message_count: session?.messages.length ?? 0,\n created_at: meta.created_at,\n };\n });\n res.json(sessions.reverse());\n });\n\n app.get(\"/api/sessions/:id\", (req, res) => {\n const session = runtime.getSession(req.params.id);\n if (!session) {\n res.status(404).json({ error: \"Session not found\" });\n return;\n }\n res.json(session);\n });\n\n app.post(\"/api/run\", async (req, res) => {\n const body: unknown = req.body;\n if (typeof body !== \"object\" || body === null) {\n res.status(400).json({ error: \"Invalid request body\" });\n return;\n }\n const agent = (body as Record<string, unknown>).agent;\n const input = (body as Record<string, unknown>).input;\n const session_id = (body as Record<string, unknown>).session_id;\n if (typeof agent !== \"string\" || agent.trim().length === 0) {\n res.status(400).json({ error: \"agent must be a non-empty string\" });\n return;\n }\n if (typeof input !== \"string\" || input.trim().length === 0) {\n res.status(400).json({ error: \"input must be a non-empty string\" });\n return;\n }\n if (session_id !== undefined && (typeof session_id !== \"string\" || session_id.trim().length === 0)) {\n res.status(400).json({ error: \"session_id must be a non-empty string when provided\" });\n return;\n }\n try {\n const result = await runtime.run(agent, input, session_id);\n res.json(result);\n } catch (err) {\n res.status(500).json({ error: err instanceof Error ? err.message : String(err) });\n }\n });\n\n // Serve UI\n app.get(\"/\", (_req, res) => {\n res.type(\"html\").send(getStudioHtml());\n });\n\n app.listen(PORT, () => {\n const url = \"http://localhost:\" + PORT;\n console.log();\n console.log(chalk.bold(\" Tutti Studio\"));\n console.log(chalk.dim(\" \" + url));\n console.log();\n console.log(chalk.dim(\" Score: \") + (runtime.score.name ?? file));\n console.log(chalk.dim(\" Agents: \") + Object.keys(runtime.score.agents).join(\", \"));\n console.log();\n openBrowser(url);\n });\n\n process.on(\"SIGINT\", () => {\n console.log(chalk.dim(\"\\nShutting down Tutti Studio...\"));\n process.exit(0);\n });\n}\n\n// ---------------------------------------------------------------------------\n// Inline HTML UI\n// ---------------------------------------------------------------------------\n\nfunction getStudioHtml(): string {\n return '<!DOCTYPE html>\\\n<html lang=\"en\">\\\n<head>\\\n<meta charset=\"utf-8\">\\\n<meta name=\"viewport\" content=\"width=device-width,initial-scale=1\">\\\n<title>Tutti Studio</title>\\\n<style>\\\n*{margin:0;padding:0;box-sizing:border-box}\\\n:root{\\\n--bg:#0a0a0f;--panel:#12121a;--card:#1a1a26;--input:#0f0f17;\\\n--border:#2a2a3a;--text:#e2e8f0;--muted:#64748b;\\\n--purple:#8b5cf6;--teal:#14b8a6;--blue:#3b82f6;--green:#10b981;\\\n--red:#ef4444;--orange:#f97316;--amber:#f59e0b;--indigo:#6366f1;\\\n}\\\nhtml,body{height:100%;font-family:system-ui,-apple-system,sans-serif;background:var(--bg);color:var(--text);font-size:13px}\\\n#app{display:flex;flex-direction:column;height:100vh}\\\n\\\nheader{display:flex;align-items:center;justify-content:space-between;padding:10px 20px;border-bottom:1px solid var(--border);background:var(--panel)}\\\nheader .logo{font-weight:700;font-size:15px;letter-spacing:.5px}\\\nheader .logo span{color:var(--purple)}\\\nheader .meta{color:var(--muted);font-size:12px}\\\nheader .status{display:flex;align-items:center;gap:6px;font-size:11px;color:var(--muted)}\\\nheader .dot{width:7px;height:7px;border-radius:50%;background:var(--green)}\\\nheader .dot.off{background:var(--red)}\\\n\\\nmain{display:grid;grid-template-columns:260px 1fr 280px;flex:1;overflow:hidden;border-bottom:1px solid var(--border)}\\\n\\\n.panel{display:flex;flex-direction:column;border-right:1px solid var(--border);overflow:hidden}\\\n.panel:last-child{border-right:none}\\\n.panel-title{padding:10px 14px;font-size:11px;font-weight:600;text-transform:uppercase;letter-spacing:.8px;color:var(--muted);border-bottom:1px solid var(--border);background:var(--panel);flex-shrink:0}\\\n.panel-body{flex:1;overflow-y:auto;padding:10px}\\\n.panel-body::-webkit-scrollbar{width:5px}\\\n.panel-body::-webkit-scrollbar-track{background:transparent}\\\n.panel-body::-webkit-scrollbar-thumb{background:var(--border);border-radius:3px}\\\n\\\n#graph-panel .panel-body{padding:0;display:flex;align-items:center;justify-content:center}\\\n#graph-panel svg text{font-family:system-ui,-apple-system,sans-serif}\\\n\\\n#events-panel{display:flex;flex-direction:column}\\\n#event-stream{flex:1;overflow-y:auto;padding:10px}\\\n#event-stream::-webkit-scrollbar{width:5px}\\\n#event-stream::-webkit-scrollbar-track{background:transparent}\\\n#event-stream::-webkit-scrollbar-thumb{background:var(--border);border-radius:3px}\\\n\\\n.ev{padding:7px 10px;margin-bottom:6px;border-radius:6px;background:var(--card);border-left:3px solid var(--muted);font-size:12px;line-height:1.5}\\\n.ev .ev-head{display:flex;justify-content:space-between;align-items:center}\\\n.ev .ev-type{font-weight:600;font-family:\"SF Mono\",Menlo,monospace;font-size:11px}\\\n.ev .ev-time{color:var(--muted);font-size:10px;font-family:\"SF Mono\",Menlo,monospace}\\\n.ev .ev-detail{color:var(--muted);margin-top:3px;font-size:11px;word-break:break-all}\\\n.ev.agent{border-left-color:var(--purple)}.ev.agent .ev-type{color:var(--purple)}\\\n.ev.turn{border-left-color:var(--blue)}.ev.turn .ev-type{color:var(--blue)}\\\n.ev.llm{border-left-color:var(--green)}.ev.llm .ev-type{color:var(--green)}\\\n.ev.tool{border-left-color:var(--teal)}.ev.tool .ev-type{color:var(--teal)}\\\n.ev.tool-error{border-left-color:var(--red)}.ev.tool-error .ev-type{color:var(--red)}\\\n.ev.security{border-left-color:var(--orange)}.ev.security .ev-type{color:var(--orange)}\\\n.ev.budget-warn{border-left-color:var(--amber)}.ev.budget-warn .ev-type{color:var(--amber)}\\\n.ev.budget-exceed{border-left-color:var(--red)}.ev.budget-exceed .ev-type{color:var(--red)}\\\n.ev.delegate{border-left-color:var(--indigo)}.ev.delegate .ev-type{color:var(--indigo)}\\\n\\\n#input-bar{display:flex;gap:8px;padding:10px 12px;border-top:1px solid var(--border);background:var(--panel);flex-shrink:0}\\\n#agent-select{background:var(--input);color:var(--text);border:1px solid var(--border);border-radius:6px;padding:6px 10px;font-size:12px;outline:none;cursor:pointer;min-width:110px}\\\n#user-input{flex:1;background:var(--input);color:var(--text);border:1px solid var(--border);border-radius:6px;padding:6px 12px;font-size:13px;outline:none}\\\n#user-input:focus{border-color:var(--purple)}\\\n#send-btn{background:var(--purple);color:#fff;border:none;border-radius:6px;padding:6px 16px;font-size:12px;font-weight:600;cursor:pointer;white-space:nowrap}\\\n#send-btn:hover{opacity:.9}\\\n#send-btn:disabled{opacity:.4;cursor:default}\\\n\\\n.session-item{padding:8px 10px;margin-bottom:4px;border-radius:6px;background:var(--card);cursor:pointer;transition:background .15s}\\\n.session-item:hover{background:#22223a}\\\n.session-item.active{background:#22223a;border:1px solid var(--purple)}\\\n.session-id{font-family:\"SF Mono\",Menlo,monospace;font-size:11px;color:var(--purple)}\\\n.session-meta{font-size:11px;color:var(--muted);margin-top:2px}\\\n\\\n#session-detail{margin-top:10px;border-top:1px solid var(--border);padding-top:10px}\\\n.msg{padding:6px 8px;margin-bottom:4px;border-radius:5px;font-size:12px;line-height:1.5;word-break:break-word}\\\n.msg.user{background:#1c1c3a;border-left:2px solid var(--blue)}\\\n.msg.assistant{background:#1a2a1a;border-left:2px solid var(--green)}\\\n.msg .msg-role{font-size:10px;font-weight:600;text-transform:uppercase;letter-spacing:.5px;margin-bottom:2px}\\\n.msg.user .msg-role{color:var(--blue)}\\\n.msg.assistant .msg-role{color:var(--green)}\\\n\\\nfooter{display:flex;align-items:center;gap:32px;padding:8px 20px;background:var(--panel);font-size:12px}\\\n.token-item{display:flex;align-items:center;gap:6px}\\\n.token-label{color:var(--muted)}\\\n.token-val{font-family:\"SF Mono\",Menlo,monospace;font-weight:600}\\\n.token-val.input{color:var(--blue)}\\\n.token-val.output{color:var(--green)}\\\n.token-val.cost{color:var(--amber)}\\\n\\\n.empty{color:var(--muted);text-align:center;padding:30px 10px;font-size:12px}\\\n</style>\\\n</head>\\\n<body>\\\n<div id=\"app\">\\\n\\\n<header>\\\n <div class=\"logo\"><span>♫</span> Tutti Studio</div>\\\n <div class=\"meta\" id=\"score-name\"></div>\\\n <div class=\"status\"><div class=\"dot\" id=\"sse-dot\"></div><span id=\"sse-label\">connecting</span></div>\\\n</header>\\\n\\\n<main>\\\n <div class=\"panel\" id=\"graph-panel\">\\\n <div class=\"panel-title\">Agent Graph</div>\\\n <div class=\"panel-body\" id=\"graph-body\"></div>\\\n </div>\\\n\\\n <div class=\"panel\" id=\"events-panel\">\\\n <div class=\"panel-title\">Live Event Stream</div>\\\n <div id=\"event-stream\"><div class=\"empty\">Waiting for events…<br>Send a message below to start an agent run.</div></div>\\\n <div id=\"input-bar\">\\\n <select id=\"agent-select\"></select>\\\n <input id=\"user-input\" placeholder=\"Type a message…\" autocomplete=\"off\">\\\n <button id=\"send-btn\">Send</button>\\\n </div>\\\n </div>\\\n\\\n <div class=\"panel\" id=\"sessions-panel\">\\\n <div class=\"panel-title\">Sessions</div>\\\n <div class=\"panel-body\" id=\"sessions-body\"><div class=\"empty\">No sessions yet</div></div>\\\n </div>\\\n</main>\\\n\\\n<footer>\\\n <div class=\"token-item\"><span class=\"token-label\">↓ Input</span><span class=\"token-val input\" id=\"tok-in\">0</span></div>\\\n <div class=\"token-item\"><span class=\"token-label\">↑ Output</span><span class=\"token-val output\" id=\"tok-out\">0</span></div>\\\n <div class=\"token-item\"><span class=\"token-label\">$ Est. cost</span><span class=\"token-val cost\" id=\"tok-cost\">0.0000</span></div>\\\n</footer>\\\n\\\n</div>\\\n\\\n<script>\\\n(function(){\\\n\\\nvar tokIn=0,tokOut=0;\\\nvar sessionMap={};\\\nvar activeSession=null;\\\n\\\n/* ---- helpers ---- */\\\nfunction esc(s){var d=document.createElement(\"div\");d.textContent=s;return d.innerHTML}\\\nfunction fmt(n){return n.toLocaleString()}\\\nfunction timeStr(){var d=new Date();return (\"0\"+d.getHours()).slice(-2)+\":\"+(\"0\"+d.getMinutes()).slice(-2)+\":\"+(\"0\"+d.getSeconds()).slice(-2)}\\\nfunction truncId(id){return id.slice(0,8)}\\\n\\\n/* ---- score + graph ---- */\\\nfunction loadScore(){\\\n fetch(\"/api/score\").then(function(r){return r.json()}).then(function(s){\\\n document.getElementById(\"score-name\").textContent=s.name||\"tutti.score.ts\";\\\n var sel=document.getElementById(\"agent-select\");\\\n sel.innerHTML=\"\";\\\n Object.keys(s.agents).forEach(function(id){\\\n var o=document.createElement(\"option\");o.value=id;o.textContent=s.agents[id].name;sel.appendChild(o);\\\n });\\\n renderGraph(s);\\\n });\\\n}\\\n\\\nfunction renderGraph(score){\\\n var body=document.getElementById(\"graph-body\");\\\n var W=260,ids=Object.keys(score.agents),N=ids.length;\\\n if(N===0){body.innerHTML=\"<div class=\\\\\"empty\\\\\">No agents</div>\";return}\\\n var hasDelegate=false;\\\n ids.forEach(function(id){if(score.agents[id].delegates&&score.agents[id].delegates.length)hasDelegate=true});\\\n var nodeR=26,padY=90,padTop=50;\\\n var leftIds=[],rightIds=[];\\\n if(hasDelegate){\\\n ids.forEach(function(id){var a=score.agents[id];if(a.delegates&&a.delegates.length)leftIds.push(id);else rightIds.push(id)});\\\n }else{leftIds=ids}\\\n var cols=hasDelegate?2:1;\\\n var cx1=cols===1?W/2:72,cx2=W-72;\\\n var H=Math.max(leftIds.length,rightIds.length)*padY+padTop*2;\\\n if(H<200)H=200;\\\n var pos={};\\\n var svg=\\'<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"\\'+W+\\'\" height=\"\\'+H+\\'\" viewBox=\"0 0 \\'+W+\" \"+H+\\'\">\\';\\\n svg+=\\'<defs><marker id=\"ah\" viewBox=\"0 0 10 10\" refX=\"10\" refY=\"5\" markerWidth=\"5\" markerHeight=\"5\" orient=\"auto\"><path d=\"M0 0L10 5L0 10z\" fill=\"#64748b\"/></marker></defs>\\';\\\n function drawNode(id,cx,cy){\\\n var a=score.agents[id];\\\n var col=a.role===\"orchestrator\"?\"#8b5cf6\":\"#14b8a6\";\\\n pos[id]={x:cx,y:cy};\\\n svg+=\\'<circle cx=\"\\'+cx+\\'\" cy=\"\\'+cy+\\'\" r=\"\\'+nodeR+\\'\" fill=\"\\'+col+\\'\" fill-opacity=\"0.15\" stroke=\"\\'+col+\\'\" stroke-width=\"2\"/>\\';\\\n svg+=\\'<text x=\"\\'+cx+\\'\" y=\"\\'+(cy+4)+\\'\" text-anchor=\"middle\" fill=\"#e2e8f0\" font-size=\"10\" font-weight=\"600\">\\'+esc(a.name)+\\'</text>\\';\\\n var model=a.model||score.default_model||\"\";\\\n if(model){var sh=model.replace(/-\\\\d{8}$/,\"\");if(sh.length>18)sh=sh.slice(0,18)+\"\\\\u2026\";svg+=\\'<text x=\"\\'+cx+\\'\" y=\"\\'+(cy+nodeR+14)+\\'\" text-anchor=\"middle\" fill=\"#64748b\" font-size=\"9\">\\'+esc(sh)+\\'</text>\\'}\\\n svg+=\\'<text x=\"\\'+cx+\\'\" y=\"\\'+(cy+nodeR+26)+\\'\" text-anchor=\"middle\" fill=\"#64748b\" font-size=\"9\">\\'+a.voice_count+\" voice\"+(a.voice_count!==1?\"s\":\"\")+\\'</text>\\';\\\n }\\\n leftIds.forEach(function(id,i){drawNode(id,cx1,padTop+i*padY)});\\\n rightIds.forEach(function(id,i){drawNode(id,cx2,padTop+i*padY)});\\\n ids.forEach(function(id){\\\n var a=score.agents[id];\\\n if(a.delegates)a.delegates.forEach(function(did){\\\n if(pos[id]&&pos[did]){\\\n var x1=pos[id].x+nodeR,y1=pos[id].y,x2=pos[did].x-nodeR,y2=pos[did].y;\\\n var mx=(x1+x2)/2;\\\n svg+=\\'<path d=\"M\\'+x1+\" \"+y1+\" C\"+mx+\" \"+y1+\" \"+mx+\" \"+y2+\" \"+x2+\" \"+y2+\\'\" fill=\"none\" stroke=\"#64748b\" stroke-width=\"1.5\" stroke-dasharray=\"4 3\" marker-end=\"url(#ah)\"/>\\';\\\n }\\\n });\\\n });\\\n svg+=\"</svg>\";\\\n body.innerHTML=svg;\\\n}\\\n\\\n/* ---- SSE ---- */\\\nfunction connectSSE(){\\\n var es=new EventSource(\"/events\");\\\n es.addEventListener(\"tutti\",function(e){\\\n var ev=JSON.parse(e.data);\\\n addEvent(ev);\\\n if(ev.type===\"llm:response\"&&ev.response&&ev.response.usage){\\\n tokIn+=ev.response.usage.input_tokens||0;\\\n tokOut+=ev.response.usage.output_tokens||0;\\\n document.getElementById(\"tok-in\").textContent=fmt(tokIn);\\\n document.getElementById(\"tok-out\").textContent=fmt(tokOut);\\\n document.getElementById(\"tok-cost\").textContent=estimateCost(tokIn,tokOut);\\\n }\\\n if(ev.type===\"agent:start\"||ev.type===\"agent:end\")refreshSessions();\\\n });\\\n es.onopen=function(){document.getElementById(\"sse-dot\").className=\"dot\";document.getElementById(\"sse-label\").textContent=\"connected\"};\\\n es.onerror=function(){document.getElementById(\"sse-dot\").className=\"dot off\";document.getElementById(\"sse-label\").textContent=\"disconnected\"};\\\n}\\\n\\\n/* Pricing: USD per 1M tokens (Sonnet-class default) */\\\nvar INPUT_PRICE_PER_MILLION=3;\\\nvar OUTPUT_PRICE_PER_MILLION=15;\\\nfunction estimateCost(inp,out){\\\n var c=(inp/1e6)*INPUT_PRICE_PER_MILLION+(out/1e6)*OUTPUT_PRICE_PER_MILLION;\\\n return c.toFixed(4);\\\n}\\\n\\\nfunction evClass(t){\\\n if(t.indexOf(\"agent\")===0)return \"agent\";\\\n if(t.indexOf(\"turn\")===0)return \"turn\";\\\n if(t===\"llm:request\"||t===\"llm:response\")return \"llm\";\\\n if(t===\"tool:error\")return \"tool-error\";\\\n if(t.indexOf(\"tool\")===0)return \"tool\";\\\n if(t.indexOf(\"security\")===0)return \"security\";\\\n if(t===\"budget:warning\")return \"budget-warn\";\\\n if(t===\"budget:exceeded\")return \"budget-exceed\";\\\n if(t.indexOf(\"delegate\")===0)return \"delegate\";\\\n return \"\";\\\n}\\\n\\\nfunction evDetail(ev){\\\n var parts=[];\\\n if(ev.agent_name)parts.push(\"agent: \"+ev.agent_name);\\\n if(ev.session_id)parts.push(\"session: \"+truncId(ev.session_id));\\\n if(ev.turn!==undefined)parts.push(\"turn: \"+ev.turn);\\\n if(ev.tool_name)parts.push(\"tool: \"+ev.tool_name);\\\n if(ev.from)parts.push(\"from: \"+ev.from);\\\n if(ev.to)parts.push(\"to: \"+ev.to);\\\n if(ev.tokens!==undefined)parts.push(\"tokens: \"+fmt(ev.tokens));\\\n if(ev.cost_usd!==undefined)parts.push(\"cost: $\"+ev.cost_usd.toFixed(4));\\\n if(ev.response&&ev.response.usage)parts.push(\"tokens: \"+fmt(ev.response.usage.input_tokens)+\" in / \"+fmt(ev.response.usage.output_tokens)+\" out\");\\\n if(ev.error){var em=typeof ev.error===\"object\"?ev.error.message||\"\":ev.error;if(em)parts.push(\"error: \"+em)}\\\n if(ev.patterns)parts.push(\"patterns: \"+ev.patterns.join(\", \"));\\\n return parts.join(\" · \");\\\n}\\\n\\\nvar firstEvent=true;\\\nfunction addEvent(ev){\\\n var stream=document.getElementById(\"event-stream\");\\\n if(firstEvent){stream.innerHTML=\"\";firstEvent=false}\\\n var div=document.createElement(\"div\");\\\n div.className=\"ev \"+evClass(ev.type);\\\n div.innerHTML=\\'<div class=\"ev-head\"><span class=\"ev-type\">\\'+esc(ev.type)+\\'</span><span class=\"ev-time\">\\'+timeStr()+\\'</span></div>\\';\\\n var det=evDetail(ev);\\\n if(det)div.innerHTML+=\\'<div class=\"ev-detail\">\\'+det+\"</div>\";\\\n stream.appendChild(div);\\\n stream.scrollTop=stream.scrollHeight;\\\n}\\\n\\\n/* ---- sessions ---- */\\\nfunction refreshSessions(){\\\n fetch(\"/api/sessions\").then(function(r){return r.json()}).then(function(list){\\\n var body=document.getElementById(\"sessions-body\");\\\n if(!list.length){body.innerHTML=\\'<div class=\"empty\">No sessions yet</div>\\';return}\\\n var html=\"\";\\\n list.forEach(function(s){\\\n var cls=\"session-item\"+(activeSession===s.id?\" active\":\"\");\\\n html+=\\'<div class=\"\\'+cls+\\'\" data-id=\"\\'+s.id+\\'\">\\';\\\n html+=\\'<div class=\"session-id\">\\'+truncId(s.id)+\"</div>\";\\\n html+=\\'<div class=\"session-meta\">\\'+esc(s.agent_name)+\" · \"+s.message_count+\" msgs</div>\";\\\n html+=\"</div>\";\\\n });\\\n if(activeSession)html+=\\'<div id=\"session-detail\"></div>\\';\\\n body.innerHTML=html;\\\n body.querySelectorAll(\".session-item\").forEach(function(el){\\\n el.addEventListener(\"click\",function(){selectSession(el.getAttribute(\"data-id\"))});\\\n });\\\n if(activeSession)loadSessionDetail(activeSession);\\\n });\\\n}\\\n\\\nfunction selectSession(id){\\\n activeSession=activeSession===id?null:id;\\\n refreshSessions();\\\n}\\\n\\\nfunction loadSessionDetail(id){\\\n var det=document.getElementById(\"session-detail\");\\\n if(!det)return;\\\n fetch(\"/api/sessions/\"+id).then(function(r){return r.json()}).then(function(session){\\\n if(!session||session.error){det.innerHTML=\\'<div class=\"empty\">Session not found</div>\\';return}\\\n var html=\"\";\\\n (session.messages||[]).forEach(function(m){\\\n var role=m.role;\\\n var text=\"\";\\\n if(typeof m.content===\"string\")text=m.content;\\\n else if(Array.isArray(m.content)){\\\n m.content.forEach(function(b){\\\n if(b.type===\"text\")text+=b.text+\"\\\\n\";\\\n else if(b.type===\"tool_use\")text+=\"[tool_use: \"+b.name+\"]\\\\n\";\\\n else if(b.type===\"tool_result\")text+=\"[tool_result]\\\\n\";\\\n });\\\n }\\\n html+=\\'<div class=\"msg \\'+role+\\'\"><div class=\"msg-role\">\\'+role+\"</div>\"+esc(text.trim())+\"</div>\";\\\n });\\\n det.innerHTML=html;\\\n });\\\n}\\\n\\\n/* ---- send ---- */\\\nfunction sendMessage(){\\\n var agentSel=document.getElementById(\"agent-select\");\\\n var inputEl=document.getElementById(\"user-input\");\\\n var btn=document.getElementById(\"send-btn\");\\\n var agent=agentSel.value;\\\n var input=inputEl.value.trim();\\\n if(!input)return;\\\n btn.disabled=true;btn.textContent=\"Running\\\\u2026\";\\\n inputEl.value=\"\";\\\n var sid=sessionMap[agent]||undefined;\\\n fetch(\"/api/run\",{method:\"POST\",headers:{\"Content-Type\":\"application/json\"},body:JSON.stringify({agent:agent,input:input,session_id:sid})})\\\n .then(function(r){return r.json()})\\\n .then(function(result){\\\n if(result.session_id)sessionMap[agent]=result.session_id;\\\n if(result.output){\\\n addEvent({type:\"__output\",agent_name:agent,output:result.output});\\\n }\\\n refreshSessions();\\\n })\\\n .catch(function(err){addEvent({type:\"__error\",error:err.message||String(err)})})\\\n .finally(function(){btn.disabled=false;btn.textContent=\"Send\"});\\\n}\\\n\\\ndocument.getElementById(\"send-btn\").addEventListener(\"click\",sendMessage);\\\ndocument.getElementById(\"user-input\").addEventListener(\"keydown\",function(e){if(e.key===\"Enter\"&&!e.shiftKey){e.preventDefault();sendMessage()}});\\\n\\\n/* ---- init ---- */\\\nloadScore();\\\nconnectSSE();\\\n\\\n})();\\\n</script>\\\n</body>\\\n</html>';\n}\n","import { existsSync, readFileSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport chalk from \"chalk\";\nimport ora from \"ora\";\nimport { createLogger } from \"@tuttiai/core\";\n\nconst logger = createLogger(\"tutti-cli\");\n\nconst REGISTRY_URL =\n \"https://raw.githubusercontent.com/tuttiai/voices/main/voices.json\";\n\ninterface VoiceEntry {\n name: string;\n package: string;\n description: string;\n tags: string[];\n official: boolean;\n tools: number;\n}\n\n// Built-in fallback when the remote registry is unreachable\nconst BUILTIN_VOICES: VoiceEntry[] = [\n {\n name: \"filesystem\",\n package: \"@tuttiai/filesystem\",\n description: \"Read, write, search, and manage files and directories\",\n tags: [\"filesystem\", \"files\", \"io\", \"read\", \"write\"],\n official: true,\n tools: 7,\n },\n {\n name: \"github\",\n package: \"@tuttiai/github\",\n description: \"Interact with GitHub repos, issues, PRs, and code search\",\n tags: [\"github\", \"git\", \"code\", \"issues\", \"pull-requests\", \"api\"],\n official: true,\n tools: 10,\n },\n {\n name: \"playwright\",\n package: \"@tuttiai/playwright\",\n description: \"Control a browser like a human — navigate, click, type, screenshot\",\n tags: [\"browser\", \"playwright\", \"web\", \"qa\", \"testing\", \"automation\", \"scraping\"],\n official: true,\n tools: 12,\n },\n {\n name: \"postgres\",\n package: \"pg\",\n description: \"PostgreSQL session persistence and database access\",\n tags: [\"database\", \"postgres\", \"sql\", \"persistence\", \"sessions\"],\n official: true,\n tools: 0,\n },\n];\n\ninterface RegistryEntry {\n name: string;\n package: string;\n description: string;\n tags: string[];\n}\n\nasync function fetchRegistry(): Promise<VoiceEntry[]> {\n try {\n const res = await fetch(REGISTRY_URL);\n if (!res.ok) throw new Error(\"HTTP \" + res.status);\n const data = (await res.json()) as { official?: RegistryEntry[]; community?: RegistryEntry[] };\n\n const voices: VoiceEntry[] = [];\n for (const entry of data.official ?? []) {\n voices.push({ ...entry, official: true, tools: toolCount(entry.name) });\n }\n for (const entry of data.community ?? []) {\n voices.push({ ...entry, official: false, tools: 0 });\n }\n if (voices.length === 0) throw new Error(\"Empty registry\");\n return voices;\n } catch {\n logger.debug(\"Registry unreachable, using built-in voice list\");\n return BUILTIN_VOICES;\n }\n}\n\nfunction toolCount(name: string): number {\n const counts: Record<string, number> = { filesystem: 7, github: 10, playwright: 12 };\n return counts[name] ?? 0;\n}\n\nfunction matchesQuery(voice: VoiceEntry, query: string): boolean {\n const q = query.toLowerCase();\n if (voice.name.toLowerCase().includes(q)) return true;\n if (voice.description.toLowerCase().includes(q)) return true;\n if (voice.tags.some((t) => t.toLowerCase().includes(q))) return true;\n return false;\n}\n\nfunction isInstalled(packageName: string): boolean {\n const pkgPath = resolve(process.cwd(), \"package.json\");\n if (!existsSync(pkgPath)) return false;\n try {\n const pkg = JSON.parse(readFileSync(pkgPath, \"utf-8\")) as { dependencies?: Record<string, string>; devDependencies?: Record<string, string> };\n const deps: Record<string, string> = { ...pkg.dependencies, ...pkg.devDependencies };\n return packageName in deps;\n } catch {\n return false;\n }\n}\n\nfunction printVoice(voice: VoiceEntry, showInstallStatus: boolean): void {\n const badge = voice.official\n ? chalk.green(\" [official]\")\n : chalk.blue(\" [community]\");\n const installed = showInstallStatus && isInstalled(voice.package);\n const status = showInstallStatus\n ? installed\n ? chalk.green(\" ✔ installed\")\n : chalk.dim(\" not installed\")\n : \"\";\n\n console.log();\n console.log(\" \" + chalk.bold(voice.package) + badge + status);\n console.log(\" \" + voice.description);\n\n const installCmd = voice.official && voice.name !== \"postgres\"\n ? \"tutti-ai add \" + voice.name\n : \"npm install \" + voice.package;\n console.log(\" \" + chalk.dim(\"Install: \") + chalk.cyan(installCmd));\n\n if (voice.tags.length > 0) {\n console.log(\" \" + chalk.dim(\"Tags: \") + voice.tags.join(\", \"));\n }\n}\n\nexport async function searchCommand(query: string): Promise<void> {\n const spinner = ora(\"Searching the Repertoire...\").start();\n\n const voices = await fetchRegistry();\n const results = voices.filter((v) => matchesQuery(v, query));\n\n spinner.stop();\n\n if (results.length === 0) {\n console.log();\n console.log(chalk.yellow(' No voices found for \"' + query + '\"'));\n console.log();\n console.log(chalk.dim(\" Browse all: https://tutti-ai.com/voices\"));\n console.log(chalk.dim(\" Build your own: tutti-ai create voice <name>\"));\n console.log();\n return;\n }\n\n console.log();\n console.log(\n \" Found \" +\n chalk.bold(String(results.length)) +\n \" voice\" +\n (results.length !== 1 ? \"s\" : \"\") +\n \" matching \" +\n chalk.cyan(\"'\" + query + \"'\") +\n \":\",\n );\n\n for (const voice of results) {\n printVoice(voice, false);\n }\n console.log();\n}\n\nexport async function voicesCommand(): Promise<void> {\n const spinner = ora(\"Loading voices...\").start();\n\n const voices = await fetchRegistry();\n const official = voices.filter((v) => v.official);\n\n spinner.stop();\n\n console.log();\n console.log(\" \" + chalk.bold(\"Official Tutti Voices\"));\n console.log();\n\n for (const voice of official) {\n printVoice(voice, true);\n }\n\n const community = voices.filter((v) => !v.official);\n if (community.length > 0) {\n console.log();\n console.log(\" \" + chalk.bold(\"Community Voices\"));\n for (const voice of community) {\n printVoice(voice, true);\n }\n }\n\n console.log();\n console.log(chalk.dim(\" Search: tutti-ai search <query>\"));\n console.log(chalk.dim(\" Browse: https://tutti-ai.com/voices\"));\n console.log();\n}\n","import { existsSync, readFileSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport { execSync } from \"node:child_process\";\nimport chalk from \"chalk\";\nimport ora from \"ora\";\nimport Enquirer from \"enquirer\";\nimport { createLogger, SecretsManager } from \"@tuttiai/core\";\n\nconst { prompt } = Enquirer;\nconst logger = createLogger(\"tutti-cli\");\n\ninterface PkgJson {\n name?: string;\n version?: string;\n description?: string;\n license?: string;\n exports?: unknown;\n}\n\nfunction readPkg(dir: string): PkgJson | undefined {\n const p = resolve(dir, \"package.json\");\n if (!existsSync(p)) return undefined;\n return JSON.parse(readFileSync(p, \"utf-8\")) as PkgJson;\n}\n\nfunction run(cmd: string, cwd: string): string {\n return execSync(cmd, { cwd, stdio: \"pipe\", encoding: \"utf-8\" });\n}\n\nfunction fail(msg: string): never {\n console.error(chalk.red(\" \" + msg));\n process.exit(1);\n}\n\nconst ok = (msg: string) => console.log(chalk.green(\" ✔ \" + msg));\n\nexport async function publishCommand(opts: { dryRun?: boolean }): Promise<void> {\n const cwd = process.cwd();\n const pkg = readPkg(cwd);\n\n console.log();\n console.log(chalk.bold(\" Tutti Voice Publisher\"));\n console.log();\n\n // ── Step 1: Pre-flight checks ──\n\n const spinner = ora(\"Running pre-flight checks...\").start();\n\n // 1a. Must be a voice directory\n if (!pkg) fail(\"No package.json found in the current directory.\");\n if (!existsSync(resolve(cwd, \"src/index.ts\"))) fail(\"No src/index.ts found — are you inside a voice directory?\");\n\n // 1b. Required fields\n const missing: string[] = [];\n if (!pkg.name) missing.push(\"name\");\n if (!pkg.version) missing.push(\"version\");\n if (!pkg.description) missing.push(\"description\");\n if (!pkg.license) missing.push(\"license\");\n if (!pkg.exports) missing.push(\"exports\");\n if (missing.length > 0) fail(\"package.json is missing: \" + missing.join(\", \"));\n\n const name = pkg.name!;\n const version = pkg.version!;\n\n // 1c. Name convention\n const validName = name.startsWith(\"@tuttiai/\") || name.startsWith(\"tutti\");\n if (!validName) fail(\"Package name must start with @tuttiai/ or tutti — got: \" + name);\n\n // 1d. Check required_permissions is declared in source\n const src = readFileSync(resolve(cwd, \"src/index.ts\"), \"utf-8\");\n if (!src.includes(\"required_permissions\")) {\n fail(\"Voice class must declare required_permissions in src/index.ts\");\n }\n\n spinner.succeed(\"Pre-flight checks passed\");\n\n // 1e. Build\n const buildSpinner = ora(\"Building...\").start();\n try {\n run(\"npm run build\", cwd);\n buildSpinner.succeed(\"Build succeeded\");\n } catch (err) {\n buildSpinner.fail(\"Build failed\");\n const msg = err instanceof Error ? err.message : String(err);\n console.error(chalk.dim(\" \" + msg.split(\"\\n\").slice(0, 5).join(\"\\n \")));\n process.exit(1);\n }\n\n // 1f. Tests\n const testSpinner = ora(\"Running tests...\").start();\n try {\n run(\"npx vitest run\", cwd);\n testSpinner.succeed(\"Tests passed\");\n } catch {\n testSpinner.fail(\"Tests failed\");\n process.exit(1);\n }\n\n // 1g. Audit\n const auditSpinner = ora(\"Checking vulnerabilities...\").start();\n try {\n run(\"npm audit --audit-level=high\", cwd);\n auditSpinner.succeed(\"No high/critical vulnerabilities\");\n } catch {\n auditSpinner.stopAndPersist({ symbol: chalk.yellow(\"⚠\"), text: \"Vulnerabilities found (npm audit)\" });\n }\n\n // ── Step 2: Dry run ──\n\n console.log();\n const drySpinner = ora(\"Packing (dry run)...\").start();\n let packOutput: string;\n try {\n packOutput = run(\"npm pack --dry-run 2>&1\", cwd);\n drySpinner.succeed(\"Pack dry-run complete\");\n } catch (err) {\n drySpinner.fail(\"Pack dry-run failed\");\n const msg = err instanceof Error ? err.message : String(err);\n console.error(chalk.dim(\" \" + msg));\n process.exit(1);\n }\n\n // Show files from the pack output\n const fileLines = packOutput\n .split(\"\\n\")\n .filter((l) => l.includes(\"npm notice\") && /\\d+(\\.\\d+)?\\s*[kM]?B\\s/.test(l))\n .map((l) => l.replace(/npm notice\\s*/, \"\"));\n\n if (fileLines.length > 0) {\n console.log(chalk.dim(\" Files:\"));\n for (const line of fileLines) {\n console.log(chalk.dim(\" \" + line.trim()));\n }\n }\n\n // Show totals\n const sizeLine = packOutput.split(\"\\n\").find((l) => l.includes(\"package size\"));\n const totalLine = packOutput.split(\"\\n\").find((l) => l.includes(\"total files\"));\n if (sizeLine) console.log(chalk.dim(\" \" + sizeLine.replace(/npm notice\\s*/, \"\").trim()));\n if (totalLine) console.log(chalk.dim(\" \" + totalLine.replace(/npm notice\\s*/, \"\").trim()));\n\n if (opts.dryRun) {\n console.log();\n ok(\"Dry run complete — no packages were published\");\n console.log(chalk.dim(\" Run without --dry-run to publish for real.\"));\n console.log();\n return;\n }\n\n // Prompt for confirmation\n console.log();\n const { confirm } = await prompt<{ confirm: boolean }>({\n type: \"confirm\",\n name: \"confirm\",\n message: \"Publish \" + chalk.cyan(name + \"@\" + version) + \"?\",\n });\n\n if (!confirm) {\n console.log(chalk.dim(\" Cancelled.\"));\n return;\n }\n\n // ── Step 3: Publish ──\n\n const pubSpinner = ora(\"Publishing to npm...\").start();\n try {\n run(\"npm publish --access public\", cwd);\n pubSpinner.succeed(\"Published \" + chalk.cyan(name + \"@\" + version));\n } catch (err) {\n pubSpinner.fail(\"Publish failed\");\n const msg = err instanceof Error ? err.message : String(err);\n logger.error({ error: msg }, \"npm publish failed\");\n process.exit(1);\n }\n\n // ── Step 4: Open PR to voice registry ──\n\n const ghToken = SecretsManager.optional(\"GITHUB_TOKEN\");\n let prUrl: string | undefined;\n\n if (ghToken) {\n const prSpinner = ora(\"Opening PR to voice registry...\").start();\n try {\n prUrl = await openRegistryPR(name, version, pkg.description ?? \"\", ghToken);\n prSpinner.succeed(\"PR opened: \" + prUrl);\n } catch (err) {\n prSpinner.fail(\"Failed to open PR\");\n const msg = err instanceof Error ? err.message : String(err);\n logger.error({ error: msg }, \"Registry PR failed\");\n }\n } else {\n console.log();\n console.log(chalk.dim(\" To list in the Repertoire, set GITHUB_TOKEN and re-run\"));\n console.log(chalk.dim(\" Or open a PR manually: github.com/tuttiai/voices\"));\n }\n\n // ── Step 5: Summary ──\n\n console.log();\n ok(name + \"@\" + version + \" published to npm\");\n if (prUrl) ok(\"PR opened to tuttiai/voices\");\n const shortName = name.replace(\"@tuttiai/\", \"\").replace(/^tutti-?/, \"\");\n ok(\"Install: tutti-ai add \" + shortName);\n ok(\"View: https://www.npmjs.com/package/\" + name);\n console.log();\n}\n\nasync function openRegistryPR(\n packageName: string,\n version: string,\n description: string,\n token: string,\n): Promise<string> {\n const owner = \"tuttiai\";\n const repo = \"voices\";\n const branch = \"add-\" + packageName.replace(/[@/]/g, \"-\").replace(/^-/, \"\");\n const shortName = packageName.replace(\"@tuttiai/\", \"\").replace(/^tutti-?/, \"\");\n const isOfficial = packageName.startsWith(\"@tuttiai/\");\n\n // 1. Get current voices.json content and SHA\n const fileRes = await fetch(\n \"https://api.github.com/repos/\" + owner + \"/\" + repo + \"/contents/voices.json\",\n { headers: { Authorization: \"Bearer \" + token, Accept: \"application/vnd.github.v3+json\" } },\n );\n if (!fileRes.ok) throw new Error(\"Failed to fetch voices.json: \" + fileRes.status);\n const fileData = (await fileRes.json()) as { content: string; sha: string };\n\n interface RegistryVoice { name: string; package: string; description: string; version: string; author: string; tags: string[]; repo?: string }\n interface Registry { official: RegistryVoice[]; community: RegistryVoice[] }\n\n const registry = JSON.parse(Buffer.from(fileData.content, \"base64\").toString(\"utf-8\")) as Registry;\n\n // 2. Add the new voice entry\n const section: keyof Registry = isOfficial ? \"official\" : \"community\";\n const entry: RegistryVoice = {\n name: shortName,\n package: packageName,\n description,\n repo: \"https://github.com/tuttiai/tutti/tree/main/voices/\" + shortName,\n version,\n author: isOfficial ? \"tuttiai\" : packageName.split(\"/\")[0]?.replace(\"@\", \"\") ?? \"community\",\n tags: [shortName],\n };\n\n if (!registry[section]) registry[section] = [];\n const exists = registry[section].some((v) => v.package === packageName);\n if (exists) {\n const idx = registry[section].findIndex((v) => v.package === packageName);\n registry[section][idx] = { ...registry[section][idx], ...entry };\n } else {\n registry[section].push(entry);\n }\n\n const updatedContent = Buffer.from(JSON.stringify(registry, null, 2) + \"\\n\").toString(\"base64\");\n\n // 3. Get default branch SHA\n const mainRes = await fetch(\n \"https://api.github.com/repos/\" + owner + \"/\" + repo + \"/git/ref/heads/main\",\n { headers: { Authorization: \"Bearer \" + token, Accept: \"application/vnd.github.v3+json\" } },\n );\n if (!mainRes.ok) throw new Error(\"Failed to get main ref: \" + mainRes.status);\n const mainData = (await mainRes.json()) as { object: { sha: string } };\n\n // 4. Create branch\n await fetch(\"https://api.github.com/repos/\" + owner + \"/\" + repo + \"/git/refs\", {\n method: \"POST\",\n headers: { Authorization: \"Bearer \" + token, \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ ref: \"refs/heads/\" + branch, sha: mainData.object.sha }),\n });\n\n // 5. Update voices.json on the new branch\n await fetch(\n \"https://api.github.com/repos/\" + owner + \"/\" + repo + \"/contents/voices.json\",\n {\n method: \"PUT\",\n headers: { Authorization: \"Bearer \" + token, \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n message: \"feat: add \" + packageName + \" to the Repertoire\",\n content: updatedContent,\n sha: fileData.sha,\n branch,\n }),\n },\n );\n\n // 6. Create PR\n const prRes = await fetch(\"https://api.github.com/repos/\" + owner + \"/\" + repo + \"/pulls\", {\n method: \"POST\",\n headers: { Authorization: \"Bearer \" + token, \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n title: \"feat: add \" + packageName + \" to the Repertoire\",\n head: branch,\n base: \"main\",\n body: \"## New voice: \" + packageName + \"@\" + version + \"\\n\\n\" + description + \"\\n\\nPublished via `tutti-ai publish`.\",\n }),\n });\n\n if (!prRes.ok) {\n const err = await prRes.text();\n throw new Error(\"Failed to create PR: \" + prRes.status + \" \" + err);\n }\n\n const prData = (await prRes.json()) as { html_url: string };\n return prData.html_url;\n}\n","import { existsSync, readFileSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport chalk from \"chalk\";\nimport ora from \"ora\";\nimport {\n ScoreLoader,\n EvalRunner,\n printEvalTable,\n createLogger,\n} from \"@tuttiai/core\";\nimport type { EvalSuite } from \"@tuttiai/core\";\n\nconst logger = createLogger(\"tutti-cli\");\n\nexport async function evalCommand(suitePath: string, opts: { ci?: boolean; score?: string }): Promise<void> {\n const suiteFile = resolve(suitePath);\n if (!existsSync(suiteFile)) {\n logger.error({ file: suiteFile }, \"Suite file not found\");\n process.exit(1);\n }\n\n // Load the eval suite JSON\n let suite: EvalSuite;\n try {\n suite = JSON.parse(readFileSync(suiteFile, \"utf-8\")) as EvalSuite;\n } catch (err) {\n logger.error({ error: err instanceof Error ? err.message : String(err) }, \"Failed to parse suite file\");\n process.exit(1);\n }\n\n // Load score\n const scoreFile = resolve(opts.score ?? \"./tutti.score.ts\");\n if (!existsSync(scoreFile)) {\n logger.error({ file: scoreFile }, \"Score file not found\");\n process.exit(1);\n }\n\n const spinner = ora(\"Loading score...\").start();\n let score;\n try {\n score = await ScoreLoader.load(scoreFile);\n } catch (err) {\n spinner.fail(\"Failed to load score\");\n logger.error({ error: err instanceof Error ? err.message : String(err) }, \"Score load failed\");\n process.exit(1);\n }\n spinner.succeed(\"Score loaded\");\n\n // Run eval\n const evalSpinner = ora(\"Running \" + suite.cases.length + \" eval cases...\").start();\n const runner = new EvalRunner(score);\n const report = await runner.run(suite);\n evalSpinner.stop();\n\n // Print results\n printEvalTable(report);\n\n // CI mode: exit 1 if any failed\n if (opts.ci && report.summary.failed > 0) {\n console.error(chalk.red(\" CI mode: \" + report.summary.failed + \" case(s) failed\"));\n process.exit(1);\n }\n}\n"],"mappings":"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","names":["createLogger","existsSync","resolve","chalk","createLogger","logger","createLogger","resolve","existsSync","chalk","existsSync","resolve","createInterface","chalk","ora","AnthropicProvider","GeminiProvider","OpenAIProvider","ScoreLoader","SecretsManager","TuttiRuntime","createLogger","logger","existsSync","resolve","chalk","ora","createLogger","logger","existsSync","resolve","chalk","ScoreLoader","AnthropicProvider","OpenAIProvider","GeminiProvider","SecretsManager","createLogger","logger","existsSync","resolve","chalk","TuttiRuntime","ScoreLoader","createLogger","logger","existsSync","readFileSync","resolve","chalk","ora","createLogger","logger","existsSync","readFileSync","resolve","execSync","chalk","ora","Enquirer","createLogger","SecretsManager","prompt","logger","fail","ok","existsSync","readFileSync","resolve","chalk","ora","ScoreLoader","createLogger","logger","logger","createLogger"]}
|