tmux-team 4.0.0 → 4.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +123 -25
- package/package.json +15 -16
- package/src/cli.test.ts +15 -1
- package/src/cli.ts +15 -1
- package/src/commands/add.ts +17 -32
- package/src/commands/basic-commands.test.ts +534 -17
- package/src/commands/check.ts +20 -0
- package/src/commands/completion.ts +6 -8
- package/src/commands/config-command.test.ts +9 -8
- package/src/commands/config.ts +1 -5
- package/src/commands/help.ts +8 -3
- package/src/commands/install.test.ts +15 -1
- package/src/commands/list.ts +21 -2
- package/src/commands/migrate.ts +84 -0
- package/src/commands/preamble.test.ts +15 -2
- package/src/commands/preamble.ts +61 -16
- package/src/commands/remove.ts +10 -6
- package/src/commands/talk.test.ts +132 -22
- package/src/commands/talk.ts +28 -3
- package/src/commands/team.ts +361 -0
- package/src/commands/update.ts +45 -14
- package/src/config.test.ts +24 -0
- package/src/config.ts +37 -3
- package/src/context.test.ts +76 -1
- package/src/context.ts +8 -1
- package/src/identity.test.ts +3 -9
- package/src/identity.ts +7 -9
- package/src/registry.test.ts +61 -0
- package/src/registry.ts +29 -0
- package/src/tmux.test.ts +190 -1
- package/src/tmux.ts +289 -9
- package/src/types.ts +55 -0
- package/src/ui.test.ts +7 -1
|
@@ -43,6 +43,25 @@ function createMockTmux(): Tmux & {
|
|
|
43
43
|
getCurrentPaneId() {
|
|
44
44
|
return null;
|
|
45
45
|
},
|
|
46
|
+
resolvePaneTarget(target: string) {
|
|
47
|
+
return target;
|
|
48
|
+
},
|
|
49
|
+
getAgentRegistry() {
|
|
50
|
+
return { paneRegistry: {}, agents: {} };
|
|
51
|
+
},
|
|
52
|
+
setAgentRegistration() {},
|
|
53
|
+
clearAgentRegistration() {
|
|
54
|
+
return false;
|
|
55
|
+
},
|
|
56
|
+
listTeams() {
|
|
57
|
+
return {};
|
|
58
|
+
},
|
|
59
|
+
listTeamPanes() {
|
|
60
|
+
return [];
|
|
61
|
+
},
|
|
62
|
+
removeTeam() {
|
|
63
|
+
return { removed: 0, agents: [] };
|
|
64
|
+
},
|
|
46
65
|
};
|
|
47
66
|
return mock;
|
|
48
67
|
}
|
|
@@ -239,7 +258,8 @@ describe('buildMessage (via cmdTalk)', () => {
|
|
|
239
258
|
pollInterval: 0.1,
|
|
240
259
|
captureLines: 100,
|
|
241
260
|
maxCaptureLines: 2000,
|
|
242
|
-
preambleEvery: 3,
|
|
261
|
+
preambleEvery: 3,
|
|
262
|
+
pasteEnterDelayMs: 500,
|
|
243
263
|
},
|
|
244
264
|
};
|
|
245
265
|
|
|
@@ -448,6 +468,27 @@ describe('cmdTalk - basic send', () => {
|
|
|
448
468
|
expect(ui.errors[0]).toContain("Agent 'unknown' not found");
|
|
449
469
|
});
|
|
450
470
|
|
|
471
|
+
it('requires explicit team when a missing agent appears in shared teams', async () => {
|
|
472
|
+
const tmux = createMockTmux();
|
|
473
|
+
vi.spyOn(tmux, 'listTeams').mockReturnValue({
|
|
474
|
+
frontend: ['codex'],
|
|
475
|
+
release: ['codex'],
|
|
476
|
+
});
|
|
477
|
+
const ui = createMockUI();
|
|
478
|
+
const ctx = createContext({
|
|
479
|
+
tmux,
|
|
480
|
+
ui,
|
|
481
|
+
paths: createTestPaths(testDir),
|
|
482
|
+
config: { paneRegistry: {} },
|
|
483
|
+
});
|
|
484
|
+
|
|
485
|
+
await expect(cmdTalk(ctx, 'codex', 'Hello')).rejects.toThrow('exit(3)');
|
|
486
|
+
|
|
487
|
+
expect(ui.errors).toEqual([
|
|
488
|
+
"Agent 'codex' is in multiple shared teams: frontend, release. Specify one with --team <team>.",
|
|
489
|
+
]);
|
|
490
|
+
});
|
|
491
|
+
|
|
451
492
|
it('outputs JSON when --json flag is set', async () => {
|
|
452
493
|
const tmux = createMockTmux();
|
|
453
494
|
const ui = createMockUI();
|
|
@@ -551,7 +592,8 @@ describe('cmdTalk - --wait mode', () => {
|
|
|
551
592
|
pollInterval: 0.01,
|
|
552
593
|
captureLines: 100,
|
|
553
594
|
maxCaptureLines: 2000,
|
|
554
|
-
preambleEvery: 3,
|
|
595
|
+
preambleEvery: 3,
|
|
596
|
+
pasteEnterDelayMs: 500,
|
|
555
597
|
},
|
|
556
598
|
},
|
|
557
599
|
});
|
|
@@ -595,7 +637,8 @@ describe('cmdTalk - --wait mode', () => {
|
|
|
595
637
|
pollInterval: 0.01,
|
|
596
638
|
captureLines: 100,
|
|
597
639
|
maxCaptureLines: 2000,
|
|
598
|
-
preambleEvery: 3,
|
|
640
|
+
preambleEvery: 3,
|
|
641
|
+
pasteEnterDelayMs: 500,
|
|
599
642
|
},
|
|
600
643
|
},
|
|
601
644
|
});
|
|
@@ -626,7 +669,8 @@ describe('cmdTalk - --wait mode', () => {
|
|
|
626
669
|
pollInterval: 0.02,
|
|
627
670
|
captureLines: 100,
|
|
628
671
|
maxCaptureLines: 2000,
|
|
629
|
-
preambleEvery: 3,
|
|
672
|
+
preambleEvery: 3,
|
|
673
|
+
pasteEnterDelayMs: 500,
|
|
630
674
|
},
|
|
631
675
|
},
|
|
632
676
|
});
|
|
@@ -674,7 +718,8 @@ describe('cmdTalk - --wait mode', () => {
|
|
|
674
718
|
pollInterval: 0.01,
|
|
675
719
|
captureLines: 100,
|
|
676
720
|
maxCaptureLines: 2000,
|
|
677
|
-
preambleEvery: 3,
|
|
721
|
+
preambleEvery: 3,
|
|
722
|
+
pasteEnterDelayMs: 500,
|
|
678
723
|
},
|
|
679
724
|
},
|
|
680
725
|
});
|
|
@@ -710,7 +755,8 @@ describe('cmdTalk - --wait mode', () => {
|
|
|
710
755
|
pollInterval: 0.01,
|
|
711
756
|
captureLines: 100,
|
|
712
757
|
maxCaptureLines: 2000,
|
|
713
|
-
preambleEvery: 3,
|
|
758
|
+
preambleEvery: 3,
|
|
759
|
+
pasteEnterDelayMs: 500,
|
|
714
760
|
},
|
|
715
761
|
},
|
|
716
762
|
});
|
|
@@ -739,7 +785,8 @@ describe('cmdTalk - --wait mode', () => {
|
|
|
739
785
|
pollInterval: 0.01,
|
|
740
786
|
captureLines: 100,
|
|
741
787
|
maxCaptureLines: 2000,
|
|
742
|
-
preambleEvery: 3,
|
|
788
|
+
preambleEvery: 3,
|
|
789
|
+
pasteEnterDelayMs: 500,
|
|
743
790
|
},
|
|
744
791
|
},
|
|
745
792
|
});
|
|
@@ -791,7 +838,8 @@ describe('cmdTalk - --wait mode', () => {
|
|
|
791
838
|
pollInterval: 0.05,
|
|
792
839
|
captureLines: 100,
|
|
793
840
|
maxCaptureLines: 2000,
|
|
794
|
-
preambleEvery: 3,
|
|
841
|
+
preambleEvery: 3,
|
|
842
|
+
pasteEnterDelayMs: 500,
|
|
795
843
|
},
|
|
796
844
|
paneRegistry: {
|
|
797
845
|
codex: { pane: '10.1' },
|
|
@@ -837,7 +885,8 @@ describe('cmdTalk - --wait mode', () => {
|
|
|
837
885
|
pollInterval: 0.02,
|
|
838
886
|
captureLines: 100,
|
|
839
887
|
maxCaptureLines: 2000,
|
|
840
|
-
preambleEvery: 3,
|
|
888
|
+
preambleEvery: 3,
|
|
889
|
+
pasteEnterDelayMs: 500,
|
|
841
890
|
},
|
|
842
891
|
paneRegistry: {
|
|
843
892
|
codex: { pane: '10.1' },
|
|
@@ -892,7 +941,8 @@ describe('cmdTalk - --wait mode', () => {
|
|
|
892
941
|
pollInterval: 0.02,
|
|
893
942
|
captureLines: 100,
|
|
894
943
|
maxCaptureLines: 2000,
|
|
895
|
-
preambleEvery: 3,
|
|
944
|
+
preambleEvery: 3,
|
|
945
|
+
pasteEnterDelayMs: 500,
|
|
896
946
|
},
|
|
897
947
|
paneRegistry: {
|
|
898
948
|
codex: { pane: '10.1' },
|
|
@@ -1003,7 +1053,8 @@ describe('cmdTalk - nonce collision handling', () => {
|
|
|
1003
1053
|
pollInterval: 0.01,
|
|
1004
1054
|
captureLines: 100,
|
|
1005
1055
|
maxCaptureLines: 2000,
|
|
1006
|
-
preambleEvery: 3,
|
|
1056
|
+
preambleEvery: 3,
|
|
1057
|
+
pasteEnterDelayMs: 500,
|
|
1007
1058
|
},
|
|
1008
1059
|
},
|
|
1009
1060
|
});
|
|
@@ -1058,7 +1109,8 @@ describe('cmdTalk - JSON output contract', () => {
|
|
|
1058
1109
|
pollInterval: 0.01,
|
|
1059
1110
|
captureLines: 100,
|
|
1060
1111
|
maxCaptureLines: 2000,
|
|
1061
|
-
preambleEvery: 3,
|
|
1112
|
+
preambleEvery: 3,
|
|
1113
|
+
pasteEnterDelayMs: 500,
|
|
1062
1114
|
},
|
|
1063
1115
|
},
|
|
1064
1116
|
});
|
|
@@ -1099,7 +1151,8 @@ describe('cmdTalk - JSON output contract', () => {
|
|
|
1099
1151
|
pollInterval: 0.01,
|
|
1100
1152
|
captureLines: 100,
|
|
1101
1153
|
maxCaptureLines: 2000,
|
|
1102
|
-
preambleEvery: 3,
|
|
1154
|
+
preambleEvery: 3,
|
|
1155
|
+
pasteEnterDelayMs: 500,
|
|
1103
1156
|
},
|
|
1104
1157
|
},
|
|
1105
1158
|
});
|
|
@@ -1141,7 +1194,8 @@ describe('cmdTalk - JSON output contract', () => {
|
|
|
1141
1194
|
pollInterval: 0.01,
|
|
1142
1195
|
captureLines: 100,
|
|
1143
1196
|
maxCaptureLines: 2000,
|
|
1144
|
-
preambleEvery: 3,
|
|
1197
|
+
preambleEvery: 3,
|
|
1198
|
+
pasteEnterDelayMs: 500,
|
|
1145
1199
|
},
|
|
1146
1200
|
},
|
|
1147
1201
|
});
|
|
@@ -1178,7 +1232,8 @@ describe('cmdTalk - JSON output contract', () => {
|
|
|
1178
1232
|
pollInterval: 0.01,
|
|
1179
1233
|
captureLines: 100,
|
|
1180
1234
|
maxCaptureLines: 2000,
|
|
1181
|
-
preambleEvery: 3,
|
|
1235
|
+
preambleEvery: 3,
|
|
1236
|
+
pasteEnterDelayMs: 500,
|
|
1182
1237
|
},
|
|
1183
1238
|
},
|
|
1184
1239
|
});
|
|
@@ -1228,7 +1283,8 @@ describe('cmdTalk - JSON output contract', () => {
|
|
|
1228
1283
|
pollInterval: 0.02,
|
|
1229
1284
|
captureLines: 100,
|
|
1230
1285
|
maxCaptureLines: 2000,
|
|
1231
|
-
preambleEvery: 3,
|
|
1286
|
+
preambleEvery: 3,
|
|
1287
|
+
pasteEnterDelayMs: 500,
|
|
1232
1288
|
},
|
|
1233
1289
|
paneRegistry: {
|
|
1234
1290
|
codex: { pane: '10.1' },
|
|
@@ -1310,7 +1366,16 @@ describe('cmdTalk - end marker detection', () => {
|
|
|
1310
1366
|
ui,
|
|
1311
1367
|
paths: createTestPaths(testDir),
|
|
1312
1368
|
flags: { wait: true, json: true, timeout: 0.5 },
|
|
1313
|
-
config: {
|
|
1369
|
+
config: {
|
|
1370
|
+
defaults: {
|
|
1371
|
+
timeout: 0.5,
|
|
1372
|
+
pollInterval: 0.01,
|
|
1373
|
+
captureLines: 100,
|
|
1374
|
+
maxCaptureLines: 2000,
|
|
1375
|
+
preambleEvery: 3,
|
|
1376
|
+
pasteEnterDelayMs: 500,
|
|
1377
|
+
},
|
|
1378
|
+
},
|
|
1314
1379
|
});
|
|
1315
1380
|
|
|
1316
1381
|
await cmdTalk(ctx, 'claude', 'Test message');
|
|
@@ -1344,7 +1409,16 @@ describe('cmdTalk - end marker detection', () => {
|
|
|
1344
1409
|
ui,
|
|
1345
1410
|
paths: createTestPaths(testDir),
|
|
1346
1411
|
flags: { wait: true, json: true, timeout: 0.5 },
|
|
1347
|
-
config: {
|
|
1412
|
+
config: {
|
|
1413
|
+
defaults: {
|
|
1414
|
+
timeout: 0.5,
|
|
1415
|
+
pollInterval: 0.01,
|
|
1416
|
+
captureLines: 100,
|
|
1417
|
+
maxCaptureLines: 2000,
|
|
1418
|
+
preambleEvery: 3,
|
|
1419
|
+
pasteEnterDelayMs: 500,
|
|
1420
|
+
},
|
|
1421
|
+
},
|
|
1348
1422
|
});
|
|
1349
1423
|
|
|
1350
1424
|
await cmdTalk(ctx, 'claude', 'Test');
|
|
@@ -1378,7 +1452,16 @@ Line 4 final`;
|
|
|
1378
1452
|
ui,
|
|
1379
1453
|
paths: createTestPaths(testDir),
|
|
1380
1454
|
flags: { wait: true, json: true, timeout: 0.5 },
|
|
1381
|
-
config: {
|
|
1455
|
+
config: {
|
|
1456
|
+
defaults: {
|
|
1457
|
+
timeout: 0.5,
|
|
1458
|
+
pollInterval: 0.01,
|
|
1459
|
+
captureLines: 100,
|
|
1460
|
+
maxCaptureLines: 2000,
|
|
1461
|
+
preambleEvery: 3,
|
|
1462
|
+
pasteEnterDelayMs: 500,
|
|
1463
|
+
},
|
|
1464
|
+
},
|
|
1382
1465
|
});
|
|
1383
1466
|
|
|
1384
1467
|
await cmdTalk(ctx, 'claude', 'Test');
|
|
@@ -1409,7 +1492,16 @@ Line 4 final`;
|
|
|
1409
1492
|
ui,
|
|
1410
1493
|
paths: createTestPaths(testDir),
|
|
1411
1494
|
flags: { wait: true, json: true, timeout: 0.5 },
|
|
1412
|
-
config: {
|
|
1495
|
+
config: {
|
|
1496
|
+
defaults: {
|
|
1497
|
+
timeout: 0.5,
|
|
1498
|
+
pollInterval: 0.01,
|
|
1499
|
+
captureLines: 100,
|
|
1500
|
+
maxCaptureLines: 2000,
|
|
1501
|
+
preambleEvery: 3,
|
|
1502
|
+
pasteEnterDelayMs: 500,
|
|
1503
|
+
},
|
|
1504
|
+
},
|
|
1413
1505
|
});
|
|
1414
1506
|
|
|
1415
1507
|
await cmdTalk(ctx, 'claude', 'Test');
|
|
@@ -1446,7 +1538,16 @@ Line 4 final`;
|
|
|
1446
1538
|
ui,
|
|
1447
1539
|
paths: createTestPaths(testDir),
|
|
1448
1540
|
flags: { wait: true, json: true, timeout: 0.5 },
|
|
1449
|
-
config: {
|
|
1541
|
+
config: {
|
|
1542
|
+
defaults: {
|
|
1543
|
+
timeout: 0.5,
|
|
1544
|
+
pollInterval: 0.01,
|
|
1545
|
+
captureLines: 100,
|
|
1546
|
+
maxCaptureLines: 2000,
|
|
1547
|
+
preambleEvery: 3,
|
|
1548
|
+
pasteEnterDelayMs: 500,
|
|
1549
|
+
},
|
|
1550
|
+
},
|
|
1450
1551
|
});
|
|
1451
1552
|
|
|
1452
1553
|
await cmdTalk(ctx, 'claude', 'Test');
|
|
@@ -1482,7 +1583,16 @@ Line 4 final`;
|
|
|
1482
1583
|
ui,
|
|
1483
1584
|
paths: createTestPaths(testDir),
|
|
1484
1585
|
flags: { wait: true, json: true, timeout: 0.5 },
|
|
1485
|
-
config: {
|
|
1586
|
+
config: {
|
|
1587
|
+
defaults: {
|
|
1588
|
+
timeout: 0.5,
|
|
1589
|
+
pollInterval: 0.01,
|
|
1590
|
+
captureLines: 200,
|
|
1591
|
+
maxCaptureLines: 2000,
|
|
1592
|
+
preambleEvery: 3,
|
|
1593
|
+
pasteEnterDelayMs: 500,
|
|
1594
|
+
},
|
|
1595
|
+
},
|
|
1486
1596
|
});
|
|
1487
1597
|
|
|
1488
1598
|
await cmdTalk(ctx, 'claude', 'Test');
|
package/src/commands/talk.ts
CHANGED
|
@@ -186,7 +186,10 @@ function extractWithExpandableCapture(
|
|
|
186
186
|
|
|
187
187
|
if (instructionLineIndex !== -1 && instructionLineIndex < endMarkerLineIndex) {
|
|
188
188
|
// Instruction visible: extract from after instruction to marker
|
|
189
|
-
const response = lines
|
|
189
|
+
const response = lines
|
|
190
|
+
.slice(instructionLineIndex + 1, endMarkerLineIndex)
|
|
191
|
+
.join('\n')
|
|
192
|
+
.trim();
|
|
190
193
|
return { response, truncated: false };
|
|
191
194
|
}
|
|
192
195
|
|
|
@@ -316,6 +319,21 @@ function buildMessage(message: string, agentName: string, ctx: Context): string
|
|
|
316
319
|
return `[SYSTEM: ${preamble}]\n\n${message}`;
|
|
317
320
|
}
|
|
318
321
|
|
|
322
|
+
function teamHintForMissingAgent(ctx: Context, target: string): string | null {
|
|
323
|
+
if (ctx.flags.team) return null;
|
|
324
|
+
|
|
325
|
+
const matches = Object.entries(ctx.tmux.listTeams())
|
|
326
|
+
.filter(([, agents]) => agents.includes(target))
|
|
327
|
+
.map(([teamName]) => teamName)
|
|
328
|
+
.sort();
|
|
329
|
+
|
|
330
|
+
if (matches.length === 0) return null;
|
|
331
|
+
if (matches.length === 1) {
|
|
332
|
+
return `Agent '${target}' is in shared team '${matches[0]}'. Specify it: tmt talk ${target} "..." --team ${matches[0]}`;
|
|
333
|
+
}
|
|
334
|
+
return `Agent '${target}' is in multiple shared teams: ${matches.join(', ')}. Specify one with --team <team>.`;
|
|
335
|
+
}
|
|
336
|
+
|
|
319
337
|
export async function cmdTalk(ctx: Context, target: string, message: string): Promise<void> {
|
|
320
338
|
const { ui, config, tmux, flags, exit } = ctx;
|
|
321
339
|
const waitEnabled = Boolean(flags.wait) || config.mode === 'wait';
|
|
@@ -386,6 +404,11 @@ export async function cmdTalk(ctx: Context, target: string, message: string): Pr
|
|
|
386
404
|
// Single agent
|
|
387
405
|
if (!config.paneRegistry[target]) {
|
|
388
406
|
const available = Object.keys(config.paneRegistry).join(', ');
|
|
407
|
+
const teamHint = teamHintForMissingAgent(ctx, target);
|
|
408
|
+
if (teamHint) {
|
|
409
|
+
ui.error(teamHint);
|
|
410
|
+
exit(ExitCodes.PANE_NOT_FOUND);
|
|
411
|
+
}
|
|
389
412
|
ui.error(`Agent '${target}' not found. Available: ${available || 'none'}`);
|
|
390
413
|
exit(ExitCodes.PANE_NOT_FOUND);
|
|
391
414
|
}
|
|
@@ -619,7 +642,8 @@ export async function cmdTalk(ctx: Context, target: string, message: string): Pr
|
|
|
619
642
|
);
|
|
620
643
|
|
|
621
644
|
// Clean Gemini CLI UI artifacts
|
|
622
|
-
const response =
|
|
645
|
+
const response =
|
|
646
|
+
target === 'gemini' ? cleanGeminiResponse(extractedResponse) : extractedResponse;
|
|
623
647
|
|
|
624
648
|
if (!flags.json && isTTY) {
|
|
625
649
|
process.stdout.write('\r' + ' '.repeat(80) + '\r');
|
|
@@ -883,7 +907,8 @@ async function cmdTalkAllWait(
|
|
|
883
907
|
);
|
|
884
908
|
|
|
885
909
|
// Clean Gemini CLI UI artifacts
|
|
886
|
-
const response =
|
|
910
|
+
const response =
|
|
911
|
+
state.agent === 'gemini' ? cleanGeminiResponse(extractedResponse) : extractedResponse;
|
|
887
912
|
state.response = response;
|
|
888
913
|
state.truncated = truncated;
|
|
889
914
|
state.status = 'completed';
|