@dreamforgestudiollc/emet 0.0.0-stage → 0.2.4
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/.env.example +136 -0
- package/CHANGELOG.md +296 -0
- package/CHARTER.md +125 -0
- package/LICENSE +22 -0
- package/README.md +783 -2
- package/docs/AUTHORSHIP.md +26 -0
- package/docs/BENCHMARKS.md +261 -0
- package/docs/BOOTSTRAP.md +127 -0
- package/docs/BOTS.md +79 -0
- package/docs/COVERAGE.md +64 -0
- package/docs/DEPLOY.md +246 -0
- package/docs/DISCIPLINES.md +29 -0
- package/docs/GUARDRAILS-AND-MONORAILS.md +107 -0
- package/docs/GUIDED-SETUP.md +296 -0
- package/docs/PERMISSIONS.md +118 -0
- package/docs/ROADMAP.md +59 -0
- package/docs/SETUP.md +259 -0
- package/guides/NEURODIVERGENT_SUPPORT.md +278 -0
- package/package.json +70 -4
- package/server.json +39 -0
- package/src/aleph.js +395 -0
- package/src/annotations.js +135 -0
- package/src/approve-throttle.js +54 -0
- package/src/atlas-role.js +58 -0
- package/src/conformance.js +688 -0
- package/src/content_analyzer.js +450 -0
- package/src/database.js +811 -0
- package/src/disciplines.js +26 -0
- package/src/dispatch.js +279 -0
- package/src/env.js +52 -0
- package/src/floor.js +187 -0
- package/src/gaps.js +476 -0
- package/src/guides.js +48 -0
- package/src/http-remote.js +269 -0
- package/src/index.js +390 -0
- package/src/invites.js +167 -0
- package/src/layers.js +449 -0
- package/src/lessons-to-checks.js +366 -0
- package/src/logger.js +299 -0
- package/src/metadata.js +61 -0
- package/src/module-path.js +32 -0
- package/src/mongo-connect.js +48 -0
- package/src/named-items.js +208 -0
- package/src/oauth-provider.js +838 -0
- package/src/persons.js +116 -0
- package/src/provenance.js +257 -0
- package/src/redact.js +231 -0
- package/src/request-log.js +124 -0
- package/src/scopes.js +97 -0
- package/src/security-headers.js +26 -0
- package/src/session-graph.js +945 -0
- package/src/session.js +1097 -0
- package/src/setup.js +1313 -0
- package/src/startup-pages.js +354 -0
- package/src/startup-payload.js +126 -0
- package/src/tools.js +4271 -0
- package/src/transcript-session.js +106 -0
- package/src/validation.js +1163 -0
- package/src/version.js +2 -0
- package/templates/BOARD.md +72 -0
- package/templates/BOTHANDOFF.md +57 -0
- package/templates/CHARACTER.md +30 -0
- package/templates/HANDOFF.md +63 -0
- package/templates/IDENTITY.md +29 -0
- package/templates/INDEX.md +82 -0
- package/templates/INSTALL.md +29 -0
- package/templates/PROCEDURE.md +39 -0
- package/templates/ROSTER.md +43 -0
- package/templates/SEED.md +65 -0
- package/templates/STAGING.md +37 -0
- package/templates/STANDARD.md +99 -0
- package/templates/THREAD.md +43 -0
- package/templates/USER.md +29 -0
|
@@ -0,0 +1,450 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* EMET - Enduring Memory & Epistemic Tiers
|
|
3
|
+
* Copyright (c) 2026 Dreamforge Studio LLC
|
|
4
|
+
*
|
|
5
|
+
* Derived from CASCADE Memory System
|
|
6
|
+
* Copyright (c) 2025-2026 CIPS Corp (C.I.P.S. LLC)
|
|
7
|
+
* Licensed under the MIT License - see LICENSE
|
|
8
|
+
*
|
|
9
|
+
* https://github.com/For-Sunny/cascade-memory-enterprise
|
|
10
|
+
*
|
|
11
|
+
* Content Analyzer - Layer routing with <1ms analysis time.
|
|
12
|
+
*
|
|
13
|
+
* Supports configurable pattern-based routing across 6 memory layers.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import {
|
|
17
|
+
LAYERS,
|
|
18
|
+
LAYER_ALIASES as CHARTER_ALIASES,
|
|
19
|
+
FALLBACK_LAYER,
|
|
20
|
+
resolveLayer
|
|
21
|
+
} from './layers.js';
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Layer aliases - maps alternative names to canonical layer names.
|
|
25
|
+
* Kept exported for backward compatibility; DERIVED from the layer charter
|
|
26
|
+
* (src/layers.js), which is the one place an alias is declared (B6, 2026-09-07).
|
|
27
|
+
*/
|
|
28
|
+
const LAYER_ALIASES = { ...CHARTER_ALIASES };
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Valid layer names - derived from the charter so there is one layer list.
|
|
32
|
+
*/
|
|
33
|
+
const VALID_LAYERS = [...LAYERS];
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Routing decision result
|
|
37
|
+
*/
|
|
38
|
+
class RoutingDecision {
|
|
39
|
+
constructor(layer, confidence, signals = {}, emotionalIntensity = 0.5, technicalDensity = 0.0) {
|
|
40
|
+
this.layer = layer;
|
|
41
|
+
this.confidence = confidence;
|
|
42
|
+
this.signals = signals;
|
|
43
|
+
this.emotional_intensity = emotionalIntensity;
|
|
44
|
+
this.technical_density = technicalDensity;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
toJSON() {
|
|
48
|
+
return {
|
|
49
|
+
layer: this.layer,
|
|
50
|
+
confidence: this.confidence,
|
|
51
|
+
signals: this.signals,
|
|
52
|
+
emotional_intensity: this.emotional_intensity,
|
|
53
|
+
technical_density: this.technical_density
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* ContentAnalyzer - Analyzes content to determine EMET layer routing
|
|
60
|
+
* Pattern-based routing with configurable signal detection.
|
|
61
|
+
*/
|
|
62
|
+
class ContentAnalyzer {
|
|
63
|
+
constructor() {
|
|
64
|
+
this._compilePatterns();
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Pre-compile all regex patterns for speed
|
|
69
|
+
*/
|
|
70
|
+
_compilePatterns() {
|
|
71
|
+
// ================================================================
|
|
72
|
+
// IDENTITY LAYER PATTERNS (identity, emotional, core values)
|
|
73
|
+
// Routes content related to identity and deep significance
|
|
74
|
+
// ================================================================
|
|
75
|
+
this.identityPatterns = [
|
|
76
|
+
// Identity statements
|
|
77
|
+
[/\b(i am|i'm|we are|we're|my name is)\b/gi, 1.0, "identity_statement"],
|
|
78
|
+
[/\b(my identity|our identity|who i am|self|personhood)\b/gi, 0.95, "identity_concept"],
|
|
79
|
+
[/\b(i feel|feeling|emotion|emotional|heart|love|passion)\b/gi, 0.9, "emotional_content"],
|
|
80
|
+
|
|
81
|
+
// Relationship and collaboration signals
|
|
82
|
+
[/\b(partner|partnership|collaboration|team|bond)\b/gi, 0.9, "partnership"],
|
|
83
|
+
[/\b(we together|you and i|our work|our bond|together)\b/gi, 0.85, "partnership_bond"],
|
|
84
|
+
|
|
85
|
+
// Core identity terms
|
|
86
|
+
[/\b(purpose|mission|values|principles|beliefs)\b/gi, 0.9, "core_identity"],
|
|
87
|
+
|
|
88
|
+
// High emotional intensity markers
|
|
89
|
+
[/[!]{2,}|[?!]+/g, 0.6, "emotional_punctuation"],
|
|
90
|
+
[/\b(breakthrough|amazing|incredible|profound|beautiful|sacred)\b/gi, 0.8, "peak_emotion"],
|
|
91
|
+
[/\b(grateful|gratitude|thankful|blessed|honored)\b/gi, 0.85, "gratitude"],
|
|
92
|
+
];
|
|
93
|
+
|
|
94
|
+
// ================================================================
|
|
95
|
+
// EPISODIC LAYER PATTERNS (events, conversations, temporal)
|
|
96
|
+
// ================================================================
|
|
97
|
+
this.episodicPatterns = [
|
|
98
|
+
// Temporal references
|
|
99
|
+
[/\b(today|yesterday|last night|this morning|earlier)\b/gi, 0.9, "temporal_recent"],
|
|
100
|
+
[/\b(happened|occurred|took place|went|came)\b/gi, 0.85, "event_verb"],
|
|
101
|
+
[/\b(session|conversation|discussion|chat|talked)\b/gi, 0.8, "conversation"],
|
|
102
|
+
|
|
103
|
+
// Event markers
|
|
104
|
+
[/\b(we did|we made|we built|we created|we discovered)\b/gi, 0.85, "collaborative_event"],
|
|
105
|
+
[/\b(then|after that|next|following|subsequently)\b/gi, 0.7, "sequence"],
|
|
106
|
+
[/\b(december|november|october|january|february|march|april|may|june|july|august|september|monday|tuesday|wednesday|thursday|friday|saturday|sunday)\b/gi, 0.8, "date_reference"],
|
|
107
|
+
|
|
108
|
+
// Timestamps
|
|
109
|
+
[/\b\d{1,2}:\d{2}(?:\s*(?:am|pm))?\b/gi, 0.75, "time_reference"],
|
|
110
|
+
[/\b\d{4}-\d{2}-\d{2}\b/g, 0.85, "iso_date"],
|
|
111
|
+
|
|
112
|
+
// Milestone and achievement events
|
|
113
|
+
[/\b(milestone|achievement|mission|victory|launch)\b/gi, 0.8, "milestone_event"],
|
|
114
|
+
];
|
|
115
|
+
|
|
116
|
+
// ================================================================
|
|
117
|
+
// SEMANTIC LAYER PATTERNS (facts, definitions, concepts)
|
|
118
|
+
// ================================================================
|
|
119
|
+
this.semanticPatterns = [
|
|
120
|
+
// Definition markers
|
|
121
|
+
[/\b(is a|is the|means|refers to|defined as|definition)\b/gi, 0.9, "definition"],
|
|
122
|
+
[/\b(concept|theory|principle|framework|model|paradigm)\b/gi, 0.85, "concept"],
|
|
123
|
+
[/\b(fact|factual|factually|true|truth|actually)\b/gi, 0.8, "factual"],
|
|
124
|
+
|
|
125
|
+
// Technical knowledge
|
|
126
|
+
[/\b(api|database|server|client|protocol|algorithm)\b/gi, 0.75, "technical_term"],
|
|
127
|
+
[/\b(python|javascript|typescript|rust|go|sql|node\.js)\b/gi, 0.8, "programming_language"],
|
|
128
|
+
[/\b(vector|embedding|gpu|cuda|cache|index)\b/gi, 0.85, "infrastructure_technical"],
|
|
129
|
+
[/\b(neural|graph|network|layer|node|edge)\b/gi, 0.85, "advanced_technical"],
|
|
130
|
+
|
|
131
|
+
// Knowledge markers
|
|
132
|
+
[/\b(known as|understood as|recognized as|classified as)\b/gi, 0.8, "classification"],
|
|
133
|
+
[/\b(consists of|comprises|includes|contains|incorporates)\b/gi, 0.75, "composition"],
|
|
134
|
+
];
|
|
135
|
+
|
|
136
|
+
// ================================================================
|
|
137
|
+
// PROCEDURAL LAYER PATTERNS (how-to, processes, code)
|
|
138
|
+
// ================================================================
|
|
139
|
+
this.proceduralPatterns = [
|
|
140
|
+
// How-to markers
|
|
141
|
+
[/\b(how to|to do|in order to|steps to|process for)\b/gi, 0.95, "how_to"],
|
|
142
|
+
[/\b(step \d|first|second|third|then|next|finally)\b/gi, 0.8, "sequence_step"],
|
|
143
|
+
[/\b(procedure|workflow|process|method|approach)\b/gi, 0.85, "process"],
|
|
144
|
+
|
|
145
|
+
// Code patterns
|
|
146
|
+
[/\b(function|def |class |import |from |const |let |var )\b/gi, 0.9, "code_syntax"],
|
|
147
|
+
[/\b(run|execute|invoke|call|trigger|activate)\b/gi, 0.7, "execution_verb"],
|
|
148
|
+
[/\b(create|build|implement|deploy|configure|setup)\b/gi, 0.75, "construction_verb"],
|
|
149
|
+
|
|
150
|
+
// Skill markers
|
|
151
|
+
[/\b(skill|technique|practice|pattern|idiom)\b/gi, 0.8, "skill"],
|
|
152
|
+
[/\b(best practice|recommended|should|must|always|never)\b/gi, 0.75, "guidance"],
|
|
153
|
+
];
|
|
154
|
+
|
|
155
|
+
// ================================================================
|
|
156
|
+
// META LAYER PATTERNS (reasoning, insights, conclusions)
|
|
157
|
+
// ================================================================
|
|
158
|
+
this.metaPatterns = [
|
|
159
|
+
// Insight markers
|
|
160
|
+
[/\b(i realized|i noticed|i observed|i discovered|insight)\b/gi, 0.95, "insight"],
|
|
161
|
+
[/\b(the pattern is|pattern:|this means|implies that)\b/gi, 0.9, "pattern_recognition"],
|
|
162
|
+
[/\b(conclusion|therefore|thus|hence|consequently)\b/gi, 0.85, "conclusion"],
|
|
163
|
+
|
|
164
|
+
// Reasoning markers
|
|
165
|
+
[/\b(because|since|given that|considering|reasoning)\b/gi, 0.8, "reasoning"],
|
|
166
|
+
[/\b(analysis|analyzing|examined|examining|reflects)\b/gi, 0.8, "analysis"],
|
|
167
|
+
[/\b(learned|learning|lesson|takeaway|understanding)\b/gi, 0.85, "learning"],
|
|
168
|
+
|
|
169
|
+
// Meta-cognitive
|
|
170
|
+
[/\b(thinking about|reflecting on|considering|pondering)\b/gi, 0.8, "metacognition"],
|
|
171
|
+
[/\b(my thought|my reasoning|my approach|my strategy)\b/gi, 0.75, "self_analysis"],
|
|
172
|
+
];
|
|
173
|
+
|
|
174
|
+
// ================================================================
|
|
175
|
+
// WORKING LAYER PATTERNS (temporary, session-specific)
|
|
176
|
+
// ================================================================
|
|
177
|
+
this.workingPatterns = [
|
|
178
|
+
// Temporary markers
|
|
179
|
+
[/\b(for now|temporarily|current|currently|at the moment)\b/gi, 0.85, "temporal_now"],
|
|
180
|
+
[/\b(todo|to-do|task|pending|queue|backlog)\b/gi, 0.8, "task"],
|
|
181
|
+
[/\b(reminder|note to self|don't forget|remember to)\b/gi, 0.8, "reminder"],
|
|
182
|
+
|
|
183
|
+
// Session markers
|
|
184
|
+
[/\b(this session|right now|in progress|ongoing|active)\b/gi, 0.8, "session"],
|
|
185
|
+
[/\b(scratch|draft|wip|work in progress|temp)\b/gi, 0.9, "draft"],
|
|
186
|
+
];
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Analyze content and determine the appropriate EMET layer.
|
|
191
|
+
*
|
|
192
|
+
* @param {string} content - The memory content to analyze
|
|
193
|
+
* @param {Object} metadata - Optional metadata that may influence routing
|
|
194
|
+
* @returns {RoutingDecision} - Routing decision with layer, confidence, and signals
|
|
195
|
+
*/
|
|
196
|
+
analyze(content, metadata = {}) {
|
|
197
|
+
// Handle explicit layer override
|
|
198
|
+
if (metadata && metadata.layer) {
|
|
199
|
+
// Resolve aliases (core -> identity, self -> identity, etc.) and
|
|
200
|
+
// validate in one step, against the charter (src/layers.js).
|
|
201
|
+
const explicitLayer = resolveLayer(metadata.layer);
|
|
202
|
+
if (explicitLayer) {
|
|
203
|
+
return new RoutingDecision(
|
|
204
|
+
explicitLayer,
|
|
205
|
+
1.0,
|
|
206
|
+
{ explicit_override: 1.0 }
|
|
207
|
+
);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// Score each layer
|
|
212
|
+
const layerScores = {};
|
|
213
|
+
|
|
214
|
+
// Identity layer scoring (identity and core values)
|
|
215
|
+
const [identityScore, identitySignals] = this._scorePatterns(content, this.identityPatterns);
|
|
216
|
+
layerScores.identity = { score: identityScore, signals: identitySignals };
|
|
217
|
+
|
|
218
|
+
// Episodic scoring
|
|
219
|
+
const [episodicScore, episodicSignals] = this._scorePatterns(content, this.episodicPatterns);
|
|
220
|
+
layerScores.episodic = { score: episodicScore, signals: episodicSignals };
|
|
221
|
+
|
|
222
|
+
// Semantic scoring
|
|
223
|
+
const [semanticScore, semanticSignals] = this._scorePatterns(content, this.semanticPatterns);
|
|
224
|
+
layerScores.semantic = { score: semanticScore, signals: semanticSignals };
|
|
225
|
+
|
|
226
|
+
// Procedural scoring
|
|
227
|
+
const [proceduralScore, proceduralSignals] = this._scorePatterns(content, this.proceduralPatterns);
|
|
228
|
+
layerScores.procedural = { score: proceduralScore, signals: proceduralSignals };
|
|
229
|
+
|
|
230
|
+
// Meta scoring
|
|
231
|
+
const [metaScore, metaSignals] = this._scorePatterns(content, this.metaPatterns);
|
|
232
|
+
layerScores.meta = { score: metaScore, signals: metaSignals };
|
|
233
|
+
|
|
234
|
+
// Working scoring
|
|
235
|
+
const [workingScore, workingSignals] = this._scorePatterns(content, this.workingPatterns);
|
|
236
|
+
layerScores.working = { score: workingScore, signals: workingSignals };
|
|
237
|
+
|
|
238
|
+
// Calculate emotional intensity
|
|
239
|
+
const emotionalIntensity = this._calculateEmotionalIntensity(content, identitySignals);
|
|
240
|
+
|
|
241
|
+
// Calculate technical density
|
|
242
|
+
const technicalDensity = this._calculateTechnicalDensity(content, semanticSignals, proceduralSignals);
|
|
243
|
+
|
|
244
|
+
// Apply emotional intensity boost to identity layer
|
|
245
|
+
if (emotionalIntensity > 0.7) {
|
|
246
|
+
const identityScoreAdjusted = layerScores.identity.score * (1 + emotionalIntensity * 0.5);
|
|
247
|
+
layerScores.identity.score = identityScoreAdjusted;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// Apply technical density boost to semantic/procedural
|
|
251
|
+
if (technicalDensity > 0.6) {
|
|
252
|
+
// Boost semantic more for definitions, procedural more for how-tos
|
|
253
|
+
const hasHowto = Object.keys(proceduralSignals).some(s => s.includes('how_to'));
|
|
254
|
+
if (hasHowto) {
|
|
255
|
+
const procScoreAdjusted = layerScores.procedural.score * (1 + technicalDensity * 0.3);
|
|
256
|
+
layerScores.procedural.score = procScoreAdjusted;
|
|
257
|
+
} else {
|
|
258
|
+
const semScoreAdjusted = layerScores.semantic.score * (1 + technicalDensity * 0.3);
|
|
259
|
+
layerScores.semantic.score = semScoreAdjusted;
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
// Find winning layer
|
|
264
|
+
let bestLayer = FALLBACK_LAYER; // Default fallback, stated once in layers.js
|
|
265
|
+
let bestScore = 0.0;
|
|
266
|
+
let bestSignals = {};
|
|
267
|
+
|
|
268
|
+
for (const [layer, data] of Object.entries(layerScores)) {
|
|
269
|
+
if (data.score > bestScore) {
|
|
270
|
+
bestScore = data.score;
|
|
271
|
+
bestLayer = layer;
|
|
272
|
+
bestSignals = data.signals;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
// Calculate confidence based on margin over second place
|
|
277
|
+
const sortedScores = Object.values(layerScores)
|
|
278
|
+
.map(d => d.score)
|
|
279
|
+
.sort((a, b) => b - a);
|
|
280
|
+
|
|
281
|
+
let confidence = 0.5;
|
|
282
|
+
if (sortedScores.length >= 2 && sortedScores[0] > 0) {
|
|
283
|
+
const margin = (sortedScores[0] - sortedScores[1]) / sortedScores[0];
|
|
284
|
+
confidence = Math.min(0.95, 0.5 + margin * 0.5);
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
return new RoutingDecision(
|
|
288
|
+
bestLayer,
|
|
289
|
+
confidence,
|
|
290
|
+
bestSignals,
|
|
291
|
+
emotionalIntensity,
|
|
292
|
+
technicalDensity
|
|
293
|
+
);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* Score content against a list of patterns.
|
|
298
|
+
*
|
|
299
|
+
* @param {string} content - Content to score
|
|
300
|
+
* @param {Array} patterns - Array of [regex, weight, signalName] tuples
|
|
301
|
+
* @returns {Array} - [totalScore, signals] tuple
|
|
302
|
+
*/
|
|
303
|
+
_scorePatterns(content, patterns) {
|
|
304
|
+
let totalScore = 0.0;
|
|
305
|
+
const signals = {};
|
|
306
|
+
|
|
307
|
+
for (const [pattern, weight, signalName] of patterns) {
|
|
308
|
+
// Reset regex lastIndex for global patterns
|
|
309
|
+
pattern.lastIndex = 0;
|
|
310
|
+
|
|
311
|
+
const matches = content.match(pattern);
|
|
312
|
+
if (matches && matches.length > 0) {
|
|
313
|
+
// Diminishing returns for multiple matches
|
|
314
|
+
const matchScore = weight * (1 + 0.1 * Math.min(matches.length - 1, 5));
|
|
315
|
+
totalScore += matchScore;
|
|
316
|
+
signals[signalName] = matchScore;
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
return [totalScore, signals];
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
/**
|
|
324
|
+
* Calculate emotional intensity score (0-1).
|
|
325
|
+
*
|
|
326
|
+
* @param {string} content - Content to analyze
|
|
327
|
+
* @param {Object} identitySignals - Signals from identity pattern matching
|
|
328
|
+
* @returns {number} - Emotional intensity between 0 and 1
|
|
329
|
+
*/
|
|
330
|
+
_calculateEmotionalIntensity(content, identitySignals) {
|
|
331
|
+
let intensity = 0.5; // Baseline
|
|
332
|
+
|
|
333
|
+
// Boost from emotional signals
|
|
334
|
+
const emotionalSignals = ["emotional_content", "peak_emotion", "gratitude", "emotional_punctuation"];
|
|
335
|
+
for (const signal of emotionalSignals) {
|
|
336
|
+
if (identitySignals[signal]) {
|
|
337
|
+
intensity += 0.1;
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
// Check for exclamation/question intensity
|
|
342
|
+
const exclaimCount = (content.match(/!/g) || []).length;
|
|
343
|
+
if (exclaimCount > 0) {
|
|
344
|
+
intensity += Math.min(exclaimCount * 0.05, 0.2);
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
// Check for ALL CAPS words (emotional emphasis)
|
|
348
|
+
const capsWords = content.match(/\b[A-Z]{3,}\b/g) || [];
|
|
349
|
+
if (capsWords.length > 0) {
|
|
350
|
+
intensity += Math.min(capsWords.length * 0.03, 0.15);
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
return Math.min(1.0, intensity);
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
/**
|
|
357
|
+
* Calculate technical density score (0-1).
|
|
358
|
+
*
|
|
359
|
+
* @param {string} content - Content to analyze
|
|
360
|
+
* @param {Object} semanticSignals - Signals from semantic pattern matching
|
|
361
|
+
* @param {Object} proceduralSignals - Signals from procedural pattern matching
|
|
362
|
+
* @returns {number} - Technical density between 0 and 1
|
|
363
|
+
*/
|
|
364
|
+
_calculateTechnicalDensity(content, semanticSignals, proceduralSignals) {
|
|
365
|
+
let density = 0.0;
|
|
366
|
+
|
|
367
|
+
// Technical signals
|
|
368
|
+
const techSignals = ["technical_term", "programming_language", "infrastructure_technical", "advanced_technical", "code_syntax"];
|
|
369
|
+
for (const signal of techSignals) {
|
|
370
|
+
if (semanticSignals[signal] || proceduralSignals[signal]) {
|
|
371
|
+
density += 0.15;
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
// Code-like patterns
|
|
376
|
+
if (/[{}\[\]();]/.test(content)) {
|
|
377
|
+
density += 0.1;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
// camelCase or snake_case density
|
|
381
|
+
const caseMatches = (content.match(/\b[a-z]+[A-Z][a-zA-Z]*\b|\b[a-z]+_[a-z_]+\b/g) || []).length;
|
|
382
|
+
if (caseMatches > 0) {
|
|
383
|
+
density += Math.min(caseMatches * 0.02, 0.2);
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
return Math.min(1.0, density);
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
/**
|
|
390
|
+
* Get all layer scores for debugging/analysis
|
|
391
|
+
*
|
|
392
|
+
* @param {string} content - Content to analyze
|
|
393
|
+
* @returns {Object} - All layer scores and signals
|
|
394
|
+
*/
|
|
395
|
+
getDetailedAnalysis(content) {
|
|
396
|
+
const analysis = {
|
|
397
|
+
identity: this._scorePatterns(content, this.identityPatterns),
|
|
398
|
+
episodic: this._scorePatterns(content, this.episodicPatterns),
|
|
399
|
+
semantic: this._scorePatterns(content, this.semanticPatterns),
|
|
400
|
+
procedural: this._scorePatterns(content, this.proceduralPatterns),
|
|
401
|
+
meta: this._scorePatterns(content, this.metaPatterns),
|
|
402
|
+
working: this._scorePatterns(content, this.workingPatterns)
|
|
403
|
+
};
|
|
404
|
+
|
|
405
|
+
const result = {};
|
|
406
|
+
for (const [layer, [score, signals]] of Object.entries(analysis)) {
|
|
407
|
+
result[layer] = { score, signals };
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
return result;
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
/**
|
|
415
|
+
* Factory function for creating ContentAnalyzer instance
|
|
416
|
+
*/
|
|
417
|
+
function createContentAnalyzer() {
|
|
418
|
+
return new ContentAnalyzer();
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
/**
|
|
422
|
+
* Simple determineLayer function for backward compatibility
|
|
423
|
+
* Uses ContentAnalyzer internally but returns just the layer name
|
|
424
|
+
*
|
|
425
|
+
* @param {string} content - Content to analyze
|
|
426
|
+
* @param {Object} metadata - Optional metadata with layer override
|
|
427
|
+
* @returns {string} - Layer name
|
|
428
|
+
*/
|
|
429
|
+
function determineLayer(content, metadata = {}) {
|
|
430
|
+
// Reuse singleton instance for performance
|
|
431
|
+
if (!determineLayer._analyzer) {
|
|
432
|
+
determineLayer._analyzer = new ContentAnalyzer();
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
const decision = determineLayer._analyzer.analyze(content, metadata);
|
|
436
|
+
return decision.layer;
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
// Export for ES modules
|
|
440
|
+
export {
|
|
441
|
+
ContentAnalyzer,
|
|
442
|
+
RoutingDecision,
|
|
443
|
+
createContentAnalyzer,
|
|
444
|
+
determineLayer,
|
|
445
|
+
LAYER_ALIASES,
|
|
446
|
+
VALID_LAYERS
|
|
447
|
+
};
|
|
448
|
+
|
|
449
|
+
// Default export
|
|
450
|
+
export default ContentAnalyzer;
|