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.
Files changed (2) hide show
  1. package/dist/cli.js +100 -4
  2. 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 = execSync(`openclaw config get ${key}`, { stdio: 'pipe', timeout: 5000, encoding: 'utf-8' }).trim();
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 = await promptLine('openclaw token', detectedToken);
588
+ const token = detectedToken;
494
589
  if (!token) {
495
- console.log(chalk.red(' missing openclaw token'));
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 = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "life-pulse",
3
- "version": "2.4.2",
3
+ "version": "2.4.3",
4
4
  "description": "macOS life diagnostic — reads local data sources, generates actionable insights",
5
5
  "main": "dist/index.js",
6
6
  "scripts": {