@hexidecibel/companion 0.0.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.
Files changed (109) hide show
  1. package/dist/__tests__/task-parser.test.d.ts +2 -0
  2. package/dist/__tests__/task-parser.test.d.ts.map +1 -0
  3. package/dist/__tests__/task-parser.test.js +79 -0
  4. package/dist/__tests__/task-parser.test.js.map +1 -0
  5. package/dist/anthropic-usage.d.ts +5 -0
  6. package/dist/anthropic-usage.d.ts.map +1 -0
  7. package/dist/anthropic-usage.js +112 -0
  8. package/dist/anthropic-usage.js.map +1 -0
  9. package/dist/cert-generator.d.ts +15 -0
  10. package/dist/cert-generator.d.ts.map +1 -0
  11. package/dist/cert-generator.js +298 -0
  12. package/dist/cert-generator.js.map +1 -0
  13. package/dist/config.d.ts +4 -0
  14. package/dist/config.d.ts.map +1 -0
  15. package/dist/config.js +122 -0
  16. package/dist/config.js.map +1 -0
  17. package/dist/encryption.d.ts +28 -0
  18. package/dist/encryption.d.ts.map +1 -0
  19. package/dist/encryption.js +95 -0
  20. package/dist/encryption.js.map +1 -0
  21. package/dist/index.d.ts +3 -0
  22. package/dist/index.d.ts.map +1 -0
  23. package/dist/index.js +211 -0
  24. package/dist/index.js.map +1 -0
  25. package/dist/input-injector.d.ts +21 -0
  26. package/dist/input-injector.d.ts.map +1 -0
  27. package/dist/input-injector.js +126 -0
  28. package/dist/input-injector.js.map +1 -0
  29. package/dist/mdns.d.ts +11 -0
  30. package/dist/mdns.d.ts.map +1 -0
  31. package/dist/mdns.js +93 -0
  32. package/dist/mdns.js.map +1 -0
  33. package/dist/parser.d.ts +43 -0
  34. package/dist/parser.d.ts.map +1 -0
  35. package/dist/parser.js +800 -0
  36. package/dist/parser.js.map +1 -0
  37. package/dist/push.d.ts +38 -0
  38. package/dist/push.d.ts.map +1 -0
  39. package/dist/push.js +359 -0
  40. package/dist/push.js.map +1 -0
  41. package/dist/qr-server.d.ts +13 -0
  42. package/dist/qr-server.d.ts.map +1 -0
  43. package/dist/qr-server.js +421 -0
  44. package/dist/qr-server.js.map +1 -0
  45. package/dist/scaffold/generator.d.ts +11 -0
  46. package/dist/scaffold/generator.d.ts.map +1 -0
  47. package/dist/scaffold/generator.js +206 -0
  48. package/dist/scaffold/generator.js.map +1 -0
  49. package/dist/scaffold/templates/index.d.ts +5 -0
  50. package/dist/scaffold/templates/index.d.ts.map +1 -0
  51. package/dist/scaffold/templates/index.js +22 -0
  52. package/dist/scaffold/templates/index.js.map +1 -0
  53. package/dist/scaffold/templates/node-express.d.ts +3 -0
  54. package/dist/scaffold/templates/node-express.d.ts.map +1 -0
  55. package/dist/scaffold/templates/node-express.js +218 -0
  56. package/dist/scaffold/templates/node-express.js.map +1 -0
  57. package/dist/scaffold/templates/python-fastapi.d.ts +3 -0
  58. package/dist/scaffold/templates/python-fastapi.d.ts.map +1 -0
  59. package/dist/scaffold/templates/python-fastapi.js +302 -0
  60. package/dist/scaffold/templates/python-fastapi.js.map +1 -0
  61. package/dist/scaffold/templates/react-mui-website.d.ts +3 -0
  62. package/dist/scaffold/templates/react-mui-website.d.ts.map +1 -0
  63. package/dist/scaffold/templates/react-mui-website.js +405 -0
  64. package/dist/scaffold/templates/react-mui-website.js.map +1 -0
  65. package/dist/scaffold/templates/react-typescript.d.ts +3 -0
  66. package/dist/scaffold/templates/react-typescript.d.ts.map +1 -0
  67. package/dist/scaffold/templates/react-typescript.js +275 -0
  68. package/dist/scaffold/templates/react-typescript.js.map +1 -0
  69. package/dist/scaffold/types.d.ts +55 -0
  70. package/dist/scaffold/types.d.ts.map +1 -0
  71. package/dist/scaffold/types.js +3 -0
  72. package/dist/scaffold/types.js.map +1 -0
  73. package/dist/subagent-watcher.d.ts +24 -0
  74. package/dist/subagent-watcher.d.ts.map +1 -0
  75. package/dist/subagent-watcher.js +307 -0
  76. package/dist/subagent-watcher.js.map +1 -0
  77. package/dist/tls.d.ts +10 -0
  78. package/dist/tls.d.ts.map +1 -0
  79. package/dist/tls.js +77 -0
  80. package/dist/tls.js.map +1 -0
  81. package/dist/tmux-manager.d.ts +71 -0
  82. package/dist/tmux-manager.d.ts.map +1 -0
  83. package/dist/tmux-manager.js +243 -0
  84. package/dist/tmux-manager.js.map +1 -0
  85. package/dist/tool-config.d.ts +33 -0
  86. package/dist/tool-config.d.ts.map +1 -0
  87. package/dist/tool-config.js +211 -0
  88. package/dist/tool-config.js.map +1 -0
  89. package/dist/types.d.ts +218 -0
  90. package/dist/types.d.ts.map +1 -0
  91. package/dist/types.js +3 -0
  92. package/dist/types.js.map +1 -0
  93. package/dist/watcher.d.ts +63 -0
  94. package/dist/watcher.d.ts.map +1 -0
  95. package/dist/watcher.js +596 -0
  96. package/dist/watcher.js.map +1 -0
  97. package/dist/watcher.test.d.ts +2 -0
  98. package/dist/watcher.test.d.ts.map +1 -0
  99. package/dist/watcher.test.js +110 -0
  100. package/dist/watcher.test.js.map +1 -0
  101. package/dist/websocket.d.ts +62 -0
  102. package/dist/websocket.d.ts.map +1 -0
  103. package/dist/websocket.js +1695 -0
  104. package/dist/websocket.js.map +1 -0
  105. package/package.json +71 -0
  106. package/scripts/build.sh +23 -0
  107. package/scripts/install-remote.sh +18 -0
  108. package/scripts/install.sh +558 -0
  109. package/scripts/uninstall.sh +113 -0
