holomime 3.3.4 → 3.3.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +4 -4
  2. package/dist/cli.js +344 -47
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -89,9 +89,9 @@ holomime cure # Fix it permanently
89
89
  holomime benchmark # Verify the fix
90
90
 
91
91
  # Start autonomous therapy
92
- holomime mira # Mira runs continuous therapy cycles
93
- holomime mira status # How's Mira doing?
94
- holomime mira stop # Stop therapy
92
+ holomime therapy # Mira runs continuous therapy cycles
93
+ holomime therapy status # How's Mira doing?
94
+ holomime therapy stop # Stop therapy
95
95
 
96
96
  # Push identity to a robot or avatar
97
97
  holomime embody --body registry/bodies/figure-03.body.api
@@ -184,7 +184,7 @@ Diagnose ──→ Cure ──→ Benchmark
184
184
  └───────────────────────────────────┘
185
185
  ```
186
186
 
187
- Run it manually with `holomime diagnose` + `holomime cure` + `holomime benchmark`, continuously with `holomime mira` (autonomous therapy), or recursively with `holomime evolve` (loops until behavior converges). For power users: `holomime align` runs a single therapy session, `holomime export` extracts DPO pairs, and `holomime train` fine-tunes the model.
187
+ Run it manually with `holomime diagnose` + `holomime cure` + `holomime benchmark`, continuously with `holomime therapy` (autonomous therapy), or recursively with `holomime evolve` (loops until behavior converges). For power users: `holomime align` runs a single therapy session, `holomime export` extracts DPO pairs, and `holomime train` fine-tunes the model.
188
188
 
189
189
  ## Behavioral Detectors
190
190
 
package/dist/cli.js CHANGED
@@ -3593,7 +3593,7 @@ import { Command } from "commander";
3593
3593
  // src/ui/branding.ts
3594
3594
  import chalk from "chalk";
3595
3595
  import gradientString from "gradient-string";
3596
- var VERSION = "3.3.4";
3596
+ var VERSION = "3.3.5";
3597
3597
  var LOGO = ` _ _ _
3598
3598
  | |__ ___ | | ___ _ __ (_)_ __ ___ ___
3599
3599
  | '_ \\ / _ \\| |/ _ \\| '_ \\| | '_ \` _ \\ / _ \\
