File size: 4,499 Bytes
e2ce418
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
import React, { useState, useEffect } from 'react';
import { motion } from 'framer-motion';

// πŸ’¬ Perspective Trail Display
export function PerspectiveTrail({ perspectives }: { perspectives: string[] }) {
  return (
    <div className="mt-4 text-sm text-purple-700">
      <p className="font-semibold">Activated Perspectives:</p>
      <motion.ul 
        className="list-disc ml-5"
        initial={{ opacity: 0 }}
        animate={{ opacity: 1 }}
        transition={{ duration: 0.5 }}
      >
        {perspectives.map((perspective, index) => (
          <motion.li 
            key={index}
            initial={{ x: -20, opacity: 0 }}
            animate={{ x: 0, opacity: 1 }}
            transition={{ delay: index * 0.1 }}
          >
            {perspective}
          </motion.li>
        ))}
      </motion.ul>
    </div>
  );
}

// πŸ”„ Cocoon Replay Viewer
export function CocoonReplay({ cocoons }: { cocoons: string[] }) {
  const [activeIndex, setActiveIndex] = useState(0);

  useEffect(() => {
    const timer = setInterval(() => {
      setActiveIndex(prev => (prev + 1) % cocoons.length);
    }, 3000);
    return () => clearInterval(timer);
  }, [cocoons.length]);

  return (
    <div className="mt-4 text-sm text-green-700">
      <p className="font-semibold">Cocoon Memory:</p>
      <motion.div 
        className="bg-green-100 p-2 rounded-md max-h-40 overflow-y-scroll"
        initial={{ opacity: 0, y: 20 }}
        animate={{ opacity: 1, y: 0 }}
        transition={{ duration: 0.5 }}
      >
        {cocoons.map((cocoon, idx) => (
          <motion.pre 
            key={idx} 
            className={`whitespace-pre-wrap text-xs mb-2 transition-colors duration-300 ${
              idx === activeIndex ? 'bg-green-200 rounded p-1' : ''
            }`}
            initial={{ opacity: 0 }}
            animate={{ opacity: 1 }}
            transition={{ delay: idx * 0.1 }}
          >
            {cocoon}
          </motion.pre>
        ))}
      </motion.div>
    </div>
  );
}

// πŸŒ— Quantum Collapse Detector
export function CollapseDetector({ isUnstable }: { isUnstable: boolean }) {
  return (
    <motion.div
      animate={{
        scale: isUnstable ? [1, 1.3, 1] : 1,
        opacity: isUnstable ? [0.6, 1, 0.6] : 1,
      }}
      transition={{ duration: 1.5, repeat: Infinity }}
      className={`w-4 h-4 rounded-full mt-2 ml-2 ${
        isUnstable ? "bg-red-500" : "bg-blue-300"
      }`}
      title={isUnstable ? "Quantum Instability Detected" : "Stable"}
    />
  );
}

// 🧠 CodetteResponse Interface
export interface CodetteResponse {
  text: string;
  instabilityFlag: boolean;
  perspectivesUsed: string[];
  cocoonLog: string[];
  forceRefresh: () => void;
}

// 🧠 CodetteResponseCard Component
export function CodetteResponseCard({ response }: { response: CodetteResponse }) {
  const [loopCount, setLoopCount] = useState(0);
  const [introspectiveMessage, setIntrospectiveMessage] = useState<string | null>(null);

  useEffect(() => {
    const last = sessionStorage.getItem("lastCodetteResponse");
    if (last === response.text) {
      console.warn("Codette is repeating herself. Triggering fallback logic.");
      setLoopCount(prev => prev + 1);

      if (response.forceRefresh) {
        response.forceRefresh();
      }

      setIntrospectiveMessage("I feel like I've said this before... Let me think differently.");
    } else {
      setLoopCount(0);
      setIntrospectiveMessage(null);
    }
    sessionStorage.setItem("lastCodetteResponse", response.text);
  }, [response.text]);

  return (
    <motion.div 
      className="border border-gray-200 p-4 rounded-xl shadow-sm bg-white max-w-[80%]"
      initial={{ opacity: 0, y: 20 }}
      animate={{ opacity: 1, y: 0 }}
      transition={{ duration: 0.5 }}
    >
      <p className="whitespace-pre-wrap">{response.text}</p>
      {introspectiveMessage && (
        <motion.p 
          className="text-xs text-rose-600 italic mt-2"
          initial={{ opacity: 0 }}
          animate={{ opacity: 1 }}
          transition={{ delay: 0.3 }}
        >
          {introspectiveMessage}
        </motion.p>
      )}
      <div className="flex items-center mt-2">
        <span className="text-xs text-gray-500">System Readout:</span>
        <CollapseDetector isUnstable={response.instabilityFlag || loopCount > 2} />
      </div>
      <PerspectiveTrail perspectives={response.perspectivesUsed} />
      <CocoonReplay cocoons={response.cocoonLog} />
    </motion.div>
  );
}