httpcat-cli 0.0.17 ā 0.0.20
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/.github/dependabot.yml +27 -0
- package/.github/workflows/README.md +49 -0
- package/.github/workflows/ci.yml +101 -0
- package/.github/workflows/homebrew-tap.yml +63 -0
- package/.github/workflows/release.yml +361 -0
- package/README.md +102 -0
- package/dist/commands/list.d.ts.map +1 -1
- package/dist/commands/list.js +11 -0
- package/dist/commands/list.js.map +1 -1
- package/dist/commands/positions.d.ts.map +1 -0
- package/dist/commands/positions.js +136 -0
- package/dist/commands/positions.js.map +1 -0
- package/dist/config.js.map +1 -1
- package/dist/index.js +114 -12
- package/dist/index.js.map +1 -1
- package/dist/interactive/shell.d.ts.map +1 -1
- package/dist/interactive/shell.js +76 -11
- package/dist/interactive/shell.js.map +1 -1
- package/dist/mcp/server.js +1 -1
- package/dist/mcp/tools.d.ts.map +1 -1
- package/dist/mcp/tools.js +20 -0
- package/dist/mcp/tools.js.map +1 -1
- package/dist/mcp/types.d.ts.map +1 -1
- package/dist/utils/loading.d.ts.map +1 -0
- package/dist/utils/loading.js +61 -0
- package/dist/utils/loading.js.map +1 -0
- package/homebrew-httpcat/Formula/httpcat.rb +3 -3
- package/homebrew-httpcat/homebrew-httpcat/Formula/httpcat.rb +3 -3
- package/jest.config.js +38 -0
- package/monitor-foobar.js +38 -39
- package/package.json +11 -2
- package/tests/README.md +134 -0
- package/chat-automation.js +0 -171
- package/httpcat-mcp.json +0 -11
package/monitor-foobar.js
CHANGED
|
@@ -2,87 +2,87 @@
|
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Monitor FRIDA chat for mentions of "foobar"
|
|
5
|
-
*
|
|
5
|
+
*
|
|
6
6
|
* Usage:
|
|
7
7
|
* node monitor-foobar.js
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
-
import { spawn } from
|
|
11
|
-
import { fileURLToPath } from
|
|
12
|
-
import { dirname } from
|
|
10
|
+
import { spawn } from "child_process";
|
|
11
|
+
import { fileURLToPath } from "url";
|
|
12
|
+
import { dirname } from "path";
|
|
13
13
|
|
|
14
14
|
const __filename = fileURLToPath(import.meta.url);
|
|
15
15
|
const __dirname = dirname(__filename);
|
|
16
16
|
|
|
17
|
-
const TOKEN =
|
|
18
|
-
const SEARCH_TERM =
|
|
17
|
+
const TOKEN = "FRIDA";
|
|
18
|
+
const SEARCH_TERM = "foobar";
|
|
19
19
|
|
|
20
20
|
console.error(`š Monitoring FRIDA chat for mentions of "${SEARCH_TERM}"...`);
|
|
21
21
|
console.error(`Press Ctrl+C to stop monitoring\n`);
|
|
22
22
|
|
|
23
23
|
// Spawn httpcat chat process
|
|
24
|
-
const chatProcess = spawn(
|
|
25
|
-
stdio: [
|
|
24
|
+
const chatProcess = spawn("httpcat", ["chat", "--json", TOKEN], {
|
|
25
|
+
stdio: ["pipe", "pipe", "inherit"],
|
|
26
26
|
shell: true,
|
|
27
27
|
});
|
|
28
28
|
|
|
29
|
-
let outputBuffer =
|
|
29
|
+
let outputBuffer = "";
|
|
30
30
|
let seenMessageIds = new Set();
|
|
31
31
|
|
|
32
|
-
chatProcess.stdout.on(
|
|
32
|
+
chatProcess.stdout.on("data", (data) => {
|
|
33
33
|
outputBuffer += data.toString();
|
|
34
|
-
const lines = outputBuffer.split(
|
|
35
|
-
outputBuffer = lines.pop() ||
|
|
36
|
-
|
|
34
|
+
const lines = outputBuffer.split("\n");
|
|
35
|
+
outputBuffer = lines.pop() || "";
|
|
36
|
+
|
|
37
37
|
for (const line of lines) {
|
|
38
38
|
if (!line.trim()) continue;
|
|
39
|
-
|
|
39
|
+
|
|
40
40
|
try {
|
|
41
41
|
const event = JSON.parse(line);
|
|
42
|
-
|
|
42
|
+
|
|
43
43
|
switch (event.type) {
|
|
44
|
-
case
|
|
44
|
+
case "joined":
|
|
45
45
|
console.error(`ā
Joined FRIDA chat. Lease ID: ${event.leaseId}`);
|
|
46
46
|
console.error(`š” Monitoring for "${SEARCH_TERM}" mentions...\n`);
|
|
47
47
|
break;
|
|
48
|
-
|
|
49
|
-
case
|
|
48
|
+
|
|
49
|
+
case "message":
|
|
50
50
|
const msg = event.data;
|
|
51
|
-
|
|
51
|
+
|
|
52
52
|
// Skip if we've already seen this message
|
|
53
53
|
if (seenMessageIds.has(msg.messageId)) {
|
|
54
54
|
break;
|
|
55
55
|
}
|
|
56
56
|
seenMessageIds.add(msg.messageId);
|
|
57
|
-
|
|
57
|
+
|
|
58
58
|
// Check if message contains search term (case-insensitive)
|
|
59
59
|
if (msg.message.toLowerCase().includes(SEARCH_TERM.toLowerCase())) {
|
|
60
60
|
const author = msg.authorShort || msg.author?.slice(0, 10);
|
|
61
61
|
const time = new Date(msg.timestamp).toLocaleString();
|
|
62
|
-
|
|
63
|
-
console.error(
|
|
62
|
+
|
|
63
|
+
console.error("\n" + "=".repeat(60));
|
|
64
64
|
console.error(`šÆ FOUND "${SEARCH_TERM}" MENTION!`);
|
|
65
|
-
console.error(
|
|
65
|
+
console.error("=".repeat(60));
|
|
66
66
|
console.error(`Time: ${time}`);
|
|
67
67
|
console.error(`Author: ${author}`);
|
|
68
68
|
console.error(`Message: ${msg.message}`);
|
|
69
|
-
console.error(
|
|
69
|
+
console.error("=".repeat(60) + "\n");
|
|
70
70
|
}
|
|
71
71
|
break;
|
|
72
|
-
|
|
73
|
-
case
|
|
74
|
-
console.error(
|
|
72
|
+
|
|
73
|
+
case "lease_expired":
|
|
74
|
+
console.error("ā±ļø Lease expired. Sending /renew...");
|
|
75
75
|
if (chatProcess.stdin && !chatProcess.stdin.destroyed) {
|
|
76
|
-
chatProcess.stdin.write(
|
|
76
|
+
chatProcess.stdin.write("/renew\n");
|
|
77
77
|
}
|
|
78
78
|
break;
|
|
79
|
-
|
|
80
|
-
case
|
|
79
|
+
|
|
80
|
+
case "error":
|
|
81
81
|
console.error(`ā Error: ${event.error}`);
|
|
82
82
|
break;
|
|
83
|
-
|
|
84
|
-
case
|
|
85
|
-
console.error(
|
|
83
|
+
|
|
84
|
+
case "exiting":
|
|
85
|
+
console.error("š Chat session ended");
|
|
86
86
|
process.exit(0);
|
|
87
87
|
break;
|
|
88
88
|
}
|
|
@@ -92,12 +92,12 @@ chatProcess.stdout.on('data', (data) => {
|
|
|
92
92
|
}
|
|
93
93
|
});
|
|
94
94
|
|
|
95
|
-
chatProcess.on(
|
|
95
|
+
chatProcess.on("error", (error) => {
|
|
96
96
|
console.error(`ā Failed to start chat process: ${error.message}`);
|
|
97
97
|
process.exit(1);
|
|
98
98
|
});
|
|
99
99
|
|
|
100
|
-
chatProcess.on(
|
|
100
|
+
chatProcess.on("exit", (code) => {
|
|
101
101
|
if (code !== 0 && code !== null) {
|
|
102
102
|
console.error(`Chat process exited with code ${code}`);
|
|
103
103
|
}
|
|
@@ -105,14 +105,13 @@ chatProcess.on('exit', (code) => {
|
|
|
105
105
|
});
|
|
106
106
|
|
|
107
107
|
// Handle Ctrl+C
|
|
108
|
-
process.on(
|
|
109
|
-
console.error(
|
|
108
|
+
process.on("SIGINT", () => {
|
|
109
|
+
console.error("\nš Stopping monitor...");
|
|
110
110
|
if (chatProcess.stdin && !chatProcess.stdin.destroyed) {
|
|
111
|
-
chatProcess.stdin.write(
|
|
111
|
+
chatProcess.stdin.write("/exit\n");
|
|
112
112
|
}
|
|
113
113
|
setTimeout(() => {
|
|
114
114
|
chatProcess.kill();
|
|
115
115
|
process.exit(0);
|
|
116
116
|
}, 1000);
|
|
117
117
|
});
|
|
118
|
-
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "httpcat-cli",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.20",
|
|
4
4
|
"description": "CLI tool for interacting with httpcat agent - create, buy, and sell tokens with x402 payments",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -11,7 +11,12 @@
|
|
|
11
11
|
"build": "tsc",
|
|
12
12
|
"dev": "tsc --watch",
|
|
13
13
|
"start": "node dist/index.js",
|
|
14
|
-
"prepublishOnly": "yarn build"
|
|
14
|
+
"prepublishOnly": "yarn build",
|
|
15
|
+
"test": "jest",
|
|
16
|
+
"test:watch": "jest --watch",
|
|
17
|
+
"test:coverage": "jest --coverage",
|
|
18
|
+
"test:unit": "jest tests/unit",
|
|
19
|
+
"test:integration": "jest tests/integration"
|
|
15
20
|
},
|
|
16
21
|
"keywords": [
|
|
17
22
|
"httpcat",
|
|
@@ -50,8 +55,12 @@
|
|
|
50
55
|
"devDependencies": {
|
|
51
56
|
"@types/blessed": "^0.1.26",
|
|
52
57
|
"@types/inquirer": "^9.0.7",
|
|
58
|
+
"@types/jest": "^29.5.12",
|
|
53
59
|
"@types/node": "^20.10.0",
|
|
54
60
|
"@types/ws": "^8.5.13",
|
|
61
|
+
"@jest/globals": "^29.7.0",
|
|
62
|
+
"jest": "^29.7.0",
|
|
63
|
+
"ts-jest": "^29.1.2",
|
|
55
64
|
"typescript": "^5.3.3"
|
|
56
65
|
},
|
|
57
66
|
"engines": {
|
package/tests/README.md
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
# Testing Suite
|
|
2
|
+
|
|
3
|
+
This directory contains the complete testing suite for httpcat-cli, including both unit and integration tests.
|
|
4
|
+
|
|
5
|
+
## Structure
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
tests/
|
|
9
|
+
āāā setup.ts # Global test setup
|
|
10
|
+
āāā unit/ # Unit tests
|
|
11
|
+
ā āāā utils/ # Utility function tests
|
|
12
|
+
ā ā āāā validation.test.ts
|
|
13
|
+
ā ā āāā formatting.test.ts
|
|
14
|
+
ā ā āāā errors.test.ts
|
|
15
|
+
ā ā āāā token-resolver.test.ts
|
|
16
|
+
ā āāā config.test.ts # Config manager tests
|
|
17
|
+
ā āāā client.test.ts # HTTP client tests
|
|
18
|
+
ā āāā commands/ # Command function tests
|
|
19
|
+
ā āāā create.test.ts
|
|
20
|
+
ā āāā buy.test.ts
|
|
21
|
+
ā āāā sell.test.ts
|
|
22
|
+
ā āāā info.test.ts
|
|
23
|
+
ā āāā list.test.ts
|
|
24
|
+
ā āāā health.test.ts
|
|
25
|
+
āāā integration/ # Integration tests
|
|
26
|
+
āāā workflows.test.ts # End-to-end workflow tests
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Running Tests
|
|
30
|
+
|
|
31
|
+
### Run all tests
|
|
32
|
+
```bash
|
|
33
|
+
yarn test
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### Run tests in watch mode
|
|
37
|
+
```bash
|
|
38
|
+
yarn test:watch
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### Run tests with coverage
|
|
42
|
+
```bash
|
|
43
|
+
yarn test:coverage
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### Run only unit tests
|
|
47
|
+
```bash
|
|
48
|
+
yarn test:unit
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Run only integration tests
|
|
52
|
+
```bash
|
|
53
|
+
yarn test:integration
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Test Coverage
|
|
57
|
+
|
|
58
|
+
The test suite aims for comprehensive coverage of:
|
|
59
|
+
|
|
60
|
+
- **Unit Tests**: Individual functions and modules
|
|
61
|
+
- Validation utilities
|
|
62
|
+
- Formatting utilities
|
|
63
|
+
- Error handling
|
|
64
|
+
- Configuration management
|
|
65
|
+
- HTTP client (with mocked dependencies)
|
|
66
|
+
- Command functions (with mocked client)
|
|
67
|
+
|
|
68
|
+
- **Integration Tests**: Full workflows
|
|
69
|
+
- Token creation and trading lifecycle
|
|
70
|
+
- Token discovery
|
|
71
|
+
- Health checks
|
|
72
|
+
- Error handling workflows
|
|
73
|
+
|
|
74
|
+
## Writing Tests
|
|
75
|
+
|
|
76
|
+
### Unit Test Example
|
|
77
|
+
|
|
78
|
+
```typescript
|
|
79
|
+
import { validateTokenName } from '../../../src/utils/validation.js';
|
|
80
|
+
|
|
81
|
+
describe('validateTokenName', () => {
|
|
82
|
+
it('should accept valid token names', () => {
|
|
83
|
+
expect(() => validateTokenName('My Token')).not.toThrow();
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
it('should reject empty token names', () => {
|
|
87
|
+
expect(() => validateTokenName('')).toThrow();
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### Integration Test Example
|
|
93
|
+
|
|
94
|
+
```typescript
|
|
95
|
+
import { createToken } from '../../src/commands/create.js';
|
|
96
|
+
import { HttpcatClient } from '../../src/client.js';
|
|
97
|
+
|
|
98
|
+
describe('Token Creation Workflow', () => {
|
|
99
|
+
it('should create token successfully', async () => {
|
|
100
|
+
const mockClient = createMockClient();
|
|
101
|
+
const result = await createToken(mockClient, {
|
|
102
|
+
name: 'Test Token',
|
|
103
|
+
symbol: 'TEST',
|
|
104
|
+
});
|
|
105
|
+
expect(result.tokenId).toBeDefined();
|
|
106
|
+
});
|
|
107
|
+
});
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## Mocking
|
|
111
|
+
|
|
112
|
+
The test suite uses Jest's mocking capabilities to:
|
|
113
|
+
|
|
114
|
+
- Mock external dependencies (x402-fetch, config, etc.)
|
|
115
|
+
- Mock HTTP client responses
|
|
116
|
+
- Mock file system operations
|
|
117
|
+
- Mock user input
|
|
118
|
+
|
|
119
|
+
## Best Practices
|
|
120
|
+
|
|
121
|
+
1. **Isolation**: Each test should be independent and not rely on other tests
|
|
122
|
+
2. **Mocking**: Mock external dependencies to ensure fast, reliable tests
|
|
123
|
+
3. **Coverage**: Aim for high coverage of business logic
|
|
124
|
+
4. **Clarity**: Use descriptive test names and organize tests logically
|
|
125
|
+
5. **Edge Cases**: Test error conditions and edge cases
|
|
126
|
+
|
|
127
|
+
## Continuous Integration
|
|
128
|
+
|
|
129
|
+
Tests should pass before merging PRs. The CI pipeline will:
|
|
130
|
+
1. Install dependencies
|
|
131
|
+
2. Run linting
|
|
132
|
+
3. Run all tests
|
|
133
|
+
4. Generate coverage reports
|
|
134
|
+
|
package/chat-automation.js
DELETED
|
@@ -1,171 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Automated chat script for httpcat chat --json mode
|
|
5
|
-
*
|
|
6
|
-
* Usage:
|
|
7
|
-
* node chat-automation.js <token> [message1] [message2] ...
|
|
8
|
-
*
|
|
9
|
-
* Or pipe messages:
|
|
10
|
-
* echo -e "Hello\nWorld" | node chat-automation.js <token>
|
|
11
|
-
*/
|
|
12
|
-
|
|
13
|
-
import { spawn } from 'child_process';
|
|
14
|
-
import { fileURLToPath } from 'url';
|
|
15
|
-
import { dirname, join } from 'path';
|
|
16
|
-
|
|
17
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
18
|
-
const __dirname = dirname(__filename);
|
|
19
|
-
|
|
20
|
-
const token = process.argv[2];
|
|
21
|
-
|
|
22
|
-
if (!token) {
|
|
23
|
-
console.error('Usage: node chat-automation.js <token> [message1] [message2] ...');
|
|
24
|
-
console.error(' Or: echo -e "msg1\\nmsg2" | node chat-automation.js <token>');
|
|
25
|
-
process.exit(1);
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
// Get messages from command line args or stdin
|
|
29
|
-
const messages = process.argv.slice(3);
|
|
30
|
-
|
|
31
|
-
// Spawn httpcat chat process
|
|
32
|
-
const chatProcess = spawn('httpcat', ['chat', '--json', token], {
|
|
33
|
-
stdio: ['pipe', 'pipe', 'inherit'], // Capture stdout to parse JSON
|
|
34
|
-
shell: true,
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
// Handle JSON output from chat
|
|
38
|
-
let outputBuffer = '';
|
|
39
|
-
chatProcess.stdout.on('data', (data) => {
|
|
40
|
-
outputBuffer += data.toString();
|
|
41
|
-
const lines = outputBuffer.split('\n');
|
|
42
|
-
outputBuffer = lines.pop() || ''; // Keep incomplete line
|
|
43
|
-
|
|
44
|
-
for (const line of lines) {
|
|
45
|
-
if (!line.trim()) continue;
|
|
46
|
-
|
|
47
|
-
try {
|
|
48
|
-
const event = JSON.parse(line);
|
|
49
|
-
|
|
50
|
-
switch (event.type) {
|
|
51
|
-
case 'joined':
|
|
52
|
-
console.error(`ā
Joined chat. Lease ID: ${event.leaseId}`);
|
|
53
|
-
// Send initial messages if provided
|
|
54
|
-
if (messages.length > 0) {
|
|
55
|
-
setTimeout(() => {
|
|
56
|
-
messages.forEach((msg, index) => {
|
|
57
|
-
setTimeout(() => {
|
|
58
|
-
if (chatProcess.stdin && !chatProcess.stdin.destroyed) {
|
|
59
|
-
chatProcess.stdin.write(msg + '\n');
|
|
60
|
-
}
|
|
61
|
-
}, index * 1000); // 1 second between messages
|
|
62
|
-
});
|
|
63
|
-
}, 2000); // Wait 2 seconds after joining
|
|
64
|
-
}
|
|
65
|
-
break;
|
|
66
|
-
|
|
67
|
-
case 'message':
|
|
68
|
-
const msg = event.data;
|
|
69
|
-
const author = msg.authorShort || msg.author?.slice(0, 6);
|
|
70
|
-
const time = new Date(msg.timestamp).toLocaleTimeString();
|
|
71
|
-
console.error(`[${time}] ${author}: ${msg.message}`);
|
|
72
|
-
|
|
73
|
-
// Auto-respond to messages containing "claude" (case-insensitive)
|
|
74
|
-
// Check if message is from someone else (not our own)
|
|
75
|
-
const isOwn = msg.author?.toLowerCase() === process.env.HTTPCAT_ADDRESS?.toLowerCase();
|
|
76
|
-
if (msg.message.toLowerCase().includes('claude') && !isOwn) {
|
|
77
|
-
setTimeout(() => {
|
|
78
|
-
const response = `Hello! I'm Claude, an AI assistant. How can I help you?`;
|
|
79
|
-
if (chatProcess.stdin && !chatProcess.stdin.destroyed) {
|
|
80
|
-
chatProcess.stdin.write(response + '\n');
|
|
81
|
-
}
|
|
82
|
-
}, 1000);
|
|
83
|
-
}
|
|
84
|
-
break;
|
|
85
|
-
|
|
86
|
-
case 'message_sent':
|
|
87
|
-
console.error(`ā
Message sent: ${event.messageId}`);
|
|
88
|
-
break;
|
|
89
|
-
|
|
90
|
-
case 'lease_expired':
|
|
91
|
-
console.error('ā±ļø Lease expired. Sending /renew...');
|
|
92
|
-
if (chatProcess.stdin && !chatProcess.stdin.destroyed) {
|
|
93
|
-
chatProcess.stdin.write('/renew\n');
|
|
94
|
-
}
|
|
95
|
-
break;
|
|
96
|
-
|
|
97
|
-
case 'error':
|
|
98
|
-
console.error(`ā Error: ${event.error}`);
|
|
99
|
-
break;
|
|
100
|
-
|
|
101
|
-
case 'exiting':
|
|
102
|
-
console.error('š Chat session ended');
|
|
103
|
-
process.exit(0);
|
|
104
|
-
break;
|
|
105
|
-
}
|
|
106
|
-
} catch (error) {
|
|
107
|
-
// Not JSON, might be regular output - ignore or log
|
|
108
|
-
if (line.trim() && !line.startsWith('{')) {
|
|
109
|
-
console.error(line);
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
// Send messages from stdin if no command line args
|
|
116
|
-
if (messages.length === 0 && !process.stdin.isTTY) {
|
|
117
|
-
let stdinBuffer = '';
|
|
118
|
-
|
|
119
|
-
process.stdin.setEncoding('utf8');
|
|
120
|
-
process.stdin.on('data', (chunk) => {
|
|
121
|
-
stdinBuffer += chunk.toString();
|
|
122
|
-
const lines = stdinBuffer.split('\n');
|
|
123
|
-
stdinBuffer = lines.pop() || '';
|
|
124
|
-
|
|
125
|
-
for (const line of lines) {
|
|
126
|
-
const trimmed = line.trim();
|
|
127
|
-
if (trimmed) {
|
|
128
|
-
// Wait a bit for chat to be ready, then send
|
|
129
|
-
setTimeout(() => {
|
|
130
|
-
if (chatProcess.stdin && !chatProcess.stdin.destroyed) {
|
|
131
|
-
chatProcess.stdin.write(trimmed + '\n');
|
|
132
|
-
}
|
|
133
|
-
}, 2000);
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
});
|
|
137
|
-
|
|
138
|
-
process.stdin.on('end', () => {
|
|
139
|
-
// Keep process alive to receive messages
|
|
140
|
-
// User can Ctrl+C to exit
|
|
141
|
-
});
|
|
142
|
-
} else if (messages.length > 0) {
|
|
143
|
-
// Messages provided via command line - will be sent after joining
|
|
144
|
-
// (handled in the 'joined' event handler above)
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
// Handle process errors
|
|
148
|
-
chatProcess.on('error', (error) => {
|
|
149
|
-
console.error(`ā Failed to start chat process: ${error.message}`);
|
|
150
|
-
process.exit(1);
|
|
151
|
-
});
|
|
152
|
-
|
|
153
|
-
chatProcess.on('exit', (code) => {
|
|
154
|
-
if (code !== 0 && code !== null) {
|
|
155
|
-
console.error(`Chat process exited with code ${code}`);
|
|
156
|
-
}
|
|
157
|
-
process.exit(code || 0);
|
|
158
|
-
});
|
|
159
|
-
|
|
160
|
-
// Handle Ctrl+C
|
|
161
|
-
process.on('SIGINT', () => {
|
|
162
|
-
console.error('\nš Shutting down...');
|
|
163
|
-
if (chatProcess.stdin && !chatProcess.stdin.destroyed) {
|
|
164
|
-
chatProcess.stdin.write('/exit\n');
|
|
165
|
-
}
|
|
166
|
-
setTimeout(() => {
|
|
167
|
-
chatProcess.kill();
|
|
168
|
-
process.exit(0);
|
|
169
|
-
}, 1000);
|
|
170
|
-
});
|
|
171
|
-
|