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,165 @@
1
+ /**
2
+ * recall.ts — unified Layer-5 recall pipeline.
3
+ *
4
+ * `doRecall` is the ONE path that injects (sync). `doRecallAsync` augments with
5
+ * optional cross-repo HNSW on resume / /mega-recall --cross-repo. Both mutate
6
+ * the shared MegaRuntime (token accounting, ticker, dashboard events).
7
+ */
8
+
9
+ import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
10
+ import { sessionEntryToContextMessages } from "@earendil-works/pi-coding-agent";
11
+ import { recallAndInline, recallAndInlineAsync, formatRecallBlock, type RecallInjectResult } from "../../src/recall.js";
12
+ import { normalizeSessionId } from "../../src/store.js";
13
+ import { incRecallInjected, incCacheHitTokens } from "../../src/store/sqlite.js";
14
+ import {
15
+ type MegaRuntime,
16
+ C,
17
+ } from "../mega-runtime.js";
18
+ import { type MegaConfig } from "../mega-config.js";
19
+
20
+ /**
21
+ * Unified recall (Layer 5). The ONE path that injects. Returns the recall
22
+ * result; callers decide whether to stage it for before_agent_start (resume)
23
+ * or report it (command).
24
+ */
25
+ export function doRecall(
26
+ runtime: MegaRuntime,
27
+ config: MegaConfig,
28
+ ctx: ExtensionContext,
29
+ query: string,
30
+ source: "resume" | "command",
31
+ ) {
32
+ runtime.bindRepo(ctx.cwd);
33
+ const sid = normalizeSessionId(ctx.sessionManager.getSessionId());
34
+ // Live window text for inline dedupe (Fix C): drop recalled checkpoints that
35
+ // are already resident in the session, so recall never re-injects context the
36
+ // model can already see. Best-effort — an empty window just skips dedupe.
37
+ const liveWindow = config.windowDedupe ? extractLiveWindow(ctx) : undefined;
38
+ const result = recallAndInline(
39
+ {
40
+ sessionId: sid,
41
+ query,
42
+ limit: config.autoInlineK,
43
+ source,
44
+ skipInjected: true,
45
+ recallMaxTokens: config.recallMaxTokens,
46
+ windowDedupe: config.windowDedupe,
47
+ liveWindow,
48
+ dedupSim: config.dedupSim,
49
+ },
50
+ runtime.store,
51
+ );
52
+ runtime.dashboard.event("recall", { source, query: query.slice(0, 120), injected: result.toInject.length, empty: result.empty });
53
+ if (!result.empty && result.toInject.length > 0) {
54
+ const top = result.toInject[0];
55
+ const scorePct = Math.round((top.score ?? 0) * 100);
56
+ const files = top.checkpoint.filesModified ?? [];
57
+ const label = files.length ? files.map((f) => f.split("/").pop() ?? f).slice(0, 2).join(", ") : top.checkpoint.checkpointId;
58
+ runtime.pushTicker(`${C.amber}↩${C.reset} recalled ${top.checkpoint.checkpointId} · ${scorePct}% · ${label}`);
59
+ runtime.lastWhy = `why: recalled@${scorePct}% (${result.toInject.length} chkpt)`;
60
+ }
61
+ if (result.toInject.length > 0) {
62
+ let sumTokens = 0; for (const h of result.toInject) sumTokens += h.checkpoint.tokenEstimate;
63
+ runtime.rt.recallInjections += result.toInject.length;
64
+ runtime.rt.cacheHitTokens += sumTokens;
65
+ incRecallInjected(result.toInject.length, runtime.currentStateDir);
66
+ incCacheHitTokens(sumTokens, runtime.currentStateDir);
67
+ }
68
+ return result;
69
+ }
70
+
71
+ /**
72
+ * S17: async recall with optional cross-repo augmentation. Used on resume
73
+ * (session_start) and /mega-recall --cross-repo — NEVER from the mid-turn
74
+ * context handler (that stays sync). Runs the sync same-repo scan first; if it
75
+ * returns < config.autoInlineK hits AND crossRepo is enabled, awaits the PGlite
76
+ * HNSW cross-repo path and merges (source-labeled, deduped by checkpointId). The
77
+ * recallMaxTokens cap + windowDedupe apply to the merged set so cross-repo can
78
+ * never net-inflate the window. Cross-repo uses a stricter cosine floor
79
+ * (config.crossRepoCosine) than same-repo. Non-fatal: any async failure returns
80
+ * the same-repo result unchanged.
81
+ */
82
+ export async function doRecallAsync(
83
+ runtime: MegaRuntime,
84
+ config: MegaConfig,
85
+ ctx: ExtensionContext,
86
+ query: string,
87
+ source: "resume" | "command",
88
+ opts: { crossRepo?: boolean } = {},
89
+ ): Promise<RecallInjectResult> {
90
+ runtime.bindRepo(ctx.cwd);
91
+ const sid = normalizeSessionId(ctx.sessionManager.getSessionId());
92
+ const liveWindow = config.windowDedupe ? extractLiveWindow(ctx) : undefined;
93
+ // Sync same-repo first (fast, never blocks).
94
+ const sameRepo = recallAndInline(
95
+ {
96
+ sessionId: sid, query, limit: config.autoInlineK, source, skipInjected: true,
97
+ recallMaxTokens: config.recallMaxTokens, windowDedupe: config.windowDedupe,
98
+ liveWindow, dedupSim: config.dedupSim,
99
+ },
100
+ runtime.store,
101
+ );
102
+ if (!config.crossRepoEnabled || !opts.crossRepo) return sameRepo;
103
+ if (sameRepo.toInject.length >= config.autoInlineK) return sameRepo; // same-repo satisfied
104
+ // Augment: cross-repo HNSW (async) with the stricter floor. Non-fatal.
105
+ try {
106
+ const x = await recallAndInlineAsync(
107
+ {
108
+ sessionId: sid, query, limit: config.autoInlineK, source, skipInjected: true,
109
+ recallMaxTokens: config.recallMaxTokens, windowDedupe: config.windowDedupe,
110
+ liveWindow, dedupSim: config.crossRepoCosine, crossRepo: true,
111
+ globalIndexDir: process.env.MEGACOMPACT_INDEX_DIR,
112
+ },
113
+ runtime.store,
114
+ );
115
+ runtime.dashboard.event("recall-crossrepo", {
116
+ source, query: query.slice(0, 120), injected: x.toInject.length,
117
+ sourceRepos: x.toInject.map((h) => h.repoId).filter(Boolean),
118
+ });
119
+ // Merge, dedup by checkpointId, respect the same token cap by reformatting.
120
+ const seen = new Set(sameRepo.toInject.map((h) => h.checkpoint.checkpointId));
121
+ const merged = [...sameRepo.toInject];
122
+ for (const h of x.toInject) {
123
+ if (!seen.has(h.checkpoint.checkpointId)) { merged.push(h); seen.add(h.checkpoint.checkpointId); }
124
+ }
125
+ const block = merged.length ? formatRecallBlock(merged) : "";
126
+ if (merged.length > 0) {
127
+ let sumTokens = 0; for (const h of merged) sumTokens += h.checkpoint.tokenEstimate;
128
+ runtime.rt.recallInjections += merged.length;
129
+ runtime.rt.cacheHitTokens += sumTokens;
130
+ incRecallInjected(merged.length, runtime.currentStateDir);
131
+ incCacheHitTokens(sumTokens, runtime.currentStateDir);
132
+ }
133
+ return {
134
+ toInject: merged,
135
+ report: merged.map((h) => ` • ${h.checkpoint.checkpointId}${h.repoId ? ` (from ${h.repoId.split("/").filter(Boolean).pop()})` : ""}`),
136
+ block,
137
+ empty: merged.length === 0,
138
+ };
139
+ } catch {
140
+ return sameRepo; // cross-repo failure → same-repo only (non-fatal)
141
+ }
142
+ }
143
+
144
+ /**
145
+ * Extract the live-window message texts from the session manager (Fix C),
146
+ * for inline-dedupe of recalled checkpoints. Best-effort: returns [] on any
147
+ * error so recall falls back to unbounded (still correct, just no dedupe).
148
+ * Mirrors recentUserQuery's use of sessionEntryToContextMessages.
149
+ */
150
+ function extractLiveWindow(ctx: ExtensionContext): string[] {
151
+ try {
152
+ const entries = ctx.sessionManager.getEntries();
153
+ const texts: string[] = [];
154
+ for (const e of entries) {
155
+ for (const m of sessionEntryToContextMessages(e)) {
156
+ const c = (m as { content?: unknown }).content;
157
+ if (typeof c === "string") texts.push(c);
158
+ else if (Array.isArray(c)) texts.push(c.map((b: { text?: string }) => b.text ?? "").join(" "));
159
+ }
160
+ }
161
+ return texts;
162
+ } catch {
163
+ return [];
164
+ }
165
+ }