pi-mega-compact 0.7.8 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (122) hide show
  1. package/README.md +11 -12
  2. package/dist/extensions/dashboard-server/html.js +1023 -0
  3. package/dist/extensions/dashboard-server/html.test.js +41 -0
  4. package/dist/extensions/dashboard-server/index-reader.js +133 -0
  5. package/dist/extensions/dashboard-server/server.js +530 -0
  6. package/dist/extensions/dashboard-server/server.test.js +120 -0
  7. package/dist/extensions/dashboard-server/snapshot.js +43 -0
  8. package/dist/extensions/dashboard-server/state.js +30 -0
  9. package/dist/extensions/dashboard-server/types.js +5 -0
  10. package/dist/extensions/dashboard-server-s32.test.js +181 -0
  11. package/dist/extensions/dashboard-server.js +7 -1315
  12. package/dist/extensions/mega-commands.js +162 -134
  13. package/dist/extensions/mega-compact.js +3 -0
  14. package/dist/extensions/mega-compact.test.js +90 -21
  15. package/dist/extensions/mega-conflict-cmds.js +5 -1
  16. package/dist/extensions/mega-dashboard-cmds.js +29 -22
  17. package/dist/extensions/mega-db-cmds.js +11 -2
  18. package/dist/extensions/mega-events/agent-handlers.js +222 -0
  19. package/dist/extensions/mega-events/compact-handlers.js +162 -0
  20. package/dist/extensions/mega-events/context-handler.js +249 -0
  21. package/dist/extensions/mega-events/register.js +21 -0
  22. package/dist/extensions/mega-events/session-handlers.js +142 -0
  23. package/dist/extensions/mega-events.js +15 -699
  24. package/dist/extensions/mega-game-cmds.js +106 -0
  25. package/dist/extensions/mega-game-cmds.test.js +113 -0
  26. package/dist/extensions/mega-pipeline/compact.js +324 -0
  27. package/dist/extensions/mega-pipeline/memory-review.js +38 -0
  28. package/dist/extensions/mega-pipeline/recall.js +147 -0
  29. package/dist/extensions/mega-pipeline.js +9 -480
  30. package/dist/extensions/mega-runtime/helpers.js +40 -0
  31. package/dist/extensions/mega-runtime/query.js +29 -0
  32. package/dist/extensions/mega-runtime/state.js +877 -0
  33. package/dist/extensions/mega-runtime/state.test.js +171 -0
  34. package/dist/extensions/mega-runtime/widget.js +270 -0
  35. package/dist/extensions/mega-runtime/widget.test.js +160 -0
  36. package/dist/extensions/mega-runtime.js +15 -947
  37. package/dist/src/config/themes.js +84 -0
  38. package/dist/src/config/themes.test.js +94 -0
  39. package/dist/src/game/scoring.js +105 -0
  40. package/dist/src/game/scoring.test.js +98 -0
  41. package/dist/src/store/sqlite/checkpoints.js +145 -0
  42. package/dist/src/store/sqlite/dedup-mirror.js +64 -0
  43. package/dist/src/store/sqlite/foundation.js +38 -0
  44. package/dist/src/store/sqlite/game-achievements.js +111 -0
  45. package/dist/src/store/sqlite/game-achievements.test.js +67 -0
  46. package/dist/src/store/sqlite/game-scores.js +105 -0
  47. package/dist/src/store/sqlite/game-scores.test.js +106 -0
  48. package/dist/src/store/sqlite/game-state.js +54 -0
  49. package/dist/src/store/sqlite/game-state.test.js +76 -0
  50. package/dist/src/store/sqlite/global-index.js +224 -0
  51. package/dist/src/store/sqlite/maintenance.js +235 -0
  52. package/dist/src/store/sqlite/memories.js +164 -0
  53. package/dist/src/store/sqlite/meta.js +82 -0
  54. package/dist/src/store/sqlite/model-snapshots.js +47 -0
  55. package/dist/src/store/sqlite/raptor.js +57 -0
  56. package/dist/src/store/sqlite/raw-transcript.js +134 -0
  57. package/dist/src/store/sqlite/schema.js +294 -0
  58. package/dist/src/store/sqlite/session-state.js +28 -0
  59. package/dist/src/store/sqlite/stats.js +66 -0
  60. package/dist/src/store/sqlite/utils.js +120 -0
  61. package/dist/src/store/sqlite.js +23 -1607
  62. package/extensions/dashboard-server/html.test.ts +50 -0
  63. package/extensions/dashboard-server/html.ts +1026 -0
  64. package/extensions/dashboard-server/index-reader.ts +130 -0
  65. package/extensions/dashboard-server/server.test.ts +131 -0
  66. package/extensions/dashboard-server/server.ts +505 -0
  67. package/extensions/dashboard-server/snapshot.ts +44 -0
  68. package/extensions/dashboard-server/state.ts +33 -0
  69. package/extensions/dashboard-server/types.ts +134 -0
  70. package/extensions/dashboard-server-s32.test.ts +195 -0
  71. package/extensions/dashboard-server.ts +7 -1431
  72. package/extensions/mega-commands.ts +33 -10
  73. package/extensions/mega-compact.test.ts +198 -43
  74. package/extensions/mega-compact.ts +3 -0
  75. package/extensions/mega-conflict-cmds.ts +6 -2
  76. package/extensions/mega-dashboard-cmds.ts +30 -23
  77. package/extensions/mega-db-cmds.ts +11 -3
  78. package/extensions/mega-events/agent-handlers.ts +262 -0
  79. package/extensions/mega-events/compact-handlers.ts +192 -0
  80. package/extensions/mega-events/context-handler.ts +290 -0
  81. package/extensions/mega-events/register.ts +37 -0
  82. package/extensions/mega-events/session-handlers.ts +165 -0
  83. package/extensions/mega-events.ts +15 -780
  84. package/extensions/mega-game-cmds.test.ts +137 -0
  85. package/extensions/mega-game-cmds.ts +122 -0
  86. package/extensions/mega-pipeline/compact.ts +366 -0
  87. package/extensions/mega-pipeline/memory-review.ts +46 -0
  88. package/extensions/mega-pipeline/recall.ts +165 -0
  89. package/extensions/mega-pipeline.ts +9 -537
  90. package/extensions/mega-runtime/helpers.ts +68 -0
  91. package/extensions/mega-runtime/query.ts +29 -0
  92. package/extensions/mega-runtime/state.test.ts +171 -0
  93. package/extensions/mega-runtime/state.ts +967 -0
  94. package/extensions/mega-runtime/widget.test.ts +185 -0
  95. package/extensions/mega-runtime/widget.ts +359 -0
  96. package/extensions/mega-runtime.ts +15 -1093
  97. package/package.json +4 -3
  98. package/src/config/themes.test.ts +116 -0
  99. package/src/config/themes.ts +124 -0
  100. package/src/game/scoring.test.ts +103 -0
  101. package/src/game/scoring.ts +158 -0
  102. package/src/store/sqlite/checkpoints.ts +204 -0
  103. package/src/store/sqlite/dedup-mirror.ts +114 -0
  104. package/src/store/sqlite/foundation.ts +63 -0
  105. package/src/store/sqlite/game-achievements.test.ts +80 -0
  106. package/src/store/sqlite/game-achievements.ts +147 -0
  107. package/src/store/sqlite/game-scores.test.ts +132 -0
  108. package/src/store/sqlite/game-scores.ts +168 -0
  109. package/src/store/sqlite/game-state.test.ts +89 -0
  110. package/src/store/sqlite/game-state.ts +87 -0
  111. package/src/store/sqlite/global-index.ts +305 -0
  112. package/src/store/sqlite/maintenance.ts +294 -0
  113. package/src/store/sqlite/memories.ts +217 -0
  114. package/src/store/sqlite/meta.ts +108 -0
  115. package/src/store/sqlite/model-snapshots.ts +83 -0
  116. package/src/store/sqlite/raptor.ts +107 -0
  117. package/src/store/sqlite/raw-transcript.ts +221 -0
  118. package/src/store/sqlite/schema.ts +305 -0
  119. package/src/store/sqlite/session-state.ts +38 -0
  120. package/src/store/sqlite/stats.ts +127 -0
  121. package/src/store/sqlite/utils.ts +125 -0
  122. package/src/store/sqlite.ts +23 -2204
