@pi-unipi/unipi 2.6.1 → 2.6.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 (186) hide show
  1. package/package.json +1 -2
  2. package/packages/ask-user/settings-tui.ts +18 -34
  3. package/packages/autocomplete/src/constants.ts +0 -15
  4. package/packages/autocomplete/src/provider.ts +3 -17
  5. package/packages/btw/extensions/btw.ts +18 -45
  6. package/packages/compactor/README.md +2 -2
  7. package/packages/compactor/skills/compactor/SKILL.md +1 -1
  8. package/packages/compactor/skills/compactor-detail/SKILL.md +3 -5
  9. package/packages/compactor/skills/compactor-doctor/SKILL.md +1 -1
  10. package/packages/compactor/skills/compactor-stats/SKILL.md +1 -1
  11. package/packages/compactor/src/commands/index.ts +47 -78
  12. package/packages/compactor/src/compaction/brief.ts +161 -90
  13. package/packages/compactor/src/compaction/build-sections.ts +3 -4
  14. package/packages/compactor/src/compaction/compact-args.ts +86 -0
  15. package/packages/compactor/src/compaction/cut.ts +270 -28
  16. package/packages/compactor/src/compaction/drill-down.ts +261 -0
  17. package/packages/compactor/src/compaction/format-recall.ts +96 -0
  18. package/packages/compactor/src/compaction/format.ts +8 -3
  19. package/packages/compactor/src/compaction/hooks.ts +248 -72
  20. package/packages/compactor/src/compaction/merge.ts +34 -4
  21. package/packages/compactor/src/compaction/rank.ts +270 -0
  22. package/packages/compactor/src/compaction/recall-scope.ts +28 -0
  23. package/packages/compactor/src/compaction/search-entries.ts +333 -96
  24. package/packages/compactor/src/compaction/skill-collapse.ts +35 -0
  25. package/packages/compactor/src/compaction/summarize.ts +37 -6
  26. package/packages/compactor/src/compaction/token-estimate.ts +104 -0
  27. package/packages/compactor/src/compaction/touched-files.ts +35 -0
  28. package/packages/compactor/src/config/manager.ts +2 -27
  29. package/packages/compactor/src/config/presets.ts +0 -2
  30. package/packages/compactor/src/config/schema.ts +2 -16
  31. package/packages/compactor/src/executor/executor.ts +6 -15
  32. package/packages/compactor/src/executor/runtime.ts +2 -12
  33. package/packages/compactor/src/index.ts +4 -121
  34. package/packages/compactor/src/info-screen.ts +3 -10
  35. package/packages/compactor/src/security/evaluator.ts +0 -53
  36. package/packages/compactor/src/security/policy.ts +7 -8
  37. package/packages/compactor/src/session/db.ts +0 -6
  38. package/packages/compactor/src/tools/ctx-execute-file.ts +0 -5
  39. package/packages/compactor/src/tools/register.ts +27 -50
  40. package/packages/compactor/src/tools/vcc-recall.ts +86 -48
  41. package/packages/compactor/src/tui/settings-overlay.ts +20 -40
  42. package/packages/compactor/src/types.ts +43 -100
  43. package/packages/core/constants.ts +0 -28
  44. package/packages/core/events.ts +1 -83
  45. package/packages/core/index.ts +1 -0
  46. package/packages/core/package.json +2 -0
  47. package/packages/core/tui-overlay.ts +89 -0
  48. package/packages/core/tui-width.ts +18 -0
  49. package/packages/core/utils.ts +43 -0
  50. package/packages/footer/src/help.ts +2 -2
  51. package/packages/footer/src/index.ts +9 -10
  52. package/packages/footer/src/presets.ts +1 -27
  53. package/packages/footer/src/registry/index.ts +0 -23
  54. package/packages/footer/src/rendering/icons.ts +0 -13
  55. package/packages/footer/src/rendering/renderer.ts +5 -40
  56. package/packages/footer/src/rendering/separators.ts +0 -10
  57. package/packages/footer/src/rendering/theme.ts +1 -15
  58. package/packages/footer/src/segments/compactor.ts +7 -14
  59. package/packages/footer/src/segments/core.ts +15 -54
  60. package/packages/footer/src/segments/kanboard.ts +5 -5
  61. package/packages/footer/src/segments/mcp.ts +5 -5
  62. package/packages/footer/src/segments/memory.ts +4 -4
  63. package/packages/footer/src/segments/notify.ts +2 -2
  64. package/packages/footer/src/segments/ralph.ts +3 -3
  65. package/packages/footer/src/segments/status-ext.ts +1 -1
  66. package/packages/footer/src/segments/workflow.ts +3 -3
  67. package/packages/footer/src/tps-tracker.ts +0 -8
  68. package/packages/footer/src/tui/settings-tui.ts +14 -31
  69. package/packages/footer/src/types.ts +0 -15
  70. package/packages/image/src/register-providers.ts +0 -11
  71. package/packages/image/src/tools.ts +0 -3
  72. package/packages/image/src/tui/model-selector.ts +36 -71
  73. package/packages/info-screen/config.ts +0 -16
  74. package/packages/info-screen/core-groups.ts +0 -10
  75. package/packages/info-screen/index.ts +22 -13
  76. package/packages/info-screen/registry.ts +1 -72
  77. package/packages/info-screen/tui/info-overlay.ts +85 -100
  78. package/packages/info-screen/usage-parser.ts +12 -47
  79. package/packages/input-shortcuts/src/index.ts +3 -3
  80. package/packages/input-shortcuts/src/registers.ts +0 -8
  81. package/packages/input-shortcuts/src/settings-overlay.ts +4 -13
  82. package/packages/input-shortcuts/src/undo-redo.ts +0 -12
  83. package/packages/mcp/src/bridge/client.ts +0 -15
  84. package/packages/mcp/src/config/manager.ts +0 -38
  85. package/packages/mcp/src/config/schema.ts +0 -27
  86. package/packages/mcp/src/config/sync.ts +0 -29
  87. package/packages/mcp/src/index.ts +1 -1
  88. package/packages/mcp/src/tui/add-overlay.ts +6 -6
  89. package/packages/mcp/src/types.ts +0 -6
  90. package/packages/memory/embedding.ts +0 -31
  91. package/packages/memory/mempalace.ts +0 -16
  92. package/packages/memory/package.json +2 -6
  93. package/packages/memory/storage.ts +56 -753
  94. package/packages/milestone/hooks.ts +1 -6
  95. package/packages/milestone/milestone.ts +2 -41
  96. package/packages/notify/events.ts +0 -10
  97. package/packages/notify/settings.ts +0 -19
  98. package/packages/notify/tui/gotify-setup.ts +108 -143
  99. package/packages/notify/tui/ntfy-setup.ts +137 -172
  100. package/packages/notify/tui/recap-model-selector.ts +36 -71
  101. package/packages/notify/tui/settings-overlay.ts +50 -86
  102. package/packages/notify/tui/telegram-setup.ts +48 -79
  103. package/packages/notify/types.ts +0 -2
  104. package/packages/ralph/index.ts +11 -35
  105. package/packages/ralph/ralph-loop.ts +3 -44
  106. package/packages/subagents/package.json +1 -0
  107. package/packages/subagents/src/agent-manager.ts +0 -51
  108. package/packages/subagents/src/agent-runner.ts +6 -80
  109. package/packages/subagents/src/conversation-viewer.ts +1 -19
  110. package/packages/subagents/src/core-compat.ts +8 -25
  111. package/packages/subagents/src/custom-agents.ts +0 -1
  112. package/packages/subagents/src/index.ts +3 -48
  113. package/packages/subagents/src/types.ts +0 -11
  114. package/packages/subagents/src/widget.ts +5 -5
  115. package/packages/unipi/bundled.js +4330 -7707
  116. package/packages/unipi/index.ts +6 -3
  117. package/packages/updater/src/changelog.ts +1 -16
  118. package/packages/updater/src/index.ts +0 -5
  119. package/packages/updater/src/installer.ts +4 -26
  120. package/packages/updater/src/markdown.ts +6 -152
  121. package/packages/updater/src/settings.ts +0 -15
  122. package/packages/updater/src/tui/changelog-overlay.ts +42 -234
  123. package/packages/updater/src/tui/list-detail-overlay.ts +260 -0
  124. package/packages/updater/src/tui/readme-overlay.ts +53 -210
  125. package/packages/updater/src/tui/settings-overlay.ts +13 -26
  126. package/packages/updater/src/version.ts +2 -31
  127. package/packages/utility/package.json +1 -3
  128. package/packages/utility/src/commands.ts +4 -5
  129. package/packages/utility/src/herdr-sync.ts +136 -0
  130. package/packages/utility/src/index.ts +11 -68
  131. package/packages/utility/src/lifecycle/cleanup.ts +2 -16
  132. package/packages/utility/src/{diff/settings.ts → settings.ts} +42 -80
  133. package/packages/utility/src/tools/env.ts +0 -0
  134. package/packages/utility/src/tui/name-badge-state.ts +18 -2
  135. package/packages/utility/src/tui/name-badge.ts +5 -4
  136. package/packages/utility/src/tui/util-settings-tui.ts +41 -224
  137. package/packages/web-api/package.json +0 -4
  138. package/packages/web-api/src/engine/dependencies.ts +13 -134
  139. package/packages/web-api/src/engine/extract.ts +9 -99
  140. package/packages/web-api/src/engine/format.ts +0 -75
  141. package/packages/web-api/src/engine/types.ts +0 -39
  142. package/packages/web-api/src/index.ts +1 -2
  143. package/packages/web-api/src/providers/base.ts +0 -10
  144. package/packages/web-api/src/providers/duckduckgo.ts +0 -1
  145. package/packages/web-api/src/providers/firecrawl.ts +0 -9
  146. package/packages/web-api/src/providers/jina-reader.ts +0 -9
  147. package/packages/web-api/src/providers/jina-search.ts +0 -9
  148. package/packages/web-api/src/providers/perplexity.ts +0 -9
  149. package/packages/web-api/src/providers/registry.ts +0 -80
  150. package/packages/web-api/src/providers/serpapi.ts +0 -9
  151. package/packages/web-api/src/providers/tavily.ts +0 -9
  152. package/packages/web-api/src/providers/wigolo-client.ts +0 -30
  153. package/packages/web-api/src/providers/wigolo.ts +0 -1
  154. package/packages/web-api/src/settings.ts +17 -77
  155. package/packages/web-api/src/tools.ts +21 -24
  156. package/packages/web-api/src/tui/settings-dialog.ts +0 -1
  157. package/packages/workflow/commands.ts +38 -122
  158. package/packages/workflow/index.ts +1 -5
  159. package/packages/cocoindex/README.md +0 -94
  160. package/packages/cocoindex/bridge.ts +0 -842
  161. package/packages/cocoindex/commands.ts +0 -175
  162. package/packages/cocoindex/index.ts +0 -48
  163. package/packages/cocoindex/installer.ts +0 -397
  164. package/packages/cocoindex/package.json +0 -49
  165. package/packages/cocoindex/skills/cocoindex/SKILL.md +0 -88
  166. package/packages/cocoindex/tools.ts +0 -157
  167. package/packages/compactor/src/display/diff-renderer.ts +0 -281
  168. package/packages/compactor/src/display/line-width-safety.ts +0 -28
  169. package/packages/compactor/src/display/render-utils.ts +0 -52
  170. package/packages/compactor/src/display/thinking-label.ts +0 -18
  171. package/packages/compactor/src/display/tool-overrides.ts +0 -136
  172. package/packages/compactor/src/tools/compact.ts +0 -20
  173. package/packages/subagents/src/file-lock.ts +0 -102
  174. package/packages/utility/src/cache/ttl-cache.ts +0 -311
  175. package/packages/utility/src/diff/highlighter.ts +0 -352
  176. package/packages/utility/src/diff/parser.ts +0 -191
  177. package/packages/utility/src/diff/renderer.ts +0 -395
  178. package/packages/utility/src/diff/theme.ts +0 -316
  179. package/packages/utility/src/diff/wrapper.ts +0 -339
  180. package/packages/utility/src/display/capabilities.ts +0 -214
  181. package/packages/utility/src/display/width.ts +0 -226
  182. package/packages/utility/src/tools/batch.ts +0 -229
  183. package/packages/utility/src/tui/badge-settings-tui.ts +0 -388
  184. package/packages/utility/src/tui/badge-settings.ts +0 -67
  185. package/packages/utility/src/tui/settings-inspector.ts +0 -303
  186. package/packages/web-api/src/providers/llm-summarize.ts +0 -71
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-unipi/unipi",
3
- "version": "2.6.1",
3
+ "version": "2.6.2",
4
4
  "description": "All-in-one extension suite for Pi coding agent",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -66,7 +66,6 @@
