life-pulse 2.4.2 → 2.4.3
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 +100 -4
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -34,6 +34,7 @@ import { fileURLToPath } from 'url';
|
|
|
34
34
|
import { homedir } from 'os';
|
|
35
35
|
import { execSync, execFileSync } from 'child_process';
|
|
36
36
|
import { createInterface } from 'readline';
|
|
37
|
+
import { randomBytes } from 'crypto';
|
|
37
38
|
import dayjs from 'dayjs';
|
|
38
39
|
const collectedDecisions = [];
|
|
39
40
|
const DEFAULT_CONFIG = {
|
|
@@ -142,14 +143,22 @@ async function promptLine(question, fallback = '') {
|
|
|
142
143
|
});
|
|
143
144
|
}
|
|
144
145
|
function detectOpenClawToken() {
|
|
146
|
+
const bin = resolveOpenClawBin();
|
|
147
|
+
if (!bin)
|
|
148
|
+
return '';
|
|
145
149
|
const keys = [
|
|
146
150
|
'gateway.http.auth.token',
|
|
147
151
|
'gateway.auth.token',
|
|
148
152
|
'gateway.http.token',
|
|
153
|
+
'gateway.token',
|
|
149
154
|
];
|
|
150
155
|
for (const key of keys) {
|
|
151
156
|
try {
|
|
152
|
-
const out =
|
|
157
|
+
const out = execFileSync(bin, ['config', 'get', key], {
|
|
158
|
+
stdio: 'pipe',
|
|
159
|
+
timeout: 5000,
|
|
160
|
+
encoding: 'utf-8',
|
|
161
|
+
}).trim();
|
|
153
162
|
if (!out)
|
|
154
163
|
continue;
|
|
155
164
|
const low = out.toLowerCase();
|
|
@@ -159,8 +168,94 @@ function detectOpenClawToken() {
|
|
|
159
168
|
}
|
|
160
169
|
catch { }
|
|
161
170
|
}
|
|
171
|
+
// Fallback: parse any config listing output for token-like values.
|
|
172
|
+
const listCommands = [
|
|
173
|
+
['config', 'list'],
|
|
174
|
+
['config', 'show'],
|
|
175
|
+
['config', '--json'],
|
|
176
|
+
];
|
|
177
|
+
for (const cmd of listCommands) {
|
|
178
|
+
try {
|
|
179
|
+
const out = execFileSync(bin, cmd, {
|
|
180
|
+
stdio: 'pipe',
|
|
181
|
+
timeout: 5000,
|
|
182
|
+
encoding: 'utf-8',
|
|
183
|
+
});
|
|
184
|
+
const tokenMatch = out.match(/token[^:\n=]*[:=]\s*([A-Za-z0-9_\-]{16,})/i);
|
|
185
|
+
if (tokenMatch?.[1])
|
|
186
|
+
return tokenMatch[1];
|
|
187
|
+
}
|
|
188
|
+
catch { }
|
|
189
|
+
}
|
|
162
190
|
return '';
|
|
163
191
|
}
|
|
192
|
+
function resolveOpenClawBin() {
|
|
193
|
+
try {
|
|
194
|
+
const out = execSync('command -v openclaw', {
|
|
195
|
+
stdio: 'pipe',
|
|
196
|
+
timeout: 3000,
|
|
197
|
+
encoding: 'utf-8',
|
|
198
|
+
shell: '/bin/zsh',
|
|
199
|
+
}).trim();
|
|
200
|
+
if (out)
|
|
201
|
+
return out;
|
|
202
|
+
}
|
|
203
|
+
catch { }
|
|
204
|
+
const candidates = [
|
|
205
|
+
join(homedir(), 'Library', 'pnpm', 'openclaw'),
|
|
206
|
+
'/opt/homebrew/bin/openclaw',
|
|
207
|
+
'/usr/local/bin/openclaw',
|
|
208
|
+
];
|
|
209
|
+
for (const c of candidates) {
|
|
210
|
+
if (existsSync(c))
|
|
211
|
+
return c;
|
|
212
|
+
}
|
|
213
|
+
return '';
|
|
214
|
+
}
|
|
215
|
+
function ensureOpenClawChatEndpoint(bin) {
|
|
216
|
+
const keys = [
|
|
217
|
+
'gateway.http.endpoints.chatCompletions.enabled',
|
|
218
|
+
'gateway.http.endpoints.chat.enabled',
|
|
219
|
+
];
|
|
220
|
+
for (const key of keys) {
|
|
221
|
+
try {
|
|
222
|
+
execFileSync(bin, ['config', 'set', key, 'true'], {
|
|
223
|
+
stdio: 'pipe',
|
|
224
|
+
timeout: 5000,
|
|
225
|
+
encoding: 'utf-8',
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
catch { }
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
function ensureOpenClawToken() {
|
|
232
|
+
const bin = resolveOpenClawBin();
|
|
233
|
+
if (!bin)
|
|
234
|
+
return '';
|
|
235
|
+
ensureOpenClawChatEndpoint(bin);
|
|
236
|
+
const existing = detectOpenClawToken();
|
|
237
|
+
if (existing)
|
|
238
|
+
return existing;
|
|
239
|
+
const generated = randomBytes(20).toString('hex');
|
|
240
|
+
const keys = [
|
|
241
|
+
'gateway.http.auth.token',
|
|
242
|
+
'gateway.auth.token',
|
|
243
|
+
'gateway.http.token',
|
|
244
|
+
'gateway.token',
|
|
245
|
+
];
|
|
246
|
+
for (const key of keys) {
|
|
247
|
+
try {
|
|
248
|
+
execFileSync(bin, ['config', 'set', key, generated], {
|
|
249
|
+
stdio: 'pipe',
|
|
250
|
+
timeout: 5000,
|
|
251
|
+
encoding: 'utf-8',
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
catch { }
|
|
255
|
+
}
|
|
256
|
+
// Best effort: return detected token if persisted, else generated.
|
|
257
|
+
return detectOpenClawToken() || generated;
|
|
258
|
+
}
|
|
164
259
|
function detectTailscaleHostOrIp() {
|
|
165
260
|
const bin = resolveTailscaleBin();
|
|
166
261
|
if (!bin)
|
|
@@ -466,13 +561,13 @@ async function main() {
|
|
|
466
561
|
// --pair: generate Desktop/nox-route.json for NOX routing
|
|
467
562
|
if (pairMode) {
|
|
468
563
|
const defaultName = getUserName() || '';
|
|
469
|
-
const detectedToken = detectOpenClawToken();
|
|
470
564
|
const envPhone = normalizePhoneCandidate(process.env.LIFE_PULSE_SELF_PHONE
|
|
471
565
|
|| process.env.NOX_OWNER_PHONE
|
|
472
566
|
|| process.env.LIFE_PULSE_BRIEF_SMS_PHONE
|
|
473
567
|
|| '');
|
|
474
568
|
const pairSpinner = process.stdin.isTTY ? new Spinner() : undefined;
|
|
475
569
|
const detectedHost = normalizeHostOrIp(await ensureTailscaleHostForPair(pairSpinner));
|
|
570
|
+
const detectedToken = ensureOpenClawToken();
|
|
476
571
|
console.log();
|
|
477
572
|
console.log(chalk.bold.hex('#c0caf5')(' pair with nox'));
|
|
478
573
|
console.log(chalk.dim(' we will create Desktop/nox-route.json'));
|
|
@@ -490,9 +585,10 @@ async function main() {
|
|
|
490
585
|
console.log(chalk.dim(' keep tailscale signed in, then rerun: npx life-pulse --pair'));
|
|
491
586
|
return;
|
|
492
587
|
}
|
|
493
|
-
const token =
|
|
588
|
+
const token = detectedToken;
|
|
494
589
|
if (!token) {
|
|
495
|
-
console.log(chalk.red('
|
|
590
|
+
console.log(chalk.red(' openclaw token unavailable'));
|
|
591
|
+
console.log(chalk.dim(' make sure openclaw is installed and running, then rerun: npx life-pulse --pair'));
|
|
496
592
|
return;
|
|
497
593
|
}
|
|
498
594
|
const payload = {
|