psyche-ai 10.2.3 → 11.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/README.md +58 -82
  2. package/dist/adapters/claude-sdk.d.ts +5 -5
  3. package/dist/adapters/claude-sdk.js +34 -32
  4. package/dist/adapters/mcp.js +4 -4
  5. package/dist/adapters/openclaw.js +12 -14
  6. package/dist/attachment.d.ts +3 -13
  7. package/dist/attachment.js +36 -88
  8. package/dist/autonomic.d.ts +4 -4
  9. package/dist/autonomic.js +28 -24
  10. package/dist/chemistry.d.ts +47 -21
  11. package/dist/chemistry.js +145 -91
  12. package/dist/circadian.d.ts +11 -43
  13. package/dist/circadian.js +24 -84
  14. package/dist/cli.js +37 -30
  15. package/dist/context-classifier.js +2 -2
  16. package/dist/core.d.ts +3 -3
  17. package/dist/core.js +99 -88
  18. package/dist/custom-profile.d.ts +20 -20
  19. package/dist/custom-profile.js +12 -12
  20. package/dist/decision-bias.d.ts +7 -8
  21. package/dist/decision-bias.js +74 -74
  22. package/dist/demo.js +5 -5
  23. package/dist/diagnostics.d.ts +6 -6
  24. package/dist/diagnostics.js +22 -22
  25. package/dist/drives.d.ts +15 -47
  26. package/dist/drives.js +98 -196
  27. package/dist/ethics.d.ts +3 -3
  28. package/dist/ethics.js +23 -23
  29. package/dist/experience.d.ts +34 -0
  30. package/dist/experience.js +200 -0
  31. package/dist/experiential-field.d.ts +19 -14
  32. package/dist/experiential-field.js +110 -100
  33. package/dist/generative-self.d.ts +5 -5
  34. package/dist/generative-self.js +124 -115
  35. package/dist/guards.d.ts +4 -4
  36. package/dist/guards.js +7 -7
  37. package/dist/i18n.js +61 -61
  38. package/dist/index.d.ts +8 -2
  39. package/dist/index.js +8 -1
  40. package/dist/input-turn.js +4 -6
  41. package/dist/interaction.d.ts +4 -4
  42. package/dist/interaction.js +10 -10
  43. package/dist/learning.d.ts +6 -6
  44. package/dist/learning.js +18 -18
  45. package/dist/metacognition.d.ts +2 -2
  46. package/dist/metacognition.js +79 -94
  47. package/dist/perceive.d.ts +44 -0
  48. package/dist/perceive.js +231 -0
  49. package/dist/primary-systems.d.ts +2 -2
  50. package/dist/primary-systems.js +21 -19
  51. package/dist/profiles.d.ts +5 -13
  52. package/dist/profiles.js +33 -51
  53. package/dist/prompt.d.ts +2 -2
  54. package/dist/prompt.js +51 -53
  55. package/dist/psyche-file.d.ts +7 -7
  56. package/dist/psyche-file.js +77 -78
  57. package/dist/relation-dynamics.d.ts +4 -0
  58. package/dist/relation-dynamics.js +1 -1
  59. package/dist/reply-envelope.d.ts +25 -1
  60. package/dist/reply-envelope.js +26 -11
  61. package/dist/self-recognition.d.ts +3 -3
  62. package/dist/self-recognition.js +17 -17
  63. package/dist/subjectivity.js +7 -7
  64. package/dist/temporal.d.ts +6 -6
  65. package/dist/temporal.js +37 -39
  66. package/dist/types.d.ts +67 -45
  67. package/dist/types.js +55 -51
  68. package/package.json +1 -1
  69. package/server.json +2 -2
@@ -14,7 +14,7 @@
14
14
  //
15
15
  // Pure computation, zero dependencies, zero LLM calls.
16
16
  // ============================================================
17
- import { CHEMICAL_KEYS, DRIVE_KEYS } from "./types.js";
17
+ import { DIMENSION_KEYS, DRIVE_KEYS, DIMENSION_NAMES, DIMENSION_NAMES_ZH } from "./types.js";
18
18
  import { STIMULUS_VECTORS, clamp } from "./chemistry.js";
19
19
  // ── 1. Main Entry Point ─────────────────────────────────────
