@pi-unipi/compactor 0.1.1

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 (65) hide show
  1. package/README.md +86 -0
  2. package/package.json +54 -0
  3. package/skills/compactor/SKILL.md +74 -0
  4. package/skills/compactor-doctor/SKILL.md +74 -0
  5. package/skills/compactor-ops/SKILL.md +65 -0
  6. package/skills/compactor-stats/SKILL.md +49 -0
  7. package/skills/compactor-tools/SKILL.md +120 -0
  8. package/src/commands/index.ts +248 -0
  9. package/src/compaction/brief.ts +334 -0
  10. package/src/compaction/build-sections.ts +77 -0
  11. package/src/compaction/content.ts +47 -0
  12. package/src/compaction/cut.ts +80 -0
  13. package/src/compaction/extract/commits.ts +52 -0
  14. package/src/compaction/extract/files.ts +58 -0
  15. package/src/compaction/extract/goals.ts +36 -0
  16. package/src/compaction/extract/preferences.ts +40 -0
  17. package/src/compaction/filter-noise.ts +46 -0
  18. package/src/compaction/format.ts +48 -0
  19. package/src/compaction/hooks.ts +145 -0
  20. package/src/compaction/merge.ts +113 -0
  21. package/src/compaction/normalize.ts +68 -0
  22. package/src/compaction/recall-scope.ts +32 -0
  23. package/src/compaction/sanitize.ts +12 -0
  24. package/src/compaction/search-entries.ts +101 -0
  25. package/src/compaction/sections.ts +15 -0
  26. package/src/compaction/summarize.ts +29 -0
  27. package/src/config/manager.ts +89 -0
  28. package/src/config/presets.ts +83 -0
  29. package/src/config/schema.ts +55 -0
  30. package/src/display/bash-display.ts +28 -0
  31. package/src/display/diff-presentation.ts +20 -0
  32. package/src/display/diff-renderer.ts +255 -0
  33. package/src/display/line-width-safety.ts +16 -0
  34. package/src/display/pending-diff-preview.ts +51 -0
  35. package/src/display/render-utils.ts +52 -0
  36. package/src/display/thinking-label.ts +18 -0
  37. package/src/display/tool-overrides.ts +136 -0
  38. package/src/display/user-message-box.ts +16 -0
  39. package/src/executor/executor.ts +242 -0
  40. package/src/executor/runtime.ts +125 -0
  41. package/src/index.ts +211 -0
  42. package/src/info-screen.ts +60 -0
  43. package/src/security/evaluator.ts +142 -0
  44. package/src/security/policy.ts +74 -0
  45. package/src/security/scanner.ts +65 -0
  46. package/src/session/db.ts +237 -0
  47. package/src/session/extract.ts +107 -0
  48. package/src/session/resume-inject.ts +25 -0
  49. package/src/session/snapshot.ts +326 -0
  50. package/src/store/chunking.ts +126 -0
  51. package/src/store/db-base.ts +79 -0
  52. package/src/store/index.ts +364 -0
  53. package/src/tools/compact.ts +20 -0
  54. package/src/tools/ctx-batch-execute.ts +53 -0
  55. package/src/tools/ctx-doctor.ts +78 -0
  56. package/src/tools/ctx-execute-file.ts +26 -0
  57. package/src/tools/ctx-execute.ts +21 -0
  58. package/src/tools/ctx-fetch-and-index.ts +37 -0
  59. package/src/tools/ctx-index.ts +42 -0
  60. package/src/tools/ctx-search.ts +23 -0
  61. package/src/tools/ctx-stats.ts +37 -0
  62. package/src/tools/register.ts +360 -0
  63. package/src/tools/vcc-recall.ts +64 -0
  64. package/src/tui/settings-overlay.ts +290 -0
  65. package/src/types.ts +269 -0
