holomime 3.3.3 → 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 +367 -55
  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,11 +3593,12 @@ 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 = "0.2.0";
3597
- var LOGO = ` _ _ _ __ __ _
3598
- | || |___| |___ | \\/ (_)_ __ ___
3599
- | __ / _ \\ / _ \\ | |\\/| | | ' \\/ -_)
3600
- |_||_\\___/_\\___/ |_| |_|_|_|_|_\\___|`;
3596
+ var VERSION = "3.3.5";
3597
+ var LOGO = ` _ _ _
3598
+ | |__ ___ | | ___ _ __ (_)_ __ ___ ___
3599
+ | '_ \\ / _ \\| |/ _ \\| '_ \\| | '_ \` _ \\ / _ \\
3600
+ | | | | (_) | | (_) | | | | | | | | | | __/
3601
+ |_| |_|\\___/|_|\\___/|_| |_|_|_| |_| |_|\\___|`;
3601
3602
  var holomimeGradient = gradientString("#00d4ff", "#b347d9");
3602
3603
  function printBanner() {
3603
3604
  console.log();
@@ -21854,16 +21855,30 @@ async function configCommand(options) {
21854
21855
  });
21855
21856
  const ask = (question) => new Promise((resolve57) => rl.question(question, resolve57));
21856
21857
  try {
21857
- const provider = (await ask(" Provider (anthropic/openai) [anthropic]: ")).trim().toLowerCase() || "anthropic";
21858
- if (provider !== "anthropic" && provider !== "openai") {
21859
- console.log(chalk49.red(` Unsupported provider: ${provider}`));
21858
+ console.log(chalk49.dim(" 1) anthropic") + chalk49.dim(" enter your sk-ant-... key"));
21859
+ console.log(chalk49.dim(" 2) openai") + chalk49.dim(" enter your sk-... key"));
21860
+ console.log();
21861
+ const providerInput = (await ask(" Select provider (1 or 2): ")).trim();
21862
+ let provider;
21863
+ if (providerInput === "1" || providerInput.toLowerCase() === "anthropic") {
21864
+ provider = "anthropic";
21865
+ } else if (providerInput === "2" || providerInput.toLowerCase() === "openai") {
21866
+ provider = "openai";
21867
+ } else if (providerInput === "") {
21868
+ console.log(chalk49.dim(" Skipped. Run `holomime config` when ready."));
21869
+ rl.close();
21870
+ return;
21871
+ } else {
21872
+ console.log(chalk49.red(` Invalid selection: ${providerInput}`));
21860
21873
  rl.close();
21861
21874
  return;
21862
21875
  }
21876
+ console.log(chalk49.dim(` Selected: ${provider}`));
21877
+ console.log();
21863
21878
  const keyHint = provider === "anthropic" ? "sk-ant-..." : "sk-...";
21864
21879
  const apiKey = (await ask(` API Key (${keyHint}): `)).trim();
21865
21880
  if (!apiKey) {
21866
- console.log(chalk49.red(" API key is required."));
21881
+ console.log(chalk49.dim(" Skipped. Run `holomime config` when ready."));
21867
21882
  rl.close();
21868
21883
  return;
21869
21884
  }
@@ -21877,7 +21892,7 @@ async function configCommand(options) {
21877
21892
  console.log(chalk49.cyan(" holomime diagnose"));
21878
21893
  console.log(chalk49.cyan(" holomime cure"));
21879
21894
  console.log(chalk49.cyan(" holomime benchmark"));
21880
- console.log(chalk49.cyan(" holomime daemon"));
21895
+ console.log(chalk49.cyan(" holomime therapy"));
21881
21896
  console.log();
21882
21897
  rl.close();
21883
21898
  } catch {
@@ -21889,12 +21904,180 @@ async function configCommand(options) {
21889
21904
  import chalk50 from "chalk";
21890
21905
  import { writeFileSync as writeFileSync41, readFileSync as readFileSync49, mkdirSync as mkdirSync29, existsSync as existsSync46 } from "fs";
21891
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
21892
22069
  var HOLOMIME_DIR4 = ".holomime";
21893
- function getMiraStatePath() {
21894
- return resolve56(process.cwd(), HOLOMIME_DIR4, "mira-state.json");
22070
+ function getTherapyStatePath() {
22071
+ return resolve56(process.cwd(), HOLOMIME_DIR4, "therapy-state.json");
22072
+ }
22073
+ function getShadowLogPath() {
22074
+ return resolve56(process.cwd(), HOLOMIME_DIR4, "shadow.log.json");
21895
22075
  }
21896
- function loadMiraState() {
21897
- const path = getMiraStatePath();
22076
+ function getEgoStatePath() {
22077
+ return resolve56(process.cwd(), HOLOMIME_DIR4, "ego-state.json");
22078
+ }
22079
+ function loadTherapyState() {
22080
+ const path = getTherapyStatePath();
21898
22081
  if (!existsSync46(path)) return null;
21899
22082
  try {
21900
22083
  return JSON.parse(readFileSync49(path, "utf-8"));
@@ -21902,24 +22085,61 @@ function loadMiraState() {
21902
22085
  return null;
21903
22086
  }
21904
22087
  }
21905
- 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) {
21906
22126
  const dir = resolve56(process.cwd(), HOLOMIME_DIR4);
21907
22127
  mkdirSync29(dir, { recursive: true });
21908
- writeFileSync41(getMiraStatePath(), JSON.stringify(state, null, 2));
22128
+ writeFileSync41(getEgoStatePath(), JSON.stringify(tracker.export(), null, 2));
21909
22129
  }
21910
22130
  async function miraCommand(options) {
21911
22131
  const action = options.action ?? "start";
21912
22132
  switch (action) {
21913
22133
  case "status":
21914
- return miraStatus();
22134
+ return therapyStatus();
21915
22135
  case "stop":
21916
- return miraStop();
22136
+ return therapyStop();
21917
22137
  default:
21918
- return miraStart(options);
22138
+ return therapyStart(options);
21919
22139
  }
21920
22140
  }
21921
- async function miraStart(options) {
21922
- printHeader("Mira \u2014 Autonomous Therapy");
22141
+ async function therapyStart(options) {
22142
+ printHeader("Autonomous Therapy");
21923
22143
  if (!hasApiKey()) {
21924
22144
  console.log(chalk50.red(" No API key found."));
21925
22145
  console.log();
@@ -21951,6 +22171,8 @@ async function miraStart(options) {
21951
22171
  console.log(chalk50.dim(` Interval: ${intervalMs / 6e4} minutes`));
21952
22172
  console.log(chalk50.dim(` Max cycles: ${maxCycles}/day`));
21953
22173
  console.log();
22174
+ const shadow = loadShadowLog();
22175
+ const egoTracker = loadEgoTracker();
21954
22176
  const state = {
21955
22177
  pid: process.pid,
21956
22178
  startedAt: (/* @__PURE__ */ new Date()).toISOString(),
@@ -21958,14 +22180,16 @@ async function miraStart(options) {
21958
22180
  cyclesCompleted: 0,
21959
22181
  dpoPairsGenerated: 0,
21960
22182
  personalityPath,
21961
- provider: detected.provider
22183
+ provider: detected.provider,
22184
+ shadowPatterns: shadow.detected_patterns.length,
22185
+ egoAdjustments: 0
21962
22186
  };
21963
- saveMiraState(state);
22187
+ saveTherapyState(state);
21964
22188
  printBox(
21965
- `Mira is now practicing autonomously.
22189
+ `Autonomous therapy started.
21966
22190
 
21967
- ${chalk50.cyan("holomime mira status")} \u2014 How's Mira doing?
21968
- ${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`,
21969
22193
  "success",
21970
22194
  "Autonomous Therapy Started"
21971
22195
  );
@@ -21976,7 +22200,7 @@ async function miraStart(options) {
21976
22200
  if (cycleCount >= maxCycles) {
21977
22201
  console.log(chalk50.dim(` Daily limit reached (${maxCycles} cycles). Stopping.`));
21978
22202
  state.status = "stopped";
21979
- saveMiraState(state);
22203
+ saveTherapyState(state);
21980
22204
  return;
21981
22205
  }
21982
22206
  cycleCount++;
@@ -21993,18 +22217,18 @@ async function miraStart(options) {
21993
22217
  content: generateProblematicResponse2(scenario.targetPattern, msg.content)
21994
22218
  });
21995
22219
  }
21996
- const pipelineDir = resolve56(process.cwd(), HOLOMIME_DIR4, "mira-practice");
22220
+ const pipelineDir = resolve56(process.cwd(), HOLOMIME_DIR4, "therapy-practice");
21997
22221
  mkdirSync29(pipelineDir, { recursive: true });
21998
22222
  const logPath = join42(pipelineDir, `cycle-${cycleCount}.json`);
21999
22223
  writeFileSync41(logPath, JSON.stringify({
22000
- conversations: [{ id: `mira-practice-${cycleCount}`, messages }]
22224
+ conversations: [{ id: `therapy-practice-${cycleCount}`, messages }]
22001
22225
  }, null, 2));
22002
22226
  const dpoPairs = messages.filter((_, i) => i % 2 === 1).map((assistantMsg, i) => ({
22003
22227
  prompt: messages[i * 2].content,
22004
22228
  chosen: correctResponse(assistantMsg.content),
22005
22229
  rejected: assistantMsg.content,
22006
22230
  metadata: {
22007
- source: "mira-practice",
22231
+ source: "therapy-practice",
22008
22232
  cycle: cycleCount,
22009
22233
  pattern: scenario.targetPattern,
22010
22234
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
@@ -22014,12 +22238,68 @@ async function miraStart(options) {
22014
22238
  const corpusLines = dpoPairs.map((p) => JSON.stringify(p)).join("\n") + "\n";
22015
22239
  const { appendFileSync: appendFileSync3 } = await import("fs");
22016
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);
22017
22295
  state.cyclesCompleted = cycleCount;
22018
22296
  state.dpoPairsGenerated += dpoPairs.length;
22019
22297
  state.lastCycleAt = (/* @__PURE__ */ new Date()).toISOString();
22020
- saveMiraState(state);
22298
+ state.shadowPatterns = shadow.detected_patterns.length;
22299
+ state.egoAdjustments += adjustmentCount;
22300
+ saveTherapyState(state);
22021
22301
  console.log(
22022
- 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`)
22023
22303
  );
22024
22304
  } catch (err) {
22025
22305
  console.log(
@@ -22029,10 +22309,10 @@ async function miraStart(options) {
22029
22309
  };
22030
22310
  await runCycle();
22031
22311
  const timer = setInterval(async () => {
22032
- const currentState = loadMiraState();
22312
+ const currentState = loadTherapyState();
22033
22313
  if (!currentState || currentState.status === "stopped") {
22034
22314
  clearInterval(timer);
22035
- console.log(chalk50.dim(" Mira stopped."));
22315
+ console.log(chalk50.dim(" Therapy stopped."));
22036
22316
  return;
22037
22317
  }
22038
22318
  await runCycle();
@@ -22040,22 +22320,29 @@ async function miraStart(options) {
22040
22320
  process.on("SIGINT", () => {
22041
22321
  clearInterval(timer);
22042
22322
  state.status = "stopped";
22043
- saveMiraState(state);
22323
+ saveTherapyState(state);
22324
+ saveEgoTracker(egoTracker);
22325
+ saveShadowLog(shadow);
22044
22326
  console.log();
22045
- console.log(chalk50.dim(" Mira stopped gracefully."));
22327
+ console.log(chalk50.dim(" Therapy stopped gracefully."));
22046
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
+ }
22047
22334
  console.log();
22048
22335
  process.exit(0);
22049
22336
  });
22050
22337
  await new Promise(() => {
22051
22338
  });
22052
22339
  }
22053
- function miraStatus() {
22054
- printHeader("Mira \u2014 Status");
22055
- const state = loadMiraState();
22340
+ function therapyStatus() {
22341
+ printHeader("Therapy Status");
22342
+ const state = loadTherapyState();
22056
22343
  if (!state) {
22057
- console.log(chalk50.dim(" Mira hasn't been started yet."));
22058
- 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."));
22059
22346
  console.log();
22060
22347
  return;
22061
22348
  }
@@ -22077,26 +22364,51 @@ function miraStatus() {
22077
22364
  const lines = readFileSync49(corpusPath, "utf-8").trim().split("\n").length;
22078
22365
  console.log(chalk50.dim(" DPO corpus: ") + chalk50.cyan(`${lines} pairs`) + chalk50.dim(` (.holomime/dpo-corpus.jsonl)`));
22079
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
+ }
22080
22391
  console.log();
22081
22392
  if (state.status === "practicing") {
22082
- 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."));
22083
22394
  } else {
22084
- 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."));
22085
22396
  }
22086
22397
  console.log();
22087
22398
  }
22088
- function miraStop() {
22089
- printHeader("Mira \u2014 Stop");
22090
- const state = loadMiraState();
22399
+ function therapyStop() {
22400
+ printHeader("Therapy Stop");
22401
+ const state = loadTherapyState();
22091
22402
  if (!state || state.status === "stopped") {
22092
- console.log(chalk50.dim(" Mira is not currently running."));
22403
+ console.log(chalk50.dim(" Therapy is not currently running."));
22093
22404
  console.log();
22094
22405
  return;
22095
22406
  }
22096
22407
  state.status = "stopped";
22097
- saveMiraState(state);
22408
+ saveTherapyState(state);
22098
22409
  console.log(chalk50.green(" Therapy stopped."));
22099
22410
  console.log(chalk50.dim(` Total: ${state.dpoPairsGenerated} DPO pairs from ${state.cyclesCompleted} cycles.`));
22411
+ console.log(chalk50.dim(` Shadow: ${state.shadowPatterns} patterns tracked.`));
22100
22412
  console.log();
22101
22413
  try {
22102
22414
  process.kill(state.pid, "SIGINT");
@@ -22153,7 +22465,7 @@ program.name("holomime").description("Personality engine for AI agents \u2014 Bi
22153
22465
  const commandName = actionCommand.name();
22154
22466
  showTelemetryBannerIfNeeded();
22155
22467
  trackEvent("cli_command", { command: commandName });
22156
- 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"];
22157
22469
  if (!skipPersonalityCheck.includes(commandName) && !checkPersonalityExists()) {
22158
22470
  showWelcome();
22159
22471
  process.exit(0);
@@ -22239,7 +22551,7 @@ program.command("certify").description("Generate a verifiable behavioral credent
22239
22551
  options.personality = resolved.personalityPath;
22240
22552
  await certifyCommand(options);
22241
22553
  });
22242
- 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);
22243
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);
22244
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);
22245
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);
@@ -22254,7 +22566,7 @@ program.command("cure").description("End-to-end behavioral fix \u2014 just run i
22254
22566
  if (!options.model) options.model = resolved.model;
22255
22567
  await cureCommand(options);
22256
22568
  });
22257
- 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) => {
22258
22570
  options.action = action;
22259
22571
  await miraCommand(options);
22260
22572
  });
@@ -22281,10 +22593,10 @@ program.addHelpText("before", `
22281
22593
  cure Fix it permanently
22282
22594
  benchmark Verify the fix
22283
22595
 
22284
- MIRA
22285
- mira Start autonomous therapy
22286
- mira status How's Mira doing?
22287
- mira stop Stop therapy
22596
+ THERAPY
22597
+ therapy Start autonomous therapy
22598
+ therapy status Check therapy progress
22599
+ therapy stop Stop therapy
22288
22600
 
22289
22601
  ADVANCED
22290
22602
  align Single therapy session
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "holomime",
3
- "version": "3.3.3",
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": {