66
66
  "packages/milestone/skills",
67
67
  "packages/kanboard/skills",
68
68
  "packages/updater/skills",
69
- "packages/cocoindex/skills",
70
69
  "packages/image/skills"
71
70
  ]
72
71
  },
@@ -6,26 +6,13 @@
6
6
  */
7
7
 
8
8
  import type { Component } from "@earendil-works/pi-tui";
9
- import { truncateToWidth, visibleWidth } from "@earendil-works/pi-tui";
10
- import { adaptiveInnerWidth, normalizeWidth, safeRepeat, shouldRenderBorder } from "@pi-unipi/core";
9
+ import { Key, matchesKey, truncateToWidth, visibleWidth } from "@earendil-works/pi-tui";
10
+ import { adaptiveInnerWidth, normalizeWidth, safeRepeat, shouldRenderBorder, ansi, TOGGLE_ON, TOGGLE_OFF } from "@pi-unipi/core";
11
11
  import { getAskUserSettings, saveAskUserSettings, type AskUserSettings } from "./config.js";
12
12
 
13
13
  /** ANSI escape codes */
14
- const ansi = {
15
- reset: "\x1b[0m",
16
- bold: "\x1b[1m",
17
- dim: "\x1b[2m",
18
- // Colors
19
- cyan: "\x1b[36m",
20
- green: "\x1b[32m",
21
- yellow: "\x1b[33m",
22
- red: "\x1b[31m",
23
- gray: "\x1b[90m",
24
- };
25
14
 