@@ -0,0 +1,290 @@
1
+ /**
2
+ * @pi-unipi/compactor — TUI Settings Overlay
3
+ *
4
+ * Interactive settings editor for compactor configuration.
5
+ * Navigate strategies, toggle on/off, cycle modes, apply presets.
6
+ */
7
+
8
+ import type { Component } from "@mariozechner/pi-tui";
9
+ import { truncateToWidth } from "@mariozechner/pi-tui";
10
+ import { loadConfig, saveConfig } from "../config/manager.js";
11
+ import { applyPreset, detectPreset } from "../config/presets.js";
12
+ import type { CompactorPreset } from "../types.js";
13
+ import type { CompactorConfig } from "../types.js";
14
+
15
+ /** ANSI escape codes */
16
+ const ansi = {
17
+ reset: "\x1b[0m",
18
+ bold: "\x1b[1m",
19
+ dim: "\x1b[2m",
20
+ cyan: "\x1b[36m",
21
+ green: "\x1b[32m",
22
+ yellow: "\x1b[33m",
23
+ red: "\x1b[31m",
24
+ gray: "\x1b[90m",
25
+ magenta: "\x1b[35m",
26
+ };
27
+
28
+ const TOGGLE_ON = `${ansi.green}●${ansi.reset}`;
29
+ const TOGGLE_OFF = `${ansi.dim}○${ansi.reset}`;
30
+
31
+ /** Strategy item definition */
32
+ interface StrategyItem {
33
+ key: string;
34
+ label: string;
35
+ description: string;
36
+ modes: string[];
37
+ getEnabled: (c: CompactorConfig) => boolean;
38
+ setEnabled: (c: CompactorConfig, v: boolean) => void;
39
+ getMode: (c: CompactorConfig) => string;
40
+ setMode: (c: CompactorConfig, v: string) => void;
41
+ }
42
+
43
+ /** All configurable strategies */
44
+ const STRATEGIES: StrategyItem[] = [
45
+ {
46
+ key: "sessionGoals",
47
+ label: "Session Goals",
48
+ description: "Extract goals from conversation",
49
+ modes: ["full", "minimal"],
50
+ getEnabled: (c) => c.sessionGoals.enabled,
51
+ setEnabled: (c, v) => (c.sessionGoals.enabled = v),
52
+ getMode: (c) => c.sessionGoals.mode,
53
+ setMode: (c, v) => (c.sessionGoals.mode = v as any),
54
+ },
55
+ {
56
+ key: "filesAndChanges",
57
+ label: "Files & Changes",
58
+ description: "Track file activity",
59
+ modes: ["all", "modified", "none"],
60
+ getEnabled: (c) => c.filesAndChanges.enabled,
61
+ setEnabled: (c, v) => (c.filesAndChanges.enabled = v),
62
+ getMode: (c) => c.filesAndChanges.mode,
63
+ setMode: (c, v) => (c.filesAndChanges.mode = v as any),
64
+ },
65
+ {
66
+ key: "commits",
67
+ label: "Commits",
68
+ description: "Extract git commits",
69
+ modes: ["full", "minimal", "none"],
70
+ getEnabled: (c) => c.commits.enabled,
71
+ setEnabled: (c, v) => (c.commits.enabled = v),
72
+ getMode: (c) => c.commits.mode,
73
+ setMode: (c, v) => (c.commits.mode = v as any),
74
+ },
75
+ {
76
+ key: "outstandingContext",
77
+ label: "Outstanding Context",
78
+ description: "Track blockers and pending items",
79
+ modes: ["full", "minimal"],
80
+ getEnabled: (c) => c.outstandingContext.enabled,
81
+ setEnabled: (c, v) => (c.outstandingContext.enabled = v),
82
+ getMode: (c) => c.outstandingContext.mode,
83
+ setMode: (c, v) => (c.outstandingContext.mode = v as any),
84
+ },
85
+ {
86
+ key: "userPreferences",
87
+ label: "User Preferences",
88
+ description: "Track learned preferences",
89
+ modes: ["all", "minimal"],
90
+ getEnabled: (c) => c.userPreferences.enabled,
91
+ setEnabled: (c, v) => (c.userPreferences.enabled = v),
92
+ getMode: (c) => c.userPreferences.mode,
93
+ setMode: (c, v) => (c.userPreferences.mode = v as any),
94
+ },
95
+ {
96
+ key: "briefTranscript",
97
+ label: "Brief Transcript",
98
+ description: "Rolling window of recent messages",
99
+ modes: ["full", "compact", "minimal"],
100
+ getEnabled: (c) => c.briefTranscript.enabled,
101
+ setEnabled: (c, v) => (c.briefTranscript.enabled = v),
102
+ getMode: (c) => c.briefTranscript.mode,
103
+ setMode: (c, v) => (c.briefTranscript.mode = v as any),
104
+ },
105
+ {
106
+ key: "sessionContinuity",
107
+ label: "Session Continuity",
108
+ description: "XML resume snapshot for compaction survival",
109
+ modes: ["full", "minimal"],
110
+ getEnabled: (c) => c.sessionContinuity.enabled,
111
+ setEnabled: (c, v) => (c.sessionContinuity.enabled = v),
112
+ getMode: (c) => c.sessionContinuity.mode,
113
+ setMode: (c, v) => (c.sessionContinuity.mode = v as any),
114
+ },
115
+ {
116
+ key: "fts5Index",
117
+ label: "FTS5 Index",
118
+ description: "Full-text search index",
119
+ modes: ["auto", "manual", "disabled"],
120
+ getEnabled: (c) => c.fts5Index.enabled,
121
+ setEnabled: (c, v) => (c.fts5Index.enabled = v),
122
+ getMode: (c) => c.fts5Index.mode,
123
+ setMode: (c, v) => (c.fts5Index.mode = v as any),
124
+ },
125
+ {
126
+ key: "sandboxExecution",
127
+ label: "Sandbox Execution",
128
+ description: "Polyglot code execution",
129
+ modes: ["all", "safe", "none"],
130
+ getEnabled: (c) => c.sandboxExecution.enabled,
131
+ setEnabled: (c, v) => (c.sandboxExecution.enabled = v),
132
+ getMode: (c) => c.sandboxExecution.mode,
133
+ setMode: (c, v) => (c.sandboxExecution.mode = v as any),
134
+ },
135
+ {
136
+ key: "toolDisplay",
137
+ label: "Tool Display",
138
+ description: "Override tool output rendering",
139
+ modes: ["opencode", "summary", "verbose", "minimal"],
140
+ getEnabled: (c) => c.toolDisplay.enabled,
141
+ setEnabled: (c, v) => (c.toolDisplay.enabled = v),
142
+ getMode: (c) => c.toolDisplay.mode,
143
+ setMode: (c, v) => (c.toolDisplay.mode = v as any),
144
+ },
145
+ ];
146
+
147
+ const PRESETS: CompactorPreset[] = ["opencode", "balanced", "verbose", "minimal"];
148
+
149
+ /**
150
+ * Settings overlay component for compactor configuration.
151
+ */
152
+ export class CompactorSettingsOverlay implements Component {
153
+ private config: CompactorConfig;
154
+ private selectedIndex = 0;
155
+ private mode = "strategy" as "strategy" | "preset";
156
+ private presetIndex = 0;
157
+ onClose?: () => void;
158
+
159
+ constructor() {
160
+ this.config = loadConfig();
161
+ const currentPreset = detectPreset(this.config);
162
+ this.presetIndex = PRESETS.indexOf(currentPreset as CompactorPreset);
163
+ if (this.presetIndex < 0) this.presetIndex = 0;
164
+ }
165
+
166
+ invalidate(): void {}
167
+
168
+ handleInput(data: string): void {
169
+ switch (data) {
170
+ case "\x1b[A": // Up
171
+ case "k":
172
+ if (this.mode === "strategy") {
173
+ this.selectedIndex = (this.selectedIndex - 1 + STRATEGIES.length) % STRATEGIES.length;
174
+ } else {
175
+ this.presetIndex = (this.presetIndex - 1 + PRESETS.length) % PRESETS.length;
176
+ }
177
+ break;
178
+ case "\x1b[B": // Down
179
+ case "j":
180
+ if (this.mode === "strategy") {
181
+ this.selectedIndex = (this.selectedIndex + 1) % STRATEGIES.length;
182
+ } else {
183
+ this.presetIndex = (this.presetIndex + 1) % PRESETS.length;
184
+ }
185
+ break;
186
+ case " ": // Space - toggle enabled
187
+ if (this.mode === "strategy") {
188
+ const item = STRATEGIES[this.selectedIndex];
189
+ item.setEnabled(this.config, !item.getEnabled(this.config));
190
+ }
191
+ break;
192
+ case "\x1b[C": // Right - cycle mode forward
193
+ case "\r": // Enter
194
+ if (this.mode === "strategy") {
195
+ const strat = STRATEGIES[this.selectedIndex];
196
+ const modes = strat.modes;
197
+ const currentIdx = modes.indexOf(strat.getMode(this.config));
198
+ const nextIdx = (currentIdx + 1) % modes.length;
199
+ strat.setMode(this.config, modes[nextIdx]);
200
+ } else {
201
+ // Apply preset
202
+ this.config = applyPreset(PRESETS[this.presetIndex]);
203
+ this.mode = "strategy";
204
+ }
205
+ break;
206
+ case "\x1b[D": // Left - cycle mode backward
207
+ if (this.mode === "strategy") {
208
+ const strat2 = STRATEGIES[this.selectedIndex];
209
+ const modes2 = strat2.modes;
210
+ const curIdx = modes2.indexOf(strat2.getMode(this.config));
211
+ const prevIdx = (curIdx - 1 + modes2.length) % modes2.length;
212
+ strat2.setMode(this.config, modes2[prevIdx]);
213
+ }
214
+ break;
215
+ case "p": // Toggle preset mode
216
+ this.mode = this.mode === "preset" ? "strategy" : "preset";
217
+ break;
218
+ case "s": // Save
219
+ saveConfig(this.config);
220
+ this.onClose?.();
221
+ break;
222
+ case "\x1b": // Escape - cancel
223
+ this.onClose?.();
224
+ break;
225
+ }
226
+ }
227
+
228
+ render(width: number): string[] {
229
+ const lines: string[] = [];
230
+ const add = (s: string) => lines.push(truncateToWidth(s, width));
231
+
232
+ // Header
233
+ add(`${ansi.bold}${ansi.cyan}🗜️ Compactor Settings${ansi.reset}`);
234
+ const presetName = detectPreset(this.config);
235
+ add(`${ansi.dim}Preset: ${presetName === "custom" ? "custom (modified)" : presetName}${ansi.reset}`);
236
+ add("");
237
+
238
+ if (this.mode === "preset") {
239
+ // Preset selection
240
+ add(`${ansi.bold}Select Preset:${ansi.reset}`);
241
+ add("");
242
+ for (let i = 0; i < PRESETS.length; i++) {
243
+ const isSelected = i === this.presetIndex;
244
+ const prefix = isSelected ? `${ansi.cyan}▸${ansi.reset}` : " ";
245
+ const label = isSelected ? `${ansi.bold}${PRESETS[i]}${ansi.reset}` : PRESETS[i];
246
+ add(`${prefix} ${label}`);
247
+ }
248
+ add("");
249
+ add(`${ansi.dim}↑↓ navigate • Enter apply • p back to strategies • s save • Esc cancel${ansi.reset}`);
250
+ } else {
251
+ // Strategy list
252
+ for (let i = 0; i < STRATEGIES.length; i++) {
253
+ const item = STRATEGIES[i];
254
+ const isSelected = i === this.selectedIndex;
255
+ const enabled = item.getEnabled(this.config);
256
+ const mode = item.getMode(this.config);
257
+ const toggle = enabled ? TOGGLE_ON : TOGGLE_OFF;
258
+ const labelColor = isSelected ? ansi.bold : "";
259
+ const modeColor = ansi.magenta;
260
+ const descColor = ansi.gray;
261
+
262
+ const cursor = isSelected ? `${ansi.cyan}▸${ansi.reset}` : " ";
263
+ add(`${cursor} ${toggle} ${labelColor}${item.label}${ansi.reset} ${modeColor}[${mode}]${ansi.reset}`);
264
+ add(` ${descColor}${item.description}${ansi.reset}`);
265
+ }
266
+
267
+ add("");
268
+ add(`${ansi.dim}↑↓ navigate • Space toggle • ←→ cycle mode • p presets • s save • Esc cancel${ansi.reset}`);
269
+ }
270
+
271
+ return lines;
272
+ }
273
+ }
274
+
275
+ /**
276
+ * Factory function for ctx.ui.custom() integration.
277
+ * Returns a render function compatible with pi-tui's custom overlay API.
278
+ */
279
+ export function renderSettingsOverlay() {
280
+ return (tui: any, _theme: any, _kb: any, done: (result: any) => void) => {
281
+ const overlay = new CompactorSettingsOverlay();
282
+ overlay.onClose = () => done(overlay);
283
+
284
+ return {
285
+ render: (width: number) => overlay.render(width),
286
+ invalidate: () => {},
287
+ handleInput: (data: string) => overlay.handleInput(data),
288
+ };
289
+ };
290
+ }
package/src/types.ts ADDED
@@ -0,0 +1,269 @@
1
+ /**
2
+ * @pi-unipi/compactor — Shared TypeScript types
3
+ */
4
+
5
+ import type { Message } from "@mariozechner/pi-ai";
6
+
7
+ // ─────────────────────────────────────────────────────────
8
+ // Normalized blocks (from pi-vcc)
9
+ // ─────────────────────────────────────────────────────────
10
+
11
+ export interface FileOps {
12
+ readFiles?: string[];
13
+ modifiedFiles?: string[];
14
+ createdFiles?: string[];
15
+ }
16
+
17
+ export type NormalizedBlock =
18
+ | { kind: "user"; text: string; sourceIndex?: number }
19
+ | { kind: "assistant"; text: string; sourceIndex?: number }
20
+ | { kind: "tool_call"; name: string; args: Record<string, unknown>; sourceIndex?: number }
21
+ | { kind: "tool_result"; name: string; text: string; isError: boolean; sourceIndex?: number }
22
+ | { kind: "thinking"; text: string; redacted: boolean; sourceIndex?: number };
23
+
24
+ // ─────────────────────────────────────────────────────────
25
+ // Section data (from pi-vcc)
26
+ // ─────────────────────────────────────────────────────────
27
+
28
+ export interface SectionData {
29
+ sessionGoal: string[];
30
+ filesAndChanges: string[];
31
+ commits: string[];
32
+ outstandingContext: string[];
33
+ userPreferences: string[];
34
+ briefTranscript: string;
35
+ transcriptEntries: TranscriptEntry[];
36
+ }
37
+
38
+ export interface TranscriptEntry {
39
+ role: "user" | "assistant" | "tool_error";
40
+ text?: string;
41
+ tool?: string;
42
+ cmd?: string;
43
+ ref?: string;
44
+ count?: number;
45
+ }
46
+
47
+ export interface BriefLine {
48
+ header: string;
49
+ lines: string[];
50
+ }
51
+
52
+ // ─────────────────────────────────────────────────────────
53
+ // Compaction input / output
54
+ // ─────────────────────────────────────────────────────────
55
+
56
+ export interface CompileInput {
57
+ messages: Message[];
58
+ previousSummary?: string;
59
+ fileOps?: FileOps;
60
+ }
61
+
62
+ export interface CompactionStats {
63
+ summarized: number;
64
+ kept: number;
65
+ keptTokensEst: number;
66
+ }
67
+
68
+ export type OwnCutCancelReason =
69
+ | "no_live_messages"
70
+ | "too_few_live_messages"
71
+ | "no_user_message";
72
+
73
+ export type OwnCutResult =
74
+ | { ok: true; messages: any[]; firstKeptEntryId: string; compactAll: boolean }
75
+ | { ok: false; reason: OwnCutCancelReason };
76
+
77
+ // ─────────────────────────────────────────────────────────
78
+ // Configuration
79
+ // ─────────────────────────────────────────────────────────
80
+
81
+ export interface CompactorStrategyConfig {
82
+ enabled: boolean;
83
+ mode: string;
84
+ }
85
+
86
+ export interface CompactorConfig {
87
+ // Compaction strategies
88
+ sessionGoals: CompactorStrategyConfig & { mode: "full" | "brief" | "off" };
89
+ filesAndChanges: CompactorStrategyConfig & { mode: "all" | "modified-only" | "off"; maxPerCategory: number };
90
+ commits: CompactorStrategyConfig & { mode: "full" | "brief" | "off"; maxCommits: number };
91
+ outstandingContext: CompactorStrategyConfig & { mode: "full" | "critical-only" | "off"; maxItems: number };
92
+ userPreferences: CompactorStrategyConfig & { mode: "all" | "recent-only" | "off"; maxPreferences: number };
93
+ briefTranscript: CompactorStrategyConfig & { mode: "full" | "compact" | "minimal" | "off"; userTokenLimit: number; assistantTokenLimit: number; toolCallLimit: number };
94
+ sessionContinuity: CompactorStrategyConfig & { mode: "full" | "essential-only" | "off"; eventCategories: string[] };
95
+ fts5Index: CompactorStrategyConfig & { mode: "auto" | "manual" | "off"; chunkSize: number; cacheTtlHours: number };
96
+ sandboxExecution: CompactorStrategyConfig & { mode: "all" | "safe-only" | "off"; allowedLanguages: string[]; outputLimit: number };
97
+ toolDisplay: CompactorStrategyConfig & { mode: "opencode" | "balanced" | "verbose" | "custom"; diffLayout: "auto" | "split" | "unified"; diffIndicator: "bars" | "classic" | "none"; showThinkingLabels: boolean; showUserMessageBox: boolean; showBashSpinner: boolean; showPendingPreviews: boolean };
98
+
99
+ // Global settings
100
+ overrideDefaultCompaction: boolean;
101
+ debug: boolean;
102
+ showTruncationHints: boolean;
103
+ }
104
+
105
+ export type CompactorPreset = "opencode" | "balanced" | "verbose" | "minimal" | "custom";
106
+
107
+ // ─────────────────────────────────────────────────────────
108
+ // Session events (from context-mode)
109
+ // ─────────────────────────────────────────────────────────
110
+
111
+ export interface SessionEvent {
112
+ type: string;
113
+ category: string;
114
+ data: string;
115
+ priority: number;
116
+ data_hash: string;
117
+ project_dir?: string;
118
+ attribution_source?: string;
119
+ attribution_confidence?: number;
120
+ }
121
+
122
+ export interface StoredEvent {
123
+ id: number;
124
+ session_id: string;
125
+ type: string;
126
+ category: string;
127
+ priority: number;
128
+ data: string;
129
+ project_dir: string;
130
+ attribution_source: string;
131
+ attribution_confidence: number;
132
+ source_hook: string;
133
+ created_at: string;
134
+ data_hash: string;
135
+ }
136
+
137
+ export interface SessionMeta {
138
+ session_id: string;
139
+ project_dir: string;
140
+ started_at: string;
141
+ last_event_at: string | null;
142
+ event_count: number;
143
+ compact_count: number;
144
+ }
145
+
146
+ export interface ResumeRow {
147
+ snapshot: string;
148
+ event_count: number;
149
+ consumed: number;
150
+ }
151
+
152
+ export interface ResumeSnapshot {
153
+ generatedAt: string;
154
+ summary: string;
155
+ events: SessionEvent[];
156
+ }
157
+
158
+ // ─────────────────────────────────────────────────────────
159
+ // Execution (from context-mode)
160
+ // ─────────────────────────────────────────────────────────
161
+
162
+ export interface ExecResult {
163
+ stdout: string;
164
+ stderr: string;
165
+ exitCode: number;
166
+ timedOut: boolean;
167
+ backgrounded?: boolean;
168
+ }
169
+
170
+ export type Language =
171
+ | "javascript"
172
+ | "typescript"
173
+ | "python"
174
+ | "shell"
175
+ | "ruby"
176
+ | "go"
177
+ | "rust"
178
+ | "php"
179
+ | "perl"
180
+ | "r"
181
+ | "elixir";
182
+
183
+ // ─────────────────────────────────────────────────────────
184
+ // Content store (from context-mode)
185
+ // ─────────────────────────────────────────────────────────
186
+
187
+ export interface IndexResult {
188
+ sourceId: number;
189
+ label: string;
190
+ totalChunks: number;
191
+ codeChunks: number;
192
+ }
193
+
194
+ export interface SearchResult {
195
+ title: string;
196
+ content: string;
197
+ source: string;
198
+ rank: number;
199
+ contentType: "code" | "prose";
200
+ matchLayer?: "porter" | "trigram" | "fuzzy" | "rrf" | "rrf-fuzzy";
201
+ highlighted?: string;
202
+ }
203
+
204
+ export interface StoreStats {
205
+ sources: number;
206
+ chunks: number;
207
+ codeChunks: number;
208
+ }
209
+
210
+ // ─────────────────────────────────────────────────────────
211
+ // Security (from context-mode)
212
+ // ─────────────────────────────────────────────────────────
213
+
214
+ export type PermissionDecision = "allow" | "deny" | "ask";
215
+
216
+ export interface SecurityPolicy {
217
+ allow: string[];
218
+ deny: string[];
219
+ ask: string[];
220
+ }
221
+
222
+ // ─────────────────────────────────────────────────────────
223
+ // Display (from pi-tool-display)
224
+ // ─────────────────────────────────────────────────────────
225
+
226
+ export type DiffLayout = "auto" | "split" | "unified";
227
+ export type DiffIndicator = "bars" | "classic" | "none";
228
+ export type OutputMode = "hidden" | "summary" | "preview" | "count";
229
+
230
+ export interface ToolDisplayConfig {
231
+ registerToolOverrides: {
232
+ read: boolean;
233
+ grep: boolean;
234
+ find: boolean;
235
+ ls: boolean;
236
+ bash: boolean;
237
+ edit: boolean;
238
+ write: boolean;
239
+ };
240
+ enableNativeUserMessageBox: boolean;
241
+ readOutputMode: OutputMode;
242
+ searchOutputMode: OutputMode;
243
+ mcpOutputMode: OutputMode;
244
+ previewLines: number;
245
+ expandedPreviewMaxLines: number;
246
+ bashOutputMode: OutputMode;
247
+ bashCollapsedLines: number;
248
+ diffViewMode: DiffLayout;
249
+ diffIndicatorMode: DiffIndicator;
250
+ diffSplitMinWidth: number;
251
+ diffCollapsedLines: number;
252
+ diffWordWrap: boolean;
253
+ showTruncationHints: boolean;
254
+ showRtkCompactionHints: boolean;
255
+ }
256
+
257
+ // ─────────────────────────────────────────────────────────
258
+ // Info-screen integration
259
+ // ─────────────────────────────────────────────────────────
260
+
261
+ export interface CompactorInfoData {
262
+ sessionEvents: { value: string; detail: string };
263
+ compactions: { value: string; detail: string };
264
+ tokensSaved: { value: string; detail: string };
265
+ compressionRatio: { value: string; detail: string };
266
+ indexedDocs: { value: string; detail: string };
267
+ sandboxExecutions: { value: string; detail: string };
268
+ searchQueries: { value: string; detail: string };
269
+ }