pi-mega-compact 0.8.23 → 0.8.24
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/dist/extensions/dashboard-server/api-contracts/endpoints.js +8 -0
- package/dist/extensions/dashboard-server/api-contracts/game-types.js +7 -0
- package/dist/extensions/mega-runtime/append-event.js +24 -0
- package/dist/extensions/mega-runtime/bind-repo.js +65 -0
- package/dist/extensions/mega-runtime/capture-model.js +87 -0
- package/dist/extensions/mega-runtime/dashboard-snapshot.js +118 -0
- package/dist/extensions/mega-runtime/effects.js +86 -0
- package/dist/extensions/mega-runtime/engine-view.js +11 -0
- package/dist/extensions/mega-runtime/game-state.js +116 -0
- package/dist/extensions/mega-runtime/get-state-dir.js +10 -0
- package/dist/extensions/mega-runtime/perf.js +49 -0
- package/dist/extensions/mega-runtime/pressure-getters.js +64 -0
- package/dist/extensions/mega-runtime/render-widget.js +17 -0
- package/dist/extensions/mega-runtime/reset-runtime.js +50 -0
- package/dist/extensions/mega-runtime/runtime-helpers.js +73 -0
- package/dist/extensions/mega-runtime/runtime-snapshot.js +204 -0
- package/dist/extensions/mega-runtime/runtime.js +352 -0
- package/dist/extensions/mega-runtime/snapshot.js +142 -0
- package/dist/extensions/mega-runtime/state.js +5 -1151
- package/dist/extensions/mega-runtime/status.js +11 -0
- package/dist/extensions/mega-runtime/widget-ansi.js +207 -0
- package/dist/extensions/mega-runtime/widget-types.js +8 -0
- package/dist/extensions/mega-runtime/widget.js +15 -204
- package/dist/extensions/openclaw-mega-compact.js +291 -0
- package/dist/src/minilm.js +92 -0
- package/dist/src/wordpiece.js +129 -0
- package/extensions/dashboard-client/dist/assets/index-D_WtU2TV.js.map +1 -1
- package/extensions/dashboard-server/api-contracts/endpoints.ts +30 -155
- package/extensions/dashboard-server/api-contracts/game-types.ts +172 -0
- package/extensions/mega-runtime/DECOMPOSITION.md +180 -0
- package/extensions/mega-runtime/README.md +38 -0
- package/extensions/mega-runtime/append-event.ts +40 -0
- package/extensions/mega-runtime/bind-repo.ts +81 -0
- package/extensions/mega-runtime/capture-model.ts +101 -0
- package/extensions/mega-runtime/dashboard-snapshot.ts +173 -0
- package/extensions/mega-runtime/effects.ts +129 -0
- package/extensions/mega-runtime/engine-view.ts +17 -0
- package/extensions/mega-runtime/game-state.ts +149 -0
- package/extensions/mega-runtime/get-state-dir.ts +19 -0
- package/extensions/mega-runtime/perf.ts +60 -0
- package/extensions/mega-runtime/pressure-getters.ts +96 -0
- package/extensions/mega-runtime/render-widget.ts +41 -0
- package/extensions/mega-runtime/reset-runtime.ts +80 -0
- package/extensions/mega-runtime/runtime-helpers.ts +119 -0
- package/extensions/mega-runtime/runtime-snapshot.ts +289 -0
- package/extensions/mega-runtime/runtime.ts +437 -0
- package/extensions/mega-runtime/snapshot.ts +230 -0
- package/extensions/mega-runtime/state.ts +5 -1268
- package/extensions/mega-runtime/status.ts +26 -0
- package/extensions/mega-runtime/widget-ansi.ts +217 -0
- package/extensions/mega-runtime/widget-types.ts +80 -0
- package/extensions/mega-runtime/widget.ts +34 -285
- package/package.json +1 -1
- package/dist/extensions/dashboard-client/src/hooks/useApi.js +0 -51
- package/dist/extensions/dashboard-client/src/hooks/useSSE.js +0 -63
|
@@ -12,9 +12,34 @@
|
|
|
12
12
|
import type { EndpointDef } from './core.js';
|
|
13
13
|
import type { SnapshotResponse } from './snapshot.js';
|
|
14
14
|
import type { IndexesIndexRow, IndexesSummaryResponse } from './multi-repo.js';
|
|
15
|
-
import type {
|
|
15
|
+
import type { GameStateResponse } from './game.js';
|
|
16
16
|
import type { SseEvent } from './index.js';
|
|
17
17
|
|
|
18
|
+
import type {
|
|
19
|
+
GameScoreRow,
|
|
20
|
+
GameScoresQuery,
|
|
21
|
+
AchievementRow,
|
|
22
|
+
SessionsResponse,
|
|
23
|
+
SessionTimeseriesQuery,
|
|
24
|
+
SessionTimeseriesResponse,
|
|
25
|
+
GameStatePatch,
|
|
26
|
+
SseEndpointDef,
|
|
27
|
+
} from './game-types.js';
|
|
28
|
+
|
|
29
|
+
export type {
|
|
30
|
+
GameScoreRow,
|
|
31
|
+
GameScoresQuery,
|
|
32
|
+
AchievementRow,
|
|
33
|
+
ActiveSession,
|
|
34
|
+
SessionsResponse,
|
|
35
|
+
SessionDataPoint,
|
|
36
|
+
SessionSeries,
|
|
37
|
+
SessionTimeseriesQuery,
|
|
38
|
+
SessionTimeseriesResponse,
|
|
39
|
+
GameStatePatch,
|
|
40
|
+
SseEndpointDef,
|
|
41
|
+
} from './game-types.js';
|
|
42
|
+
|
|
18
43
|
// ─── New Response Types (inline) ───────────────────────────────────────────
|
|
19
44
|
|
|
20
45
|
/**
|
|
@@ -293,167 +318,17 @@ export interface PerfResponse {
|
|
|
293
318
|
}
|
|
294
319
|
|
|
295
320
|
// ─── Game Score & Achievement Types ─────────────────────────────────────────
|
|
296
|
-
|
|
297
|
-
/**
|
|
298
|
-
* A leaderboard row for GET /api/game-scores. One row per repo per metric.
|
|
299
|
-
*/
|
|
300
|
-
export interface GameScoreRow {
|
|
301
|
-
/** Absolute path to the repo root. */
|
|
302
|
-
readonly repo_root: string;
|
|
303
|
-
/** Score value (interpretation depends on the metric). */
|
|
304
|
-
readonly value: number;
|
|
305
|
-
/** Unix timestamp (milliseconds) when the score was recorded. */
|
|
306
|
-
readonly ts: number;
|
|
307
|
-
/** Optional metadata associated with the score event. */
|
|
308
|
-
readonly meta: unknown;
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
/**
|
|
312
|
-
* Query parameters for GET /api/game-scores.
|
|
313
|
-
*/
|
|
314
|
-
export interface GameScoresQuery {
|
|
315
|
-
/** Leaderboard metric (must be one of: cache, dedupe, turns, repos, mega_cache). Optional. */
|
|
316
|
-
readonly metric?: string;
|
|
317
|
-
/** Maximum number of rows to return (default: 10, clamped to [1, 100]). Optional. */
|
|
318
|
-
readonly limit?: number;
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
/**
|
|
322
|
-
* An achievement row for GET /api/achievements. One row per seeded achievement.
|
|
323
|
-
*/
|
|
324
|
-
export interface AchievementRow {
|
|
325
|
-
/** Achievement identifier. */
|
|
326
|
-
readonly id: string;
|
|
327
|
-
/** Display title of the achievement. */
|
|
328
|
-
readonly title: string;
|
|
329
|
-
/** Description of the unlock condition. */
|
|
330
|
-
readonly description: string;
|
|
331
|
-
/** Whether the achievement is hidden (1 = hidden, 0 = visible). */
|
|
332
|
-
readonly hidden: number;
|
|
333
|
-
/** Icon identifier, or null if no icon. */
|
|
334
|
-
readonly icon: string | null;
|
|
335
|
-
/** Unix timestamp (seconds) when unlocked, or null if not yet unlocked. */
|
|
336
|
-
readonly unlocked_at: number | null;
|
|
337
|
-
}
|
|
321
|
+
// (moved to game-types.ts; re-exported for backwards compatibility)
|
|
338
322
|
|
|
339
323
|
// ─── Sessions Memory Graph (S39) ─────────────────────────────────────────
|
|
340
|
-
|
|
341
|
-
/**
|
|
342
|
-
* A single active session in the GET /api/sessions response. Represents a
|
|
343
|
-
* live pi process with its latest token usage and heartbeat.
|
|
344
|
-
*/
|
|
345
|
-
export interface ActiveSession {
|
|
346
|
-
/** OS process ID of the pi process. */
|
|
347
|
-
readonly pid: number;
|
|
348
|
-
/** Session identifier (normalized). */
|
|
349
|
-
readonly sessionId: string;
|
|
350
|
-
/** Absolute path to the repo root, or null if not in a git repo. */
|
|
351
|
-
readonly repoRoot: string | null;
|
|
352
|
-
/** Display name (repo basename or state dir basename). */
|
|
353
|
-
readonly displayName: string;
|
|
354
|
-
/** Model name, or null if not captured. Available from repo_registry join. */
|
|
355
|
-
readonly model: string | null;
|
|
356
|
-
/** Latest context token count, or null if no sample yet. */
|
|
357
|
-
readonly tokens: number | null;
|
|
358
|
-
/** Latest context pressure percentage (0–100), or null. */
|
|
359
|
-
readonly percent: number | null;
|
|
360
|
-
/** Context window size in tokens. */
|
|
361
|
-
readonly ctxWindow: number;
|
|
362
|
-
/** Unix timestamp (ms) of the last heartbeat. */
|
|
363
|
-
readonly lastSeen: number;
|
|
364
|
-
/** State directory of the session. */
|
|
365
|
-
readonly stateDir: string | null;
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
/**
|
|
369
|
-
* Response for GET /api/sessions. Lists active sessions with their latest
|
|
370
|
-
* token usage after pruning stale entries.
|
|
371
|
-
*/
|
|
372
|
-
export interface SessionsResponse {
|
|
373
|
-
/** ISO timestamp when the response was generated. */
|
|
374
|
-
readonly updatedAt: string;
|
|
375
|
-
/** Number of stale sessions pruned during this request. */
|
|
376
|
-
readonly pruned: number;
|
|
377
|
-
/** Array of active sessions, sorted by lastSeen descending. */
|
|
378
|
-
readonly sessions: ActiveSession[];
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
/** A single time-series data point for a session. */
|
|
382
|
-
export interface SessionDataPoint {
|
|
383
|
-
/** Unix timestamp (ms). */
|
|
384
|
-
readonly ts: number;
|
|
385
|
-
/** Token count at this sample. */
|
|
386
|
-
readonly tokens: number;
|
|
387
|
-
/** Context pressure percentage (0–100). */
|
|
388
|
-
readonly percent: number;
|
|
389
|
-
}
|
|
390
|
-
|
|
391
|
-
/** A recharts-ready per-session series with a stable color. */
|
|
392
|
-
export interface SessionSeries {
|
|
393
|
-
/** Session identifier. */
|
|
394
|
-
readonly sessionId: string;
|
|
395
|
-
/** Short display label for the legend. */
|
|
396
|
-
readonly label: string;
|
|
397
|
-
/** Stable hex color string (e.g. "#60a5fa"). */
|
|
398
|
-
readonly color: string;
|
|
399
|
-
/** Data points ordered by timestamp ascending. */
|
|
400
|
-
readonly data: SessionDataPoint[];
|
|
401
|
-
}
|
|
402
|
-
|
|
403
|
-
/**
|
|
404
|
-
* Query parameters for GET /api/sessions/timeseries. The `minutes` parameter
|
|
405
|
-
* controls the rolling window size.
|
|
406
|
-
*/
|
|
407
|
-
export interface SessionTimeseriesQuery {
|
|
408
|
-
/** Rolling window size in minutes (default: 30, clamped to [1, 1440]). */
|
|
409
|
-
readonly minutes?: number;
|
|
410
|
-
}
|
|
411
|
-
|
|
412
|
-
/**
|
|
413
|
-
* Response for GET /api/sessions/timeseries. Returns recharts-ready stacked
|
|
414
|
-
* per-session series + a totals array.
|
|
415
|
-
*/
|
|
416
|
-
export interface SessionTimeseriesResponse {
|
|
417
|
-
/** ISO timestamp when the response was generated. */
|
|
418
|
-
readonly updatedAt: string;
|
|
419
|
-
/** Rolling window size in minutes. */
|
|
420
|
-
readonly windowMinutes: number;
|
|
421
|
-
/** Per-session series with stable colors. */
|
|
422
|
-
readonly series: SessionSeries[];
|
|
423
|
-
/** Totals (sum of all sessions) per timestamp. */
|
|
424
|
-
readonly totals: { readonly ts: number; readonly tokens: number }[];
|
|
425
|
-
}
|
|
324
|
+
// (moved to game-types.ts; re-exported for backwards compatibility)
|
|
426
325
|
|
|
427
326
|
// ─── Game State Patch (PUT request body) ────────────────────────────────────
|
|
428
|
-
|
|
429
|
-
/**
|
|
430
|
-
* Request body for PUT /api/game-state. A partial patch of the game config.
|
|
431
|
-
* Unknown keys are ignored; invalid values result in a 400 response.
|
|
432
|
-
*/
|
|
433
|
-
export type GameStatePatch = Partial<GameConfig>;
|
|
327
|
+
// (moved to game-types.ts; re-exported for backwards compatibility)
|
|
434
328
|
|
|
435
329
|
// ─── SSE Endpoint Definition ────────────────────────────────────────────────
|
|
330
|
+
// (moved to game-types.ts; re-exported for backwards compatibility)
|
|
436
331
|
|
|
437
|
-
/**
|
|
438
|
-
* Endpoint definition for SSE (Server-Sent Events) streaming endpoints.
|
|
439
|
-
* Unlike standard REST endpoints, the response is a continuous `text/event-stream`
|
|
440
|
-
* with `data:` frames containing JSON-serialized event objects.
|
|
441
|
-
* @template Data - The SSE event data type streamed by this endpoint.
|
|
442
|
-
*/
|
|
443
|
-
export interface SseEndpointDef<Data extends SseEvent = SseEvent> {
|
|
444
|
-
/** Discriminator: always 'sse' for streaming endpoints. */
|
|
445
|
-
readonly type: 'sse';
|
|
446
|
-
/** HTTP method (always 'GET' for SSE). */
|
|
447
|
-
readonly method: 'GET';
|
|
448
|
-
/** URL path of the endpoint. */
|
|
449
|
-
readonly path: string;
|
|
450
|
-
/** Human-readable description of the endpoint. */
|
|
451
|
-
readonly description: string;
|
|
452
|
-
/** SSE event name sent with each data frame. */
|
|
453
|
-
readonly event: string;
|
|
454
|
-
/** The SSE event data type streamed by this endpoint. */
|
|
455
|
-
readonly dataType?: Data;
|
|
456
|
-
}
|
|
457
332
|
|
|
458
333
|
// ─── ENDPOINTS Registry ─────────────────────────────────────────────────────
|
|
459
334
|
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* api-contracts/game-types.ts — Split-out dashboard API types.
|
|
3
|
+
*
|
|
4
|
+
* Contains the “Game Score & Achievement Types” and “Sessions Memory Graph”
|
|
5
|
+
* related type definitions that previously lived in endpoints.ts.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { GameConfig } from './game.js';
|
|
9
|
+
import type { SseEvent } from './index.js';
|
|
10
|
+
|
|
11
|
+
// ─── Game Score & Achievement Types ─────────────────────────────────────────
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* A leaderboard row for GET /api/game-scores. One row per repo per metric.
|
|
15
|
+
*/
|
|
16
|
+
export interface GameScoreRow {
|
|
17
|
+
/** Absolute path to the repo root. */
|
|
18
|
+
readonly repo_root: string;
|
|
19
|
+
/** Score value (interpretation depends on the metric). */
|
|
20
|
+
readonly value: number;
|
|
21
|
+
/** Unix timestamp (milliseconds) when the score was recorded. */
|
|
22
|
+
readonly ts: number;
|
|
23
|
+
/** Optional metadata associated with the score event. */
|
|
24
|
+
readonly meta: unknown;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Query parameters for GET /api/game-scores.
|
|
29
|
+
*/
|
|
30
|
+
export interface GameScoresQuery {
|
|
31
|
+
/** Leaderboard metric (must be one of: cache, dedupe, turns, repos, mega_cache). Optional. */
|
|
32
|
+
readonly metric?: string;
|
|
33
|
+
/** Maximum number of rows to return (default: 10, clamped to [1, 100]). Optional. */
|
|
34
|
+
readonly limit?: number;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* An achievement row for GET /api/achievements. One row per seeded achievement.
|
|
39
|
+
*/
|
|
40
|
+
export interface AchievementRow {
|
|
41
|
+
/** Achievement identifier. */
|
|
42
|
+
readonly id: string;
|
|
43
|
+
/** Display title of the achievement. */
|
|
44
|
+
readonly title: string;
|
|
45
|
+
/** Description of the unlock condition. */
|
|
46
|
+
readonly description: string;
|
|
47
|
+
/** Whether the achievement is hidden (1 = hidden, 0 = visible). */
|
|
48
|
+
readonly hidden: number;
|
|
49
|
+
/** Icon identifier, or null if no icon. */
|
|
50
|
+
readonly icon: string | null;
|
|
51
|
+
/** Unix timestamp (seconds) when unlocked, or null if not yet unlocked. */
|
|
52
|
+
readonly unlocked_at: number | null;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// ─── Sessions Memory Graph (S39) ─────────────────────────────────────────
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* A single active session in the GET /api/sessions response. Represents a
|
|
59
|
+
* live pi process with its latest token usage and heartbeat.
|
|
60
|
+
*/
|
|
61
|
+
export interface ActiveSession {
|
|
62
|
+
/** OS process ID of the pi process. */
|
|
63
|
+
readonly pid: number;
|
|
64
|
+
/** Session identifier (normalized). */
|
|
65
|
+
readonly sessionId: string;
|
|
66
|
+
/** Absolute path to the repo root, or null if not in a git repo. */
|
|
67
|
+
readonly repoRoot: string | null;
|
|
68
|
+
/** Display name (repo basename or state dir basename). */
|
|
69
|
+
readonly displayName: string;
|
|
70
|
+
/** Model name, or null if not captured. Available from repo_registry join. */
|
|
71
|
+
readonly model: string | null;
|
|
72
|
+
/** Latest context token count, or null if no sample yet. */
|
|
73
|
+
readonly tokens: number | null;
|
|
74
|
+
/** Latest context pressure percentage (0–100), or null. */
|
|
75
|
+
readonly percent: number | null;
|
|
76
|
+
/** Context window size in tokens. */
|
|
77
|
+
readonly ctxWindow: number;
|
|
78
|
+
/** Unix timestamp (ms) of the last heartbeat. */
|
|
79
|
+
readonly lastSeen: number;
|
|
80
|
+
/** State directory of the session. */
|
|
81
|
+
readonly stateDir: string | null;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Response for GET /api/sessions. Lists active sessions with their latest
|
|
86
|
+
* token usage after pruning stale entries.
|
|
87
|
+
*/
|
|
88
|
+
export interface SessionsResponse {
|
|
89
|
+
/** ISO timestamp when the response was generated. */
|
|
90
|
+
readonly updatedAt: string;
|
|
91
|
+
/** Number of stale sessions pruned during this request. */
|
|
92
|
+
readonly pruned: number;
|
|
93
|
+
/** Array of active sessions, sorted by lastSeen descending. */
|
|
94
|
+
readonly sessions: ActiveSession[];
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/** A single time-series data point for a session. */
|
|
98
|
+
export interface SessionDataPoint {
|
|
99
|
+
/** Unix timestamp (ms). */
|
|
100
|
+
readonly ts: number;
|
|
101
|
+
/** Token count at this sample. */
|
|
102
|
+
readonly tokens: number;
|
|
103
|
+
/** Context pressure percentage (0–100). */
|
|
104
|
+
readonly percent: number;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/** A recharts-ready per-session series with a stable color. */
|
|
108
|
+
export interface SessionSeries {
|
|
109
|
+
/** Session identifier. */
|
|
110
|
+
readonly sessionId: string;
|
|
111
|
+
/** Short display label for the legend. */
|
|
112
|
+
readonly label: string;
|
|
113
|
+
/** Stable hex color string (e.g. "#60a5fa"). */
|
|
114
|
+
readonly color: string;
|
|
115
|
+
/** Data points ordered by timestamp ascending. */
|
|
116
|
+
readonly data: SessionDataPoint[];
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Query parameters for GET /api/sessions/timeseries. The `minutes` parameter
|
|
121
|
+
* controls the rolling window size.
|
|
122
|
+
*/
|
|
123
|
+
export interface SessionTimeseriesQuery {
|
|
124
|
+
/** Rolling window size in minutes (default: 30, clamped to [1, 1440]). */
|
|
125
|
+
readonly minutes?: number;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Response for GET /api/sessions/timeseries. Returns recharts-ready stacked
|
|
130
|
+
* per-session series + a totals array.
|
|
131
|
+
*/
|
|
132
|
+
export interface SessionTimeseriesResponse {
|
|
133
|
+
/** ISO timestamp when the response was generated. */
|
|
134
|
+
readonly updatedAt: string;
|
|
135
|
+
/** Rolling window size in minutes. */
|
|
136
|
+
readonly windowMinutes: number;
|
|
137
|
+
/** Per-session series with stable colors. */
|
|
138
|
+
readonly series: SessionSeries[];
|
|
139
|
+
/** Totals (sum of all sessions) per timestamp. */
|
|
140
|
+
readonly totals: { readonly ts: number; readonly tokens: number }[];
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// ─── Game State Patch (PUT request body) ────────────────────────────────────
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Request body for PUT /api/game-state. A partial patch of the game config.
|
|
147
|
+
* Unknown keys are ignored; invalid values result in a 400 response.
|
|
148
|
+
*/
|
|
149
|
+
export type GameStatePatch = Partial<GameConfig>;
|
|
150
|
+
|
|
151
|
+
// ─── SSE Endpoint Definition ────────────────────────────────────────────────
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Endpoint definition for SSE (Server-Sent Events) streaming endpoints.
|
|
155
|
+
* Unlike standard REST endpoints, the response is a continuous `text/event-stream`
|
|
156
|
+
* with `data:` frames containing JSON-serialized event objects.
|
|
157
|
+
* @template Data - The SSE event data type streamed by this endpoint.
|
|
158
|
+
*/
|
|
159
|
+
export interface SseEndpointDef<Data extends SseEvent = SseEvent> {
|
|
160
|
+
/** Discriminator: always 'sse' for streaming endpoints. */
|
|
161
|
+
readonly type: 'sse';
|
|
162
|
+
/** HTTP method (always 'GET' for SSE). */
|
|
163
|
+
readonly method: 'GET';
|
|
164
|
+
/** URL path of the endpoint. */
|
|
165
|
+
readonly path: string;
|
|
166
|
+
/** Human-readable description of the endpoint. */
|
|
167
|
+
readonly description: string;
|
|
168
|
+
/** SSE event name sent with each data frame. */
|
|
169
|
+
readonly event: string;
|
|
170
|
+
/** The SSE event data type streamed by this endpoint. */
|
|
171
|
+
readonly dataType?: Data;
|
|
172
|
+
}
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
# mega-runtime — Decomposition Tracker
|
|
2
|
+
|
|
3
|
+
This file tracks the progressive decomposition of the original `mega-runtime.ts`
|
|
4
|
+
monolith (2 600+ lines) into focused single-responsibility modules.
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Current State (raptor-promotion branch)
|
|
9
|
+
|
|
10
|
+
### Completed — Phase 1: Extract pure helpers
|
|
11
|
+
|
|
12
|
+
The original `state.ts` (later `mega-runtime.ts`) has been split into:
|
|
13
|
+
|
|
14
|
+
| File | Lines | Responsibility |
|
|
15
|
+
|---|---|---|
|
|
16
|
+
| `state.ts` | 8 | **Re-export placeholder** — re-exports `MegaRuntime` from `runtime.ts` so all existing imports keep working |
|
|
17
|
+
| `runtime.ts` | ~522 | **MegaRuntime class** — the orchestrator (constructor, dispose, bindRepo, 1-line delegate methods) |
|
|
18
|
+
| `runtime-snapshot.ts` | ~289 | `snapshotImpl(ctx, ctxPi)` — the full `snapshot()` body (vector stats, threshold/armed/ready, drift, widget, dashboard.json write) |
|
|
19
|
+
| `runtime-helpers.ts` | ~119 | Extracted private helpers: `materialSigImpl`, `embedderNameImpl`, `driftStatusImpl`, `getTurnLevelImpl` + `RuntimeHelpersContext` |
|
|
20
|
+
| `snapshot.ts` | ~229 | `computeMegaSnapshot()` — pure function, no class state |
|
|
21
|
+
| `dashboard-snapshot.ts` | ~173 | `computeDashboardSnapshot()` — dashboard-specific snapshot variant |
|
|
22
|
+
| `widget.ts` | ~172 | **Thin barrel** — owns `buildWidgetLines()` + re-exports from `widget-ansi.ts`/`widget-types.ts` |
|
|
23
|
+
| `widget-ansi.ts` | ~218 | ANSI palette (`C`), `PULSE`, panel layout helpers, ambient border-effect helpers, token/time formatters |
|
|
24
|
+
| `widget-types.ts` | ~81 | `TickerEntry` + `WidgetData` interfaces (pure types, zero imports) |
|
|
25
|
+
| `effects.ts` | ~129 | Effect/flare helpers: `armMegaCacheFlareImpl`, `armAchievementFlareImpl`, `setEffectImpl`, `pushTickerImpl` |
|
|
26
|
+
| `game-state.ts` | ~125 | Game state cache: `ensureGameStateWatcherImpl`, `bumpGameStateImpl`, `refreshWidgetGameStateImpl` |
|
|
27
|
+
| `capture-model.ts` | ~101 | Model capture: `captureModelImpl` |
|
|
28
|
+
| `bind-repo.ts` | ~81 | Repo binding: `resolveRepoId`, `resolveMemoRoot` |
|
|
29
|
+
| `perf.ts` | ~60 | Perf sample helpers: `recordPerfSample`, `ensurePerfIntervalImpl`, `disposePerf` |
|
|
30
|
+
| `helpers.ts` | ~73 | Shared constants/types (`MEGA_HOME`, `DEFAULT_CONFIG`, `MegaConfig`, etc.) |
|
|
31
|
+
| `query.ts` | ~29 | Query helpers (`recentUserQuery`) |
|
|
32
|
+
|
|
33
|
+
All tests pass (the suite is built and run via `npm test` → `node scripts/run-tests.mjs`).
|
|
34
|
+
|
|
35
|
+
### Completed — Phase 2a: Split `widget.ts` (~422 → 172 + 218 + 81 lines)
|
|
36
|
+
|
|
37
|
+
The original monolithic `widget.ts` has been decomposed into three files with a
|
|
38
|
+
preserved barrel so **no consumer import changed**:
|
|
39
|
+
|
|
40
|
+
| New file | Content | Source of the code |
|
|
41
|
+
|---|---|---|
|
|
42
|
+
| `widget-types.ts` | `TickerEntry`, `WidgetData` interfaces | moved verbatim from the old `widget.ts` |
|
|
43
|
+
| `widget-ansi.ts` | `C` palette, `PULSE`, `DEFAULT_PANEL_BG`, `panelBgFor`, `themeAnsi`, `sgrReset`, `wrapLine`, `panelLine`, `panelBar`, `EFFECT_BASE`, `effectBorderSgr`, `effectBar`, `fmtTokens`, `ramp`, `sinceCompactStr` | moved verbatim; the previously-private helpers are now `export`ed |
|
|
44
|
+
| `widget.ts` (slimmed) | `buildWidgetLines()` + `export { … } from "./widget-ansi.js"` + `export type { … } from "./widget-types.js"` | the render function stays here; barrel re-exports keep `./widget.js` resolving `C`, `TickerEntry`, `WidgetData`, `buildWidgetLines` |
|
|
45
|
+
|
|
46
|
+
**Compatibility:** the only names the old `widget.ts` exported were `C`,
|
|
47
|
+
`TickerEntry`, `WidgetData`, `buildWidgetLines`; every other helper was a
|
|
48
|
+
non-exported `const`/`function`. The new `widget.ts` re-exports **all** of them
|
|
49
|
+
(additive — more public surface, no removed names), and there is **zero name
|
|
50
|
+
collision** with the sibling barrels (`helpers.ts`/`state.ts`/`query.ts`), so the
|
|
51
|
+
`extensions/mega-runtime.ts` `export * from "./mega-runtime/widget.js"` keeps
|
|
52
|
+
resolving identically. Verified: `tsc --noEmit` passes; `widget.test.ts`
|
|
53
|
+
(S31 matrix + ambient-effect + footer-stability + achievement-flare) green.
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## Completed — Phase 2b: Extract `runtime.ts` private helpers (~783 → ~754 lines + 120)
|
|
58
|
+
|
|
59
|
+
The four pure/instance helpers were extracted from the `MegaRuntime` class into
|
|
60
|
+
`runtime-helpers.ts` following the established context-interface + free-function
|
|
61
|
+
+ thin-delegate pattern (same as `effects.ts` / `game-state.ts` / `capture-model.ts`
|
|
62
|
+
/ `bind-repo.ts` / `perf.ts`).
|
|
63
|
+
|
|
64
|
+
| New file | Content | Source of the code |
|
|
65
|
+
|---|---|---|
|
|
66
|
+
| `runtime-helpers.ts` | `RuntimeHelpersContext` interface + `materialSigImpl(ctx)`, `embedderNameImpl()`, `driftStatusImpl(ctx)`, `getTurnLevelImpl(ctx)` | moved verbatim from the old private methods |
|
|
67
|
+
| `runtime.ts` (slightly slimmer) | the four methods are now 1-line delegates (`return *Impl(this)`); `driftCache` is now public so `MegaRuntime` satisfies `RuntimeHelpersContext` structurally | — |
|
|
68
|
+
|
|
69
|
+
**What moved:**
|
|
70
|
+
- `materialSig()` → `materialSigImpl(ctx)` — pure over all-public fields.
|
|
71
|
+
- `embedderName()` → `embedderNameImpl()` — trivially pure (reads `process.env`).
|
|
72
|
+
- `driftStatus()` → `driftStatusImpl(ctx)` — required `driftCache` to become
|
|
73
|
+
public (one-token change; internal state, not an API contract). The
|
|
74
|
+
`detectCrossRepoDrift` import moved into `runtime-helpers.ts` (was only used
|
|
75
|
+
there) and was dropped from `runtime.ts`.
|
|
76
|
+
- `getTurnLevel()` → `getTurnLevelImpl(ctx)` — the `turnLevel` import moved into
|
|
77
|
+
`runtime-helpers.ts` and was dropped from `runtime.ts`.
|
|
78
|
+
|
|
79
|
+
All call sites (`this.materialSig()`, `this.embedderName()`, `this.driftStatus()`,
|
|
80
|
+
`this.getTurnLevel()`) are unchanged — the thin in-class delegates preserve the
|
|
81
|
+
existing API. Verified: `tsc --noEmit` passes; full suite green.
|
|
82
|
+
|
|
83
|
+
## Completed — Phase 2c: Extract `snapshot()` body to `runtime-snapshot.ts` (~783 → ~522 lines + 289)
|
|
84
|
+
|
|
85
|
+
The `snapshot()` method — the single largest method on `MegaRuntime` — was
|
|
86
|
+
extracted into `runtime-snapshot.ts` as `snapshotImpl(self, ctx?)`, following
|
|
87
|
+
the same context-interface + free-function + thin-delegate pattern.
|
|
88
|
+
|
|
89
|
+
| New file | Content | Source of the code |
|
|
90
|
+
|---|---|---|
|
|
91
|
+
| `runtime-snapshot.ts` | `RuntimeSnapshotContext` interface + `snapshotImpl(self, ctx?)` — the full snapshot body: material-sig gate, vector stats, effective threshold/armed/ready, drift status, `computeMegaSnapshot` → `widgetData` + `renderWidget`, `writeFileSync(dashboard.json)`, perf sample, ticker push, flare arming | moved verbatim from the old `snapshot()` method |
|
|
92
|
+
| `runtime.ts` (slimmed) | `snapshot(ctx?)` is now a 1-line delegate (`return snapshotImpl(this, ctx)`); `lastSnapshotSig` is now public so `MegaRuntime` satisfies `RuntimeSnapshotContext` structurally | — |
|
|
93
|
+
|
|
94
|
+
**What moved:**
|
|
95
|
+
- The `computeMegaSnapshot`, `buildDashboardSnapshot`, `detectCrossRepoDrift`,
|
|
96
|
+
`vectorStats`/`vectorRepoStats`/`vectorDataInvariant`, `recordPerfSample`,
|
|
97
|
+
`recordSessionHeartbeat`, `appendTokenSample`, and `latestModelSnapshot`
|
|
98
|
+
imports moved into `runtime-snapshot.ts` (none are used by `runtime.ts`
|
|
99
|
+
anymore) — `runtime.ts` only imports `VectorStore` (type) now.
|
|
100
|
+
- `lastSnapshotSig` became public (one-token change; internal state, not an
|
|
101
|
+
API contract) so `MegaRuntime` satisfies `RuntimeSnapshotContext`.
|
|
102
|
+
|
|
103
|
+
All call sites (the `before_agent_start`/`context`/`compact` handlers that
|
|
104
|
+
call `this.snapshot(ctx)`) are unchanged — the thin in-class delegate
|
|
105
|
+
preserves the existing API. Verified: `tsc --noEmit` passes; full suite
|
|
106
|
+
green (649 tests across 61 files).
|
|
107
|
+
|
|
108
|
+
## Completed — Phase 2d: Maximal split of `runtime.ts` (~522 → ~437 lines, zero method bodies)
|
|
109
|
+
|
|
110
|
+
The maximal split moves **every** remaining method body in `runtime.ts` into
|
|
111
|
+
its own single-responsibility module, leaving the class as field declarations,
|
|
112
|
+
the constructor, and 1-line delegates only. This completes the decomposition
|
|
113
|
+
charter: no logic lives in the orchestrator file anymore.
|
|
114
|
+
|
|
115
|
+
| New file | Content | Source of the code |
|
|
116
|
+
|---|---|---|
|
|
117
|
+
| `pressure-getters.ts` | `PressureContext` + `pressureImpl` / `effectiveThresholdImpl` / `pressureBandImpl` | moved verbatim from the `pressure` / `effectiveThreshold` / `pressureBand` getters |
|
|
118
|
+
| `reset-runtime.ts` | `ResetRuntimeContext` + `resetRuntimeImpl(self, sessionId)` | moved verbatim from `resetRuntime()` |
|
|
119
|
+
| `append-event.ts` | `AppendEventContext` + `appendEventImpl(self, event, fields)` | moved verbatim from `appendEvent()` |
|
|
120
|
+
| `get-state-dir.ts` | `GetStateDirContext` + `getStateDirImpl(self)` | moved verbatim from `getStateDir()` |
|
|
121
|
+
| `render-widget.ts` | `RenderWidgetContext` + `renderWidgetImpl(self, ctx)` | moved verbatim from `renderWidget()` |
|
|
122
|
+
| `status.ts` | `SetStatusContext` + `setStatusImpl(self, ctx, text)` | moved verbatim from `setStatus()` |
|
|
123
|
+
| `engine-view.ts` | `engineViewImpl(messages)` | moved verbatim from `engineView()` |
|
|
124
|
+
| `game-state.ts` (+append) | `DisposeRuntimeContext` + `disposeRuntimeImpl(self)` | moved verbatim from `dispose()` (game-state.ts already owns the watcher context, so this lands there alongside `ensureGameStateWatcherImpl`) |
|
|
125
|
+
|
|
126
|
+
**What moved / changed:**
|
|
127
|
+
- `runtime.ts` import block rewritten: dropped `appendFileSync`/`mkdirSync`,
|
|
128
|
+
`STATUS_KEY`/`WIDGET_KEY`, `buildWidgetLines`, and
|
|
129
|
+
`pressureRatio`/`pressureFromPct`/`pressureBand`/`effectiveThresholdTokens`
|
|
130
|
+
(now consumed only in their respective modules); added imports of the 7 new
|
|
131
|
+
`*Impl` functions + `disposeRuntimeImpl`. `toEngineMessages` is kept
|
|
132
|
+
(`engineView`'s return type still references it); `normalizeSessionId` is kept
|
|
133
|
+
(the `rt` field initializer still uses it).
|
|
134
|
+
- The big pressure doc comment moved to `pressure-getters.ts`; `runtime.ts`
|
|
135
|
+
keeps a one-line pointer comment per delegate.
|
|
136
|
+
- `dispose()` delegates to `disposeRuntimeImpl` (in `game-state.ts`), which
|
|
137
|
+
composes `GameStateContext` + `PerfContext` and calls the existing
|
|
138
|
+
`disposePerf` — so `disposePerf` is no longer imported by `runtime.ts`.
|
|
139
|
+
|
|
140
|
+
**Why maximal:** the soft `~500 line` doc-length target (CLAUDE.md §6) applies to
|
|
141
|
+
source files too. `runtime.ts` at 522 lines was the only mega-runtime source
|
|
142
|
+
file over the target; the split brings it to **437 lines** (delegates + fields +
|
|
143
|
+
constructor only), with every new file ≤96 lines. The pattern (context-interface
|
|
144
|
+
+ free-function + thin-delegate) is the same one established in Phase 1
|
|
145
|
+
(`effects.ts`/`game-state.ts`/`capture-model.ts`/`bind-repo.ts`/`perf.ts`) and
|
|
146
|
+
extended in Phase 2b/2c (`runtime-helpers.ts`/`runtime-snapshot.ts`).
|
|
147
|
+
|
|
148
|
+
Verified: `tsc --noEmit` passes; `npm run lint` (tsc + guardrails-scan +
|
|
149
|
+
semantic-scan) green; `npm test` green (678 tests, 61 files, 0 failures);
|
|
150
|
+
`python3 scripts/regression_check.py --all` green; 8-point structural audit
|
|
151
|
+
green (line counts, no logic primitives left, 22 `Impl(this)` delegates, no
|
|
152
|
+
`this.` in new files, each `*Impl` defined exactly once, git scope limited to
|
|
153
|
+
the 2 modified + 7 new files, game-state.ts diff is purely additive, tsc clean).
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
### Deferred — effects wrappers
|
|
157
|
+
|
|
158
|
+
The `armMegaCacheFlare` / `armAchievementFlare` / `setEffect` / `pushTicker`
|
|
159
|
+
methods on `MegaRuntime` are already thin one-line delegates whose bodies live
|
|
160
|
+
in `effects.ts` (`*Impl` functions). They could optionally be collapsed into a
|
|
161
|
+
`runtime-effects.ts` barrel-of-delegates, but this yields little benefit (each
|
|
162
|
+
is already one line) and risks churn. **Deferred** unless `runtime.ts` grows.
|
|
163
|
+
|
|
164
|
+
## Sprint Backlog (prioritised)
|
|
165
|
+
|
|
166
|
+
1. ~~**Split `widget.ts`** — done (Phase 2a).~~
|
|
167
|
+
2. ~~**Split `runtime.ts`** — extract `materialSig`/`embedderName`/`driftStatus`/`getTurnLevel` into `runtime-helpers.ts` — done (Phase 2b).~~
|
|
168
|
+
3. ~~**Extract `snapshot()` body** into `runtime-snapshot.ts` — done (Phase 2c).~~
|
|
169
|
+
4. ~~**Verify `state.ts` re-export** — confirm `state.ts` → `runtime.ts` → final modules chain works (`state.test.ts` uses `createRequire` to load compiled JS) — green after Phase 2b.~~
|
|
170
|
+
5. ~~**Run full test suite** after each split (`npm test`) — green after 2a, 2b, and 2c (649 tests, 61 files, 0 failures).~~
|
|
171
|
+
6. **Final cleanup** — remove the `state.ts` placeholder once all consumers are updated to import `MegaRuntime` directly from `runtime.ts` (low priority; `state.ts` re-export is zero-cost).
|
|
172
|
+
7. **Commit Phase 2** — stage the Phase 2a/2b/2c changes (`runtime-helpers.ts`, `widget-ansi.ts`, `widget-types.ts`, `widget.ts`, `runtime-snapshot.ts`, `runtime.ts`, `DECOMPOSITION.md`) and commit.
|
|
173
|
+
|
|
174
|
+
---
|
|
175
|
+
|
|
176
|
+
## Notes
|
|
177
|
+
|
|
178
|
+
- `state.ts` is intentionally kept as a re-export to avoid a breaking change in `extensions/mega-runtime.ts:18` which imports `MegaRuntime` from `./mega-runtime/state.js`.
|
|
179
|
+
- `state.test.ts` and `widget.test.ts` exist alongside the source — they use `createRequire` to load compiled JS, not direct TS imports, so they exercise the built `dist/` output (build before testing).
|
|
180
|
+
- The `extensions/mega-runtime.ts` barrel does `export * from "./mega-runtime/widget.js"`; the widget split keeps that resolving because `widget.ts` re-exports the same public surface.
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# mega-runtime
|
|
2
|
+
|
|
3
|
+
Runtime state and widget rendering for the mega-compact dashboard.
|
|
4
|
+
|
|
5
|
+
## Module structure
|
|
6
|
+
|
|
7
|
+
`MegaRuntime` (in `runtime.ts`) is a delegates-only orchestrator: field
|
|
8
|
+
declarations, the constructor, and 1-line delegates to `*Impl` free functions in
|
|
9
|
+
single-responsibility modules. Keep it that way — when adding logic, put the body
|
|
10
|
+
in a new `*.ts` module and add a thin delegate, rather than growing `runtime.ts`
|
|
11
|
+
(see `DECOMPOSITION.md` + the "no large files" rule in `CLAUDE.md` §6).
|
|
12
|
+
|
|
13
|
+
| Module | Responsibility |
|
|
14
|
+
|---|---|
|
|
15
|
+
| `state.ts` | Barrel re-export of `MegaRuntime` (backwards-compat import path) |
|
|
16
|
+
| `runtime.ts` | `MegaRuntime` class — delegates-only orchestrator (fields + constructor + 1-line delegates) |
|
|
17
|
+
| `runtime-snapshot.ts` | `snapshotImpl()` — the full `snapshot()` body (dashboard write + widget-data compute + gate) |
|
|
18
|
+
| `runtime-helpers.ts` | `materialSigImpl` / `embedderNameImpl` / `driftStatusImpl` / `getTurnLevelImpl` + `RuntimeHelpersContext` |
|
|
19
|
+
| `pressure-getters.ts` | `pressureImpl` / `effectiveThresholdImpl` / `pressureBandImpl` (the pressure accessors) |
|
|
20
|
+
| `reset-runtime.ts` | `resetRuntimeImpl()` — per-session state reset |
|
|
21
|
+
| `append-event.ts` | `appendEventImpl()` — structured events.log sink |
|
|
22
|
+
| `get-state-dir.ts` | `getStateDirImpl()` — bound repo state dir (S21) |
|
|
23
|
+
| `render-widget.ts` | `renderWidgetImpl()` — width-aware above-editor widget factory |
|
|
24
|
+
| `status.ts` | `setStatusImpl()` — status-key text mirrored to pi's status line |
|
|
25
|
+
| `engine-view.ts` | `engineViewImpl()` — pi→engine message adapter passthrough |
|
|
26
|
+
| `snapshot.ts` | `computeMegaSnapshot()` pure function |
|
|
27
|
+
| `dashboard-snapshot.ts` | `computeDashboardSnapshot()` |
|
|
28
|
+
| `widget.ts` | Barrel — `buildWidgetLines()` + re-exports from `widget-ansi.ts` / `widget-types.ts` |
|
|
29
|
+
| `widget-ansi.ts` | ANSI palette (`C`), `PULSE`, panel layout + border-effect helpers, token/time formatters |
|
|
30
|
+
| `widget-types.ts` | `TickerEntry` + `WidgetData` interfaces (pure types) |
|
|
31
|
+
| `effects.ts` | Effect/flare helpers (`setEffectImpl`, `armMegaCacheFlareImpl`, etc.) |
|
|
32
|
+
| `game-state.ts` | Game-state cache + watcher (`ensureGameStateWatcherImpl`, `bumpGameStateImpl`, `disposeRuntimeImpl`) |
|
|
33
|
+
| `capture-model.ts` | Model capture (`captureModelImpl`) |
|
|
34
|
+
| `bind-repo.ts` | Repo binding utilities (`bindRepoImpl`) |
|
|
35
|
+
| `perf.ts` | Perf sample recording + interval (`ensurePerfIntervalImpl`, `disposePerf`) |
|
|
36
|
+
| `helpers.ts` | Shared constants/types (`SessionRuntime`, `STATUS_KEY`, `WIDGET_KEY`, …) |
|
|
37
|
+
| `query.ts` | Query helpers (`recentUserQuery`) |
|
|
38
|
+
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* append-event.ts — extracted `MegaRuntime.appendEvent()`: the structured
|
|
3
|
+
* events.log diagnostics sink. Same context-interface + free-function +
|
|
4
|
+
* thin-delegate pattern as runtime-helpers.ts / effects.ts / game-state.ts.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { join } from "node:path";
|
|
8
|
+
import { appendFileSync, mkdirSync } from "node:fs";
|
|
9
|
+
|
|
10
|
+
// ---------------------------------------------------------------------- types
|
|
11
|
+
|
|
12
|
+
/** The slice of `MegaRuntime` appendEvent reads (the bound repo's state dir). */
|
|
13
|
+
export interface AppendEventContext {
|
|
14
|
+
readonly currentStateDir: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// ---------------------------------------------------------------- appendEvent
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Append a structured line to the repo's events.log — the always-on
|
|
21
|
+
* diagnostics sink the dashboard live-streams. Unlike the runtime logger
|
|
22
|
+
* (gated by config.debug), this fires in production, so capture failures
|
|
23
|
+
* surface during a real capture even with debugging off. Best-effort +
|
|
24
|
+
* non-fatal.
|
|
25
|
+
*/
|
|
26
|
+
export function appendEventImpl(
|
|
27
|
+
self: AppendEventContext,
|
|
28
|
+
event: string,
|
|
29
|
+
fields: Record<string, unknown>,
|
|
30
|
+
): void {
|
|
31
|
+
try {
|
|
32
|
+
mkdirSync(self.currentStateDir, { recursive: true });
|
|
33
|
+
appendFileSync(
|
|
34
|
+
join(self.currentStateDir, "events.log"),
|
|
35
|
+
JSON.stringify({ ts: Date.now(), event, ...fields }) + "\n",
|
|
36
|
+
);
|
|
37
|
+
} catch {
|
|
38
|
+
/* non-fatal */
|
|
39
|
+
}
|
|
40
|
+
}
|