pi-mega-compact 0.8.6 → 0.8.8
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/html.js +46 -1
- package/dist/extensions/dashboard-server/perf-server.test.js +80 -0
- package/dist/extensions/dashboard-server/server.js +87 -0
- package/dist/extensions/mega-cache-replay.test.js +189 -0
- package/dist/extensions/mega-dashboard.js +9 -0
- package/dist/extensions/mega-events/context-handler.js +17 -2
- package/dist/extensions/mega-events/perf-handler.js +71 -0
- package/dist/extensions/mega-events/register.js +2 -0
- package/dist/extensions/mega-events.js +1 -0
- package/dist/extensions/mega-runtime/state.js +59 -1
- package/dist/src/store/sqlite/perf-samples.js +81 -0
- package/dist/src/store/sqlite/perf-samples.test.js +54 -0
- package/dist/src/store/sqlite/schema.js +14 -0
- package/dist/src/store/sqlite.js +1 -0
- package/extensions/dashboard-server/html.ts +46 -1
- package/extensions/dashboard-server/perf-server.test.ts +101 -0
- package/extensions/dashboard-server/server.ts +79 -0
- package/extensions/mega-cache-replay.test.ts +211 -0
- package/extensions/mega-dashboard.ts +17 -0
- package/extensions/mega-events/context-handler.ts +18 -2
- package/extensions/mega-events/perf-handler.ts +113 -0
- package/extensions/mega-events/register.ts +2 -0
- package/extensions/mega-events.ts +1 -0
- package/extensions/mega-runtime/state.ts +57 -0
- package/package.json +1 -1
- package/src/store/sqlite/perf-samples.test.ts +65 -0
- package/src/store/sqlite/perf-samples.ts +125 -0
- package/src/store/sqlite/schema.ts +14 -0
- package/src/store/sqlite.ts +1 -0
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* perf-samples.ts — `perf_samples` table accessors (v0.8.8 Perf dashboard).
|
|
3
|
+
*
|
|
4
|
+
* Append-only local instrumentation store for the dashboard's Perf tab: model
|
|
5
|
+
* endpoint latency, TPS, cache hit %, CPU/mem, and the snapshot() recompute /
|
|
6
|
+
* disk-write cost. One row per sample; the dashboard server reads a rolling
|
|
7
|
+
* window and derives p50/p95 + latest values.
|
|
8
|
+
*
|
|
9
|
+
* PREVENT-PI-004: local SQLite only, zero network.
|
|
10
|
+
* PREVENT-002: all SQL parameterized (? placeholders). The optional `kind`
|
|
11
|
+
* filter is bound as a parameter (never string-concatenated); the only
|
|
12
|
+
* interpolated fragment is the code-controlled `AND kind = ?` clause toggle,
|
|
13
|
+
* never external input.
|
|
14
|
+
* Pi-agnostic: no pi runtime types (mirrors game-scores.ts / meta.ts).
|
|
15
|
+
*/
|
|
16
|
+
import { getStateDir } from "../../store.js";
|
|
17
|
+
import { openStore } from "./utils.js";
|
|
18
|
+
|
|
19
|
+
/** Sample kinds recorded into perf_samples. */
|
|
20
|
+
export type PerfKind =
|
|
21
|
+
| "turn_latency_ms"
|
|
22
|
+
| "provider_latency_ms"
|
|
23
|
+
| "tps"
|
|
24
|
+
| "cache_hit_pct"
|
|
25
|
+
| "rss_mb"
|
|
26
|
+
| "heap_mb"
|
|
27
|
+
| "cpu_user_ms"
|
|
28
|
+
| "cpu_sys_ms"
|
|
29
|
+
| "db_recompute_ms"
|
|
30
|
+
| "disk_write_ms";
|
|
31
|
+
|
|
32
|
+
/** Allow-list of valid perf sample kinds (mirrors the table's domain). */
|
|
33
|
+
export const PERF_KINDS: readonly PerfKind[] = [
|
|
34
|
+
"turn_latency_ms",
|
|
35
|
+
"provider_latency_ms",
|
|
36
|
+
"tps",
|
|
37
|
+
"cache_hit_pct",
|
|
38
|
+
"rss_mb",
|
|
39
|
+
"heap_mb",
|
|
40
|
+
"cpu_user_ms",
|
|
41
|
+
"cpu_sys_ms",
|
|
42
|
+
"db_recompute_ms",
|
|
43
|
+
"disk_write_ms",
|
|
44
|
+
];
|
|
45
|
+
|
|
46
|
+
/** A single perf sample row (as stored + returned). */
|
|
47
|
+
export interface PerfSampleRow {
|
|
48
|
+
id: number;
|
|
49
|
+
ts: number;
|
|
50
|
+
kind: PerfKind;
|
|
51
|
+
value: number;
|
|
52
|
+
meta: unknown;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function isPerfKind(k: string): k is PerfKind {
|
|
56
|
+
return (PERF_KINDS as readonly string[]).includes(k);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Record one perf sample. `ts` is set to Date.now(). SQL is fully parameterized
|
|
61
|
+
* (PREVENT-002); the kind is validated against the fixed allow-list. Pi-agnostic.
|
|
62
|
+
* Never throws on an unknown kind or non-finite value (silently ignored) so
|
|
63
|
+
* instrumentation can never block the agent; a known kind + finite value always
|
|
64
|
+
* writes.
|
|
65
|
+
*/
|
|
66
|
+
export function recordPerfSample(
|
|
67
|
+
stateDir: string = getStateDir(),
|
|
68
|
+
kind: PerfKind,
|
|
69
|
+
value: number,
|
|
70
|
+
meta?: unknown,
|
|
71
|
+
): void {
|
|
72
|
+
if (!isPerfKind(kind)) return;
|
|
73
|
+
if (!Number.isFinite(value)) return;
|
|
74
|
+
const db = openStore(stateDir);
|
|
75
|
+
db.prepare(
|
|
76
|
+
`INSERT INTO perf_samples (ts, kind, value, meta)
|
|
77
|
+
VALUES (?, ?, ?, ?)`,
|
|
78
|
+
).run(
|
|
79
|
+
Date.now(),
|
|
80
|
+
kind,
|
|
81
|
+
value,
|
|
82
|
+
meta != null ? JSON.stringify(meta) : null,
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Read perf samples since `sinceTs` (epoch ms), optionally filtered by kind.
|
|
88
|
+
* Returns rows ascending by ts. The optional kind filter is bound as a
|
|
89
|
+
* parameter (PREVENT-002). Pi-agnostic. `meta` is parsed defensively (null-safe:
|
|
90
|
+
* PREVENT-001 — assigned to a variable before any property access).
|
|
91
|
+
*/
|
|
92
|
+
export function readPerfSamples(
|
|
93
|
+
stateDir: string = getStateDir(),
|
|
94
|
+
sinceTs: number = 0,
|
|
95
|
+
kind?: PerfKind,
|
|
96
|
+
): PerfSampleRow[] {
|
|
97
|
+
const db = openStore(stateDir);
|
|
98
|
+
const sql = kind
|
|
99
|
+
? `SELECT id, ts, kind, value, meta FROM perf_samples
|
|
100
|
+
WHERE ts >= ? AND kind = ? ORDER BY ts ASC`
|
|
101
|
+
: `SELECT id, ts, kind, value, meta FROM perf_samples
|
|
102
|
+
WHERE ts >= ? ORDER BY ts ASC`;
|
|
103
|
+
const params = kind ? [sinceTs, kind] : [sinceTs];
|
|
104
|
+
const rows = db.prepare(sql).all(...params) as Array<{
|
|
105
|
+
id: number;
|
|
106
|
+
ts: number;
|
|
107
|
+
kind: string;
|
|
108
|
+
value: number;
|
|
109
|
+
meta: string | null;
|
|
110
|
+
}>;
|
|
111
|
+
const out: PerfSampleRow[] = [];
|
|
112
|
+
for (const r of rows) {
|
|
113
|
+
if (!isPerfKind(r.kind)) continue; // defensive: unknown kind row skipped
|
|
114
|
+
let meta: unknown = null;
|
|
115
|
+
if (r.meta != null) {
|
|
116
|
+
try {
|
|
117
|
+
meta = JSON.parse(r.meta);
|
|
118
|
+
} catch {
|
|
119
|
+
meta = null;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
out.push({ id: r.id, ts: r.ts, kind: r.kind, value: r.value, meta });
|
|
123
|
+
}
|
|
124
|
+
return out;
|
|
125
|
+
}
|
|
@@ -267,6 +267,20 @@ export function initSchema(db: DatabaseSync): void {
|
|
|
267
267
|
icon TEXT,
|
|
268
268
|
unlocked_at INTEGER NULL
|
|
269
269
|
) WITHOUT ROWID;
|
|
270
|
+
|
|
271
|
+
-- v0.8.8 Perf dashboard: append-only local instrumentation samples (one row
|
|
272
|
+
-- per turn / provider round-trip / 5s cpu-mem tick / snapshot-recompute).
|
|
273
|
+
-- Drives the dashboard Perf tab. Local SQLite (PREVENT-PI-004); parameterized
|
|
274
|
+
-- accessors in perf-samples.ts (PREVENT-002).
|
|
275
|
+
CREATE TABLE IF NOT EXISTS perf_samples (
|
|
276
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
277
|
+
ts INTEGER NOT NULL,
|
|
278
|
+
kind TEXT NOT NULL,
|
|
279
|
+
value REAL NOT NULL,
|
|
280
|
+
meta TEXT
|
|
281
|
+
);
|
|
282
|
+
CREATE INDEX IF NOT EXISTS idx_perf_samples_ts ON perf_samples(ts);
|
|
283
|
+
CREATE INDEX IF NOT EXISTS idx_perf_samples_kind_ts ON perf_samples(kind, ts);
|
|
270
284
|
`);
|
|
271
285
|
// Idempotent column migrations. `CREATE TABLE IF NOT EXISTS` is a no-op on a
|
|
272
286
|
// pre-existing table, so new columns added to context_chunks after a store was
|
package/src/store/sqlite.ts
CHANGED