26
15
  /** Toggle symbols */
27
- const TOGGLE_ON = `${ansi.green}●${ansi.reset}`;
28
- const TOGGLE_OFF = `${ansi.dim}○${ansi.reset}`;
29
16
 
30
17
  /** Setting items */
31
18
  interface SettingItem {
@@ -99,25 +86,22 @@ export class AskUserSettingsOverlay implements Component {
99
86
  * Handle keyboard input.
100
87
  */
101
88
  handleInput(data: string): void {
102
- switch (data) {
103
- case "\x1b[A": // Up
104
- case "k":
105
- this.selectedIndex = (this.selectedIndex - 1 + SETTINGS.length) % SETTINGS.length;
106
- break;
107
- case "\x1b[B": // Down
108
- case "j":
109
- this.selectedIndex = (this.selectedIndex + 1) % SETTINGS.length;
110
- break;
111
- case " ": // Space - toggle
112
- this.toggleSetting(SETTINGS[this.selectedIndex].key);
113
- break;
114
- case "\r": // Enter - save and close
115
- this.save();
116
- this.onClose?.();
117
- break;
118
- case "\x1b": // Escape - close without saving
119
- this.onClose?.();
120
- break;
89
+ if (matchesKey(data, Key.up) || data === "k") {
90
+ // Up
91
+ this.selectedIndex = (this.selectedIndex - 1 + SETTINGS.length) % SETTINGS.length;
92
+ } else if (matchesKey(data, Key.down) || data === "j") {
93
+ // Down
94
+ this.selectedIndex = (this.selectedIndex + 1) % SETTINGS.length;
95
+ } else if (matchesKey(data, Key.space)) {
96
+ // Space - toggle
97
+ this.toggleSetting(SETTINGS[this.selectedIndex].key);
98
+ } else if (matchesKey(data, Key.enter)) {
99
+ // Enter - save and close
100
+ this.save();
101
+ this.onClose?.();
102
+ } else if (matchesKey(data, Key.escape)) {
103
+ // Escape - close without saving
104
+ this.onClose?.();
121
105
  }
122
106
  }
123
107
 
@@ -33,7 +33,6 @@ export const PACKAGE_ORDER: string[] = [
33
33
  "footer",
34
34
  "updater",
35
35
  "input-shortcuts",
36
- "cocoindex",
37
36
  "image",
38
37
  ];
39
38
 
@@ -56,7 +55,6 @@ export const PACKAGE_COLORS: Record<string, string> = {
56
55
  footer: `${ESC}[34m`, // Blue
57
56
  updater: `${ESC}[93m`, // Bright Yellow
58
57
  "input-shortcuts": `${ESC}[95m`, // Bright Magenta
59
- cocoindex: `${ESC}[97m`, // Bright White
60
58
  image: `${ESC}[35m`, // Magenta
61
59
  };
62
60
 
@@ -151,12 +149,6 @@ export const COMMAND_REGISTRY: Record<string, string> = {
151
149
  "unipi:compact-preset": "compact",
152
150
  "unipi:compact-help": "compact",
153
151
 
154
- // cocoindex (5 commands)
155
- "unipi:cocoindex-update": "cocoindex",
156
- "unipi:cocoindex-status": "cocoindex",
157
- "unipi:cocoindex-init": "cocoindex",
158
- "unipi:cocoindex-search": "cocoindex",
159
- "unipi:cocoindex-settings": "cocoindex",
160
152
 
161
153
  // milestone (2 commands)
162
154
  "unipi:milestone-onboard": "milestone",
@@ -271,12 +263,6 @@ export const COMMAND_DESCRIPTIONS: Record<string, string> = {
271
263
  "unipi:compact-settings": "Configure compaction settings",
272
264
  "unipi:compact-preset": "Manage compaction presets",
273
265
  "unipi:compact-help": "Show compactor command help",
274
- "unipi:cocoindex-update": "Run CocoIndex update to index project",
275
- "unipi:cocoindex-status": "Show CocoIndex indexing status",
276
- "unipi:cocoindex-init": "Initialize CocoIndex pipeline",
277
- "unipi:cocoindex-search": "Search indexed codebase semantically",
278
- "unipi:cocoindex-settings": "Show CocoIndex configuration",
279
-
280
266
  "unipi:notify-settings": "Configure notification platforms and events",
281
267
  "unipi:notify-set-gotify": "Set up Gotify push notifications",
282
268
  "unipi:notify-set-tg": "Set up Telegram bot notifications",
@@ -318,6 +304,5 @@ export const PACKAGE_LABELS: Record<string, string> = {
318
304
  footer: "footer",
319
305
  updater: "updater",
320
306
  "input-shortcuts": "input-shortcuts",
321
- cocoindex: "cocoindex",
322
307
  image: "image",
323
308
  };
@@ -11,7 +11,7 @@ import type {
11
11
  AutocompleteProvider,
12
12
  AutocompleteSuggestions,
13
13
  } from "@earendil-works/pi-tui";
14
- import { fuzzyFilter } from "@earendil-works/pi-tui";
14
+ import { fuzzyMatch as piFuzzyMatch } from "@earendil-works/pi-tui";
15
15
 
16
16
  import {
17
17
  COMMAND_REGISTRY,
@@ -27,20 +27,6 @@ import {
27
27
  } from "./sorting.js";
28
28
  import type { TaggedItem } from "./sorting.js";
29
29
 
30
- // ─── Fuzzy matching ──────────────────────────────────────────────────
31
-
32
- /** Simple character-subsequence fuzzy match (case-insensitive) */
33
- function fuzzyMatch(text: string, query: string): boolean {
34
- if (!query) return true;
35
- const lower = text.toLowerCase();
36
- const q = query.toLowerCase();
37
- let qi = 0;
38
- for (let i = 0; i < lower.length && qi < q.length; i++) {
39
- if (lower[i] === q[qi]) qi++;
40
- }
41
- return qi === q.length;
42
- }
43
-
44
30
  // ─── Namespace detection ─────────────────────────────────────────────
45
31
 
46
32
  /**
@@ -131,9 +117,9 @@ function getEnhancedUnipiItems(
131
117
  // commands surface when the user hasn't typed the full prefix.
132
118
  matched = entries.filter(([cmd]) => {
133
119
  if (isPastUnipiColon) {
134
- return fuzzyMatch(cmd.replace("unipi:", "").toLowerCase(), query);
120
+ return piFuzzyMatch(query, cmd.replace("unipi:", "").toLowerCase()).matches;
135
121
  }
136
- return fuzzyMatch(cmd.toLowerCase(), query);
122
+ return piFuzzyMatch(query, cmd.toLowerCase()).matches;
137
123
  });
138
124
  }
139
125
 
@@ -606,9 +606,8 @@ function applyAssistantMessageToTranscript(
606
606
  message: AssistantMessage,
607
607
  streaming: boolean,
608
608
  ): void {
609
- const assistantMessage = message;
610
- const thinking = extractThinking(assistantMessage);
611
- const answer = extractMessageText(assistantMessage);
609
+ const thinking = extractThinking(message);
610
+ const answer = extractMessageText(message);
612
611
 
613
612
  if (thinking) {
614
613
  upsertTranscriptTextEntry(state, turnId, "thinking", thinking, streaming);
@@ -972,11 +971,6 @@ function getOverlayTitle(mode: BtwThreadMode): string {
972
971
 
973
972
  class BtwOverlayComponent extends Container implements Focusable {
974
973
  private readonly input: Input;
975
- private readonly transcript: Container;
976
- private readonly statusText: Text;
977
- private readonly modeText: Text;
978
- private readonly summaryText: Text;
979
- private readonly hintsText: Text;
980
974
  private readonly readTranscriptEntries: () => BtwTranscript;
981
975
  private readonly getStatus: () => string | null;
982
976
  private readonly getMode: () => BtwThreadMode;
@@ -1025,11 +1019,6 @@ class BtwOverlayComponent extends Container implements Focusable {
1025
1019
  this.onDismissCallback = onDismiss;
1026
1020
  this.onUnfocusCallback = onUnfocus;
1027
1021
 
1028
- this.modeText = new Text("", 1, 0);
1029
- this.summaryText = new Text("", 1, 0);
1030
- this.transcript = new Container();
1031
- this.statusText = new Text("", 1, 0);
1032
-
1033
1022
  this.input = new Input();
1034
1023
  this.input.onSubmit = (value) => {
1035
1024
  this.followTranscript = true;
@@ -1039,8 +1028,6 @@ class BtwOverlayComponent extends Container implements Focusable {
1039
1028
  this.onDismissCallback();
1040
1029
  };
1041
1030
 
1042
- this.hintsText = new Text("", 1, 0);
1043
-
1044
1031
  const originalHandleInput = this.input.handleInput.bind(this.input);
1045
1032
  this.input.handleInput = (data: string) => {
1046
1033
  if (keybindings.matches(data, "tui.select.cancel")) {
@@ -1092,14 +1079,14 @@ class BtwOverlayComponent extends Container implements Focusable {
1092
1079
  return;
1093
1080
  }
1094
1081
 
1095
- if (matchesKey(data, Key.pageUp)) {
1082
+ if (matchesKey(data, Key.pageUp) || matchesKey(data, Key.ctrl("pageUp")) || matchesKey(data, Key.alt("pageUp"))) {
1096
1083
  this.followTranscript = false;
1097
1084
  this.transcriptScrollOffset = Math.max(0, this.transcriptScrollOffset - Math.max(1, this.transcriptViewportHeight - 1));
1098
1085
  this.tui.requestRender();
1099
1086
  return;
1100
1087
  }
1101
1088
 
1102
- if (matchesKey(data, Key.pageDown)) {
1089
+ if (matchesKey(data, Key.pageDown) || matchesKey(data, Key.ctrl("pageDown")) || matchesKey(data, Key.alt("pageDown"))) {
1103
1090
  this.transcriptScrollOffset += Math.max(1, this.transcriptViewportHeight - 1);
1104
1091
  this.tui.requestRender();
1105
1092
  return;
@@ -1182,30 +1169,18 @@ class BtwOverlayComponent extends Container implements Focusable {
1182
1169
  return this.input.getValue();
1183
1170
  }
1184
1171
 
1185
- getTranscriptEntries(): BtwTranscript {
1186
- return this.readTranscriptEntries().map((entry) => ({ ...entry }));
1187
- }
1188
-
1189
1172
  refresh(): void {
1190
1173
  this.modeTextValue = `${getOverlayTitle(this.getMode())} · hidden thread preserved`;
1191
- this.modeText.setText(this.modeTextValue);
1192
1174
  const entries = this.readTranscriptEntries();
1193
1175
  const exchanges = getCompletedExchangeCount(entries);
1194
1176
  const active = hasStreamingTranscriptEntry(entries) ? " · streaming" : " · idle";
1195
1177
  this.summaryTextValue = `${exchanges} exchange${exchanges === 1 ? "" : "s"}${active}`;
1196
- this.summaryText.setText(this.summaryTextValue);
1197
1178
 
1198
1179
  this.transcriptLines = buildOverlayTranscript(entries, this.theme);
1199
- this.transcript.clear();
1200
- for (const line of this.transcriptLines) {
1201
- this.transcript.addChild(new Text(line, 1, 0));
1202
- }
1203
1180
 
1204
1181
  const status = this.getStatus() ?? "Ready. Enter submits; Escape dismisses without clearing.";
1205
1182
  this.statusTextValue = status;
1206
- this.statusText.setText(this.statusTextValue);
1207
- this.hintsTextValue = "Enter submit · Alt+/ toggle focus · Escape dismiss · PgUp/PgDn scroll";
1208
- this.hintsText.setText(this.hintsTextValue);
1183
+ this.hintsTextValue = "Enter submit · Alt+/ toggle focus · Escape dismiss · PgUp/Ctrl+PgUp scroll up · PgDn/Ctrl+PgDn scroll down";
1209
1184
  this.tui.requestRender();
1210
1185
  }
1211
1186
  }
@@ -1498,7 +1473,7 @@ export default function (pi: ExtensionAPI) {
1498
1473
  });
1499
1474
  }
1500
1475
 
1501
- async function dispatchBtwCommand(name: string, args: string, ctx: ExtensionCommandContext): Promise<boolean> {
1476
+ async function dispatchBtwCommand(name: string, args: string, ctx: ExtensionCommandContext): Promise<void> {
1502
1477
  const trimmedArgs = args.trim();
1503
1478
 
1504
1479
  if (name === "btw") {
@@ -1506,7 +1481,7 @@ export default function (pi: ExtensionAPI) {
1506
1481
  if (!question) {
1507
1482
  await ensureBtwSession(ctx, pendingMode);
1508
1483
  await ensureOverlay(ctx);
1509
- return true;
1484
+ return;
1510
1485
  }
1511
1486
 
1512
1487
  if (pendingMode !== "contextual") {
@@ -1514,7 +1489,7 @@ export default function (pi: ExtensionAPI) {
1514
1489
  }
1515
1490
 
1516
1491
  await runBtw(ctx, question, save, "contextual");
1517
- return true;
1492
+ return;
1518
1493
  }
1519
1494
 
1520
1495
  if (name === "btw:tangent") {
@@ -1526,11 +1501,11 @@ export default function (pi: ExtensionAPI) {
1526
1501
  if (!question) {
1527
1502
  await ensureBtwSession(ctx, "tangent");
1528
1503
  await ensureOverlay(ctx);
1529
- return true;
1504
+ return;
1530
1505
  }
1531
1506
 
1532
1507
  await runBtw(ctx, question, save, "tangent");
1533
- return true;
1508
+ return;
1534
1509
  }
1535
1510
 
1536
1511
  if (name === "btw:new") {
@@ -1544,20 +1519,20 @@ export default function (pi: ExtensionAPI) {
1544
1519
  await ensureOverlay(ctx);
1545
1520
  notify(ctx, "Started a fresh BTW thread.", "info");
1546
1521
  }
1547
- return true;
1522
+ return;
1548
1523
  }
1549
1524
 
1550
1525
  if (name === "btw:clear") {
1551
1526
  await resetThread(ctx);
1552
1527
  dismissOverlay();
1553
1528
  notify(ctx, "Cleared BTW thread.", "info");
1554
- return true;
1529
+ return;
1555
1530
  }
1556
1531
 
1557
1532
  if (name === "btw:inject") {
1558
1533
  if (pendingThread.length === 0) {
1559
1534
  notify(ctx, "No BTW thread to inject.", "warning");
1560
- return true;
1535
+ return;
1561
1536
  }
1562
1537
 
1563
1538
  setOverlayStatus("⏳ injecting into the main session...", ctx);
@@ -1579,13 +1554,13 @@ export default function (pi: ExtensionAPI) {
1579
1554
  setOverlayStatus("Inject failed. Thread preserved for retry or summarize.", ctx);
1580
1555
  notify(ctx, error instanceof Error ? error.message : String(error), "error");
1581
1556
  }
1582
- return true;
1557
+ return;
1583
1558
  }
1584
1559
 
1585
1560
  if (name === "btw:summarize") {
1586
1561
  if (pendingThread.length === 0) {
1587
1562
  notify(ctx, "No BTW thread to summarize.", "warning");
1588
- return true;
1563
+ return;
1589
1564
  }
1590
1565
 
1591
1566
  setOverlayStatus("⏳ summarizing...", ctx);
@@ -1608,10 +1583,8 @@ export default function (pi: ExtensionAPI) {
1608
1583
  setOverlayStatus("Summarize failed. Thread preserved for retry or injection.", ctx);
1609
1584
  notify(ctx, error instanceof Error ? error.message : String(error), "error");
1610
1585
  }
1611
- return true;
1586
+ return;
1612
1587
  }
1613
-
1614
- return false;
1615
1588
  }
1616
1589
 
1617
1590
  function parseOverlayBtwCommand(value: string): { name: string; args: string } | null {
@@ -1817,7 +1790,7 @@ export default function (pi: ExtensionAPI) {
1817
1790
 
1818
1791
  async function getBtwHandoffThread(
1819
1792
  ctx: ExtensionCommandContext,
1820
- ): Promise<{ sessionRuntime: BtwSessionRuntime | null; thread: BtwHandoffExchange[] }> {
1793
+ ): Promise<{ thread: BtwHandoffExchange[] }> {
1821
1794
  const sessionRuntime = activeBtwSession ?? (await ensureBtwSession(ctx, pendingMode));
1822
1795
  const thread = sessionRuntime ? extractBtwHandoffThread(sessionRuntime) : [];
1823
1796
  const resolvedThread = thread.length > 0 ? thread : getPendingThreadForHandoff();
@@ -1826,7 +1799,7 @@ export default function (pi: ExtensionAPI) {
1826
1799
  throw new Error("No BTW thread available for handoff.");
1827
1800
  }
1828
1801
 
1829
- return { sessionRuntime, thread: resolvedThread };
1802
+ return { thread: resolvedThread };
1830
1803
  }
1831
1804
 
1832
1805
  async function summarizeThread(ctx: ExtensionCommandContext, thread: BtwHandoffExchange[]): Promise<string> {
@@ -51,7 +51,7 @@ Per-project config is merged over global config when the current project directo
51
51
  | `/unipi:compact-preset <name>` | Applies a preset globally. | Names: `precise`, `balanced`, `thorough`, `lean`. Old names map to new ones: `opencode→precise`, `verbose→thorough`, `minimal→lean`. |
52
52
  | `/unipi:compact-help` | Shows compact help inside Pi. | Quick command reference. |
53
53
 
54
- Content/project indexing is handled by `@pi-unipi/cocoindex`, not this package. Use `/unipi:cocoindex-init`, `/unipi:cocoindex-update`, and `cocoindex_search` for indexed project search.
54
+ Content/project indexing is not part of this package. Use `read`/`bash` (rg) for project search.
55
55
 
56
56
  ---
57
57
 
@@ -102,7 +102,7 @@ These settings control what is extracted into compaction summaries or how relate
102
102
  | `Session Continuity` | `full`, `off` | Controls XML-style resume snapshots. Off prevents snapshot creation and injection; Pi’s normal compaction summary still remains. |
103
103
  | `Sandbox Execution` | `all`, `off` | Controls sandbox tool registration. Changes require a session reload. Allowed languages and output limit are enforced from config. |
104
104
 
105
- Config-only legacy field: `fts5Index` remains in the schema for compatibility, but project indexing has moved to `@pi-unipi/cocoindex`. It is hidden from Compactor settings and presets. Legacy `sessionContinuity.mode: "essential-only"`, `eventCategories`, and `sandboxExecution.mode: "safe-only"` values remain loadable; essential-only behaves as full and safe-only behaves as enabled/all until explicit filtering/security policies are designed. Legacy `toolDisplay` and `showTruncationHints` fields also remain loadable but are deprecated and ignored; their profile names were never mapped to runtime renderer modes. Narrow-terminal diff clamping remains active as independent safety behavior.
105
+ Config-only legacy field: `fts5Index` remains in the schema for compatibility. It is hidden from Compactor settings and presets. Legacy `sessionContinuity.mode: "essential-only"`, `eventCategories`, and `sandboxExecution.mode: "safe-only"` values remain loadable; essential-only behaves as full and safe-only behaves as enabled/all until explicit filtering/security policies are designed. Legacy `toolDisplay` and `showTruncationHints` fields also remain loadable but are deprecated and ignored; their profile names were never mapped to runtime renderer modes. Narrow-terminal diff clamping remains active as independent safety behavior.
106
106
 
107
107
  ### Auto tab
108
108
 
@@ -12,7 +12,7 @@ description: Context management — compact session, recall history, run code, s
12
12
 
13
13
  ## Finding Past Work
14
14
  - `session_recall(query)` → search this session (BM25 or regex), including raw messages that may no longer be in live context after compaction.
15
- - For indexed project/file search, use the CocoIndex package (`cocoindex_search`) when installed; content indexing no longer lives in compactor.
15
+ - For project/file search, use `read`/`bash` (rg) directly; content indexing is not part of compactor.
16
16
 
17
17
  ## Running Code
18
18
  - `sandbox(lang, code)` → single script. `sandbox_batch(items)` → atomic.
@@ -88,7 +88,7 @@ Estimate remaining context tokens and percent full. Uses Pi's live context usage
88
88
  ## Anti-Patterns
89
89
 
90
90
  1. **Don't compact in a tight loop.** Use `context_budget` first and compact at natural break points.
91
- 2. **Don't use `session_recall` for project-wide code search.** It searches the conversation/session. Use CocoIndex (`cocoindex_search`) for indexed files when installed.
91
+ 2. **Don't use `session_recall` for project-wide code search.** It searches the conversation/session only use `read`/`bash`(rg) for files.
92
92
  3. **Don't use `sandbox` for file operations.** Use normal file tools for reads/writes; sandbox is for computation or quick scripts.
93
93
  4. **Don't use empty or vague recall queries.** Search for specific filenames, issue numbers, commands, or decisions.
94
94
  5. **Don't compact mid-thought if avoidable.** Finish the current step, then compact.
@@ -112,7 +112,5 @@ Estimate remaining context tokens and percent full. Uses Pi's live context usage
112
112
  3. `compactor_stats` — confirm compactions/savings are recorded.
113
113
 
114
114
  ### Project Search
115
- Compactor no longer owns project content indexing. Use the CocoIndex package if installed:
116
- 1. `/unipi:cocoindex-init`
117
- 2. `/unipi:cocoindex-update`
118
- 3. `cocoindex_search(query)`
115
+ Compactor does not own project content indexing. For code search use `bash` with rg.
116
+ 1. `bash` with `rg` for code search
@@ -68,4 +68,4 @@ python3 --version
68
68
  bash --version
69
69
  ```
70
70
 
71
- Project content indexing diagnostics live in the CocoIndex package, not compactor.
71
+ Project content indexing is not part of compactor.
@@ -48,4 +48,4 @@ This means:
48
48
  - 3 compactions saved roughly 15K tokens.
49
49
  - 7 sandbox executions and 15 recall/search queries were recorded.
50
50
 
51
- Project content indexing stats are not owned by compactor anymore; use the CocoIndex package for indexed file search/status.
51
+ Project content indexing stats are not owned by compactor; use `read`/`bash` (rg) for file search.
@@ -8,13 +8,14 @@
8
8
  import type { ExtensionAPI, ExtensionCommandContext } from "@earendil-works/pi-coding-agent";
9
9
  import { loadConfig, saveConfig } from "../config/manager.js";
10
10
  import { applyPreset, parsePreset } from "../config/presets.js";
11
- import { COMPACTOR_INSTRUCTION } from "@pi-unipi/core";
12
- import { getLastCompactionStats } from "../compaction/hooks.js";
11
+ import { COMPACTOR_INSTRUCTION, formatTokens } from "@pi-unipi/core";
12
+ import { getLastCompactionStats, formatCompactionStats } from "../compaction/hooks.js";
13
13
  import { vccRecall } from "../tools/vcc-recall.js";
14
14
  import { ctxStats } from "../tools/ctx-stats.js";
15
15
  import { ctxDoctor } from "../tools/ctx-doctor.js";
16
16
  import { recallBlocksFromContext } from "../session/recall-blocks.js";
17
17
  import { filterNoise } from "../compaction/filter-noise.js";
18
+ import { parseRecallScope } from "../compaction/recall-scope.js";
18
19
  import type { SessionDB } from "../session/db.js";
19
20
  import type { NormalizedBlock, RuntimeCounters } from "../types.js";
20
21
 
@@ -25,77 +26,55 @@ export interface CommandDeps {
25
26
  getCounters?: () => RuntimeCounters;
26
27
  }
27
28
 
28
- function deprecationLog(_oldName: string, _newName: string): void {
29
- // Deprecation logging disabled — was writing to stdout causing TUI rendering issues.
30
- }
31
-
32
- const formatTokens = (n: number): string => {
33
- if (n >= 1000) return `${(n / 1000).toFixed(1)}k`;
34
- return String(n);
35
- };
36
-
37
29
  export function registerCommands(pi: ExtensionAPI, deps?: CommandDeps): void {
38
30
  // ── /unipi:lossless-compact ──────────────────────────
31
+ const losslessCompactHandler = async (_args: string, ctx: ExtensionCommandContext) => {
32
+ ctx.compact({
33
+ customInstructions: COMPACTOR_INSTRUCTION,
34
+ onComplete: () => {
35
+ const stats = getLastCompactionStats();
36
+ if (stats) {
37
+ ctx.ui.notify(formatCompactionStats(stats), "info");
38
+ } else {
39
+ ctx.ui.notify("Compaction completed.", "info");
40
+ }
41
+ },
42
+ onError: (err: Error) => {
43
+ if (err.message === "Compaction cancelled" || err.message === "Already compacted") {
44
+ ctx.ui.notify("Nothing to compact.", "info");
45
+ } else {
46
+ ctx.ui.notify(`Compaction failed: ${err.message}`, "error");
47
+ }
48
+ },
49
+ });
50
+ };
39
51
  pi.registerCommand("unipi:lossless-compact", {
40
52
  description: "Immediate zero-LLM compaction — structured summary with full recall",
41
- handler: async (_args: string, ctx: ExtensionCommandContext) => {
42
- ctx.compact({
43
- customInstructions: COMPACTOR_INSTRUCTION,
44
- onComplete: () => {
45
- const stats = getLastCompactionStats();
46
- if (stats) {
47
- ctx.ui.notify(
48
- `Compacted ${stats.totalMessages} messages (~${formatTokens(stats.tokensBefore)} tokens) → ${stats.kept} messages (~${formatTokens(stats.tokensAfterEst)} tokens)`,
49
- "info",
50
- );
51
- } else {
52
- ctx.ui.notify("Compaction completed.", "info");
53
- }
54
- },
55
- onError: (err: Error) => {
56
- if (err.message === "Compaction cancelled" || err.message === "Already compacted") {
57
- ctx.ui.notify("Nothing to compact.", "info");
58
- } else {
59
- ctx.ui.notify(`Compaction failed: ${err.message}`, "error");
60
- }
61
- },
62
- });
63
- },
53
+ handler: losslessCompactHandler,
64
54
  });
65
- // Deprecated alias — old name
66
55
  pi.registerCommand("unipi:compact", {
67
- description: "(DEPRECATED) Use /unipi:lossless-compact instead",
68
- handler: async (_args: string, ctx: ExtensionCommandContext) => {
69
- deprecationLog("/unipi:compact", "/unipi:lossless-compact");
70
- ctx.compact({
71
- customInstructions: COMPACTOR_INSTRUCTION,
72
- onComplete: () => {
73
- const stats = getLastCompactionStats();
74
- if (stats) {
75
- ctx.ui.notify(
76
- `Compacted ${stats.totalMessages} messages (~${formatTokens(stats.tokensBefore)} tokens) → ${stats.kept} messages (~${formatTokens(stats.tokensAfterEst)} tokens)`,
77
- "info",
78
- );
79
- } else {
80
- ctx.ui.notify("Compaction completed.", "info");
81
- }
82
- },
83
- onError: (err: Error) => {
84
- if (err.message === "Compaction cancelled" || err.message === "Already compacted") {
85
- ctx.ui.notify("Nothing to compact.", "info");
86
- } else {
87
- ctx.ui.notify(`Compaction failed: ${err.message}`, "error");
88
- }
89
- },
90
- });
91
- },
56
+ description: "Alias for /unipi:lossless-compact",
57
+ handler: losslessCompactHandler,
92
58
  });
93
59
 
94
60
  // ── /unipi:session-recall (new) ─────────────────────
61
+ // pi-vcc parity: results are sent as a visible custom message AND fed to the
62
+ // agent as context (triggerTurn), so recall results drive the next turn.
95
63
  const sessionRecallHandler = async (args: string, ctx: ExtensionCommandContext, commandName = "/unipi:session-recall") => {
96
- const query = args.trim();
64
+ const raw = args.trim();
65
+ const suffix = commandName === "/unipi:compact-recall" ? " (deprecated; use /unipi:session-recall <query>)" : "";
66
+ if (!raw) {
67
+ ctx.ui.notify(`Usage: ${commandName} <query>${suffix}`, "warning");
68
+ return;
69
+ }
70
+
71
+ // Parse scope:all and page:N inline (pi-vcc parity)
72
+ const parsed = parseRecallScope(raw);
73
+ const pageMatch = parsed.text.match(/\bpage:(\d+)\b/i);
74
+ const page = pageMatch ? Math.max(1, parseInt(pageMatch[1], 10)) : 1;
75
+ const query = parsed.text.replace(/\bpage:\d+\b/i, "").trim();
76
+
97
77
  if (!query) {
98
- const suffix = commandName === "/unipi:compact-recall" ? " (deprecated; use /unipi:session-recall <query>)" : "";
99
78
  ctx.ui.notify(`Usage: ${commandName} <query>${suffix}`, "warning");
100
79
  return;
101
80
  }
@@ -109,25 +88,20 @@ export function registerCommands(pi: ExtensionAPI, deps?: CommandDeps): void {
109
88
  ctx.ui.notify("No session history available for search.", "warning");
110
89
  return;
111
90
  }
112
- const result = vccRecall(blocks, { query, limit: 10 });
113
- if (result.hits.length === 0) {
114
- ctx.ui.notify(`No results for "${query}".`, "info");
115
- return;
116
- }
117
- const lines = result.hits.map(
118
- (h, i) => `[${i + 1}] score=${h.score.toFixed(2)} kind=${h.kind}\n${h.text.slice(0, 200)}`,
91
+ const result = vccRecall(blocks, { query, scope: parsed.scope, page });
92
+ pi.sendMessage(
93
+ { customType: "compactor-recall", content: result.text, display: true },
94
+ { triggerTurn: true },
119
95
  );
120
- ctx.ui.notify(`Found ${result.total} results:\n${lines.join("\n\n")}`, "info");
121
96
  };
122
97
  pi.registerCommand("unipi:session-recall", {
123
- description: "Search session history (BM25 or regex)",
98
+ description: "Recall earlier parts of this session. Plain keywords work best; add scope:all to reach edited or retried turns.",
124
99
  handler: sessionRecallHandler,
125
100
  });
126
101
  // Deprecated alias
127
102
  pi.registerCommand("unipi:compact-recall", {
128
103
  description: "(DEPRECATED) Search session history — use /unipi:session-recall instead",
129
104
  handler: async (args: string, ctx: ExtensionCommandContext) => {
130
- deprecationLog("/unipi:compact-recall", "/unipi:session-recall");
131
105
  return sessionRecallHandler(args, ctx, "/unipi:compact-recall");
132
106
  },
133
107
  });
@@ -233,12 +207,7 @@ export function registerCommands(pi: ExtensionAPI, deps?: CommandDeps): void {
233
207
  " /unipi:compact-preset <name> — apply preset\n" +
234
208
  "\n" +
235
209
  "Percentage trigger:\n" +
236
- " Disabled by default. Enable in /unipi:compact-settings to compact at a context % before Pi's reserve-token limit.\n" +
237
- "\n" +
238
- "Content indexing has moved to @pi-unipi/cocoindex:\n" +
239
- " /unipi:cocoindex-init — initialize pipeline\n" +
240
- " /unipi:cocoindex-update — index project files\n" +
241
- " cocoindex_search — search indexed content",
210
+ " Disabled by default. Enable in /unipi:compact-settings to compact at a context % before Pi's reserve-token limit.",
242
211
  "info",
243
212
  );
244
213
  },