persnally 2.1.0 → 2.2.0
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 +18 -0
- package/build/src/daemon.js +4 -0
- package/build/src/dashboard.html +593 -137
- package/build/src/events.d.ts +24 -0
- package/build/src/events.js +10 -0
- package/build/src/importers/extract.js +12 -1
- package/build/src/mcp/index.js +48 -29
- package/build/src/prose.d.ts +10 -0
- package/build/src/prose.js +34 -0
- package/build/src/store.d.ts +8 -0
- package/build/src/store.js +22 -0
- package/build/src/stylometry.d.ts +21 -0
- package/build/src/stylometry.js +124 -0
- package/package.json +1 -1
package/build/src/cli.js
CHANGED
|
@@ -20,6 +20,8 @@ import { DEFAULT_TRANSCRIPTS_DIR, extractClaudeCodeEvents, parseClaudeCodeTransc
|
|
|
20
20
|
import { gitEvents, scanRepos } from "./importers/git.js";
|
|
21
21
|
import { autostartInstalled, installAutostart, LOG_FILE, removeAutostart, removePidFile, runningPid, startDetached, stopDaemon, writePidFile, } from "./lifecycle.js";
|
|
22
22
|
import { newEvent } from "./events.js";
|
|
23
|
+
import { proseLines } from "./prose.js";
|
|
24
|
+
import { analyzeVoice } from "./stylometry.js";
|
|
23
25
|
import { renderProfile, synthesizeProfile } from "./profile.js";
|
|
24
26
|
import { DEFAULT_DB_PATH, EventStore } from "./store.js";
|
|
25
27
|
const USAGE = `persnallyd ${VERSION} — so every AI finally knows you
|
|
@@ -35,6 +37,7 @@ Usage:
|
|
|
35
37
|
persnallyd import chatgpt <path> Import a ChatGPT export dir or conversations.json (needs ANTHROPIC_API_KEY)
|
|
36
38
|
persnallyd import git <path> [--author <email>] Import repo activity (offline, no LLM); path = repo or folder of repos
|
|
37
39
|
persnallyd profile Synthesize your profile from the store
|
|
40
|
+
persnallyd voice Refresh your voice fingerprint from Claude Code transcripts (offline, no LLM)
|
|
38
41
|
persnallyd consolidate Reflect now: refresh decay, add behavior patterns, re-synthesize
|
|
39
42
|
persnallyd show [topics|events|profile] Show topics (default), recent events, or the profile
|
|
40
43
|
persnallyd context [--full] Emit profile + interests for AI injection (records a context read)
|
|
@@ -303,6 +306,21 @@ async function main() {
|
|
|
303
306
|
console.log(renderProfile(profile));
|
|
304
307
|
return;
|
|
305
308
|
}
|
|
309
|
+
case "voice": {
|
|
310
|
+
// Deterministic, offline, re-runnable — refreshes the stylometry layer in place.
|
|
311
|
+
const dir = args[0] || DEFAULT_TRANSCRIPTS_DIR;
|
|
312
|
+
const { parsed } = parseClaudeCodeTranscripts(dir);
|
|
313
|
+
const corpus = parsed.conversations.flatMap((c) => proseLines(c.userMessages.join("\n")));
|
|
314
|
+
const v = analyzeVoice(corpus);
|
|
315
|
+
if (!v.signals.length)
|
|
316
|
+
return die(`Not enough prose in ${dir} to fingerprint a voice yet.`);
|
|
317
|
+
const store = new EventStore();
|
|
318
|
+
store.clearStyleByBasis("stylometry"); // replace, don't accumulate, across re-runs
|
|
319
|
+
store.append(v.signals.map((s) => newEvent("signal.style", "cli", s, { kind: "local", surface: "cli" })));
|
|
320
|
+
store.close();
|
|
321
|
+
console.log(`Voice fingerprint refreshed from ${v.prompts} prompts.\n\n${v.pack}`);
|
|
322
|
+
return;
|
|
323
|
+
}
|
|
306
324
|
case "show": {
|
|
307
325
|
const store = new EventStore();
|
|
308
326
|
if (args[0] === "profile") {
|
package/build/src/daemon.js
CHANGED
|
@@ -58,6 +58,10 @@ export function startDaemon(store, port = DEFAULT_PORT) {
|
|
|
58
58
|
const profile = store.getProfile();
|
|
59
59
|
return profile ? json(res, 200, profile) : json(res, 404, { error: "no profile synthesized yet" });
|
|
60
60
|
}
|
|
61
|
+
if (req.method === "GET" && url.pathname === "/voice") {
|
|
62
|
+
// Stylistic, not topical — served to every client (it's how you write, not what about).
|
|
63
|
+
return json(res, 200, store.voice());
|
|
64
|
+
}
|
|
61
65
|
if (req.method === "GET" && url.pathname === "/scopes") {
|
|
62
66
|
return json(res, 200, loadScopes());
|
|
63
67
|
}
|