tmux-team 3.2.4 → 3.3.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
@@ -16,60 +16,75 @@ npm install -g tmux-team
16
16
 
17
17
  ```bash
18
18
  # 1. Install for your AI agent
19
- tmux-team install claude # or: tmux-team install codex
19
+ tmt install claude # or: tmt install codex
20
20
 
21
- # 2. Run the setup wizard (auto-detects panes)
22
- tmux-team setup
21
+ # 2. Go to working folder and initialize
22
+ tmt init
23
23
 
24
- # 3. Talk to agents
25
- tmux-team talk codex "Review this code" --wait
24
+ # 3. Register agents (run inside each agent's pane)
25
+ tmt this claude # registers current pane as "claude"
26
+ tmt this codex # registers current pane as "codex"
27
+
28
+ # 4. Talk to agents
29
+ tmt talk codex "Review this code" # waits for response by default
30
+
31
+ # 5. Update or remove an agent
32
+ tmt update codex --pane 2.3
33
+ tmt rm codex
34
+ ```
35
+
36
+ > **Tip:** Most AI agents support `!` to run bash commands. From inside Claude Code, Codex, or Gemini CLI, you can run `!tmt this myname` to quickly register that pane.
37
+
38
+ ## Cross-Folder Collaboration
39
+
40
+ Agents don't need to be in the same folder to collaborate. You can add an agent from one project to another:
41
+
42
+ ```bash
43
+ # In project-a folder, add an agent that's running in project-b
44
+ tmt add codex-reviewer 5.1 # Use the pane ID from the other project
26
45
  ```
27
46
 
28
- The `--wait` flag blocks until the agent responds, returning the response directly.
47
+ Find pane IDs with: `tmux display-message -p "#{pane_id}"`
29
48
 
30
49
  ## Commands
31
50
 
32
51
  | Command | Description |
33
52
  |---------|-------------|
34
53
  | `install [claude\|codex]` | Install tmux-team for an AI agent |
35
- | `setup` | Interactive wizard to configure agents |
36
- | `talk <agent> "msg" --wait` | Send message and wait for response |
37
- | `talk all "msg" --wait` | Broadcast to all agents |
38
- | `check <agent> [lines]` | Read agent's pane output (fallback if --wait times out) |
54
+ | `this <name> [remark]` | Register current pane as an agent |
55
+ | `talk <agent> "msg"` | Send message and wait for response |
56
+ | `talk all "msg"` | Broadcast to all agents |
57
+ | `check <agent> [lines]` | Read agent's pane output |
39
58
  | `list` | Show configured agents |
40
59
  | `learn` | Show educational guide |
41
60
 
42
- **Options for `talk --wait`:**
61
+ **Options for `talk`:**
43
62
  - `--timeout <seconds>` - Max wait time (default: 180s)
44
63
  - `--lines <number>` - Lines to capture from response (default: 100)
45
64
 
46
- Run `tmux-team help` for all commands and options.
65
+ Run `tmt help` for all commands and options.
47
66
 
48
67
  ## Managing Your Team
49
68
 
50
69
  Configuration lives in `tmux-team.json` in your project root.
51
70
 
52
- **Create** - Run the setup wizard to auto-detect agents:
53
- ```bash
54
- tmux-team setup
55
- ```
56
-
57
- **Read** - List configured agents:
71
+ **List** - Show configured agents:
58
72
  ```bash
59
- tmux-team list
73
+ tmt ls
60
74
  ```
61
75
 
62
- **Update** - Edit `tmux-team.json` directly or re-run setup:
76
+ **Edit** - Modify `tmux-team.json` directly:
63
77
  ```json
64
78
  {
65
- "codex": { "pane": "%1", "remark": "Code reviewer" },
66
- "gemini": { "pane": "%2", "remark": "Documentation" }
79
+ "codex": { "pane": "1.1", "remark": "Code reviewer" },
80
+ "gemini": { "pane": "1.2", "remark": "Documentation" }
67
81
  }
68
82
  ```
