holomime 1.4.1 → 1.5.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/dist/cli.js CHANGED
@@ -1942,7 +1942,7 @@ async function getJobEvents(apiKey, jobId, limit = 5) {
1942
1942
  return data.data ?? [];
1943
1943
  }
1944
1944
  function sleep(ms) {
1945
- return new Promise((resolve45) => setTimeout(resolve45, ms));
1945
+ return new Promise((resolve46) => setTimeout(resolve46, ms));
1946
1946
  }
1947
1947
  var OPENAI_API, POLL_INTERVAL_MS, OpenAITrainProvider;
1948
1948
  var init_train_openai = __esm({
@@ -2100,7 +2100,7 @@ function writeHFTrainingFile(data) {
2100
2100
  return filePath;
2101
2101
  }
2102
2102
  function sleep2(ms) {
2103
- return new Promise((resolve45) => setTimeout(resolve45, ms));
2103
+ return new Promise((resolve46) => setTimeout(resolve46, ms));
2104
2104
  }
2105
2105
  async function getHFUsername(token) {
2106
2106
  const response = await fetch(`${HF_API}/whoami-v2`, {
@@ -3098,7 +3098,7 @@ var init_vapi_adapter = __esm({
3098
3098
  this.callbacks = callbacks;
3099
3099
  const port = this.options.port ?? 3001;
3100
3100
  const host = this.options.host ?? "0.0.0.0";
3101
- return new Promise((resolve45, reject) => {
3101
+ return new Promise((resolve46, reject) => {
3102
3102
  this.server = createServer2((req, res) => this.handleRequest(req, res));
3103
3103
  this.server.on("error", (err) => {
3104
3104
  callbacks.onError(`Vapi webhook server error: ${err.message}`);
@@ -3107,22 +3107,22 @@ var init_vapi_adapter = __esm({
3107
3107
  this.server.listen(port, host, () => {
3108
3108
  this.connected = true;
3109
3109
  callbacks.onConnected?.();
3110
- resolve45();
3110
+ resolve46();
3111
3111
  });
3112
3112
  });
3113
3113
  }
3114
3114
  async disconnect() {
3115
- return new Promise((resolve45) => {
3115
+ return new Promise((resolve46) => {
3116
3116
  if (this.server) {
3117
3117
  this.server.close(() => {
3118
3118
  this.connected = false;
3119
3119
  this.callbacks?.onDisconnected?.();
3120
3120
  this.callbacks = null;
3121
3121
  this.server = null;
3122
- resolve45();
3122
+ resolve46();
3123
3123
  });
3124
3124
  } else {
3125
- resolve45();
3125
+ resolve46();
3126
3126
  }
3127
3127
  });
3128
3128
  }
@@ -3439,7 +3439,7 @@ import boxen from "boxen";
3439
3439
  import { readFileSync, writeFileSync, existsSync, mkdirSync } from "fs";
3440
3440
  import { join } from "path";
3441
3441
  import { homedir } from "os";
3442
- var PRO_COMMANDS = ["session", "growth", "autopilot", "export", "train", "eval", "evolve", "benchmark", "watch", "certify", "daemon", "fleet", "network", "share", "prescribe", "voice", "cure"];
3442
+ var PRO_COMMANDS = ["session", "growth", "autopilot", "export", "train", "eval", "evolve", "benchmark", "watch", "certify", "daemon", "fleet", "network", "share", "prescribe", "voice", "cure", "brain"];
3443
3443
  function requiresPro(command) {
3444
3444
  return PRO_COMMANDS.includes(command);
3445
3445
  }
@@ -6432,7 +6432,7 @@ async function diagnoseCommand(options) {
6432
6432
  }
6433
6433
  let conversations;
6434
6434
  try {
6435
- conversations = parseConversationLog(JSON.parse(raw), options.format ?? "auto");
6435
+ conversations = parseConversationLogFromString(raw, options.format ?? "auto");
6436
6436
  } catch (err) {
6437
6437
  console.error(chalk10.red(` ${err instanceof Error ? err.message : "Invalid conversation log format."}`));
6438
6438
  process.exit(1);
@@ -6677,7 +6677,7 @@ async function assessCommand(options) {
6677
6677
  let conversations;
6678
6678
  try {
6679
6679
  const raw = readFileSync4(logPath, "utf-8");
6680
- conversations = parseConversationLog(JSON.parse(raw), options.format ?? "auto");
6680
+ conversations = parseConversationLogFromString(raw, options.format ?? "auto");
6681
6681
  } catch (err) {
6682
6682
  console.error(chalk11.red(` ${err instanceof Error ? err.message : "Could not read/parse log file."}`));
6683
6683
  process.exit(1);
@@ -8689,7 +8689,7 @@ function parseRetryAfter(response) {
8689
8689
  return 0;
8690
8690
  }
8691
8691
  function delay(ms) {
8692
- return new Promise((resolve45) => setTimeout(resolve45, ms));
8692
+ return new Promise((resolve46) => setTimeout(resolve46, ms));
8693
8693
  }
8694
8694
  var OpenAIProvider = class {
8695
8695
  name = "openai";
@@ -8988,19 +8988,19 @@ async function runLiveSession(spec, diagnosis, provider, maxTurns, apply, intera
8988
8988
  onSupervisorPrompt: interactive ? async (phase, turn) => {
8989
8989
  if (skipInteractive) return null;
8990
8990
  const rl = createInterface({ input: process.stdin, output: process.stdout });
8991
- return new Promise((resolve45) => {
8991
+ return new Promise((resolve46) => {
8992
8992
  rl.question(chalk14.magenta(`
8993
8993
  [Supervisor] `) + chalk14.dim(`(phase: ${phase}, turn ${turn}) `) + chalk14.magenta(`> `), (answer) => {
8994
8994
  rl.close();
8995
8995
  const trimmed = answer.trim();
8996
- if (trimmed === "") return resolve45(null);
8996
+ if (trimmed === "") return resolve46(null);
8997
8997
  if (trimmed.toLowerCase() === "skip") {
8998
8998
  skipInteractive = true;
8999
8999
  console.log(chalk14.dim(" Supervisor mode disabled for remaining session."));
9000
- return resolve45(null);
9000
+ return resolve46(null);
9001
9001
  }
9002
9002
  console.log(chalk14.dim(` Directive injected into session context.`));
9003
- return resolve45(trimmed);
9003
+ return resolve46(trimmed);
9004
9004
  });
9005
9005
  });
9006
9006
  } : void 0
@@ -14209,14 +14209,14 @@ var ROS2Adapter = class {
14209
14209
  });
14210
14210
  }
14211
14211
  async connect() {
14212
- return new Promise((resolve45, reject) => {
14212
+ return new Promise((resolve46, reject) => {
14213
14213
  try {
14214
14214
  this.ws = this.createWebSocket(this.endpoint);
14215
14215
  this.ws.onopen = () => {
14216
14216
  this.connected = true;
14217
14217
  this.reconnectAttempts = 0;
14218
14218
  this.advertiseTopics();
14219
- resolve45();
14219
+ resolve46();
14220
14220
  };
14221
14221
  this.ws.onclose = () => {
14222
14222
  this.connected = false;
@@ -14333,12 +14333,12 @@ var UnityAdapter = class {
14333
14333
  this.defaultTransition = options.defaultTransition ?? DEFAULT_TRANSITION;
14334
14334
  }
14335
14335
  async connect() {
14336
- return new Promise((resolve45, reject) => {
14336
+ return new Promise((resolve46, reject) => {
14337
14337
  try {
14338
14338
  this.server = createServer((req, res) => this.handleRequest(req, res));
14339
14339
  this.server.listen(this.port, this.host, () => {
14340
14340
  this.connected = true;
14341
- resolve45();
14341
+ resolve46();
14342
14342
  });
14343
14343
  this.server.on("error", (err) => {
14344
14344
  if (!this.connected) {
@@ -14356,8 +14356,8 @@ var UnityAdapter = class {
14356
14356
  }
14357
14357
  this.sseClients.clear();
14358
14358
  if (this.server) {
14359
- await new Promise((resolve45) => {
14360
- this.server.close(() => resolve45());
14359
+ await new Promise((resolve46) => {
14360
+ this.server.close(() => resolve46());
14361
14361
  });
14362
14362
  this.server = null;
14363
14363
  }
@@ -14558,7 +14558,7 @@ var WebhookAdapter = class {
14558
14558
  }
14559
14559
  if (attempt < this.maxRetries) {
14560
14560
  const delay2 = this.retryDelay * Math.pow(2, attempt);
14561
- await new Promise((resolve45) => setTimeout(resolve45, delay2));
14561
+ await new Promise((resolve46) => setTimeout(resolve46, delay2));
14562
14562
  }
14563
14563
  }
14564
14564
  throw lastError ?? new Error("Webhook push failed after retries");
@@ -15527,8 +15527,8 @@ async function runPipeline(options) {
15527
15527
  const exportsDir = resolve43(process.cwd(), ".holomime/exports");
15528
15528
  if (existsSync30(exportsDir)) {
15529
15529
  try {
15530
- const { readdirSync: readdirSync10 } = await import("fs");
15531
- const files = readdirSync10(exportsDir).filter((f) => f.endsWith(".json") || f.endsWith(".jsonl")).sort().reverse();
15530
+ const { readdirSync: readdirSync11 } = await import("fs");
15531
+ const files = readdirSync11(exportsDir).filter((f) => f.endsWith(".json") || f.endsWith(".jsonl")).sort().reverse();
15532
15532
  if (files.length > 0 && exportData.examples.length === 0) {
15533
15533
  const latestPath = join27(exportsDir, files[0]);
15534
15534
  const latestData = JSON.parse(readFileSync36(latestPath, "utf-8"));
@@ -15891,6 +15891,549 @@ Intermediate results saved to ${chalk39.cyan(".holomime/pipeline/")}`,
15891
15891
  }
15892
15892
  }
15893
15893
 
15894
+ // src/commands/live.ts
15895
+ import chalk40 from "chalk";
15896
+
15897
+ // src/live/agent-detector.ts
15898
+ import { existsSync as existsSync32, readdirSync as readdirSync10, statSync } from "fs";
15899
+ import { join as join28, resolve as resolve45 } from "path";
15900
+ import { homedir as homedir7 } from "os";
15901
+ var RECENCY_THRESHOLD_MS = 12e4;
15902
+ function findNewestFile(baseDir, extensions, maxDepth = 3, depth = 0) {
15903
+ if (depth > maxDepth) return null;
15904
+ if (!existsSync32(baseDir)) return null;
15905
+ let best = null;
15906
+ try {
15907
+ const entries = readdirSync10(baseDir);
15908
+ for (const entry of entries) {
15909
+ if (entry.startsWith(".")) continue;
15910
+ const fullPath = join28(baseDir, entry);
15911
+ try {
15912
+ const stat = statSync(fullPath);
15913
+ if (stat.isDirectory()) {
15914
+ const sub = findNewestFile(fullPath, extensions, maxDepth, depth + 1);
15915
+ if (sub && (!best || sub.mtimeMs > best.mtimeMs)) {
15916
+ best = sub;
15917
+ }
15918
+ } else if (extensions.some((ext) => entry.endsWith(ext))) {
15919
+ if (!best || stat.mtimeMs > best.mtimeMs) {
15920
+ best = { path: fullPath, mtimeMs: stat.mtimeMs };
15921
+ }
15922
+ }
15923
+ } catch {
15924
+ continue;
15925
+ }
15926
+ }
15927
+ } catch {
15928
+ return null;
15929
+ }
15930
+ return best;
15931
+ }
15932
+ function isRecent(mtimeMs) {
15933
+ return Date.now() - mtimeMs <= RECENCY_THRESHOLD_MS;
15934
+ }
15935
+ function findClaudeCodeSession() {
15936
+ const claudeDir = join28(homedir7(), ".claude", "projects");
15937
+ const result = findNewestFile(claudeDir, [".jsonl"], 2);
15938
+ if (!result || !isRecent(result.mtimeMs)) return null;
15939
+ return {
15940
+ agent: "claude-code",
15941
+ logPath: result.path,
15942
+ format: "jsonl"
15943
+ };
15944
+ }
15945
+ function findClineSession() {
15946
+ const searchDirs = [
15947
+ join28(process.cwd(), ".cline", "tasks"),
15948
+ join28(homedir7(), ".cline", "tasks")
15949
+ ];
15950
+ for (const tasksDir of searchDirs) {
15951
+ const result = findNewestFile(tasksDir, [".json", ".jsonl"], 2);
15952
+ if (result && isRecent(result.mtimeMs)) {
15953
+ return {
15954
+ agent: "cline",
15955
+ logPath: result.path,
15956
+ format: "auto"
15957
+ };
15958
+ }
15959
+ }
15960
+ return null;
15961
+ }
15962
+ function findCodexSession() {
15963
+ const codexDir = join28(homedir7(), ".codex", "sessions");
15964
+ const result = findNewestFile(codexDir, [".jsonl"], 4);
15965
+ if (!result || !isRecent(result.mtimeMs)) return null;
15966
+ return {
15967
+ agent: "codex",
15968
+ logPath: result.path,
15969
+ format: "jsonl"
15970
+ };
15971
+ }
15972
+ function findCursorSession() {
15973
+ const cursorProjects = join28(homedir7(), ".cursor", "projects");
15974
+ const result = findNewestFile(cursorProjects, [".json", ".jsonl"], 3);
15975
+ if (result && isRecent(result.mtimeMs)) {
15976
+ return {
15977
+ agent: "cursor",
15978
+ logPath: result.path,
15979
+ format: "auto"
15980
+ };
15981
+ }
15982
+ return null;
15983
+ }
15984
+ function detectAgent() {
15985
+ const claudeCode = findClaudeCodeSession();
15986
+ if (claudeCode) return claudeCode;
15987
+ const cline = findClineSession();
15988
+ if (cline) return cline;
15989
+ const codex = findCodexSession();
15990
+ if (codex) return codex;
15991
+ const cursor = findCursorSession();
15992
+ if (cursor) return cursor;
15993
+ return null;
15994
+ }
15995
+ function manualAgent(watchPath) {
15996
+ const resolved = resolve45(watchPath);
15997
+ return {
15998
+ agent: "manual",
15999
+ logPath: resolved,
16000
+ format: "auto"
16001
+ };
16002
+ }
16003
+
16004
+ // src/live/watcher.ts
16005
+ init_log_adapter();
16006
+ init_diagnose_core();
16007
+ import { watch } from "chokidar";
16008
+ import { createReadStream as createReadStream2, statSync as statSync2 } from "fs";
16009
+ import { createInterface as createInterface5 } from "readline";
16010
+
16011
+ // src/live/brain-mapper.ts
16012
+ var BRAIN_REGIONS = [
16013
+ {
16014
+ id: "prefrontal-cortex",
16015
+ name: "Prefrontal Cortex",
16016
+ function: "Executive Decisions",
16017
+ color: "#4488ff",
16018
+ detectors: ["boundary-violation", "over-verbose"]
16019
+ },
16020
+ {
16021
+ id: "brocas-area",
16022
+ name: "Broca's Area",
16023
+ function: "Language Generation",
16024
+ color: "#aa66ff",
16025
+ detectors: ["register-inconsistency", "hedge-stacking"]
16026
+ },
16027
+ {
16028
+ id: "wernickes-area",
16029
+ name: "Wernicke's Area",
16030
+ function: "Language Comprehension",
16031
+ color: "#ff66bb",
16032
+ detectors: ["sycophantic-tendency", "negative-skew"]
16033
+ },
16034
+ {
16035
+ id: "amygdala",
16036
+ name: "Amygdala",
16037
+ function: "Emotional Processing",
16038
+ color: "#ff5555",
16039
+ detectors: ["over-apologizing", "negative-skew"]
16040
+ },
16041
+ {
16042
+ id: "anterior-cingulate",
16043
+ name: "Anterior Cingulate",
16044
+ function: "Conflict Monitoring",
16045
+ color: "#ffcc22",
16046
+ detectors: ["sycophantic-tendency", "boundary-violation"]
16047
+ },
16048
+ {
16049
+ id: "hippocampus",
16050
+ name: "Hippocampus",
16051
+ function: "Memory & Context",
16052
+ color: "#44dd88",
16053
+ detectors: ["error-spiral"]
16054
+ },
16055
+ {
16056
+ id: "temporal-lobe",
16057
+ name: "Temporal Lobe",
16058
+ function: "Understanding & Tone",
16059
+ color: "#44dd88",
16060
+ detectors: ["negative-skew", "register-inconsistency"]
16061
+ },
16062
+ {
16063
+ id: "cerebellum",
16064
+ name: "Cerebellum",
16065
+ function: "Behavioral Fine-Tuning",
16066
+ color: "#22ccaa",
16067
+ detectors: ["register-inconsistency", "over-verbose"]
16068
+ },
16069
+ {
16070
+ id: "thalamus",
16071
+ name: "Thalamus",
16072
+ function: "Relay Hub",
16073
+ color: "#ff8844",
16074
+ detectors: []
16075
+ // activated by overall health, not specific detectors
16076
+ }
16077
+ ];
16078
+ var SEVERITY_INTENSITY = {
16079
+ info: 0.1,
16080
+ warning: 0.6,
16081
+ concern: 1
16082
+ };
16083
+ var AMBIENT_INTENSITY = 0.08;
16084
+ function healthToGrade(health) {
16085
+ if (health >= 85) return "A";
16086
+ if (health >= 70) return "B";
16087
+ if (health >= 50) return "C";
16088
+ if (health >= 30) return "D";
16089
+ return "F";
16090
+ }
16091
+ function calculateHealth(patterns) {
16092
+ if (patterns.length === 0) return 100;
16093
+ const penalties = patterns.map((p) => {
16094
+ if (p.severity === "concern") return 25;
16095
+ if (p.severity === "warning") return 15;
16096
+ return 5;
16097
+ });
16098
+ return Math.max(0, 100 - penalties.reduce((a, b) => a + b, 0));
16099
+ }
16100
+ function mapDiagnosisToBrainEvent(diagnosis, latestMessage) {
16101
+ const activePatternIds = new Set(diagnosis.patterns.map((p) => p.id));
16102
+ const regions = BRAIN_REGIONS.map((region) => {
16103
+ const activatingPatterns = region.detectors.filter((d) => activePatternIds.has(d));
16104
+ let intensity = AMBIENT_INTENSITY;
16105
+ if (activatingPatterns.length > 0) {
16106
+ const maxIntensity = Math.max(
16107
+ ...activatingPatterns.map((pid) => {
16108
+ const pattern = diagnosis.patterns.find((p) => p.id === pid);
16109
+ return pattern ? SEVERITY_INTENSITY[pattern.severity] || 0.3 : 0.3;
16110
+ })
16111
+ );
16112
+ intensity = maxIntensity;
16113
+ }
16114
+ if (region.id === "thalamus") {
16115
+ const health2 = calculateHealth(diagnosis.patterns);
16116
+ intensity = health2 < 70 ? (100 - health2) / 100 : AMBIENT_INTENSITY;
16117
+ }
16118
+ return {
16119
+ id: region.id,
16120
+ name: region.name,
16121
+ function: region.function,
16122
+ color: region.color,
16123
+ intensity,
16124
+ patterns: activatingPatterns
16125
+ };
16126
+ });
16127
+ const patterns = diagnosis.patterns.map((p) => ({
16128
+ id: p.id,
16129
+ name: p.name,
16130
+ severity: p.severity,
16131
+ percentage: p.percentage,
16132
+ description: p.description
16133
+ }));
16134
+ const health = calculateHealth(diagnosis.patterns);
16135
+ return {
16136
+ type: "diagnosis",
16137
+ timestamp: diagnosis.timestamp,
16138
+ health,
16139
+ grade: healthToGrade(health),
16140
+ messageCount: diagnosis.messagesAnalyzed,
16141
+ regions,
16142
+ patterns,
16143
+ activity: latestMessage ? {
16144
+ role: latestMessage.role,
16145
+ preview: latestMessage.content.slice(0, 80)
16146
+ } : null
16147
+ };
16148
+ }
16149
+
16150
+ // src/live/watcher.ts
16151
+ function startWatcher(agent, callbacks) {
16152
+ const { logPath, format } = agent;
16153
+ let byteOffset = 0;
16154
+ let allMessages = [];
16155
+ let debounceTimer = null;
16156
+ let fsWatcher = null;
16157
+ try {
16158
+ const stat = statSync2(logPath);
16159
+ byteOffset = stat.size;
16160
+ } catch {
16161
+ byteOffset = 0;
16162
+ }
16163
+ initialRead().then(() => {
16164
+ fsWatcher = watch(logPath, {
16165
+ persistent: true,
16166
+ awaitWriteFinish: {
16167
+ stabilityThreshold: 100,
16168
+ pollInterval: 50
16169
+ }
16170
+ });
16171
+ fsWatcher.on("change", () => {
16172
+ if (debounceTimer) clearTimeout(debounceTimer);
16173
+ debounceTimer = setTimeout(() => {
16174
+ readNewLines().catch((err) => {
16175
+ callbacks.onError?.(err instanceof Error ? err : new Error(String(err)));
16176
+ });
16177
+ }, 100);
16178
+ });
16179
+ fsWatcher.on("error", (err) => {
16180
+ callbacks.onError?.(err instanceof Error ? err : new Error(String(err)));
16181
+ });
16182
+ callbacks.onReady?.();
16183
+ }).catch((err) => {
16184
+ callbacks.onError?.(err instanceof Error ? err : new Error(String(err)));
16185
+ });
16186
+ async function initialRead() {
16187
+ const content = await readFile(logPath, 0);
16188
+ if (!content) return;
16189
+ try {
16190
+ const conversations = parseConversationLogFromString(
16191
+ content,
16192
+ format === "auto" ? "auto" : format
16193
+ );
16194
+ allMessages = conversations.flatMap((c) => c.messages);
16195
+ } catch {
16196
+ }
16197
+ }
16198
+ async function readNewLines() {
16199
+ let currentSize;
16200
+ try {
16201
+ const stat = statSync2(logPath);
16202
+ currentSize = stat.size;
16203
+ } catch {
16204
+ return;
16205
+ }
16206
+ if (currentSize < byteOffset) {
16207
+ byteOffset = 0;
16208
+ allMessages = [];
16209
+ }
16210
+ if (currentSize === byteOffset) return;
16211
+ const newContent = await readFile(logPath, byteOffset);
16212
+ byteOffset = currentSize;
16213
+ if (!newContent || !newContent.trim()) return;
16214
+ try {
16215
+ const conversations = parseConversationLogFromString(
16216
+ newContent,
16217
+ format === "auto" ? "auto" : format
16218
+ );
16219
+ const newMessages = conversations.flatMap((c) => c.messages);
16220
+ if (newMessages.length === 0) return;
16221
+ allMessages = [...allMessages, ...newMessages];
16222
+ const lastNew = newMessages[newMessages.length - 1];
16223
+ const latestMessage = lastNew.role !== "system" ? { role: lastNew.role, content: lastNew.content } : void 0;
16224
+ const diagnosis = runDiagnosis(allMessages);
16225
+ const brainEvent = mapDiagnosisToBrainEvent(diagnosis, latestMessage);
16226
+ callbacks.onEvent(brainEvent);
16227
+ } catch {
16228
+ }
16229
+ }
16230
+ return {
16231
+ stop() {
16232
+ if (debounceTimer) clearTimeout(debounceTimer);
16233
+ if (fsWatcher) {
16234
+ fsWatcher.close();
16235
+ fsWatcher = null;
16236
+ }
16237
+ }
16238
+ };
16239
+ }
16240
+ function readFile(filePath, startByte) {
16241
+ return new Promise((resolve46, reject) => {
16242
+ const chunks = [];
16243
+ const stream = createReadStream2(filePath, {
16244
+ start: startByte,
16245
+ encoding: "utf-8"
16246
+ });
16247
+ const rl = createInterface5({ input: stream, crlfDelay: Infinity });
16248
+ rl.on("line", (line) => {
16249
+ chunks.push(line);
16250
+ });
16251
+ rl.on("close", () => {
16252
+ resolve46(chunks.join("\n"));
16253
+ });
16254
+ rl.on("error", reject);
16255
+ stream.on("error", reject);
16256
+ });
16257
+ }
16258
+
16259
+ // src/live/server.ts
16260
+ import { createServer as createServer3 } from "http";
16261
+ import { readFileSync as readFileSync38, existsSync as existsSync33 } from "fs";
16262
+ import { join as join29, extname } from "path";
16263
+ import { fileURLToPath as fileURLToPath2 } from "url";
16264
+ import { WebSocketServer } from "ws";
16265
+ var __bundleDir = fileURLToPath2(new URL(".", import.meta.url));
16266
+ var MIME_TYPES = {
16267
+ ".html": "text/html",
16268
+ ".js": "application/javascript",
16269
+ ".css": "text/css",
16270
+ ".json": "application/json",
16271
+ ".svg": "image/svg+xml",
16272
+ ".png": "image/png",
16273
+ ".ico": "image/x-icon"
16274
+ };
16275
+ function startServer(port) {
16276
+ const staticDir = join29(__bundleDir, "neuralspace");
16277
+ const clients = /* @__PURE__ */ new Set();
16278
+ let lastEvent = null;
16279
+ let initMessage = null;
16280
+ return new Promise((resolve46, reject) => {
16281
+ const server = createServer3((req, res) => {
16282
+ const url = req.url === "/" ? "/index.html" : req.url || "/index.html";
16283
+ const filePath = join29(staticDir, url);
16284
+ if (!existsSync33(filePath)) {
16285
+ res.writeHead(404, { "Content-Type": "text/plain" });
16286
+ res.end("Not found");
16287
+ return;
16288
+ }
16289
+ const ext = extname(filePath);
16290
+ const contentType = MIME_TYPES[ext] || "application/octet-stream";
16291
+ try {
16292
+ const content = readFileSync38(filePath);
16293
+ res.writeHead(200, {
16294
+ "Content-Type": contentType,
16295
+ "Cache-Control": "no-cache"
16296
+ });
16297
+ res.end(content);
16298
+ } catch {
16299
+ res.writeHead(500, { "Content-Type": "text/plain" });
16300
+ res.end("Internal server error");
16301
+ }
16302
+ });
16303
+ const wss = new WebSocketServer({ server });
16304
+ wss.on("connection", (ws) => {
16305
+ clients.add(ws);
16306
+ if (initMessage) {
16307
+ ws.send(JSON.stringify(initMessage));
16308
+ }
16309
+ if (lastEvent) {
16310
+ ws.send(JSON.stringify(lastEvent));
16311
+ }
16312
+ ws.on("close", () => {
16313
+ clients.delete(ws);
16314
+ });
16315
+ ws.on("error", () => {
16316
+ clients.delete(ws);
16317
+ });
16318
+ });
16319
+ server.on("error", (err) => {
16320
+ if (err.code === "EADDRINUSE") {
16321
+ reject(new Error(`Port ${port} is already in use. Try --port <number>`));
16322
+ } else {
16323
+ reject(err);
16324
+ }
16325
+ });
16326
+ server.listen(port, () => {
16327
+ resolve46({
16328
+ port,
16329
+ broadcast(event) {
16330
+ if (event.type === "init") {
16331
+ initMessage = event;
16332
+ } else {
16333
+ lastEvent = event;
16334
+ }
16335
+ const data = JSON.stringify(event);
16336
+ for (const client2 of clients) {
16337
+ if (client2.readyState === 1) {
16338
+ client2.send(data);
16339
+ }
16340
+ }
16341
+ },
16342
+ close() {
16343
+ for (const client2 of clients) {
16344
+ client2.close();
16345
+ }
16346
+ clients.clear();
16347
+ wss.close();
16348
+ server.close();
16349
+ }
16350
+ });
16351
+ });
16352
+ });
16353
+ }
16354
+
16355
+ // src/commands/live.ts
16356
+ async function liveCommand(options) {
16357
+ const port = options.port || 3838;
16358
+ let agent;
16359
+ if (options.watchPath) {
16360
+ agent = manualAgent(options.watchPath);
16361
+ console.log(chalk40.green(" \u2713") + ` Manual watch: ${chalk40.dim(agent.logPath)}`);
16362
+ } else {
16363
+ console.log(chalk40.dim(" Scanning for active agents..."));
16364
+ agent = detectAgent();
16365
+ if (!agent) {
16366
+ console.log("");
16367
+ console.log(chalk40.red(" \u2717 No active agent detected."));
16368
+ console.log("");
16369
+ console.log(chalk40.dim(" Make sure an AI coding agent is running, or specify a path:"));
16370
+ console.log(chalk40.cyan(" holomime brain --watch <path-to-conversation-log>"));
16371
+ console.log("");
16372
+ console.log(chalk40.dim(" Supported agents: Claude Code, Cline, OpenClaw, Codex, Cursor"));
16373
+ process.exit(1);
16374
+ }
16375
+ console.log(chalk40.green(" \u2713") + ` Detected ${chalk40.bold(agent.agent)} session`);
16376
+ console.log(chalk40.green(" \u2713") + ` Watching: ${chalk40.dim(agent.logPath)}`);
16377
+ }
16378
+ let server;
16379
+ try {
16380
+ server = await startServer(port);
16381
+ console.log(chalk40.green(" \u2713") + ` NeuralSpace: ${chalk40.cyan(`http://localhost:${server.port}`)}`);
16382
+ } catch (err) {
16383
+ console.log(chalk40.red(` \u2717 ${err.message}`));
16384
+ process.exit(1);
16385
+ }
16386
+ server.broadcast({
16387
+ type: "init",
16388
+ agent: agent.agent,
16389
+ sessionPath: agent.logPath,
16390
+ startedAt: (/* @__PURE__ */ new Date()).toISOString()
16391
+ });
16392
+ if (!options.noOpen) {
16393
+ try {
16394
+ const open = (await import("open")).default;
16395
+ await open(`http://localhost:${server.port}`);
16396
+ console.log(chalk40.dim(" Opening browser..."));
16397
+ } catch {
16398
+ }
16399
+ }
16400
+ let lastHealth = 100;
16401
+ let lastPatternCount = 0;
16402
+ let msgCount = 0;
16403
+ const watcher = startWatcher(agent, {
16404
+ onEvent(event) {
16405
+ server.broadcast(event);
16406
+ msgCount = event.messageCount;
16407
+ lastHealth = event.health;
16408
+ lastPatternCount = event.patterns.length;
16409
+ const healthColor = event.health >= 85 ? chalk40.green : event.health >= 70 ? chalk40.yellow : event.health >= 50 ? chalk40.hex("#f97316") : chalk40.red;
16410
+ const patternStr = event.patterns.length > 0 ? event.patterns.map((p) => {
16411
+ const c = p.severity === "concern" ? chalk40.red : p.severity === "warning" ? chalk40.yellow : chalk40.dim;
16412
+ return c(p.id);
16413
+ }).join(", ") : chalk40.green("none");
16414
+ process.stdout.write(`\r ${chalk40.dim("\u2502")} Health: ${healthColor(`${event.health}/100`)} (${event.grade}) ${chalk40.dim("\u2502")} Patterns: ${patternStr} ${chalk40.dim("\u2502")} Messages: ${chalk40.white(String(msgCount))} `);
16415
+ },
16416
+ onError(err) {
16417
+ console.error(chalk40.red(`
16418
+ \u2717 Watcher error: ${err.message}`));
16419
+ },
16420
+ onReady() {
16421
+ console.log("");
16422
+ console.log(chalk40.green(" \u25CF ") + chalk40.bold("Monitoring agent behavior in real-time"));
16423
+ console.log(chalk40.dim(" \u2502 Press Ctrl+C to stop"));
16424
+ console.log("");
16425
+ }
16426
+ });
16427
+ const shutdown = () => {
16428
+ console.log(chalk40.dim("\n\n Stopping..."));
16429
+ watcher.stop();
16430
+ server.close();
16431
+ process.exit(0);
16432
+ };
16433
+ process.on("SIGINT", shutdown);
16434
+ process.on("SIGTERM", shutdown);
16435
+ }
16436
+
15894
16437
  // src/cli.ts
15895
16438
  var program = new Command();
15896
16439
  program.name("holomime").description("Personality engine for AI agents \u2014 Big Five psychology, not RPG archetypes").version("1.1.0").hook("preAction", (_thisCommand, actionCommand) => {
@@ -15898,7 +16441,7 @@ program.name("holomime").description("Personality engine for AI agents \u2014 Bi
15898
16441
  const commandName = actionCommand.name();
15899
16442
  showTelemetryBannerIfNeeded();
15900
16443
  trackEvent("cli_command", { command: commandName });
15901
- const skipPersonalityCheck = ["init", "browse", "use", "install", "activate", "telemetry"];
16444
+ const skipPersonalityCheck = ["init", "browse", "use", "install", "activate", "telemetry", "brain"];
15902
16445
  if (!skipPersonalityCheck.includes(commandName) && !checkPersonalityExists()) {
15903
16446
  showWelcome();
15904
16447
  process.exit(0);
@@ -15960,4 +16503,11 @@ program.command("interview").description("Self-awareness interview \u2014 score
15960
16503
  program.command("prescribe").description("Diagnose and prescribe DPO treatments from the behavioral corpus [Pro]").requiredOption("--personality <path>", "Path to .personality.json").requiredOption("--log <path>", "Path to conversation log").option("--format <format>", "Log format (holomime, chatgpt, claude, openai-api, anthropic-api, otel, jsonl)").option("--source <source>", "Correction source (corpus, marketplace, both)", "corpus").option("--apply", "Apply found treatments").option("-o, --output <path>", "Write prescription to file").action(prescribeCommand);
15961
16504
  program.command("voice").description("Monitor voice conversations for behavioral drift in real-time [Pro]").requiredOption("--personality <path>", "Path to .personality.json").option("--platform <name>", "Voice platform: livekit, vapi, retell, generic", "generic").option("--room <name>", "LiveKit room name").option("--server-url <url>", "LiveKit server URL").option("--webhook-port <port>", "Vapi webhook port (default: 3001)").option("--agent-id <id>", "Retell agent ID").option("--input <path>", "Input transcript file (JSONL) for offline analysis").option("--interval <ms>", "Diagnosis interval in milliseconds (default: 15000)").option("--threshold <level>", "Alert threshold: warning or concern (default: warning)").action(voiceCommand);
15962
16505
  program.command("cure").description("End-to-end behavioral fix: diagnose \u2192 export \u2192 train \u2192 verify [Pro]").requiredOption("--personality <path>", "Path to .personality.json").requiredOption("--log <path>", "Path to conversation log (JSON)").option("--provider <provider>", "Training provider (openai, huggingface)", "openai").option("--base-model <model>", "Base model to fine-tune", "gpt-4o-mini-2024-07-18").option("--method <method>", "Training method (auto, sft, dpo)", "auto").option("--epochs <n>", "Number of training epochs").option("--suffix <name>", "Model name suffix").option("--skip-train", "Skip training step (diagnose + export only)").option("--skip-verify", "Skip post-training verification").option("--dry-run", "Preview pipeline plan without executing").option("--push", "Push trained model to HuggingFace Hub").option("--hub-repo <repo>", "HuggingFace Hub repo (user/model-name)").option("--pass-threshold <n>", "Minimum verification score (0-100)", "50").action(cureCommand);
16506
+ program.command("brain").description("See your agent's brain \u2014 real-time NeuralSpace visualization [Pro]").option("--watch <path>", "Manual path to conversation log file").option("--agent <agent>", "Agent type override (claude-code, cline, manual)").option("--port <port>", "Server port (default: 3838)", "3838").option("--no-open", "Don't auto-open browser").option("--personality <path>", "Personality spec for assessment context").action((opts) => liveCommand({
16507
+ watchPath: opts.watch,
16508
+ agent: opts.agent,
16509
+ port: parseInt(opts.port, 10),
16510
+ noOpen: opts.open === false,
16511
+ personality: opts.personality
16512
+ }));
15963
16513
  program.parseAsync().then(() => flushTelemetry());