@tuttiai/cli 0.9.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 CHANGED
@@ -29,6 +29,8 @@ Load a score file and open an interactive REPL:
29
29
  ```bash
30
30
  tutti-ai run # defaults to ./tutti.score.ts
31
31
  tutti-ai run ./custom-score.ts # specify a score file
32
+ tutti-ai run --watch # hot-reload the score on file changes
33
+ tutti-ai run -w ./score.ts # short alias
32
34
  ```
33
35
 
34
36
  Features:
@@ -36,6 +38,44 @@ Features:
36
38
  - Colored tool execution trace
37
39
  - Session continuity across messages
38
40
  - Graceful Ctrl+C handling
41
+ - Hot reload with `--watch` / `-w` (see below)
42
+
43
+ #### Watch mode
44
+
45
+ `--watch` reloads the score (and any file in the score's directory tree,
46
+ excluding `node_modules`, `dist`, and dotfiles) whenever it changes on
47
+ disk. Changes are debounced 200ms so editor saves that touch the file
48
+ multiple times collapse into a single reload.
49
+
50
+ ```
51
+ > research quantum computing
52
+ [tutti] Score changed, reloading...
53
+ [tutti] Score reloaded. Changes applied.
54
+ > what did you learn last turn?
55
+ ```
56
+
57
+ Semantics:
58
+
59
+ - **Changes take effect at turn boundaries**, never mid-tool-call. The
60
+ current turn always completes with the config it started with; the
61
+ next turn reads the new config.
62
+ - **Session history is preserved** across reloads — the REPL's
63
+ `session_id` carries over, so the conversation continues.
64
+ - **Syntax errors are recovered** — if the reload fails to parse or
65
+ validate, the error is printed and the REPL keeps using the previous
66
+ config. Fix the file and save again.
67
+ - **Trade-off**: runtime internals (tool cache, semantic memory) reset
68
+ on reload. Conversation history survives because the REPL owns the
69
+ session store and reuses it across runtime swaps.
70
+
71
+ Deferred (known gaps):
72
+ - The watcher uses a directory-tree watch, not a resolved import graph —
73
+ unrelated file edits in the project tree will also trigger reloads.
74
+ A future revision may use `madge` or the TS compiler API for
75
+ precision.
76
+ - Voice-level partial reload isn't implemented; the whole runtime is
77
+ rebuilt on every change. Fast enough in practice (typically <50ms)
78
+ but means runtime-internal caches reset.
39
79
 
40
80
  ### `tutti-ai resume <session-id>`
41
81
 