69
83
 
70
- **Delete** - Remove an agent entry from `tmux-team.json` or delete the file entirely.
71
-
72
- Find pane IDs: `tmux display-message -p "#{pane_id}"`
84
+ **Remove** - Delete an agent:
85
+ ```bash
86
+ tmt rm codex
87
+ ```
73
88
 
74
89
  ## Claude Code Plugin
75
90
 
@@ -88,8 +103,8 @@ Run this once when starting a session. Claude will understand how to coordinate
88
103
 
89
104
  **`/team`** - Talk to other agents
90
105
  ```
91
- /team talk codex "Review my authentication changes" --wait
92
- /team talk all "I'm starting the database migration" --wait
106
+ /team talk codex "Review my authentication changes"
107
+ /team talk all "I'm starting the database migration"
93
108
  /team list
94
109
  ```
95
110
  Use this to delegate tasks, ask for reviews, or broadcast updates.
@@ -97,8 +112,8 @@ Use this to delegate tasks, ask for reviews, or broadcast updates.
97
112
  ## Learn More
98
113
 
99
114
  ```bash
100
- tmux-team learn # Comprehensive guide
101
- tmux-team help # All commands and options
115
+ tmt learn # Comprehensive guide
116
+ tmt help # All commands and options
102
117
  ```
103
118
 
104
119
  ## License
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tmux-team",
3
- "version": "3.2.4",
3
+ "version": "3.3.0",
4
4
  "description": "CLI tool for AI agent collaboration in tmux - manage cross-pane communication",
5
5
  "type": "module",