package/dist/config.js ADDED
@@ -0,0 +1,122 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.loadConfig = loadConfig;
37
+ exports.saveConfig = saveConfig;
38
+ const fs = __importStar(require("fs"));
39
+ const path = __importStar(require("path"));
40
+ const HOME_DIR = process.env.HOME || '/root';
41
+ const CONFIG_DIR = path.join(HOME_DIR, '.companion');
42
+ // Safe tools that can be auto-approved without user confirmation
43
+ const DEFAULT_AUTO_APPROVE_TOOLS = [
44
+ 'Read',
45
+ 'Glob',
46
+ 'Grep',
47
+ 'WebFetch',
48
+ 'WebSearch',
49
+ ];
50
+ const DEFAULT_CONFIG = {
51
+ port: 9877,
52
+ token: '',
53
+ tls: false,
54
+ certPath: path.join(CONFIG_DIR, 'certs', 'cert.pem'),
55
+ keyPath: path.join(CONFIG_DIR, 'certs', 'key.pem'),
56
+ tmuxSession: 'main',
57
+ codeHome: path.join(HOME_DIR, '.claude'),
58
+ mdnsEnabled: true,
59
+ pushDelayMs: 60000, // 1 minute
60
+ autoApproveTools: DEFAULT_AUTO_APPROVE_TOOLS,
61
+ };
62
+ function loadConfig() {
63
+ const configPath = process.env.CONFIG_PATH || path.join(CONFIG_DIR, 'config.json');
64
+ let fileConfig = {};
65
+ if (fs.existsSync(configPath)) {
66
+ try {
67
+ const content = fs.readFileSync(configPath, 'utf-8');
68
+ const parsed = JSON.parse(content);
69
+ // Map snake_case from config file to camelCase
70
+ fileConfig = {
71
+ port: parsed.port,
72
+ token: parsed.token,
73
+ tls: parsed.tls,
74
+ certPath: parsed.cert_path,
75
+ keyPath: parsed.key_path,
76
+ tmuxSession: parsed.tmux_session,
77
+ codeHome: parsed.code_home || parsed.claude_home,
78
+ mdnsEnabled: parsed.mdns_enabled,
79
+ fcmCredentialsPath: parsed.fcm_credentials_path,
80
+ pushDelayMs: parsed.push_delay_ms,
81
+ autoApproveTools: parsed.auto_approve_tools,
82
+ anthropicAdminApiKey: parsed.anthropic_admin_api_key,
83
+ };
84
+ }
85
+ catch (err) {
86
+ console.error(`Error loading config from ${configPath}:`, err);
87
+ }
88
+ }
89
+ else {
90
+ console.warn(`Config file not found at ${configPath}, using defaults`);
91
+ }
92
+ // Merge with defaults
93
+ const config = {
94
+ ...DEFAULT_CONFIG,
95
+ ...Object.fromEntries(Object.entries(fileConfig).filter(([_, v]) => v !== undefined)),
96
+ };
97
+ // Validate required fields
98
+ if (!config.token) {
99
+ console.error('Error: No authentication token configured');
100
+ console.error('Please set a token in the config file');
101
+ process.exit(1);
102
+ }
103
+ return config;
104
+ }
105
+ function saveConfig(config) {
106
+ const configPath = process.env.CONFIG_PATH || path.join(CONFIG_DIR, 'config.json');
107
+ // Convert to snake_case for file
108
+ const fileConfig = {
109
+ port: config.port,
110
+ token: config.token,
111
+ tls: config.tls,
112
+ cert_path: config.certPath,
113
+ key_path: config.keyPath,
114
+ tmux_session: config.tmuxSession,
115
+ code_home: config.codeHome,
116
+ mdns_enabled: config.mdnsEnabled,
117
+ fcm_credentials_path: config.fcmCredentialsPath,
118
+ push_delay_ms: config.pushDelayMs,
119
+ };
120
+ fs.writeFileSync(configPath, JSON.stringify(fileConfig, null, 2));
121
+ }
122
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ export interface KeyPair {
2
+ publicKey: string;
3
+ secretKey: string;
4
+ }
5
+ export interface EncryptedPayload {
6
+ encrypted: true;
7
+ ciphertext: string;
8
+ nonce: string;
9
+ }
10
+ export interface DecryptedPayload {
11
+ encrypted: false;
12
+ data: unknown;
13
+ }
14
+ export type MessagePayload = EncryptedPayload | DecryptedPayload | unknown;
15
+ export declare class EncryptionService {
16
+ private keyPair;
17
+ private clientPublicKeys;
18
+ constructor();
19
+ getPublicKey(): string;
20
+ setClientPublicKey(clientId: string, publicKeyBase64: string): void;
21
+ removeClientPublicKey(clientId: string): void;
22
+ hasClientPublicKey(clientId: string): boolean;
23
+ encrypt(clientId: string, data: unknown): EncryptedPayload | null;
24
+ decrypt(clientId: string, payload: EncryptedPayload): unknown | null;
25
+ isEncryptedPayload(payload: unknown): payload is EncryptedPayload;
26
+ }
27
+ export declare const encryptionService: EncryptionService;
28
+ //# sourceMappingURL=encryption.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"encryption.d.ts","sourceRoot":"","sources":["../src/encryption.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,OAAO;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,IAAI,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,KAAK,CAAC;IACjB,IAAI,EAAE,OAAO,CAAC;CACf;AAED,MAAM,MAAM,cAAc,GAAG,gBAAgB,GAAG,gBAAgB,GAAG,OAAO,CAAC;AAE3E,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,OAAO,CAAkB;IACjC,OAAO,CAAC,gBAAgB,CAAsC;;IAQ9D,YAAY,IAAI,MAAM;IAItB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,GAAG,IAAI;IAcnE,qBAAqB,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAI7C,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO;IAI7C,OAAO,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,gBAAgB,GAAG,IAAI;IAwBjE,OAAO,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,gBAAgB,GAAG,OAAO,GAAG,IAAI;IA0BpE,kBAAkB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,IAAI,gBAAgB;CAUlE;AAGD,eAAO,MAAM,iBAAiB,mBAA0B,CAAC"}
@@ -0,0 +1,95 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.encryptionService = exports.EncryptionService = void 0;
7
+ const tweetnacl_1 = __importDefault(require("tweetnacl"));
8
+ const tweetnacl_util_1 = require("tweetnacl-util");
9
+ class EncryptionService {
10
+ keyPair;
11
+ clientPublicKeys = new Map();
12
+ constructor() {
13
+ // Generate server key pair on startup
14
+ this.keyPair = tweetnacl_1.default.box.keyPair();
15
+ console.log('Encryption: Key pair generated');
16
+ }
17
+ getPublicKey() {
18
+ return (0, tweetnacl_util_1.encodeBase64)(this.keyPair.publicKey);
19
+ }
20
+ setClientPublicKey(clientId, publicKeyBase64) {
21
+ try {
22
+ const publicKey = (0, tweetnacl_util_1.decodeBase64)(publicKeyBase64);
23
+ if (publicKey.length !== tweetnacl_1.default.box.publicKeyLength) {
24
+ throw new Error('Invalid public key length');
25
+ }
26
+ this.clientPublicKeys.set(clientId, publicKey);
27
+ console.log(`Encryption: Stored public key for client ${clientId}`);
28
+ }
29
+ catch (err) {
30
+ console.error(`Encryption: Failed to store public key for ${clientId}:`, err);
31
+ throw err;
32
+ }
33
+ }
34
+ removeClientPublicKey(clientId) {
35
+ this.clientPublicKeys.delete(clientId);
36
+ }
37
+ hasClientPublicKey(clientId) {
38
+ return this.clientPublicKeys.has(clientId);
39
+ }
40
+ encrypt(clientId, data) {
41
+ const clientPublicKey = this.clientPublicKeys.get(clientId);
42
+ if (!clientPublicKey) {
43
+ console.warn(`Encryption: No public key for client ${clientId}`);
44
+ return null;
45
+ }
46
+ try {
47
+ const message = (0, tweetnacl_util_1.encodeUTF8)(JSON.stringify(data));
48
+ const nonce = tweetnacl_1.default.randomBytes(tweetnacl_1.default.box.nonceLength);
49
+ const ciphertext = tweetnacl_1.default.box(message, nonce, clientPublicKey, this.keyPair.secretKey);
50
+ return {
51
+ encrypted: true,
52
+ ciphertext: (0, tweetnacl_util_1.encodeBase64)(ciphertext),
53
+ nonce: (0, tweetnacl_util_1.encodeBase64)(nonce),
54
+ };
55
+ }
56
+ catch (err) {
57
+ console.error('Encryption: Failed to encrypt:', err);
58
+ return null;
59
+ }
60
+ }
61
+ decrypt(clientId, payload) {
62
+ const clientPublicKey = this.clientPublicKeys.get(clientId);
63
+ if (!clientPublicKey) {
64
+ console.warn(`Encryption: No public key for client ${clientId}`);
65
+ return null;
66
+ }
67
+ try {
68
+ const ciphertext = (0, tweetnacl_util_1.decodeBase64)(payload.ciphertext);
69
+ const nonce = (0, tweetnacl_util_1.decodeBase64)(payload.nonce);
70
+ const decrypted = tweetnacl_1.default.box.open(ciphertext, nonce, clientPublicKey, this.keyPair.secretKey);
71
+ if (!decrypted) {
72
+ console.error('Encryption: Decryption failed (authentication failed)');
73
+ return null;
74
+ }
75
+ const json = (0, tweetnacl_util_1.decodeUTF8)(decrypted);
76
+ return JSON.parse(json);
77
+ }
78
+ catch (err) {
79
+ console.error('Encryption: Failed to decrypt:', err);
80
+ return null;
81
+ }
82
+ }
83
+ isEncryptedPayload(payload) {
84
+ return (typeof payload === 'object' &&
85
+ payload !== null &&
86
+ 'encrypted' in payload &&
87
+ payload.encrypted === true &&
88
+ 'ciphertext' in payload &&
89
+ 'nonce' in payload);
90
+ }
91
+ }
92
+ exports.EncryptionService = EncryptionService;
93
+ // Export singleton instance
94
+ exports.encryptionService = new EncryptionService();
95
+ //# sourceMappingURL=encryption.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"encryption.js","sourceRoot":"","sources":["../src/encryption.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
package/dist/index.js ADDED
@@ -0,0 +1,211 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ const config_1 = require("./config");
5
+ const watcher_1 = require("./watcher");
6
+ const subagent_watcher_1 = require("./subagent-watcher");
7
+ const input_injector_1 = require("./input-injector");
8
+ const mdns_1 = require("./mdns");
9
+ const push_1 = require("./push");
10
+ const websocket_1 = require("./websocket");
11
+ const tmux_manager_1 = require("./tmux-manager");
12
+ const tls_1 = require("./tls");
13
+ const cert_generator_1 = require("./cert-generator");
14
+ const qr_server_1 = require("./qr-server");
15
+ async function main() {
16
+ console.log('Companion Daemon v0.0.1');
17
+ console.log('==============================');
18
+ // Load configuration
19
+ const config = (0, config_1.loadConfig)();
20
+ console.log(`Config: Port ${config.port}, TLS: ${config.tls}, mDNS: ${config.mdnsEnabled}`);
21
+ // Auto-generate TLS certificates if enabled and missing
22
+ if (config.tls) {
23
+ const certPath = config.certPath || (0, cert_generator_1.getDefaultCertPaths)().certPath;
24
+ const keyPath = config.keyPath || (0, cert_generator_1.getDefaultCertPaths)().keyPath;
25
+ if (!(0, cert_generator_1.certsExist)(certPath, keyPath)) {
26
+ console.log('TLS certificates not found, generating self-signed certificates...');
27
+ try {
28
+ const paths = (0, cert_generator_1.generateAndSaveCerts)(certPath, keyPath);
29
+ config.certPath = paths.certPath;
30
+ config.keyPath = paths.keyPath;
31
+ console.log('Self-signed certificates generated successfully');
32
+ console.log('Note: Clients may need to accept the self-signed certificate');
33
+ }
34
+ catch (err) {
35
+ console.error('Failed to generate TLS certificates:', err);
36
+ console.error('Falling back to non-TLS mode');
37
+ config.tls = false;
38
+ }
39
+ }
40
+ // Validate TLS config
41
+ if (config.tls) {
42
+ const tlsErrors = (0, tls_1.validateTlsConfig)({
43
+ enabled: config.tls,
44
+ certPath: config.certPath,
45
+ keyPath: config.keyPath,
46
+ });
47
+ if (tlsErrors.length > 0) {
48
+ console.error('TLS configuration errors:');
49
+ tlsErrors.forEach((e) => console.error(` - ${e}`));
50
+ process.exit(1);
51
+ }
52
+ }
53
+ }
54
+ // Initialize components
55
+ const watcher = new watcher_1.SessionWatcher(config.codeHome);
56
+ const subAgentWatcher = new subagent_watcher_1.SubAgentWatcher(config.codeHome);
57
+ const injector = new input_injector_1.InputInjector(config.tmuxSession);
58
+ const push = new push_1.PushNotificationService(config.fcmCredentialsPath, config.pushDelayMs);
59
+ // Create HTTP/HTTPS server with QR code endpoint
60
+ const qrHandler = (0, qr_server_1.createQRRequestHandler)(config);
61
+ const server = (0, tls_1.createServer)({
62
+ enabled: config.tls,
63
+ certPath: config.certPath,
64
+ keyPath: config.keyPath,
65
+ }, qrHandler);
66
+ // Initialize WebSocket handler
67
+ const wsHandler = new websocket_1.WebSocketHandler(server, config, watcher, injector, push, undefined, subAgentWatcher);
68
+ // Start mDNS advertisement
69
+ let mdns = null;
70
+ if (config.mdnsEnabled) {
71
+ mdns = new mdns_1.MdnsAdvertiser(config.port, config.tls);
72
+ mdns.start();
73
+ }
74
+ // Start file watchers
75
+ watcher.start();
76
+ subAgentWatcher.start();
77
+ // Auto-approve safe tools (from config and/or client toggle)
78
+ {
79
+ console.log(`Auto-approve tools from config: ${config.autoApproveTools.length > 0 ? config.autoApproveTools.join(', ') : '(none - client toggle only)'}`);
80
+ const tmux = new tmux_manager_1.TmuxManager('companion');
81
+ // Track in-flight approvals using composite key (sessionId:tools) to prevent double-firing
82
+ const pendingAutoApprovals = new Map();
83
+ watcher.on('pending-approval', async ({ sessionId, projectPath, tools }) => {
84
+ // Skip if auto-approve is not enabled (neither config nor client toggle)
85
+ if (config.autoApproveTools.length === 0 && !wsHandler.autoApproveEnabled) {
86
+ console.log(`[AUTO-APPROVE] Skipped: auto-approve not enabled (config tools: ${config.autoApproveTools.length}, client toggle: ${wsHandler.autoApproveEnabled})`);
87
+ return;
88
+ }
89
+ // Check if any pending tool should be auto-approved
90
+ const autoApprovable = tools.filter((tool) => {
91
+ if (config.autoApproveTools.includes(tool))
92
+ return true;
93
+ if (wsHandler.autoApproveEnabled)
94
+ return true;
95
+ return false;
96
+ });
97
+ if (autoApprovable.length === 0) {
98
+ console.log(`[AUTO-APPROVE] No auto-approvable tools in: [${tools.join(', ')}]`);
99
+ return;
100
+ }
101
+ // Composite dedup key: session + sorted tool names
102
+ // The watcher already deduplicates emissions (only fires on change),
103
+ // but this provides a safety net against rapid re-fires.
104
+ const dedupKey = `${sessionId}:${autoApprovable.sort().join(',')}`;
105
+ const now = Date.now();
106
+ const lastApproval = pendingAutoApprovals.get(dedupKey);
107
+ if (lastApproval && now - lastApproval < 15000) {
108
+ console.log(`[AUTO-APPROVE] Dedup: skipping (last approval ${now - lastApproval}ms ago for ${dedupKey})`);
109
+ return;
110
+ }
111
+ pendingAutoApprovals.set(dedupKey, now);
112
+ // Clean up old entries
113
+ for (const [key, ts] of pendingAutoApprovals) {
114
+ if (now - ts > 30000)
115
+ pendingAutoApprovals.delete(key);
116
+ }
117
+ try {
118
+ // Find the tmux session that matches this conversation's project path
119
+ let targetTmuxSession;
120
+ if (projectPath) {
121
+ const tmuxSessions = await tmux.listSessions();
122
+ // Try exact match first
123
+ const exactMatch = tmuxSessions.find(ts => ts.workingDir === projectPath);
124
+ if (exactMatch) {
125
+ targetTmuxSession = exactMatch.name;
126
+ }
127
+ else {
128
+ // Try normalized path match (trailing slash differences, symlinks)
129
+ const normalizedPath = projectPath.replace(/\/+$/, '');
130
+ const fuzzyMatch = tmuxSessions.find(ts => ts.workingDir?.replace(/\/+$/, '') === normalizedPath);
131
+ if (fuzzyMatch) {
132
+ targetTmuxSession = fuzzyMatch.name;
133
+ console.log(`[AUTO-APPROVE] Fuzzy path match: "${fuzzyMatch.name}" for ${projectPath}`);
134
+ }
135
+ }
136
+ }
137
+ // Wait for terminal to settle before sending approval
138
+ await new Promise(resolve => setTimeout(resolve, 300));
139
+ const sendApproval = async (target) => {
140
+ try {
141
+ await injector.sendInput('yes', target);
142
+ return true;
143
+ }
144
+ catch (err) {
145
+ console.log(`[AUTO-APPROVE] Send failed: ${err}`);
146
+ return false;
147
+ }
148
+ };
149
+ if (targetTmuxSession) {
150
+ console.log(`[AUTO-APPROVE] Sending to tmux="${targetTmuxSession}" for tools [${autoApprovable.join(', ')}] (session: ${sessionId})`);
151
+ const success = await sendApproval(targetTmuxSession);
152
+ if (!success) {
153
+ // Retry once after 500ms
154
+ console.log(`[AUTO-APPROVE] Retrying after 500ms...`);
155
+ await new Promise(resolve => setTimeout(resolve, 500));
156
+ await sendApproval(targetTmuxSession);
157
+ }
158
+ }
159
+ else {
160
+ console.log(`[AUTO-APPROVE] Sending to active session for tools [${autoApprovable.join(', ')}] (no tmux match for ${projectPath})`);
161
+ const success = await sendApproval();
162
+ if (!success) {
163
+ console.log(`[AUTO-APPROVE] Retrying after 500ms...`);
164
+ await new Promise(resolve => setTimeout(resolve, 500));
165
+ await sendApproval();
166
+ }
167
+ }
168
+ }
169
+ catch (err) {
170
+ console.error(`[AUTO-APPROVE] Error: ${err}`);
171
+ }
172
+ });
173
+ }
174
+ // Start HTTP server
175
+ server.listen(config.port, () => {
176
+ console.log(`Server listening on port ${config.port}`);
177
+ console.log(`WebSocket endpoint: ws${config.tls ? 's' : ''}://localhost:${config.port}`);
178
+ console.log(`QR code setup: http${config.tls ? 's' : ''}://localhost:${config.port}/qr`);
179
+ });
180
+ // Graceful shutdown
181
+ const shutdown = async () => {
182
+ console.log('\nShutting down...');
183
+ watcher.stop();
184
+ subAgentWatcher.stop();
185
+ if (mdns)
186
+ mdns.stop();
187
+ server.close(() => {
188
+ console.log('Server closed');
189
+ process.exit(0);
190
+ });
191
+ // Force exit after 5 seconds
192
+ setTimeout(() => {
193
+ console.error('Forced shutdown after timeout');
194
+ process.exit(1);
195
+ }, 5000);
196
+ };
197
+ process.on('SIGINT', shutdown);
198
+ process.on('SIGTERM', shutdown);
199
+ // Log status periodically
200
+ setInterval(() => {
201
+ const status = watcher.getStatus();
202
+ console.log(`Status: ${wsHandler.getAuthenticatedClientCount()} clients, ` +
203
+ `waiting: ${status.isWaitingForInput}, ` +
204
+ `push devices: ${push.getRegisteredDeviceCount()}`);
205
+ }, 60000);
206
+ }
207
+ main().catch((err) => {
208
+ console.error('Fatal error:', err);
209
+ process.exit(1);
210
+ });
211
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AACA,qCAAsC;AACtC,uCAA2C;AAC3C,yDAAqD;AACrD,qDAAiD;AACjD,iCAAwC;AACxC,iCAAiD;AACjD,2CAA+C;AAC/C,iDAA6C;AAC7C,+BAAwD;AACxD,qDAAyF;AACzF,2CAAqD;AAErD,KAAK,UAAU,IAAI;IACjB,OAAO,CAAC,GAAG,CAAC,yBAAyB,CAAC,CAAC;IACvC,OAAO,CAAC,GAAG,CAAC,gCAAgC,CAAC,CAAC;IAE9C,qBAAqB;IACrB,MAAM,MAAM,GAAG,IAAA,mBAAU,GAAE,CAAC;IAC5B,OAAO,CAAC,GAAG,CAAC,gBAAgB,MAAM,CAAC,IAAI,UAAU,MAAM,CAAC,GAAG,WAAW,MAAM,CAAC,WAAW,EAAE,CAAC,CAAC;IAE5F,wDAAwD;IACxD,IAAI,MAAM,CAAC,GAAG,EAAE,CAAC;QACf,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,IAAI,IAAA,oCAAmB,GAAE,CAAC,QAAQ,CAAC;QACnE,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,IAAI,IAAA,oCAAmB,GAAE,CAAC,OAAO,CAAC;QAEhE,IAAI,CAAC,IAAA,2BAAU,EAAC,QAAQ,EAAE,OAAO,CAAC,EAAE,CAAC;YACnC,OAAO,CAAC,GAAG,CAAC,oEAAoE,CAAC,CAAC;YAClF,IAAI,CAAC;gBACH,MAAM,KAAK,GAAG,IAAA,qCAAoB,EAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;gBACtD,MAAM,CAAC,QAAQ,GAAG,KAAK,CAAC,QAAQ,CAAC;gBACjC,MAAM,CAAC,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC;gBAC/B,OAAO,CAAC,GAAG,CAAC,iDAAiD,CAAC,CAAC;gBAC/D,OAAO,CAAC,GAAG,CAAC,8DAA8D,CAAC,CAAC;YAC9E,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,OAAO,CAAC,KAAK,CAAC,sCAAsC,EAAE,GAAG,CAAC,CAAC;gBAC3D,OAAO,CAAC,KAAK,CAAC,8BAA8B,CAAC,CAAC;gBAC9C,MAAM,CAAC,GAAG,GAAG,KAAK,CAAC;YACrB,CAAC;QACH,CAAC;QAED,sBAAsB;QACtB,IAAI,MAAM,CAAC,GAAG,EAAE,CAAC;YACf,MAAM,SAAS,GAAG,IAAA,uBAAiB,EAAC;gBAClC,OAAO,EAAE,MAAM,CAAC,GAAG;gBACnB,QAAQ,EAAE,MAAM,CAAC,QAAQ;gBACzB,OAAO,EAAE,MAAM,CAAC,OAAO;aACxB,CAAC,CAAC;YACH,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACzB,OAAO,CAAC,KAAK,CAAC,2BAA2B,CAAC,CAAC;gBAC3C,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC;gBACpD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAClB,CAAC;QACH,CAAC;IACH,CAAC;IAED,wBAAwB;IACxB,MAAM,OAAO,GAAG,IAAI,wBAAc,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IACpD,MAAM,eAAe,GAAG,IAAI,kCAAe,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IAC7D,MAAM,QAAQ,GAAG,IAAI,8BAAa,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;IACvD,MAAM,IAAI,GAAG,IAAI,8BAAuB,CAAC,MAAM,CAAC,kBAAkB,EAAE,MAAM,CAAC,WAAW,CAAC,CAAC;IAExF,iDAAiD;IACjD,MAAM,SAAS,GAAG,IAAA,kCAAsB,EAAC,MAAM,CAAC,CAAC;IACjD,MAAM,MAAM,GAAG,IAAA,kBAAY,EACzB;QACE,OAAO,EAAE,MAAM,CAAC,GAAG;QACnB,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,OAAO,EAAE,MAAM,CAAC,OAAO;KACxB,EACD,SAAS,CACV,CAAC;IAEF,+BAA+B;IAC/B,MAAM,SAAS,GAAG,IAAI,4BAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE,eAAe,CAAC,CAAC;IAE5G,2BAA2B;IAC3B,IAAI,IAAI,GAA0B,IAAI,CAAC;IACvC,IAAI,MAAM,CAAC,WAAW,EAAE,CAAC;QACvB,IAAI,GAAG,IAAI,qBAAc,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC;QACnD,IAAI,CAAC,KAAK,EAAE,CAAC;IACf,CAAC;IAED,sBAAsB;IACtB,OAAO,CAAC,KAAK,EAAE,CAAC;IAChB,eAAe,CAAC,KAAK,EAAE,CAAC;IAExB,6DAA6D;IAC7D,CAAC;QACC,OAAO,CAAC,GAAG,CAAC,mCAAmC,MAAM,CAAC,gBAAgB,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,6BAA6B,EAAE,CAAC,CAAC;QAC1J,MAAM,IAAI,GAAG,IAAI,0BAAW,CAAC,WAAW,CAAC,CAAC;QAC1C,2FAA2F;QAC3F,MAAM,oBAAoB,GAAG,IAAI,GAAG,EAAkB,CAAC;QAEvD,OAAO,CAAC,EAAE,CAAC,kBAAkB,EAAE,KAAK,EAAE,EAAE,SAAS,EAAE,WAAW,EAAE,KAAK,EAAE,EAAE,EAAE;YACzE,yEAAyE;YACzE,IAAI,MAAM,CAAC,gBAAgB,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,kBAAkB,EAAE,CAAC;gBAC1E,OAAO,CAAC,GAAG,CAAC,mEAAmE,MAAM,CAAC,gBAAgB,CAAC,MAAM,oBAAoB,SAAS,CAAC,kBAAkB,GAAG,CAAC,CAAC;gBAClK,OAAO;YACT,CAAC;YAED,oDAAoD;YACpD,MAAM,cAAc,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,IAAY,EAAE,EAAE;gBACnD,IAAI,MAAM,CAAC,gBAAgB,CAAC,QAAQ,CAAC,IAAI,CAAC;oBAAE,OAAO,IAAI,CAAC;gBACxD,IAAI,SAAS,CAAC,kBAAkB;oBAAE,OAAO,IAAI,CAAC;gBAC9C,OAAO,KAAK,CAAC;YACf,CAAC,CAAC,CAAC;YAEH,IAAI,cAAc,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBAChC,OAAO,CAAC,GAAG,CAAC,gDAAgD,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;gBACjF,OAAO;YACT,CAAC;YAED,mDAAmD;YACnD,qEAAqE;YACrE,yDAAyD;YACzD,MAAM,QAAQ,GAAG,GAAG,SAAS,IAAI,cAAc,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;YACnE,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YACvB,MAAM,YAAY,GAAG,oBAAoB,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;YACxD,IAAI,YAAY,IAAI,GAAG,GAAG,YAAY,GAAG,KAAK,EAAE,CAAC;gBAC/C,OAAO,CAAC,GAAG,CAAC,iDAAiD,GAAG,GAAG,YAAY,cAAc,QAAQ,GAAG,CAAC,CAAC;gBAC1G,OAAO;YACT,CAAC;YACD,oBAAoB,CAAC,GAAG,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;YAExC,uBAAuB;YACvB,KAAK,MAAM,CAAC,GAAG,EAAE,EAAE,CAAC,IAAI,oBAAoB,EAAE,CAAC;gBAC7C,IAAI,GAAG,GAAG,EAAE,GAAG,KAAK;oBAAE,oBAAoB,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACzD,CAAC;YAED,IAAI,CAAC;gBACH,sEAAsE;gBACtE,IAAI,iBAAqC,CAAC;gBAC1C,IAAI,WAAW,EAAE,CAAC;oBAChB,MAAM,YAAY,GAAG,MAAM,IAAI,CAAC,YAAY,EAAE,CAAC;oBAC/C,wBAAwB;oBACxB,MAAM,UAAU,GAAG,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,UAAU,KAAK,WAAW,CAAC,CAAC;oBAC1E,IAAI,UAAU,EAAE,CAAC;wBACf,iBAAiB,GAAG,UAAU,CAAC,IAAI,CAAC;oBACtC,CAAC;yBAAM,CAAC;wBACN,mEAAmE;wBACnE,MAAM,cAAc,GAAG,WAAW,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;wBACvD,MAAM,UAAU,GAAG,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CACxC,EAAE,CAAC,UAAU,EAAE,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,KAAK,cAAc,CACtD,CAAC;wBACF,IAAI,UAAU,EAAE,CAAC;4BACf,iBAAiB,GAAG,UAAU,CAAC,IAAI,CAAC;4BACpC,OAAO,CAAC,GAAG,CAAC,qCAAqC,UAAU,CAAC,IAAI,SAAS,WAAW,EAAE,CAAC,CAAC;wBAC1F,CAAC;oBACH,CAAC;gBACH,CAAC;gBAED,sDAAsD;gBACtD,MAAM,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,CAAC;gBAEvD,MAAM,YAAY,GAAG,KAAK,EAAE,MAAe,EAAoB,EAAE;oBAC/D,IAAI,CAAC;wBACH,MAAM,QAAQ,CAAC,SAAS,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;wBACxC,OAAO,IAAI,CAAC;oBACd,CAAC;oBAAC,OAAO,GAAG,EAAE,CAAC;wBACb,OAAO,CAAC,GAAG,CAAC,+BAA+B,GAAG,EAAE,CAAC,CAAC;wBAClD,OAAO,KAAK,CAAC;oBACf,CAAC;gBACH,CAAC,CAAC;gBAEF,IAAI,iBAAiB,EAAE,CAAC;oBACtB,OAAO,CAAC,GAAG,CAAC,mCAAmC,iBAAiB,gBAAgB,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,eAAe,SAAS,GAAG,CAAC,CAAC;oBACtI,MAAM,OAAO,GAAG,MAAM,YAAY,CAAC,iBAAiB,CAAC,CAAC;oBACtD,IAAI,CAAC,OAAO,EAAE,CAAC;wBACb,yBAAyB;wBACzB,OAAO,CAAC,GAAG,CAAC,wCAAwC,CAAC,CAAC;wBACtD,MAAM,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,CAAC;wBACvD,MAAM,YAAY,CAAC,iBAAiB,CAAC,CAAC;oBACxC,CAAC;gBACH,CAAC;qBAAM,CAAC;oBACN,OAAO,CAAC,GAAG,CAAC,uDAAuD,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,wBAAwB,WAAW,GAAG,CAAC,CAAC;oBACpI,MAAM,OAAO,GAAG,MAAM,YAAY,EAAE,CAAC;oBACrC,IAAI,CAAC,OAAO,EAAE,CAAC;wBACb,OAAO,CAAC,GAAG,CAAC,wCAAwC,CAAC,CAAC;wBACtD,MAAM,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,CAAC;wBACvD,MAAM,YAAY,EAAE,CAAC;oBACvB,CAAC;gBACH,CAAC;YACH,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,OAAO,CAAC,KAAK,CAAC,yBAAyB,GAAG,EAAE,CAAC,CAAC;YAChD,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC;IAED,oBAAoB;IACpB,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,GAAG,EAAE;QAC9B,OAAO,CAAC,GAAG,CAAC,4BAA4B,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC;QACvD,OAAO,CAAC,GAAG,CAAC,yBAAyB,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,gBAAgB,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC;QACzF,OAAO,CAAC,GAAG,CAAC,sBAAsB,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,gBAAgB,MAAM,CAAC,IAAI,KAAK,CAAC,CAAC;IAC3F,CAAC,CAAC,CAAC;IAEH,oBAAoB;IACpB,MAAM,QAAQ,GAAG,KAAK,IAAmB,EAAE;QACzC,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAC;QAElC,OAAO,CAAC,IAAI,EAAE,CAAC;QACf,eAAe,CAAC,IAAI,EAAE,CAAC;QACvB,IAAI,IAAI;YAAE,IAAI,CAAC,IAAI,EAAE,CAAC;QAEtB,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE;YAChB,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;YAC7B,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC,CAAC,CAAC;QAEH,6BAA6B;QAC7B,UAAU,CAAC,GAAG,EAAE;YACd,OAAO,CAAC,KAAK,CAAC,+BAA+B,CAAC,CAAC;YAC/C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC,EAAE,IAAI,CAAC,CAAC;IACX,CAAC,CAAC;IAEF,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;IAC/B,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;IAEhC,0BAA0B;IAC1B,WAAW,CAAC,GAAG,EAAE;QACf,MAAM,MAAM,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC;QACnC,OAAO,CAAC,GAAG,CACT,WAAW,SAAS,CAAC,2BAA2B,EAAE,YAAY;YAC5D,YAAY,MAAM,CAAC,iBAAiB,IAAI;YACxC,iBAAiB,IAAI,CAAC,wBAAwB,EAAE,EAAE,CACrD,CAAC;IACJ,CAAC,EAAE,KAAK,CAAC,CAAC;AACZ,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IACnB,OAAO,CAAC,KAAK,CAAC,cAAc,EAAE,GAAG,CAAC,CAAC;IACnC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
@@ -0,0 +1,21 @@
1
+ export declare class InputInjector {
2
+ private defaultSession;
3
+ private activeSession;
4
+ private sendLock;
5
+ constructor(tmuxSession: string);
6
+ /**
7
+ * Send input to the active session (or a specific session if provided)
8
+ * Uses a lock to prevent concurrent sends from interleaving
9
+ */
10
+ sendInput(input: string, targetSession?: string): Promise<boolean>;
11
+ private doSendInput;
12
+ private escapeTmuxInput;
13
+ checkSessionExists(sessionName?: string): Promise<boolean>;
14
+ listSessions(): Promise<string[]>;
15
+ setActiveSession(sessionName: string): void;
16
+ getActiveSession(): string;
17
+ getDefaultSession(): string;
18
+ setSession(sessionName: string): void;
19
+ getSession(): string;
20
+ }
21
+ //# sourceMappingURL=input-injector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"input-injector.d.ts","sourceRoot":"","sources":["../src/input-injector.ts"],"names":[],"mappings":"AAEA,qBAAa,aAAa;IACxB,OAAO,CAAC,cAAc,CAAS;IAC/B,OAAO,CAAC,aAAa,CAAS;IAC9B,OAAO,CAAC,QAAQ,CAAoC;gBAExC,WAAW,EAAE,MAAM;IAK/B;;;OAGG;IACG,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,aAAa,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;YA4B1D,WAAW;IAoCzB,OAAO,CAAC,eAAe;IAWjB,kBAAkB,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAS1D,YAAY,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;IAqBvC,gBAAgB,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI;IAI3C,gBAAgB,IAAI,MAAM;IAI1B,iBAAiB,IAAI,MAAM;IAK3B,UAAU,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI;IAKrC,UAAU,IAAI,MAAM;CAGrB"}
@@ -0,0 +1,126 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.InputInjector = void 0;
4
+ const child_process_1 = require("child_process");
5
+ class InputInjector {
6
+ defaultSession;
7
+ activeSession;
8
+ sendLock = Promise.resolve();
9
+ constructor(tmuxSession) {
10
+ this.defaultSession = tmuxSession;
11
+ this.activeSession = tmuxSession;
12
+ }
13
+ /**
14
+ * Send input to the active session (or a specific session if provided)
15
+ * Uses a lock to prevent concurrent sends from interleaving
16
+ */
17
+ async sendInput(input, targetSession) {
18
+ // Wait for any pending send to complete before starting this one
19
+ const previousLock = this.sendLock;
20
+ let releaseLock;
21
+ this.sendLock = new Promise(resolve => {
22
+ releaseLock = resolve;
23
+ });
24
+ try {
25
+ await previousLock;
26
+ const session = targetSession || this.activeSession;
27
+ const { spawnSync } = require('child_process');
28
+ // First, check if the tmux session exists
29
+ const checkResult = spawnSync('tmux', ['has-session', '-t', session], { timeout: 5000 });
30
+ if (checkResult.status !== 0) {
31
+ console.error(`Tmux session '${session}' not found`);
32
+ return false;
33
+ }
34
+ // Session exists, send the input
35
+ return await this.doSendInput(input, session);
36
+ }
37
+ finally {
38
+ releaseLock();
39
+ }
40
+ }
41
+ async doSendInput(input, session) {
42
+ try {
43
+ console.log(`Sending input to tmux session '${session}': ${input.substring(0, 80)}...`);
44
+ const { spawnSync } = require('child_process');
45
+ // Send the text using spawnSync (avoids shell interpretation)
46
+ const textResult = spawnSync('tmux', ['send-keys', '-t', session, '-l', '--', input], { timeout: 5000 });
47
+ if (textResult.status !== 0) {
48
+ console.error('Failed to send text:', textResult.stderr?.toString());
49
+ return false;
50
+ }
51
+ console.log('Text sent to tmux');
52
+ // Wait for tmux to process the text before sending Enter
53
+ await new Promise(resolve => setTimeout(resolve, 150));
54
+ // Send Enter
55
+ const enterResult = spawnSync('tmux', ['send-keys', '-t', session, 'Enter'], { timeout: 5000 });
56
+ if (enterResult.status !== 0) {
57
+ console.error('Failed to send Enter:', enterResult.stderr?.toString());
58
+ return false;
59
+ }
60
+ console.log('Enter sent to tmux');
61
+ // Small delay after Enter to ensure tmux processes it before next message
62
+ await new Promise(resolve => setTimeout(resolve, 50));
63
+ console.log(`Input sent successfully to tmux session '${session}'`);
64
+ return true;
65
+ }
66
+ catch (err) {
67
+ console.error('Error sending input to tmux:', err);
68
+ return false;
69
+ }
70
+ }
71
+ escapeTmuxInput(input) {
72
+ // Escape special characters that tmux interprets
73
+ // Replace backslashes first, then other special chars
74
+ return input
75
+ .replace(/\\/g, '\\\\')
76
+ .replace(/"/g, '\\"')
77
+ .replace(/'/g, "\\'")
78
+ .replace(/\$/g, '\\$')
79
+ .replace(/`/g, '\\`');
80
+ }
81
+ async checkSessionExists(sessionName) {
82
+ const session = sessionName || this.activeSession;
83
+ return new Promise((resolve) => {
84
+ const check = (0, child_process_1.spawn)('tmux', ['has-session', '-t', session]);
85
+ check.on('close', (code) => resolve(code === 0));
86
+ check.on('error', () => resolve(false));
87
+ });
88
+ }
89
+ async listSessions() {
90
+ return new Promise((resolve) => {
91
+ const list = (0, child_process_1.spawn)('tmux', ['list-sessions', '-F', '#{session_name}']);
92
+ let output = '';
93
+ list.stdout.on('data', (data) => {
94
+ output += data.toString();
95
+ });
96
+ list.on('close', (code) => {
97
+ if (code === 0) {
98
+ resolve(output.trim().split('\n').filter(Boolean));
99
+ }
100
+ else {
101
+ resolve([]);
102
+ }
103
+ });
104
+ list.on('error', () => resolve([]));
105
+ });
106
+ }
107
+ setActiveSession(sessionName) {
108
+ this.activeSession = sessionName;
109
+ }
110
+ getActiveSession() {
111
+ return this.activeSession;
112
+ }
113
+ getDefaultSession() {
114
+ return this.defaultSession;
115
+ }
116
+ // Deprecated - use setActiveSession
117
+ setSession(sessionName) {
118
+ this.activeSession = sessionName;
119
+ }
120
+ // Deprecated - use getActiveSession
121
+ getSession() {
122
+ return this.activeSession;
123
+ }
124
+ }
125
+ exports.InputInjector = InputInjector;
126
+ //# sourceMappingURL=input-injector.js.map