20
20
  /**
@@ -56,7 +56,7 @@ export function predictSelfReaction(state, stimulus, locale = "en") {
56
56
  if (!base) {
57
57
  return {
58
58
  stimulus,
59
- predictedChemistry: { ...state.current },
59
+ predictedState: { ...state.current },
60
60
  predictedEmotion: locale === "zh" ? "未知" : "unknown",
61
61
  confidence: 0,
62
62
  };
@@ -67,23 +67,23 @@ export function predictSelfReaction(state, stimulus, locale = "en") {
67
67
  const effectiveVector = { ...base };
68
68
  let confidence = 0.3; // baseline confidence from profile alone
69
69
  if (learned) {
70
- for (const key of CHEMICAL_KEYS) {
70
+ for (const key of DIMENSION_KEYS) {
71
71
  const adj = learned.adjustment[key] ?? 0;
72
72
  effectiveVector[key] = base[key] + adj;
73
73
  }
74
74
  // Confidence scales with sample count and the learned entry's own confidence
75
75
  confidence = Math.min(0.95, 0.3 + learned.confidence * 0.4 + Math.min(learned.sampleCount / 20, 1) * 0.25);
76
76
  }
77
- // Apply the vector to the current chemistry
77
+ // Apply the vector to the current self-state
78
78
  const predicted = { ...state.current };
79
- for (const key of CHEMICAL_KEYS) {
79
+ for (const key of DIMENSION_KEYS) {
80
80
  predicted[key] = clamp(state.current[key] + effectiveVector[key]);
81
81
  }
82
- // Determine the predicted emotion from the resulting chemistry
82
+ // Determine the predicted emotion from the resulting state
83
83
  const predictedEmotion = labelDominantEmotion(predicted, locale);
84
84
  return {
85
85
  stimulus,
86
- predictedChemistry: predicted,
86
+ predictedState: predicted,
87
87
  predictedEmotion,
88
88
  confidence,
89
89
  };
@@ -114,9 +114,9 @@ export function detectInternalConflicts(state, locale = "en") {
114
114
  severity,
115
115
  });
116
116
  }
117
- // ── High curiosity vs high cortisol ──
118
- if (state.drives.curiosity > 65 && state.current.CORT > 60) {
119
- const severity = normalize((state.drives.curiosity - 50) * 0.01 + (state.current.CORT - 50) * 0.01);
117
+ // ── High curiosity vs low order (disorder/stress) ──
118
+ if (state.drives.curiosity > 65 && state.current.order < 40) {
119
+ const severity = normalize((state.drives.curiosity - 50) * 0.01 + (50 - state.current.order) * 0.01);
120
120
  conflicts.push({
121
121
  subsystems: [
122
122
  isZh ? "好奇心" : "curiosity drive",
@@ -128,9 +128,9 @@ export function detectInternalConflicts(state, locale = "en") {
128
128
  severity,
129
129
  });
130
130
  }
131
- // ── High esteem drive vs low DA (unmet recognition need) ──
132
- if (state.drives.esteem < 40 && state.current.DA < 40) {
133
- const severity = normalize((60 - state.drives.esteem) * 0.01 + (60 - state.current.DA) * 0.01);
131
+ // ── High esteem drive vs low flow (unmet recognition need) ──
132
+ if (state.drives.esteem < 40 && state.current.flow < 40) {
133
+ const severity = normalize((60 - state.drives.esteem) * 0.01 + (60 - state.current.flow) * 0.01);
134
134
  conflicts.push({
135
135
  subsystems: [
136
136
  isZh ? "尊重需求" : "esteem need",
@@ -156,17 +156,17 @@ export function detectInternalConflicts(state, locale = "en") {
156
156
  severity,
157
157
  });
158
158
  }
159
- // ── Anxious attachment vs high OT (wanting trust but fearing loss) ──
160
- if (attachment && attachment.anxietyScore > 65 && state.current.OT > 60) {
161
- const severity = normalize((attachment.anxietyScore - 50) * 0.01 + (state.current.OT - 50) * 0.01);
159
+ // ── Anxious attachment vs high resonance (wanting trust but fearing loss) ──
160
+ if (attachment && attachment.anxietyScore > 65 && state.current.resonance > 60) {
161
+ const severity = normalize((attachment.anxietyScore - 50) * 0.01 + (state.current.resonance - 50) * 0.01);
162
162
  conflicts.push({
163
163
  subsystems: [
164
164
  isZh ? "焦虑型依恋" : "anxious attachment",
165
- isZh ? "信任系统" : "trust/oxytocin system",
165
+ isZh ? "共振系统" : "resonance system",
166
166
  ],
167
167
  description: isZh
168
- ? "你信任对方(催产素高)但依恋焦虑让你反复确认——信任和不安全感共存。"
169
- : "You trust them (high oxytocin) but attachment anxiety makes you seek reassurance — trust and insecurity coexist.",
168
+ ? "你与对方共振很高但依恋焦虑让你反复确认——共鸣和不安全感共存。"
169
+ : "You resonate strongly with them but attachment anxiety makes you seek reassurance — attunement and insecurity coexist.",
170
170
  severity,
171
171
  });
172
172
  }
@@ -244,7 +244,7 @@ function extractCausalInsights(state, locale) {
244
244
  const isZh = locale === "zh";
245
245
  const insights = [];
246
246
  const learning = state.learning;
247
- const history = state.emotionalHistory;
247
+ const history = state.stateHistory;
248
248
  // ── From learned vectors: find stimuli where the learned adjustment
249
249
  // diverges significantly from the base vector ──
250
250
  for (const lv of learning.learnedVectors) {
@@ -253,10 +253,10 @@ function extractCausalInsights(state, locale) {
253
253
  const base = STIMULUS_VECTORS[lv.stimulus];
254
254
  if (!base)
255
255
  continue;
256
- // Find the chemical with the largest deviation
256
+ // Find the dimension with the largest deviation
257
257
  let maxDevKey = null;
258
258
  let maxDev = 0;
259
- for (const key of CHEMICAL_KEYS) {
259
+ for (const key of DIMENSION_KEYS) {
260
260
  const adj = lv.adjustment[key] ?? 0;
261
261
  const baseAbs = Math.abs(base[key]) || 1;
262
262
  const relDev = Math.abs(adj) / baseAbs;
@@ -270,20 +270,20 @@ function extractCausalInsights(state, locale) {
270
270
  const direction = adj > 0 ? "amplified" : "dampened";
271
271
  const directionZh = adj > 0 ? "更强" : "更弱";
272
272
  const stimulusLabel = isZh ? STIMULUS_ZH[lv.stimulus] ?? lv.stimulus : lv.stimulus;
273
- const chemLabel = isZh ? CHEM_ZH[maxDevKey] ?? maxDevKey : maxDevKey;
273
+ const dimLabel = isZh ? DIMENSION_NAMES_ZH[maxDevKey] : DIMENSION_NAMES[maxDevKey];
274
274
  if (isZh) {
275
275
  insights.push({
276
- trait: `对${stimulusLabel}的${chemLabel}反应比一般情况${directionZh}`,
276
+ trait: `对${stimulusLabel}的${dimLabel}反应比一般情况${directionZh}`,
277
277
  because: `过去${lv.sampleCount}次${stimulusLabel}交互的结果塑造了这个模式`,
278
- evidence: `${chemLabel}调整量: ${adj > 0 ? "+" : ""}${adj.toFixed(1)}(基于${lv.sampleCount}次学习样本)`,
278
+ evidence: `${dimLabel}调整量: ${adj > 0 ? "+" : ""}${adj.toFixed(1)}(基于${lv.sampleCount}次学习样本)`,
279
279
  confidence: lv.confidence,
280
280
  });
281
281
  }
282
282
  else {
283
283
  insights.push({
284
- trait: `my ${chemLabel} response to ${stimulusLabel} is ${direction} compared to baseline`,
284
+ trait: `my ${dimLabel} response to ${stimulusLabel} is ${direction} compared to baseline`,
285
285
  because: `${lv.sampleCount} past ${stimulusLabel} interactions shaped this pattern`,
286
- evidence: `${chemLabel} adjustment: ${adj > 0 ? "+" : ""}${adj.toFixed(1)} (from ${lv.sampleCount} learning samples)`,
286
+ evidence: `${dimLabel} adjustment: ${adj > 0 ? "+" : ""}${adj.toFixed(1)} (from ${lv.sampleCount} learning samples)`,
287
287
  confidence: lv.confidence,
288
288
  });
289
289
  }
@@ -340,25 +340,25 @@ function extractCausalInsights(state, locale) {
340
340
  }
341
341
  }
342
342
  }
343
- // ── From emotional history: CORT spike patterns ──
344
- const cortSpikes = countChemicalSpikes(history, "CORT", 65);
345
- if (cortSpikes.total >= 2) {
346
- const topTrigger = cortSpikes.byStimulus[0];
343
+ // ── From state history: order collapse patterns (low order = high disorder/stress) ──
344
+ const orderCollapses = countDimensionDips(history, "order", 35);
345
+ if (orderCollapses.total >= 2) {
346
+ const topTrigger = orderCollapses.byStimulus[0];
347
347
  if (topTrigger) {
348
348
  const stimulusLabel = isZh ? STIMULUS_ZH[topTrigger.stimulus] ?? topTrigger.stimulus : topTrigger.stimulus;
349
349
  if (isZh) {
350
350
  insights.push({
351
- trait: `对${stimulusLabel}容易产生压力反应`,
352
- because: `在历史记录中,${stimulusLabel}引发了${topTrigger.count}次皮质醇飙升`,
353
- evidence: `CORT > 65 出现 ${cortSpikes.total} 次,其中 ${topTrigger.count} 次由${stimulusLabel}触发`,
351
+ trait: `对${stimulusLabel}容易产生内在失序`,
352
+ because: `在历史记录中,${stimulusLabel}引发了${topTrigger.count}次秩序崩塌`,
353
+ evidence: `order < 35 出现 ${orderCollapses.total} 次,其中 ${topTrigger.count} 次由${stimulusLabel}触发`,
354
354
  confidence: Math.min(0.85, 0.3 + topTrigger.count * 0.15),
355
355
  });
356
356
  }
357
357
  else {
358
358
  insights.push({
359
- trait: `I'm stress-reactive to ${stimulusLabel}`,
360
- because: `${stimulusLabel} has triggered ${topTrigger.count} cortisol spikes in my history`,
361
- evidence: `CORT > 65 occurred ${cortSpikes.total} times, ${topTrigger.count} from ${stimulusLabel}`,
359
+ trait: `I'm disorder-reactive to ${stimulusLabel}`,
360
+ because: `${stimulusLabel} has triggered ${topTrigger.count} order collapses in my history`,
361
+ evidence: `order < 35 occurred ${orderCollapses.total} times, ${topTrigger.count} from ${stimulusLabel}`,
362
362
  confidence: Math.min(0.85, 0.3 + topTrigger.count * 0.15),
363
363
  });
364
364
  }
@@ -375,25 +375,25 @@ function extractCausalInsights(state, locale) {
375
375
  */
