@pi-unipi/unipi 2.4.1 → 2.4.2

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 (96) hide show
  1. package/CHANGELOG.md +37 -0
  2. package/package.json +26 -22
  3. package/packages/ask-user/package.json +2 -2
  4. package/packages/autocomplete/package.json +4 -2
  5. package/packages/btw/package.json +2 -2
  6. package/packages/cocoindex/package.json +2 -2
  7. package/packages/cocoindex/tools.ts +0 -8
  8. package/packages/compactor/README.md +18 -22
  9. package/packages/compactor/package.json +3 -3
  10. package/packages/compactor/src/compaction/build-sections.ts +2 -2
  11. package/packages/compactor/src/compaction/format.ts +1 -1
  12. package/packages/compactor/src/config/presets.ts +19 -30
  13. package/packages/compactor/src/index.ts +39 -56
  14. package/packages/compactor/src/session/resume-inject.ts +27 -0
  15. package/packages/compactor/src/tools/ctx-batch-execute.ts +4 -2
  16. package/packages/compactor/src/tools/ctx-execute-file.ts +4 -2
  17. package/packages/compactor/src/tools/ctx-execute.ts +4 -2
  18. package/packages/compactor/src/tools/register.ts +22 -4
  19. package/packages/compactor/src/tui/settings-overlay.ts +9 -22
  20. package/packages/compactor/src/types.ts +24 -2
  21. package/packages/core/events.ts +13 -13
  22. package/packages/core/package.json +3 -2
  23. package/packages/footer/README.md +2 -2
  24. package/packages/footer/package.json +3 -3
  25. package/packages/footer/src/events.ts +0 -10
  26. package/packages/footer/src/segments/core.ts +0 -9
  27. package/packages/image/package.json +2 -2
  28. package/packages/info-screen/core-groups.ts +0 -14
  29. package/packages/info-screen/package.json +2 -2
  30. package/packages/input-shortcuts/package.json +2 -2
  31. package/packages/kanboard/commands.ts +0 -1
  32. package/packages/kanboard/package.json +2 -2
  33. package/packages/mcp/package.json +2 -2
  34. package/packages/memory/package.json +3 -3
  35. package/packages/memory/storage.ts +0 -18
  36. package/packages/memory/tools.ts +0 -1
  37. package/packages/milestone/hooks.ts +9 -15
  38. package/packages/milestone/package.json +2 -2
  39. package/packages/notify/README.md +2 -0
  40. package/packages/notify/events.ts +23 -13
  41. package/packages/notify/package.json +2 -2
  42. package/packages/notify/tools.ts +17 -8
  43. package/packages/notify/types.ts +5 -1
  44. package/packages/ralph/package.json +3 -3
  45. package/packages/ralph/ralph-loop.ts +10 -0
  46. package/packages/subagents/README.md +3 -1
  47. package/packages/subagents/package.json +10 -6
  48. package/packages/subagents/src/agent-manager.ts +46 -11
  49. package/packages/subagents/src/core-compat.ts +38 -0
  50. package/packages/subagents/src/global.d.ts +7 -0
  51. package/packages/subagents/src/index.ts +6 -3
  52. package/packages/subagents/src/widget.ts +0 -7
  53. package/packages/unipi/bundled.js +364 -434
  54. package/packages/updater/package.json +4 -3
  55. package/packages/utility/README.md +1 -1
  56. package/packages/utility/package.json +7 -4
  57. package/packages/utility/src/commands.ts +2 -10
  58. package/packages/utility/src/diff/theme.ts +0 -3
  59. package/packages/utility/src/tui/name-badge.ts +0 -9
  60. package/packages/web-api/package.json +2 -2
  61. package/packages/web-api/src/engine/extract.ts +0 -26
  62. package/packages/web-api/src/tools.ts +0 -13
  63. package/packages/workflow/commands.ts +13 -1
  64. package/packages/workflow/index.ts +12 -1
  65. package/packages/workflow/lifecycle.ts +43 -0
  66. package/packages/workflow/package.json +3 -2
  67. package/packages/autocomplete/index.ts +0 -7
  68. package/packages/autocomplete/src/__tests__/command-registry.audit.test.ts +0 -120
  69. package/packages/autocomplete/src/__tests__/provider.sorting.test.ts +0 -423
  70. package/packages/compactor/src/compaction/recall-scope.ts +0 -32
  71. package/packages/compactor/src/compaction/sections.ts +0 -15
  72. package/packages/compactor/src/display/bash-display.ts +0 -28
  73. package/packages/compactor/src/display/diff-presentation.ts +0 -25
  74. package/packages/compactor/src/display/pending-diff-preview.ts +0 -51
  75. package/packages/compactor/src/display/user-message-box.ts +0 -16
  76. package/packages/compactor/src/session/analytics.ts +0 -205
  77. package/packages/image/index.ts +0 -1
  78. package/packages/input-shortcuts/index.ts +0 -5
  79. package/packages/input-shortcuts/src/status.ts +0 -35
  80. package/packages/kanboard/tui/kanboard-overlay.ts +0 -300
  81. package/packages/mcp/index.ts +0 -1
  82. package/packages/memory/search.ts +0 -134
  83. package/packages/milestone/coexist.ts +0 -114
  84. package/packages/notify/src/__tests__/ask-user-prompt-message.test.ts +0 -159
  85. package/packages/notify/src/__tests__/event-bus.test.ts +0 -119
  86. package/packages/notify/src/__tests__/permission-prompt-message.test.ts +0 -172
  87. package/packages/subagents/src/__tests__/badge-generation.test.ts +0 -315
  88. package/packages/subagents/src/__tests__/config.test.ts +0 -240
  89. package/packages/subagents/src/__tests__/esc-propagation.test.ts +0 -162
  90. package/packages/subagents/src/__tests__/file-lock.test.ts +0 -244
  91. package/packages/subagents/src/__tests__/shutdown-stale-ctx.test.ts +0 -185
  92. package/packages/subagents/src/__tests__/workflow-integration.test.ts +0 -334
  93. package/packages/subagents/src/prompts.ts +0 -39
  94. package/packages/utility/index.ts +0 -1
  95. package/packages/web-api/src/tui/progress.ts +0 -168
  96. package/packages/web-api/src/tui/result.ts +0 -173
