claude-phone-local 2.1.0 → 2.1.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.
- package/cli/lib/commands/logs.js +40 -36
- package/cli/lib/process-manager.js +10 -1
- package/package.json +1 -1
package/cli/lib/commands/logs.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
2
|
import { spawn } from 'child_process';
|
|
3
|
-
import
|
|
4
|
-
import { loadConfig, configExists, getDockerComposePath, getPidPath } from '../config.js';
|
|
3
|
+
import { loadConfig, configExists, getDockerComposePath, getPidPath, getConfigDir } from '../config.js';
|
|
5
4
|
import fs from 'fs';
|
|
5
|
+
import path from 'path';
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* Logs command - Tail service logs
|
|
@@ -104,49 +104,53 @@ function tailDockerLogs(dockerComposePath) {
|
|
|
104
104
|
|
|
105
105
|
/**
|
|
106
106
|
* Tail API server logs
|
|
107
|
-
* @param {object}
|
|
107
|
+
* @param {object} _config - Configuration object (unused; log path is fixed)
|
|
108
108
|
*/
|
|
109
|
-
function tailAPIServerLogs(
|
|
110
|
-
|
|
109
|
+
function tailAPIServerLogs(_config) {
|
|
110
|
+
const logPath = path.join(getConfigDir(), 'claude-api-server.log');
|
|
111
111
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
112
|
+
if (!fs.existsSync(logPath)) {
|
|
113
|
+
console.log(chalk.yellow('⚠ No log file yet - the API server has not written any output'));
|
|
114
|
+
console.log(chalk.gray(` Expected at: ${logPath}\n`));
|
|
115
|
+
process.exit(1);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
console.log(chalk.gray(`Watching ${logPath}\n`));
|
|
119
|
+
|
|
120
|
+
// Print the last ~50 lines, then follow new writes. No native `tail -f` on
|
|
121
|
+
// Windows, so poll the file size and read only the appended bytes.
|
|
122
|
+
const fullContent = fs.readFileSync(logPath, 'utf8');
|
|
123
|
+
const lines = fullContent.split('\n');
|
|
124
|
+
const tailLines = lines.slice(Math.max(0, lines.length - 50));
|
|
125
|
+
process.stdout.write(tailLines.join('\n'));
|
|
116
126
|
|
|
117
|
-
let
|
|
127
|
+
let position = fs.statSync(logPath).size;
|
|
118
128
|
|
|
119
|
-
const
|
|
129
|
+
const poll = setInterval(() => {
|
|
120
130
|
try {
|
|
121
|
-
const
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
if (response.status === 200) {
|
|
126
|
-
console.log(chalk.green(`[${new Date().toISOString()}] ✓ API server healthy`));
|
|
127
|
-
consecutiveFailures = 0;
|
|
128
|
-
} else {
|
|
129
|
-
console.log(chalk.yellow(`[${new Date().toISOString()}] ⚠ Unexpected status: ${response.status}`));
|
|
131
|
+
const { size } = fs.statSync(logPath);
|
|
132
|
+
if (size < position) {
|
|
133
|
+
// Log file was rotated/truncated (e.g. by a restart) - start over.
|
|
134
|
+
position = 0;
|
|
130
135
|
}
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
136
|
+
if (size > position) {
|
|
137
|
+
const fd = fs.openSync(logPath, 'r');
|
|
138
|
+
const buffer = Buffer.alloc(size - position);
|
|
139
|
+
fs.readSync(fd, buffer, 0, buffer.length, position);
|
|
140
|
+
fs.closeSync(fd);
|
|
141
|
+
process.stdout.write(buffer.toString('utf8'));
|
|
142
|
+
position = size;
|
|
138
143
|
}
|
|
144
|
+
} catch (err) {
|
|
145
|
+
console.log(chalk.red(`\n✗ Lost access to log file: ${err.message}\n`));
|
|
146
|
+
clearInterval(poll);
|
|
147
|
+
process.exit(1);
|
|
139
148
|
}
|
|
140
|
-
};
|
|
149
|
+
}, 1000);
|
|
141
150
|
|
|
142
|
-
// Check immediately, then every 5 seconds
|
|
143
|
-
checkHealth();
|
|
144
|
-
const interval = setInterval(checkHealth, 5000);
|
|
145
|
-
|
|
146
|
-
// Handle Ctrl+C
|
|
147
151
|
process.on('SIGINT', () => {
|
|
148
|
-
clearInterval(
|
|
149
|
-
console.log(chalk.gray('\n\nStopped
|
|
152
|
+
clearInterval(poll);
|
|
153
|
+
console.log(chalk.gray('\n\nStopped tailing logs.\n'));
|
|
150
154
|
process.exit(0);
|
|
151
155
|
});
|
|
152
156
|
}
|
|
@@ -157,7 +161,7 @@ function tailAPIServerLogs(config) {
|
|
|
157
161
|
* @param {object} _config - Configuration object (unused)
|
|
158
162
|
*/
|
|
159
163
|
function tailBothServices(dockerComposePath, _config) {
|
|
160
|
-
console.log(chalk.gray('Showing Docker container logs
|
|
164
|
+
console.log(chalk.gray('Showing Docker container logs. Run "claude-phone logs api-server" separately for the host-side API server log.\n'));
|
|
161
165
|
|
|
162
166
|
const child = spawn('docker', [
|
|
163
167
|
'compose',
|
|
@@ -70,17 +70,26 @@ export async function startServer(serverPath, port, pidPath = null) {
|
|
|
70
70
|
}
|
|
71
71
|
|
|
72
72
|
return new Promise((resolve, reject) => {
|
|
73
|
+
// Redirect stdout/stderr to a log file instead of discarding them - this
|
|
74
|
+
// process's own console.log is the only place query timing, session
|
|
75
|
+
// tracking, and CLI/SDK errors are visible; with stdio: 'ignore' there
|
|
76
|
+
// was no way to diagnose a slow or failed call after the fact.
|
|
77
|
+
const logPath = path.join(getConfigDir(), 'claude-api-server.log');
|
|
78
|
+
const logFd = fs.openSync(logPath, 'a');
|
|
79
|
+
|
|
73
80
|
// Spawn detached process
|
|
74
81
|
const child = spawn('node', ['server.js'], {
|
|
75
82
|
cwd: serverPath,
|
|
76
83
|
detached: true,
|
|
77
|
-
stdio: 'ignore',
|
|
84
|
+
stdio: ['ignore', logFd, logFd],
|
|
78
85
|
env: {
|
|
79
86
|
...process.env,
|
|
80
87
|
PORT: port
|
|
81
88
|
}
|
|
82
89
|
});
|
|
83
90
|
|
|
91
|
+
fs.closeSync(logFd); // child holds its own reference to the fd via dup()
|
|
92
|
+
|
|
84
93
|
// Don't wait for child process
|
|
85
94
|
child.unref();
|
|
86
95
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claude-phone-local",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.1",
|
|
4
4
|
"description": "Local/offline fork of NetworkChuck's claude-phone: talk to Claude Code over 3CX/SIP with faster-whisper STT + Piper TTS in one Docker container.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|