claude-tempo 0.20.0 → 0.20.1

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.
@@ -668,13 +668,93 @@ async function up(opts) {
668
668
  }
669
669
  // Resolve conductor agent from lineup or CLI flags
670
670
  const conductorAgent = lineup?.conductor?.agent === 'copilot' ? 'copilot' : opts.agent;
671
- // Step 5: Connect to Temporal and pre-create conductor workflow before spawning
671
+ // Step 5: Connect to Temporal and check for existing conductor
672
672
  console.log();
673
- out.log(`Launching conductor in ensemble ${out.cyan(opts.ensemble)}${conductorAgent === 'copilot' ? out.dim(' (copilot)') : ''}...`);
674
673
  const connection = await (0, connection_1.createTemporalConnection)(config);
675
674
  const client = new client_1.Client({ connection, namespace: config.temporalNamespace });
676
- const sessionName = opts.name || lineup?.conductor?.name || (conductorAgent === 'copilot' ? `${opts.ensemble}-conductor` : 'conductor');
677
675
  const conductorWfId = (0, config_1.conductorWorkflowId)(opts.ensemble);
676
+ // Check if a conductor is already running
677
+ try {
678
+ const existingHandle = client.workflow.getHandle(conductorWfId);
679
+ const desc = await existingHandle.describe();
680
+ if (desc.status.name === 'RUNNING') {
681
+ if (!process.stdin.isTTY) {
682
+ out.error(`A conductor is already running for ensemble "${opts.ensemble}".`);
683
+ out.log(` Use ${out.dim('--resume')} to reconnect, or ${out.dim('claude-tempo start')} to join as a player.`);
684
+ process.exit(1);
685
+ }
686
+ out.warn(`A conductor is already running for ensemble "${opts.ensemble}".`);
687
+ console.log();
688
+ out.log(` 1) Join as a new player session`);
689
+ out.log(` 2) Reconnect to the existing conductor (--resume)`);
690
+ out.log(` 3) Tear down and start fresh`);
691
+ out.log(` 4) Cancel`);
692
+ console.log();
693
+ const choice = await new Promise((res) => {
694
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
695
+ rl.question(` ${out.cyan('?')} Choose an option [1-4]: `, (answer) => {
696
+ rl.close();
697
+ res(answer.trim());
698
+ });
699
+ });
700
+ switch (choice) {
701
+ case '1':
702
+ // Join as a player — delegate to start()
703
+ console.log();
704
+ out.log('Joining as a player session...');
705
+ await start({
706
+ ensemble: opts.ensemble,
707
+ conductor: false,
708
+ name: opts.name,
709
+ skipPreflight: true, // infrastructure already verified above
710
+ agent: opts.agent,
711
+ dir: process.cwd(),
712
+ });
713
+ return;
714
+ case '2':
715
+ // Reconnect to existing conductor
716
+ console.log();
717
+ out.log('Reconnecting to existing conductor...');
718
+ await start({
719
+ ensemble: opts.ensemble,
720
+ conductor: true,
721
+ resume: true,
722
+ name: opts.name,
723
+ skipPreflight: true,
724
+ agent: opts.agent,
725
+ dir: process.cwd(),
726
+ });
727
+ return;
728
+ case '3':
729
+ // Terminate existing workflows, then fall through to normal up flow
730
+ console.log();
731
+ try {
732
+ await client.workflow.getHandle(conductorWfId).terminate('up: fresh start');
733
+ }
734
+ catch { /* may not exist */ }
735
+ try {
736
+ await client.workflow.getHandle((0, config_1.schedulerWorkflowId)(opts.ensemble)).terminate('up: fresh start');
737
+ }
738
+ catch { /* may not exist */ }
739
+ try {
740
+ await client.workflow.getHandle((0, config_1.maestroWorkflowId)(opts.ensemble)).terminate('up: fresh start');
741
+ }
742
+ catch { /* may not exist */ }
743
+ out.success('Existing ensemble torn down');
744
+ // Fall through to normal up flow below
745
+ break;
746
+ case '4':
747
+ default:
748
+ out.log('Cancelled.');
749
+ process.exit(0);
750
+ }
751
+ }
752
+ }
753
+ catch {
754
+ // No existing conductor — proceed normally
755
+ }
756
+ out.log(`Launching conductor in ensemble ${out.cyan(opts.ensemble)}${conductorAgent === 'copilot' ? out.dim(' (copilot)') : ''}...`);
757
+ const sessionName = opts.name || lineup?.conductor?.name || (conductorAgent === 'copilot' ? `${opts.ensemble}-conductor` : 'conductor');
678
758
  // Resolve conductor agent type from lineup
679
759
  const conductorType = lineup?.conductor?.agent && lineup.conductor.agent !== 'default' && lineup.conductor.agent !== 'copilot'
680
760
  ? lineup.conductor.agent
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-tempo",
3
- "version": "0.20.0",
3
+ "version": "0.20.1",
4
4
  "description": "MCP server for multi-session Claude Code coordination via Temporal",
5
5
  "keywords": [
6
6
  "mcp",