@pi-unipi/unipi 2.6.0 → 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.
- package/CHANGELOG.md +19 -0
- package/package.json +21 -22
- package/packages/ask-user/package.json +2 -2
- package/packages/ask-user/settings-tui.ts +18 -34
- package/packages/autocomplete/package.json +1 -1
- package/packages/autocomplete/src/constants.ts +2 -15
- package/packages/autocomplete/src/provider.ts +3 -17
- package/packages/btw/extensions/btw.ts +18 -45
- package/packages/btw/package.json +2 -2
- package/packages/compactor/README.md +2 -2
- package/packages/compactor/package.json +3 -3
- package/packages/compactor/skills/compactor/SKILL.md +1 -1
- package/packages/compactor/skills/compactor-detail/SKILL.md +3 -5
- package/packages/compactor/skills/compactor-doctor/SKILL.md +1 -1
- package/packages/compactor/skills/compactor-stats/SKILL.md +1 -1
- package/packages/compactor/src/commands/index.ts +47 -78
- package/packages/compactor/src/compaction/brief.ts +161 -90
- package/packages/compactor/src/compaction/build-sections.ts +3 -4
- package/packages/compactor/src/compaction/compact-args.ts +86 -0
- package/packages/compactor/src/compaction/cut.ts +270 -28
- package/packages/compactor/src/compaction/drill-down.ts +261 -0
- package/packages/compactor/src/compaction/format-recall.ts +96 -0
- package/packages/compactor/src/compaction/format.ts +8 -3
- package/packages/compactor/src/compaction/hooks.ts +248 -72
- package/packages/compactor/src/compaction/merge.ts +34 -4
- package/packages/compactor/src/compaction/rank.ts +270 -0
- package/packages/compactor/src/compaction/recall-scope.ts +28 -0
- package/packages/compactor/src/compaction/search-entries.ts +333 -96
- package/packages/compactor/src/compaction/skill-collapse.ts +35 -0
- package/packages/compactor/src/compaction/summarize.ts +37 -6
- package/packages/compactor/src/compaction/token-estimate.ts +104 -0
- package/packages/compactor/src/compaction/touched-files.ts +35 -0
- package/packages/compactor/src/config/manager.ts +2 -27
- package/packages/compactor/src/config/presets.ts +0 -2
- package/packages/compactor/src/config/schema.ts +2 -16
- package/packages/compactor/src/executor/executor.ts +6 -15
- package/packages/compactor/src/executor/runtime.ts +2 -12
- package/packages/compactor/src/index.ts +4 -121
- package/packages/compactor/src/info-screen.ts +3 -10
- package/packages/compactor/src/security/evaluator.ts +0 -53
- package/packages/compactor/src/security/policy.ts +7 -8
- package/packages/compactor/src/session/db.ts +0 -6
- package/packages/compactor/src/tools/ctx-execute-file.ts +0 -5
- package/packages/compactor/src/tools/register.ts +27 -50
- package/packages/compactor/src/tools/vcc-recall.ts +86 -48
- package/packages/compactor/src/tui/settings-overlay.ts +20 -40
- package/packages/compactor/src/types.ts +43 -100
- package/packages/core/constants.ts +1 -28
- package/packages/core/events.ts +1 -83
- package/packages/core/index.ts +1 -0
- package/packages/core/model-cache.ts +18 -12
- package/packages/core/package.json +3 -1
- package/packages/core/tui-overlay.ts +89 -0
- package/packages/core/tui-width.ts +18 -0
- package/packages/core/utils.ts +43 -0
- package/packages/footer/package.json +2 -2
- package/packages/footer/src/help.ts +2 -2
- package/packages/footer/src/index.ts +9 -10
- package/packages/footer/src/presets.ts +1 -27
- package/packages/footer/src/registry/index.ts +0 -23
- package/packages/footer/src/rendering/icons.ts +0 -13
- package/packages/footer/src/rendering/renderer.ts +5 -40
- package/packages/footer/src/rendering/separators.ts +0 -10
- package/packages/footer/src/rendering/theme.ts +1 -15
- package/packages/footer/src/segments/compactor.ts +7 -14
- package/packages/footer/src/segments/core.ts +15 -54
- package/packages/footer/src/segments/kanboard.ts +5 -5
- package/packages/footer/src/segments/mcp.ts +5 -5
- package/packages/footer/src/segments/memory.ts +4 -4
- package/packages/footer/src/segments/notify.ts +2 -2
- package/packages/footer/src/segments/ralph.ts +3 -3
- package/packages/footer/src/segments/status-ext.ts +1 -1
- package/packages/footer/src/segments/workflow.ts +3 -3
- package/packages/footer/src/tps-tracker.ts +0 -8
- package/packages/footer/src/tui/settings-tui.ts +14 -31
- package/packages/footer/src/types.ts +0 -15
- package/packages/image/package.json +2 -2
- package/packages/image/src/register-providers.ts +0 -11
- package/packages/image/src/tools.ts +0 -3
- package/packages/image/src/tui/model-selector.ts +36 -71
- package/packages/info-screen/config.ts +0 -16
- package/packages/info-screen/core-groups.ts +0 -10
- package/packages/info-screen/index.ts +22 -13
- package/packages/info-screen/package.json +2 -2
- package/packages/info-screen/registry.ts +1 -72
- package/packages/info-screen/tui/info-overlay.ts +85 -100
- package/packages/info-screen/usage-parser.ts +12 -47
- package/packages/input-shortcuts/package.json +2 -2
- package/packages/input-shortcuts/src/index.ts +3 -3
- package/packages/input-shortcuts/src/registers.ts +0 -8
- package/packages/input-shortcuts/src/settings-overlay.ts +4 -13
- package/packages/input-shortcuts/src/undo-redo.ts +0 -12
- package/packages/kanboard/package.json +2 -2
- package/packages/mcp/package.json +2 -2
- package/packages/mcp/src/bridge/client.ts +0 -15
- package/packages/mcp/src/config/manager.ts +0 -38
- package/packages/mcp/src/config/schema.ts +0 -27
- package/packages/mcp/src/config/sync.ts +0 -29
- package/packages/mcp/src/index.ts +1 -1
- package/packages/mcp/src/tui/add-overlay.ts +6 -6
- package/packages/mcp/src/types.ts +0 -6
- package/packages/memory/embedding.ts +0 -31
- package/packages/memory/mempalace.ts +0 -16
- package/packages/memory/package.json +4 -8
- package/packages/memory/storage.ts +56 -753
- package/packages/milestone/hooks.ts +1 -6
- package/packages/milestone/milestone.ts +2 -41
- package/packages/milestone/package.json +2 -2
- package/packages/notify/README.md +1 -0
- package/packages/notify/commands.ts +61 -3
- package/packages/notify/events.ts +0 -10
- package/packages/notify/package.json +2 -2
- package/packages/notify/settings.ts +0 -19
- package/packages/notify/tui/gotify-setup.ts +108 -143
- package/packages/notify/tui/ntfy-setup.ts +137 -172
- package/packages/notify/tui/recap-model-selector.ts +107 -101
- package/packages/notify/tui/settings-overlay.ts +94 -117
- package/packages/notify/tui/telegram-setup.ts +48 -79
- package/packages/notify/types.ts +0 -2
- package/packages/ralph/index.ts +11 -35
- package/packages/ralph/package.json +3 -3
- package/packages/ralph/ralph-loop.ts +3 -44
- package/packages/subagents/package.json +2 -1
- package/packages/subagents/src/agent-manager.ts +0 -51
- package/packages/subagents/src/agent-runner.ts +6 -80
- package/packages/subagents/src/conversation-viewer.ts +1 -19
- package/packages/subagents/src/core-compat.ts +8 -25
- package/packages/subagents/src/custom-agents.ts +0 -1
- package/packages/subagents/src/index.ts +3 -48
- package/packages/subagents/src/types.ts +0 -11
- package/packages/subagents/src/widget.ts +5 -5
- package/packages/unipi/bundled.js +4468 -7769
- package/packages/unipi/index.ts +6 -3
- package/packages/updater/package.json +2 -2
- package/packages/updater/src/changelog.ts +1 -16
- package/packages/updater/src/index.ts +0 -5
- package/packages/updater/src/installer.ts +4 -26
- package/packages/updater/src/markdown.ts +6 -152
- package/packages/updater/src/settings.ts +0 -15
- package/packages/updater/src/tui/changelog-overlay.ts +42 -234
- package/packages/updater/src/tui/list-detail-overlay.ts +260 -0
- package/packages/updater/src/tui/readme-overlay.ts +53 -210
- package/packages/updater/src/tui/settings-overlay.ts +13 -26
- package/packages/updater/src/version.ts +2 -31
- package/packages/utility/package.json +2 -4
- package/packages/utility/src/commands.ts +4 -5
- package/packages/utility/src/herdr-sync.ts +136 -0
- package/packages/utility/src/index.ts +11 -68
- package/packages/utility/src/lifecycle/cleanup.ts +2 -16
- package/packages/utility/src/{diff/settings.ts → settings.ts} +42 -80
- package/packages/utility/src/tools/env.ts +0 -0
- package/packages/utility/src/tui/name-badge-state.ts +18 -2
- package/packages/utility/src/tui/name-badge.ts +5 -4
- package/packages/utility/src/tui/util-settings-tui.ts +41 -224
- package/packages/web-api/package.json +2 -6
- package/packages/web-api/src/engine/dependencies.ts +13 -134
- package/packages/web-api/src/engine/extract.ts +9 -99
- package/packages/web-api/src/engine/format.ts +0 -75
- package/packages/web-api/src/engine/types.ts +0 -39
- package/packages/web-api/src/index.ts +1 -2
- package/packages/web-api/src/providers/base.ts +0 -10
- package/packages/web-api/src/providers/duckduckgo.ts +0 -1
- package/packages/web-api/src/providers/firecrawl.ts +0 -9
- package/packages/web-api/src/providers/jina-reader.ts +0 -9
- package/packages/web-api/src/providers/jina-search.ts +0 -9
- package/packages/web-api/src/providers/perplexity.ts +0 -9
- package/packages/web-api/src/providers/registry.ts +0 -80
- package/packages/web-api/src/providers/serpapi.ts +0 -9
- package/packages/web-api/src/providers/tavily.ts +0 -9
- package/packages/web-api/src/providers/wigolo-client.ts +0 -30
- package/packages/web-api/src/providers/wigolo.ts +0 -1
- package/packages/web-api/src/settings.ts +17 -77
- package/packages/web-api/src/tools.ts +21 -24
- package/packages/web-api/src/tui/settings-dialog.ts +0 -1
- package/packages/workflow/commands.ts +38 -122
- package/packages/workflow/index.ts +1 -5
- package/packages/workflow/package.json +2 -2
- package/packages/cocoindex/README.md +0 -94
- package/packages/cocoindex/bridge.ts +0 -842
- package/packages/cocoindex/commands.ts +0 -175
- package/packages/cocoindex/index.ts +0 -48
- package/packages/cocoindex/installer.ts +0 -397
- package/packages/cocoindex/package.json +0 -49
- package/packages/cocoindex/skills/cocoindex/SKILL.md +0 -88
- package/packages/cocoindex/tools.ts +0 -157
- package/packages/compactor/src/display/diff-renderer.ts +0 -281
- package/packages/compactor/src/display/line-width-safety.ts +0 -28
- package/packages/compactor/src/display/render-utils.ts +0 -52
- package/packages/compactor/src/display/thinking-label.ts +0 -18
- package/packages/compactor/src/display/tool-overrides.ts +0 -136
- package/packages/compactor/src/tools/compact.ts +0 -20
- package/packages/subagents/src/file-lock.ts +0 -102
- package/packages/utility/src/cache/ttl-cache.ts +0 -311
- package/packages/utility/src/diff/highlighter.ts +0 -352
- package/packages/utility/src/diff/parser.ts +0 -191
- package/packages/utility/src/diff/renderer.ts +0 -395
- package/packages/utility/src/diff/theme.ts +0 -316
- package/packages/utility/src/diff/wrapper.ts +0 -339
- package/packages/utility/src/display/capabilities.ts +0 -214
- package/packages/utility/src/display/width.ts +0 -226
- package/packages/utility/src/tools/batch.ts +0 -229
- package/packages/utility/src/tui/badge-settings-tui.ts +0 -388
- package/packages/utility/src/tui/badge-settings.ts +0 -67
- package/packages/utility/src/tui/settings-inspector.ts +0 -303
- package/packages/web-api/src/providers/llm-summarize.ts +0 -71
|
@@ -1,352 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @pi-unipi/utility — Shiki Highlighter
|
|
3
|
-
*
|
|
4
|
-
* Singleton Shiki ANSI highlighter with LRU cache, language detection,
|
|
5
|
-
* and contrast normalization.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
// ─── Constants ──────────────────────────────────────────────────────────────────
|
|
9
|
-
|
|
10
|
-
/** Maximum number of cached highlight results */
|
|
11
|
-
export const CACHE_LIMIT = 192;
|
|
12
|
-
|
|
13
|
-
/** Maximum characters to highlight (skip Shiki above this) */
|
|
14
|
-
export const MAX_HL_CHARS = 80_000;
|
|
15
|
-
|
|
16
|
-
// ─── LRU Cache ──────────────────────────────────────────────────────────────────
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Simple LRU cache with string keys.
|
|
20
|
-
* Evicts oldest entries when capacity is reached.
|
|
21
|
-
*/
|
|
22
|
-
export class LruCache<V> {
|
|
23
|
-
private map = new Map<string, V>();
|
|
24
|
-
private capacity: number;
|
|
25
|
-
|
|
26
|
-
constructor(capacity: number) {
|
|
27
|
-
this.capacity = capacity;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
get(key: string): V | undefined {
|
|
31
|
-
const value = this.map.get(key);
|
|
32
|
-
if (value !== undefined) {
|
|
33
|
-
// Move to end (most recently used)
|
|
34
|
-
this.map.delete(key);
|
|
35
|
-
this.map.set(key, value);
|
|
36
|
-
}
|
|
37
|
-
return value;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
set(key: string, value: V): void {
|
|
41
|
-
if (this.map.has(key)) {
|
|
42
|
-
this.map.delete(key);
|
|
43
|
-
} else if (this.map.size >= this.capacity) {
|
|
44
|
-
// Evict oldest (first entry)
|
|
45
|
-
const firstKey = this.map.keys().next().value;
|
|
46
|
-
if (firstKey !== undefined) {
|
|
47
|
-
this.map.delete(firstKey);
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
this.map.set(key, value);
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
has(key: string): boolean {
|
|
54
|
-
return this.map.has(key);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
get size(): number {
|
|
58
|
-
return this.map.size;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
clear(): void {
|
|
62
|
-
this.map.clear();
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
// ─── Language Detection ─────────────────────────────────────────────────────────
|
|
67
|
-
|
|
68
|
-
/** File extension → Shiki language mapping */
|
|
69
|
-
export const EXT_LANG: Record<string, string> = {
|
|
70
|
-
".ts": "typescript",
|
|
71
|
-
".tsx": "tsx",
|
|
72
|
-
".js": "javascript",
|
|
73
|
-
".jsx": "jsx",
|
|
74
|
-
".mjs": "javascript",
|
|
75
|
-
".cjs": "javascript",
|
|
76
|
-
".mts": "typescript",
|
|
77
|
-
".cts": "typescript",
|
|
78
|
-
".json": "json",
|
|
79
|
-
".jsonc": "jsonc",
|
|
80
|
-
".json5": "json5",
|
|
81
|
-
".html": "html",
|
|
82
|
-
".htm": "html",
|
|
83
|
-
".css": "css",
|
|
84
|
-
".scss": "scss",
|
|
85
|
-
".sass": "sass",
|
|
86
|
-
".less": "less",
|
|
87
|
-
".md": "markdown",
|
|
88
|
-
".mdx": "mdx",
|
|
89
|
-
".py": "python",
|
|
90
|
-
".rb": "ruby",
|
|
91
|
-
".go": "go",
|
|
92
|
-
".rs": "rust",
|
|
93
|
-
".java": "java",
|
|
94
|
-
".kt": "kotlin",
|
|
95
|
-
".kts": "kotlin",
|
|
96
|
-
".c": "c",
|
|
97
|
-
".h": "c",
|
|
98
|
-
".cpp": "cpp",
|
|
99
|
-
".hpp": "cpp",
|
|
100
|
-
".cc": "cpp",
|
|
101
|
-
".cs": "csharp",
|
|
102
|
-
".swift": "swift",
|
|
103
|
-
".php": "php",
|
|
104
|
-
".sql": "sql",
|
|
105
|
-
".sh": "bash",
|
|
106
|
-
".bash": "bash",
|
|
107
|
-
".zsh": "bash",
|
|
108
|
-
".fish": "fish",
|
|
109
|
-
".yaml": "yaml",
|
|
110
|
-
".yml": "yaml",
|
|
111
|
-
".toml": "toml",
|
|
112
|
-
".xml": "xml",
|
|
113
|
-
".svg": "xml",
|
|
114
|
-
".graphql": "graphql",
|
|
115
|
-
".gql": "graphql",
|
|
116
|
-
".vue": "vue",
|
|
117
|
-
".svelte": "svelte",
|
|
118
|
-
".astro": "astro",
|
|
119
|
-
".prisma": "prisma",
|
|
120
|
-
".dockerfile": "dockerfile",
|
|
121
|
-
".tf": "hcl",
|
|
122
|
-
".hcl": "hcl",
|
|
123
|
-
".lua": "lua",
|
|
124
|
-
".r": "r",
|
|
125
|
-
".R": "r",
|
|
126
|
-
".dart": "dart",
|
|
127
|
-
".ex": "elixir",
|
|
128
|
-
".exs": "elixir",
|
|
129
|
-
".erl": "erlang",
|
|
130
|
-
".hrl": "erlang",
|
|
131
|
-
".clj": "clojure",
|
|
132
|
-
".cljs": "clojure",
|
|
133
|
-
".hs": "haskell",
|
|
134
|
-
".elm": "elm",
|
|
135
|
-
".nim": "nim",
|
|
136
|
-
".zig": "zig",
|
|
137
|
-
".v": "v",
|
|
138
|
-
".jl": "julia",
|
|
139
|
-
".ml": "ocaml",
|
|
140
|
-
".mli": "ocaml",
|
|
141
|
-
".fs": "fsharp",
|
|
142
|
-
".fsx": "fsharp",
|
|
143
|
-
".fsi": "fsharp",
|
|
144
|
-
};
|
|
145
|
-
|
|
146
|
-
/**
|
|
147
|
-
* Detect the Shiki language from a file extension.
|
|
148
|
-
* Returns "text" if the extension is unknown.
|
|
149
|
-
*/
|
|
150
|
-
export function detectLanguage(extension: string): string {
|
|
151
|
-
const ext = extension.startsWith(".") ? extension.toLowerCase() : `.${extension.toLowerCase()}`;
|
|
152
|
-
return EXT_LANG[ext] ?? "text";
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
/**
|
|
156
|
-
* Detect language from a file path.
|
|
157
|
-
*/
|
|
158
|
-
export function detectLanguageFromPath(filePath: string): string {
|
|
159
|
-
const ext = filePath.lastIndexOf(".") >= 0 ? filePath.substring(filePath.lastIndexOf(".")) : "";
|
|
160
|
-
return detectLanguage(ext);
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
// ─── Contrast Normalization ─────────────────────────────────────────────────────
|
|
164
|
-
|
|
165
|
-
/**
|
|
166
|
-
* Calculate the relative luminance of a hex color.
|
|
167
|
-
* Used for contrast ratio calculations.
|
|
168
|
-
*/
|
|
169
|
-
function relativeLuminance(hex: string): number {
|
|
170
|
-
const h = hex.replace(/^#/, "");
|
|
171
|
-
const r = parseInt(h.substring(0, 2), 16) / 255;
|
|
172
|
-
const g = parseInt(h.substring(2, 4), 16) / 255;
|
|
173
|
-
const b = parseInt(h.substring(4, 6), 16) / 255;
|
|
174
|
-
|
|
175
|
-
const toLinear = (c: number) => (c <= 0.03928 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4));
|
|
176
|
-
return 0.2126 * toLinear(r) + 0.7152 * toLinear(g) + 0.0722 * toLinear(b);
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
/**
|
|
180
|
-
* Calculate contrast ratio between two colors.
|
|
181
|
-
*/
|
|
182
|
-
function contrastRatio(fg: string, bg: string): number {
|
|
183
|
-
const l1 = relativeLuminance(fg);
|
|
184
|
-
const l2 = relativeLuminance(bg);
|
|
185
|
-
const lighter = Math.max(l1, l2);
|
|
186
|
-
const darker = Math.min(l1, l2);
|
|
187
|
-
return (lighter + 0.05) / (darker + 0.05);
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
/**
|
|
191
|
-
* Extract the foreground color from an ANSI 24-bit escape sequence.
|
|
192
|
-
* Returns the hex color and the full match for replacement.
|
|
193
|
-
*/
|
|
194
|
-
function extractAnsiFg(ansi: string): { hex: string; match: string } | null {
|
|
195
|
-
const match = ansi.match(/\x1b\[38;2;(\d+);(\d+);(\d+)m/);
|
|
196
|
-
if (!match) return null;
|
|
197
|
-
const r = parseInt(match[1]);
|
|
198
|
-
const g = parseInt(match[2]);
|
|
199
|
-
const b = parseInt(match[3]);
|
|
200
|
-
const hex = `#${r.toString(16).padStart(2, "0")}${g.toString(16).padStart(2, "0")}${b.toString(16).padStart(2, "0")}`;
|
|
201
|
-
return { hex, match: match[0] };
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
/**
|
|
205
|
-
* Normalize low-contrast Shiki foregrounds against a dark background.
|
|
206
|
-
*
|
|
207
|
-
* Shiki themes sometimes produce foreground colors with poor contrast
|
|
208
|
-
* against diff backgrounds. This function bumps the brightness of any
|
|
209
|
-
* foreground that falls below the minimum contrast ratio.
|
|
210
|
-
*
|
|
211
|
-
* @param ansi - ANSI string with 24-bit color codes
|
|
212
|
-
* @param bgHex - Background hex color to test against (default: dark bg)
|
|
213
|
-
* @param minRatio - Minimum contrast ratio (default: 3.0)
|
|
214
|
-
*/
|
|
215
|
-
export function normalizeShikiContrast(
|
|
216
|
-
ansi: string,
|
|
217
|
-
bgHex: string = "#1a1a2e",
|
|
218
|
-
minRatio: number = 3.0,
|
|
219
|
-
): string {
|
|
220
|
-
// Find all 24-bit foreground sequences
|
|
221
|
-
const fgRegex = /\x1b\[38;2;\d+;\d+;\d+m/g;
|
|
222
|
-
let result = ansi;
|
|
223
|
-
let match: RegExpExecArray | null;
|
|
224
|
-
|
|
225
|
-
while ((match = fgRegex.exec(ansi)) !== null) {
|
|
226
|
-
const fgInfo = extractAnsiFg(match[0] + ansi.substring(match.index + match[0].length));
|
|
227
|
-
if (!fgInfo) continue;
|
|
228
|
-
|
|
229
|
-
const ratio = contrastRatio(fgInfo.hex, bgHex);
|
|
230
|
-
if (ratio < minRatio) {
|
|
231
|
-
// Brighten the foreground by mixing with white
|
|
232
|
-
const [r, g, b] = [
|
|
233
|
-
parseInt(fgInfo.hex.slice(1, 3), 16),
|
|
234
|
-
parseInt(fgInfo.hex.slice(3, 5), 16),
|
|
235
|
-
parseInt(fgInfo.hex.slice(5, 7), 16),
|
|
236
|
-
];
|
|
237
|
-
const factor = minRatio / Math.max(ratio, 0.01);
|
|
238
|
-
const nr = Math.min(255, Math.round(r + (255 - r) * Math.min(1, factor * 0.5)));
|
|
239
|
-
const ng = Math.min(255, Math.round(g + (255 - g) * Math.min(1, factor * 0.5)));
|
|
240
|
-
const nb = Math.min(255, Math.round(b + (255 - b) * Math.min(1, factor * 0.5)));
|
|
241
|
-
const newFg = `\x1b[38;2;${nr};${ng};${nb}m`;
|
|
242
|
-
result = result.replace(match[0], newFg);
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
return result;
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
// ─── Shiki Highlighter ──────────────────────────────────────────────────────────
|
|
250
|
-
|
|
251
|
-
/** Shiki highlighter instance (lazy singleton) */
|
|
252
|
-
let shikiHighlighter: import("shiki").Highlighter | null = null;
|
|
253
|
-
let shikiInitPromise: Promise<any> | null = null;
|
|
254
|
-
|
|
255
|
-
/**
|
|
256
|
-
* Initialize the Shiki highlighter (singleton).
|
|
257
|
-
* Returns the highlighter instance.
|
|
258
|
-
*/
|
|
259
|
-
export async function getShikiHighlighter(): Promise<any> {
|
|
260
|
-
if (shikiHighlighter) return shikiHighlighter;
|
|
261
|
-
if (shikiInitPromise) return shikiInitPromise;
|
|
262
|
-
|
|
263
|
-
shikiInitPromise = (async () => {
|
|
264
|
-
try {
|
|
265
|
-
const { createHighlighter } = await import("shiki");
|
|
266
|
-
shikiHighlighter = await createHighlighter({
|
|
267
|
-
themes: ["github-dark"],
|
|
268
|
-
langs: [
|
|
269
|
-
"typescript", "javascript", "tsx", "jsx", "json", "jsonc",
|
|
270
|
-
"html", "css", "scss", "markdown", "python", "go", "rust",
|
|
271
|
-
"java", "c", "cpp", "csharp", "ruby", "php", "swift", "kotlin",
|
|
272
|
-
"bash", "yaml", "toml", "xml", "sql", "graphql", "vue", "svelte",
|
|
273
|
-
],
|
|
274
|
-
});
|
|
275
|
-
return shikiHighlighter;
|
|
276
|
-
} catch {
|
|
277
|
-
// If Shiki fails to load, return null — we'll use plain text
|
|
278
|
-
shikiInitPromise = null;
|
|
279
|
-
return null;
|
|
280
|
-
}
|
|
281
|
-
})();
|
|
282
|
-
|
|
283
|
-
return shikiInitPromise;
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
/**
|
|
287
|
-
* Pre-warm the Shiki highlighter.
|
|
288
|
-
* Call this early in the extension lifecycle to avoid first-render delay.
|
|
289
|
-
*/
|
|
290
|
-
export async function preWarmHighlighter(): Promise<void> {
|
|
291
|
-
await getShikiHighlighter();
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
/** LRU cache for highlighted blocks */
|
|
295
|
-
const hlCache = new LruCache<string[]>(CACHE_LIMIT);
|
|
296
|
-
|
|
297
|
-
/**
|
|
298
|
-
* Generate a cache key for a code block.
|
|
299
|
-
*/
|
|
300
|
-
function hlCacheKey(code: string, language: string): string {
|
|
301
|
-
// Use first 200 chars + length + language for cache key
|
|
302
|
-
const prefix = code.substring(0, 200);
|
|
303
|
-
return `${language}:${code.length}:${prefix}`;
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
/**
|
|
307
|
-
* Highlight a code block to ANSI using Shiki.
|
|
308
|
-
* Results are cached in an LRU cache (192 entries).
|
|
309
|
-
*
|
|
310
|
-
* @param code - Code to highlight
|
|
311
|
-
* @param language - Shiki language identifier
|
|
312
|
-
* @returns Array of ANSI-highlighted lines, or plain lines if Shiki unavailable
|
|
313
|
-
*/
|
|
314
|
-
export async function hlBlock(code: string, language: string): Promise<string[]> {
|
|
315
|
-
// Skip highlighting for very large content
|
|
316
|
-
if (code.length > MAX_HL_CHARS) {
|
|
317
|
-
return code.split("\n");
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
// Check cache
|
|
321
|
-
const key = hlCacheKey(code, language);
|
|
322
|
-
const cached = hlCache.get(key);
|
|
323
|
-
if (cached) return cached;
|
|
324
|
-
|
|
325
|
-
// Get highlighter
|
|
326
|
-
const highlighter = await getShikiHighlighter();
|
|
327
|
-
if (!highlighter) {
|
|
328
|
-
// Shiki not available — return plain text
|
|
329
|
-
return code.split("\n");
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
try {
|
|
333
|
-
// Highlight with Shiki
|
|
334
|
-
const ansi = highlighter.codeToANSI(code, {
|
|
335
|
-
lang: language === "text" ? "text" : language,
|
|
336
|
-
theme: "github-dark",
|
|
337
|
-
});
|
|
338
|
-
|
|
339
|
-
const lines = ansi.split("\n");
|
|
340
|
-
|
|
341
|
-
// Normalize contrast
|
|
342
|
-
const normalized = lines.map((line: string) => normalizeShikiContrast(line));
|
|
343
|
-
|
|
344
|
-
// Cache result
|
|
345
|
-
hlCache.set(key, normalized);
|
|
346
|
-
|
|
347
|
-
return normalized;
|
|
348
|
-
} catch {
|
|
349
|
-
// Fallback on error
|
|
350
|
-
return code.split("\n");
|
|
351
|
-
}
|
|
352
|
-
}
|
|
@@ -1,191 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @pi-unipi/utility — Diff Parser
|
|
3
|
-
*
|
|
4
|
-
* Parses unified diffs from structuredPatch and provides word-level diff analysis.
|
|
5
|
-
* Wraps the `diff` library for structured output.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import * as Diff from "diff";
|
|
9
|
-
|
|
10
|
-
// ─── Types ──────────────────────────────────────────────────────────────────────
|
|
11
|
-
|
|
12
|
-
/** A single line in a parsed diff */
|
|
13
|
-
export interface DiffLine {
|
|
14
|
-
/** Line type: added, removed, context, or hunk separator */
|
|
15
|
-
type: "add" | "remove" | "context" | "hunk";
|
|
16
|
-
/** Original line number (null for added lines) */
|
|
17
|
-
oldLine: number | null;
|
|
18
|
-
/** New line number (null for removed lines) */
|
|
19
|
-
newLine: number | null;
|
|
20
|
-
/** Line content (without +/- prefix) */
|
|
21
|
-
content: string;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
/** Result of parsing a diff */
|
|
25
|
-
export interface ParsedDiff {
|
|
26
|
-
/** Old file name */
|
|
27
|
-
oldName: string;
|
|
28
|
-
/** New file name */
|
|
29
|
-
newName: string;
|
|
30
|
-
/** Parsed lines */
|
|
31
|
-
lines: DiffLine[];
|
|
32
|
-
/** Total additions */
|
|
33
|
-
additions: number;
|
|
34
|
-
/** Total deletions */
|
|
35
|
-
deletions: number;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
/** Word-level diff result */
|
|
39
|
-
export interface WordDiffResult {
|
|
40
|
-
/** Similarity score (0-1, where 1 = identical) */
|
|
41
|
-
similarity: number;
|
|
42
|
-
/** Changed ranges in the new text */
|
|
43
|
-
addedRanges: Array<{ start: number; end: number }>;
|
|
44
|
-
/** Changed ranges in the old text */
|
|
45
|
-
removedRanges: Array<{ start: number; end: number }>;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
// ─── Diff Parsing ───────────────────────────────────────────────────────────────
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* Parse a unified diff from two content strings.
|
|
52
|
-
* Returns structured DiffLine[] with line numbers and hunk separators.
|
|
53
|
-
*
|
|
54
|
-
* @param oldContent - Original content
|
|
55
|
-
* @param newContent - Modified content
|
|
56
|
-
* @param context - Number of context lines around changes (default 3)
|
|
57
|
-
* @param oldName - Label for old file
|
|
58
|
-
* @param newName - Label for new file
|
|
59
|
-
*/
|
|
60
|
-
export function parseDiff(
|
|
61
|
-
oldContent: string,
|
|
62
|
-
newContent: string,
|
|
63
|
-
context: number = 3,
|
|
64
|
-
oldName: string = "old",
|
|
65
|
-
newName: string = "new",
|
|
66
|
-
): ParsedDiff {
|
|
67
|
-
// Handle edge cases
|
|
68
|
-
if (oldContent === newContent) {
|
|
69
|
-
return { oldName, newName, lines: [], additions: 0, deletions: 0 };
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
if (oldContent === "") {
|
|
73
|
-
// New file — all lines are additions
|
|
74
|
-
const lines = newContent.split("\n");
|
|
75
|
-
const diffLines: DiffLine[] = lines.map((content, i) => ({
|
|
76
|
-
type: "add" as const,
|
|
77
|
-
oldLine: null,
|
|
78
|
-
newLine: i + 1,
|
|
79
|
-
content,
|
|
80
|
-
}));
|
|
81
|
-
return { oldName, newName, lines: diffLines, additions: lines.length, deletions: 0 };
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
if (newContent === "") {
|
|
85
|
-
// Deleted file — all lines are removals
|
|
86
|
-
const lines = oldContent.split("\n");
|
|
87
|
-
const diffLines: DiffLine[] = lines.map((content, i) => ({
|
|
88
|
-
type: "remove" as const,
|
|
89
|
-
oldLine: i + 1,
|
|
90
|
-
newLine: null,
|
|
91
|
-
content,
|
|
92
|
-
}));
|
|
93
|
-
return { oldName, newName, lines: diffLines, additions: 0, deletions: lines.length };
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
// Use structuredPatch for unified diff
|
|
97
|
-
const patches = Diff.structuredPatch(oldName, newName, oldContent, newContent, "", "", { context });
|
|
98
|
-
|
|
99
|
-
const lines: DiffLine[] = [];
|
|
100
|
-
let additions = 0;
|
|
101
|
-
let deletions = 0;
|
|
102
|
-
|
|
103
|
-
for (const hunk of patches.hunks) {
|
|
104
|
-
// Add hunk separator
|
|
105
|
-
lines.push({
|
|
106
|
-
type: "hunk",
|
|
107
|
-
oldLine: hunk.oldStart,
|
|
108
|
-
newLine: hunk.newStart,
|
|
109
|
-
content: `@@ -${hunk.oldStart},${hunk.oldLines} +${hunk.newStart},${hunk.newLines} @@`,
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
let oldLine = hunk.oldStart;
|
|
113
|
-
let newLine = hunk.newStart;
|
|
114
|
-
|
|
115
|
-
for (const line of hunk.lines) {
|
|
116
|
-
const prefix = line[0];
|
|
117
|
-
const content = line.substring(1);
|
|
118
|
-
|
|
119
|
-
if (prefix === "+") {
|
|
120
|
-
lines.push({ type: "add", oldLine: null, newLine, content });
|
|
121
|
-
additions++;
|
|
122
|
-
newLine++;
|
|
123
|
-
} else if (prefix === "-") {
|
|
124
|
-
lines.push({ type: "remove", oldLine, newLine: null, content });
|
|
125
|
-
deletions++;
|
|
126
|
-
oldLine++;
|
|
127
|
-
} else {
|
|
128
|
-
// Context line (space prefix)
|
|
129
|
-
lines.push({ type: "context", oldLine, newLine, content });
|
|
130
|
-
oldLine++;
|
|
131
|
-
newLine++;
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
return { oldName, newName, lines, additions, deletions };
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
/**
|
|
140
|
-
* Word-level diff analysis between two strings.
|
|
141
|
-
* Returns similarity score and character ranges of changes.
|
|
142
|
-
*/
|
|
143
|
-
export function wordDiffAnalysis(a: string, b: string): WordDiffResult {
|
|
144
|
-
// Fast path: identical strings
|
|
145
|
-
if (a === b) {
|
|
146
|
-
return { similarity: 1, addedRanges: [], removedRanges: [] };
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
// Fast path: empty strings
|
|
150
|
-
if (a.length === 0 && b.length === 0) {
|
|
151
|
-
return { similarity: 1, addedRanges: [], removedRanges: [] };
|
|
152
|
-
}
|
|
153
|
-
if (a.length === 0) {
|
|
154
|
-
return { similarity: 0, addedRanges: [{ start: 0, end: b.length }], removedRanges: [] };
|
|
155
|
-
}
|
|
156
|
-
if (b.length === 0) {
|
|
157
|
-
return { similarity: 0, addedRanges: [], removedRanges: [{ start: 0, end: a.length }] };
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
const changes = Diff.diffWords(a, b);
|
|
161
|
-
|
|
162
|
-
const addedRanges: Array<{ start: number; end: number }> = [];
|
|
163
|
-
const removedRanges: Array<{ start: number; end: number }> = [];
|
|
164
|
-
let aPos = 0;
|
|
165
|
-
let bPos = 0;
|
|
166
|
-
let unchangedChars = 0;
|
|
167
|
-
|
|
168
|
-
for (const change of changes) {
|
|
169
|
-
if (change.added) {
|
|
170
|
-
addedRanges.push({ start: bPos, end: bPos + (change.value?.length ?? 0) });
|
|
171
|
-
bPos += change.value?.length ?? 0;
|
|
172
|
-
} else if (change.removed) {
|
|
173
|
-
removedRanges.push({ start: aPos, end: aPos + (change.value?.length ?? 0) });
|
|
174
|
-
aPos += change.value?.length ?? 0;
|
|
175
|
-
} else {
|
|
176
|
-
// Unchanged
|
|
177
|
-
unchangedChars += change.value?.length ?? 0;
|
|
178
|
-
aPos += change.value?.length ?? 0;
|
|
179
|
-
bPos += change.value?.length ?? 0;
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
const totalChars = Math.max(a.length + b.length, 1);
|
|
184
|
-
const similarity = (unchangedChars * 2) / totalChars;
|
|
185
|
-
|
|
186
|
-
return {
|
|
187
|
-
similarity: Math.min(1, Math.max(0, similarity)),
|
|
188
|
-
addedRanges,
|
|
189
|
-
removedRanges,
|
|
190
|
-
};
|
|
191
|
-
}
|