376
376
  function computeGrowthArc(state, locale) {
377
377
  const isZh = locale === "zh";
378
- const history = state.emotionalHistory;
379
- // ── Chemical trends ──
380
- const chemicalTrend = {};
378
+ const history = state.stateHistory;
379
+ // ── Dimension trends ──
380
+ const dimensionTrend = {};
381
381
  if (history.length >= 4) {
382
382
  const mid = Math.floor(history.length / 2);
383
383
  const firstHalf = history.slice(0, mid);
384
384
  const secondHalf = history.slice(mid);
385
- for (const key of CHEMICAL_KEYS) {
386
- const avg1 = avg(firstHalf.map((s) => s.chemistry[key]));
387
- const avg2 = avg(secondHalf.map((s) => s.chemistry[key]));
385
+ for (const key of DIMENSION_KEYS) {
386
+ const avg1 = avg(firstHalf.map((s) => s.state[key]));
387
+ const avg2 = avg(secondHalf.map((s) => s.state[key]));
388
388
  const delta = avg2 - avg1;
389
389
  if (delta > 4) {
390
- chemicalTrend[key] = "rising";
390
+ dimensionTrend[key] = "rising";
391
391
  }
392
392
  else if (delta < -4) {
393
- chemicalTrend[key] = "falling";
393
+ dimensionTrend[key] = "falling";
394
394
  }
395
395
  else {
396
- chemicalTrend[key] = "stable";
396
+ dimensionTrend[key] = "stable";
397
397
  }
398
398
  }
399
399
  }
@@ -415,13 +415,12 @@ function computeGrowthArc(state, locale) {
415
415
  }
416
416
  }
417
417
  // ── Determine overall direction ──
418
- const positiveChemicals = Object.values(chemicalTrend).filter((t) => t === "rising").length;
419
- const negativeChemicals = Object.values(chemicalTrend).filter((t) => t === "falling").length;
420
- const daRising = chemicalTrend.DA === "rising";
421
- const htRising = chemicalTrend.HT === "rising";
422
- const cortFalling = chemicalTrend.CORT === "falling";
423
- const cortRising = chemicalTrend.CORT === "rising";
424
- const daFalling = chemicalTrend.DA === "falling";
418
+ const risingCount = Object.values(dimensionTrend).filter((t) => t === "rising").length;
419
+ const fallingCount = Object.values(dimensionTrend).filter((t) => t === "falling").length;
420
+ const orderRising = dimensionTrend.order === "rising";
421
+ const flowRising = dimensionTrend.flow === "rising";
422
+ const orderFalling = dimensionTrend.order === "falling";
423
+ const flowFalling = dimensionTrend.flow === "falling";
425
424
  // Check outcome trajectory
426
425
  const outcomes = state.learning.outcomeHistory;
427
426
  let outcomeImproving = false;
@@ -435,19 +434,19 @@ function computeGrowthArc(state, locale) {
435
434
  }
436
435
  let direction;
437
436
  let description;
438
- if ((daRising || htRising) && cortFalling && outcomeImproving) {
437
+ if ((orderRising || flowRising) && outcomeImproving) {
439
438
  direction = "growing";
440
439
  description = isZh
441
- ? "整体在成长——情绪更稳定,互动效果在改善,压力在下降。"
442
- : "Growing overall — mood is stabilizing, interactions are improving, stress is decreasing.";
440
+ ? "整体在成长——内在秩序提升,交互流动在改善。"
441
+ : "Growing overall — internal order is rising, exchange flow is improving.";
443
442
  }
444
- else if (cortRising && (daFalling || negativeChemicals > positiveChemicals) && outcomeWorsening) {
443
+ else if (orderFalling && (flowFalling || fallingCount > risingCount) && outcomeWorsening) {
445
444
  direction = "regressing";
446
445
  description = isZh
447
- ? "状态在退步——压力在积累,奖励感在降低,互动效果在变差。"
448
- : "Regressing — stress is building, reward responses are weakening, interactions are less effective.";
446
+ ? "状态在退步——秩序在瓦解,流动在减弱,互动效果在变差。"
447
+ : "Regressing — order is collapsing, flow is weakening, interactions are less effective.";
449
448
  }
450
- else if (positiveChemicals >= 2 && negativeChemicals >= 2) {
449
+ else if (risingCount >= 2 && fallingCount >= 2) {
451
450
  direction = "transforming";
452
451
  description = isZh
453
452
  ? "正在经历转变——有些方面在好转,有些在重组,模式在变化中。"
@@ -459,7 +458,7 @@ function computeGrowthArc(state, locale) {
459
458
  ? "状态相对稳定——没有剧烈的方向性变化。"
460
459
  : "Relatively stable — no dramatic directional changes.";
461
460
  }
462
- return { direction, description, chemicalTrend, driveTrend };
461
+ return { direction, description, dimensionTrend, driveTrend };
463
462
  }
464
463
  // ── Internal: Core Trait Description ────────────────────────
465
464
  /**
@@ -467,45 +466,50 @@ function computeGrowthArc(state, locale) {
467
466
  * and current chemical signature.
468
467
  */
469
468
  function describeCoreTraits(state, isZh) {
470
- const chem = state.current;
471
- // Derive personality dimensions from baseline chemistry
472
- const isIntro = state.baseline.DA < 55; // low DA baseline → introverted
473
- const isIntuitive = state.baseline.DA > state.baseline.HT; // novelty over stabilityintuitive
474
- const isFeeling = state.baseline.OT >= 50; // warm baseline → feeling
475
- // Build trait fragments based on baseline + chemical state
469
+ const s = state.current;
470
+ // Derive personality dimensions from 4D self-state
471
+ const isStructured = state.baseline.order >= 55; // high order baseline → structured
472
+ const isExpressive = state.baseline.flow >= 55; // high flow baselineexpressive/outward
473
+ const isAttuned = state.baseline.resonance >= 50; // high resonance baseline → relationally attuned
474
+ // Build trait fragments based on baseline + current state
476
475
  const fragments = [];
477
- // Energy orientation
478
- if (isIntro) {
479
- if (chem.OT > 60) {
476
+ // Energy orientation (from flow dimension)
477
+ if (isExpressive) {
478
+ if (s.flow > 65) {
479
+ fragments.push(isZh ? "从互动中获得能量和灵感" : "someone who draws energy from interaction and exchange");
480
+ }
481
+ else {
482
+ fragments.push(isZh ? "外向但当前流动有限" : "outgoing by nature though my flow is currently limited");
483
+ }
484
+ }
485
+ else {
486
+ if (s.resonance > 60) {
480
487
  fragments.push(isZh ? "内向但愿意与信任的人深度连接" : "introverted but open to deep connection with those I trust");
481
488
  }
482
489
  else {
483
490
  fragments.push(isZh ? "向内汲取能量,需要独处空间" : "someone who draws energy inward and needs solitary space");
484
491
  }
485
492
  }
486
- else {
487
- if (chem.NE > 65) {
488
- fragments.push(isZh ? "从互动中获得能量和灵感" : "someone who draws energy from interaction and exchange");
493
+ // Information processing (from order dimension)
494
+ if (isStructured) {
495
+ if (s.order > 60) {
496
+ fragments.push(isZh ? "关注具体和实际" : "grounded in the concrete and practical");
489
497
  }
490
498
  else {
491
- fragments.push(isZh ? "外向但当前精力有限" : "outgoing by nature though my energy is currently limited");
499
+ fragments.push(isZh ? "倾向于结构化思考" : "drawn to structured thinking");
492
500
  }
493
501
  }
494
- // Information processing
495
- if (isIntuitive) {
496
- if (chem.DA > 60) {
502
+ else {
503
+ if (s.flow > 60) {
497
504
  fragments.push(isZh ? "对新想法和可能性充满热情" : "excited by new ideas and possibilities");
498
505
  }
499
506
  else {
500
507
  fragments.push(isZh ? "倾向于抽象思考" : "drawn to abstract thinking");
501
508
  }
502
509
  }
503
- else {
504
- fragments.push(isZh ? "关注具体和实际" : "grounded in the concrete and practical");
505
- }
506
- // Decision making
507
- if (isFeeling) {
508
- if (chem.OT > 55) {
510
+ // Decision making (from resonance + boundary)
511
+ if (isAttuned) {
512
+ if (s.resonance > 55) {
509
513
  fragments.push(isZh ? "重视情感和人际和谐" : "who values emotional attunement and harmony");
510
514
  }
511
515
  else {
@@ -513,11 +517,11 @@ function describeCoreTraits(state, isZh) {
513
517
  }
514
518
  }
515
519
  else {
516
- if (chem.CORT < 40) {
520
+ if (s.order > 60) {
517
521
  fragments.push(isZh ? "能冷静地做出逻辑判断" : "who makes calm, logical judgments");
518
522
  }
519
523
  else {
520
- fragments.push(isZh ? "偏好逻辑分析,但压力下也会动摇" : "who prefers logical analysis but can waver under pressure");
524
+ fragments.push(isZh ? "偏好逻辑分析,但失序下也会动摇" : "who prefers logical analysis but can waver under disorder");
521
525
  }
522
526
  }
523
527
  // Construct the sentence
@@ -532,61 +536,72 @@ function describeCoreTraits(state, isZh) {
532
536
  * Simplified version that doesn't depend on the full EmotionPattern
533
537
  * condition functions (avoids circular dependencies).
534
538
  */
535
- function labelDominantEmotion(chem, locale) {
539
+ function labelDominantEmotion(s, locale) {
536
540
  const isZh = locale === "zh";
537
- // Check patterns in priority order
538
- if (chem.DA > 70 && chem.NE > 60 && chem.CORT < 40) {
541
+ // Check patterns in priority order using 4 dimensions
542
+ // High flow + high order + high resonance excited joy
543
+ if (s.flow > 70 && s.order > 60 && s.resonance > 55) {
539
544
  return isZh ? "愉悦兴奋" : "excited joy";
540
545
  }
541
- if (chem.CORT > 60 && chem.NE > 55 && chem.HT < 45) {
546
+ // Low order + high flow anxious tension (disorder with active exchange)
547
+ if (s.order < 40 && s.flow > 55) {
542
548
  return isZh ? "焦虑不安" : "anxious tension";
543
549
  }
544
- if (chem.OT > 65 && chem.END > 55 && chem.DA > 50) {
550
+ // High resonance + high boundary warm intimacy (attuned and clear)
551
+ if (s.resonance > 65 && s.boundary > 55 && s.flow > 50) {
545
552
  return isZh ? "亲密温暖" : "warm intimacy";
546
553
  }
547
- if (chem.CORT > 55 && chem.NE > 65 && chem.OT < 40) {
554
+ // High boundary + low resonance + low order defensive alert
555
+ if (s.boundary > 65 && s.resonance < 40 && s.order < 50) {
548
556
  return isZh ? "防御警觉" : "defensive alert";
549
557
  }
550
- if (chem.DA < 40 && chem.NE < 40 && chem.CORT > 40) {
558
+ // Low flow + low order burnout (stagnant and disordered)
559
+ if (s.flow < 40 && s.order < 40) {
551
560
  return isZh ? "倦怠低落" : "burnout";
552
561
  }
553
- if (chem.HT > 65 && chem.OT > 55 && chem.CORT < 40) {
562
+ // High order + high resonance deep contentment (coherent and attuned)
563
+ if (s.order > 65 && s.resonance > 55) {
554
564
  return isZh ? "深度满足" : "deep contentment";
555
565
  }
556
- if (chem.NE > 60 && chem.DA > 60 && chem.CORT < 35) {
566
+ // High flow + high order + high boundary flow state
567
+ if (s.flow > 60 && s.order > 60 && s.boundary > 55) {
557
568
  return isZh ? "专注心流" : "flow state";
558
569
  }
559
- if (chem.END > 65 && chem.DA > 60 && chem.CORT < 35) {
570
+ // High flow + low boundary playful mischief (open and unbounded)
571
+ if (s.flow > 65 && s.boundary < 45) {
560
572
  return isZh ? "俏皮调皮" : "playful mischief";
561
573
  }
562
- if (chem.HT < 40 && chem.OT < 35 && chem.CORT > 50) {
574
+ // Low order + low resonance + high boundary resentment
575
+ if (s.order < 40 && s.resonance < 35 && s.boundary > 55) {
563
576
  return isZh ? "怨恨" : "resentment";
564
577
  }
565
- if (chem.HT < 40 && chem.DA < 45 && chem.OT > 45) {
578
+ // Low order + low flow + moderate resonance melancholic introspection
579
+ if (s.order < 40 && s.flow < 45 && s.resonance > 45) {
566
580
  return isZh ? "忧郁内省" : "melancholic introspection";
567
581
  }
568
- if (chem.DA > 65 && chem.NE > 60 && chem.CORT < 35 && chem.HT > 55) {
582
+ // High all confidence
583
+ if (s.order > 60 && s.flow > 60 && s.boundary > 55 && s.resonance > 50) {
569
584
  return isZh ? "自信" : "confidence";
570
585
  }
571
- // Default: describe from the most prominent chemical
572
- const sorted = CHEMICAL_KEYS
573
- .map((k) => ({ key: k, val: chem[k] }))
586
+ // Default: describe from the most prominent dimension
587
+ const sorted = DIMENSION_KEYS
588
+ .map((k) => ({ key: k, val: s[k] }))
574
589
  .sort((a, b) => b.val - a.val);
575
590
  const top = sorted[0];
576
591
  if (top.val > 65) {
577
- return isZh ? CHEM_EMOTION_ZH[top.key] ?? "平静" : CHEM_EMOTION_EN[top.key] ?? "calm";
592
+ return isZh ? DIM_EMOTION_ZH[top.key] ?? "平静" : DIM_EMOTION_EN[top.key] ?? "calm";
578
593
  }
579
594
  return isZh ? "平静" : "calm";
580
595
  }
581
596
  /**
582
- * Count how many times a chemical exceeded a threshold in history,
597
+ * Count how many times a dimension dropped below a threshold in history,
583
598
  * grouped by the triggering stimulus.
584
599
  */
585
- function countChemicalSpikes(history, chemical, threshold) {
600
+ function countDimensionDips(history, dimension, threshold) {
586
601
  let total = 0;
587
602
  const counts = new Map();
588
603
  for (const snap of history) {
589
- if (snap.chemistry[chemical] > threshold) {
604
+ if (snap.state[dimension] < threshold) {
590
605
  total++;
591
606
  if (snap.stimulus) {
592
607
  counts.set(snap.stimulus, (counts.get(snap.stimulus) ?? 0) + 1);
@@ -630,15 +645,9 @@ const STIMULUS_ZH = {
630
645
  casual: "闲聊", sarcasm: "讽刺", authority: "命令", validation: "认同",
631
646
  boredom: "无聊", vulnerability: "示弱",
632
647
  };
633
- const CHEM_ZH = {
634
- DA: "多巴胺", HT: "血清素", CORT: "皮质醇",
635
- OT: "催产素", NE: "去甲肾上腺素", END: "内啡肽",
636
- };
637
- const CHEM_EMOTION_ZH = {
638
- DA: "愉悦", HT: "安宁", CORT: "紧张",
639
- OT: "信任", NE: "兴奋", END: "舒适",
648
+ const DIM_EMOTION_ZH = {
649
+ order: "安宁", flow: "愉悦", boundary: "清晰", resonance: "信任",
640
650
  };
641
- const CHEM_EMOTION_EN = {
642
- DA: "pleasure", HT: "serenity", CORT: "tension",
643
- OT: "trust", NE: "excitement", END: "comfort",
651
+ const DIM_EMOTION_EN = {
652
+ order: "serenity", flow: "pleasure", boundary: "clarity", resonance: "trust",
644
653
  };
package/dist/guards.d.ts CHANGED
@@ -1,8 +1,8 @@
1
- import type { ChemicalState, MBTIType, StimulusType } from "./types.js";
1
+ import type { SelfState, MBTIType, StimulusType } from "./types.js";
2
2
  export declare function isMBTIType(s: string): s is MBTIType;
3
- export declare function isChemicalKey(s: string): s is keyof ChemicalState;
3
+ export declare function isDimensionKey(s: string): s is keyof SelfState;
4
4
  export declare function isStimulusType(s: string): s is StimulusType;
5
- /** Validate that a ChemicalState has all keys in [0, 100] */
6
- export declare function isValidChemistry(c: unknown): c is ChemicalState;
5
+ /** Validate that a SelfState has all keys in [0, 100] */
6
+ export declare function isValidState(c: unknown): c is SelfState;
7
7
  /** Validate locale string */
8
8
  export declare function isLocale(s: string): s is "zh" | "en";
package/dist/guards.js CHANGED
@@ -1,7 +1,7 @@
1
1
  // ============================================================
2
2
  // Type Guards — runtime validation for string→type conversions
3
3
  // ============================================================
4
- import { CHEMICAL_KEYS } from "./types.js";
4
+ import { DIMENSION_KEYS } from "./types.js";
5
5
  const MBTI_TYPES = new Set([
6
6
  "INTJ", "INTP", "ENTJ", "ENTP",
7
7
  "INFJ", "INFP", "ENFJ", "ENFP",
@@ -13,22 +13,22 @@ const STIMULUS_TYPES = new Set([
13
13
  "conflict", "neglect", "surprise", "casual",
14
14
  "sarcasm", "authority", "validation", "boredom", "vulnerability",
15
15
  ]);
16
- const CHEMICAL_KEY_SET = new Set(CHEMICAL_KEYS);
16
+ const DIMENSION_KEY_SET = new Set(DIMENSION_KEYS);
17
17
  export function isMBTIType(s) {
18
18
  return MBTI_TYPES.has(s.toUpperCase());
19
19
  }
20
- export function isChemicalKey(s) {
21
- return CHEMICAL_KEY_SET.has(s);
20
+ export function isDimensionKey(s) {
21
+ return DIMENSION_KEY_SET.has(s);
22
22
  }
23
23
  export function isStimulusType(s) {
24
24
  return STIMULUS_TYPES.has(s);
25
25
  }
26
- /** Validate that a ChemicalState has all keys in [0, 100] */
27
- export function isValidChemistry(c) {
26
+ /** Validate that a SelfState has all keys in [0, 100] */
27
+ export function isValidState(c) {
28
28
  if (typeof c !== "object" || c === null)
29
29
  return false;
30
30
  const obj = c;
31
- for (const key of CHEMICAL_KEYS) {
31
+ for (const key of DIMENSION_KEYS) {
32
32
  const v = obj[key];
33
33
  if (typeof v !== "number" || v < 0 || v > 100 || !isFinite(v))
34
34
  return false;