vibeoscore 1.0.2 → 1.0.9

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 (45) hide show
  1. package/client.js +1 -0
  2. package/client.ts +2 -0
  3. package/lib/logger.js +27 -0
  4. package/mcp-server.js +5 -4
  5. package/mcp-server.ts +4 -3
  6. package/package.json +12 -10
  7. package/dashboard/dist/assets/index-BnPt1Fii.js +0 -1
  8. package/dashboard/dist/assets/index-CfH00tOL.css +0 -1
  9. package/dashboard/dist/index.html +0 -3
  10. package/lib/blackbox-rf.js +0 -1099
  11. package/lib/blackbox.js +0 -137
  12. package/lib/compression.js +0 -119
  13. package/lib/db.js +0 -106
  14. package/lib/db.ts +0 -113
  15. package/lib/delegation.js +0 -137
  16. package/lib/meta-controller.js +0 -418
  17. package/lib/meta-controller.mjs +0 -499
  18. package/lib/patterns.js +0 -150
  19. package/lib/resolution-tracker.js +0 -486
  20. package/lib/stress.js +0 -84
  21. package/lib/tdd.js +0 -218
  22. package/lib/tier-routing.js +0 -48
  23. package/middleware/auth.js +0 -75
  24. package/middleware/auth.ts +0 -87
  25. package/middleware/usage-logging.js +0 -29
  26. package/middleware/usage-logging.ts +0 -41
  27. package/nginx-vibetheog-api.conf +0 -64
  28. package/routes/admin.js +0 -93
  29. package/routes/admin.ts +0 -107
  30. package/routes/blackbox.js +0 -463
  31. package/routes/compression.js +0 -12
  32. package/routes/delegation.js +0 -30
  33. package/routes/patterns.js +0 -53
  34. package/routes/pricing.js +0 -62
  35. package/routes/stress.js +0 -30
  36. package/routes/tdd.js +0 -68
  37. package/routes/tier-routing.js +0 -31
  38. package/scripts/dashboard-server.mjs +0 -246
  39. package/scripts/deploy-zero-downtime.sh +0 -77
  40. package/scripts/deploy.sh +0 -68
  41. package/scripts/release.mjs +0 -30
  42. package/scripts/seed-master-token.js +0 -29
  43. package/scripts/start-all.mjs +0 -34
  44. package/server.js +0 -88
  45. package/vibeos-api.service +0 -19