@@ -0,0 +1,41 @@
1
+ /**
2
+ * html.test.ts — S34 Game Mode tab presence in the dashboard HTML template.
3
+ */
4
+ import { test, describe } from "node:test";
5
+ import assert from "node:assert/strict";
6
+ import { dashboardHtml } from "./html.js";
7
+ describe("S34 dashboard HTML Game Mode", () => {
8
+ const html = dashboardHtml("custom");
9
+ test("Game Mode tab button + panel-game exist", () => {
10
+ assert.ok(html.includes('<button class="tab" data-tab="game">Game Mode</button>'), "game tab button present");
11
+ assert.ok(html.includes('<div class="tab-panel" id="panel-game">'), "panel-game present");
12
+ });
13
+ test("level-up-pulse + mega-flash keyframes present", () => {
14
+ assert.ok(html.includes("@keyframes level-up-pulse"), "level-up-pulse keyframe present");
15
+ assert.ok(html.includes("@keyframes mega-flash"), "mega-flash keyframe present");
16
+ });
17
+ test("empty-state string present", () => {
18
+ assert.ok(html.includes("No scores yet — run a session with game mode on."), "empty-state string present");
19
+ });
20
+ });
21
+ describe("S35 dashboard HTML achievements", () => {
22
+ const html = dashboardHtml("custom");
23
+ test("Achievements heading + ach-tiles/ach-toast containers present", () => {
24
+ assert.ok(html.includes(">Achievements</h3>"), "Achievements heading present");
25
+ assert.ok(html.includes('id="ach-tiles"'), "ach-tiles container present");
26
+ assert.ok(html.includes('id="ach-toast"'), "ach-toast element present");
27
+ });
28
+ test("ach-unlock-pulse keyframe + ach-tile classes present", () => {
29
+ assert.ok(html.includes("@keyframes ach-unlock-pulse"), "ach-unlock-pulse keyframe present");
30
+ assert.ok(html.includes(".ach-tile"), "ach-tile class present");
31
+ assert.ok(html.includes(".ach-tile.unlocked"), "unlocked class present");
32
+ assert.ok(html.includes(".ach-tile.locked"), "locked class present");
33
+ });
34
+ test("renderAchievements fn + GET /api/achievements fetch present", () => {
35
+ assert.ok(html.includes("function renderAchievements"), "renderAchievements fn present");
36
+ assert.ok(html.includes("fetch('/api/achievements')"), "achievements fetch present");
37
+ });
38
+ test("visible-but-locked teaser string present", () => {
39
+ assert.ok(html.includes("??? "), "??? teaser present");
40
+ });
41
+ });
@@ -0,0 +1,133 @@
1
+ /**
2
+ * dashboard-server/index-reader.ts — machine-wide repo registry reader.
3
+ *
4
+ * The extension writes a machine-wide repo registry into a single SQLite DB
5
+ * (<indexDir>/index.sqlite) as the concurrency-safe write path; the dashboard
6
+ * reads that table directly (one read-only connection, opened per request so a
7
+ * concurrent writer's WAL never blocks the request). All registry data lives in
8
+ * SQLite (the project's one-store invariant) — there is no JSON mirror. Same
9
+ * index-dir resolution as src/store/sqlite.ts getIndexDir().
10
+ */
11
+ import { existsSync } from "node:fs";
12
+ import { homedir } from "node:os";
13
+ import { join } from "node:path";
14
+ import { DatabaseSync } from "node:sqlite";
15
+ export function getIndexDir() {
16
+ const override = process.env.MEGACOMPACT_INDEX_DIR;
17
+ if (override && override.trim() !== "")
18
+ return override;
19
+ try {
20
+ return join(homedir(), ".mega-compact-index");
21
+ }
22
+ catch {
23
+ return join("/tmp", ".mega-compact-index");
24
+ }
25
+ }
26
+ /** Read the machine-wide repo registry from SQLite (read-only, single shot). */
27
+ export function readIndex() {
28
+ const indexPath = join(getIndexDir(), "index.sqlite");
29
+ if (!existsSync(indexPath))
30
+ return null;
31
+ let db;
32
+ try {
33
+ // Read-only + immutable WAL so a concurrent writer's WAL never blocks us.
34
+ db = new DatabaseSync(indexPath, { readOnly: true });
35
+ db.exec("PRAGMA journal_mode = WAL");
36
+ const rows = db
37
+ .prepare("SELECT * FROM repo_registry ORDER BY last_seen DESC")
38
+ .all();
39
+ const mapped = rows.map((r) => ({
40
+ repoRoot: String(r.repo_root ?? ""),
41
+ displayName: String(r.display_name ?? ""),
42
+ stateDir: String(r.state_dir ?? ""),
43
+ checkpointCount: Number(r.checkpoint_count ?? 0),
44
+ tokensSaved: Number(r.tokens_saved ?? 0),
45
+ compressedOriginalBytes: Number(r.compressed_original_bytes ?? 0),
46
+ lastCompactedAt: r.last_compacted_at ?? null,
47
+ provider: r.provider ?? null,
48
+ providerName: r.provider_name ?? null,
49
+ modelName: r.model_name ?? null,
50
+ inputRate: r.input_rate ?? null,
51
+ outputRate: r.output_rate ?? null,
52
+ lastSeen: Number(r.last_seen ?? 0),
53
+ // Defaults — enriched below from each repo's own store.
54
+ tokensKept: 0,
55
+ tokensDropped: 0,
56
+ sessions: 0,
57
+ contextWindow: null,
58
+ maxTokens: null,
59
+ reasoning: null,
60
+ }));
61
+ // Enrich each repo with per-store token + model detail read directly via
62
+ // node:sqlite (same zero-dependency invariant as readIndex; no store graph
63
+ // import). Best-effort: a missing/corrupt store degrades to the defaults
64
+ // above so the dashboard never fails to render.
65
+ for (const repo of mapped) {
66
+ try {
67
+ const storePath = join(repo.stateDir, "sqlite.db");
68
+ if (existsSync(storePath)) {
69
+ const sdb = new DatabaseSync(storePath, { readOnly: true });
70
+ try {
71
+ const tok = sdb
72
+ .prepare(`SELECT COALESCE(SUM(token_estimate),0) AS kept,
73
+ COALESCE(SUM(original_token_estimate),0) AS dropped,
74
+ COUNT(DISTINCT session_id) AS sess
75
+ FROM context_chunks WHERE dedup_status != 'removed'`)
76
+ .get();
77
+ repo.tokensKept = Number(tok.kept ?? 0);
78
+ repo.tokensDropped = Number(tok.dropped ?? 0);
79
+ repo.sessions = Number(tok.sess ?? 0);
80
+ const mrow = sdb
81
+ .prepare(`SELECT context_window, max_tokens, reasoning
82
+ FROM model_snapshots ORDER BY captured_at DESC LIMIT 1`)
83
+ .get();
84
+ if (mrow) {
85
+ repo.contextWindow = Number(mrow.context_window ?? 0) || null;
86
+ repo.maxTokens = Number(mrow.max_tokens ?? 0) || null;
87
+ repo.reasoning = Number(mrow.reasoning ?? 0) === 1;
88
+ }
89
+ }
90
+ finally {
91
+ sdb.close();
92
+ }
93
+ }
94
+ }
95
+ catch {
96
+ /* best-effort — keep the defaults */
97
+ }
98
+ }
99
+ // Defensive display hygiene (belt-and-suspenders — the real fix is that
100
+ // tests now isolate via MEGACOMPACT_INDEX_DIR): drop transient test/temp
101
+ // paths that should never have been real repos, and collapse duplicate
102
+ // display names to the most-recently-seen row (rows are last_seen DESC, so
103
+ // the first occurrence wins). Keeps the All-repos list readable.
104
+ const isTransient = (p) => /^\/tmp\//.test(p) || /^\/private\/tmp\//.test(p) || /^\/var\/folders\//.test(p) ||
105
+ /\/mc-(ext|e2e|resume|recall)-/.test(p);
106
+ const seenName = new Set();
107
+ const repos = [];
108
+ for (const r of mapped) {
109
+ if (isTransient(r.repoRoot))
110
+ continue;
111
+ if (seenName.has(r.displayName))
112
+ continue;
113
+ seenName.add(r.displayName);
114
+ repos.push(r);
115
+ }
116
+ const summary = {
117
+ totalRepos: repos.length,
118
+ totalCheckpoints: repos.reduce((a, r) => a + r.checkpointCount, 0),
119
+ totalTokensSaved: repos.reduce((a, r) => a + r.tokensSaved, 0),
120
+ totalCompressedOriginalBytes: repos.reduce((a, r) => a + r.compressedOriginalBytes, 0),
121
+ };
122
+ return { updatedAt: new Date().toISOString(), summary, repos };
123
+ }
124
+ catch {
125
+ return null;
126
+ }
127
+ finally {
128
+ try {
129
+ db?.close();
130
+ }
131
+ catch { /* ignore */ }
132
+ }
133
+ }