package/dist/index.js CHANGED
@@ -356,7 +356,7 @@ function templatesCommand() {
356
356
 
357
357
  // src/commands/run.ts
358
358
  import { existsSync as existsSync2 } from "fs";
359
- import { resolve } from "path";
359
+ import { resolve as resolve2 } from "path";
360
360
  import { createInterface } from "readline/promises";
361
361
  import chalk2 from "chalk";
362
362
  import ora from "ora";
@@ -367,11 +367,122 @@ import {
367
367
  OpenAIProvider,
368
368
  GeminiProvider,
369
369
  SecretsManager,
370
+ InMemorySessionStore,
370
371
  createLogger as createLogger2
371
372
  } from "@tuttiai/core";
373
+
374
+ // src/watch/score-watcher.ts
375
+ import { dirname, resolve } from "path";
376
+ import { EventEmitter } from "events";
377
+ import chokidar from "chokidar";
378
+ import { validateScore } from "@tuttiai/core";
379
+ var DEFAULT_DEBOUNCE_MS = 200;
380
+ var DEFAULT_IGNORED = [
381
+ /(^|[/\\])\../,
382
+ // dotfiles (.git, .env, etc.)
383
+ /node_modules/,
384
+ /[/\\]dist[/\\]/,
385
+ /[/\\]coverage[/\\]/
386
+ ];
387
+ async function defaultLoadScore(path) {
388
+ const absolute = resolve(path);
389
+ const { pathToFileURL } = await import("url");
390
+ const url = pathToFileURL(absolute).href + "?t=" + Date.now().toString(36);
391
+ const mod = await import(url);
392
+ if (!mod.default) {
393
+ throw new Error(
394
+ "Score file has no default export: " + path + " \u2014 your score must export `defineScore({ ... })` as its default."
395
+ );
396
+ }
397
+ validateScore(mod.default);
398
+ return mod.default;
399
+ }
400
+ var ReactiveScore = class extends EventEmitter {
401
+ _current;
402
+ scorePath;
403
+ load;
404
+ debounceMs;
405
+ watcher;
406
+ debounceTimer;
407
+ closed = false;
408
+ _pendingReload = false;
409
+ constructor(initialScore, scorePath, options = {}) {
410
+ super();
411
+ this._current = initialScore;
412
+ this.scorePath = resolve(scorePath);
413
+ this.load = options.load ?? defaultLoadScore;
414
+ this.debounceMs = options.debounceMs ?? DEFAULT_DEBOUNCE_MS;
415
+ const watchTargets = [
416
+ this.scorePath,
417
+ dirname(this.scorePath),
418
+ ...options.extraPaths ?? []
419
+ ];
420
+ this.watcher = chokidar.watch(watchTargets, {
421
+ ignored: DEFAULT_IGNORED,
422
+ ignoreInitial: true,
423
+ // awaitWriteFinish: guard against partial writes from editors that
424
+ // save atomically via rename/move.
425
+ awaitWriteFinish: {
426
+ stabilityThreshold: 50,
427
+ pollInterval: 20
428
+ }
429
+ });
430
+ this.watcher.on("change", (path) => this.handleChange(path));
431
+ this.watcher.on("add", (path) => this.handleChange(path));
432
+ }
433
+ /** The most recent successfully-loaded score. Never stale. */
434
+ get current() {
435
+ return this._current;
436
+ }
437
+ /**
438
+ * True when a file change has been observed and a reload is pending
439
+ * (or just completed and not yet consumed). Readers call
440
+ * {@link consumePendingReload} to clear the flag when they've taken
441
+ * action on the new config.
442
+ */
443
+ get pendingReload() {
444
+ return this._pendingReload;
445
+ }
446
+ consumePendingReload() {
447
+ this._pendingReload = false;
448
+ }
449
+ /** Release the underlying filesystem watchers. */
450
+ async close() {
451
+ this.closed = true;
452
+ if (this.debounceTimer) clearTimeout(this.debounceTimer);
453
+ await this.watcher.close();
454
+ }
455
+ /**
456
+ * Force an immediate reload without waiting for a filesystem event.
457
+ * Exposed for tests and for the `reload` REPL command.
458
+ */
459
+ async reloadNow() {
460
+ if (this.closed) return;
461
+ this.emit("reloading");
462
+ try {
463
+ const next = await this.load(this.scorePath);
464
+ this._current = next;
465
+ this._pendingReload = true;
466
+ this.emit("reloaded", next);
467
+ } catch (err) {
468
+ const error = err instanceof Error ? err : new Error(String(err));
469
+ this.emit("reload-failed", error);
470
+ }
471
+ }
472
+ handleChange(path) {
473
+ if (this.closed) return;
474
+ this.emit("file-change", path);
475
+ if (this.debounceTimer) clearTimeout(this.debounceTimer);
476
+ this.debounceTimer = setTimeout(() => {
477
+ void this.reloadNow();
478
+ }, this.debounceMs);
479
+ }
480
+ };
481
+
482
+ // src/commands/run.ts
372
483
  var logger2 = createLogger2("tutti-cli");
373
- async function runCommand(scorePath) {
374
- const file = resolve(scorePath ?? "./tutti.score.ts");
484
+ async function runCommand(scorePath, options = {}) {
485
+ const file = resolve2(scorePath ?? "./tutti.score.ts");
375
486
  if (!existsSync2(file)) {
376
487
  logger2.error({ file }, "Score file not found");
377
488
  console.error(chalk2.dim('Run "tutti-ai init" to create a new project.'));
@@ -401,90 +512,128 @@ async function runCommand(scorePath) {
401
512
  }
402
513
  }
403
514
  }
404
- for (const agent of Object.values(score.agents)) {
405
- agent.streaming = true;
406
- }
407
- const runtime = new TuttiRuntime(score);
515
+ const applyRunDefaults = (cfg) => {
516
+ for (const agent of Object.values(cfg.agents)) {
517
+ agent.streaming = true;
518
+ }
519
+ };
520
+ applyRunDefaults(score);
521
+ const sharedSessions = options.watch ? new InMemorySessionStore() : void 0;
408
522
  const spinner = ora({ color: "cyan" });
409
523
  let streaming = false;
410
- runtime.events.on("agent:start", (e) => {
411
- logger2.info({ agent: e.agent_name }, "Running agent");
412
- });
413
- runtime.events.on("llm:request", () => {
414
- spinner.start("Thinking...");
415
- });
416
- runtime.events.on("token:stream", (e) => {
417
- if (!streaming) {
418
- spinner.stop();
419
- streaming = true;
420
- }
421
- process.stdout.write(e.text);
422
- });
423
- runtime.events.on("llm:response", () => {
424
- if (streaming) {
425
- process.stdout.write("\n");
426
- } else {
427
- spinner.stop();
428
- }
429
- });
430
- runtime.events.on("tool:start", (e) => {
431
- if (streaming) {
432
- process.stdout.write(chalk2.dim("\n [using: " + e.tool_name + "]"));
433
- } else {
434
- spinner.stop();
435
- console.log(chalk2.dim(" [using: " + e.tool_name + "]"));
436
- }
437
- });
438
- runtime.events.on("tool:end", (e) => {
439
- if (streaming) {
440
- process.stdout.write(chalk2.dim(" [done: " + e.tool_name + "]\n"));
441
- }
442
- });
443
- runtime.events.on("tool:error", (e) => {
444
- spinner.stop();
445
- logger2.error({ tool: e.tool_name }, "Tool error");
446
- });
447
- runtime.events.on("security:injection_detected", (e) => {
448
- logger2.warn({ tool: e.tool_name }, "Potential prompt injection detected");
449
- });
450
- runtime.events.on("budget:warning", () => {
451
- logger2.warn("Approaching token budget (80%)");
452
- });
453
- runtime.events.on("budget:exceeded", () => {
454
- logger2.error("Token budget exceeded \u2014 stopping");
455
- });
524
+ let runtime = buildRuntime(score, sharedSessions);
525
+ attachListeners(runtime);
456
526
  const rl = createInterface({
457
527
  input: process.stdin,
458
528
  output: process.stdout
459
529
  });
460
- runtime.events.on("hitl:requested", (e) => {
461
- spinner.stop();
462
- if (streaming) {
463
- process.stdout.write("\n");
464
- streaming = false;
465
- }
466
- console.log();
467
- console.log(chalk2.yellow(" " + chalk2.bold("[Agent needs input]") + " " + e.question));
468
- if (e.options) {
469
- e.options.forEach((opt, i) => {
470
- console.log(chalk2.yellow(" " + (i + 1) + ". " + opt));
530
+ function attachListeners(r) {
531
+ r.events.on("agent:start", (e) => {
532
+ logger2.info({ agent: e.agent_name }, "Running agent");
533
+ });
534
+ r.events.on("llm:request", () => {
535
+ spinner.start("Thinking...");
536
+ });
537
+ r.events.on("token:stream", (e) => {
538
+ if (!streaming) {
539
+ spinner.stop();
540
+ streaming = true;
541
+ }
542
+ process.stdout.write(e.text);
543
+ });
544
+ r.events.on("llm:response", () => {
545
+ if (streaming) {
546
+ process.stdout.write("\n");
547
+ } else {
548
+ spinner.stop();
549
+ }
550
+ });
551
+ r.events.on("tool:start", (e) => {
552
+ if (streaming) {
553
+ process.stdout.write(chalk2.dim("\n [using: " + e.tool_name + "]"));
554
+ } else {
555
+ spinner.stop();
556
+ console.log(chalk2.dim(" [using: " + e.tool_name + "]"));
557
+ }
558
+ });
559
+ r.events.on("tool:end", (e) => {
560
+ if (streaming) {
561
+ process.stdout.write(chalk2.dim(" [done: " + e.tool_name + "]\n"));
562
+ }
563
+ });
564
+ r.events.on("tool:error", (e) => {
565
+ spinner.stop();
566
+ logger2.error({ tool: e.tool_name }, "Tool error");
567
+ });
568
+ r.events.on("security:injection_detected", (e) => {
569
+ logger2.warn({ tool: e.tool_name }, "Potential prompt injection detected");
570
+ });
571
+ r.events.on("budget:warning", () => {
572
+ logger2.warn("Approaching token budget (80%)");
573
+ });
574
+ r.events.on("budget:exceeded", () => {
575
+ logger2.error("Token budget exceeded \u2014 stopping");
576
+ });
577
+ r.events.on("hitl:requested", (e) => {
578
+ spinner.stop();
579
+ if (streaming) {
580
+ process.stdout.write("\n");
581
+ streaming = false;
582
+ }
583
+ console.log();
584
+ console.log(
585
+ chalk2.yellow(
586
+ " " + chalk2.bold("[Agent needs input]") + " " + e.question
587
+ )
588
+ );
589
+ if (e.options) {
590
+ e.options.forEach((opt, i) => {
591
+ console.log(chalk2.yellow(" " + (i + 1) + ". " + opt));
592
+ });
593
+ }
594
+ void rl.question(chalk2.yellow(" > ")).then((answer) => {
595
+ runtime.answer(e.session_id, answer.trim());
471
596
  });
472
- }
473
- void rl.question(chalk2.yellow(" > ")).then((answer) => {
474
- runtime.answer(e.session_id, answer.trim());
475
597
  });
476
- });
598
+ }
599
+ let reactive;
600
+ if (options.watch) {
601
+ reactive = new ReactiveScore(score, file);
602
+ reactive.on("file-change", () => {
603
+ console.log(chalk2.cyan("\n[tutti] Score changed, reloading..."));
604
+ });
605
+ reactive.on("reloaded", () => {
606
+ console.log(chalk2.green("[tutti] Score reloaded. Changes applied."));
607
+ });
608
+ reactive.on("reload-failed", (err) => {
609
+ logger2.error(
610
+ { error: err instanceof Error ? err.message : String(err) },
611
+ "[tutti] Reload failed \u2014 using previous config"
612
+ );
613
+ });
614
+ }
477
615
  console.log(chalk2.dim('Tutti REPL \u2014 type "exit" to quit\n'));
616
+ if (options.watch) {
617
+ console.log(chalk2.dim("Watching " + file + " for changes\u2026\n"));
618
+ }
478
619
  let sessionId;
479
620
  process.on("SIGINT", () => {
480
621
  if (streaming) process.stdout.write("\n");
481
622
  spinner.stop();
482
623
  console.log(chalk2.dim("Goodbye!"));
483
624
  rl.close();
625
+ if (reactive) void reactive.close();
484
626
  process.exit(0);
485
627
  });
486
628
  try {
487
629
  while (true) {
630
+ if (reactive?.pendingReload) {
631
+ const nextScore = reactive.current;
632
+ applyRunDefaults(nextScore);
633
+ runtime = buildRuntime(nextScore, sharedSessions);
634
+ attachListeners(runtime);
635
+ reactive.consumePendingReload();
636
+ }
488
637
  const input = await rl.question(chalk2.cyan("> "));
489
638
  const trimmed = input.trim();
490
639
  if (!trimmed) continue;
@@ -511,12 +660,19 @@ async function runCommand(scorePath) {
511
660
  }
512
661
  console.log(chalk2.dim("Goodbye!"));
513
662
  rl.close();
663
+ if (reactive) await reactive.close();
514
664
  process.exit(0);
515
665
  }
666
+ function buildRuntime(score, sessionStore) {
667
+ return new TuttiRuntime(
668
+ score,
669
+ sessionStore ? { sessionStore } : {}
670
+ );
671
+ }
516
672
 
517
673
  // src/commands/resume.ts
518
674
  import { existsSync as existsSync3 } from "fs";
519
- import { resolve as resolve2 } from "path";
675
+ import { resolve as resolve3 } from "path";
520
676
  import { createInterface as createInterface2 } from "readline/promises";
521
677
  import chalk3 from "chalk";
522
678
  import ora2 from "ora";
@@ -532,7 +688,7 @@ import {
532
688
  } from "@tuttiai/core";
533
689
  var logger3 = createLogger3("tutti-cli");
534
690
  async function resumeCommand(sessionId, opts) {
535
- const scoreFile = resolve2(opts.score ?? "./tutti.score.ts");
691
+ const scoreFile = resolve3(opts.score ?? "./tutti.score.ts");
536
692
  if (!existsSync3(scoreFile)) {
537
693
  logger3.error({ file: scoreFile }, "Score file not found");
538
694
  console.error(chalk3.dim('Run "tutti-ai init" to create a new project.'));
@@ -776,7 +932,7 @@ function wireProgress(runtime) {
776
932
 
777
933
  // src/commands/add.ts
778
934
  import { existsSync as existsSync4, readFileSync } from "fs";
779
- import { resolve as resolve3 } from "path";
935
+ import { resolve as resolve4 } from "path";
780
936
  import { execSync } from "child_process";
781
937
  import chalk4 from "chalk";
782
938
  import ora3 from "ora";
@@ -832,7 +988,7 @@ function resolvePackageName(input) {
832
988
  return `@tuttiai/${input}`;
833
989
  }
834
990
  function isAlreadyInstalled(packageName) {
835
- const pkgPath = resolve3(process.cwd(), "package.json");
991
+ const pkgPath = resolve4(process.cwd(), "package.json");
836
992
  if (!existsSync4(pkgPath)) return false;
837
993
  try {
838
994
  const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
@@ -844,7 +1000,7 @@ function isAlreadyInstalled(packageName) {
844
1000
  }
845
1001
  function addCommand(voiceName) {
846
1002
  const packageName = resolvePackageName(voiceName);
847
- const pkgPath = resolve3(process.cwd(), "package.json");
1003
+ const pkgPath = resolve4(process.cwd(), "package.json");
848
1004
  if (!existsSync4(pkgPath)) {
849
1005
  logger4.error("No package.json found in the current directory");
850
1006
  console.error(chalk4.dim('Run "tutti-ai init" to create a new project first.'));
@@ -884,7 +1040,7 @@ function addCommand(voiceName) {
884
1040
 
885
1041
  // src/commands/check.ts
886
1042
  import { existsSync as existsSync5 } from "fs";
887
- import { resolve as resolve4 } from "path";
1043
+ import { resolve as resolve5 } from "path";
888
1044
  import chalk5 from "chalk";
889
1045
  import {
890
1046
  ScoreLoader as ScoreLoader3,
@@ -898,7 +1054,7 @@ var logger5 = createLogger5("tutti-cli");
898
1054
  var ok = (msg) => console.log(chalk5.green(" \u2714 " + msg));
899
1055
  var fail = (msg) => console.log(chalk5.red(" \u2718 " + msg));
900
1056
  async function checkCommand(scorePath) {
901
- const file = resolve4(scorePath ?? "./tutti.score.ts");
1057
+ const file = resolve5(scorePath ?? "./tutti.score.ts");
902
1058
  console.log(chalk5.cyan(`
903
1059
  Checking ${file}...
904
1060
  `));
@@ -981,7 +1137,7 @@ Checking ${file}...
981
1137
 
982
1138
  // src/commands/studio.ts
983
1139
  import { existsSync as existsSync6 } from "fs";
984
- import { resolve as resolve5 } from "path";
1140
+ import { resolve as resolve6 } from "path";
985
1141
  import { execFile } from "child_process";
986
1142
  import express from "express";
987
1143
  import chalk6 from "chalk";
@@ -1009,7 +1165,7 @@ function openBrowser(url) {
1009
1165
  execFile(cmd, [url]);
1010
1166
  }
1011
1167
  async function studioCommand(scorePath) {
1012
- const file = resolve5(scorePath ?? "./tutti.score.ts");
1168
+ const file = resolve6(scorePath ?? "./tutti.score.ts");
1013
1169
  if (!existsSync6(file)) {
1014
1170
  logger6.error({ file }, "Score file not found");
1015
1171
  console.error(chalk6.dim('Run "tutti-ai init" to create a new project.'));
@@ -1144,7 +1300,7 @@ function getStudioHtml() {
1144
1300
 
1145
1301
  // src/commands/search.ts
1146
1302
  import { existsSync as existsSync7, readFileSync as readFileSync2 } from "fs";
1147
- import { resolve as resolve6 } from "path";
1303
+ import { resolve as resolve7 } from "path";
1148
1304
  import chalk7 from "chalk";
1149
1305
  import ora4 from "ora";
1150
1306
  import { createLogger as createLogger7 } from "@tuttiai/core";
@@ -1215,7 +1371,7 @@ function matchesQuery(voice, query) {
1215
1371
  return false;
1216
1372
  }
1217
1373
  function isInstalled(packageName) {
1218
- const pkgPath = resolve6(process.cwd(), "package.json");
1374
+ const pkgPath = resolve7(process.cwd(), "package.json");
1219
1375
  if (!existsSync7(pkgPath)) return false;
1220
1376
  try {
1221
1377
  const pkg = JSON.parse(readFileSync2(pkgPath, "utf-8"));
@@ -1288,7 +1444,7 @@ async function voicesCommand() {
1288
1444
 
1289
1445
  // src/commands/publish.ts
1290
1446
  import { existsSync as existsSync8, readFileSync as readFileSync3 } from "fs";
1291
- import { resolve as resolve7 } from "path";
1447
+ import { resolve as resolve8 } from "path";
1292
1448
  import { execSync as execSync2 } from "child_process";
1293
1449
  import chalk8 from "chalk";
1294
1450
  import ora5 from "ora";
@@ -1297,7 +1453,7 @@ import { createLogger as createLogger8, SecretsManager as SecretsManager4 } from
1297
1453
  var { prompt: prompt2 } = Enquirer2;
1298
1454
  var logger8 = createLogger8("tutti-cli");
1299
1455
  function readPkg(dir) {
1300
- const p = resolve7(dir, "package.json");
1456
+ const p = resolve8(dir, "package.json");
1301
1457
  if (!existsSync8(p)) return void 0;
1302
1458
  return JSON.parse(readFileSync3(p, "utf-8"));
1303
1459
  }
@@ -1317,7 +1473,7 @@ async function publishCommand(opts) {
1317
1473
  console.log();
1318
1474
  const spinner = ora5("Running pre-flight checks...").start();
1319
1475
  if (!pkg) fail2("No package.json found in the current directory.");
1320
- if (!existsSync8(resolve7(cwd, "src/index.ts"))) fail2("No src/index.ts found \u2014 are you inside a voice directory?");
1476
+ if (!existsSync8(resolve8(cwd, "src/index.ts"))) fail2("No src/index.ts found \u2014 are you inside a voice directory?");
1321
1477
  const missing = [];
1322
1478
  if (!pkg.name) missing.push("name");
1323
1479
  if (!pkg.version) missing.push("version");
@@ -1329,7 +1485,7 @@ async function publishCommand(opts) {
1329
1485
  const version = pkg.version;
1330
1486
  const validName = name.startsWith("@tuttiai/") || name.startsWith("tutti");
1331
1487
  if (!validName) fail2("Package name must start with @tuttiai/ or tutti \u2014 got: " + name);
1332
- const src = readFileSync3(resolve7(cwd, "src/index.ts"), "utf-8");
1488
+ const src = readFileSync3(resolve8(cwd, "src/index.ts"), "utf-8");
1333
1489
  if (!src.includes("required_permissions")) {
1334
1490
  fail2("Voice class must declare required_permissions in src/index.ts");
1335
1491
  }
@@ -1510,7 +1666,7 @@ async function openRegistryPR(packageName, version, description, token) {
1510
1666
 
1511
1667
  // src/commands/eval.ts
1512
1668
  import { existsSync as existsSync9, readFileSync as readFileSync4 } from "fs";
1513
- import { resolve as resolve8 } from "path";
1669
+ import { resolve as resolve9 } from "path";
1514
1670
  import chalk9 from "chalk";
1515
1671
  import ora6 from "ora";
1516
1672
  import {
@@ -1521,7 +1677,7 @@ import {
1521
1677
  } from "@tuttiai/core";
1522
1678
  var logger9 = createLogger9("tutti-cli");
1523
1679
  async function evalCommand(suitePath, opts) {
1524
- const suiteFile = resolve8(suitePath);
1680
+ const suiteFile = resolve9(suitePath);
1525
1681
  if (!existsSync9(suiteFile)) {
1526
1682
  logger9.error({ file: suiteFile }, "Suite file not found");
1527
1683
  process.exit(1);
@@ -1533,7 +1689,7 @@ async function evalCommand(suitePath, opts) {
1533
1689
  logger9.error({ error: err instanceof Error ? err.message : String(err) }, "Failed to parse suite file");
1534
1690
  process.exit(1);
1535
1691
  }
1536
- const scoreFile = resolve8(opts.score ?? "./tutti.score.ts");
1692
+ const scoreFile = resolve9(opts.score ?? "./tutti.score.ts");
1537
1693
  if (!existsSync9(scoreFile)) {
1538
1694
  logger9.error({ file: scoreFile }, "Score file not found");
1539
1695
  process.exit(1);
@@ -1571,15 +1727,15 @@ process.on("uncaughtException", (err) => {
1571
1727
  process.exit(1);
1572
1728
  });
1573
1729
  var program = new Command();
1574
- program.name("tutti-ai").description("Tutti \u2014 multi-agent orchestration. All agents. All together.").version("0.9.0");
1730
+ program.name("tutti-ai").description("Tutti \u2014 multi-agent orchestration. All agents. All together.").version("0.10.0");
1575
1731
  program.command("init [project-name]").description("Create a new Tutti project").option("-t, --template <id>", "Project template to use").action(async (projectName, opts) => {
1576
1732
  await initCommand(projectName, opts.template);
1577
1733
  });
1578
1734
  program.command("templates").description("List all available project templates").action(() => {
1579
1735
  templatesCommand();
1580
1736
  });
1581
- program.command("run [score]").description("Run a Tutti score interactively").action(async (score) => {
1582
- await runCommand(score);
1737
+ program.command("run [score]").description("Run a Tutti score interactively").option("-w, --watch", "Reload the score on file changes").action(async (score, opts) => {
1738
+ await runCommand(score, { watch: opts.watch });
1583
1739
  });
1584
1740
  program.command("resume <session-id>").description("Resume a crashed or interrupted run from its last checkpoint").option(
1585
1741
  "--store <backend>",
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/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.9.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(\"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 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 } 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>&#9835;</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&hellip;<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&hellip;\" 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\">&#x2193; Input</span><span class=\"token-val input\" id=\"tok-in\">0</span></div>\\\n <div class=\"token-item\"><span class=\"token-label\">&#x2191; 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(\" &middot; \");\\\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)+\" &middot; \"+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","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"]}
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>&#9835;</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&hellip;<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&hellip;\" 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\">&#x2193; Input</span><span class=\"token-val input\" id=\"tok-in\">0</span></div>\\\n <div class=\"token-item\"><span class=\"token-label\">&#x2191; 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(\" &middot; \");\\\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)+\" &middot; \"+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"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tuttiai/cli",
3
- "version": "0.9.0",
3
+ "version": "0.10.0",
4
4
  "description": "Tutti CLI — scaffold and run multi-agent projects",
5
5
  "type": "module",
6
6
  "bin": {
@@ -28,6 +28,7 @@
28
28
  "@tuttiai/core": "*",
29
29
  "@tuttiai/types": "*",
30
30
  "chalk": "5.6.2",
31
+ "chokidar": "5.0.0",
31
32
  "commander": "4.1.1",
32
33
  "dotenv": "17.4.1",
33
34
  "enquirer": "2.4.1",