@fonz/tgcc 0.0.1 → 0.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/dist/cli.js ADDED
@@ -0,0 +1,668 @@
1
+ #!/usr/bin/env node
2
+ import { createConnection } from 'node:net';
3
+ import { existsSync, readdirSync, readFileSync, writeFileSync, mkdirSync } from 'node:fs';
4
+ import { join, dirname, resolve } from 'node:path';
5
+ import { homedir } from 'node:os';
6
+ import { loadConfig, agentForRepo, CONFIG_PATH, updateConfig, isValidRepoName, findRepoOwner } from './config.js';
7
+ const CTL_DIR = '/tmp/tgcc/ctl';
8
+ // ── Socket communication ──
9
+ function sendRequest(socketPath, request) {
10
+ return new Promise((resolve, reject) => {
11
+ if (!existsSync(socketPath)) {
12
+ reject(new Error(`Agent socket not found: ${socketPath}\nIs the TGCC service running?`));
13
+ return;
14
+ }
15
+ const socket = createConnection(socketPath);
16
+ let buffer = '';
17
+ socket.on('connect', () => {
18
+ socket.write(JSON.stringify(request) + '\n');
19
+ });
20
+ socket.on('data', (data) => {
21
+ buffer += data.toString();
22
+ const newlineIdx = buffer.indexOf('\n');
23
+ if (newlineIdx !== -1) {
24
+ const line = buffer.slice(0, newlineIdx);
25
+ try {
26
+ const response = JSON.parse(line);
27
+ socket.destroy();
28
+ resolve(response);
29
+ }
30
+ catch (err) {
31
+ socket.destroy();
32
+ reject(new Error(`Invalid response from agent: ${line}`));
33
+ }
34
+ }
35
+ });
36
+ socket.on('error', (err) => {
37
+ reject(new Error(`Cannot connect to agent: ${err.message}`));
38
+ });
39
+ // Timeout after 10s
40
+ socket.setTimeout(10_000, () => {
41
+ socket.destroy();
42
+ reject(new Error('Connection timed out'));
43
+ });
44
+ });
45
+ }
46
+ // ── Agent resolution ──
47
+ function resolveAgent(explicitAgent, config) {
48
+ if (explicitAgent) {
49
+ if (!config.agents[explicitAgent]) {
50
+ console.error(`Error: Unknown agent "${explicitAgent}"`);
51
+ process.exit(1);
52
+ }
53
+ return explicitAgent;
54
+ }
55
+ // Auto-detect from cwd
56
+ const cwd = process.cwd();
57
+ const agentId = agentForRepo(config, cwd);
58
+ if (!agentId) {
59
+ console.error(`Error: No agent configured for this repo (${cwd})`);
60
+ console.error('Use --agent <name> to specify explicitly');
61
+ process.exit(1);
62
+ }
63
+ return agentId;
64
+ }
65
+ // ── Commands ──
66
+ async function cmdMessage(args) {
67
+ let agentName;
68
+ let sessionId;
69
+ const textParts = [];
70
+ // Parse flags
71
+ for (let i = 0; i < args.length; i++) {
72
+ if (args[i] === '--agent' && i + 1 < args.length) {
73
+ agentName = args[++i];
74
+ }
75
+ else if (args[i] === '--session' && i + 1 < args.length) {
76
+ sessionId = args[++i];
77
+ }
78
+ else {
79
+ textParts.push(args[i]);
80
+ }
81
+ }
82
+ const text = textParts.join(' ');
83
+ if (!text) {
84
+ console.error('Error: No message text provided');
85
+ console.error('Usage: tgcc message [--agent <name>] [--session <id>] "your message"');
86
+ process.exit(1);
87
+ }
88
+ const config = loadConfigSafe();
89
+ const agentId = resolveAgent(agentName, config);
90
+ const socketPath = join(CTL_DIR, `${agentId}.sock`);
91
+ const request = {
92
+ type: 'message',
93
+ text,
94
+ agent: agentId,
95
+ ...(sessionId ? { session: sessionId } : {}),
96
+ };
97
+ const response = await sendRequest(socketPath, request);
98
+ if (response.type === 'error') {
99
+ console.error(`Error: ${response.message}`);
100
+ process.exit(1);
101
+ }
102
+ if (response.type === 'ack') {
103
+ console.log(`Message sent to ${agentId}`);
104
+ console.log(` Session: ${response.sessionId?.slice(0, 8) ?? 'pending'}`);
105
+ console.log(` State: ${response.state}`);
106
+ }
107
+ }
108
+ async function cmdStatus(args) {
109
+ let agentName;
110
+ for (let i = 0; i < args.length; i++) {
111
+ if (args[i] === '--agent' && i + 1 < args.length) {
112
+ agentName = args[++i];
113
+ }
114
+ }
115
+ // If no explicit agent and we can detect from cwd, use it
116
+ const config = loadConfigSafe();
117
+ // Find which sockets exist (running agents)
118
+ const sockets = existsSync(CTL_DIR)
119
+ ? readdirSync(CTL_DIR).filter(f => f.endsWith('.sock'))
120
+ : [];
121
+ if (sockets.length === 0) {
122
+ console.log('No running agents found.');
123
+ return;
124
+ }
125
+ // If specific agent requested, only query that one
126
+ const targetAgents = agentName ? [`${agentName}.sock`] : sockets;
127
+ for (const sockFile of targetAgents) {
128
+ const socketPath = join(CTL_DIR, sockFile);
129
+ if (!existsSync(socketPath)) {
130
+ console.log(`Agent ${sockFile.replace('.sock', '')}: not running`);
131
+ continue;
132
+ }
133
+ try {
134
+ const response = await sendRequest(socketPath, {
135
+ type: 'status',
136
+ agent: sockFile.replace('.sock', ''),
137
+ });
138
+ if (response.type === 'status') {
139
+ for (const agent of response.agents) {
140
+ console.log(`\n${agent.id}:`);
141
+ console.log(` State: ${agent.state}`);
142
+ console.log(` Session: ${agent.sessionId?.slice(0, 8) ?? 'none'}`);
143
+ console.log(` Repo: ${agent.repo}`);
144
+ }
145
+ if (response.sessions.length > 0) {
146
+ console.log('\n Recent sessions:');
147
+ for (const sess of response.sessions) {
148
+ console.log(` ${sess.id.slice(0, 8)} — ${sess.messageCount} msgs, $${sess.totalCostUsd.toFixed(4)}`);
149
+ }
150
+ }
151
+ }
152
+ else if (response.type === 'error') {
153
+ console.error(` Error: ${response.message}`);
154
+ }
155
+ }
156
+ catch (err) {
157
+ console.error(` ${err instanceof Error ? err.message : err}`);
158
+ }
159
+ }
160
+ }
161
+ function loadConfigSafe() {
162
+ try {
163
+ return loadConfig();
164
+ }
165
+ catch (err) {
166
+ console.error(`Error loading config: ${err instanceof Error ? err.message : err}`);
167
+ process.exit(1);
168
+ }
169
+ }
170
+ // ── Raw config read/write (preserves structure for agent management) ──
171
+ function readRawConfig() {
172
+ if (!existsSync(CONFIG_PATH)) {
173
+ return { agents: {} };
174
+ }
175
+ return JSON.parse(readFileSync(CONFIG_PATH, 'utf-8'));
176
+ }
177
+ function writeRawConfig(raw) {
178
+ const dir = dirname(CONFIG_PATH);
179
+ if (!existsSync(dir))
180
+ mkdirSync(dir, { recursive: true });
181
+ writeFileSync(CONFIG_PATH, JSON.stringify(raw, null, 2) + '\n');
182
+ }
183
+ // ── Agent management commands ──
184
+ function cmdAgentAdd(args) {
185
+ const name = args[0];
186
+ if (!name) {
187
+ console.error('Usage: tgcc agent add <name> --bot-token <token> [--repo <name-or-path>]');
188
+ process.exit(1);
189
+ }
190
+ let botToken;
191
+ let repo;
192
+ for (let i = 1; i < args.length; i++) {
193
+ if ((args[i] === '--bot-token' || args[i] === '--token') && i + 1 < args.length) {
194
+ botToken = args[++i];
195
+ }
196
+ else if (args[i] === '--repo' && i + 1 < args.length) {
197
+ repo = args[++i];
198
+ }
199
+ }
200
+ if (!botToken) {
201
+ console.error('Error: --bot-token is required');
202
+ process.exit(1);
203
+ }
204
+ const raw = readRawConfig();
205
+ const agents = (raw.agents ?? {});
206
+ if (agents[name]) {
207
+ console.error(`Error: Agent "${name}" already exists. Remove it first.`);
208
+ process.exit(1);
209
+ }
210
+ const agentEntry = {
211
+ botToken,
212
+ allowedUsers: ['7016073156'], // default — user can edit config
213
+ };
214
+ if (repo) {
215
+ // Check if it's a registry key or a path
216
+ const repos = (raw.repos ?? {});
217
+ if (repos[repo]) {
218
+ agentEntry.defaults = { repo };
219
+ }
220
+ else {
221
+ // It's a direct path — add to repos registry and reference it
222
+ const repoName = repo.split('/').pop() ?? name;
223
+ const absPath = resolve(repo);
224
+ repos[repoName] = absPath;
225
+ raw.repos = repos;
226
+ agentEntry.defaults = { repo: repoName };
227
+ }
228
+ }
229
+ agents[name] = agentEntry;
230
+ raw.agents = agents;
231
+ writeRawConfig(raw);
232
+ console.log(`Agent "${name}" added.`);
233
+ if (repo)
234
+ console.log(` Default repo: ${repo}`);
235
+ console.log('Config hot-reload will pick it up automatically.');
236
+ }
237
+ function cmdAgentRemove(args) {
238
+ const name = args[0];
239
+ if (!name) {
240
+ console.error('Usage: tgcc agent remove <name>');
241
+ process.exit(1);
242
+ }
243
+ const raw = readRawConfig();
244
+ const agents = (raw.agents ?? {});
245
+ if (!agents[name]) {
246
+ console.error(`Error: Agent "${name}" not found.`);
247
+ process.exit(1);
248
+ }
249
+ delete agents[name];
250
+ raw.agents = agents;
251
+ writeRawConfig(raw);
252
+ console.log(`Agent "${name}" removed.`);
253
+ }
254
+ function cmdAgentList() {
255
+ const raw = readRawConfig();
256
+ const agents = (raw.agents ?? {});
257
+ const repos = (raw.repos ?? {});
258
+ const entries = Object.entries(agents);
259
+ if (entries.length === 0) {
260
+ console.log('No agents configured.');
261
+ return;
262
+ }
263
+ for (const [name, agent] of entries) {
264
+ const defaults = (agent.defaults ?? {});
265
+ const repoKey = defaults.repo;
266
+ const repoPath = repoKey ? (repos[repoKey] ?? repoKey) : 'none (generic)';
267
+ console.log(`${name}:`);
268
+ console.log(` Token: ${agent.botToken?.slice(0, 10)}...`);
269
+ console.log(` Repo: ${repoPath}`);
270
+ console.log(` Users: ${agent.allowedUsers?.join(', ') ?? 'none'}`);
271
+ }
272
+ }
273
+ function cmdAgentRepo(args) {
274
+ const name = args[0];
275
+ const repoArg = args[1];
276
+ if (!name || !repoArg) {
277
+ console.error('Usage: tgcc agent repo <name> <name-or-path>');
278
+ process.exit(1);
279
+ }
280
+ const raw = readRawConfig();
281
+ const agents = (raw.agents ?? {});
282
+ if (!agents[name]) {
283
+ console.error(`Error: Agent "${name}" not found.`);
284
+ process.exit(1);
285
+ }
286
+ const repos = (raw.repos ?? {});
287
+ if (repos[repoArg]) {
288
+ // It's a registry key
289
+ const defaults = (agents[name].defaults ?? {});
290
+ defaults.repo = repoArg;
291
+ agents[name].defaults = defaults;
292
+ }
293
+ else {
294
+ // Direct path — add to registry
295
+ const repoName = repoArg.split('/').pop() ?? name;
296
+ const absPath = resolve(repoArg);
297
+ repos[repoName] = absPath;
298
+ raw.repos = repos;
299
+ const defaults = (agents[name].defaults ?? {});
300
+ defaults.repo = repoName;
301
+ agents[name].defaults = defaults;
302
+ }
303
+ raw.agents = agents;
304
+ writeRawConfig(raw);
305
+ console.log(`Agent "${name}" repo set to "${repoArg}".`);
306
+ }
307
+ function cmdAgentRename(args) {
308
+ const oldName = args[0];
309
+ const newName = args[1];
310
+ if (!oldName || !newName) {
311
+ console.error('Usage: tgcc agent rename <old-name> <new-name>');
312
+ process.exit(1);
313
+ }
314
+ const raw = readRawConfig();
315
+ const agents = (raw.agents ?? {});
316
+ if (!agents[oldName]) {
317
+ console.error(`Error: Agent "${oldName}" not found.`);
318
+ process.exit(1);
319
+ }
320
+ if (agents[newName]) {
321
+ console.error(`Error: Agent "${newName}" already exists.`);
322
+ process.exit(1);
323
+ }
324
+ // Move agent config to new key
325
+ agents[newName] = agents[oldName];
326
+ delete agents[oldName];
327
+ raw.agents = agents;
328
+ writeRawConfig(raw);
329
+ // Update session state file (rename agent key if present)
330
+ const globalRaw = (raw.global ?? {});
331
+ const stateFile = globalRaw.stateFile ?? join(homedir(), '.tgcc', 'state.json');
332
+ if (existsSync(stateFile)) {
333
+ try {
334
+ const state = JSON.parse(readFileSync(stateFile, 'utf-8'));
335
+ if (state.agents && state.agents[oldName]) {
336
+ state.agents[newName] = state.agents[oldName];
337
+ delete state.agents[oldName];
338
+ writeFileSync(stateFile, JSON.stringify(state, null, 2));
339
+ }
340
+ }
341
+ catch (err) {
342
+ console.warn(`Warning: Could not update state file: ${err instanceof Error ? err.message : err}`);
343
+ }
344
+ }
345
+ console.log(`Agent "${oldName}" renamed to "${newName}".`);
346
+ }
347
+ function cmdAgent(args) {
348
+ const subcommand = args[0];
349
+ switch (subcommand) {
350
+ case 'add':
351
+ cmdAgentAdd(args.slice(1));
352
+ break;
353
+ case 'remove':
354
+ case 'rm':
355
+ cmdAgentRemove(args.slice(1));
356
+ break;
357
+ case 'rename':
358
+ case 'mv':
359
+ cmdAgentRename(args.slice(1));
360
+ break;
361
+ case 'list':
362
+ case 'ls':
363
+ cmdAgentList();
364
+ break;
365
+ case 'repo':
366
+ cmdAgentRepo(args.slice(1));
367
+ break;
368
+ default:
369
+ console.error('Usage: tgcc agent <add|remove|rename|list|repo>');
370
+ console.error('');
371
+ console.error(' add <name> --bot-token <token> [--repo <path>]');
372
+ console.error(' remove <name>');
373
+ console.error(' rename <old> <new>');
374
+ console.error(' list');
375
+ console.error(' repo <name> <path>');
376
+ process.exit(1);
377
+ }
378
+ }
379
+ // ── Repo management commands ──
380
+ function cmdRepoList() {
381
+ const raw = readRawConfig();
382
+ const repos = (raw.repos ?? {});
383
+ const entries = Object.entries(repos);
384
+ if (entries.length === 0) {
385
+ console.log('No repos registered.');
386
+ return;
387
+ }
388
+ for (const [name, path] of entries) {
389
+ const owner = findRepoOwner(raw, name);
390
+ console.log(`${name}:`);
391
+ console.log(` Path: ${path}`);
392
+ console.log(` Agent: ${owner ?? 'unassigned'}`);
393
+ }
394
+ }
395
+ function cmdRepoAdd(args) {
396
+ const name = args[0];
397
+ const repoPath = args[1];
398
+ if (!name || !repoPath) {
399
+ console.error('Usage: tgcc repo add <name> <path>');
400
+ process.exit(1);
401
+ }
402
+ if (!isValidRepoName(name)) {
403
+ console.error('Invalid repo name. Use alphanumeric + hyphens only (must start with alphanumeric).');
404
+ process.exit(1);
405
+ }
406
+ if (!existsSync(repoPath)) {
407
+ console.error(`Path not found: ${repoPath}`);
408
+ process.exit(1);
409
+ }
410
+ const raw = readRawConfig();
411
+ const repos = (raw.repos ?? {});
412
+ if (repos[name]) {
413
+ console.error(`Repo "${name}" already exists.`);
414
+ process.exit(1);
415
+ }
416
+ const absPath = resolve(repoPath);
417
+ updateConfig((cfg) => {
418
+ const r = (cfg.repos ?? {});
419
+ r[name] = absPath;
420
+ cfg.repos = r;
421
+ });
422
+ console.log(`Repo "${name}" added → ${absPath}`);
423
+ }
424
+ function cmdRepoRemove(args) {
425
+ const name = args[0];
426
+ if (!name) {
427
+ console.error('Usage: tgcc repo remove <name>');
428
+ process.exit(1);
429
+ }
430
+ const raw = readRawConfig();
431
+ const repos = (raw.repos ?? {});
432
+ if (!repos[name]) {
433
+ console.error(`Repo "${name}" not found.`);
434
+ process.exit(1);
435
+ }
436
+ const owner = findRepoOwner(raw, name);
437
+ if (owner) {
438
+ console.error(`Can't remove: repo "${name}" is assigned to agent "${owner}". Use "tgcc repo clear ${owner}" first.`);
439
+ process.exit(1);
440
+ }
441
+ updateConfig((cfg) => {
442
+ const r = (cfg.repos ?? {});
443
+ delete r[name];
444
+ cfg.repos = r;
445
+ });
446
+ console.log(`Repo "${name}" removed.`);
447
+ }
448
+ function cmdRepoAssign(args) {
449
+ const agentName = args[0];
450
+ const repoName = args[1];
451
+ if (!agentName || !repoName) {
452
+ console.error('Usage: tgcc repo assign <agent> <name>');
453
+ process.exit(1);
454
+ }
455
+ const raw = readRawConfig();
456
+ const repos = (raw.repos ?? {});
457
+ const agents = (raw.agents ?? {});
458
+ if (!repos[repoName]) {
459
+ console.error(`Repo "${repoName}" not found in registry.`);
460
+ process.exit(1);
461
+ }
462
+ if (!agents[agentName]) {
463
+ console.error(`Agent "${agentName}" not found.`);
464
+ process.exit(1);
465
+ }
466
+ const existingOwner = findRepoOwner(raw, repoName);
467
+ if (existingOwner && existingOwner !== agentName) {
468
+ console.error(`Repo "${repoName}" is already assigned to agent "${existingOwner}".`);
469
+ process.exit(1);
470
+ }
471
+ updateConfig((cfg) => {
472
+ const a = (cfg.agents ?? {});
473
+ const agentCfg = a[agentName];
474
+ if (agentCfg) {
475
+ const defaults = (agentCfg.defaults ?? {});
476
+ defaults.repo = repoName;
477
+ agentCfg.defaults = defaults;
478
+ }
479
+ });
480
+ console.log(`Repo "${repoName}" assigned to agent "${agentName}".`);
481
+ }
482
+ function cmdRepoClear(args) {
483
+ const agentName = args[0];
484
+ if (!agentName) {
485
+ console.error('Usage: tgcc repo clear <agent>');
486
+ process.exit(1);
487
+ }
488
+ const raw = readRawConfig();
489
+ const agents = (raw.agents ?? {});
490
+ if (!agents[agentName]) {
491
+ console.error(`Agent "${agentName}" not found.`);
492
+ process.exit(1);
493
+ }
494
+ updateConfig((cfg) => {
495
+ const a = (cfg.agents ?? {});
496
+ const agentCfg = a[agentName];
497
+ if (agentCfg) {
498
+ const defaults = (agentCfg.defaults ?? {});
499
+ delete defaults.repo;
500
+ agentCfg.defaults = defaults;
501
+ }
502
+ });
503
+ console.log(`Default repo cleared for agent "${agentName}".`);
504
+ }
505
+ function cmdRepo(args) {
506
+ const subcommand = args[0];
507
+ switch (subcommand) {
508
+ case 'add':
509
+ cmdRepoAdd(args.slice(1));
510
+ break;
511
+ case 'remove':
512
+ case 'rm':
513
+ cmdRepoRemove(args.slice(1));
514
+ break;
515
+ case 'assign':
516
+ cmdRepoAssign(args.slice(1));
517
+ break;
518
+ case 'clear':
519
+ cmdRepoClear(args.slice(1));
520
+ break;
521
+ case undefined:
522
+ case 'list':
523
+ case 'ls':
524
+ cmdRepoList();
525
+ break;
526
+ default:
527
+ console.error('Usage: tgcc repo [add|remove|assign|clear|list]');
528
+ console.error('');
529
+ console.error(' (no args) List all repos');
530
+ console.error(' add <name> <path> Register a repo');
531
+ console.error(' remove <name> Remove a repo');
532
+ console.error(' assign <agent> <name> Set agent default repo');
533
+ console.error(' clear <agent> Clear agent default repo');
534
+ process.exit(1);
535
+ }
536
+ }
537
+ // ── Permissions management commands ──
538
+ function cmdPermissionsList() {
539
+ const raw = readRawConfig();
540
+ const agents = (raw.agents ?? {});
541
+ const entries = Object.entries(agents);
542
+ if (entries.length === 0) {
543
+ console.log('No agents configured.');
544
+ return;
545
+ }
546
+ for (const [name, agent] of entries) {
547
+ const defaults = (agent.defaults ?? {});
548
+ const mode = defaults.permissionMode ?? 'dangerously-skip';
549
+ console.log(`${name}: ${mode}`);
550
+ }
551
+ }
552
+ function cmdPermissionsSet(args) {
553
+ const agentName = args[0];
554
+ const mode = args[1];
555
+ if (!agentName || !mode) {
556
+ console.error('Usage: tgcc permissions set <agent> <mode>');
557
+ console.error('Modes: dangerously-skip, acceptEdits, default, plan');
558
+ process.exit(1);
559
+ }
560
+ const validModes = ['dangerously-skip', 'acceptEdits', 'default', 'plan'];
561
+ if (!validModes.includes(mode)) {
562
+ console.error(`Invalid mode: ${mode}`);
563
+ console.error(`Valid modes: ${validModes.join(', ')}`);
564
+ process.exit(1);
565
+ }
566
+ const raw = readRawConfig();
567
+ const agents = (raw.agents ?? {});
568
+ if (!agents[agentName]) {
569
+ console.error(`Agent "${agentName}" not found.`);
570
+ process.exit(1);
571
+ }
572
+ updateConfig((cfg) => {
573
+ const a = (cfg.agents ?? {});
574
+ const agentCfg = a[agentName];
575
+ if (agentCfg) {
576
+ const defaults = (agentCfg.defaults ?? {});
577
+ defaults.permissionMode = mode;
578
+ agentCfg.defaults = defaults;
579
+ }
580
+ });
581
+ console.log(`Permission mode for "${agentName}" set to "${mode}".`);
582
+ }
583
+ function cmdPermissions(args) {
584
+ const subcommand = args[0];
585
+ switch (subcommand) {
586
+ case 'set':
587
+ cmdPermissionsSet(args.slice(1));
588
+ break;
589
+ case undefined:
590
+ case 'list':
591
+ case 'ls':
592
+ cmdPermissionsList();
593
+ break;
594
+ default:
595
+ console.error('Usage: tgcc permissions [set <agent> <mode>]');
596
+ console.error('');
597
+ console.error(' (no args) Show permission mode for all agents');
598
+ console.error(' set <agent> <mode> Set agent default permissionMode');
599
+ console.error('');
600
+ console.error('Modes: dangerously-skip, acceptEdits, default, plan');
601
+ process.exit(1);
602
+ }
603
+ }
604
+ // ── Main ──
605
+ async function main() {
606
+ const args = process.argv.slice(2);
607
+ const command = args[0];
608
+ switch (command) {
609
+ case 'message':
610
+ case 'msg':
611
+ await cmdMessage(args.slice(1));
612
+ break;
613
+ case 'status':
614
+ await cmdStatus(args.slice(1));
615
+ break;
616
+ case 'agent':
617
+ cmdAgent(args.slice(1));
618
+ break;
619
+ case 'repo':
620
+ cmdRepo(args.slice(1));
621
+ break;
622
+ case 'permissions':
623
+ cmdPermissions(args.slice(1));
624
+ break;
625
+ case 'help':
626
+ case '--help':
627
+ case '-h':
628
+ printHelp();
629
+ break;
630
+ default:
631
+ if (!command) {
632
+ printHelp();
633
+ }
634
+ else {
635
+ console.error(`Unknown command: ${command}`);
636
+ printHelp();
637
+ process.exit(1);
638
+ }
639
+ }
640
+ }
641
+ function printHelp() {
642
+ console.log(`tgcc — Telegram ↔ Claude Code CLI
643
+
644
+ Usage:
645
+ tgcc message [--agent <name>] [--session <id>] "your message"
646
+ tgcc status [--agent <name>]
647
+ tgcc agent add|remove|rename|list|repo
648
+ tgcc repo [add|remove|assign|clear|list]
649
+ tgcc permissions [set <agent> <mode>]
650
+ tgcc help
651
+
652
+ Commands:
653
+ message Send a message to a running agent
654
+ status Show running agents and active sessions
655
+ agent Manage agent registrations
656
+ repo Manage repo registry
657
+ permissions View/set agent permission modes
658
+ help Show this help message
659
+
660
+ Options:
661
+ --agent Specify agent by name (auto-detected from cwd if omitted)
662
+ --session Resume a specific session by ID`);
663
+ }
664
+ main().catch((err) => {
665
+ console.error(err instanceof Error ? err.message : err);
666
+ process.exit(1);
667
+ });
668
+ //# sourceMappingURL=cli.js.map