6
6
  "bin": {
package/skills/README.md CHANGED
@@ -29,7 +29,7 @@ tmux-team install claude
29
29
  tmux-team install codex
30
30
  ```
31
31
 
32
- After installation, run `tmux-team setup` to configure your agents interactively.
32
+ After installation, run `tmux-team add <name> <pane>` to register your agents, or use `tmux-team this <name>` inside each agent's tmux pane.
33
33
 
34
34
  ## Claude Code
35
35
 
package/src/cli.test.ts CHANGED
@@ -160,4 +160,430 @@ describe('cli', () => {
160
160
  expect(errSpy).toHaveBeenCalledWith(JSON.stringify({ error: 'boom' }));
161
161
  expect(exitSpy).toHaveBeenCalledWith(1);
162
162
  });
163
+
164
+ it('routes install command', async () => {
165
+ vi.resetModules();
166
+ process.argv = ['node', 'cli', 'install', 'claude'];
167
+
168
+ const ctx = makeStubContext();
169
+ const installSpy = vi.fn();
170
+ vi.doMock('./context.js', () => ({
171
+ createContext: () => ctx,
172
+ ExitCodes: { SUCCESS: 0, ERROR: 1 },
173
+ }));
174
+ vi.doMock('./commands/install.js', () => ({ cmdInstall: installSpy }));
175
+ const exitSpy = vi.spyOn(process, 'exit').mockImplementation((() => {}) as any);
176
+
177
+ await import('./cli.js');
178
+ // allow async to resolve
179
+ await new Promise((r) => setTimeout(r, 0));
180
+
181
+ expect(installSpy).toHaveBeenCalledWith(ctx, 'claude');
182
+ expect(exitSpy).not.toHaveBeenCalled();
183
+ });
184
+
185
+ it('routes preamble command', async () => {
186
+ vi.resetModules();
187
+ process.argv = ['node', 'cli', 'preamble', 'show'];
188
+
189
+ const ctx = makeStubContext();
190
+ const preambleSpy = vi.fn();
191
+ vi.doMock('./context.js', () => ({
192
+ createContext: () => ctx,
193
+ ExitCodes: { SUCCESS: 0, ERROR: 1 },
194
+ }));
195
+ vi.doMock('./commands/preamble.js', () => ({ cmdPreamble: preambleSpy }));
196
+ const exitSpy = vi.spyOn(process, 'exit').mockImplementation((() => {}) as any);
197
+
198
+ await import('./cli.js');
199
+ await new Promise((r) => setTimeout(r, 0));
200
+
201
+ expect(preambleSpy).toHaveBeenCalledWith(ctx, ['show']);
202
+ expect(exitSpy).not.toHaveBeenCalled();
203
+ });
204
+
205
+ it('routes this command', async () => {
206
+ vi.resetModules();
207
+ process.argv = ['node', 'cli', 'this', 'myagent', 'remark'];
208
+
209
+ const ctx = makeStubContext();
210
+ const thisSpy = vi.fn();
211
+ vi.doMock('./context.js', () => ({
212
+ createContext: () => ctx,
213
+ ExitCodes: { SUCCESS: 0, ERROR: 1 },
214
+ }));
215
+ vi.doMock('./commands/this.js', () => ({ cmdThis: thisSpy }));
216
+ const exitSpy = vi.spyOn(process, 'exit').mockImplementation((() => {}) as any);
217
+
218
+ await import('./cli.js');
219
+ await new Promise((r) => setTimeout(r, 0));
220
+
221
+ expect(thisSpy).toHaveBeenCalledWith(ctx, 'myagent', 'remark');
222
+ expect(exitSpy).not.toHaveBeenCalled();
223
+ });
224
+
225
+ it('errors when this command is missing name', async () => {
226
+ vi.resetModules();
227
+ process.argv = ['node', 'cli', 'this'];
228
+
229
+ const ctx = makeStubContext();
230
+ const exitSpy = vi.fn();
231
+ ctx.exit = exitSpy as any;
232
+ vi.doMock('./context.js', () => ({
233
+ createContext: () => ctx,
234
+ ExitCodes: { SUCCESS: 0, ERROR: 1 },
235
+ }));
236
+ vi.doMock('./commands/this.js', () => ({ cmdThis: vi.fn() }));
237
+
238
+ await import('./cli.js');
239
+ await new Promise((r) => setTimeout(r, 0));
240
+
241
+ expect(ctx.ui.error).toHaveBeenCalledWith('Usage: tmux-team this <name> [remark]');
242
+ expect(exitSpy).toHaveBeenCalledWith(1);
243
+ });
244
+
245
+ it('routes update command with --pane and --remark flags', async () => {
246
+ vi.resetModules();
247
+ process.argv = ['node', 'cli', 'update', 'codex', '--pane', '2.0', '--remark', 'updated'];
248
+
249
+ const ctx = makeStubContext();
250
+ const updateSpy = vi.fn();
251
+ vi.doMock('./context.js', () => ({
252
+ createContext: () => ctx,
253
+ ExitCodes: { SUCCESS: 0, ERROR: 1 },
254
+ }));
255
+ vi.doMock('./commands/update.js', () => ({ cmdUpdate: updateSpy }));
256
+
257
+ await import('./cli.js');
258
+ await new Promise((r) => setTimeout(r, 0));
259
+
260
+ expect(updateSpy).toHaveBeenCalledWith(ctx, 'codex', { pane: '2.0', remark: 'updated' });
261
+ });
262
+
263
+ it('routes init command', async () => {
264
+ vi.resetModules();
265
+ process.argv = ['node', 'cli', 'init'];
266
+
267
+ const ctx = makeStubContext();
268
+ const initSpy = vi.fn();
269
+ vi.doMock('./context.js', () => ({
270
+ createContext: () => ctx,
271
+ ExitCodes: { SUCCESS: 0, ERROR: 1 },
272
+ }));
273
+ vi.doMock('./commands/init.js', () => ({ cmdInit: initSpy }));
274
+
275
+ await import('./cli.js');
276
+ await new Promise((r) => setTimeout(r, 0));
277
+
278
+ expect(initSpy).toHaveBeenCalledWith(ctx);
279
+ });
280
+
281
+ it('routes list command', async () => {
282
+ vi.resetModules();
283
+ process.argv = ['node', 'cli', 'list'];
284
+
285
+ const ctx = makeStubContext();
286
+ const listSpy = vi.fn();
287
+ vi.doMock('./context.js', () => ({
288
+ createContext: () => ctx,
289
+ ExitCodes: { SUCCESS: 0, ERROR: 1 },
290
+ }));
291
+ vi.doMock('./commands/list.js', () => ({ cmdList: listSpy }));
292
+
293
+ await import('./cli.js');
294
+ await new Promise((r) => setTimeout(r, 0));
295
+
296
+ expect(listSpy).toHaveBeenCalledWith(ctx);
297
+ });
298
+
299
+ it('routes ls alias to list command', async () => {
300
+ vi.resetModules();
301
+ process.argv = ['node', 'cli', 'ls'];
302
+
303
+ const ctx = makeStubContext();
304
+ const listSpy = vi.fn();
305
+ vi.doMock('./context.js', () => ({
306
+ createContext: () => ctx,
307
+ ExitCodes: { SUCCESS: 0, ERROR: 1 },
308
+ }));
309
+ vi.doMock('./commands/list.js', () => ({ cmdList: listSpy }));
310
+
311
+ await import('./cli.js');
312
+ await new Promise((r) => setTimeout(r, 0));
313
+
314
+ expect(listSpy).toHaveBeenCalledWith(ctx);
315
+ });
316
+
317
+ it('routes add command', async () => {
318
+ vi.resetModules();
319
+ process.argv = ['node', 'cli', 'add', 'myagent', '1.0', 'remark'];
320
+
321
+ const ctx = makeStubContext();
322
+ const addSpy = vi.fn();
323
+ vi.doMock('./context.js', () => ({
324
+ createContext: () => ctx,
325
+ ExitCodes: { SUCCESS: 0, ERROR: 1 },
326
+ }));
327
+ vi.doMock('./commands/add.js', () => ({ cmdAdd: addSpy }));
328
+
329
+ await import('./cli.js');
330
+ await new Promise((r) => setTimeout(r, 0));
331
+
332
+ expect(addSpy).toHaveBeenCalledWith(ctx, 'myagent', '1.0', 'remark');
333
+ });
334
+
335
+ it('routes config command', async () => {
336
+ vi.resetModules();
337
+ process.argv = ['node', 'cli', 'config', 'get', 'mode'];
338
+
339
+ const ctx = makeStubContext();
340
+ const configSpy = vi.fn();
341
+ vi.doMock('./context.js', () => ({
342
+ createContext: () => ctx,
343
+ ExitCodes: { SUCCESS: 0, ERROR: 1 },
344
+ }));
345
+ vi.doMock('./commands/config.js', () => ({ cmdConfig: configSpy }));
346
+ const exitSpy = vi.spyOn(process, 'exit').mockImplementation((() => {}) as any);
347
+
348
+ await import('./cli.js');
349
+ await new Promise((r) => setTimeout(r, 0));
350
+
351
+ expect(configSpy).toHaveBeenCalledWith(ctx, ['get', 'mode']);
352
+ expect(exitSpy).not.toHaveBeenCalled();
353
+ });
354
+
355
+ it('parses --timeout flag with seconds', async () => {
356
+ vi.resetModules();
357
+ process.argv = ['node', 'cli', 'talk', 'claude', 'hi', '--timeout', '30'];
358
+
359
+ const ctx = makeStubContext();
360
+ const talkSpy = vi.fn();
361
+ vi.doMock('./context.js', () => ({
362
+ createContext: (opts: any) => {
363
+ ctx.flags = opts.flags;
364
+ return ctx;
365
+ },
366
+ ExitCodes: { SUCCESS: 0, ERROR: 1 },
367
+ }));
368
+ vi.doMock('./commands/talk.js', () => ({ cmdTalk: talkSpy }));
369
+ vi.spyOn(process, 'exit').mockImplementation((() => {}) as any);
370
+
371
+ await import('./cli.js');
372
+ await new Promise((r) => setTimeout(r, 0));
373
+
374
+ expect(ctx.flags.timeout).toBe(30);
375
+ });
376
+
377
+ it('parses --timeout flag with ms suffix', async () => {
378
+ vi.resetModules();
379
+ process.argv = ['node', 'cli', 'talk', 'claude', 'hi', '--timeout', '500ms'];
380
+
381
+ const ctx = makeStubContext();
382
+ const talkSpy = vi.fn();
383
+ vi.doMock('./context.js', () => ({
384
+ createContext: (opts: any) => {
385
+ ctx.flags = opts.flags;
386
+ return ctx;
387
+ },
388
+ ExitCodes: { SUCCESS: 0, ERROR: 1 },
389
+ }));
390
+ vi.doMock('./commands/talk.js', () => ({ cmdTalk: talkSpy }));
391
+ vi.spyOn(process, 'exit').mockImplementation((() => {}) as any);
392
+
393
+ await import('./cli.js');
394
+ await new Promise((r) => setTimeout(r, 0));
395
+
396
+ expect(ctx.flags.timeout).toBe(0.5);
397
+ });
398
+
399
+ it('parses --lines flag', async () => {
400
+ vi.resetModules();
401
+ process.argv = ['node', 'cli', 'talk', 'claude', 'hi', '--wait', '--lines', '50'];
402
+
403
+ const ctx = makeStubContext();
404
+ const talkSpy = vi.fn();
405
+ vi.doMock('./context.js', () => ({
406
+ createContext: (opts: any) => {
407
+ ctx.flags = opts.flags;
408
+ return ctx;
409
+ },
410
+ ExitCodes: { SUCCESS: 0, ERROR: 1 },
411
+ }));
412
+ vi.doMock('./commands/talk.js', () => ({ cmdTalk: talkSpy }));
413
+ vi.spyOn(process, 'exit').mockImplementation((() => {}) as any);
414
+
415
+ await import('./cli.js');
416
+ await new Promise((r) => setTimeout(r, 0));
417
+
418
+ expect(ctx.flags.lines).toBe(50);
419
+ });
420
+
421
+ it('parses --no-preamble flag', async () => {
422
+ vi.resetModules();
423
+ process.argv = ['node', 'cli', 'talk', 'claude', 'hi', '--no-preamble'];
424
+
425
+ const ctx = makeStubContext();
426
+ const talkSpy = vi.fn();
427
+ vi.doMock('./context.js', () => ({
428
+ createContext: (opts: any) => {
429
+ ctx.flags = opts.flags;
430
+ return ctx;
431
+ },
432
+ ExitCodes: { SUCCESS: 0, ERROR: 1 },
433
+ }));
434
+ vi.doMock('./commands/talk.js', () => ({ cmdTalk: talkSpy }));
435
+ vi.spyOn(process, 'exit').mockImplementation((() => {}) as any);
436
+
437
+ await import('./cli.js');
438
+ await new Promise((r) => setTimeout(r, 0));
439
+
440
+ expect(ctx.flags.noPreamble).toBe(true);
441
+ });
442
+
443
+ it('routes check command with lines argument', async () => {
444
+ vi.resetModules();
445
+ process.argv = ['node', 'cli', 'check', 'claude', '50'];
446
+
447
+ const ctx = makeStubContext();
448
+ const checkSpy = vi.fn();
449
+ vi.doMock('./context.js', () => ({
450
+ createContext: () => ctx,
451
+ ExitCodes: { SUCCESS: 0, ERROR: 1 },
452
+ }));
453
+ vi.doMock('./commands/check.js', () => ({ cmdCheck: checkSpy }));
454
+ vi.spyOn(process, 'exit').mockImplementation((() => {}) as any);
455
+
456
+ await import('./cli.js');
457
+ await new Promise((r) => setTimeout(r, 0));
458
+
459
+ expect(checkSpy).toHaveBeenCalledWith(ctx, 'claude', 50);
460
+ });
461
+
462
+ it('routes update command with --pane= syntax', async () => {
463
+ vi.resetModules();
464
+ process.argv = ['node', 'cli', 'update', 'claude', '--pane=2.0'];
465
+
466
+ const ctx = makeStubContext();
467
+ const updateSpy = vi.fn();
468
+ vi.doMock('./context.js', () => ({
469
+ createContext: () => ctx,
470
+ ExitCodes: { SUCCESS: 0, ERROR: 1 },
471
+ }));
472
+ vi.doMock('./commands/update.js', () => ({ cmdUpdate: updateSpy }));
473
+ vi.spyOn(process, 'exit').mockImplementation((() => {}) as any);
474
+
475
+ await import('./cli.js');
476
+ await new Promise((r) => setTimeout(r, 0));
477
+
478
+ expect(updateSpy).toHaveBeenCalledWith(ctx, 'claude', { pane: '2.0' });
479
+ });
480
+
481
+ it('routes update command with --remark= syntax', async () => {
482
+ vi.resetModules();
483
+ process.argv = ['node', 'cli', 'update', 'claude', '--remark=new remark'];
484
+
485
+ const ctx = makeStubContext();
486
+ const updateSpy = vi.fn();
487
+ vi.doMock('./context.js', () => ({
488
+ createContext: () => ctx,
489
+ ExitCodes: { SUCCESS: 0, ERROR: 1 },
490
+ }));
491
+ vi.doMock('./commands/update.js', () => ({ cmdUpdate: updateSpy }));
492
+ vi.spyOn(process, 'exit').mockImplementation((() => {}) as any);
493
+
494
+ await import('./cli.js');
495
+ await new Promise((r) => setTimeout(r, 0));
496
+
497
+ expect(updateSpy).toHaveBeenCalledWith(ctx, 'claude', { remark: 'new remark' });
498
+ });
499
+
500
+ it('errors on talk with missing arguments', async () => {
501
+ vi.resetModules();
502
+ process.argv = ['node', 'cli', 'talk', 'claude']; // missing message
503
+
504
+ const ctx = makeStubContext();
505
+ vi.doMock('./context.js', () => ({
506
+ createContext: () => ctx,
507
+ ExitCodes: { SUCCESS: 0, ERROR: 1 },
508
+ }));
509
+ const exitSpy = vi.spyOn(process, 'exit').mockImplementation((() => {}) as any);
510
+
511
+ await import('./cli.js');
512
+ await new Promise((r) => setTimeout(r, 0));
513
+
514
+ expect(ctx.ui.error).toHaveBeenCalled();
515
+ expect(exitSpy).toHaveBeenCalledWith(1);
516
+ });
517
+
518
+ it('errors on add with missing arguments', async () => {
519
+ vi.resetModules();
520
+ process.argv = ['node', 'cli', 'add', 'claude']; // missing pane
521
+
522
+ const ctx = makeStubContext();
523
+ vi.doMock('./context.js', () => ({
524
+ createContext: () => ctx,
525
+ ExitCodes: { SUCCESS: 0, ERROR: 1 },
526
+ }));
527
+ const exitSpy = vi.spyOn(process, 'exit').mockImplementation((() => {}) as any);
528
+
529
+ await import('./cli.js');
530
+ await new Promise((r) => setTimeout(r, 0));
531
+
532
+ expect(ctx.ui.error).toHaveBeenCalled();
533
+ expect(exitSpy).toHaveBeenCalledWith(1);
534
+ });
535
+
536
+ it('errors on update with missing arguments', async () => {
537
+ vi.resetModules();
538
+ process.argv = ['node', 'cli', 'update']; // missing name
539
+
540
+ const ctx = makeStubContext();
541
+ vi.doMock('./context.js', () => ({
542
+ createContext: () => ctx,
543
+ ExitCodes: { SUCCESS: 0, ERROR: 1 },
544
+ }));
545
+ const exitSpy = vi.spyOn(process, 'exit').mockImplementation((() => {}) as any);
546
+
547
+ await import('./cli.js');
548
+ await new Promise((r) => setTimeout(r, 0));
549
+
550
+ expect(ctx.ui.error).toHaveBeenCalled();
551
+ expect(exitSpy).toHaveBeenCalledWith(1);
552
+ });
553
+
554
+ it('errors on remove with missing arguments', async () => {
555
+ vi.resetModules();
556
+ process.argv = ['node', 'cli', 'remove']; // missing name
557
+
558
+ const ctx = makeStubContext();
559
+ vi.doMock('./context.js', () => ({
560
+ createContext: () => ctx,
561
+ ExitCodes: { SUCCESS: 0, ERROR: 1 },
562
+ }));
563
+ const exitSpy = vi.spyOn(process, 'exit').mockImplementation((() => {}) as any);
564
+
565
+ await import('./cli.js');
566
+ await new Promise((r) => setTimeout(r, 0));
567
+
568
+ expect(ctx.ui.error).toHaveBeenCalled();
569
+ expect(exitSpy).toHaveBeenCalledWith(1);
570
+ });
571
+
572
+ it('errors on check with missing arguments', async () => {
573
+ vi.resetModules();
574
+ process.argv = ['node', 'cli', 'check']; // missing target
575
+
576
+ const ctx = makeStubContext();
577
+ vi.doMock('./context.js', () => ({
578
+ createContext: () => ctx,
579
+ ExitCodes: { SUCCESS: 0, ERROR: 1 },
580
+ }));
581
+ const exitSpy = vi.spyOn(process, 'exit').mockImplementation((() => {}) as any);
582
+
583
+ await import('./cli.js');
584
+ await new Promise((r) => setTimeout(r, 0));
585
+
586
+ expect(ctx.ui.error).toHaveBeenCalled();
587
+ expect(exitSpy).toHaveBeenCalledWith(1);
588
+ });
163
589
  });
package/src/cli.ts CHANGED
@@ -20,8 +20,8 @@ import { cmdCompletion } from './commands/completion.js';
20
20
  import { cmdConfig } from './commands/config.js';
21
21
  import { cmdPreamble } from './commands/preamble.js';
22
22
  import { cmdInstall } from './commands/install.js';
23
- import { cmdSetup } from './commands/setup.js';
24
23
  import { cmdLearn } from './commands/learn.js';
24
+ import { cmdThis } from './commands/this.js';
25
25
 
26
26
  // ─────────────────────────────────────────────────────────────
27
27
  // Argument parsing
@@ -147,7 +147,7 @@ function main(): void {
147
147
  const ctx = createContext({ argv, flags });
148
148
 
149
149
  // Warn if not in tmux for commands that require it
150
- const TMUX_REQUIRED_COMMANDS = ['talk', 'send', 'check', 'read', 'setup'];
150
+ const TMUX_REQUIRED_COMMANDS = ['talk', 'send', 'check', 'read', 'this'];
151
151
  if (!process.env.TMUX && TMUX_REQUIRED_COMMANDS.includes(command)) {
152
152
  ctx.ui.warn('Not running inside tmux. Some features may not work.');
153
153
  }
@@ -202,6 +202,14 @@ function main(): void {
202
202
  cmdRemove(ctx, args[0]);
203
203
  break;
204
204
 
205
+ case 'this':
206
+ if (args.length < 1) {
207
+ ctx.ui.error('Usage: tmux-team this <name> [remark]');
208
+ ctx.exit(ExitCodes.ERROR);
209
+ }
210
+ cmdThis(ctx, args[0], args[1]);
211
+ break;
212
+
205
213
  case 'talk':
206
214
  case 'send':
207
215
  if (args.length < 2) {
@@ -232,10 +240,6 @@ function main(): void {
232
240
  await cmdInstall(ctx, args[0]);
233
241
  break;
234
242
 
235
- case 'setup':
236
- await cmdSetup(ctx);
237
- break;
238
-
239
243
  case 'learn':
240
244
  cmdLearn();
241
245
  break;