@@ -2,10 +2,16 @@
2
2
  * Resume injection — inject snapshot into session context post-compaction
3
3
  */
4
4
 
5
+ import type { BeforeAgentStartEventResult } from "@earendil-works/pi-coding-agent";
5
6
  import type { SessionDB } from "./db.js";
6
7
  import { buildResumeSnapshot } from "./snapshot.js";
7
8
  import { buildAutoInjection } from "./auto-inject.js";
8
9
  import { loadConfig } from "../config/manager.js";
10
+ import type { CompactorConfig } from "../types.js";
11
+
12
+ export function isSessionContinuityEnabled(config: CompactorConfig): boolean {
13
+ return config.sessionContinuity.enabled && config.sessionContinuity.mode !== "off";
14
+ }
9
15
 
10
16
  export async function injectResumeSnapshot(
11
17
  db: SessionDB,
@@ -35,3 +41,24 @@ export async function injectResumeSnapshot(
35
41
  db.markResumeConsumed(sessionId);
36
42
  return fullSnapshot;
37
43
  }
44
+
45
+ /**
46
+ * Build the one-shot hidden context message used on the first turn after
47
+ * compaction. Keeping this out of the system prompt preserves Pi's stable
48
+ * prompt/history prefix for provider cache reuse.
49
+ */
50
+ export async function buildResumeContextMessage(
51
+ db: SessionDB,
52
+ sessionId: string,
53
+ ): Promise<BeforeAgentStartEventResult | undefined> {
54
+ const snapshot = await injectResumeSnapshot(db, sessionId);
55
+ if (!snapshot) return undefined;
56
+
57
+ return {
58
+ message: {
59
+ customType: "unipi-compactor-resume",
60
+ content: snapshot,
61
+ display: false,
62
+ },
63
+ };
64
+ }
@@ -20,9 +20,11 @@ export interface BatchResult {
20
20
  >;
21
21
  }
22
22
 
23
- export async function ctxBatchExecute(items: BatchItem[]): Promise<BatchResult> {
23
+ export async function ctxBatchExecute(
24
+ items: BatchItem[],
25
+ executor = new PolyglotExecutor(),
26
+ ): Promise<BatchResult> {
24
27
  const results: BatchResult["results"] = [];
25
- const executor = new PolyglotExecutor();
26
28
 
27
29
  for (const item of items) {
28
30
  if (item.type === "execute") {
@@ -12,11 +12,13 @@ export interface CtxExecuteFileInput {
12
12
  timeout?: number;
13
13
  }
14
14
 
15
- export async function ctxExecuteFile(input: CtxExecuteFileInput): Promise<ExecResult> {
15
+ export async function ctxExecuteFile(
16
+ input: CtxExecuteFileInput,
17
+ executor = new PolyglotExecutor(),
18
+ ): Promise<ExecResult> {
16
19
  const content = readFileSync(input.path, "utf-8");
17
20
  const code = `const FILE_CONTENT = ${JSON.stringify(content)};\n// User script follows:\n`;
18
21
 
19
- const executor = new PolyglotExecutor();
20
22
  return executor.executeFile({
21
23
  language: input.language,
22
24
  path: input.path,
@@ -11,8 +11,10 @@ export interface CtxExecuteInput {
11
11
  timeout?: number;
12
12
  }
13
13
 
14
- export async function ctxExecute(input: CtxExecuteInput): Promise<ExecResult> {
15
- const executor = new PolyglotExecutor();
14
+ export async function ctxExecute(
15
+ input: CtxExecuteInput,
16
+ executor = new PolyglotExecutor(),
17
+ ): Promise<ExecResult> {
16
18
  return executor.execute({
17
19
  language: input.language,
18
20
  code: input.code,
@@ -27,7 +27,8 @@ import { recallBlocksFromContext } from "../session/recall-blocks.js";
27
27
  import { filterNoise } from "../compaction/filter-noise.js";
28
28
  import { loadConfig } from "../config/manager.js";
29
29
  import type { SessionDB } from "../session/db.js";
30
- import type { NormalizedBlock, RuntimeCounters } from "../types.js";
30
+ import type { Language, NormalizedBlock, RuntimeCounters } from "../types.js";
31
+ import type { PolyglotExecutor } from "../executor/executor.js";
31
32
 
32
33
  // --- TypeBox Schemas for each tool ---
33
34
 
@@ -127,6 +128,10 @@ export interface CompactorToolDeps {
127
128
  getSessionId: () => string;
128
129
  getBlocks: () => NormalizedBlock[];
129
130
  getCounters?: () => RuntimeCounters;
131
+ sandbox?: {
132
+ executor: PolyglotExecutor;
133
+ allowedLanguages: Language[];
134
+ };
130
135
  }
131
136
 
132
137
  /**
@@ -189,13 +194,23 @@ export function registerCompactorTools(pi: ExtensionAPI, deps: CompactorToolDeps
189
194
  pi.registerTool({ name: "session_recall", label: "Session Recall", description: "Search session history using BM25 or regex. Find previous goals, files, commits, and context.", parameters: RecallParams, execute: recallExec } as any);
190
195
  pi.registerTool({ name: "vcc_recall", label: "Session Recall", description: "Search session history using BM25 or regex. (DEPRECATED: use session_recall instead)", parameters: VccRecallParams, async execute(tcId: string, p: any) { deprecationLog("vcc_recall", "session_recall"); return recallExec(tcId, p); } } as any);
191
196
 
197
+ // Sandbox tools are session-scoped and only registered when enabled.
198
+ if (deps.sandbox) {
199
+ const { executor, allowedLanguages } = deps.sandbox;
200
+ const assertAllowedLanguage = (language: Language): void => {
201
+ if (!allowedLanguages.includes(language)) {
202
+ throw new Error(`Language "${language}" is disabled by Compactor sandbox settings. Allowed: ${allowedLanguages.join(", ") || "none"}`);
203
+ }
204
+ };
205
+
192
206
  // 3. sandbox (new) / ctx_execute (deprecated) — run code in sandbox
193
207
  const sandboxExec = async (_toolCallId: string, params: any): Promise<import("@earendil-works/pi-coding-agent").AgentToolResult<unknown>> => {
194
208
  try {
195
209
  const c = deps.getCounters?.();
196
210
  if (c) { c.sandboxRuns++; }
197
211
  deps.sessionDB.incrementSandboxRuns(deps.getSessionId());
198
- const result = await ctxExecute(params as CtxExecuteInput);
212
+ assertAllowedLanguage(params.language as Language);
213
+ const result = await ctxExecute(params as CtxExecuteInput, executor);
199
214
  const parts: string[] = [];
200
215
  if (result.stdout) parts.push(result.stdout);
201
216
  if (result.stderr) parts.push(`[stderr] ${result.stderr}`);
@@ -215,7 +230,8 @@ export function registerCompactorTools(pi: ExtensionAPI, deps: CompactorToolDeps
215
230
  const c = deps.getCounters?.();
216
231
  if (c) { c.sandboxRuns++; }
217
232
  deps.sessionDB.incrementSandboxRuns(deps.getSessionId());
218
- const result = await ctxExecuteFile(params as CtxExecuteFileInput);
233
+ assertAllowedLanguage(params.language as Language);
234
+ const result = await ctxExecuteFile(params as CtxExecuteFileInput, executor);
219
235
  const parts: string[] = [];
220
236
  if (result.stdout) parts.push(result.stdout);
221
237
  if (result.stderr) parts.push(`[stderr] ${result.stderr}`);
@@ -234,7 +250,8 @@ export function registerCompactorTools(pi: ExtensionAPI, deps: CompactorToolDeps
234
250
  const c = deps.getCounters?.();
235
251
  if (c) { c.sandboxRuns++; }
236
252
  deps.sessionDB.incrementSandboxRuns(deps.getSessionId());
237
- const result = await ctxBatchExecute(params.items as BatchItem[]);
253
+ for (const item of params.items as BatchItem[]) assertAllowedLanguage(item.language);
254
+ const result = await ctxBatchExecute(params.items as BatchItem[], executor);
238
255
  const summaries = result.results.map((r, i) => {
239
256
  const s = r.result.stdout?.slice(0, 200) || "(no output)";
240
257
  return `[${i}] execute → ${r.result.exitCode === 0 ? "ok" : "fail"}: ${s}`;
@@ -246,6 +263,7 @@ export function registerCompactorTools(pi: ExtensionAPI, deps: CompactorToolDeps
246
263
  };
247
264
  pi.registerTool({ name: "sandbox_batch", label: "Sandbox Batch", description: "Run multiple code executions atomically as a batch.", parameters: SandboxBatchParams, execute: sandboxBatchExec } as any);
248
265
  pi.registerTool({ name: "ctx_batch_execute", label: "Sandbox Batch", description: "Run batch operations. (DEPRECATED: use sandbox_batch instead)", parameters: CtxBatchExecuteParams, async execute(tcId: string, p: any) { deprecationLog("ctx_batch_execute", "sandbox_batch"); return sandboxBatchExec(tcId, p); } } as any);
266
+ }
249
267
 
250
268
  // 6. compactor_stats (new) / ctx_stats (deprecated) — context savings dashboard
251
269
  const statsExec = async (): Promise<import("@earendil-works/pi-coding-agent").AgentToolResult<unknown>> => {
@@ -122,7 +122,7 @@ const STRATEGIES: StrategyDef[] = [
122
122
  key: "sessionContinuity",
123
123
  label: "Session Continuity",
124
124
  description: "XML resume snapshot for compaction survival",
125
- modes: ["full", "essential-only", "off"],
125
+ modes: ["full", "off"],
126
126
  getEnabled: (c) => c.sessionContinuity.enabled,
127
127
  setEnabled: (c, v) => (c.sessionContinuity.enabled = v),
128
128
  getMode: (c) => c.sessionContinuity.mode,
@@ -132,31 +132,18 @@ const STRATEGIES: StrategyDef[] = [
132
132
  key: "sandboxExecution",
133
133
  label: "Sandbox Execution",
134
134
  description: "Polyglot code execution",
135
- modes: ["all", "safe-only", "off"],
135
+ modes: ["all", "off"],
136
136
  getEnabled: (c) => c.sandboxExecution.enabled,
137
137
  setEnabled: (c, v) => (c.sandboxExecution.enabled = v),
138
138
  getMode: (c) => c.sandboxExecution.mode,
139
139
  setMode: (c, v) => (c.sandboxExecution.mode = v as any),
140
140
  },
141
- {
142
- key: "toolDisplay",
143
- label: "Tool Display",
144
- description: "Override tool output rendering",
145
- modes: ["opencode", "balanced", "verbose", "custom"],
146
- getEnabled: (c) => c.toolDisplay.enabled,
147
- setEnabled: (c, v) => (c.toolDisplay.enabled = v),
148
- getMode: (c) => c.toolDisplay.mode,
149
- setMode: (c, v) => (c.toolDisplay.mode = v as any),
150
- },
151
141
  ];
152
142
 
153
143
  const PIPELINE_ITEMS: PipelineDef[] = [
154
- { key: "ttlCache", label: "TTL Cache", description: "Cache with time-based expiry", group: "On Compaction", getValue: (c) => c.pipeline.ttlCache, setValue: (c, v) => (c.pipeline.ttlCache = v) },
144
+ // Only expose implemented behavior. Reserved compatibility fields remain in
145
+ // the persisted schema so existing config files continue to load.
155
146
  { key: "autoInjection", label: "Auto Injection", description: "Inject behavioral state after compaction", group: "On Compaction", getValue: (c) => c.pipeline.autoInjection, setValue: (c, v) => (c.pipeline.autoInjection = v) },
156
- { key: "mmapPragma", label: "MMap Pragma", description: "Use mmap for SQLite I/O", group: "On Compaction", getValue: (c) => c.pipeline.mmapPragma, setValue: (c, v) => (c.pipeline.mmapPragma = v) },
157
- { key: "proximityReranking", label: "Proximity Reranking", description: "Rerank search results by proximity", group: "On Search", getValue: (c) => c.pipeline.proximityReranking, setValue: (c, v) => (c.pipeline.proximityReranking = v) },
158
- { key: "timelineSort", label: "Timeline Sort", description: "Sort session events chronologically", group: "On Search", getValue: (c) => c.pipeline.timelineSort, setValue: (c, v) => (c.pipeline.timelineSort = v) },
159
- { key: "progressiveThrottling", label: "Progressive Throttling", description: "Slow down processing for large projects", group: "On Compaction", getValue: (c) => c.pipeline.progressiveThrottling, setValue: (c, v) => (c.pipeline.progressiveThrottling = v) },
160
147
  ];
161
148
 
162
149
  const PRESETS: CompactorPreset[] = ["precise", "balanced", "thorough", "lean"];
@@ -167,20 +154,20 @@ const REPEAT_GROWTH_VALUES = ["0", "1k", "4k", "8k", "16k", "32k"];
167
154
 
168
155
  const PRESET_DESCRIPTIONS: Record<string, { summary: string; detail: string }> = {
169
156
  precise: {
170
- summary: "Code-heavy, minimal waste — compaction: full, sandbox: safe-only",
171
- detail: "Max token savings. Compaction: full. Display: minimal.\nSandbox: safe-only. Pipeline: ttlCache+mmap on.",
157
+ summary: "Code-heavy, minimal waste — compaction: full, sandbox: all",
158
+ detail: "Max token savings. Compaction: full.\nSandbox: all. Auto injection: off.",
172
159
  },
173
160
  balanced: {
174
161
  summary: "Daily use (default) — all strategies moderate",
175
- detail: "Moderate all strategies. Display: balanced.\nSandbox: all. Pipeline: all 6 on.",
162
+ detail: "Moderate all strategies.\nSandbox: all. Auto injection: on.",
176
163
  },
177
164
  thorough: {
178
165
  summary: "Debug/audit — everything on, full transcript",
179
- detail: "Everything enabled. Display: verbose.\nSandbox: all. Pipeline: all 6 on.",
166
+ detail: "Everything enabled.\nSandbox: all. Auto injection: on.",
180
167
  },
181
168
  lean: {
182
169
  summary: "Quick fixes, short sessions — compaction only",
183
- detail: "Compaction only. Display: opencode.\nSandbox: off. Pipeline: all 6 off.",
170
+ detail: "Compaction only.\nSandbox: off. Auto injection: off.",
184
171
  },
185
172
  };
186
173
 
@@ -49,6 +49,16 @@ export interface BriefLine {
49
49
  lines: string[];
50
50
  }
51
51
 
52
+ /** Runtime stats tracked during a live session. */
53
+ export interface RuntimeStats {
54
+ bytesReturned: Record<string, number>;
55
+ bytesSandboxed: number;
56
+ calls: Record<string, number>;
57
+ sessionStart: number;
58
+ cacheHits: number;
59
+ cacheBytesSaved: number;
60
+ }
61
+
52
62
  // ─────────────────────────────────────────────────────────
53
63
  // Compaction input / output
54
64
  // ─────────────────────────────────────────────────────────
@@ -110,18 +120,29 @@ export interface CompactorConfig {
110
120
  outstandingContext: CompactorStrategyConfig & { mode: "full" | "critical-only" | "off"; maxItems: number };
111
121
  userPreferences: CompactorStrategyConfig & { mode: "all" | "recent-only" | "off"; maxPreferences: number };
112
122
  briefTranscript: CompactorStrategyConfig & { mode: "full" | "compact" | "minimal" | "off"; userTokenLimit: number; assistantTokenLimit: number; toolCallLimit: number };
113
- sessionContinuity: CompactorStrategyConfig & { mode: "full" | "essential-only" | "off"; eventCategories: string[] };
123
+ sessionContinuity: CompactorStrategyConfig & {
124
+ mode: "full" | "essential-only" | "off";
125
+ /** @deprecated Category filtering was never implemented; ignored by runtime. */
126
+ eventCategories: string[];
127
+ };
128
+ /** @deprecated Project indexing moved to @pi-unipi/cocoindex; retained for config compatibility. */
114
129
  fts5Index: CompactorStrategyConfig & { mode: "auto" | "manual" | "off"; chunkSize: number; cacheTtlHours: number };
115
- sandboxExecution: CompactorStrategyConfig & { mode: "all" | "safe-only" | "off"; allowedLanguages: string[]; outputLimit: number };
130
+ sandboxExecution: CompactorStrategyConfig & { mode: "all" | "safe-only" | "off"; allowedLanguages: Language[]; outputLimit: number };
131
+ /** @deprecated Display profiles were never connected to runtime; retained for config compatibility. */
116
132
  toolDisplay: CompactorStrategyConfig & { mode: "opencode" | "balanced" | "verbose" | "custom"; diffLayout: "auto" | "split" | "unified"; diffIndicator: "bars" | "classic" | "none"; showThinkingLabels: boolean; showUserMessageBox: boolean; showBashSpinner: boolean; showPendingPreviews: boolean };
117
133
 
118
134
  // Pipeline features
119
135
  pipeline: {
136
+ /** @deprecated Reserved compatibility field; ignored by runtime. */
120
137
  ttlCache: boolean;
121
138
  autoInjection: boolean;
139
+ /** @deprecated Reserved compatibility field; ignored by runtime. */
122
140
  proximityReranking: boolean;
141
+ /** @deprecated Reserved compatibility field; ignored by runtime. */
123
142
  timelineSort: boolean;
143
+ /** @deprecated Reserved compatibility field; ignored by runtime. */
124
144
  progressiveThrottling: boolean;
145
+ /** @deprecated Reserved compatibility field; ignored by runtime. */
125
146
  mmapPragma: boolean;
126
147
  customNoisePatterns: string[];
127
148
  };
@@ -132,6 +153,7 @@ export interface CompactorConfig {
132
153
  // Global settings
133
154
  overrideDefaultCompaction: boolean;
134
155
  debug: boolean;
156
+ /** @deprecated Truncation hints were never connected to runtime; retained for config compatibility. */
135
157
  showTruncationHints: boolean;
136
158
  }
137
159
 
@@ -9,7 +9,7 @@
9
9
  export const UNIPI_EVENTS = {
10
10
  /** Module loaded and ready */
11
11
  MODULE_READY: "unipi:module:ready",
12
- /** Module unloading */
12
+ /** @deprecated No built-in emitter; retained for external compatibility. */
13
13
  MODULE_GONE: "unipi:module:gone",
14
14
 
15
15
  /** Workflow command started */
@@ -24,9 +24,9 @@ export const UNIPI_EVENTS = {
24
24
  /** Ralph loop iteration completed */
25
25
  RALPH_ITERATION_DONE: "unipi:ralph:iteration:done",
26
26
 
27
- /** Request module status (for info-screen) */
27
+ /** @deprecated No built-in responders; use the info registry and /unipi:info. */
28
28
  MODULE_STATUS_REQUEST: "unipi:module:status:request",
29
- /** Module status response */
29
+ /** @deprecated No built-in aggregator; use the info registry and /unipi:info. */
30
30
  MODULE_STATUS_RESPONSE: "unipi:module:status:response",
31
31
 
32
32
  /** Info screen group registered */
@@ -38,7 +38,7 @@ export const UNIPI_EVENTS = {
38
38
  MEMORY_STORED: "unipi:memory:stored",
39
39
  /** Memory deleted */
40
40
  MEMORY_DELETED: "unipi:memory:deleted",
41
- /** Memory search performed */
41
+ /** @deprecated No built-in emitter; retained for external compatibility. */
42
42
  MEMORY_SEARCHED: "unipi:memory:searched",
43
43
  /** Memory consolidation completed */
44
44
  MEMORY_CONSOLIDATED: "unipi:memory:consolidated",
@@ -58,9 +58,9 @@ export const UNIPI_EVENTS = {
58
58
 
59
59
  /** Compactor: compaction completed */
60
60
  COMPACTOR_COMPACTED: "unipi:compactor:compacted",
61
- /** Compactor: stats updated */
61
+ /** @deprecated Footer reads live Pi session data; retained for compatibility. */
62
62
  COMPACTOR_STATS_UPDATED: "unipi:compactor:stats:updated",
63
- /** Utility module cleanup started */
63
+ /** @deprecated No built-in emitter; retained for external compatibility. */
64
64
  UTILITY_CLEANUP_START: "unipi:utility:cleanup:start",
65
65
  /** Utility module cleanup completed */
66
66
  UTILITY_CLEANUP_DONE: "unipi:utility:cleanup:done",
@@ -68,9 +68,9 @@ export const UNIPI_EVENTS = {
68
68
  UTILITY_DIAGNOSTICS_START: "unipi:utility:diagnostics:start",
69
69
  /** Utility diagnostics completed */
70
70
  UTILITY_DIAGNOSTICS_DONE: "unipi:utility:diagnostics:done",
71
- /** Utility cache invalidated */
71
+ /** @deprecated No built-in emitter; retained for external compatibility. */
72
72
  UTILITY_CACHE_INVALIDATED: "unipi:utility:cache:invalidated",
73
- /** Utility lifecycle state changed */
73
+ /** @deprecated No built-in emitter; retained for external compatibility. */
74
74
  UTILITY_LIFECYCLE_STATE: "unipi:utility:lifecycle:state",
75
75
 
76
76
  /** Notification sent */
@@ -91,11 +91,11 @@ export const UNIPI_EVENTS = {
91
91
  /** Update error */
92
92
  UPDATE_ERROR: "unipi:update:error",
93
93
 
94
- /** CocoIndex: update started */
94
+ /** @deprecated Reserved external contract; no built-in emitter. */
95
95
  COCOINDEX_UPDATE_STARTED: "unipi:cocoindex:update:started",
96
- /** CocoIndex: update completed */
96
+ /** @deprecated Reserved external contract; no built-in emitter. */
97
97
  COCOINDEX_UPDATE_COMPLETED: "unipi:cocoindex:update:completed",
98
- /** CocoIndex: search performed */
98
+ /** @deprecated Reserved external contract; no built-in emitter. */
99
99
  COCOINDEX_SEARCH_PERFORMED: "unipi:cocoindex:search:performed",
100
100
  } as const;
101
101
 
@@ -151,13 +151,13 @@ export interface UnipiRalphIterationEvent {
151
151
  nextIteration: number;
152
152
  }
153
153
 
154
- /** Payload for MODULE_STATUS_REQUEST */
154
+ /** @deprecated No built-in responders; retained for compatibility. */
155
155
  export interface UnipiStatusRequestEvent {
156
156
  /** Request ID for correlation */
157
157
  requestId: string;
158
158
  }
159
159
 
160
- /** Payload for MODULE_STATUS_RESPONSE */
160
+ /** @deprecated No built-in aggregator; retained for compatibility. */
161
161
  export interface UnipiStatusResponseEvent {
162
162
  /** Request ID this responds to */
163
163
  requestId: string;
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-unipi/core",
3
- "version": "2.4.0",
3
+ "version": "2.4.1",
4
4
  "description": "Shared utilities, event types, and constants for Unipi extension suite",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -17,7 +17,8 @@
17
17
  ],
18
18
  "files": [
19
19
  "*.ts",
20
- "README.md"
20
+ "README.md",
21
+ "!*.test.ts"
21
22
  ],
22
23
  "publishConfig": {
23
24
  "access": "public"
@@ -22,7 +22,7 @@ Footer subscribes to events from every Unipi package:
22
22
  | Group | Events | Segments |
23
23
  |-------|--------|----------|
24
24
  | core | Pi SDK | model, thinking, path, git, context_pct, cost, tokens, session |
25
- | compactor | `COMPACTOR_STATS_UPDATED` | session_events, compactions, tokens_saved, compression_ratio |
25
+ | compactor | Pi session data + `COMPACTOR_COMPACTED` | session_events, compactions, tokens_saved, compression_ratio |
26
26
  | memory | `MEMORY_STORED`/`DELETED`/`CONSOLIDATED` | project_count, total_count, consolidations |
27
27
  | mcp | `MCP_SERVER_STARTED`/`STOPPED`/`ERROR` | servers_total, servers_active, tools_total |
28
28
  | ralph | `RALPH_LOOP_START`/`END`/`ITERATION_DONE` | active_loops, total_iterations, loop_status |
@@ -48,7 +48,7 @@ Footer works even if packages load after it — late-arriving events update the
48
48
  | Group | Default | Data Source |
49
49
  |-------|---------|-------------|
50
50
  | **core** | ON | Pi SDK (ctx.sessionManager, footerData) |
51
- | **compactor** | ON | `COMPACTOR_STATS_UPDATED` event |
51
+ | **compactor** | ON | Live Pi session data; last-compaction event |
52
52
  | **memory** | ON | `MEMORY_STORED`/`DELETED`/`CONSOLIDATED` events |
53
53
  | **mcp** | ON | `MCP_SERVER_STARTED`/`STOPPED`/`ERROR` events |
54
54
  | **ralph** | ON | `RALPH_LOOP_START`/`END`/`ITERATION_DONE` events |
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "name": "@pi-unipi/footer",
3
- "version": "2.4.0",
3
+ "version": "2.4.1",
4
4
  "description": "Persistent status bar for Unipi — subscribes to UNIPI_EVENTS and renders key stats from all unipi packages",
5
5
  "type": "module",
6
- "main": "src/index.ts",
6
+ "main": "index.ts",
7
7
  "license": "MIT",
8
8
  "author": "Neuron Mr White",
9
9
  "repository": {
@@ -32,7 +32,7 @@
32
32
  "access": "public"
33
33
  },
34
34
  "dependencies": {
35
- "@pi-unipi/core": "2.4.0"
35
+ "@pi-unipi/core": "2.4.1"
36
36
  },
37
37
  "peerDependencies": {
38
38
  "@earendil-works/pi-coding-agent": "^0.80.0",
@@ -26,16 +26,6 @@ export function subscribeToEvents(
26
26
 
27
27
  // ─── Compactor events ───────────────────────────────────────────────────
28
28
 
29
- unsubscribers.push(
30
- pi.events.on(UNIPI_EVENTS.COMPACTOR_STATS_UPDATED, (event: unknown) => {
31
- try {
32
- registry.updateData("compactor", event);
33
- } catch {
34
- // Silently ignore — event handler errors are non-blocking.
35
- }
36
- })
37
- );
38
-
39
29
  unsubscribers.push(
40
30
  pi.events.on(UNIPI_EVENTS.COMPACTOR_COMPACTED, (event: unknown) => {
41
31
  try {
@@ -219,15 +219,6 @@ function renderHostnameSegment(_ctx: FooterSegmentContext): RenderedSegment {
219
219
  return { content, visible: true };
220
220
  }
221
221
 
222
- function renderTimeSegment(ctx: FooterSegmentContext): RenderedSegment {
223
- const now = new Date();
224
- const hours = now.getHours();
225
- const mins = now.getMinutes().toString().padStart(2, "0");
226
- const timeStr = `${hours}:${mins}`;
227
- const content = withIcon("time", timeStr);
228
- return { content, visible: true };
229
- }
230
-
231
222
  // ─── TPS tier color function ────────────────────────────────────────────────
232
223
 
233
224
  function getTpsSemanticColor(tps: number): SemanticColor {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-unipi/image",
3
- "version": "2.4.0",
3
+ "version": "2.4.1",
4
4
  "description": "Image generation and image recognition tools for the Pi coding agent",
5
5
  "type": "module",
6
6
  "main": "src/index.ts",
@@ -34,7 +34,7 @@
34
34
  "access": "public"
35
35
  },
36
36
  "dependencies": {
37
- "@pi-unipi/core": "2.4.0"
37
+ "@pi-unipi/core": "2.4.1"
38
38
  },
39
39
  "peerDependencies": {
40
40
  "@earendil-works/pi-ai": "^0.80.0",
@@ -14,20 +14,6 @@ import { infoRegistry } from "./registry.js";
14
14
  import { parseUsageStatsAsync, formatTokens, formatCost } from "./usage-parser.js";
15
15
  import type { InfoGroup } from "./types.js";
16
16
 
17
- /**
18
- * Get package version from package.json.
19
- */
20
- function getPackageVersion(packageDir: string): string {
21
- try {
22
- const pkgPath = join(packageDir, "package.json");
23
- if (!existsSync(pkgPath)) return "0.0.0";
24
- const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
25
- return pkg?.version ?? "0.0.0";
26
- } catch {
27
- return "0.0.0";
28
- }
29
- }
30
-
31
17
  /**
32
18
  * Discover loaded extensions by scanning filesystem.
33
19
  */
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-unipi/info-screen",
3
- "version": "2.4.0",
3
+ "version": "2.4.1",
4
4
  "description": "Dashboard and module registry for Unipi — configurable info overlay with tabbed groups",
5
5
  "type": "module",
6
6
  "main": "index.ts",
@@ -33,7 +33,7 @@
33
33
  "access": "public"
34
34
  },
35
35
  "dependencies": {
36
- "@pi-unipi/core": "2.4.0"
36
+ "@pi-unipi/core": "2.4.1"
37
37
  },
38
38
  "peerDependencies": {
39
39
  "@earendil-works/pi-coding-agent": "^0.80.0",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-unipi/input-shortcuts",
3
- "version": "2.4.0",
3
+ "version": "2.4.1",
4
4
  "description": "Keyboard shortcuts for stash/restore, undo/redo, clipboard, and thinking toggle — chord-based overlay system",
5
5
  "type": "module",
6
6
  "main": "src/index.ts",
@@ -33,7 +33,7 @@
33
33
  "access": "public"
34
34
  },
35
35
  "dependencies": {
36
- "@pi-unipi/core": "2.4.0"
36
+ "@pi-unipi/core": "2.4.1"
37
37
  },
38
38
  "peerDependencies": {
39
39
  "@earendil-works/pi-coding-agent": "^0.80.0",
@@ -9,7 +9,6 @@ import * as path from "node:path";
9
9
  import type { ExtensionAPI, ExtensionCommandContext } from "@earendil-works/pi-coding-agent";
10
10
  import { UNIPI_PREFIX, KANBOARD_COMMANDS, KANBOARD_DIRS, UNIPI_EVENTS, emitEvent } from "@pi-unipi/core";
11
11
  import { startServer, KanboardServer } from "./server/index.js";
12
- import { renderKanboardOverlay } from "./tui/kanboard-overlay.js";
13
12
 
14
13
  /** Module-level reference to running server */
15
14
  let runningServer: KanboardServer | null = null;
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-unipi/kanboard",
3
- "version": "2.4.0",
3
+ "version": "2.4.1",
4
4
  "description": "Visualization layer for unipi workflow — HTTP server with htmx/Alpine.js UI, modular parsers, TUI overlay, and kanban board",
5
5
  "type": "module",
6
6
  "main": "index.ts",
@@ -39,7 +39,7 @@
39
39
  "access": "public"
40
40
  },
41
41
  "dependencies": {
42
- "@pi-unipi/core": "2.4.0"
42
+ "@pi-unipi/core": "2.4.1"
43
43
  },
44
44
  "peerDependencies": {
45
45
  "@earendil-works/pi-coding-agent": "^0.80.0",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-unipi/mcp",
3
- "version": "2.4.0",
3
+ "version": "2.4.1",
4
4
  "description": "MCP server management extension for Pi coding agent — browse, add, configure, and use MCP servers",
5
5
  "type": "module",
6
6
  "main": "src/index.ts",
@@ -27,7 +27,7 @@
27
27
  "README.md"
28
28
  ],
29
29
  "dependencies": {
30
- "@pi-unipi/core": "2.4.0"
30
+ "@pi-unipi/core": "2.4.1"
31
31
  },
32
32
  "peerDependencies": {
33
33
  "@earendil-works/pi-coding-agent": "^0.80.0",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-unipi/memory",
3
- "version": "2.4.0",
3
+ "version": "2.4.1",
4
4
  "description": "Persistent cross-session memory with MemPalace backend (auto-installed) and SQLite fallback for Pi coding agent",
5
5
  "type": "module",
6
6
  "main": "index.ts",
@@ -43,8 +43,8 @@
43
43
  "better-sqlite3": "^12.9.0",
44
44
  "sqlite-vec": "^0.1.9",
45
45
  "js-yaml": "^4.1.0",
46
- "@pi-unipi/core": "2.4.0",
47
- "@pi-unipi/info-screen": "2.4.0"
46
+ "@pi-unipi/core": "2.4.1",
47
+ "@pi-unipi/info-screen": "2.4.1"
48
48
  },
49
49
  "peerDependencies": {
50
50
  "@earendil-works/pi-coding-agent": "^0.80.0",
@@ -454,24 +454,6 @@ export class MemoryStorage {
454
454
  }
455
455
  }
456
456
 
457
- /**
458
- * Remove corrupted database files (db, wal, shm).
459
- */
460
- private removeCorruptedDb(): void {
461
- const dbPath = path.join(this.scopeDir, MEMORY_DB_NAME);
462
- const files = [dbPath, `${dbPath}-wal`, `${dbPath}-shm`];
463
- for (const file of files) {
464
- try {
465
- if (fs.existsSync(file)) {
466
- fs.unlinkSync(file);
467
- // Removed console.warn — corrupted file cleanup is silent.
468
- }
469
- } catch {
470
- // Ignore removal errors
471
- }
472
- }
473
- }
474
-
475
457
  /**
476
458
  * Check if database is healthy.
477
459
  */
@@ -15,7 +15,6 @@ import {
15
15
  type MemoryRecord,
16
16
  } from "./storage.js";
17
17
  import { generateEmbedding } from "./embedding.js";
18
- import { hybridSearch } from "./search.js";
19
18
 
20
19
  /** Tool names */
21
20
  export const MEMORY_TOOLS = {