@goodandready/dsh-context-lens 0.1.15 → 0.1.17

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 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
@@ -148,7 +158,6 @@ dsh-context-lens:
148
158
 
149
159
  MIT © [GooDAnDReaDY](https://github.com/GooDAnDReaDY)
150
160
 
151
-
152
161
  ## Changed in v0.1.11
153
162
 
154
163
  Audit fixes (#33–#47, #18):
@@ -161,19 +170,16 @@ Audit fixes (#33–#47, #18):
161
170
  - Python imports kept in skeletons; Java locals no longer mistaken for signatures.
162
171
  - Shared `estimateTokens` helper; unused `dsh-credentials` peer removed.
163
172
 
164
-
165
173
  ## Changed in v0.1.12
166
174
 
167
175
  #43: extract shared `StatusPanel` used by LensTab and HeaderChip popover (budget bar, history, refresh).
168
176
 
169
-
170
177
  ## Changed in v0.1.13
171
178
 
172
179
  - **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
180
  - **Fix (#50)**: Safely guard `_ctx.settingsScope` access in `PluginCard` with try/catch to prevent proxy property errors.
174
181
  - **Test**: Added regression test suite simulating strict Cordis Context Proxy behavior.
175
182
 
176
-
177
183
  ## Changed in v0.1.15
178
184
 
179
185
  - **Feature (#54)**: Support native DSH right sidebar (`ctx.sidebarRightTabs` + `sidebar.right.pane.tab` slot) introduced in DSH 0.1.5-alpha.1.
@@ -188,3 +194,11 @@ Audit fixes (#33–#47, #18):
188
194
  - **Quality & UX (#52)**: Dynamic RU/EN locale detection in `HeaderChip`, `LensTab`, and `StatusPanel` via `ctx.locale` for seamless UI integration.
189
195
  - **Perf & Stability (#52)**: Adaptive polling in `HeaderChip` pausing on hidden tabs (`visibilitychange`) and polling actively (4s) only when popover is open.
190
196
  - **Reliability (#52)**: Atomic settings save (`scope.patch` / `scope.setAll`) in `PluginCard` with graceful fallback.
197
+
198
+ ### UI & Styling System (v0.1.16+)
199
+
200
+ Context Lens shares its visual language and component architecture with `dsh-clinebot`:
201
+ - **Native Design System**: 100% theme integration using `--dsw-alias-*` tokens.
202
+ - **Resilient UI Surfaces**: Every component (`PluginCard`, `LensTab`, `StatusPanel`) is protected by an `ErrorBoundary` with instant retry capability.
203
+ - **Reactive Settings**: Live updates via `scope.subscribe()` and zero-delay reads via `scope.getSnapshot()`.
204
+ - **Adaptive Telemetry**: Popover and tab display metric cards for tokens saved, percentage reduced, and live budget utilization.
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
@@ -145,24 +155,20 @@ dsh-context-lens:
145
155
 
146
156
  MIT © [GooDAnDReaDY](https://github.com/GooDAnDReaDY)
147
157
 
148
-
149
158
  ## Changed in v0.1.11
150
159
 
151
160
  Исправления 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
161
 
153
-
154
162
  ## Changed in v0.1.12
155
163
 
156
164
  #43: extract shared `StatusPanel` used by LensTab and HeaderChip popover (budget bar, history, refresh).
157
165
 
158
-
159
166
  ## Changed in v0.1.13
160
167
 
161
168
  - **Fix (#50)**: Безопасная регистрация вкладки BetterSidebar через `ctx.inject(['betterSidebar'], ...)` вместо прямого чтения свойства из Cordis Context Proxy. Устранена ошибка `cannot get property "betterSidebar" without inject` при загрузке клиентской половины в DSH.
162
169
  - **Fix (#50)**: Безопасное обращение к `_ctx.settingsScope` в `PluginCard` через try/catch.
163
170
  - **Тесты**: Добавлены регрессионные тесты со строгим Cordis Context Proxy.
164
171
 
165
-
166
172
  ## Changed in v0.1.15
167
173
 
168
174
  - **Функциональность (#54)**: Поддержка встроенной правой боковой панели DSH (`ctx.sidebarRightTabs` + слот `sidebar.right.pane.tab`) из DSH 0.1.5-alpha.1.
@@ -177,3 +183,11 @@ MIT © [GooDAnDReaDY](https://github.com/GooDAnDReaDY)
177
183
  - **Качество и локализация (#52)**: Динамическое переключение языка интерфейса (RU/EN) в чипе шапки (`HeaderChip`), боковой вкладке (`LensTab`) и панели статуса (`StatusPanel`) через `ctx.locale`.
178
184
  - **Производительность (#52)**: Адаптивный поллинг в `HeaderChip` с паузой при неактивной вкладке браузера (`document.visibilityState`) и учащённым опросом (4 сек) только при открытом поповере.
179
185
  - **Стабильность (#52)**: Атомарное сохранение конфигурации в карточке настроек (`scope.patch` / `scope.setAll`) без риска частичной записи.
186
+
187
+ ### Визуальный стиль и отказоустойчивость UI (v0.1.16+)
188
+
189
+ Context Lens приведен к единому стандарту оформления `dsh-clinebot`:
190
+ - **Нативные токены**: 100% совместимость со светлой и тёмной темами DSH через токены `--dsw-alias-*`.
191
+ - **Изоляция сбоев интерфейса**: Компоненты (`PluginCard`, `LensTab`, `StatusPanel`) обёрнуты в `ErrorBoundary` с кнопкой быстрого повтора («Retry»).
192
+ - **Реактивные настройки**: Автоматическое обновление через `scope.subscribe()` и мгновенное чтение через `scope.getSnapshot()`.
193
+ - **Наглядная телеметрия**: Компактные карточки метрик сэкономленных токенов, процента оптимизации и шкалы сессионного бюджета.
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
@@ -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 IMPORT_RE = /^\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+/;
7
- const COMMENT_RE = /^\s*(\/\/.*|\/\*.*\*\/|\/\*.*|\*.*|#.*)/;
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 JSDoc or line comments directly above a definition)
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)) sig = candidateLine.trim();
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 };