persnally 2.5.2 → 2.5.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/build/src/cli.js +43 -11
- package/build/src/lifecycle.d.ts +10 -0
- package/build/src/lifecycle.js +21 -0
- package/package.json +1 -1
package/build/src/cli.js
CHANGED
|
@@ -19,7 +19,7 @@ import { extractClaudeEvents, parseClaudeExport } from "./importers/claude.js";
|
|
|
19
19
|
import { DEFAULT_TRANSCRIPTS_DIR, extractClaudeCodeEvents, parseClaudeCodeTranscripts, } from "./importers/claude-code.js";
|
|
20
20
|
import { gitEvents, scanRepos } from "./importers/git.js";
|
|
21
21
|
import { freshConversations } from "./importers/extract.js";
|
|
22
|
-
import { autostartInstalled, installAutostart, LOG_FILE, removeAutostart, removePidFile, runningPid, startDetached, stopDaemon, writePidFile, } from "./lifecycle.js";
|
|
22
|
+
import { autostartInstalled, installAutostart, LOG_FILE, reloadAutostart, removeAutostart, removePidFile, runningPid, startDetached, stopDaemon, writePidFile, } from "./lifecycle.js";
|
|
23
23
|
import { newEvent } from "./events.js";
|
|
24
24
|
import { proseLines } from "./prose.js";
|
|
25
25
|
import { analyzeVoice } from "./stylometry.js";
|
|
@@ -50,6 +50,7 @@ Usage:
|
|
|
50
50
|
persnallyd activity Context-read engagement over time (retention pulse)
|
|
51
51
|
persnallyd start [--port N] Start the daemon in the background
|
|
52
52
|
persnallyd stop Stop the background daemon
|
|
53
|
+
persnallyd restart Restart the daemon (correctly handles autostart/launchd)
|
|
53
54
|
persnallyd serve [--port N] Run the daemon in the foreground (127.0.0.1:${DEFAULT_PORT})
|
|
54
55
|
persnallyd autostart [--remove] Start the daemon at login and keep it alive (macOS)
|
|
55
56
|
persnallyd config set-key <key> Store the Anthropic API key (owner-only file) for the daemon
|
|
@@ -171,13 +172,8 @@ async function main() {
|
|
|
171
172
|
console.error(`· Context hook skipped: ${e instanceof Error ? e.message : e}`);
|
|
172
173
|
}
|
|
173
174
|
}
|
|
174
|
-
console.log(`\nDone${imported ? ` — ${imported} events imported` : ""}
|
|
175
|
-
|
|
176
|
-
try {
|
|
177
|
-
execFileSync("open", [`http://127.0.0.1:${port}`]);
|
|
178
|
-
}
|
|
179
|
-
catch { /* non-fatal */ }
|
|
180
|
-
}
|
|
175
|
+
console.log(`\nDone${imported ? ` — ${imported} events imported` : ""}.`);
|
|
176
|
+
announceDashboard(port);
|
|
181
177
|
return;
|
|
182
178
|
}
|
|
183
179
|
case "scope": {
|
|
@@ -483,19 +479,43 @@ async function main() {
|
|
|
483
479
|
const existing = runningPid();
|
|
484
480
|
if (existing)
|
|
485
481
|
return die(`daemon already running (pid ${existing})`);
|
|
486
|
-
const
|
|
487
|
-
|
|
482
|
+
const port = parsePort(args);
|
|
483
|
+
const pid = await startDetached(process.argv[1], port);
|
|
484
|
+
console.log(`persnallyd started (pid ${pid}).`);
|
|
485
|
+
announceDashboard(port);
|
|
488
486
|
console.log(`Logs: ${LOG_FILE}`);
|
|
489
487
|
return;
|
|
490
488
|
}
|
|
491
489
|
case "stop": {
|
|
492
490
|
if (autostartInstalled()) {
|
|
493
|
-
console.error("Note: autostart is installed — launchd will
|
|
491
|
+
console.error("Note: autostart is installed — launchd will respawn the daemon. To restart cleanly use `persnallyd restart`; to stop it for good use `persnallyd autostart --remove`.");
|
|
494
492
|
}
|
|
495
493
|
const pid = await stopDaemon();
|
|
496
494
|
console.log(pid ? `Stopped daemon (pid ${pid}).` : "Daemon was not running.");
|
|
497
495
|
return;
|
|
498
496
|
}
|
|
497
|
+
case "restart": {
|
|
498
|
+
const port = parsePort(args);
|
|
499
|
+
if (autostartInstalled()) {
|
|
500
|
+
// launchd owns the lifecycle — a plain stop just gets respawned. Reload the
|
|
501
|
+
// job so it comes back on the current install (also heals a drifted plist path).
|
|
502
|
+
const health = await reloadAutostart(process.argv[1], port);
|
|
503
|
+
if (health) {
|
|
504
|
+
console.log(`Restarted via launchd — daemon up on v${health.version}.`);
|
|
505
|
+
announceDashboard(port);
|
|
506
|
+
}
|
|
507
|
+
else {
|
|
508
|
+
console.log("Reloaded autostart; daemon is still coming up — check: persnallyd status");
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
else {
|
|
512
|
+
await stopDaemon();
|
|
513
|
+
const pid = await startDetached(process.argv[1], port);
|
|
514
|
+
console.log(`persnallyd restarted (pid ${pid}).`);
|
|
515
|
+
announceDashboard(port);
|
|
516
|
+
}
|
|
517
|
+
return;
|
|
518
|
+
}
|
|
499
519
|
case "autostart": {
|
|
500
520
|
if (args[0] === "--remove") {
|
|
501
521
|
console.log(removeAutostart() ? "Autostart removed; daemon stopped." : "Autostart was not installed.");
|
|
@@ -507,6 +527,7 @@ async function main() {
|
|
|
507
527
|
console.log(`Stopped existing daemon (pid ${stopped}) — launchd takes over.`);
|
|
508
528
|
const plist = installAutostart(process.argv[1], parsePort(args));
|
|
509
529
|
console.log(`Autostart installed (${plist}). The daemon now runs at login and restarts if it exits.`);
|
|
530
|
+
announceDashboard(parsePort(args), false); // launchd brings it up async — show the link, don't open a not-yet-ready page
|
|
510
531
|
return;
|
|
511
532
|
}
|
|
512
533
|
case "serve": {
|
|
@@ -553,6 +574,17 @@ function summarize(payload) {
|
|
|
553
574
|
const s = JSON.stringify(payload);
|
|
554
575
|
return s.length > 80 ? s.slice(0, 77) + "..." : s;
|
|
555
576
|
}
|
|
577
|
+
/** Print the dashboard URL and, when run interactively on macOS, open it. */
|
|
578
|
+
function announceDashboard(port, open = true) {
|
|
579
|
+
const url = `http://127.0.0.1:${port}`;
|
|
580
|
+
console.log(`Dashboard: ${url}`);
|
|
581
|
+
if (open && process.platform === "darwin" && process.stdout.isTTY) {
|
|
582
|
+
try {
|
|
583
|
+
execFileSync("open", [url]);
|
|
584
|
+
}
|
|
585
|
+
catch { /* non-fatal — the link is printed above */ }
|
|
586
|
+
}
|
|
587
|
+
}
|
|
556
588
|
function die(msg) {
|
|
557
589
|
console.error(msg);
|
|
558
590
|
process.exit(1);
|
package/build/src/lifecycle.d.ts
CHANGED
|
@@ -12,3 +12,13 @@ export declare function stopDaemon(): Promise<number | null>;
|
|
|
12
12
|
export declare function autostartInstalled(): boolean;
|
|
13
13
|
export declare function installAutostart(cliPath: string, port: number): string;
|
|
14
14
|
export declare function removeAutostart(): boolean;
|
|
15
|
+
/**
|
|
16
|
+
* Reload the launchd job so the daemon restarts on the currently-installed build.
|
|
17
|
+
* `unload` then `load` — a plain `load` can't replace an already-loaded job, which
|
|
18
|
+
* is how a plist path silently drifts from the running process. Rewriting from the
|
|
19
|
+
* caller's cliPath also heals that drift. Returns the new daemon's /health once it
|
|
20
|
+
* answers, or null if it didn't come up in time.
|
|
21
|
+
*/
|
|
22
|
+
export declare function reloadAutostart(cliPath: string, port: number): Promise<{
|
|
23
|
+
version: string;
|
|
24
|
+
} | null>;
|
package/build/src/lifecycle.js
CHANGED
|
@@ -118,6 +118,27 @@ export function removeAutostart() {
|
|
|
118
118
|
rmSync(PLIST_PATH);
|
|
119
119
|
return true;
|
|
120
120
|
}
|
|
121
|
+
/**
|
|
122
|
+
* Reload the launchd job so the daemon restarts on the currently-installed build.
|
|
123
|
+
* `unload` then `load` — a plain `load` can't replace an already-loaded job, which
|
|
124
|
+
* is how a plist path silently drifts from the running process. Rewriting from the
|
|
125
|
+
* caller's cliPath also heals that drift. Returns the new daemon's /health once it
|
|
126
|
+
* answers, or null if it didn't come up in time.
|
|
127
|
+
*/
|
|
128
|
+
export async function reloadAutostart(cliPath, port) {
|
|
129
|
+
removeAutostart();
|
|
130
|
+
installAutostart(cliPath, port);
|
|
131
|
+
for (let i = 0; i < 30; i++) {
|
|
132
|
+
await sleep(100);
|
|
133
|
+
try {
|
|
134
|
+
const r = await fetch(`http://127.0.0.1:${port}/health`);
|
|
135
|
+
if (r.ok)
|
|
136
|
+
return (await r.json());
|
|
137
|
+
}
|
|
138
|
+
catch { /* launchd hasn't brought it up yet */ }
|
|
139
|
+
}
|
|
140
|
+
return null;
|
|
141
|
+
}
|
|
121
142
|
function sleep(ms) {
|
|
122
143
|
return new Promise((r) => setTimeout(r, ms));
|
|
123
144
|
}
|