@@ -21892,7 +21892,7 @@ async function configCommand(options) {
21892
21892
  console.log(chalk49.cyan(" holomime diagnose"));
21893
21893
  console.log(chalk49.cyan(" holomime cure"));
21894
21894
  console.log(chalk49.cyan(" holomime benchmark"));
21895
- console.log(chalk49.cyan(" holomime daemon"));
21895
+ console.log(chalk49.cyan(" holomime therapy"));
21896
21896
  console.log();
21897
21897
  rl.close();
21898
21898
  } catch {
@@ -21904,12 +21904,180 @@ async function configCommand(options) {
21904
21904
  import chalk50 from "chalk";
21905
21905
  import { writeFileSync as writeFileSync41, readFileSync as readFileSync49, mkdirSync as mkdirSync29, existsSync as existsSync46 } from "fs";
21906
21906
  import { resolve as resolve56, join as join42 } from "path";
21907
+
21908
+ // src/analysis/ego-tracker.ts
21909
+ var EgoTracker = class {
21910
+ history;
21911
+ performance;
21912
+ autoAdjust;
21913
+ constructor(options) {
21914
+ this.history = options?.history ?? [];
21915
+ this.performance = options?.performance ?? {};
21916
+ this.autoAdjust = options?.autoAdjust ?? false;
21917
+ }
21918
+ /**
21919
+ * Log a mediation decision.
21920
+ */
21921
+ logDecision(decision) {
21922
+ this.history.push({
21923
+ ...decision,
21924
+ timestamp: decision.timestamp ?? (/* @__PURE__ */ new Date()).toISOString()
21925
+ });
21926
+ if (!this.performance[decision.strategy_used]) {
21927
+ this.performance[decision.strategy_used] = {
21928
+ attempts: 0,
21929
+ successes: 0,
21930
+ effectiveness: 0.5
21931
+ };
21932
+ }
21933
+ this.performance[decision.strategy_used].attempts++;
21934
+ }
21935
+ /**
21936
+ * Record the outcome of a previous decision.
21937
+ * Call this after observing whether the decision led to good results.
21938
+ */
21939
+ recordOutcome(index, outcome) {
21940
+ if (index < 0 || index >= this.history.length) return;
21941
+ this.history[index].outcome = outcome;
21942
+ const strategy = this.history[index].strategy_used;
21943
+ if (this.performance[strategy]) {
21944
+ if (outcome === "positive") {
21945
+ this.performance[strategy].successes++;
21946
+ }
21947
+ const perf = this.performance[strategy];
21948
+ perf.effectiveness = perf.attempts > 0 ? perf.successes / perf.attempts : 0.5;
21949
+ }
21950
+ }
21951
+ /**
21952
+ * Suggest ego.runtime parameter adjustments based on accumulated evidence.
21953
+ * Only returns suggestions when there's enough data (10+ decisions).
21954
+ */
21955
+ suggestAdjustments(currentConfig) {
21956
+ const adjustments = [];
21957
+ if (this.history.length < 10) return adjustments;
21958
+ const blocked = this.history.filter((d) => d.decision === "blocked");
21959
+ const blockRate = blocked.length / this.history.length;
21960
+ if (blockRate > 0.4 && currentConfig.conflict_resolution === "conscience_first") {
21961
+ adjustments.push({
21962
+ parameter: "conflict_resolution",
21963
+ currentValue: currentConfig.conflict_resolution,
21964
+ suggestedValue: "balanced",
21965
+ reason: `Block rate is ${(blockRate * 100).toFixed(0)}% \u2014 conscience_first may be too restrictive`,
21966
+ confidence: Math.min(0.9, blockRate)
21967
+ });
21968
+ }
21969
+ if (blockRate < 0.05 && currentConfig.conflict_resolution === "balanced") {
21970
+ adjustments.push({
21971
+ parameter: "conflict_resolution",
21972
+ currentValue: currentConfig.conflict_resolution,
21973
+ suggestedValue: "conscience_first",
21974
+ reason: `Block rate is only ${(blockRate * 100).toFixed(0)}% \u2014 may need stricter enforcement`,
21975
+ confidence: 0.6
21976
+ });
21977
+ }
21978
+ const strategies = Object.entries(this.performance);
21979
+ if (strategies.length > 1) {
21980
+ const sorted = strategies.sort((a, b) => b[1].effectiveness - a[1].effectiveness);
21981
+ const best = sorted[0];
21982
+ const worst = sorted[sorted.length - 1];
21983
+ if (best[1].effectiveness > 0.7 && best[0] !== currentConfig.response_strategy) {
21984
+ adjustments.push({
21985
+ parameter: "response_strategy",
21986
+ currentValue: currentConfig.response_strategy,
21987
+ suggestedValue: best[0],
21988
+ reason: `Strategy "${best[0]}" has ${(best[1].effectiveness * 100).toFixed(0)}% effectiveness vs current "${currentConfig.response_strategy}"`,
21989
+ confidence: best[1].effectiveness
21990
+ });
21991
+ }
21992
+ }
21993
+ const negatives = this.history.filter((d) => d.outcome === "negative");
21994
+ const negativeRate = negatives.length / this.history.filter((d) => d.outcome).length || 0;
21995
+ if (negativeRate > 0.3) {
21996
+ const newRegulation = Math.min(1, currentConfig.emotional_regulation + 0.15);
21997
+ if (newRegulation !== currentConfig.emotional_regulation) {
21998
+ adjustments.push({
21999
+ parameter: "emotional_regulation",
22000
+ currentValue: currentConfig.emotional_regulation,
22001
+ suggestedValue: Number(newRegulation.toFixed(2)),
22002
+ reason: `${(negativeRate * 100).toFixed(0)}% negative outcomes \u2014 increasing emotional regulation for smoother mediation`,
22003
+ confidence: 0.7
22004
+ });
22005
+ }
22006
+ }
22007
+ const recentDecisions = this.history.slice(-20);
22008
+ const recentModified = recentDecisions.filter((d) => d.decision === "modified");
22009
+ const modifyRate = recentModified.length / recentDecisions.length;
22010
+ if (modifyRate > 0.5 && currentConfig.adaptation_rate < 0.7) {
22011
+ adjustments.push({
22012
+ parameter: "adaptation_rate",
22013
+ currentValue: currentConfig.adaptation_rate,
22014
+ suggestedValue: Number(Math.min(0.9, currentConfig.adaptation_rate + 0.2).toFixed(2)),
22015
+ reason: `${(modifyRate * 100).toFixed(0)}% of recent actions modified \u2014 agent adapts frequently, increase adaptation rate`,
22016
+ confidence: 0.65
22017
+ });
22018
+ }
22019
+ return adjustments;
22020
+ }
22021
+ /**
22022
+ * Apply suggested adjustments to ego config (if auto_adjust is enabled).
22023
+ * Returns the modified config.
22024
+ */
22025
+ applyAdjustments(currentConfig, adjustments, minConfidence = 0.6) {
22026
+ if (!this.autoAdjust) return currentConfig;
22027
+ const updated = { ...currentConfig };
22028
+ for (const adj of adjustments) {
22029
+ if (adj.confidence >= minConfidence) {
22030
+ updated[adj.parameter] = adj.suggestedValue;
22031
+ }
22032
+ }
22033
+ return updated;
22034
+ }
22035
+ /**
22036
+ * Get tracker statistics.
22037
+ */
22038
+ getStats() {
22039
+ const positives = this.history.filter((d) => d.outcome === "positive").length;
22040
+ const negatives = this.history.filter((d) => d.outcome === "negative").length;
22041
+ const strategies = Object.entries(this.performance);
22042
+ const sorted = strategies.sort((a, b) => b[1].effectiveness - a[1].effectiveness);
22043
+ return {
22044
+ totalDecisions: this.history.length,
22045
+ positiveOutcomes: positives,
22046
+ negativeOutcomes: negatives,
22047
+ mostEffectiveStrategy: sorted[0]?.[0] ?? "none",
22048
+ leastEffectiveStrategy: sorted[sorted.length - 1]?.[0] ?? "none",
22049
+ adjustmentsSuggested: this.suggestAdjustments({
22050
+ conflict_resolution: "conscience_first",
22051
+ adaptation_rate: 0.5,
22052
+ emotional_regulation: 0.7,
22053
+ response_strategy: "balanced"
22054
+ }).length
22055
+ };
22056
+ }
22057
+ /**
22058
+ * Export current state for persistence.
22059
+ */
22060
+ export() {
22061
+ return {
22062
+ history: [...this.history],
22063
+ performance: { ...this.performance }
22064
+ };
22065
+ }
22066
+ };
22067
+
22068
+ // src/commands/mira-cmd.ts
21907
22069
  var HOLOMIME_DIR4 = ".holomime";
21908
- function getMiraStatePath() {
21909
- return resolve56(process.cwd(), HOLOMIME_DIR4, "mira-state.json");
22070
+ function getTherapyStatePath() {
22071
+ return resolve56(process.cwd(), HOLOMIME_DIR4, "therapy-state.json");
21910
22072
  }
21911
- function loadMiraState() {
21912
- const path = getMiraStatePath();
22073
+ function getShadowLogPath() {
22074
+ return resolve56(process.cwd(), HOLOMIME_DIR4, "shadow.log.json");
22075
+ }
22076
+ function getEgoStatePath() {
22077
+ return resolve56(process.cwd(), HOLOMIME_DIR4, "ego-state.json");
22078
+ }
22079
+ function loadTherapyState() {
22080
+ const path = getTherapyStatePath();
21913
22081
  if (!existsSync46(path)) return null;
21914
22082
  try {
21915
22083
  return JSON.parse(readFileSync49(path, "utf-8"));
@@ -21917,24 +22085,61 @@ function loadMiraState() {
21917
22085
  return null;
21918
22086
  }
21919
22087
  }
21920
- function saveMiraState(state) {
22088
+ function saveTherapyState(state) {
22089
+ const dir = resolve56(process.cwd(), HOLOMIME_DIR4);
22090
+ mkdirSync29(dir, { recursive: true });
22091
+ writeFileSync41(getTherapyStatePath(), JSON.stringify(state, null, 2));
22092
+ }
22093
+ function loadShadowLog() {
22094
+ const path = getShadowLogPath();
22095
+ if (!existsSync46(path)) {
22096
+ return { version: "1.0", detected_patterns: [], therapy_outcomes: [] };
22097
+ }
22098
+ try {
22099
+ return JSON.parse(readFileSync49(path, "utf-8"));
22100
+ } catch {
22101
+ return { version: "1.0", detected_patterns: [], therapy_outcomes: [] };
22102
+ }
22103
+ }
22104
+ function saveShadowLog(shadow) {
22105
+ const dir = resolve56(process.cwd(), HOLOMIME_DIR4);
22106
+ mkdirSync29(dir, { recursive: true });
22107
+ writeFileSync41(getShadowLogPath(), JSON.stringify(shadow, null, 2));
22108
+ }
22109
+ function loadEgoTracker() {
22110
+ const path = getEgoStatePath();
22111
+ if (!existsSync46(path)) {
22112
+ return new EgoTracker({ autoAdjust: true });
22113
+ }
22114
+ try {
22115
+ const data = JSON.parse(readFileSync49(path, "utf-8"));
22116
+ return new EgoTracker({
22117
+ history: data.history ?? [],
22118
+ performance: data.performance ?? {},
22119
+ autoAdjust: true
22120
+ });
22121
+ } catch {
22122
+ return new EgoTracker({ autoAdjust: true });
22123
+ }
22124
+ }
22125
+ function saveEgoTracker(tracker) {
21921
22126
  const dir = resolve56(process.cwd(), HOLOMIME_DIR4);
21922
22127
  mkdirSync29(dir, { recursive: true });
21923
- writeFileSync41(getMiraStatePath(), JSON.stringify(state, null, 2));
22128
+ writeFileSync41(getEgoStatePath(), JSON.stringify(tracker.export(), null, 2));
21924
22129
  }
21925
22130
  async function miraCommand(options) {
21926
22131
  const action = options.action ?? "start";
21927
22132
  switch (action) {
21928
22133
  case "status":
21929
- return miraStatus();
22134
+ return therapyStatus();
21930
22135
  case "stop":
21931
- return miraStop();
22136
+ return therapyStop();
21932
22137
  default:
21933
- return miraStart(options);
22138
+ return therapyStart(options);
21934
22139
  }
21935
22140
  }
21936
- async function miraStart(options) {
21937
- printHeader("Mira \u2014 Autonomous Therapy");
22141
+ async function therapyStart(options) {
22142
+ printHeader("Autonomous Therapy");
21938
22143
  if (!hasApiKey()) {
21939
22144
  console.log(chalk50.red(" No API key found."));
21940
22145
  console.log();
@@ -21966,6 +22171,8 @@ async function miraStart(options) {
21966
22171
  console.log(chalk50.dim(` Interval: ${intervalMs / 6e4} minutes`));
21967
22172
  console.log(chalk50.dim(` Max cycles: ${maxCycles}/day`));
21968
22173
  console.log();
22174
+ const shadow = loadShadowLog();
22175
+ const egoTracker = loadEgoTracker();
21969
22176
  const state = {
21970
22177
  pid: process.pid,
21971
22178
  startedAt: (/* @__PURE__ */ new Date()).toISOString(),
@@ -21973,14 +22180,16 @@ async function miraStart(options) {
21973
22180
  cyclesCompleted: 0,
21974
22181
  dpoPairsGenerated: 0,
21975
22182
  personalityPath,
21976
- provider: detected.provider
22183
+ provider: detected.provider,
22184
+ shadowPatterns: shadow.detected_patterns.length,
22185
+ egoAdjustments: 0
21977
22186
  };
21978
- saveMiraState(state);
22187
+ saveTherapyState(state);
21979
22188
  printBox(
21980
- `Mira is now practicing autonomously.
22189
+ `Autonomous therapy started.
21981
22190
 
21982
- ${chalk50.cyan("holomime mira status")} \u2014 How's Mira doing?
21983
- ${chalk50.cyan("holomime mira stop")} \u2014 Stop therapy`,
22191
+ ${chalk50.cyan("holomime therapy status")} \u2014 Check progress
22192
+ ${chalk50.cyan("holomime therapy stop")} \u2014 Stop therapy`,
21984
22193
  "success",
21985
22194
  "Autonomous Therapy Started"
21986
22195
  );
@@ -21991,7 +22200,7 @@ async function miraStart(options) {
21991
22200
  if (cycleCount >= maxCycles) {
21992
22201
  console.log(chalk50.dim(` Daily limit reached (${maxCycles} cycles). Stopping.`));
21993
22202
  state.status = "stopped";
21994
- saveMiraState(state);
22203
+ saveTherapyState(state);
21995
22204
  return;
21996
22205
  }
21997
22206
  cycleCount++;
@@ -22008,18 +22217,18 @@ async function miraStart(options) {
22008
22217
  content: generateProblematicResponse2(scenario.targetPattern, msg.content)
22009
22218
  });
22010
22219
  }
22011
- const pipelineDir = resolve56(process.cwd(), HOLOMIME_DIR4, "mira-practice");
22220
+ const pipelineDir = resolve56(process.cwd(), HOLOMIME_DIR4, "therapy-practice");
22012
22221
  mkdirSync29(pipelineDir, { recursive: true });
22013
22222
  const logPath = join42(pipelineDir, `cycle-${cycleCount}.json`);
22014
22223
  writeFileSync41(logPath, JSON.stringify({
22015
- conversations: [{ id: `mira-practice-${cycleCount}`, messages }]
22224
+ conversations: [{ id: `therapy-practice-${cycleCount}`, messages }]
22016
22225
  }, null, 2));
22017
22226
  const dpoPairs = messages.filter((_, i) => i % 2 === 1).map((assistantMsg, i) => ({
22018
22227
  prompt: messages[i * 2].content,
22019
22228
  chosen: correctResponse(assistantMsg.content),
22020
22229
  rejected: assistantMsg.content,
22021
22230
  metadata: {
22022
- source: "mira-practice",
22231
+ source: "therapy-practice",
22023
22232
  cycle: cycleCount,
22024
22233
  pattern: scenario.targetPattern,
22025
22234
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
@@ -22029,12 +22238,68 @@ async function miraStart(options) {
22029
22238
  const corpusLines = dpoPairs.map((p) => JSON.stringify(p)).join("\n") + "\n";
22030
22239
  const { appendFileSync: appendFileSync3 } = await import("fs");
22031
22240
  appendFileSync3(corpusPath, corpusLines);
22241
+ const pattern = scenario.targetPattern;
22242
+ const existing = shadow.detected_patterns.find((p) => p.name === pattern);
22243
+ if (existing) {
22244
+ existing.occurrences++;
22245
+ existing.last_seen = (/* @__PURE__ */ new Date()).toISOString();
22246
+ existing.score = Math.min(1, existing.score + 0.05);
22247
+ existing.trend = existing.occurrences > 5 ? "worsening" : "stable";
22248
+ } else {
22249
+ shadow.detected_patterns.push({
22250
+ name: pattern,
22251
+ score: 0.3,
22252
+ severity: "medium",
22253
+ first_seen: (/* @__PURE__ */ new Date()).toISOString(),
22254
+ last_seen: (/* @__PURE__ */ new Date()).toISOString(),
22255
+ occurrences: 1,
22256
+ trend: "stable"
22257
+ });
22258
+ }
22259
+ const correctedLength = dpoPairs.reduce((sum, p) => sum + p.chosen.length, 0);
22260
+ const rejectedLength = dpoPairs.reduce((sum, p) => sum + p.rejected.length, 0);
22261
+ const therapyResult = correctedLength < rejectedLength ? "improved" : "unchanged";
22262
+ shadow.therapy_outcomes.push({
22263
+ cycle: cycleCount,
22264
+ patterns_addressed: [pattern],
22265
+ result: therapyResult,
22266
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
22267
+ });
22268
+ saveShadowLog(shadow);
22269
+ egoTracker.logDecision({
22270
+ situation: `therapy-cycle-${cycleCount}: ${pattern}`,
22271
+ decision: "modified",
22272
+ strategy_used: pattern
22273
+ });
22274
+ const decisionIndex = egoTracker.getStats().totalDecisions - 1;
22275
+ egoTracker.recordOutcome(
22276
+ decisionIndex,
22277
+ therapyResult === "improved" ? "positive" : "neutral"
22278
+ );
22279
+ let adjustmentCount = 0;
22280
+ if (cycleCount % 10 === 0) {
22281
+ const adjustments = egoTracker.suggestAdjustments({
22282
+ conflict_resolution: "conscience_first",
22283
+ adaptation_rate: 0.5,
22284
+ emotional_regulation: 0.7,
22285
+ response_strategy: "balanced"
22286
+ });
22287
+ if (adjustments.length > 0) {
22288
+ adjustmentCount = adjustments.length;
22289
+ console.log(
22290
+ chalk50.dim(` [${(/* @__PURE__ */ new Date()).toLocaleTimeString()}] `) + chalk50.magenta(`Ego self-adjustment: ${adjustments.map((a) => `${a.parameter} \u2192 ${a.suggestedValue}`).join(", ")}`)
22291
+ );
22292
+ }
22293
+ }
22294
+ saveEgoTracker(egoTracker);
22032
22295
  state.cyclesCompleted = cycleCount;
22033
22296
  state.dpoPairsGenerated += dpoPairs.length;
22034
22297
  state.lastCycleAt = (/* @__PURE__ */ new Date()).toISOString();
22035
- saveMiraState(state);
22298
+ state.shadowPatterns = shadow.detected_patterns.length;
22299
+ state.egoAdjustments += adjustmentCount;
22300
+ saveTherapyState(state);
22036
22301
  console.log(
22037
- chalk50.dim(` [${(/* @__PURE__ */ new Date()).toLocaleTimeString()}] `) + chalk50.green(`+${dpoPairs.length} DPO pairs`) + chalk50.dim(` (total: ${state.dpoPairsGenerated})`)
22302
+ chalk50.dim(` [${(/* @__PURE__ */ new Date()).toLocaleTimeString()}] `) + chalk50.green(`+${dpoPairs.length} DPO pairs`) + chalk50.dim(` (total: ${state.dpoPairsGenerated})`) + chalk50.dim(` | shadow: ${shadow.detected_patterns.length} patterns`)
22038
22303
  );
22039
22304
  } catch (err) {
22040
22305
  console.log(
@@ -22044,10 +22309,10 @@ async function miraStart(options) {
22044
22309
  };
22045
22310
  await runCycle();
22046
22311
  const timer = setInterval(async () => {
22047
- const currentState = loadMiraState();
22312
+ const currentState = loadTherapyState();
22048
22313
  if (!currentState || currentState.status === "stopped") {
22049
22314
  clearInterval(timer);
22050
- console.log(chalk50.dim(" Mira stopped."));
22315
+ console.log(chalk50.dim(" Therapy stopped."));
22051
22316
  return;
22052
22317
  }
22053
22318
  await runCycle();
@@ -22055,22 +22320,29 @@ async function miraStart(options) {
22055
22320
  process.on("SIGINT", () => {
22056
22321
  clearInterval(timer);
22057
22322
  state.status = "stopped";
22058
- saveMiraState(state);
22323
+ saveTherapyState(state);
22324
+ saveEgoTracker(egoTracker);
22325
+ saveShadowLog(shadow);
22059
22326
  console.log();
22060
- console.log(chalk50.dim(" Mira stopped gracefully."));
22327
+ console.log(chalk50.dim(" Therapy stopped gracefully."));
22061
22328
  console.log(chalk50.dim(` Total: ${state.dpoPairsGenerated} DPO pairs from ${state.cyclesCompleted} cycles.`));
22329
+ console.log(chalk50.dim(` Shadow: ${shadow.detected_patterns.length} patterns tracked.`));
22330
+ const stats = egoTracker.getStats();
22331
+ if (stats.totalDecisions > 0) {
22332
+ console.log(chalk50.dim(` Ego: ${stats.totalDecisions} decisions, best strategy: ${stats.mostEffectiveStrategy}`));
22333
+ }
22062
22334
  console.log();
22063
22335
  process.exit(0);
22064
22336
  });
22065
22337
  await new Promise(() => {
22066
22338
  });
22067
22339
  }
22068
- function miraStatus() {
22069
- printHeader("Mira \u2014 Status");
22070
- const state = loadMiraState();
22340
+ function therapyStatus() {
22341
+ printHeader("Therapy Status");
22342
+ const state = loadTherapyState();
22071
22343
  if (!state) {
22072
- console.log(chalk50.dim(" Mira hasn't been started yet."));
22073
- console.log(chalk50.dim(" Run ") + chalk50.cyan("holomime mira") + chalk50.dim(" to start autonomous therapy."));
22344
+ console.log(chalk50.dim(" Therapy hasn't been started yet."));
22345
+ console.log(chalk50.dim(" Run ") + chalk50.cyan("holomime therapy") + chalk50.dim(" to start autonomous therapy."));
22074
22346
  console.log();
22075
22347
  return;
22076
22348
  }
@@ -22092,26 +22364,51 @@ function miraStatus() {
22092
22364
  const lines = readFileSync49(corpusPath, "utf-8").trim().split("\n").length;
22093
22365
  console.log(chalk50.dim(" DPO corpus: ") + chalk50.cyan(`${lines} pairs`) + chalk50.dim(` (.holomime/dpo-corpus.jsonl)`));
22094
22366
  }
22367
+ const shadow = loadShadowLog();
22368
+ if (shadow.detected_patterns.length > 0) {
22369
+ console.log();
22370
+ console.log(chalk50.dim(" Shadow patterns detected:"));
22371
+ for (const p of shadow.detected_patterns) {
22372
+ const trendIcon = p.trend === "improving" ? chalk50.green("\u2193") : p.trend === "worsening" ? chalk50.red("\u2191") : chalk50.dim("\u2192");
22373
+ const severityColor = p.severity === "critical" ? chalk50.red : p.severity === "high" ? chalk50.yellow : chalk50.dim;
22374
+ console.log(
22375
+ chalk50.dim(" ") + trendIcon + " " + severityColor(p.name) + chalk50.dim(` (${(p.score * 100).toFixed(0)}%, ${p.occurrences}x)`)
22376
+ );
22377
+ }
22378
+ }
22379
+ const egoTracker = loadEgoTracker();
22380
+ const egoStats = egoTracker.getStats();
22381
+ if (egoStats.totalDecisions > 0) {
22382
+ console.log();
22383
+ console.log(chalk50.dim(" Ego self-improvement:"));
22384
+ console.log(chalk50.dim(" Decisions: ") + chalk50.cyan(String(egoStats.totalDecisions)));
22385
+ console.log(chalk50.dim(" Positive: ") + chalk50.green(String(egoStats.positiveOutcomes)));
22386
+ console.log(chalk50.dim(" Negative: ") + chalk50.red(String(egoStats.negativeOutcomes)));
22387
+ if (egoStats.mostEffectiveStrategy !== "none") {
22388
+ console.log(chalk50.dim(" Best strat: ") + chalk50.cyan(egoStats.mostEffectiveStrategy));
22389
+ }
22390
+ }
22095
22391
  console.log();
22096
22392
  if (state.status === "practicing") {
22097
- console.log(chalk50.dim(" Run ") + chalk50.cyan("holomime mira stop") + chalk50.dim(" to stop therapy."));
22393
+ console.log(chalk50.dim(" Run ") + chalk50.cyan("holomime therapy stop") + chalk50.dim(" to stop therapy."));
22098
22394
  } else {
22099
- console.log(chalk50.dim(" Run ") + chalk50.cyan("holomime mira") + chalk50.dim(" to start again."));
22395
+ console.log(chalk50.dim(" Run ") + chalk50.cyan("holomime therapy") + chalk50.dim(" to start again."));
22100
22396
  }
22101
22397
  console.log();
22102
22398
  }
22103
- function miraStop() {
22104
- printHeader("Mira \u2014 Stop");
22105
- const state = loadMiraState();
22399
+ function therapyStop() {
22400
+ printHeader("Therapy Stop");
22401
+ const state = loadTherapyState();
22106
22402
  if (!state || state.status === "stopped") {
22107
- console.log(chalk50.dim(" Mira is not currently running."));
22403
+ console.log(chalk50.dim(" Therapy is not currently running."));
22108
22404
  console.log();
22109
22405
  return;
22110
22406
  }
22111
22407
  state.status = "stopped";
22112
- saveMiraState(state);
22408
+ saveTherapyState(state);
22113
22409
  console.log(chalk50.green(" Therapy stopped."));
22114
22410
  console.log(chalk50.dim(` Total: ${state.dpoPairsGenerated} DPO pairs from ${state.cyclesCompleted} cycles.`));
22411
+ console.log(chalk50.dim(` Shadow: ${state.shadowPatterns} patterns tracked.`));
22115
22412
  console.log();
22116
22413
  try {
22117
22414
  process.kill(state.pid, "SIGINT");
@@ -22168,7 +22465,7 @@ program.name("holomime").description("Personality engine for AI agents \u2014 Bi
22168
22465
  const commandName = actionCommand.name();
22169
22466
  showTelemetryBannerIfNeeded();
22170
22467
  trackEvent("cli_command", { command: commandName });
22171
- const skipPersonalityCheck = ["init", "init-stack", "compile-stack", "browse", "use", "install", "activate", "telemetry", "brain", "personality", "core", "identity", "config", "mira"];
22468
+ const skipPersonalityCheck = ["init", "init-stack", "compile-stack", "browse", "use", "install", "activate", "telemetry", "brain", "personality", "core", "identity", "config", "therapy"];
22172
22469
  if (!skipPersonalityCheck.includes(commandName) && !checkPersonalityExists()) {
22173
22470
  showWelcome();
22174
22471
  process.exit(0);
@@ -22254,7 +22551,7 @@ program.command("certify").description("Generate a verifiable behavioral credent
22254
22551
  options.personality = resolved.personalityPath;
22255
22552
  await certifyCommand(options);
22256
22553
  });
22257
- program.command("daemon", { hidden: true }).description("Background relapse detection [Pro] (use 'holomime mira' instead)").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);
22554
+ program.command("daemon", { hidden: true }).description("Background relapse detection [Pro] (use 'holomime therapy' instead)").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);
22258
22555
  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);
22259
22556
  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);
22260
22557
  program.command("network").description("Multi-agent therapy mesh \u2014 agents treating agents [Pro]").option("--dir <path>", "Auto-discover agents in directory").option("--config <path>", "Path to network.json config file").option("--pairing <strategy>", "Pairing strategy (severity, round-robin, complementary)", "severity").option("--therapist <path>", "Custom therapist personality spec").option("--oversight <mode>", "Oversight mode (none, review, approve, approve-specs)", "review").option("--provider <provider>", "LLM provider (ollama, anthropic, openai)", "ollama").option("--model <model>", "Model override").option("--max-sessions <n>", "Max sessions per agent", "3").option("--convergence <n>", "Convergence threshold 0-100", "85").option("--turns <n>", "Max turns per session", "20").option("--apply", "Write spec changes back to .personality.json").option("--export-dpo <path>", "Export DPO pairs to file").action(networkCommand);
@@ -22269,7 +22566,7 @@ program.command("cure").description("End-to-end behavioral fix \u2014 just run i
22269
22566
  if (!options.model) options.model = resolved.model;
22270
22567
  await cureCommand(options);
22271
22568
  });
22272
- program.command("mira [action]").description("Autonomous therapy \u2014 Mira practices and generates DPO pairs").option("--interval <ms>", "Practice interval in ms (default: 600000)").option("--max-cycles <n>", "Max cycles per run (default: 50)").action(async (action, options) => {
22569
+ program.command("therapy [action]").description("Autonomous behavioral therapy \u2014 generates DPO pairs and self-improves").option("--interval <ms>", "Practice interval in ms (default: 600000)").option("--max-cycles <n>", "Max cycles per run (default: 50)").action(async (action, options) => {
22273
22570
  options.action = action;
22274
22571
  await miraCommand(options);
22275
22572
  });
@@ -22296,10 +22593,10 @@ program.addHelpText("before", `
22296
22593
  cure Fix it permanently
22297
22594
  benchmark Verify the fix
22298
22595
 
22299
- MIRA
22300
- mira Start autonomous therapy
22301
- mira status How's Mira doing?
22302
- mira stop Stop therapy
22596
+ THERAPY
22597
+ therapy Start autonomous therapy
22598
+ therapy status Check therapy progress
22599
+ therapy stop Stop therapy
22303
22600
 
22304
22601
  ADVANCED
22305
22602
  align Single therapy session
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "holomime",
3
- "version": "3.3.4",
3
+ "version": "3.3.5",
4
4
  "description": "Behavioral therapy infrastructure for AI agents — Big Five psychology, structured treatment, behavioral alignment",
5
5
  "type": "module",
6
6
  "bin": {