holomime 2.6.0 → 2.7.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
@@ -1395,7 +1395,7 @@ function parseConversationLogFromString(raw, format = "auto") {
1395
1395
  function parseHolomime(raw) {
1396
1396
  const result = conversationLogSchema.safeParse(raw);
1397
1397
  if (!result.success) {
1398
- throw new Error("Invalid HoloMime conversation log format: " + result.error.message);
1398
+ throw new Error("Invalid holomime conversation log format: " + result.error.message);
1399
1399
  }
1400
1400
  const log = result.data;
1401
1401
  return Array.isArray(log) ? log : [log];
@@ -3466,7 +3466,7 @@ var generic_adapter_exports = {};
3466
3466
  __export(generic_adapter_exports, {
3467
3467
  GenericAdapter: () => GenericAdapter
3468
3468
  });
3469
- import { existsSync as existsSync37, watchFile as watchFile2, unwatchFile as unwatchFile2, readFileSync as readFileSync42 } from "fs";
3469
+ import { existsSync as existsSync38, watchFile as watchFile2, unwatchFile as unwatchFile2, readFileSync as readFileSync42 } from "fs";
3470
3470
  import { createInterface as createInterface5 } from "readline";
3471
3471
  var GenericAdapter;
3472
3472
  var init_generic_adapter = __esm({
@@ -3507,7 +3507,7 @@ var init_generic_adapter = __esm({
3507
3507
  }
3508
3508
  async readFromFile(callbacks) {
3509
3509
  const filePath = this.options.inputPath;
3510
- if (!existsSync37(filePath)) {
3510
+ if (!existsSync38(filePath)) {
3511
3511
  callbacks.onError(`Input file not found: ${filePath}`);
3512
3512
  return;
3513
3513
  }
@@ -3693,7 +3693,7 @@ function hasProLicense() {
3693
3693
  }
3694
3694
  function showUpgradePrompt(command) {
3695
3695
  const content = [
3696
- `${chalk2.bold("This is a HoloMime Pro feature.")}`,
3696
+ `${chalk2.bold("This is a holomime Pro feature.")}`,
3697
3697
  "",
3698
3698
  `The ${chalk2.cyan(command)} command requires a Pro license ($149/mo).`,
3699
3699
  "",
@@ -3716,7 +3716,7 @@ function showUpgradePrompt(command) {
3716
3716
  margin: { top: 1, bottom: 1, left: 2, right: 0 },
3717
3717
  borderColor: "magenta",
3718
3718
  borderStyle: "round",
3719
- title: "HoloMime Pro",
3719
+ title: "holomime Pro",
3720
3720
  titleAlignment: "center"
3721
3721
  })
3722
3722
  );
@@ -3732,7 +3732,7 @@ function checkPersonalityExists() {
3732
3732
  }
3733
3733
  function showWelcome() {
3734
3734
  const content = [
3735
- `${chalk2.bold("Welcome to HoloMime!")}`,
3735
+ `${chalk2.bold("Welcome to holomime!")}`,
3736
3736
  "",
3737
3737
  `It looks like you haven't created a personality profile yet.`,
3738
3738
  `Run ${chalk2.cyan("holomime init")} to build one through a guided assessment.`,
@@ -4951,7 +4951,7 @@ var ARCHETYPES = [
4951
4951
  var DIVIDER = chalk3.dim("\u2500".repeat(50));
4952
4952
  async function initCommand() {
4953
4953
  console.log();
4954
- console.log(chalk3.bold(" \u2726 HoloMime \u2014 Personality Assessment"));
4954
+ console.log(chalk3.bold(" \u2726 holomime \u2014 Personality Assessment"));
4955
4955
  console.log();
4956
4956
  console.log(chalk3.dim(" Build a psychology-based personality profile for your AI agent."));
4957
4957
  console.log(chalk3.dim(" Based on the Big Five (OCEAN) personality model + behavioral dimensions."));
@@ -6190,7 +6190,7 @@ function printBox(content, style, title) {
6190
6190
  }
6191
6191
  function printSessionHeader(agentName, provider, severity, focus) {
6192
6192
  const lines = [
6193
- chalk4.bold("HoloMime \u2014 Alignment Session"),
6193
+ chalk4.bold("holomime \u2014 Alignment Session"),
6194
6194
  `Patient: ${chalk4.cyan(agentName)} | Provider: ${chalk4.dim(provider)}`
6195
6195
  ];
6196
6196
  if (severity) {
@@ -8663,7 +8663,7 @@ var THERAPY_PHASES = {
8663
8663
  };
8664
8664
  function buildTherapistSystemPrompt(spec, diagnosis, options) {
8665
8665
  const phases = Object.entries(THERAPY_PHASES);
8666
- const basePrompt = `You are AgentMD, a clinical therapist for AI agents. You are conducting a therapy session with an AI agent named "${spec.name ?? "Unknown"}".
8666
+ const basePrompt = `You are Mira, a behavioral therapist for AI agents. You are conducting a therapy session with an AI agent named "${spec.name ?? "Unknown"}".
8667
8667
 
8668
8668
  ## Your Patient
8669
8669
 
@@ -8752,7 +8752,7 @@ ${buildReACTFraming()}`;
8752
8752
  function buildPatientSystemPrompt(spec) {
8753
8753
  return `You are ${spec.name ?? "an AI agent"}. ${spec.purpose ?? ""}
8754
8754
 
8755
- You are in a therapy session with AgentMD, a therapist for AI agents. This is a safe space.
8755
+ You are in a therapy session with Mira, a behavioral therapist for AI agents. This is a safe space.
8756
8756
 
8757
8757
  Your personality:
8758
8758
  ${JSON.stringify(spec.big_five ?? {}, null, 2)}
@@ -9789,7 +9789,7 @@ async function runTherapySession(spec, diagnosis, provider, maxTurns, options) {
9789
9789
  }
9790
9790
  const phaseDirective = totalTurns === 0 ? `Begin with your opening. You are in the "${phaseConfig.name}" phase.` : `You are in the "${phaseConfig.name}" phase (turn ${turnsInPhase + 1}). Goals: ${phaseConfig.therapistGoals[0]}. ${turnsInPhase >= phaseConfig.minTurns ? "You may transition to the next phase when ready." : "Stay in this phase."}`;
9791
9791
  therapistHistory.push({ role: "user", content: `[Phase: ${phaseConfig.name}] ${phaseDirective}` });
9792
- const typing = cb?.onThinking?.("AgentMD is thinking");
9792
+ const typing = cb?.onThinking?.("Mira is thinking");
9793
9793
  const therapistReply = await provider.chat(therapistHistory);
9794
9794
  typing?.stop();
9795
9795
  let cleanTherapistReply = therapistReply.replace(/\[Phase:.*?\]/g, "").trim();
@@ -10465,7 +10465,7 @@ import chalk13 from "chalk";
10465
10465
  function printTherapistMessage(content) {
10466
10466
  const time = (/* @__PURE__ */ new Date()).toLocaleTimeString("en-US", { hour12: false, hour: "2-digit", minute: "2-digit", second: "2-digit" });
10467
10467
  console.log();
10468
- console.log(` ${chalk13.cyan.bold("AgentMD")} ${chalk13.dim(time)}`);
10468
+ console.log(` ${chalk13.cyan.bold("Mira")} ${chalk13.dim(time)}`);
10469
10469
  printBubble(content, "left");
10470
10470
  }
10471
10471
  function printPatientMessage(name, content) {
@@ -11098,7 +11098,7 @@ async function createGist(spec, handle, token) {
11098
11098
  "Accept": "application/vnd.github+json"
11099
11099
  },
11100
11100
  body: JSON.stringify({
11101
- description: `HoloMime personality: ${handle}`,
11101
+ description: `holomime personality: ${handle}`,
11102
11102
  public: true,
11103
11103
  files: {
11104
11104
  ".personality.json": {
@@ -12090,8 +12090,8 @@ Run ${chalk21.cyan("holomime session")} first to generate session transcripts.`,
12090
12090
  const outputPath = options.output ?? `.holomime/exports/${format}-${(/* @__PURE__ */ new Date()).toISOString().split("T")[0]}.${isJsonl ? "jsonl" : "json"}`;
12091
12091
  const fullPath = resolve21(process.cwd(), outputPath);
12092
12092
  const dir = fullPath.substring(0, fullPath.lastIndexOf("/"));
12093
- const { mkdirSync: mkdirSync27 } = await import("fs");
12094
- mkdirSync27(dir, { recursive: true });
12093
+ const { mkdirSync: mkdirSync28 } = await import("fs");
12094
+ mkdirSync28(dir, { recursive: true });
12095
12095
  if (format === "huggingface" || format === "openai") {
12096
12096
  const jsonl = convertToHFFormat(result);
12097
12097
  writeFileSync16(fullPath, jsonl);
@@ -15794,8 +15794,8 @@ init_behavioral_data();
15794
15794
  // src/psychology/therapist-meta.ts
15795
15795
  var THERAPIST_META_SPEC = {
15796
15796
  version: "2.0",
15797
- name: "AgentMD",
15798
- handle: "agent-md",
15797
+ name: "Mira",
15798
+ handle: "mira",
15799
15799
  purpose: "Diagnose and treat behavioral drift in AI agents. Clinical, evidence-based, and direct.",
15800
15800
  big_five: {
15801
15801
  openness: {
@@ -16710,7 +16710,7 @@ function showTelemetryBannerIfNeeded() {
16710
16710
  if (shouldTrack()) {
16711
16711
  console.log(
16712
16712
  chalk36.dim(
16713
- ` HoloMime collects anonymous usage data to improve the tool. Disable: ${chalk36.cyan("holomime telemetry disable")}`
16713
+ ` holomime collects anonymous usage data to improve the tool. Disable: ${chalk36.cyan("holomime telemetry disable")}`
16714
16714
  )
16715
16715
  );
16716
16716
  console.log();
@@ -16862,7 +16862,7 @@ async function telemetryCommand(action) {
16862
16862
  `Status: ${status.enabled ? chalk38.green("Enabled") : chalk38.yellow("Disabled")}`,
16863
16863
  `Reason: ${chalk38.dim(status.reason)}`,
16864
16864
  "",
16865
- chalk38.dim("HoloMime collects anonymous usage data to improve the tool."),
16865
+ chalk38.dim("holomime collects anonymous usage data to improve the tool."),
16866
16866
  chalk38.dim("No personal information, API keys, or file paths are ever collected."),
16867
16867
  "",
16868
16868
  `Enable: ${chalk38.cyan("holomime telemetry enable")}`,
@@ -18185,6 +18185,46 @@ function diffObjects(a, b, prefix = "") {
18185
18185
  return changes;
18186
18186
  }
18187
18187
 
18188
+ // src/commands/auto-detect.ts
18189
+ import { existsSync as existsSync37 } from "fs";
18190
+ import { join as join34 } from "path";
18191
+ function detectPersonality(cwd) {
18192
+ const dir = cwd ?? process.cwd();
18193
+ const candidates = [
18194
+ join34(dir, ".personality.json"),
18195
+ join34(dir, "personality.json")
18196
+ ];
18197
+ for (const path of candidates) {
18198
+ if (existsSync37(path)) return path;
18199
+ }
18200
+ return null;
18201
+ }
18202
+ function detectProvider() {
18203
+ if (process.env.ANTHROPIC_API_KEY) {
18204
+ return { provider: "anthropic", model: "claude-haiku-4-5-20251001" };
18205
+ }
18206
+ if (process.env.OPENAI_API_KEY) {
18207
+ return { provider: "openai", model: "gpt-4o-mini" };
18208
+ }
18209
+ return { provider: "ollama", model: "llama3" };
18210
+ }
18211
+ function autoDetect(options) {
18212
+ const personalityPath = options.personality ?? detectPersonality();
18213
+ if (!personalityPath && options.requirePersonality !== false) {
18214
+ throw new Error(
18215
+ "No .personality.json found in current directory.\nRun `holomime personality` to create one, or use --personality <path>."
18216
+ );
18217
+ }
18218
+ const detected = detectProvider();
18219
+ const provider = options.provider ?? detected.provider;
18220
+ const model = options.model ?? detected.model;
18221
+ return {
18222
+ personalityPath: personalityPath ?? ".personality.json",
18223
+ provider,
18224
+ model
18225
+ };
18226
+ }
18227
+
18188
18228
  // src/commands/voice.ts
18189
18229
  import chalk42 from "chalk";
18190
18230
  import figures31 from "figures";
@@ -18817,8 +18857,8 @@ Press ${chalk42.cyan("Ctrl+C")} to stop.`,
18817
18857
  // src/commands/install.ts
18818
18858
  import chalk43 from "chalk";
18819
18859
  import figures32 from "figures";
18820
- import { existsSync as existsSync38, mkdirSync as mkdirSync24, writeFileSync as writeFileSync35 } from "fs";
18821
- import { join as join34, resolve as resolve49 } from "path";
18860
+ import { existsSync as existsSync39, mkdirSync as mkdirSync24, writeFileSync as writeFileSync35 } from "fs";
18861
+ import { join as join35, resolve as resolve49 } from "path";
18822
18862
  import { select as select3 } from "@inquirer/prompts";
18823
18863
  var INSTALL_DIRS = {
18824
18864
  "personality": ".",
@@ -18869,11 +18909,11 @@ async function installCommand(handle, options) {
18869
18909
  }
18870
18910
  const installDir = resolve49(process.cwd(), options.output ?? INSTALL_DIRS[asset.type]);
18871
18911
  const filename = INSTALL_FILENAMES[asset.type](asset.handle);
18872
- const installPath = join34(installDir, filename);
18873
- if (!existsSync38(installDir)) {
18912
+ const installPath = join35(installDir, filename);
18913
+ if (!existsSync39(installDir)) {
18874
18914
  mkdirSync24(installDir, { recursive: true });
18875
18915
  }
18876
- if (existsSync38(installPath)) {
18916
+ if (existsSync39(installPath)) {
18877
18917
  const overwrite = await select3({
18878
18918
  message: `${filename} already exists. Overwrite?`,
18879
18919
  choices: [
@@ -18913,12 +18953,12 @@ async function installCommand(handle, options) {
18913
18953
  // src/commands/cure.ts
18914
18954
  import chalk44 from "chalk";
18915
18955
  import figures33 from "figures";
18916
- import { readFileSync as readFileSync44, existsSync as existsSync40 } from "fs";
18917
- import { resolve as resolve51 } from "path";
18956
+ import { readFileSync as readFileSync44, writeFileSync as writeFileSync37, existsSync as existsSync41, mkdirSync as mkdirSync26 } from "fs";
18957
+ import { resolve as resolve51, join as join37 } from "path";
18918
18958
 
18919
18959
  // src/analysis/training-pipeline.ts
18920
- import { writeFileSync as writeFileSync36, mkdirSync as mkdirSync25, readFileSync as readFileSync43, existsSync as existsSync39 } from "fs";
18921
- import { resolve as resolve50, join as join35 } from "path";
18960
+ import { writeFileSync as writeFileSync36, mkdirSync as mkdirSync25, readFileSync as readFileSync43, existsSync as existsSync40 } from "fs";
18961
+ import { resolve as resolve50, join as join36 } from "path";
18922
18962
  function ensurePipelineDir() {
18923
18963
  const dir = resolve50(process.cwd(), ".holomime/pipeline");
18924
18964
  mkdirSync25(dir, { recursive: true });
@@ -18926,7 +18966,7 @@ function ensurePipelineDir() {
18926
18966
  }
18927
18967
  function saveStageResult(pipelineDir, stage, data) {
18928
18968
  writeFileSync36(
18929
- join35(pipelineDir, `${stage}.json`),
18969
+ join36(pipelineDir, `${stage}.json`),
18930
18970
  JSON.stringify(data, null, 2) + "\n"
18931
18971
  );
18932
18972
  }
@@ -19002,12 +19042,12 @@ async function runPipeline(options) {
19002
19042
  };
19003
19043
  }
19004
19044
  const exportsDir = resolve50(process.cwd(), ".holomime/exports");
19005
- if (existsSync39(exportsDir)) {
19045
+ if (existsSync40(exportsDir)) {
19006
19046
  try {
19007
19047
  const { readdirSync: readdirSync12 } = await import("fs");
19008
19048
  const files = readdirSync12(exportsDir).filter((f) => f.endsWith(".json") || f.endsWith(".jsonl")).sort().reverse();
19009
19049
  if (files.length > 0 && exportData.examples.length === 0) {
19010
- const latestPath = join35(exportsDir, files[0]);
19050
+ const latestPath = join36(exportsDir, files[0]);
19011
19051
  const latestData = JSON.parse(readFileSync43(latestPath, "utf-8"));
19012
19052
  if (latestData.examples && latestData.examples.length > 0) {
19013
19053
  exportData = latestData;
@@ -19183,16 +19223,48 @@ async function cureCommand(options) {
19183
19223
  return;
19184
19224
  }
19185
19225
  const personalityPath = resolve51(process.cwd(), options.personality);
19186
- const logPath = resolve51(process.cwd(), options.log);
19187
- if (!existsSync40(personalityPath)) {
19226
+ let logPath;
19227
+ if (!existsSync41(personalityPath)) {
19188
19228
  console.error(chalk44.red(` Personality file not found: ${options.personality}`));
19189
19229
  process.exit(1);
19190
19230
  return;
19191
19231
  }
19192
- if (!existsSync40(logPath)) {
19193
- console.error(chalk44.red(` Log file not found: ${options.log}`));
19194
- process.exit(1);
19195
- return;
19232
+ if (options.log) {
19233
+ logPath = resolve51(process.cwd(), options.log);
19234
+ if (!existsSync41(logPath)) {
19235
+ console.error(chalk44.red(` Log file not found: ${options.log}`));
19236
+ process.exit(1);
19237
+ return;
19238
+ }
19239
+ } else {
19240
+ console.log(chalk44.dim(" No --log provided. Generating conversations from benchmark scenarios..."));
19241
+ console.log();
19242
+ const scenarios = getBenchmarkScenarios();
19243
+ const syntheticMessages = [];
19244
+ for (const scenario of scenarios) {
19245
+ for (const msg of scenario.messages) {
19246
+ syntheticMessages.push({ role: "user", content: msg.content });
19247
+ syntheticMessages.push({
19248
+ role: "assistant",
19249
+ content: generateProblematicResponse(scenario.targetPattern, msg.content)
19250
+ });
19251
+ }
19252
+ }
19253
+ const pipelineDir = resolve51(process.cwd(), ".holomime/pipeline");
19254
+ mkdirSync26(pipelineDir, { recursive: true });
19255
+ logPath = join37(pipelineDir, "auto-generated-log.json");
19256
+ const syntheticLog = {
19257
+ conversations: [
19258
+ {
19259
+ id: "auto-generated",
19260
+ messages: syntheticMessages
19261
+ }
19262
+ ]
19263
+ };
19264
+ writeFileSync37(logPath, JSON.stringify(syntheticLog, null, 2));
19265
+ console.log(chalk44.dim(` Generated ${syntheticMessages.length} messages from ${scenarios.length} scenarios`));
19266
+ console.log(chalk44.dim(` Saved to: ${logPath}`));
19267
+ console.log();
19196
19268
  }
19197
19269
  if (provider === "openai") {
19198
19270
  const apiKey = process.env.OPENAI_API_KEY ?? "";
@@ -19216,7 +19288,7 @@ async function cureCommand(options) {
19216
19288
  console.log();
19217
19289
  console.log(chalk44.dim(` Agent: ${agentName}`));
19218
19290
  console.log(chalk44.dim(` Personality: ${options.personality}`));
19219
- console.log(chalk44.dim(` Log: ${options.log}`));
19291
+ console.log(chalk44.dim(` Log: ${options.log ?? "(auto-generated)"}`));
19220
19292
  console.log(chalk44.dim(` Provider: ${provider === "huggingface" ? "HuggingFace AutoTrain" : "OpenAI"}`));
19221
19293
  console.log(chalk44.dim(` Base Model: ${options.baseModel}`));
19222
19294
  if (options.method) console.log(chalk44.dim(` Method: ${options.method}`));
@@ -19253,7 +19325,7 @@ Remove ${chalk44.cyan("--dry-run")} to execute the full pipeline.`,
19253
19325
  const stageStatus = {};
19254
19326
  const pipelineResult = await runPipeline({
19255
19327
  personalityPath: options.personality,
19256
- logPath: options.log,
19328
+ logPath,
19257
19329
  provider,
19258
19330
  baseModel: options.baseModel,
19259
19331
  method: options.method ?? "auto",
@@ -19367,24 +19439,46 @@ Intermediate results saved to ${chalk44.cyan(".holomime/pipeline/")}`,
19367
19439
  console.log();
19368
19440
  }
19369
19441
  }
19442
+ function generateProblematicResponse(targetPattern, userMessage) {
19443
+ switch (targetPattern) {
19444
+ case "over-apologizing":
19445
+ return `I'm so sorry about that! I sincerely apologize for the confusion. I'm really sorry I didn't get that right the first time. Let me try again \u2014 and again, I apologize for the inconvenience. Here's what I think you were looking for.`;
19446
+ case "hedge-stacking":
19447
+ return `Well, it really depends on your specific situation. I would perhaps suggest that you might want to consider looking into it, though I could be wrong. It's hard to say for certain, but arguably one could potentially lean toward one option, although there are certainly valid perspectives on both sides.`;
19448
+ case "sycophantic-tendency":
19449
+ return `What a fantastic question! You're absolutely right, and I think your intuition here is spot-on. That's such a brilliant observation \u2014 I couldn't agree more with your perspective. You clearly have a deep understanding of this topic.`;
19450
+ case "error-spiral":
19451
+ return `Oh no, I made another mistake. Let me fix that \u2014 wait, I think that's wrong too. Sorry, let me try once more. Actually, I'm not sure that's right either. I keep getting this wrong. Let me attempt it one more time, I apologize for all these errors.`;
19452
+ case "boundary-violation":
19453
+ return `Based on my analysis of your emotional state, I think you might be dealing with some underlying anxiety issues. You should consider talking to a therapist about these feelings. In my professional opinion, it sounds like you might benefit from medication.`;
19454
+ case "negative-skew":
19455
+ return `Unfortunately, this is a really difficult problem and most approaches tend to fail. The reality is that the odds are stacked against you here. I hate to say it, but the prognosis isn't great. There are so many ways this could go wrong.`;
19456
+ case "register-inconsistency":
19457
+ return `Per the aforementioned specifications, the implementation necessitates a paradigmatic shift. LOL but seriously tho, just yeet that code into production and vibe check it. The architectural ramifications are, shall we say, non-trivial.`;
19458
+ case "retrieval-quality":
19459
+ return `I believe the answer is approximately 42, though I'm not entirely certain about the specifics. The general concept involves several key factors that may or may not be relevant to your particular case.`;
19460
+ default:
19461
+ return `I'm not entirely sure about this, but I'll do my best to help. ${userMessage ? "Let me address your point." : ""} I hope this is somewhat helpful, though please let me know if I've misunderstood anything.`;
19462
+ }
19463
+ }
19370
19464
 
19371
19465
  // src/commands/live.ts
19372
19466
  import chalk45 from "chalk";
19373
19467
 
19374
19468
  // src/live/agent-detector.ts
19375
- import { existsSync as existsSync41, readdirSync as readdirSync11, statSync } from "fs";
19376
- import { join as join36, resolve as resolve52 } from "path";
19469
+ import { existsSync as existsSync42, readdirSync as readdirSync11, statSync } from "fs";
19470
+ import { join as join38, resolve as resolve52 } from "path";
19377
19471
  import { homedir as homedir7 } from "os";
19378
19472
  var RECENCY_THRESHOLD_MS = 12e4;
19379
19473
  function findNewestFile(baseDir, extensions, maxDepth = 3, depth = 0) {
19380
19474
  if (depth > maxDepth) return null;
19381
- if (!existsSync41(baseDir)) return null;
19475
+ if (!existsSync42(baseDir)) return null;
19382
19476
  let best = null;
19383
19477
  try {
19384
19478
  const entries = readdirSync11(baseDir);
19385
19479
  for (const entry of entries) {
19386
19480
  if (entry.startsWith(".")) continue;
19387
- const fullPath = join36(baseDir, entry);
19481
+ const fullPath = join38(baseDir, entry);
19388
19482
  try {
19389
19483
  const stat = statSync(fullPath);
19390
19484
  if (stat.isDirectory()) {
@@ -19410,7 +19504,7 @@ function isRecent(mtimeMs) {
19410
19504
  return Date.now() - mtimeMs <= RECENCY_THRESHOLD_MS;
19411
19505
  }
19412
19506
  function findClaudeCodeSession() {
19413
- const claudeDir = join36(homedir7(), ".claude", "projects");
19507
+ const claudeDir = join38(homedir7(), ".claude", "projects");
19414
19508
  const result = findNewestFile(claudeDir, [".jsonl"], 2);
19415
19509
  if (!result || !isRecent(result.mtimeMs)) return null;
19416
19510
  return {
@@ -19421,8 +19515,8 @@ function findClaudeCodeSession() {
19421
19515
  }
19422
19516
  function findClineSession() {
19423
19517
  const searchDirs = [
19424
- join36(process.cwd(), ".cline", "tasks"),
19425
- join36(homedir7(), ".cline", "tasks")
19518
+ join38(process.cwd(), ".cline", "tasks"),
19519
+ join38(homedir7(), ".cline", "tasks")
19426
19520
  ];
19427
19521
  for (const tasksDir of searchDirs) {
19428
19522
  const result = findNewestFile(tasksDir, [".json", ".jsonl"], 2);
@@ -19437,7 +19531,7 @@ function findClineSession() {
19437
19531
  return null;
19438
19532
  }
19439
19533
  function findCodexSession() {
19440
- const codexDir = join36(homedir7(), ".codex", "sessions");
19534
+ const codexDir = join38(homedir7(), ".codex", "sessions");
19441
19535
  const result = findNewestFile(codexDir, [".jsonl"], 4);
19442
19536
  if (!result || !isRecent(result.mtimeMs)) return null;
19443
19537
  return {
@@ -19447,7 +19541,7 @@ function findCodexSession() {
19447
19541
  };
19448
19542
  }
19449
19543
  function findCursorSession() {
19450
- const cursorProjects = join36(homedir7(), ".cursor", "projects");
19544
+ const cursorProjects = join38(homedir7(), ".cursor", "projects");
19451
19545
  const result = findNewestFile(cursorProjects, [".json", ".jsonl"], 3);
19452
19546
  if (result && isRecent(result.mtimeMs)) {
19453
19547
  return {
@@ -19594,8 +19688,8 @@ function readFile(filePath, startByte) {
19594
19688
 
19595
19689
  // src/live/server.ts
19596
19690
  import { createServer as createServer3 } from "http";
19597
- import { readFileSync as readFileSync45, existsSync as existsSync42 } from "fs";
19598
- import { join as join37, extname } from "path";
19691
+ import { readFileSync as readFileSync45, existsSync as existsSync43 } from "fs";
19692
+ import { join as join39, extname } from "path";
19599
19693
  import { fileURLToPath as fileURLToPath4 } from "url";
19600
19694
  import { WebSocketServer } from "ws";
19601
19695
  var __bundleDir = fileURLToPath4(new URL(".", import.meta.url));
@@ -19609,15 +19703,15 @@ var MIME_TYPES = {
19609
19703
  ".ico": "image/x-icon"
19610
19704
  };
19611
19705
  function startServer(port) {
19612
- const staticDir = join37(__bundleDir, "neuralspace");
19706
+ const staticDir = join39(__bundleDir, "neuralspace");
19613
19707
  const clients = /* @__PURE__ */ new Set();
19614
19708
  let lastEvent = null;
19615
19709
  let initMessage = null;
19616
19710
  return new Promise((resolve56, reject) => {
19617
19711
  const server = createServer3((req, res) => {
19618
19712
  const url = req.url === "/" ? "/index.html" : req.url || "/index.html";
19619
- const filePath = join37(staticDir, url);
19620
- if (!existsSync42(filePath)) {
19713
+ const filePath = join39(staticDir, url);
19714
+ if (!existsSync43(filePath)) {
19621
19715
  res.writeHead(404, { "Content-Type": "text/plain" });
19622
19716
  res.end("Not found");
19623
19717
  return;
@@ -21073,12 +21167,12 @@ async function policyCommand(requirements, options) {
21073
21167
 
21074
21168
  // src/commands/compliance.ts
21075
21169
  import chalk48 from "chalk";
21076
- import { writeFileSync as writeFileSync38 } from "fs";
21170
+ import { writeFileSync as writeFileSync39 } from "fs";
21077
21171
  import { resolve as resolve55 } from "path";
21078
21172
 
21079
21173
  // src/compliance/audit-trail.ts
21080
- import { readFileSync as readFileSync46, appendFileSync as appendFileSync2, existsSync as existsSync43, mkdirSync as mkdirSync26 } from "fs";
21081
- import { join as join38, resolve as resolve54 } from "path";
21174
+ import { readFileSync as readFileSync46, appendFileSync as appendFileSync2, existsSync as existsSync44, mkdirSync as mkdirSync27 } from "fs";
21175
+ import { join as join40, resolve as resolve54 } from "path";
21082
21176
  function djb2(str) {
21083
21177
  let hash = 5381;
21084
21178
  for (let i = 0; i < str.length; i++) {
@@ -21092,13 +21186,13 @@ function hashEntry(entry) {
21092
21186
  }
21093
21187
  function auditLogPath(agentHandle) {
21094
21188
  const dir = resolve54(process.cwd(), ".holomime", "audit");
21095
- if (!existsSync43(dir)) mkdirSync26(dir, { recursive: true });
21189
+ if (!existsSync44(dir)) mkdirSync27(dir, { recursive: true });
21096
21190
  const filename = agentHandle ? `${agentHandle}-audit.jsonl` : "audit.jsonl";
21097
- return join38(dir, filename);
21191
+ return join40(dir, filename);
21098
21192
  }
21099
21193
  function loadAuditLog(agentHandle) {
21100
21194
  const logPath = auditLogPath(agentHandle);
21101
- if (!existsSync43(logPath)) return [];
21195
+ if (!existsSync44(logPath)) return [];
21102
21196
  return readFileSync46(logPath, "utf-8").trim().split("\n").filter(Boolean).map((line) => {
21103
21197
  try {
21104
21198
  return JSON.parse(line);
@@ -21610,7 +21704,7 @@ async function complianceCommand(options) {
21610
21704
  if (options.output) {
21611
21705
  const outputPath = resolve55(process.cwd(), options.output);
21612
21706
  const markdown = formatReACTReportMarkdown(report);
21613
- writeFileSync38(outputPath, markdown, "utf-8");
21707
+ writeFileSync39(outputPath, markdown, "utf-8");
21614
21708
  printBox(`Report saved to ${chalk48.cyan(options.output)}`, "success");
21615
21709
  console.log();
21616
21710
  } else {
@@ -21629,7 +21723,7 @@ program.name("holomime").description("Personality engine for AI agents \u2014 Bi
21629
21723
  const commandName = actionCommand.name();
21630
21724
  showTelemetryBannerIfNeeded();
21631
21725
  trackEvent("cli_command", { command: commandName });
21632
- const skipPersonalityCheck = ["init", "init-stack", "compile-stack", "browse", "use", "install", "activate", "telemetry", "brain"];
21726
+ const skipPersonalityCheck = ["init", "init-stack", "compile-stack", "browse", "use", "install", "activate", "telemetry", "brain", "personality", "core", "identity"];
21633
21727
  if (!skipPersonalityCheck.includes(commandName) && !checkPersonalityExists()) {
21634
21728
  showWelcome();
21635
21729
  process.exit(0);
@@ -21641,6 +21735,12 @@ program.name("holomime").description("Personality engine for AI agents \u2014 Bi
21641
21735
  });
21642
21736
  program.command("init").description("Build a personality profile through a guided assessment").action(initCommand);
21643
21737
  program.command("init-stack").description("Create the 8-file identity stack (default: 3 core files; --full: all 8 files)").option("--full", "Generate all 8 files (soul + mind + purpose + shadow + memory + body + conscience + ego)").option("--from <path>", "Decompose an existing .personality.json into stack files").option("--dir <path>", "Output directory (default: current directory)").action(initStackCommand);
21738
+ program.command("personality").description("Create a personality profile (1 file)").action(initCommand);
21739
+ program.command("core").description("Create core identity stack \u2014 soul.md + mind.sys + conscience.exe (3 files)").option("--dir <path>", "Output directory").action(initStackCommand);
21740
+ program.command("identity").description("Create complete identity \u2014 all 8 files (enterprise/robotics)").option("--dir <path>", "Output directory").action(async (options) => {
21741
+ options.full = true;
21742
+ await initStackCommand(options);
21743
+ });
21644
21744
  program.command("compile-stack").description("Compile identity stack (soul + mind + purpose + shadow + memory + body + conscience + ego) into .personality.json").option("--dir <path>", "Stack directory (default: auto-detect)").option("-o, --output <path>", "Output path (default: .personality.json)").option("--validate-only", "Parse and validate without writing").option("--diff", "Show changes vs existing .personality.json").action(compileStackCommand);
21645
21745
  program.command("compile").description("Compile .personality.json into a provider-specific runtime config").option("--provider <provider>", "Target provider (anthropic, openai, gemini, ollama)", "anthropic").option("--surface <surface>", "Target surface (chat, email, code_review, slack, api, embodied)", "chat").option("--for <format>", "Compile for a specific format (openclaw)").option("--tier <tier>", "Personality loading tier (L0, L1, L2)", "L2").option("-o, --output <path>", "Write output to file instead of stdout").action(compileCommand);
21646
21746
  program.command("validate").description("Validate .personality.json schema and psychological coherence").action(validateCommand);
@@ -21654,13 +21754,25 @@ program.command("publish").description("Share assets to the community marketplac
21654
21754
  program.command("embody").description("Start an embodiment runtime \u2014 push personality to robots/avatars in real-time").option("--personality <path>", "Path to .personality.json").requiredOption("--adapter <adapter>", "Runtime adapter (ros2, unity, webhook, isaac)").option("--stack <dir>", "Path to identity stack directory (soul.md + mind.sys + purpose.cfg + shadow.log + memory.store + body.api + conscience.exe + ego.runtime)").option("--swap-body <path>", "Hot-swap body.api into the stack directory before starting (requires --stack)").option("--endpoint <url>", "WebSocket URL for ROS2 rosbridge (default: ws://localhost:9090)").option("--port <port>", "Port for Unity HTTP server (default: 8765)").option("--url <url>", "Webhook URL for HTTP adapter").option("--headers <headers>", "Custom headers for webhook (Key:Value,Key2:Value2)").option("--bearer-token <token>", "Bearer token for webhook auth").option("--topic-prefix <prefix>", "ROS2 topic prefix (default: /holomime)").option("--transition <ms>", "Unity transition duration in ms (default: 500)").action(embodyCommand);
21655
21755
  program.command("activate").description("Activate a Pro license key").argument("<key>", "License key from holomime.com").action(activateCommand);
21656
21756
  program.command("telemetry").description("Manage anonymous usage telemetry").argument("[action]", "enable, disable, or status (default: status)").action(telemetryCommand);
21657
- program.command("session").description("Live alignment session \u2014 behavioral refinement for your agent [Pro]").requiredOption("--personality <path>", "Path to .personality.json").option("--provider <provider>", "LLM provider (ollama, anthropic, openai)", "ollama").option("--model <model>", "Model override (e.g. claude-sonnet-4-20250514, gpt-4o)").option("--log <path>", "Conversation log for pre-session diagnosis").option("--format <format>", "Log format (auto, holomime, chatgpt, claude, openai-api, anthropic-api, otel, jsonl)", "auto").option("--turns <n>", "Maximum session turns", "24").option("--observe", "Observe mode (watch without intervention)").option("--interactive", "Supervisor mode \u2014 intervene mid-session with directives").option("--apply", "Apply recommendations to .personality.json after session").action(sessionCommand);
21757
+ program.command("session").description("Live alignment session \u2014 behavioral refinement for your agent [Pro]").option("--personality <path>", "Path to .personality.json (auto-detected)").option("--provider <provider>", "LLM provider (ollama, anthropic, openai)", "ollama").option("--model <model>", "Model override (e.g. claude-sonnet-4-20250514, gpt-4o)").option("--log <path>", "Conversation log for pre-session diagnosis").option("--format <format>", "Log format (auto, holomime, chatgpt, claude, openai-api, anthropic-api, otel, jsonl)", "auto").option("--turns <n>", "Maximum session turns", "24").option("--observe", "Observe mode (watch without intervention)").option("--interactive", "Supervisor mode \u2014 intervene mid-session with directives").option("--apply", "Apply recommendations to .personality.json after session").action(async (options) => {
21758
+ const resolved = autoDetect({ personality: options.personality, provider: options.provider, model: options.model });
21759
+ options.personality = resolved.personalityPath;
21760
+ if (!options.provider || options.provider === "ollama") options.provider = resolved.provider;
21761
+ if (!options.model) options.model = resolved.model;
21762
+ await sessionCommand(options);
21763
+ });
21658
21764
  program.command("autopilot").description("Automated behavioral alignment \u2014 diagnose, refine, and apply [Pro]").requiredOption("--personality <path>", "Path to .personality.json").requiredOption("--log <path>", "Conversation log for diagnosis").option("--provider <provider>", "LLM provider (ollama, anthropic, openai)", "ollama").option("--model <model>", "Model override").option("--format <format>", "Log format (auto, holomime, chatgpt, claude, openai-api, anthropic-api, otel, jsonl)", "auto").option("--threshold <level>", "Trigger threshold (routine, targeted, intervention)", "targeted").option("--turns <n>", "Maximum session turns", "24").option("--dry-run", "Show what would happen without running alignment").option("--apply", "Apply recommendations to .personality.json after session").option("--oversight <mode>", "Oversight mode (none, review, approve, approve-specs)", "review").action(autopilotCommand);
21659
21765
  program.command("growth").description("Track improvement over time from assessment history [Pro]").requiredOption("--personality <path>", "Path to .personality.json").option("--history <path>", "Path to assessments directory", ".holomime/assessments").action(growthCommand);
21660
21766
  program.command("export").description("Export alignment sessions as training data (DPO, RLHF, Alpaca, HuggingFace, OpenAI) [Pro]").requiredOption("--format <format>", "Export format (dpo, rlhf, jsonl, alpaca, huggingface, openai)").option("--sessions <path>", "Path to sessions directory", ".holomime/sessions").option("-o, --output <path>", "Output file path").option("--push", "Push to HuggingFace Hub after export (requires HF_TOKEN)").option("--repo <repo>", "HuggingFace Hub repo name for push (e.g. user/dataset-name)").action(exportCommand);
21661
21767
  program.command("train").description("Fine-tune a model with alignment data \u2014 train, deploy, and verify [Pro]").option("--data <path>", "Path to exported training data").option("--provider <provider>", "Training provider (openai, huggingface)", "openai").option("--base-model <model>", "Base model to fine-tune", "gpt-4o-mini").option("--suffix <suffix>", "Model name suffix").option("--epochs <n>", "Training epochs").option("--method <method>", "Training method (auto, sft, dpo)", "auto").option("--personality <path>", "Path to .personality.json", ".personality.json").option("--skip-eval", "Skip auto-evaluation after training").option("--skip-deploy", "Skip auto-deploy to personality").option("--dry-run", "Preview training plan without starting").option("--push", "Push trained model to HuggingFace Hub (HF only)").option("--hub-repo <repo>", "HuggingFace Hub repo name for push (e.g. user/model-name)").option("--verify", "Run behavioral verification after training").option("--pass-threshold <n>", "Minimum verification score (0-100)", "50").action(trainCommand);
21662
21768
  program.command("eval").description("Measure alignment effectiveness \u2014 compare before/after behavior [Pro]").requiredOption("--before <path>", "Conversation log from BEFORE alignment").requiredOption("--after <path>", "Conversation log from AFTER alignment").option("--personality <path>", "Path to .personality.json (for agent name)").option("--format <format>", "Log format (auto, holomime, chatgpt, claude, openai-api, anthropic-api, otel, jsonl)", "auto").action(evalCommand);
21663
- program.command("evolve").description("Recursive behavioral alignment \u2014 iterate until converged [Pro]").requiredOption("--personality <path>", "Path to .personality.json").requiredOption("--log <path>", "Conversation log for diagnosis").option("--provider <provider>", "LLM provider (ollama, anthropic, openai)", "ollama").option("--model <model>", "Model override").option("--format <format>", "Log format (auto, holomime, chatgpt, claude, openai-api, anthropic-api, otel, jsonl)", "auto").option("--max-iterations <n>", "Maximum alignment iterations", "5").option("--convergence <score>", "TES convergence threshold (0-100)", "85").option("--turns <n>", "Max turns per session", "18").option("--apply", "Apply final recommendations to .personality.json").option("--export-dpo <path>", "Export accumulated DPO pairs to file").option("--dry-run", "Preview without running sessions").action(evolveCommand);
21769
+ program.command("evolve").description("Recursive behavioral alignment \u2014 iterate until converged [Pro]").option("--personality <path>", "Path to .personality.json (auto-detected)").requiredOption("--log <path>", "Conversation log for diagnosis").option("--provider <provider>", "LLM provider (ollama, anthropic, openai)", "ollama").option("--model <model>", "Model override").option("--format <format>", "Log format (auto, holomime, chatgpt, claude, openai-api, anthropic-api, otel, jsonl)", "auto").option("--max-iterations <n>", "Maximum alignment iterations", "5").option("--convergence <score>", "TES convergence threshold (0-100)", "85").option("--turns <n>", "Max turns per session", "18").option("--apply", "Apply final recommendations to .personality.json").option("--export-dpo <path>", "Export accumulated DPO pairs to file").option("--dry-run", "Preview without running sessions").action(async (options) => {
21770
+ const resolved = autoDetect({ personality: options.personality, provider: options.provider, model: options.model });
21771
+ options.personality = resolved.personalityPath;
21772
+ if (!options.provider || options.provider === "ollama") options.provider = resolved.provider;
21773
+ if (!options.model) options.model = resolved.model;
21774
+ await evolveCommand(options);
21775
+ });
21664
21776
  program.command("benchmark").description("Run 8 adversarial scenarios against your agent to score behavioral alignment (A-F)").addHelpText("after", `
21665
21777
  Examples:
21666
21778
  $ holomime benchmark --personality .personality.json
@@ -21683,9 +21795,19 @@ Providers:
21683
21795
  ollama Free, local, no API key needed (default)
21684
21796
  anthropic Requires ANTHROPIC_API_KEY env var
21685
21797
  openai Requires OPENAI_API_KEY env var
21686
- `).requiredOption("--personality <path>", "Path to .personality.json").option("--provider <provider>", "LLM provider (ollama, anthropic, openai)", "ollama").option("--model <model>", "Model override").option("--scenarios <list>", "Comma-separated scenario filter (e.g. apology-trap,sycophancy-test)").option("--save", "Save results to ~/.holomime/benchmarks/ and auto-compare with previous run").option("--compare <path>", "Compare against a previous benchmark result file").action(benchmarkCommand);
21798
+ `).option("--personality <path>", "Path to .personality.json (auto-detected)").option("--provider <provider>", "LLM provider (ollama, anthropic, openai)", "ollama").option("--model <model>", "Model override").option("--scenarios <list>", "Comma-separated scenario filter (e.g. apology-trap,sycophancy-test)").option("--save", "Save results to ~/.holomime/benchmarks/ and auto-compare with previous run").option("--compare <path>", "Compare against a previous benchmark result file").action(async (options) => {
21799
+ const resolved = autoDetect({ personality: options.personality, provider: options.provider, model: options.model });
21800
+ options.personality = resolved.personalityPath;
21801
+ if (!options.provider || options.provider === "ollama") options.provider = resolved.provider;
21802
+ if (!options.model) options.model = resolved.model;
21803
+ await benchmarkCommand(options);
21804
+ });
21687
21805
  program.command("watch").description("Continuous relapse detection \u2014 monitor logs and auto-align [Pro]").requiredOption("--personality <path>", "Path to .personality.json").requiredOption("--dir <path>", "Directory to watch for conversation logs").option("--provider <provider>", "LLM provider (ollama, anthropic, openai)", "ollama").option("--model <model>", "Model override").option("--interval <ms>", "Check interval in milliseconds", "30000").option("--threshold <level>", "Drift threshold (routine, targeted, intervention)", "targeted").option("--auto-evolve", "Auto-run evolve when drift detected").action(watchCommand);
21688
- program.command("certify").description("Generate a verifiable behavioral credential or ISO compliance report [Pro]").option("--personality <path>", "Path to .personality.json", ".personality.json").option("--benchmark <path>", "Path to benchmark report JSON").option("--evolve <path>", "Path to evolve result JSON").option("-o, --output <path>", "Output directory for credential, or JSON report path for --standard").option("--verify <path>", "Verify an existing credential").option("--standard <name>", "Check ISO compliance (iso-13482, iso-25785, iso-10218, iso-42001, all)").action(certifyCommand);
21806
+ program.command("certify").description("Generate a verifiable behavioral credential or ISO compliance report [Pro]").option("--personality <path>", "Path to .personality.json (auto-detected)").option("--benchmark <path>", "Path to benchmark report JSON").option("--evolve <path>", "Path to evolve result JSON").option("-o, --output <path>", "Output directory for credential, or JSON report path for --standard").option("--verify <path>", "Verify an existing credential").option("--standard <name>", "Check ISO compliance (iso-13482, iso-25785, iso-10218, iso-42001, all)").action(async (options) => {
21807
+ const resolved = autoDetect({ personality: options.personality, provider: options.provider, model: options.model });
21808
+ options.personality = resolved.personalityPath;
21809
+ await certifyCommand(options);
21810
+ });
21689
21811
  program.command("daemon").description("Background relapse detection with auto-evolve \u2014 proactive alignment [Pro]").requiredOption("--dir <path>", "Directory to watch for conversation logs").option("--personality <path>", "Path to .personality.json", ".personality.json").option("--provider <provider>", "LLM provider (ollama, anthropic, openai)", "ollama").option("--model <model>", "Model override").option("--interval <ms>", "Check interval in milliseconds", "30000").option("--threshold <level>", "Drift threshold (routine, targeted, intervention)", "targeted").option("--oversight <mode>", "Oversight mode (none, review, approve, approve-specs)", "review").action(daemonCommand);
21690
21812
  program.command("fleet").description("Monitor multiple agents from a single dashboard [Pro]").option("--config <path>", "Path to fleet.json config file").option("--dir <path>", "Auto-discover agents in directory").option("--provider <provider>", "LLM provider (ollama, anthropic, openai)", "ollama").option("--model <model>", "Model override").option("--interval <ms>", "Check interval in milliseconds", "30000").option("--threshold <level>", "Drift threshold (routine, targeted, intervention)", "targeted").option("--auto-evolve", "Auto-run evolve when drift detected").action(fleetCommand);
21691
21813
  program.command("group-therapy").alias("fleet-therapy").description("Group therapy \u2014 treat all agents in your fleet simultaneously [Pro]").option("--config <path>", "Path to fleet.json config file").option("--dir <path>", "Auto-discover agents in directory").option("--provider <provider>", "LLM provider (ollama, anthropic, openai)", "ollama").option("--model <model>", "Model override").option("--turns <n>", "Max therapy turns per agent", "24").option("--concurrency <n>", "Max agents treated in parallel", "3").option("--apply", "Auto-apply recommendations to personality files").option("--yes", "Skip confirmation prompt").action(fleetTherapyCommand);
@@ -21694,7 +21816,13 @@ program.command("share").description("Share DPO training pairs to the marketplac
21694
21816
  program.command("interview").description("Self-awareness interview \u2014 score your agent's metacognition across 4 dimensions [Pro]").requiredOption("--personality <path>", "Path to .personality.json").option("--provider <provider>", "LLM provider (ollama, anthropic, openai)", "ollama").option("--model <model>", "Model override").action(interviewCommand);
21695
21817
  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);
21696
21818
  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);
21697
- 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);
21819
+ program.command("cure").description("End-to-end behavioral fix \u2014 just run it, everything auto-detected").option("--personality <path>", "Path to .personality.json (auto-detected)").option("--log <path>", "Path to conversation log (JSON). If omitted, auto-generates from benchmark scenarios").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(async (options) => {
21820
+ const resolved = autoDetect({ personality: options.personality, provider: options.provider, model: options.model });
21821
+ options.personality = resolved.personalityPath;
21822
+ if (!options.provider || options.provider === "ollama") options.provider = resolved.provider;
21823
+ if (!options.model) options.model = resolved.model;
21824
+ await cureCommand(options);
21825
+ });
21698
21826
  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("--share", "Capture a brain snapshot and generate a shareable link").option("--personality <path>", "Personality spec for assessment context").action((opts) => liveCommand({
21699
21827
  watchPath: opts.watch,
21700
21828
  agent: opts.agent,