@aleph-ai/tinyaleph 1.3.0 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/core/logger.js ADDED
@@ -0,0 +1,350 @@
1
+ /**
2
+ * Structured Logger for TinyAleph
3
+ *
4
+ * Provides structured logging with:
5
+ * - Multiple log levels (TRACE through FATAL)
6
+ * - JSON and text output formats
7
+ * - Child logger namespaces
8
+ * - Log history for analysis
9
+ * - Event emission for log aggregation
10
+ *
11
+ * Browser-compatible: Uses console API instead of Node.js streams.
12
+ * Extracted from apps/sentient/lib/error-handler.js for library reuse.
13
+ */
14
+
15
+ const { LogLevel, LogLevelNames, SimpleEventEmitter } = require('./errors');
16
+
17
+ // ============================================================================
18
+ // LOGGER
19
+ // ============================================================================
20
+
21
+ /**
22
+ * Structured Logger
23
+ */
24
+ class Logger extends SimpleEventEmitter {
25
+ constructor(options = {}) {
26
+ super();
27
+
28
+ this.name = options.name || 'aleph';
29
+ this.level = options.level ?? LogLevel.INFO;
30
+ this.format = options.format || 'text'; // text, json
31
+ this.colorize = options.colorize ?? true;
32
+ this.includeTimestamp = options.includeTimestamp ?? true;
33
+ this.includeLevel = options.includeLevel ?? true;
34
+
35
+ // Custom output functions (defaults to console)
36
+ this.output = options.output || {
37
+ log: (...args) => console.log(...args),
38
+ error: (...args) => console.error(...args),
39
+ warn: (...args) => console.warn(...args),
40
+ info: (...args) => console.info(...args),
41
+ debug: (...args) => console.debug(...args)
42
+ };
43
+
44
+ // Log history for error aggregation
45
+ this.history = [];
46
+ this.maxHistory = options.maxHistory || 1000;
47
+
48
+ // Child loggers
49
+ this.children = new Map();
50
+
51
+ // Colors (browser console supports CSS, Node uses ANSI)
52
+ this.isBrowser = typeof window !== 'undefined';
53
+ this.ansiColors = {
54
+ trace: '\x1b[90m',
55
+ debug: '\x1b[36m',
56
+ info: '\x1b[32m',
57
+ warn: '\x1b[33m',
58
+ error: '\x1b[31m',
59
+ fatal: '\x1b[35m',
60
+ reset: '\x1b[0m'
61
+ };
62
+ this.cssColors = {
63
+ trace: 'color: #888',
64
+ debug: 'color: #0aa',
65
+ info: 'color: #0a0',
66
+ warn: 'color: #aa0',
67
+ error: 'color: #a00',
68
+ fatal: 'color: #a0a'
69
+ };
70
+ }
71
+
72
+ /**
73
+ * Create a child logger with a specific namespace
74
+ * @param {string} namespace - Child namespace
75
+ * @returns {Logger}
76
+ */
77
+ child(namespace) {
78
+ if (this.children.has(namespace)) {
79
+ return this.children.get(namespace);
80
+ }
81
+
82
+ const child = new Logger({
83
+ name: `${this.name}:${namespace}`,
84
+ level: this.level,
85
+ format: this.format,
86
+ colorize: this.colorize,
87
+ output: this.output
88
+ });
89
+
90
+ // Forward events to parent
91
+ child.on('log', (entry) => {
92
+ this.history.push(entry);
93
+ if (this.history.length > this.maxHistory) {
94
+ this.history.shift();
95
+ }
96
+ this.emit('log', entry);
97
+ });
98
+
99
+ this.children.set(namespace, child);
100
+ return child;
101
+ }
102
+
103
+ /**
104
+ * Log at a specific level
105
+ * @param {number} level - Log level
106
+ * @param {string} message - Log message
107
+ * @param {Object} data - Additional data
108
+ */
109
+ log(level, message, data = {}) {
110
+ if (level < this.level) return;
111
+
112
+ const entry = {
113
+ timestamp: new Date().toISOString(),
114
+ level: LogLevelNames[level].toLowerCase(),
115
+ name: this.name,
116
+ message,
117
+ data: Object.keys(data).length > 0 ? data : undefined
118
+ };
119
+
120
+ // Add to history
121
+ this.history.push(entry);
122
+ if (this.history.length > this.maxHistory) {
123
+ this.history.shift();
124
+ }
125
+
126
+ // Format and output
127
+ this.writeOutput(entry, level);
128
+
129
+ // Emit event
130
+ this.emit('log', entry);
131
+
132
+ return entry;
133
+ }
134
+
135
+ /**
136
+ * Write log entry to output
137
+ * @param {Object} entry - Log entry
138
+ * @param {number} level - Log level number
139
+ */
140
+ writeOutput(entry, level) {
141
+ if (this.format === 'json') {
142
+ const output = JSON.stringify(entry);
143
+ if (level >= LogLevel.ERROR) {
144
+ this.output.error(output);
145
+ } else {
146
+ this.output.log(output);
147
+ }
148
+ return;
149
+ }
150
+
151
+ // Text format
152
+ if (this.isBrowser && this.colorize) {
153
+ this.writeBrowserColorized(entry, level);
154
+ } else if (this.colorize) {
155
+ this.writeAnsiColorized(entry, level);
156
+ } else {
157
+ this.writePlain(entry, level);
158
+ }
159
+ }
160
+
161
+ /**
162
+ * Write colorized output for browser console
163
+ */
164
+ writeBrowserColorized(entry, level) {
165
+ const parts = [];
166
+ const styles = [];
167
+
168
+ if (this.includeTimestamp) {
169
+ parts.push(`%c[${entry.timestamp}]`);
170
+ styles.push('color: #666');
171
+ }
172
+
173
+ if (this.includeLevel) {
174
+ const levelStr = entry.level.toUpperCase().padEnd(5);
175
+ parts.push(`%c${levelStr}`);
176
+ styles.push(this.cssColors[entry.level] || '');
177
+ }
178
+
179
+ parts.push(`%c[${entry.name}]`);
180
+ styles.push('color: #888');
181
+
182
+ parts.push(`%c${entry.message}`);
183
+ styles.push('color: inherit');
184
+
185
+ const formatStr = parts.join(' ');
186
+ const args = [formatStr, ...styles];
187
+
188
+ if (entry.data) {
189
+ args.push(entry.data);
190
+ }
191
+
192
+ if (level >= LogLevel.ERROR) {
193
+ this.output.error(...args);
194
+ } else if (level >= LogLevel.WARN) {
195
+ this.output.warn(...args);
196
+ } else if (level >= LogLevel.INFO) {
197
+ this.output.info(...args);
198
+ } else {
199
+ this.output.debug(...args);
200
+ }
201
+ }
202
+
203
+ /**
204
+ * Write ANSI colorized output for Node.js terminal
205
+ */
206
+ writeAnsiColorized(entry, level) {
207
+ const parts = [];
208
+
209
+ if (this.includeTimestamp) {
210
+ parts.push(`[${entry.timestamp}]`);
211
+ }
212
+
213
+ if (this.includeLevel) {
214
+ const levelStr = entry.level.toUpperCase().padEnd(5);
215
+ const color = this.ansiColors[entry.level] || '';
216
+ parts.push(`${color}${levelStr}${this.ansiColors.reset}`);
217
+ }
218
+
219
+ parts.push(`[${entry.name}]`);
220
+ parts.push(entry.message);
221
+
222
+ if (entry.data) {
223
+ parts.push(JSON.stringify(entry.data));
224
+ }
225
+
226
+ const output = parts.join(' ');
227
+
228
+ if (level >= LogLevel.ERROR) {
229
+ this.output.error(output);
230
+ } else {
231
+ this.output.log(output);
232
+ }
233
+ }
234
+
235
+ /**
236
+ * Write plain text output
237
+ */
238
+ writePlain(entry, level) {
239
+ const parts = [];
240
+
241
+ if (this.includeTimestamp) {
242
+ parts.push(`[${entry.timestamp}]`);
243
+ }
244
+
245
+ if (this.includeLevel) {
246
+ parts.push(entry.level.toUpperCase().padEnd(5));
247
+ }
248
+
249
+ parts.push(`[${entry.name}]`);
250
+ parts.push(entry.message);
251
+
252
+ if (entry.data) {
253
+ parts.push(JSON.stringify(entry.data));
254
+ }
255
+
256
+ const output = parts.join(' ');
257
+
258
+ if (level >= LogLevel.ERROR) {
259
+ this.output.error(output);
260
+ } else {
261
+ this.output.log(output);
262
+ }
263
+ }
264
+
265
+ // Convenience methods
266
+ trace(message, data) { return this.log(LogLevel.TRACE, message, data); }
267
+ debug(message, data) { return this.log(LogLevel.DEBUG, message, data); }
268
+ info(message, data) { return this.log(LogLevel.INFO, message, data); }
269
+ warn(message, data) { return this.log(LogLevel.WARN, message, data); }
270
+ error(message, data) { return this.log(LogLevel.ERROR, message, data); }
271
+ fatal(message, data) { return this.log(LogLevel.FATAL, message, data); }
272
+
273
+ /**
274
+ * Set log level
275
+ * @param {number|string} level - New level
276
+ */
277
+ setLevel(level) {
278
+ if (typeof level === 'string') {
279
+ this.level = LogLevel[level.toUpperCase()] ?? LogLevel.INFO;
280
+ } else {
281
+ this.level = level;
282
+ }
283
+ }
284
+
285
+ /**
286
+ * Get recent log entries
287
+ * @param {number} count - Number of entries
288
+ * @param {string} level - Optional level filter
289
+ * @returns {Array}
290
+ */
291
+ getRecent(count = 100, level = null) {
292
+ let entries = this.history.slice(-count);
293
+ if (level) {
294
+ entries = entries.filter(e => e.level === level);
295
+ }
296
+ return entries;
297
+ }
298
+
299
+ /**
300
+ * Get error summary
301
+ * @returns {Object}
302
+ */
303
+ getErrorSummary() {
304
+ const errors = this.history.filter(e => e.level === 'error' || e.level === 'fatal');
305
+ const categories = {};
306
+
307
+ for (const error of errors) {
308
+ const cat = error.data?.category || 'unknown';
309
+ categories[cat] = (categories[cat] || 0) + 1;
310
+ }
311
+
312
+ return {
313
+ totalErrors: errors.length,
314
+ byCategory: categories,
315
+ recentErrors: errors.slice(-10)
316
+ };
317
+ }
318
+
319
+ /**
320
+ * Clear log history
321
+ */
322
+ clearHistory() {
323
+ this.history = [];
324
+ }
325
+ }
326
+
327
+ /**
328
+ * Create a namespaced logger
329
+ * @param {string} namespace - Logger namespace
330
+ * @param {Object} options - Logger options
331
+ * @returns {Logger}
332
+ */
333
+ function createLogger(namespace, options = {}) {
334
+ return new Logger({
335
+ name: namespace,
336
+ ...options
337
+ });
338
+ }
339
+
340
+ // ============================================================================
341
+ // EXPORTS
342
+ // ============================================================================
343
+
344
+ module.exports = {
345
+ Logger,
346
+ createLogger,
347
+ // Re-export LogLevel for convenience
348
+ LogLevel,
349
+ LogLevelNames
350
+ };
package/core/prime.js CHANGED
@@ -175,10 +175,145 @@ function firstNPrimes(n) {
175
175
  // Default prime list (first 100 primes)
176
176
  const DEFAULT_PRIMES = firstNPrimes(100);
177
177
 
178
+ // ============================================================================
179
+ // 108 INVARIANT (from 108bio.pdf - Twist Eigenstates and Topological Morphogenesis)
180
+ // ============================================================================
181
+
182
+ /**
183
+ * The 108 Invariant - The minimal self-referential twist cavity
184
+ *
185
+ * 108 = 2² × 3³ is identified as the fundamental invariant for:
186
+ * - Standard Model gauge groups (SU(3) × SU(2) × U(1))
187
+ * - Biological self-organization (pentagon angle 108°)
188
+ * - Consciousness as free energy minimization
189
+ *
190
+ * Key relationships:
191
+ * - Trefoil complexity (17) × 108 = 1836 (proton/electron mass ratio)
192
+ * - 108 + 29 (mod-30 prime sieve boundary) = 137 (fine structure constant inverse)
193
+ * - 5³ = 125 GeV (Higgs mass prediction)
194
+ */
195
+ const TWIST_108 = {
196
+ // Fundamental value
197
+ value: 108,
198
+
199
+ // Prime factorization: 2² × 3³
200
+ binary: 4, // 2²
201
+ ternary: 27, // 3³
202
+
203
+ // Gauge symmetry angles
204
+ su3Angle: 120, // SU(3) color symmetry: 360°/3 = 120° (ternary)
205
+ su2Angle: 180, // SU(2) weak symmetry: 360°/2 = 180° (binary)
206
+ u1Angle: 360, // U(1) electromagnetic: full rotation
207
+
208
+ // Biological resonance
209
+ pentagonAngle: 108, // Internal angle of regular pentagon
210
+ phyllotaxisComplement: 137.5, // Golden angle in phyllotaxis
211
+
212
+ // Physical constants derived
213
+ trefoilComplexity: 17, // Trefoil knot complexity number
214
+ protonElectronRatio: 1836, // 17 × 108 = proton/electron mass ratio
215
+ fineStructureInverse: 137, // 108 + 29 = α⁻¹
216
+ higgsMass: 125, // 5³ GeV (first prime outside minimal twist set)
217
+ mod30Boundary: 29, // Prime sieve boundary
218
+
219
+ // Twist eigenstate formula: |n⟩τ = e^(i·2π/n)
220
+ twistEigenstate(n) {
221
+ const angle = (2 * Math.PI) / n;
222
+ return { re: Math.cos(angle), im: Math.sin(angle) };
223
+ },
224
+
225
+ // Check if n exhibits 108-resonance (divides cleanly with 108)
226
+ resonates(n) {
227
+ if (n === 0) return false;
228
+ const ratio = 108 / n;
229
+ return Math.abs(ratio - Math.round(ratio)) < 0.001 ||
230
+ Math.abs(n / 108 - Math.round(n / 108)) < 0.001;
231
+ },
232
+
233
+ // Get gauge group contribution from factorization
234
+ gaugeDecomposition(n) {
235
+ const factors = factorize(n);
236
+ return {
237
+ su3Contribution: factors[3] || 0, // Powers of 3
238
+ su2Contribution: factors[2] || 0, // Powers of 2
239
+ u1Contribution: Object.keys(factors)
240
+ .filter(p => p !== '2' && p !== '3')
241
+ .reduce((sum, p) => sum + factors[p], 0)
242
+ };
243
+ },
244
+
245
+ // Derive mass ratio from topological integers
246
+ deriveMassRatio(crossings, sticks, bridge, unknotting) {
247
+ const trefoilComplexity = sticks * crossings - bridge + unknotting;
248
+ return trefoilComplexity * 108;
249
+ }
250
+ };
251
+
252
+ /**
253
+ * Twist angle for a prime (from Enochian layer and 108bio.pdf)
254
+ * κ(p) = 360°/p
255
+ * @param {number} p - Prime number
256
+ * @returns {number} Twist angle in degrees
257
+ */
258
+ function twistAngle(p) {
259
+ return 360 / p;
260
+ }
261
+
262
+ /**
263
+ * Total twist for a sequence of primes
264
+ * T(P) = Σᵢ κ(pᵢ)
265
+ * @param {Array<number>} primes - Sequence of primes
266
+ * @returns {number} Total twist in degrees
267
+ */
268
+ function totalTwist(primes) {
269
+ return primes.reduce((sum, p) => sum + twistAngle(p), 0);
270
+ }
271
+
272
+ /**
273
+ * Check twist closure (from discrete.pdf equation 18)
274
+ * A sequence is twist-closed when T(P) mod 360 ∈ [0,ε) ∪ (360-ε, 360]
275
+ * @param {Array<number>} primes - Sequence of primes
276
+ * @param {number} epsilon - Tolerance in degrees (default 1.0)
277
+ * @returns {boolean} True if twist-closed
278
+ */
279
+ function isTwistClosed(primes, epsilon = 1.0) {
280
+ const twist = totalTwist(primes);
281
+ const mod = ((twist % 360) + 360) % 360;
282
+ return mod < epsilon || mod > (360 - epsilon);
283
+ }
284
+
285
+ /**
286
+ * Find primes that would close a twist sequence
287
+ * @param {Array<number>} currentPrimes - Current prime sequence
288
+ * @param {number} epsilon - Closure tolerance
289
+ * @returns {Array<Object>} Candidate primes with closure errors
290
+ */
291
+ function findClosingPrimes(currentPrimes, epsilon = 1.0) {
292
+ const currentTwist = totalTwist(currentPrimes);
293
+ const mod = ((currentTwist % 360) + 360) % 360;
294
+
295
+ const candidates = [];
296
+ const testPrimes = primesUpTo(100);
297
+
298
+ for (const p of testPrimes) {
299
+ const newMod = ((mod + twistAngle(p)) % 360);
300
+ const error = Math.min(newMod, 360 - newMod);
301
+ candidates.push({ prime: p, error, closesAt: error < epsilon });
302
+ }
303
+
304
+ return candidates.sort((a, b) => a.error - b.error);
305
+ }
306
+
178
307
  module.exports = {
179
308
  primeGenerator, nthPrime, primesUpTo, isPrime,
180
309
  factorize, primeSignature, firstNPrimes,
181
310
  GaussianInteger, EisensteinInteger,
182
311
  primeToFrequency, primeToAngle, sumOfTwoSquares,
183
- DEFAULT_PRIMES
312
+ DEFAULT_PRIMES,
313
+ // 108 Invariant exports
314
+ TWIST_108,
315
+ twistAngle,
316
+ totalTwist,
317
+ isTwistClosed,
318
+ findClosingPrimes
184
319
  };