@@ -1,499 +0,0 @@
1
- // SPDX-License-Identifier: MIT
2
- // SPDX-FileCopyrightText: 2026 vibeOS <https://github.com/DrunkkToys/vibeOS>
3
- // Meta-Controller — maps blackbox resolution state to a unified control vector.
4
- // v2 orchestration: single source of truth for all subsystem directives.
5
- // v3: OptimizationMode system — 4 session-level profiles + auto mode.
6
-
7
- export type OptimizationMode = "balanced" | "budget" | "speed" | "longrun" | "auto"
8
-
9
- export type ControlVector = {
10
- enforcement_mode: "relaxed" | "normal" | "strict"
11
- enforcement_reason: string
12
-
13
- flow_mode: "audit" | "normal" | "strict"
14
- flow_focus: string[]
15
-
16
- tdd_mode: "lazy" | "normal" | "strict" | "quality"
17
- tdd_focus: string[]
18
-
19
- tier_bias: "cheap" | "auto" | "medium" | "brain"
20
-
21
- thinking_mode: "off" | "brief" | "full" | "auto"
22
-
23
- stress_multiplier: number
24
-
25
- context7_urgency: "optional" | "preferred" | "required"
26
-
27
- wbp_verbosity: "minimal" | "normal" | "detailed"
28
-
29
- optimization_mode: OptimizationMode
30
-
31
- context_packet: ContextPacket
32
-
33
- directives: string[]
34
- }
35
-
36
- export type ContextPacketKind = "budget" | "speed" | "quality" | "forensic" | "research" | "pivot"
37
-
38
- export type ContextPacket = {
39
- kind: ContextPacketKind
40
- budget_kb: "1-3" | "3-10" | "10-20" | "20-100"
41
- title: string
42
- summary: string
43
- signals: string[]
44
- }
45
-
46
- type RegimeControlMap = Record<string, Omit<ControlVector, "context_packet" | "directives" | "enforcement_reason" | "optimization_mode"> & { enforcement_reason: string }>
47
-
48
- const REGIME_CONTROL: RegimeControlMap = {
49
- INIT: {
50
- enforcement_mode: "normal",
51
- enforcement_reason: "fresh session — baseline enforcement",
52
- flow_mode: "normal",
53
- flow_focus: [],
54
- tdd_mode: "normal",
55
- tdd_focus: [],
56
- tier_bias: "auto",
57
- thinking_mode: "auto",
58
- stress_multiplier: 1.0,
59
- context7_urgency: "preferred",
60
- wbp_verbosity: "normal",
61
- },
62
- DIVERGENT: {
63
- enforcement_mode: "relaxed",
64
- enforcement_reason: "signals scattered — avoid interrupting exploration",
65
- flow_mode: "audit",
66
- flow_focus: ["no-write-without-clarification"],
67
- tdd_mode: "lazy",
68
- tdd_focus: [],
69
- tier_bias: "medium",
70
- thinking_mode: "off",
71
- stress_multiplier: 0.5,
72
- context7_urgency: "optional",
73
- wbp_verbosity: "detailed",
74
- },
75
- EXPLORING: {
76
- enforcement_mode: "relaxed",
77
- enforcement_reason: "user researching — minimal enforcement, save brain for real work",
78
- flow_mode: "audit",
79
- flow_focus: [],
80
- tdd_mode: "lazy",
81
- tdd_focus: [],
82
- tier_bias: "cheap",
83
- thinking_mode: "off",
84
- stress_multiplier: 0.7,
85
- context7_urgency: "optional",
86
- wbp_verbosity: "detailed",
87
- },
88
- REFINING: {
89
- enforcement_mode: "normal",
90
- enforcement_reason: "user narrowing down — balanced mode",
91
- flow_mode: "normal",
92
- flow_focus: [],
93
- tdd_mode: "normal",
94
- tdd_focus: [],
95
- tier_bias: "auto",
96
- thinking_mode: "auto",
97
- stress_multiplier: 1.0,
98
- context7_urgency: "preferred",
99
- wbp_verbosity: "normal",
100
- },
101
- CONVERGING: {
102
- enforcement_mode: "strict",
103
- enforcement_reason: "user about to commit — full enforcement, catch violations",
104
- flow_mode: "strict",
105
- flow_focus: ["write-edit-check", "no-untouched-files"],
106
- tdd_mode: "strict",
107
- tdd_focus: ["skeleton-on-write", "assertion-check"],
108
- tier_bias: "brain",
109
- thinking_mode: "brief",
110
- stress_multiplier: 1.5,
111
- context7_urgency: "required",
112
- wbp_verbosity: "minimal",
113
- },
114
- LOOPING: {
115
- enforcement_mode: "relaxed",
116
- enforcement_reason: "user stuck — relax all enforcement, fresh perspective",
117
- flow_mode: "audit",
118
- flow_focus: ["suggest-alternative"],
119
- tdd_mode: "lazy",
120
- tdd_focus: [],
121
- tier_bias: "medium",
122
- thinking_mode: "off",
123
- stress_multiplier: 0.3,
124
- context7_urgency: "optional",
125
- wbp_verbosity: "detailed",
126
- },
127
- CLOSED: {
128
- enforcement_mode: "strict",
129
- enforcement_reason: "finalizing — full enforcement, max stress sensitivity",
130
- flow_mode: "strict",
131
- flow_focus: ["write-edit-check", "no-untouched-files", "no-lgtm"],
132
- tdd_mode: "quality",
133
- tdd_focus: ["full-coverage", "edge-cases"],
134
- tier_bias: "brain",
135
- thinking_mode: "brief",
136
- stress_multiplier: 2.0,
137
- context7_urgency: "required",
138
- wbp_verbosity: "minimal",
139
- },
140
- }
141
-
142
- const DEFAULT_CONTROL: Omit<ControlVector, "directives" | "enforcement_reason" | "optimization_mode"> & { enforcement_reason: string } = REGIME_CONTROL.EXPLORING
143
-
144
- // ── Optimization Mode Delta Tables ─────────────────────────────────────
145
- // Each mode defines overrides applied after the base per-regime control vector.
146
- // "balanced" = no overrides (use per-regime defaults as-is).
147
-
148
- type ModeDelta = Partial<Omit<ControlVector, "directives" | "enforcement_reason" | "optimization_mode"> & { loop_threshold?: number; api_enrichment?: boolean; outcome_detection?: boolean }>
149
- type ContextState = {
150
- sub_regime?: string
151
- is_looping?: boolean
152
- loop_intervention_level?: string
153
- momentum?: number
154
- n_interactions?: number
155
- pivot_detected?: boolean
156
- pivot_score?: number
157
- continuity_state?: string
158
- resolution?: string
159
- latest_stress_multiplier?: number
160
- user_text?: string
161
- prompt?: string
162
- features?: Record<string, unknown>
163
- action?: string
164
- outcome?: string
165
- signals?: Record<string, number>
166
- }
167
-
168
- const MODE_DELTAS: Record<Exclude<OptimizationMode, "auto">, ModeDelta> = {
169
- balanced: {},
170
- budget: {
171
- agent_mode: "build",
172
- tier_bias: "cheap",
173
- thinking_mode: "brief",
174
- tdd_mode: "normal",
175
- tdd_focus: [],
176
- flow_mode: "normal",
177
- flow_focus: [],
178
- enforcement_mode: "normal",
179
- wbp_verbosity: "normal",
180
- context7_urgency: "preferred",
181
- stress_multiplier: 0.5,
182
- loop_threshold: 0.7,
183
- api_enrichment: false,
184
- outcome_detection: true,
185
- },
186
- quality: {
187
- tier_bias: "brain",
188
- thinking_mode: "full",
189
- tdd_mode: "quality",
190
- tdd_focus: ["full-coverage", "edge-cases", "property-based"],
191
- flow_mode: "strict",
192
- flow_focus: ["write-edit-check", "no-untouched-files", "no-lgtm", "suggest-alternative"],
193
- enforcement_mode: "strict",
194
- wbp_verbosity: "detailed",
195
- context7_urgency: "required",
196
- stress_multiplier: 2.0,
197
- loop_threshold: 0.4,
198
- api_enrichment: true,
199
- outcome_detection: true,
200
- },
201
- speed: {
202
- tier_bias: "medium",
203
- thinking_mode: "off",
204
- tdd_mode: "lazy",
205
- tdd_focus: [],
206
- flow_mode: "audit",
207
- flow_focus: [],
208
- enforcement_mode: "relaxed",
209
- wbp_verbosity: "minimal",
210
- context7_urgency: "optional",
211
- stress_multiplier: 0.0,
212
- loop_threshold: 0.9,
213
- api_enrichment: false,
214
- outcome_detection: false,
215
- },
216
- longrun: {
217
- tier_bias: "brain",
218
- thinking_mode: "brief",
219
- tdd_mode: "quality",
220
- tdd_focus: ["full-coverage", "edge-cases", "skeleton-on-write", "assertion-check"],
221
- flow_mode: "strict",
222
- flow_focus: ["write-edit-check", "no-untouched-files", "no-lgtm", "suggest-alternative"],
223
- enforcement_mode: "strict",
224
- wbp_verbosity: "detailed",
225
- context7_urgency: "required",
226
- stress_multiplier: 1.0,
227
- loop_threshold: 0.5,
228
- api_enrichment: true,
229
- outcome_detection: true,
230
- },
231
- }
232
-
233
- export function autoSelectMode(subRegime: string, stressMultiplier?: number, context: { state?: ContextState; recentSignals?: { recentStressAvg?: number; recentStressPeak?: number; repeatRatio?: number; anomalyRate?: number; negativeRate?: number } } = {}): OptimizationMode {
234
- const text = String(context.state?.user_text || context.state?.prompt || "").trim()
235
- const wordCount = text ? text.split(/\s+/).filter(Boolean).length : 0
236
- const hasEvidenceSignal = /error|fail|broken|fix|review|compare|deploy|test|debug|refactor|security|memory leak|pipeline|auth|ci|cd|optimi|validate|inspect|audit|research|study|trace/i.test(text)
237
- const recent = context.recentSignals || {}
238
- const recentStressAvg = Number(recent.recentStressAvg ?? 0)
239
- const recentStressPeak = Number(recent.recentStressPeak ?? 0)
240
- const recentAnomalyRate = Number(recent.anomalyRate ?? 0)
241
- const recentNegativeRate = Number(recent.negativeRate ?? 0)
242
- const elevatedRecentLoad = recentStressAvg > 0.35 || recentStressPeak > 0.6 || recentAnomalyRate > 0.35 || recentNegativeRate > 0.15
243
- if (subRegime === "LOOPING") return "speed"
244
- if (stressMultiplier && stressMultiplier > 1.5) return "quality"
245
- if (elevatedRecentLoad && subRegime !== "RESEARCH") {
246
- if (subRegime === "INIT" && wordCount <= 2 && !hasEvidenceSignal) return "budget"
247
- if (/(review|compare|audit|inspect|trace)/i.test(text)) return "audit"
248
- return "quality"
249
- }
250
- if (subRegime === "INIT") {
251
- if (wordCount <= 2 && text.length <= 16 && !hasEvidenceSignal) return "budget"
252
- return hasEvidenceSignal ? "audit" : "quality"
253
- }
254
- if (subRegime === "RESEARCH") return "longrun"
255
- if (subRegime === "CONVERGING" || subRegime === "CLOSED") return "quality"
256
- if (subRegime === "REFINING") return "quality"
257
- if (subRegime === "EXPLORING" || subRegime === "DIVERGENT") return hasEvidenceSignal ? "audit" : "quality"
258
- return "quality"
259
- }
260
-
261
- export function computeControlVector(
262
- state: ContextState,
263
- action?: string,
264
- optimizationMode?: OptimizationMode,
265
- ): ControlVector {
266
- const regime = state.sub_regime || "INIT"
267
- const base = REGIME_CONTROL[regime] || DEFAULT_CONTROL
268
-
269
- // Determine effective mode
270
- let effectiveMode: OptimizationMode = optimizationMode || "balanced"
271
- if (effectiveMode === "auto") {
272
- effectiveMode = autoSelectMode(regime, state.latest_stress_multiplier, { state })
273
- }
274
-
275
- // Apply mode deltas on top of base (only for non-balanced modes)
276
- const delta = effectiveMode !== "balanced" ? (MODE_DELTAS[effectiveMode] || {}) : {}
277
-
278
- const overridden: Omit<ControlVector, "directives"> = {
279
- optimization_mode: effectiveMode,
280
- enforcement_mode: delta.enforcement_mode ?? base.enforcement_mode,
281
- enforcement_reason: delta.enforcement_mode
282
- ? `[optimize: ${effectiveMode}] ${describeMode(delta)}`
283
- : base.enforcement_reason,
284
- flow_mode: delta.flow_mode ?? base.flow_mode,
285
- flow_focus: delta.flow_focus ?? base.flow_focus,
286
- tdd_mode: delta.tdd_mode ?? base.tdd_mode,
287
- tdd_focus: delta.tdd_focus ?? base.tdd_focus,
288
- tier_bias: delta.tier_bias ?? base.tier_bias,
289
- thinking_mode: delta.thinking_mode ?? base.thinking_mode,
290
- stress_multiplier: delta.stress_multiplier ?? base.stress_multiplier,
291
- context7_urgency: delta.context7_urgency ?? base.context7_urgency,
292
- wbp_verbosity: delta.wbp_verbosity ?? base.wbp_verbosity,
293
- }
294
-
295
- const contextPacket = buildContextPacket(overridden, regime, state, action, effectiveMode)
296
- const directives = buildDirectives(overridden, regime, state, action, effectiveMode, contextPacket)
297
-
298
- return {
299
- ...overridden,
300
- context_packet: contextPacket,
301
- directives,
302
- }
303
- }
304
-
305
- function describeMode(delta: ModeDelta): string {
306
- if (delta.tier_bias === "cheap") return "budget mode — max cost savings"
307
- if (delta.tier_bias === "brain" && delta.thinking_mode === "full") return "quality mode — max output quality"
308
- if (delta.tdd_mode === "quality" && delta.flow_mode === "strict") return "longrun mode — codebase health"
309
- if (delta.tier_bias === "medium" && delta.stress_multiplier === 0) return "speed mode — max response speed"
310
- return `${delta.tier_bias || "auto"} / ${delta.thinking_mode || "auto"}`
311
- }
312
-
313
- function buildContextPacket(
314
- cv: Omit<ControlVector, "context_packet" | "directives">,
315
- regime: string,
316
- state: ContextState,
317
- action?: string,
318
- optimizationMode?: OptimizationMode,
319
- ): ContextPacket {
320
- const text = String(state.user_text || state.prompt || "")
321
- const lower = text.toLowerCase()
322
- const stress = Number(state.latest_stress_multiplier ?? cv.stress_multiplier ?? 0)
323
- const features = state.features || {}
324
- const fileMentions = Number(features.file_mentions ?? 0)
325
- const errorSignals = Number(features.error_signals ?? 0)
326
- const promptSignals = {
327
- error: /bug|error|fail|broken|trace|stack|panic|crash|corrupt|refactor|debug|fix|issue|exception/i.test(lower) || errorSignals > 0.3,
328
- forensic: /forensic|investigate|inspect|trace|audit|root cause|reproduce|evidence|logs|stack/i.test(lower) || fileMentions > 0.2,
329
- research: regime === "RESEARCH" || optimizationMode === "longrun" || cv.context7_urgency === "required" || /research|study|compare|source|reference|docs/i.test(lower),
330
- pivot: Boolean(state.pivot_detected) || /new topic|switch gears|different issue|change topic|pivot/i.test(lower),
331
- looping: Boolean(state.is_looping) || regime === "LOOPING",
332
- finalizing: regime === "CONVERGING" || regime === "CLOSED" || optimizationMode === "quality",
333
- }
334
-
335
- const choose = (): ContextPacketKind => {
336
- if (promptSignals.pivot) return "pivot"
337
- if (promptSignals.looping || optimizationMode === "speed") return "speed"
338
- const evidenceHeavy = promptSignals.error && (errorSignals > 0.4 || fileMentions > 0.2)
339
- const docsHeavy = promptSignals.research && /docs|reference|library|api|spec|compare|read|lookup/i.test(lower)
340
- const commitHeavy = promptSignals.finalizing && (/commit|ship|release|validate|verify|finalize|close/i.test(lower) || stress > 1.5)
341
- if (evidenceHeavy) return "forensic"
342
- if (docsHeavy) return "research"
343
- if (commitHeavy) return "quality"
344
- return "budget"
345
- }
346
-
347
- const kind = choose()
348
- const packets: Record<ContextPacketKind, ContextPacket> = {
349
- budget: {
350
- kind: "budget",
351
- budget_kb: "1-3",
352
- title: "whisper the minimum",
353
- summary: "Keep only the smallest useful frame. One decision, one next action, no broad recap.",
354
- signals: ["one cheap check", "ask for the single missing detail", "drop everything that does not change the answer"],
355
- },
356
- speed: {
357
- kind: "speed",
358
- budget_kb: "1-3",
359
- title: "escape the loop",
360
- summary: "Use the shortest context that can break repetition. Prefer a fresh angle over more history.",
361
- signals: ["summarize the dead end in one line", "offer a new path", "avoid re-injecting prior boilerplate"],
362
- },
363
- quality: {
364
- kind: "quality",
365
- budget_kb: "3-10",
366
- title: "tighten for correctness",
367
- summary: "Carry only the constraints, invariants, and validation steps needed to finish cleanly.",
368
- signals: ["check edge cases", "keep the last known good state", "validate before claiming done"],
369
- },
370
- forensic: {
371
- kind: "forensic",
372
- budget_kb: "3-10",
373
- title: "inspect the evidence",
374
- summary: "Load only the artifact trail needed to explain failure: logs, traces, diff, repro steps, and exact scope.",
375
- signals: ["prefer concrete evidence", "one hypothesis at a time", "do not expand into unrelated context"],
376
- },
377
- research: {
378
- kind: "research",
379
- budget_kb: "10-20",
380
- title: "retrieve the right references",
381
- summary: "Pull only the specific docs or prior findings relevant to the current decision. Whisper, do not flood.",
382
- signals: ["use context7 when required", "summarize only the relevant sources", "stop after the decision is supported"],
383
- },
384
- pivot: {
385
- kind: "pivot",
386
- budget_kb: "1-3",
387
- title: "acknowledge the turn",
388
- summary: "The topic changed. Preserve the new goal and discard stale assumptions before proceeding.",
389
- signals: ["confirm the new scope", "reset stale context", "resume with the new target only"],
390
- },
391
- }
392
-
393
- return packets[kind]
394
- }
395
-
396
- function buildDirectives(
397
- cv: Omit<ControlVector, "directives">,
398
- regime: string,
399
- state: ContextState,
400
- action?: string,
401
- optimizationMode?: OptimizationMode,
402
- contextPacket?: ContextPacket,
403
- ): string[] {
404
- const d: string[] = []
405
-
406
- if (cv.enforcement_mode !== "normal") {
407
- d.push(
408
- `[delegation enforcement: ${cv.enforcement_mode}] ${cv.enforcement_reason}. ` +
409
- (cv.enforcement_mode === "relaxed"
410
- ? "Write/Edit restrictions are temporarily eased. Proceed with caution."
411
- : "ALL write/edit operations must pass strict validation. No exceptions.")
412
- )
413
- }
414
-
415
- if (cv.flow_mode !== "normal") {
416
- const focusNote = cv.flow_focus.length > 0 ? ` Focus rules: ${cv.flow_focus.join(", ")}.` : ""
417
- d.push(`[flow: ${cv.flow_mode}] Flow enforcer is in ${cv.flow_mode} mode.${focusNote}`)
418
- }
419
-
420
- if (cv.tdd_mode !== "normal") {
421
- const focusNote = cv.tdd_focus.length > 0 ? ` Focus: ${cv.tdd_focus.join(", ")}.` : ""
422
- d.push(`[tdd: ${cv.tdd_mode}] TDD enforcement is ${cv.tdd_mode}.${focusNote}`)
423
- }
424
-
425
- if (cv.tier_bias !== "auto") {
426
- d.push(`[tier routing] Route to ${cv.tier_bias} tier for this turn.`)
427
- }
428
-
429
- if (contextPacket) {
430
- d.push(`[context packet: ${contextPacket.kind} | ${contextPacket.budget_kb} KB] ${contextPacket.title}. ${contextPacket.summary}`)
431
- d.push(`[context packet signals] ${contextPacket.signals.join(" | ")}`)
432
- }
433
-
434
- if (cv.context7_urgency !== "preferred" && contextPacket?.kind !== "research") {
435
- d.push(
436
- `[context7] Documentation lookup is ${cv.context7_urgency}. ` +
437
- (cv.context7_urgency === "required"
438
- ? "Use mcp__context7__* only for the exact library/framework facts needed here."
439
- : "context7 tools are available if they change the decision.")
440
- )
441
- }
442
-
443
- if (cv.wbp_verbosity !== "normal" && contextPacket?.kind !== "speed") {
444
- d.push(
445
- `[wbp protocol] Delegation output synthesis is ${cv.wbp_verbosity}. ` +
446
- (cv.wbp_verbosity === "minimal"
447
- ? "Summarize subagent results in 1-2 sentences."
448
- : "Provide only the actionable result and the minimum necessary rationale.")
449
- )
450
- }
451
-
452
- if (cv.thinking_mode !== "auto" && contextPacket?.kind !== "speed") {
453
- d.push(
454
- `[thinking mode: ${cv.thinking_mode}] Reasoning depth set to ${cv.thinking_mode}. ` +
455
- (cv.thinking_mode === "off"
456
- ? "Skip extended thinking and stay concise."
457
- : "Use extended thinking only when the selected context packet cannot resolve the task.")
458
- )
459
- }
460
-
461
- if (state.is_looping && state.loop_intervention_level && state.loop_intervention_level !== "none") {
462
- const severity = state.loop_intervention_level === "escalated" ? "CRITICAL"
463
- : state.loop_intervention_level === "assertive" ? "WARNING" : "NOTICE"
464
- d.push(`[loop prevention: ${severity}] The conversation may be looping — try a different approach. (level: ${state.loop_intervention_level})`)
465
- }
466
-
467
- if (optimizationMode && optimizationMode !== "balanced") {
468
- d.push(`[optimization: ${optimizationMode}] Session optimization mode is "${optimizationMode}". This overrides default per-regime behavior.`)
469
- }
470
-
471
- return d
472
- }
473
-
474
- export function buildControlHistoryEntry(
475
- turn: number,
476
- regime: string,
477
- control: ControlVector,
478
- reward: number | null = null,
479
- ): Record<string, unknown> {
480
- return {
481
- turn,
482
- regime,
483
- control: {
484
- enforcement_mode: control.enforcement_mode,
485
- flow_mode: control.flow_mode,
486
- tdd_mode: control.tdd_mode,
487
- tier_bias: control.tier_bias,
488
- thinking_mode: control.thinking_mode,
489
- stress_multiplier: control.stress_multiplier,
490
- context7_urgency: control.context7_urgency,
491
- wbp_verbosity: control.wbp_verbosity,
492
- context_packet: control.context_packet,
493
- },
494
- reward,
495
- }
496
- }
497
-
498
- export const REGIME_CONTROL_TABLE = REGIME_CONTROL
499
- export { MODE_DELTAS }
package/lib/patterns.js DELETED
@@ -1,150 +0,0 @@
1
- class PatternStore {
2
- constructor() {
3
- this.patterns = { friction: {}, routines: {} }
4
- this.recentToolEvents = []
5
- this.MAX_PATTERNS = 50
6
- this.MAX_RECENT = 20
7
- this.REPEAT_THRESHOLD = 3
8
- }
9
-
10
- recordPattern(kind, key, summary, meta = {}) {
11
- const target = kind === "routine" ? this.patterns.routines : this.patterns.friction
12
- const now = new Date().toISOString()
13
-
14
- const row = target[key] || {
15
- kind,
16
- summary,
17
- count: 0,
18
- sessions: [],
19
- firstSeen: now,
20
- lastSeen: null,
21
- meta: {},
22
- }
23
-
24
- row.count = Number(row.count || 0) + 1
25
- row.lastSeen = now
26
- row.sessions = [...new Set([...(row.sessions || []), meta.sessionId || "unknown"])].slice(-10)
27
- if (meta) {
28
- row.meta = { ...row.meta, ...meta }
29
- }
30
-
31
- target[key] = row
32
-
33
- if (Object.keys(target).length > this.MAX_PATTERNS) {
34
- const sorted = Object.entries(target).sort((a, b) => (a[1].lastSeen || "").localeCompare(b[1].lastSeen || ""))
35
- const toRemove = sorted.slice(0, Object.keys(target).length - this.MAX_PATTERNS)
36
- for (const [k] of toRemove) delete target[k]
37
- }
38
-
39
- return row
40
- }
41
-
42
- observeToolEvent(toolName, input, output, directory) {
43
- const normalized = {
44
- tool: toolName,
45
- timestamp: Date.now(),
46
- target: this.extractTarget(toolName, input),
47
- directory,
48
- }
49
-
50
- this.recentToolEvents.push(normalized)
51
- if (this.recentToolEvents.length > this.MAX_RECENT) {
52
- this.recentToolEvents = this.recentToolEvents.slice(-this.MAX_RECENT)
53
- }
54
-
55
- const patterns = []
56
-
57
- const repeated = this.detectRepeatedToolCalls()
58
- if (repeated) {
59
- patterns.push(this.recordPattern("friction", repeated.key, repeated.summary, { tool: toolName }))
60
- }
61
-
62
- const verification = this.detectPostEditVerification(output)
63
- if (verification) {
64
- patterns.push(this.recordPattern(
65
- verification.success ? "routine" : "friction",
66
- verification.key,
67
- verification.summary,
68
- { tool: toolName }
69
- ))
70
- }
71
-
72
- return patterns
73
- }
74
-
75
- detectRepeatedToolCalls() {
76
- if (this.recentToolEvents.length < this.REPEAT_THRESHOLD) return null
77
-
78
- const recent = this.recentToolEvents.slice(-this.REPEAT_THRESHOLD)
79
- const key = `${recent[0].tool}:${recent[0].target}`
80
-
81
- if (recent.every(e => `${e.tool}:${e.target}` === key)) {
82
- return {
83
- key,
84
- summary: `Repeated ${recent[0].tool} on ${recent[0].target} (${this.REPEAT_THRESHOLD}x)`,
85
- tool: recent[0].tool,
86
- target: recent[0].target,
87
- }
88
- }
89
-
90
- return null
91
- }
92
-
93
- detectPostEditVerification(output) {
94
- if (!output) return null
95
-
96
- const isBuild = /build|compile|lint|typecheck/i.test(output)
97
- const isSuccess = /success|passed|no errors|0 failed/i.test(output)
98
- const isFailure = /error|failed|failed|syntax|cannot find/i.test(output)
99
-
100
- if (isBuild) {
101
- return {
102
- key: `post_edit_${isSuccess ? "success" : "failure"}`,
103
- summary: isSuccess ? "Post-edit verification passed" : "Post-edit verification failed",
104
- success: isSuccess,
105
- }
106
- }
107
-
108
- return null
109
- }
110
-
111
- extractTarget(toolName, input) {
112
- if (!input) return "unknown"
113
- if (typeof input === "string") return input.substring(0, 100)
114
- if (typeof input === "object") {
115
- return input.filePath || input.file_path || input.command || input.url || JSON.stringify(input).substring(0, 100)
116
- }
117
- return "unknown"
118
- }
119
-
120
- getPatterns(kind = null) {
121
- if (kind === "friction") return Object.values(this.patterns.friction)
122
- if (kind === "routine") return Object.values(this.patterns.routines)
123
- return [...Object.values(this.patterns.friction), ...Object.values(this.patterns.routines)]
124
- }
125
-
126
- getLearnedExploratoryWords() {
127
- const words = new Set()
128
- for (const pattern of Object.values(this.patterns.friction)) {
129
- if (pattern.meta?.firstWord && pattern.count >= 2) {
130
- words.add(pattern.meta.firstWord)
131
- }
132
- }
133
- return [...words]
134
- }
135
-
136
- clear() {
137
- this.patterns = { friction: {}, routines: {} }
138
- this.recentToolEvents = []
139
- }
140
-
141
- toJSON() {
142
- return {
143
- friction: this.patterns.friction,
144
- routines: this.patterns.routines,
145
- recent_events: this.recentToolEvents.length,
146
- }
147
- }
148
- }
149
-
150
- export { PatternStore }