@goodandready/dsh-context-lens 0.1.16 → 0.1.18
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/README.md +21 -5
- package/README.ru.md +21 -5
- package/README.zh.md +21 -1
- package/lib/ast/skeletonizer.js +31 -15
- package/lib/client.js +284 -48
- package/lib/http.js +114 -0
- package/lib/index.js +136 -190
- package/lib/tokens/tracker.js +14 -6
- package/lib/tools.js +179 -0
- package/lib/updater.js +237 -0
- package/package.json +3 -1
package/README.md
CHANGED
|
@@ -22,6 +22,16 @@
|
|
|
22
22
|
<a href="README.zh.md"><b>🇨🇳 中文说明</b></a>
|
|
23
23
|
</p>
|
|
24
24
|
|
|
25
|
+
<table align="center">
|
|
26
|
+
<tr>
|
|
27
|
+
<td align="center">
|
|
28
|
+
⭐ <strong>If you like this plugin, please star it on GitHub</strong> — it shows me that the plugin is useful to you and motivates me to keep developing it.
|
|
29
|
+
<br><br>
|
|
30
|
+
🐛 <strong>If you find a bug or would like to request a feature</strong>, open a GitHub issue in any language — I will review your proposal and implement useful suggestions in a future plugin version.
|
|
31
|
+
</td>
|
|
32
|
+
</tr>
|
|
33
|
+
</table>
|
|
34
|
+
|
|
25
35
|
</div>
|
|
26
36
|
|
|
27
37
|
---
|
|
@@ -32,7 +42,7 @@
|
|
|
32
42
|
|
|
33
43
|
Large context windows are expensive, prone to model distraction, and vulnerable to rate limits. When agents inspect multi-file codebases or run bulky test suites, thousands of tokens are wasted on boilerplate function bodies, passing test logs, and build artifacts.
|
|
34
44
|
|
|
35
|
-
`dsh-context-lens` introduces **active path focusing, AST structural code skeletonization (JS/TS/Python/Go), and fast O(n) heuristic log compression**, shrinking context consumption by **up to 85%** while keeping 100% of essential architectural interfaces and failure traces.
|
|
45
|
+
`dsh-context-lens` introduces **active path focusing, AST structural code skeletonization (JS/TS/Python/Go/Rust/Java/C/C++/SQL), and fast O(n) heuristic log compression**, shrinking context consumption by **up to 85%** while keeping 100% of essential architectural interfaces and failure traces.
|
|
36
46
|
|
|
37
47
|
```mermaid
|
|
38
48
|
graph LR
|
|
@@ -144,11 +154,20 @@ dsh-context-lens:
|
|
|
144
154
|
|
|
145
155
|
---
|
|
146
156
|
|
|
157
|
+
|
|
158
|
+
## Changed in v0.1.18
|
|
159
|
+
|
|
160
|
+
- **Critical Fix (#71, GH #2)**: Conformed `output.render` to DeepSeek Harness core contract by returning `ContentBlock[]` (`[{ type: 'text', text: ... }]`). Prevents irreversible DSH session poisoning caused by `TypeError: content.some is not a function` in `@deepseek-ai/dsh-llm`.
|
|
161
|
+
- **Security & Reliability (#62, #63, #70)**: Hardened HTTP endpoints (`/clear-focus`, `/compress-preview`, `/status`): strictly requires `POST` on write actions, enforces loopback/same-origin trust checks, caps body size to 256KB (413 on exceed), validates `maxLines` (1-5000), and handles malformed session queries with clear 400 responses.
|
|
162
|
+
- **One-Click In-App Updater (#61)**: Added canonical plugin updater module (`lib/updater.js`) with `/api/dsh-context-lens/update` endpoint and an in-app update UI banner with one-click update button in the settings card.
|
|
163
|
+
- **Settings & Lifecycle (#64, #66)**: Injected `settingsScope` directly into client plugin dependencies and removed foreign `lanSettings` fallback. Wrapped settings and locale registrations in `ctx.effect` with disposable cleanups.
|
|
164
|
+
- **UI & Theme Alignment (#67, #68)**: Implemented smooth vector SVG 14x14 chevron with 180° rotation animation and replaced hardcoded colors with `--dsw-alias-*` theme tokens for seamless light/dark mode presentation.
|
|
165
|
+
- **Repository Hygiene (#65)**: Purged internal agent artifacts (`AGENTS.md`, `index.md`, `docs/plans/`) from tracked git tree and added denylist to `.gitignore`.
|
|
166
|
+
|
|
147
167
|
## 📄 License
|
|
148
168
|
|
|
149
169
|
MIT © [GooDAnDReaDY](https://github.com/GooDAnDReaDY)
|
|
150
170
|
|
|
151
|
-
|
|
152
171
|
## Changed in v0.1.11
|
|
153
172
|
|
|
154
173
|
Audit fixes (#33–#47, #18):
|
|
@@ -161,19 +180,16 @@ Audit fixes (#33–#47, #18):
|
|
|
161
180
|
- Python imports kept in skeletons; Java locals no longer mistaken for signatures.
|
|
162
181
|
- Shared `estimateTokens` helper; unused `dsh-credentials` peer removed.
|
|
163
182
|
|
|
164
|
-
|
|
165
183
|
## Changed in v0.1.12
|
|
166
184
|
|
|
167
185
|
#43: extract shared `StatusPanel` used by LensTab and HeaderChip popover (budget bar, history, refresh).
|
|
168
186
|
|
|
169
|
-
|
|
170
187
|
## Changed in v0.1.13
|
|
171
188
|
|
|
172
189
|
- **Fix (#50)**: Guard optional `betterSidebar` tab registration via `ctx.inject(['betterSidebar'], ...)` instead of direct property access on Cordis context proxy, resolving `cannot get property "betterSidebar" without inject` on client boot.
|
|
173
190
|
- **Fix (#50)**: Safely guard `_ctx.settingsScope` access in `PluginCard` with try/catch to prevent proxy property errors.
|
|
174
191
|
- **Test**: Added regression test suite simulating strict Cordis Context Proxy behavior.
|
|
175
192
|
|
|
176
|
-
|
|
177
193
|
## Changed in v0.1.15
|
|
178
194
|
|
|
179
195
|
- **Feature (#54)**: Support native DSH right sidebar (`ctx.sidebarRightTabs` + `sidebar.right.pane.tab` slot) introduced in DSH 0.1.5-alpha.1.
|
package/README.ru.md
CHANGED
|
@@ -22,6 +22,16 @@
|
|
|
22
22
|
<a href="README.zh.md"><b>🇨🇳 中文说明</b></a>
|
|
23
23
|
</p>
|
|
24
24
|
|
|
25
|
+
<table align="center">
|
|
26
|
+
<tr>
|
|
27
|
+
<td align="center">
|
|
28
|
+
⭐ <strong>Если вам нравится этот плагин, поставьте ему звезду на GitHub</strong> — это покажет мне, что плагин вам полезен, и будет мотивировать меня развивать его дальше.
|
|
29
|
+
<br><br>
|
|
30
|
+
🐛 <strong>Если вы нашли баг или хотите предложить новый функционал</strong>, создайте issue на GitHub на любом языке — я рассмотрю ваше предложение и реализую полезные идеи в одной из следующих версий плагина.
|
|
31
|
+
</td>
|
|
32
|
+
</tr>
|
|
33
|
+
</table>
|
|
34
|
+
|
|
25
35
|
</div>
|
|
26
36
|
|
|
27
37
|
---
|
|
@@ -32,7 +42,7 @@
|
|
|
32
42
|
|
|
33
43
|
Большие объёмы контекста приводят к высоким затратам токенов, замедлению генерации и быстрой перегрузке лимитов. При изучении крупных репозиториев или прогоне тестов тысячи токенов тратятся на однотипные тела функций, логи успешных тестов и сборку.
|
|
34
44
|
|
|
35
|
-
Плагин внедряет **фокусировку на активных файлах, AST-скелетонизацию исходного кода (JS/TS/Python/Go) и сверхбыструю эвристическую компрессию логов**, снижая расход контекста **до 85%** при сохранении 100% сигнатур типов, интерфейсов и сообщений об ошибках.
|
|
45
|
+
Плагин внедряет **фокусировку на активных файлах, AST-скелетонизацию исходного кода (JS/TS/Python/Go/Rust/Java/C/C++/SQL) и сверхбыструю эвристическую компрессию логов**, снижая расход контекста **до 85%** при сохранении 100% сигнатур типов, интерфейсов и сообщений об ошибках.
|
|
36
46
|
|
|
37
47
|
```mermaid
|
|
38
48
|
graph LR
|
|
@@ -141,28 +151,34 @@ dsh-context-lens:
|
|
|
141
151
|
|
|
142
152
|
---
|
|
143
153
|
|
|
154
|
+
|
|
155
|
+
## Изменения в v0.1.18
|
|
156
|
+
|
|
157
|
+
- **Критическое исправление (#71, GH #2)**: Приведение контракта `output.render` к стандарту ядра DeepSeek Harness: теперь возвращается массив `ContentBlock[]` (`[{ type: 'text', text: ... }]`). Полностью устранено необратимое повреждение сессий DSH с ошибкой `TypeError: content.some is not a function` в модуле `@deepseek-ai/dsh-llm`.
|
|
158
|
+
- **Безопасность и отказоустойчивость HTTP (#62, #63, #70)**: Защита маршрутов (`/clear-focus`, `/compress-preview`, `/status`): проверка метода (`POST` для изменений), верификация loopback и same-origin, ограничение размера тела запроса до 256 КБ (код 413 при превышении), клампинг `maxLines` (1–5000), возврат 400 Bad Request при невалидном идентификаторе сессии.
|
|
159
|
+
- **One-Click автообновление плагина (#61)**: Внедрен стандартный модуль автообновления `lib/updater.js`, endpoint `/api/dsh-context-lens/update` и блок проверки/установки обновления в карточке настроек.
|
|
160
|
+
- **Сервис настроек и жизненный цикл (#64, #66)**: Клиентский плагин объявляет зависимость `settingsScope`, убрана привязка к чужому сервису `lanSettings`. Регистрации настроек и локали обёрнуты в `ctx.effect` с корректными уборщиками.
|
|
161
|
+
- **Визуальная часть UI и темы (#67, #68)**: Запасной шеврон заменён на векторный SVG 14x14 с плавной анимацией поворота на 180°. Исключены захардкоженные цвета `rgba()`, интерфейс переведён на токены `--dsw-alias-*`.
|
|
162
|
+
- **Санитайзинг репозитория (#65)**: Из отслеживаемого дерева исключены внутренние файлы (`AGENTS.md`, `index.md`, `docs/plans/`), обновлён `.gitignore`.
|
|
163
|
+
|
|
144
164
|
## 📄 Лицензия
|
|
145
165
|
|
|
146
166
|
MIT © [GooDAnDReaDY](https://github.com/GooDAnDReaDY)
|
|
147
167
|
|
|
148
|
-
|
|
149
168
|
## Changed in v0.1.11
|
|
150
169
|
|
|
151
170
|
Исправления audit #33–#47 / #18: режим auto-compress не форсирует balanced; budgetLimit останавливает подсчёт; focus per-session; поля settings card; optional betterSidebar; серверный preview; Python imports / Java locals; общий estimateTokens; удалён unused peer dsh-credentials.
|
|
152
171
|
|
|
153
|
-
|
|
154
172
|
## Changed in v0.1.12
|
|
155
173
|
|
|
156
174
|
#43: extract shared `StatusPanel` used by LensTab and HeaderChip popover (budget bar, history, refresh).
|
|
157
175
|
|
|
158
|
-
|
|
159
176
|
## Changed in v0.1.13
|
|
160
177
|
|
|
161
178
|
- **Fix (#50)**: Безопасная регистрация вкладки BetterSidebar через `ctx.inject(['betterSidebar'], ...)` вместо прямого чтения свойства из Cordis Context Proxy. Устранена ошибка `cannot get property "betterSidebar" without inject` при загрузке клиентской половины в DSH.
|
|
162
179
|
- **Fix (#50)**: Безопасное обращение к `_ctx.settingsScope` в `PluginCard` через try/catch.
|
|
163
180
|
- **Тесты**: Добавлены регрессионные тесты со строгим Cordis Context Proxy.
|
|
164
181
|
|
|
165
|
-
|
|
166
182
|
## Changed in v0.1.15
|
|
167
183
|
|
|
168
184
|
- **Функциональность (#54)**: Поддержка встроенной правой боковой панели DSH (`ctx.sidebarRightTabs` + слот `sidebar.right.pane.tab`) из DSH 0.1.5-alpha.1.
|
package/README.zh.md
CHANGED
|
@@ -22,6 +22,16 @@
|
|
|
22
22
|
<a href="README.zh.md"><b>🇨🇳 中文说明</b></a>
|
|
23
23
|
</p>
|
|
24
24
|
|
|
25
|
+
<table align="center">
|
|
26
|
+
<tr>
|
|
27
|
+
<td align="center">
|
|
28
|
+
⭐ <strong>如果您喜欢这个插件,请在 GitHub 上为它点亮 Star</strong> — 这能让我知道插件对您有用,并鼓励我继续开发和维护它。
|
|
29
|
+
<br><br>
|
|
30
|
+
🐛 <strong>如果您发现 Bug 或希望增加功能</strong>,请使用任意语言在 GitHub 上提交 Issue — 我会评估您的建议,并在后续版本中实现有价值的改进。
|
|
31
|
+
</td>
|
|
32
|
+
</tr>
|
|
33
|
+
</table>
|
|
34
|
+
|
|
25
35
|
</div>
|
|
26
36
|
|
|
27
37
|
---
|
|
@@ -30,7 +40,7 @@
|
|
|
30
40
|
|
|
31
41
|
**`dsh-context-lens`** 为 **DeepSeek Harness** 智能体提供深度上下文窗口与 Token 预算优化。
|
|
32
42
|
|
|
33
|
-
超长上下文不仅消耗高昂 Token 成本,还会导致模型注意力涣散并频繁触发限流。本插件通过**工作区文件焦点聚焦、跨语言 AST 结构骨架提取(支持 JS/TS/Python/Go)以及 $O(n)$ 终端测试日志启发式精简**,在保留 100% 架构接口与错误堆栈的前提下,将上下文体积削减**高达 85%**。
|
|
43
|
+
超长上下文不仅消耗高昂 Token 成本,还会导致模型注意力涣散并频繁触发限流。本插件通过**工作区文件焦点聚焦、跨语言 AST 结构骨架提取(支持 JS/TS/Python/Go/Rust/Java/C/C++/SQL)以及 $O(n)$ 终端测试日志启发式精简**,在保留 100% 架构接口与错误堆栈的前提下,将上下文体积削减**高达 85%**。
|
|
34
44
|
|
|
35
45
|
```mermaid
|
|
36
46
|
graph LR
|
|
@@ -71,3 +81,13 @@ dsh plugin --profile web add @goodandready/dsh-context-lens
|
|
|
71
81
|
## 📄 开源协议
|
|
72
82
|
|
|
73
83
|
MIT © [GooDAnDReaDY](https://github.com/GooDAnDReaDY)
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
## v0.1.18 更新日志
|
|
87
|
+
|
|
88
|
+
- **严重问题修复 (#71, GH #2)**:严格遵循 DeepSeek Harness 核心工具返回规范,将 `output.render` 调整为返回 `ContentBlock[]` 数组 (`[{ type: 'text', text: ... }]`)。彻底解决第三方工具调用后会话写入非数组导致 `@deepseek-ai/dsh-llm` 报错 `TypeError: content.some is not a function` 并永久损坏会话的严重缺陷。
|
|
89
|
+
- **安全性与稳定性加固 (#62, #63, #70)**:全面加固 HTTP 接口 (`/clear-focus`, `/compress-preview`, `/status`):写操作严格要求 `POST` 请求,校验环回与同源请求来源,限制请求体上限为 256KB(超限返回 413),限制 `maxLines` 范围为 1–5000,无效 session 参数返回规范 400 错误。
|
|
90
|
+
- **一键在线更新支持 (#61)**:引入标准更新管理模块 (`lib/updater.js`) 及 `/api/dsh-context-lens/update` 接口,在设置卡片中增加版本检查与一键更新按钮。
|
|
91
|
+
- **设置域与生命周期规范 (#64, #66)**:客户端显式声明 `settingsScope` 依赖并移除对外部 `lanSettings` 的隐式依赖,将设置注册与多语言注册统一纳入 `ctx.effect` 生命周期清理管理。
|
|
92
|
+
- **UI 与主题深度适配 (#67, #68)**:将折叠箭头升级为 14x14 矢量 SVG 并支持平滑 180° 旋转动画,全面替换硬编码色值,使用 `--dsw-alias-*` 主题变量完美适配明暗主题。
|
|
93
|
+
- **仓库代码纯净性 (#65)**:从 Git 跟踪树中彻底剥离内部计划文件 (`AGENTS.md`, `index.md`, `docs/plans/`),并更新 `.gitignore` 防护清单。
|
package/lib/ast/skeletonizer.js
CHANGED
|
@@ -1,13 +1,17 @@
|
|
|
1
|
-
// ponytail: regex skeletons, no tree-sitter — handles JS/TS/Python/Go/Rust/Java signatures + imports/comments + multiline signatures
|
|
1
|
+
// ponytail: regex skeletons, no tree-sitter — handles JS/TS/Python/Go/Rust/Java/C/C++/SQL signatures + imports/comments + multiline signatures
|
|
2
2
|
const JS_FUNC_RE = /^\s*(export\s+)?(async\s+)?(function\s+(\w+)|const\s+(\w+)\s*=\s*(async\s+)?\([^)]*\)\s*=>|(\w+)\s*:\s*\([^)]*\)\s*=>|class\s+(\w+)|interface\s+(\w+)|type\s+(\w+)\s*=)/;
|
|
3
3
|
const PY_RE = /^\s*(def\s+(\w+)\s*\([^)]*\)|class\s+(\w+).*?:|async def\s+(\w+)\s*\([^)]*\))/;
|
|
4
4
|
const GO_RE = /^\s*(func\s+(\([^)]+\)\s+)?(\w+)\s*\([^)]*\)|type\s+(\w+)\s+(struct|interface))/;
|
|
5
5
|
const RUST_RE = /^\s*(pub(\([^)]+\))?\s+)?(async\s+)?(fn|struct|enum|impl|trait|type|const|static)\s+\w+/;
|
|
6
|
-
const
|
|
7
|
-
const
|
|
6
|
+
const CPP_CLASS_RE = /^\s*(?:class|struct)\s+\w+(?:\s*:\s*(?:public|protected|private)\s+\w+)?/;
|
|
7
|
+
const CPP_FUNC_RE = /^\s*(?:(?:virtual|inline|static|explicit|constexpr|friend)\s+)*(?:[\w:<>&*~]+\s+)+[\w:~]+\s*\([^)]*\)(?:\s*const)?(?:\s*override|\s*noexcept)?(?:\s*=\s*0)?/;
|
|
8
|
+
const SQL_RE = /^\s*(?:CREATE|ALTER)\s+(?:TABLE|VIEW|INDEX|TRIGGER|FUNCTION|PROCEDURE)\s+(?:IF\s+NOT\s+EXISTS\s+)?[\w."`]+|^\s*CONSTRAINT\s+[\w."`]+|^\s*FOREIGN\s+KEY|^\s*PRIMARY\s+KEY/i;
|
|
9
|
+
|
|
10
|
+
const IMPORT_RE = /^\s*#include\s+[<"][^>"]+[>"]|^\s*import\s+.*from\s+['"].*['"]|^\s*import\s+['"].*['"]|^\s*export\s+.*from\s+['"]|^\s*use\s+[a-zA-Z0-9_:]+|^\s*(from\s+\S+\s+)?import\s+\S+|^\s*from\s+\S+\s+import\s+/;
|
|
11
|
+
const COMMENT_RE = /^\s*(\/\/.*|\/\*.*\*\/|\/\*.*|\*.*|#.*|--.*)/;
|
|
8
12
|
|
|
9
13
|
// Multiline signature starters
|
|
10
|
-
const MULTILINE_START_RE = /^\s*(export\s+)?(async\s+)?(function\b|const\s+\w+\s*=|\w+\s*:\s*(async\s+)?\(|def\b|async\s+def\b|func\b|(pub(\([^)]+\))?\s+)?(async\s+)?fn\b|(?:(?:public|protected|private|static|final|abstract|synchronized|native|default)\s+)+[\w.<>,\[\]?]+\s+\w+\s*\()/;
|
|
14
|
+
const MULTILINE_START_RE = /^\s*(export\s+)?(async\s+)?(function\b|const\s+\w+\s*=|\w+\s*:\s*(async\s+)?\(|def\b|async\s+def\b|func\b|(pub(\([^)]+\))?\s+)?(async\s+)?fn\b|(?:(?:public|protected|private|static|final|abstract|synchronized|native|default)\s+)+[\w.<>,\[\]?]+\s+\w+\s*\(|(?:(?:virtual|inline|static|explicit|constexpr|friend)\s+)*(?:[\w:<>&*~]+\s+)+[\w:~]+\s*\()/;
|
|
11
15
|
|
|
12
16
|
function indentDepth(line) {
|
|
13
17
|
const m = line.match(/^(\s*)/);
|
|
@@ -28,7 +32,7 @@ export function skeletonize(text, { maxDepth = 3, language, includeImports = tru
|
|
|
28
32
|
const d = indentDepth(raw);
|
|
29
33
|
if (d > maxDepth) { pendingComment = null; continue; }
|
|
30
34
|
|
|
31
|
-
// Handle imports
|
|
35
|
+
// Handle imports & includes
|
|
32
36
|
if (includeImports && IMPORT_RE.test(line)) {
|
|
33
37
|
const sig = line.trim().slice(0, 120);
|
|
34
38
|
if (!seen.has(sig)) {
|
|
@@ -39,19 +43,19 @@ export function skeletonize(text, { maxDepth = 3, language, includeImports = tru
|
|
|
39
43
|
continue;
|
|
40
44
|
}
|
|
41
45
|
|
|
42
|
-
// Handle comments (keep
|
|
46
|
+
// Handle comments (keep doc or line comments directly above a definition)
|
|
43
47
|
if (includeComments && COMMENT_RE.test(line)) {
|
|
44
48
|
let nextIdx = idx + 1;
|
|
45
49
|
while (nextIdx < lines.length && !lines[nextIdx].trim()) nextIdx++;
|
|
46
50
|
if (nextIdx < lines.length) {
|
|
47
51
|
const nextLine = lines[nextIdx];
|
|
48
|
-
if (JS_FUNC_RE.test(nextLine) || PY_RE.test(nextLine) || GO_RE.test(nextLine) || RUST_RE.test(nextLine) || MULTILINE_START_RE.test(nextLine) || /^\s*(class|function|interface|type|def |func |pub |fn )/.test(nextLine)) {
|
|
52
|
+
if (JS_FUNC_RE.test(nextLine) || PY_RE.test(nextLine) || GO_RE.test(nextLine) || RUST_RE.test(nextLine) || CPP_CLASS_RE.test(nextLine) || CPP_FUNC_RE.test(nextLine) || SQL_RE.test(nextLine) || MULTILINE_START_RE.test(nextLine) || /^\s*(class|function|interface|type|def |func |pub |fn )/.test(nextLine)) {
|
|
49
53
|
pendingComment = line.trim().slice(0, 120);
|
|
50
54
|
continue;
|
|
51
55
|
}
|
|
52
56
|
}
|
|
53
57
|
// Otherwise, keep top-level comments (up to 5)
|
|
54
|
-
if (out.length < 5 && (line.trim().startsWith('//') || line.trim().startsWith('#') || line.trim().startsWith('/*'))) {
|
|
58
|
+
if (out.length < 5 && (line.trim().startsWith('//') || line.trim().startsWith('#') || line.trim().startsWith('/*') || line.trim().startsWith('--'))) {
|
|
55
59
|
const sig = line.trim().slice(0, 120);
|
|
56
60
|
if (!seen.has(sig)) {
|
|
57
61
|
seen.add(sig);
|
|
@@ -65,7 +69,7 @@ export function skeletonize(text, { maxDepth = 3, language, includeImports = tru
|
|
|
65
69
|
// Multiline signature detection: if line starts a signature but doesn't finish with '{', '=>', or ':'
|
|
66
70
|
let candidateLine = line;
|
|
67
71
|
let accumulatedIdx = idx;
|
|
68
|
-
const isComplete = (s) => (s.includes('{') && s.includes(')')) || (s.includes('=>') && s.includes(')')) || (s.endsWith(':') && s.includes(')'));
|
|
72
|
+
const isComplete = (s) => (s.includes('{') && s.includes(')')) || (s.includes('=>') && s.includes(')')) || (s.endsWith(':') && s.includes(')')) || (s.includes(';') && s.includes(')'));
|
|
69
73
|
if (MULTILINE_START_RE.test(candidateLine) && !isComplete(candidateLine)) {
|
|
70
74
|
let buffer = candidateLine.trim();
|
|
71
75
|
let scanIdx = idx + 1;
|
|
@@ -73,7 +77,7 @@ export function skeletonize(text, { maxDepth = 3, language, includeImports = tru
|
|
|
73
77
|
const nextRaw = lines[scanIdx].trim();
|
|
74
78
|
if (!nextRaw) { scanIdx++; continue; }
|
|
75
79
|
buffer += ' ' + nextRaw;
|
|
76
|
-
if ((nextRaw.includes('{') || nextRaw.includes('=>') || nextRaw.endsWith(':')) && buffer.includes(')')) {
|
|
80
|
+
if ((nextRaw.includes('{') || nextRaw.includes('=>') || nextRaw.endsWith(':') || nextRaw.includes(';')) && buffer.includes(')')) {
|
|
77
81
|
candidateLine = buffer;
|
|
78
82
|
accumulatedIdx = scanIdx;
|
|
79
83
|
break;
|
|
@@ -107,9 +111,21 @@ export function skeletonize(text, { maxDepth = 3, language, includeImports = tru
|
|
|
107
111
|
|| /^\s*(?:(?:public|protected|private|static|final|abstract|synchronized|native|default)\s+)+[\w.<>,\[\]?]+\s+\w+\s*\(/.test(candidateLine)
|
|
108
112
|
|| /^\s*(class|interface|enum|record)\s+\w+/.test(candidateLine)) sig = candidateLine.trim();
|
|
109
113
|
}
|
|
114
|
+
if (!sig && (!language || language === 'cpp' || language === 'c')) {
|
|
115
|
+
if (CPP_CLASS_RE.test(candidateLine) || CPP_FUNC_RE.test(candidateLine)) {
|
|
116
|
+
sig = candidateLine.trim();
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
if (!sig && (!language || language === 'sql')) {
|
|
120
|
+
if (SQL_RE.test(candidateLine)) {
|
|
121
|
+
sig = candidateLine.trim();
|
|
122
|
+
}
|
|
123
|
+
}
|
|
110
124
|
// generic fallback: if no specific language, try all
|
|
111
125
|
if (!sig && !language) {
|
|
112
|
-
if (JS_FUNC_RE.test(candidateLine) || PY_RE.test(candidateLine) || GO_RE.test(candidateLine) || RUST_RE.test(candidateLine))
|
|
126
|
+
if (JS_FUNC_RE.test(candidateLine) || PY_RE.test(candidateLine) || GO_RE.test(candidateLine) || RUST_RE.test(candidateLine) || CPP_CLASS_RE.test(candidateLine) || CPP_FUNC_RE.test(candidateLine) || SQL_RE.test(candidateLine)) {
|
|
127
|
+
sig = candidateLine.trim();
|
|
128
|
+
}
|
|
113
129
|
}
|
|
114
130
|
|
|
115
131
|
if (sig) {
|
|
@@ -125,8 +141,8 @@ export function skeletonize(text, { maxDepth = 3, language, includeImports = tru
|
|
|
125
141
|
}
|
|
126
142
|
pendingComment = null;
|
|
127
143
|
}
|
|
128
|
-
// normalize: trim trailing { : etc, keep signature short
|
|
129
|
-
sig = sig.replace(/\s*\{\s*$/, '').replace(/:\s*$/, '').trim();
|
|
144
|
+
// normalize: trim trailing { : ; etc, keep signature short
|
|
145
|
+
sig = sig.replace(/\s*\{\s*$/, '').replace(/:\s*$/, '').replace(/;\s*$/, '').trim();
|
|
130
146
|
if (sig.length > 180) sig = sig.slice(0, 177) + '...';
|
|
131
147
|
const key = sig;
|
|
132
148
|
if (!seen.has(key)) {
|
|
@@ -147,10 +163,10 @@ export function skeletonize(text, { maxDepth = 3, language, includeImports = tru
|
|
|
147
163
|
const total = lines.filter(l => l.trim()).length;
|
|
148
164
|
const removed = total - out.length;
|
|
149
165
|
if (removed > 0 && out.length > 0) {
|
|
150
|
-
const commentPrefix = (language === 'py' || language === 'python') ? '# ' : '// ';
|
|
166
|
+
const commentPrefix = (language === 'py' || language === 'python') ? '# ' : (language === 'sql' ? '-- ' : '// ');
|
|
151
167
|
out.push(`${commentPrefix}... ${removed} lines collapsed (skeleton, maxDepth=${maxDepth})`);
|
|
152
168
|
}
|
|
153
169
|
return out.join('\n');
|
|
154
170
|
}
|
|
155
171
|
|
|
156
|
-
export default { skeletonize };
|
|
172
|
+
export default { skeletonize };
|