dsh-code-index 0.11.0 → 0.11.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 CHANGED
@@ -2,6 +2,16 @@
2
2
 
3
3
  All notable changes to dsh-code-index are documented here.
4
4
 
5
+ ## 0.11.2 — DSH compatibility range
6
+
7
+ - Allow DSH versions from `0.2.0-rc.2` onward, including prereleases, without claiming future versions have been verified.
8
+
9
+ ## 0.11.1 — DSH rc.3 compatibility
10
+
11
+ - Add the verified exact `@deepseek-ai/dsh-tools@0.2.1-rc.3` host group; retain `0.2.0-rc.2` and `0.2.1-rc.2` support without exemptions or an open-ended range.
12
+ - Verify all eight tools and Impact X-Ray in a real DSH rc.3 Web/Host environment. Keep server/client behavior, runtime dependencies and the development API baseline unchanged.
13
+ - Make rc.3 the default installed-package smoke target and include `code_health` in native runtime dispatch coverage. See `RELEASE_EVIDENCE_v0.11.1.md` for methods and limits.
14
+
5
15
  ## 0.11.0 — Impact X-Ray
6
16
 
7
17
  - Present the existing `code_change_context` analysis in an interactive bilingual Desktop view with source-backed nodes and relationships; keep default text output and `code_context` Context Packs compatible.
package/README.md CHANGED
@@ -5,36 +5,35 @@
5
5
 
6
6
  English | [中文](README.zh.md)
7
7
 
8
- **v0.11.0 — Impact X-Ray.** See the potential blast radius before AI edits code, then inspect each relationship against real source evidence. The 30-second recording shows the real `0.11.0-dev.0` MVP; the dev.1 first-screen change-center and uncertainty improvements are shown in separate [real Desktop screenshots](IMPACT_XRAY_RC.md#first-screen-and-visual-evidence). The release preserves existing `code_change_context` analysis and `code_context` packs.
8
+ ## Impact X-Ray
9
9
 
10
- **Supported Desktop versions**
10
+ **See the blast radius before your AI edits the code.**
11
11
 
12
- The compatibility support introduced in [v0.10.1](https://github.com/lemonxiny55/dsh-code-index/releases/tag/v0.10.1) remains: only DSH/dsh-tools `0.2.0-rc.2` and `0.2.1-rc.2` host groups are supported. Keep each host's first-party packages on the same version.
12
+ A local [DeepSeek Harness (DSH)](https://github.com/deepseek-ai/deepseek-harness) plugin that turns a code diff into an inspectable map of potentially affected callers, imports and test leads. Click a relationship to check its source file, line and evidence.
13
13
 
14
- ## Impact X-Ray
14
+ **For DSH users working with existing code:** inspect likely ripple effects before asking an AI agent to edit. Install the stable **v0.11.1** in a compatible DSH profile:
15
15
 
16
- **See the blast radius before your AI edits the code.**
16
+ ```sh
17
+ dsh plugin --profile desktop add dsh-code-index@0.11.1
18
+ ```
17
19
 
18
- - **Before AI edits your code:** start from a real working-tree Git diff, a supplied diff, or an explicitly labeled file/symbol selection.
19
- - **See what may break:** inspect changed declarations, direct callers, indirect paths, module imports and candidate tests.
20
- - **Inspect the evidence:** select a node or arrow to see its reason, provenance, file, line and actual source snapshot. Expand the view for a graph and evidence side by side; open current files in Desktop's native preview.
21
- - **Know what remains uncertain:** dotted amber `name-only` candidates, import scope, unmapped ranges, missing source and truncation stay visible. A test lead does not prove coverage or failure.
20
+ Restart Desktop after installation. v0.11.1 declares DSH `0.2.0-rc.2`, `0.2.1-rc.2` and `0.2.1-rc.3` host groups; for Desktop rc.3, the compatibility warning was reported gone, but full Electron Desktop feature and Agent acceptance is not claimed. [Install details](#install) · [v0.11.1 verification and limits](RELEASE_EVIDENCE_v0.11.1.md).
22
21
 
23
- This is an interactive presentation of the existing `code_change_context` analysis, with source from the existing reader. It does not introduce a new impact-analysis engine.
22
+ **Watch the 30-second real Desktop demo:** a change to `normalize()` → inspect callers and a test lead → click a relationship to see the actual source location.
24
23
 
25
- ![Impact X-Ray in actual DSH Desktop](assets/impact-xray-mvp.gif)
24
+ ![Impact X-Ray in actual DSH Desktop: changed normalize function, callers, tests and clickable source evidence](assets/impact-xray-mvp.gif)
26
25
 
27
- [Actual recording and reproduction notes](assets/impact-xray-mvp-demo.md) · [Release evidence and remaining limits](RELEASE_EVIDENCE_v0.11.0.md) · [Bilingual release notes](RELEASE_NOTES_v0.11.0.md)
26
+ [Watch MP4](assets/impact-xray-mvp.mp4) · [Full-size GIF](assets/impact-xray-mvp.gif) · [Demo notes and reproduction](assets/impact-xray-mvp-demo.md) · [Install v0.11.1 from npm](https://www.npmjs.com/package/dsh-code-index/v/0.11.1) · [Project](https://github.com/lemonxiny55/dsh-code-index)
28
27
 
29
- The recording shows the real `dev.0` MVP; its first 10 seconds show the changed function, caller/test lanes and source-backed exact relationship. The `dev.1` first-screen improvements are documented separately with actual Desktop screenshots; the video has not been represented as a recording of those later header changes.
28
+ The recording is an actual DSH Desktop interaction with the `0.11.0-dev.0` MVP in Desktop 0.2.1-rc.2. It shows existing analysis and source evidence; it is not a model-driven Agent latency or success claim. See [recording provenance](assets/impact-xray-mvp-demo.md).
30
29
 
31
- Install v0.11.0 into an existing supported Desktop profile with Desktop's bundled CLI:
30
+ - Start from a Git diff or an explicitly selected file/symbol; inspect callers, import dependents, paths and candidate tests.
31
+ - Click a relationship to inspect its provenance and available source snapshot at a file and line.
32
+ - Treat candidates as leads: `name-only` matches can be uncertain, and a test lead does not prove coverage or failure.
32
33
 
33
- ```sh
34
- dsh plugin --profile desktop add dsh-code-index@0.11.0
35
- ```
34
+ Impact X-Ray is an interactive view of the existing `code_change_context` analysis and source reader; it does not add an impact-analysis engine. Relationships are static evidence, not guaranteed runtime impact.
36
35
 
37
- Restart Desktop after installation. For local development, use Node 22/24 and pnpm 11. Desktop 0.2.1-rc.2 received full UI verification. Desktop 0.2.0-rc.2 passed installation and ToolRuntime checks; its full Impact X-Ray UI was not validated. The peer range remains unchanged. See the release evidence for actual methods, performance observations and limitations.
36
+ **Verified:** full X-Ray UI in Desktop 0.2.1-rc.2; Web/Host rc.3 verified for all eight tools and X-Ray (no model-driven Agent run). Desktop 0.2.0-rc.2 passed installation and ToolRuntime checks, not full X-Ray UI. Keep each host's first-party packages on the same declared version. [v0.11.1 evidence and limits](RELEASE_EVIDENCE_v0.11.1.md).
38
37
 
39
38
  Ask the Agent to call `code_change_context` with:
40
39
 
@@ -88,16 +87,16 @@ This supports syntax and static code context, without full HarmonyOS SDK semanti
88
87
 
89
88
  ## Quick start
90
89
 
91
- Requires Node 22/24 and a matching DSH `0.2.0-rc.2` or `0.2.1-rc.2` host group. Install into an existing Desktop profile using its bundled `dsh` CLI:
90
+ Requires Node 22/24. The v0.11.2 candidate allows DSH `>=0.2.0-rc.2`, including prereleases; matching first-party packages should be used. Later versions may attempt to load but have not all been verified. Install into an existing Desktop profile using its bundled `dsh` CLI:
92
91
 
93
92
  ```sh
94
- dsh plugin --profile desktop add dsh-code-index@0.11.0
93
+ dsh plugin --profile desktop add dsh-code-index@0.11.1
95
94
  ```
96
95
 
97
96
  Restart Desktop after installation. For a matching Web profile:
98
97
 
99
98
  ```sh
100
- npx @deepseek-ai/dsh@0.2.1-rc.2 plugin --profile web add dsh-code-index@0.11.0
99
+ npx @deepseek-ai/dsh@0.2.1-rc.2 plugin --profile web add dsh-code-index@0.11.1
101
100
  npx @deepseek-ai/dsh@0.2.1-rc.2 web
102
101
  ```
103
102
 
@@ -149,13 +148,13 @@ Plus an optional **auto-injected system prompt section** (`code-index:repo-map`,
149
148
 
150
149
  Requires `dsh` (any install path — npx, npm, or source) and Node ≥ 22.
151
150
 
152
- The compatibility range introduced in v0.10.1 remains `@deepseek-ai/dsh-tools: 0.2.0-rc.2 || 0.2.1-rc.2`. Use matching DSH/dsh-tools groups, rather than mixing first-party RC packages. The DSH plugin surface remains a preview API; other RCs and future releases are outside this compatibility declaration.
151
+ The v0.11.2 candidate declares `@deepseek-ai/dsh-tools: >=0.2.0-rc.2`, with no upper bound. DSH includes prereleases when checking this range, so future DSH versions may attempt to load the plugin; this does not mean every version has been verified. Use matching DSH/dsh-tools groups. The plugin surface remains a preview API, and future releases may introduce incompatibilities.
153
152
 
154
- Desktop checks DSH peer requirements before activation. v0.10.0's exact `0.2.0-rc.2` pin is rejected by DSH `0.2.1-rc.2`; v0.10.1 enumerates the supported groups instead of requiring a version exemption or an unbounded range. Its development dependency stays on `0.2.0-rc.2` for backward API checks.
153
+ Desktop checks DSH peer requirements before activation. v0.10.0's exact `0.2.0-rc.2` pin is rejected by DSH `0.2.1-rc.2`; v0.10.1 enumerated the then-supported groups; v0.11.2 removes that enumeration. Its development dependency stays on `0.2.0-rc.2` for backward API checks.
155
154
 
156
155
  ```sh
157
156
  # from npm (prebuilt)
158
- npx @deepseek-ai/dsh@0.2.0-rc.2 plugin --profile web add dsh-code-index@0.11.0
157
+ npx @deepseek-ai/dsh@0.2.0-rc.2 plugin --profile web add dsh-code-index@0.11.1
159
158
 
160
159
  # or from a directory containing this checkout
161
160
  npx @deepseek-ai/dsh@0.2.0-rc.2 plugin --profile web add ./dsh-code-index
@@ -323,3 +322,4 @@ To make a report actionable, include the approximate repository size and languag
323
322
 
324
323
  MIT. Not affiliated with DeepSeek; built on the public `dsh` plugin surface.
325
324
 
325
+
package/README.zh.md CHANGED
@@ -2,36 +2,37 @@
2
2
 
3
3
  [English](README.md) | 中文
4
4
 
5
- **v0.11.0 — Impact X-Ray。**在 AI 修改代码前查看潜在影响范围,并用真实源码证据核对每条关系。30 秒录屏来自真实运行的 `0.11.0-dev.0` MVP;dev.1 首屏对变更中心及不确定性的改进另有[真实 Desktop 截图](IMPACT_XRAY_RC.md#first-screen-and-visual-evidence)。本版本复用现有 `code_change_context` 分析,保留 `code_context` pack 行为。
5
+ ## Impact X-Ray
6
6
 
7
- **支持的 Desktop 版本**
7
+ **See the blast radius before your AI edits the code.**
8
8
 
9
- [v0.10.1](https://github.com/lemonxiny55/dsh-code-index/releases/tag/v0.10.1) 引入的兼容范围保持不变:仅支持 DSH/dsh-tools `0.2.0-rc.2`、`0.2.1-rc.2` 两个精确宿主组,每组第一方包必须同版。
9
+ **在 AI 修改代码前,看清潜在影响范围。**
10
10
 
11
- ## Impact X-Ray
11
+ 这是 [DeepSeek Harness(DSH)](https://github.com/deepseek-ai/deepseek-harness) 的本地插件:把代码 diff 呈现为一张可检查的潜在影响图,列出可能受影响的调用者、导入和测试线索。点击关系即可核对源码文件、行号与证据。
12
12
 
13
- **See the blast radius before your AI edits the code.**
13
+ **适合正在维护现有代码的 DSH 用户:** 在让 AI Agent 修改代码前,先查看可能的连带影响。使用正式稳定版 **v0.11.1**,安装到兼容的 DSH profile:
14
+
15
+ ```sh
16
+ dsh plugin --profile desktop add dsh-code-index@0.11.1
17
+ ```
14
18
 
15
- - **在 AI 修改之前:**从真实工作区 Git diff、输入 diff,或明确标注的文件/符号选择开始。
16
- - **看清可能影响什么:**检查变更声明、直接调用者、间接路径、模块导入和测试候选。
17
- - **检查真实证据:**点击节点或箭头,查看纳入原因、关系来源、文件行号及实际源码快照。放大视图中图与证据并排展示,可打开 Desktop 原生文件预览。
18
- - **了解不确定性:**黄色点线的 `name-only` 候选、导入范围、未映射行、缺失源码和裁剪均明确呈现;测试线索不证明覆盖率或必然失败。
19
+ 安装后重启 Desktop。v0.11.1 声明支持 DSH `0.2.0-rc.2`、`0.2.1-rc.2` 和 `0.2.1-rc.3` 宿主版本组;Desktop rc.3 的兼容性提示据反馈已消失,但这不代表 Electron Desktop 全部功能或 Agent 验收通过。[安装说明](#安装) · [v0.11.1 验证与限制](RELEASE_EVIDENCE_v0.11.1.md)。
19
20
 
20
- 这是既有 `code_change_context` 分析和源码读取能力的交互展示,不是新开发的影响分析算法。
21
+ **观看 30 秒真实 Desktop 演示:**`normalize()` 被修改 → 查看调用者与测试线索 → 点击关系查看真实源码位置。
21
22
 
22
- ![真实 DSH Desktop 中的 Impact X-Ray](assets/impact-xray-mvp.gif)
23
+ ![真实 DSH Desktop 中的 Impact X-Ray:变更的 normalize、调用者、测试与可点击的源码证据](assets/impact-xray-mvp.gif)
23
24
 
24
- [真实录制与复现说明](assets/impact-xray-mvp-demo.md) · [发布证据与已知限制](RELEASE_EVIDENCE_v0.11.0.md) · [中英文发布说明](RELEASE_NOTES_v0.11.0.md)
25
+ [观看 MP4](assets/impact-xray-mvp.mp4) · [全尺寸 GIF](assets/impact-xray-mvp.gif) · [演示说明与复现](assets/impact-xray-mvp-demo.md) · [从 npm 安装 v0.11.1](https://www.npmjs.com/package/dsh-code-index/v/0.11.1) · [项目主页](https://github.com/lemonxiny55/dsh-code-index)
25
26
 
26
- 视频展示真实 `dev.0` MVP;前 10 秒可看到变更函数、调用者/测试和有源码证据的 exact 关系。`dev.1` 首屏的变更中心改进另以实机截图记录,没有把视频描述成后续首屏版本的录制。
27
+ 录屏来自真实 DSH Desktop 0.2.1-rc.2 中的 `0.11.0-dev.0` MVP 操作,展示的是既有分析与源码证据;它不代表模型驱动 Agent 的耗时或成功率。详见[录制来源](assets/impact-xray-mvp-demo.md)。
27
28
 
28
- 使用 Desktop 自带的 CLI 将 v0.11.0 安装到现有受支持的 Desktop profile:
29
+ - 从 Git diff 或明确选定的文件/符号出发,查看调用者、导入依赖、影响路径和测试候选。
30
+ - 点击关系,查看其来源,以及可用的文件行号和源码快照。
31
+ - 把候选视为线索:`name-only` 匹配可能不确定;测试线索不证明覆盖率或测试失败。
29
32
 
30
- ```sh
31
- dsh plugin --profile desktop add dsh-code-index@0.11.0
32
- ```
33
+ Impact X-Ray 是既有 `code_change_context` 分析及源码读取能力的交互展示,并未新增影响分析引擎。关系属于静态证据,不保证运行时必然受影响。
33
34
 
34
- 安装后重启 Desktop。本版本的完整 UI 已在 DSH Desktop 0.2.1-rc.2 实机验证;0.2.0-rc.2 通过安装及 ToolRuntime 检查,但未完成完整 Impact X-Ray UI 验收。peer 范围未扩大。实际验证方法、性能观察和已知限制见发布证据。开发构建使用 Node 22/24 与 pnpm 11。
35
+ **验证范围:** Desktop 0.2.1-rc.2 完成完整 X-Ray UI 验证;Web/Host rc.3 完成全部八个工具及 X-Ray 验证(未运行模型驱动 Agent);Desktop 0.2.0-rc.2 通过安装和 ToolRuntime 检查,未验证完整 X-Ray UI。宿主中的第一方包须使用同一已声明版本。[v0.11.1 验证与限制](RELEASE_EVIDENCE_v0.11.1.md)。
35
36
 
36
37
  让 Agent 调用 `code_change_context`:
37
38
 
@@ -85,16 +86,16 @@ node scripts/impact-xray-demo.mjs D:/absolute/path/to/new-demo-repo
85
86
 
86
87
  ## 快速开始
87
88
 
88
- 需要 Node 22/24 与匹配的 DSH `0.2.0-rc.2` 或 `0.2.1-rc.2` 宿主版本组。用 Desktop 自带的 `dsh` CLI 安装到现有 profile:
89
+ 需要 Node 22/24。v0.11.2 候选版本允许 DSH `>=0.2.0-rc.2`(包括预发布版本),第一方包应使用配套版本。后续版本可以尝试加载,但并不代表全部经过验证。用 Desktop 自带的 `dsh` CLI 安装到现有 profile:
89
90
 
90
91
  ```sh
91
- dsh plugin --profile desktop add dsh-code-index@0.11.0
92
+ dsh plugin --profile desktop add dsh-code-index@0.11.1
92
93
  ```
93
94
 
94
95
  安装后重启 Desktop。匹配的 Web profile 可使用:
95
96
 
96
97
  ```sh
97
- npx @deepseek-ai/dsh@0.2.1-rc.2 plugin --profile web add dsh-code-index@0.11.0
98
+ npx @deepseek-ai/dsh@0.2.1-rc.2 plugin --profile web add dsh-code-index@0.11.1
98
99
  npx @deepseek-ai/dsh@0.2.1-rc.2 web
99
100
  ```
100
101
 
@@ -146,13 +147,13 @@ npx @deepseek-ai/dsh@0.2.1-rc.2 web
146
147
 
147
148
  需要 `dsh`(任意安装方式——npx、npm 或源码)与 Node ≥ 22。
148
149
 
149
- v0.10.1 引入的兼容范围继续保持 `@deepseek-ai/dsh-tools: 0.2.0-rc.2 || 0.2.1-rc.2`。使用配套的 DSH/dsh-tools 版本组,不混装第一方 RC 包。DSH 插件接口仍属于预览 API;其他 RC 和未来版本不在此兼容声明范围内。
150
+ v0.11.2 候选版本声明 `@deepseek-ai/dsh-tools: >=0.2.0-rc.2`,不设置上限。DSH 检查范围时包含预发布版本,因此未来版本可以尝试加载插件,但这不代表每个版本都经过验证。请使用配套的 DSH/dsh-tools 版本组;插件接口仍是预览 API,未来版本可能产生兼容问题。
150
151
 
151
- Desktop 在激活前检查 DSH peer 约束。v0.10.0 的精确 `0.2.0-rc.2` pin 会被 DSH `0.2.1-rc.2` 拒绝;v0.10.1 明确列举支持组,不依赖版本豁免或无上限范围。开发依赖保留 `0.2.0-rc.2`,继续检查旧版 API。
152
+ Desktop 在激活前检查 DSH peer 约束。v0.10.0 的精确 `0.2.0-rc.2` pin 会被 DSH `0.2.1-rc.2` 拒绝;v0.10.1 列举了当时支持的版本组;v0.11.2 移除这一枚举。开发依赖保留 `0.2.0-rc.2`,继续检查旧版 API。
152
153
 
153
154
  ```sh
154
155
  # 从 npm(预编译)
155
- npx @deepseek-ai/dsh@0.2.0-rc.2 plugin --profile web add dsh-code-index@0.11.0
156
+ npx @deepseek-ai/dsh@0.2.0-rc.2 plugin --profile web add dsh-code-index@0.11.1
156
157
 
157
158
  # 或从包含本仓库检查副本的目录
158
159
  npx @deepseek-ai/dsh@0.2.0-rc.2 plugin --profile web add ./dsh-code-index
@@ -312,3 +313,4 @@ node.exe scripts\fix-wsl-links.mjs C:\Users\you\.dsh\profiles\web # dsh profil
312
313
 
313
314
  MIT。与 DeepSeek 无关;基于公开的 `dsh` 插件接口构建。
314
315
 
316
+
package/dist/index.d.ts CHANGED
@@ -1,708 +1,22 @@
1
- import * as _deepseek_ai_dsh_tools from '@deepseek-ai/dsh-tools';
2
- import Schema from '@deepseek-ai/schemastery';
3
-
4
- /** Shared data model for dsh-code-index. */
5
- /** On-disk cache layout version. Bump when persisted graph/symbol shapes change. */
6
- declare const REPO_INDEX_SCHEMA_VERSION: 4;
7
- type SymbolKind = 'function' | 'method' | 'class' | 'interface' | 'type' | 'enum' | 'variable' | 'field' | 'import' | 'module';
8
- /** Stable, file-qualified symbol identity: `sym:v1:<file>#<scope>/<segment>`. */
9
- type SymbolId = string;
10
- /** Vocabulary for one scope segment in a qualified symbol id. */
11
- type ScopeKind = 'module' | 'namespace' | 'class' | 'interface' | 'trait' | 'impl' | 'function' | 'method' | 'owner';
12
- interface SymbolScopePart {
13
- kind: ScopeKind;
14
- name: string;
15
- /** 1-based among sibling scope owners with the same kind and name. */
16
- ordinal: number;
17
- }
18
- interface SymbolInfo {
19
- /** ArkTS decorators as written; their source lines belong to the definition. */
20
- decorators?: string[];
21
- /** Stable qualified id; unique within a RepoIndex. */
22
- id: SymbolId;
23
- /** Symbol name (identifier / type id / member name). */
24
- name: string;
25
- kind: SymbolKind;
26
- /** Repo-relative path of the containing file, always forward-slash. */
27
- file: string;
28
- /** 1-based start line. */
29
- line: number;
30
- /** 1-based end line (inclusive). */
31
- endLine: number;
32
- /** Normalized public/export status by language; Rust: unrestricted `pub` only. */
33
- exported: boolean;
34
- /** Short human-readable signature, e.g. `greet(name: string)` — empty when n/a. */
35
- signature: string;
36
- /** Owners only; excludes the symbol itself. Empty at module level. */
37
- scope: SymbolScopePart[];
38
- /** 1-based among symbols with the same scope, kind, and name. */
39
- ordinal: number;
40
- }
41
- /** One name bound by an import statement, with its local alias. */
42
- interface ImportBinding {
43
- /** Imported name: "foo" | "default" | "*" | null (namespace/package). */
44
- imported: string | null;
45
- /** Name visible in this file (alias when renamed). */
46
- local: string;
47
- kind: 'named' | 'default' | 'namespace' | 'package' | 'static' | 'glob';
48
- }
49
- /** Structured form of one import/include/use site. */
50
- interface ImportInfo {
51
- specifier: string;
52
- line: number;
53
- kind: 'import' | 'reexport' | 'include' | 'use';
54
- bindings: ImportBinding[];
55
- }
56
- /** One call site: callee name, line, and enclosing function ('' = module level). */
57
- interface CallInfo {
58
- /** ArkUI syntax requires an explicit/local binding; no global name guessing. */
59
- context?: 'arkui';
60
- /** Callee name as written (identifier, member/property, or qualified tail). */
61
- name: string;
62
- /** 1-based line of the call expression. */
63
- line: number;
64
- /** Enclosing function/method name, or '' for a module-level call. */
65
- from: string;
66
- /** Structural owner from AST containment; null at module level. */
67
- fromId: SymbolId | null;
68
- /** Receiver/namespace text when available: `ns.foo()` -> "ns"; bare -> null. */
69
- qualifier: string | null;
70
- }
71
- interface IndexedFile {
72
- /** Syntax/read completeness, not a typecheck or HarmonyOS runtime verdict. */
73
- diagnostic?: ParseDiagnostic;
74
- /** Repo-relative path (forward-slash). */
75
- path: string;
76
- lang: string;
77
- /** fs mtime of the source file at index time (milliseconds). */
78
- mtimeMs: number;
79
- symbols: SymbolInfo[];
80
- /** Derived compatibility view of {@link importDetails} specifiers. */
81
- imports?: string[];
82
- /** Structured import/include/use sites with their name bindings. */
83
- importDetails?: ImportInfo[];
84
- /** Call sites found in this file (callee + line + enclosing function).
85
- * Optional because caches written before call-graph support lack it. */
86
- calls?: CallInfo[];
87
- }
88
- interface ParseDiagnostic {
89
- status: 'parsed' | 'partial' | 'failed';
90
- errorCount: number;
91
- missingCount: number;
92
- issues: Array<{
93
- kind: 'ERROR' | 'MISSING';
94
- line: number;
95
- }>;
96
- reason?: 'source-unavailable' | 'parser-failed';
97
- }
98
- interface RepoIndex {
99
- /** Persisted layout version; see {@link REPO_INDEX_SCHEMA_VERSION}. */
100
- schemaVersion: typeof REPO_INDEX_SCHEMA_VERSION;
101
- /** Absolute source root this index describes. */
102
- root: string;
103
- /** Unix ms when the index was generated. */
104
- generatedAt: number;
105
- files: IndexedFile[];
106
- excludedDirs: string[];
107
- }
108
- declare function symbolCount(index: RepoIndex): number;
109
- /** Optional config consumed by the index build pipeline. */
110
- interface IndexOptions {
111
- /** Extra directories to exclude, appended to the defaults. */
112
- excludeDirs?: string[];
113
- /** Minimum mtime delta (ms) that forces a re-extract in refresh mode. */
114
- staleToleranceMs?: number;
115
- }
116
-
117
- /** Build a RepoIndex for a workspace: scan -> extract -> persist. */
118
-
119
- /**
120
- * Full build: scan + extract every supported file. Existing per-file
121
- * extraction is reused when `previous` holds an identical mtime for the
122
- * same rel path (incremental refresh), so touched files alone re-parse.
123
- */
124
- declare function buildIndex(root: string, options?: IndexOptions, previous?: RepoIndex | null, forcePaths?: ReadonlySet<string>): Promise<RepoIndex>;
125
- /** Convenience wrapper: evolve an on-disk cache if `root` exists. */
126
- declare function buildIndexWithCache(root: string, options?: IndexOptions, cacheDir?: string, forcePaths?: ReadonlySet<string>): Promise<RepoIndex>;
127
- /**
128
- * Locate the git repo root for a path by walking up to the nearest `.git`
129
- * directory. Bounded walk (max `maxLevels` levels); returns `null` when no
130
- * repo marker is found — callers must NOT index an untagged directory
131
- * (the fs root is the classic footgun: indexing `C:\` by accident).
132
- */
133
- declare function findRepoRoot(startDir: string, maxLevels?: number): Promise<string | null>;
134
-
135
- /**
136
- * tree-sitter symbol extraction.
137
- *
138
- * Parses a source text with a per-language grammar (web-tree-sitter WASM,
139
- * static grammars from tree-sitter-wasms) and returns flat SymbolInfo rows.
140
- *
141
- * web-tree-sitter 0.25 loads the existing tree-sitter-wasms grammars and the
142
- * pinned ArkTS ABI-14 asset. See grammars/README.md for provenance.
143
- */
144
-
145
- type LanguageId = 'arkts' | 'typescript' | 'javascript' | 'python' | 'go' | 'rust' | 'java' | 'cpp' | 'c';
146
- declare function languageForFile(filePath: string): LanguageId | null;
147
- interface ExtractedFile {
148
- diagnostic: ParseDiagnostic;
149
- symbols: SymbolInfo[];
150
- /** Derived compatibility view of {@link importDetails} specifiers. */
151
- imports: string[];
152
- /** Structured import/include/use sites with name bindings. */
153
- importDetails: ImportInfo[];
154
- /** Call sites, ordered by line: callee name + enclosing function. */
155
- calls: CallInfo[];
156
- }
157
- declare function extractAll(code: string, id: LanguageId, file?: string): Promise<ExtractedFile>;
158
- /** Symbols only — see extractAll for the combined parse. */
159
- declare function extractSymbols(code: string, id: LanguageId): Promise<SymbolInfo[]>;
160
- /** Compile a symbol query for a code sample (used by tests). */
161
- declare function parseFileToSymbols(filePath: string, repoRoot: string, code?: string): Promise<SymbolInfo[]>;
162
-
163
- /** Workspace file discovery with dir exclusions and mtime tracking. */
164
-
165
- declare const DEFAULT_EXCLUDED_DIRS: string[];
166
- /** Language-agnostic source extensions we index. */
167
- declare const SUPPORTED_EXTS: Set<string>;
168
- interface ScannedFile {
169
- /** Absolute path on disk. */
170
- abs: string;
171
- /** Repo-relative path (forward-slash). */
172
- rel: string;
173
- mtimeMs: number;
174
- }
175
- /**
176
- * Recursively walk `root` and return indexed files, skipping excluded dir
177
- * components at any depth. Uses readdir with `withFileTypes` so we never
178
- * stat every entry; mtime comes from a targeted stat per candidate file.
179
- */
180
- declare function scanRepo(root: string, options?: IndexOptions): Promise<ScannedFile[]>;
181
-
182
- /** On-disk JSON cache for RepoIndex, keyed by repo root. */
183
-
184
- declare const CACHE_DIR_NAME = ".dsh-code-index";
185
- /** Default cache location: `<repoRoot>/.dsh-code-index/index.json`. */
186
- declare function defaultCachePath(root: string, cacheDir?: string): string;
187
- declare function loadIndex(cachePath: string): Promise<RepoIndex | null>;
188
- declare function saveIndex(cachePath: string, index: RepoIndex): Promise<void>;
189
-
190
- /** One summary and at most three file locations. No source or exception dump. */
191
- declare function indexIntegrityWarnings(index: RepoIndex): string[];
192
-
193
- /** Pure search / filter logic over a RepoIndex — unit-testable, no IO. */
194
-
195
- interface SymbolFilter {
196
- query?: string;
197
- file?: string;
198
- kind?: SymbolKind;
199
- exportedOnly?: boolean;
200
- }
201
- interface RankedHit extends SymbolInfo {
202
- /** 0..1 relevance. 1 = exact name match; lower = fuzzier. */
203
- score: number;
204
- }
205
- /** Filter symbols by file/kind/export, then score by name against query (if any). */
206
- declare function searchSymbols(index: RepoIndex, filter: SymbolFilter, limit?: number, refs?: Map<string, number>): RankedHit[];
207
- /** Neat one-line rendering of a hit for terminal/chat output. */
208
- declare function renderHit(hit: RankedHit): string;
209
-
210
- /**
211
- * Bounded, ranked repo map generation — the "aider-style" overview the model
212
- * can turn to before browsing files. Pure logic, no IO.
213
- */
214
-
215
- interface RepoMapOptions {
216
- /** Max files to include (default 24). */
217
- topFiles?: number;
218
- /** Max symbols per file (default 18). */
219
- symbolsPerFile?: number;
220
- /** Hard cap on rendered characters (default 3200). */
221
- maxChars?: number;
222
- }
223
- interface RepoMapEntry {
224
- path: string;
225
- score: number;
226
- symbols: Array<{
227
- name: string;
228
- kind: SymbolKind;
229
- line: number;
230
- signature: string;
231
- }>;
232
- }
233
- /** Density-aware file score: weighted symbols minus bloat; test paths damped. */
234
- declare function scoreFile(file: IndexedFile): number;
235
- /** Rank files, take the top slice, cap per-file symbols. */
236
- declare function rankRepoMap(index: RepoIndex, options?: RepoMapOptions): RepoMapEntry[];
237
- /** Render the ranked map as markdown, hard-truncated to maxChars. */
238
- declare function renderRepoMap(entries: RepoMapEntry[], options?: RepoMapOptions): string;
239
-
240
- /** Function-level call graph built from the cached index — pure, no IO. */
241
-
242
- /** name -> definitions; several when same-named symbols live in different files. */
243
- declare function buildSymbolTable(index: RepoIndex): Map<string, SymbolInfo[]>;
244
- /** One call site that invokes the queried symbol. */
245
- interface CallerHit {
246
- file: string;
247
- line: number;
248
- from: string;
249
- }
250
- /** One distinct symbol the queried function calls, with its first call line. */
251
- interface CalleeHit {
252
- name: string;
253
- line: number;
254
- /** In-repo definitions matched by the callee name. */
255
- targets: SymbolInfo[];
256
- }
257
- interface SymbolRefs {
258
- /** Definitions of the queried symbol (empty when only call sites exist). */
259
- defs: SymbolInfo[];
260
- callers: CallerHit[];
261
- callees: CalleeHit[];
262
- }
263
- /** How many call sites reference each name — used to rank search hits. */
264
- declare function callerCounts(index: RepoIndex): Map<string, number>;
265
- /**
266
- * Resolve one symbol to its callers (call sites invoking it anywhere) and its
267
- * callees (calls made inside the definition, attributed by the extracted
268
- * enclosing-function name). Name-based, so it is a best-effort view: like-named
269
- * symbols are reported as candidates rather than guessed apart.
270
- */
271
- declare function symbolRefs(index: RepoIndex, symbol: string, limit?: number): SymbolRefs;
272
- /**
273
- * How sure the graph is about one resolved edge. Deliberately coarse: the
274
- * index has no type checker, so `exact` only ever means "one structurally
275
- * unambiguous target under this index's model".
276
- */
277
- type ResolutionLabel = 'exact' | 'import-scoped' | 'name-only';
278
- /** Which resolution tier produced an edge — the *why* behind its label. */
279
- type ResolutionProvenance = 'structural-owner' | 'local-unique' | 'explicit-import-binding' | 'namespace-import' | 'resolved-import-module' | 'global-name';
280
-
281
- /** Import-graph health checks: circular dependencies and orphan modules. */
282
-
283
- interface ModuleGraph {
284
- nodes: string[];
285
- edges: Map<string, Set<string>>;
286
- }
287
- /** Nodes are indexed files; an edge A -> B means A imports B (self-edges dropped). */
288
- declare function buildModuleGraph(index: RepoIndex): ModuleGraph;
289
- /** Tarjan strongly-connected components of size > 1 — i.e. import cycles. */
290
- declare function findCycles(index: RepoIndex): string[][];
291
- /**
292
- * Symbol-bearing files that neither import nor are imported by any other file,
293
- * excluding conventional entry points and tests (which are legitimately
294
- * unreferenced). A cheap, low-false-positive stand-in for dead-code detection.
295
- */
296
- declare function findOrphanModules(index: RepoIndex): string[];
297
-
298
- /**
299
- * Unified-diff parsing and a thin `git` adapter.
300
- *
301
- * `parseUnifiedDiff` is pure (no IO) so it is unit-testable in isolation; the
302
- * two readers shell out to `git` exclusively through `execFile` with an argv
303
- * array — a ref or path is never interpolated into a shell string.
304
- */
305
- /** One `@@` hunk header; a missing count means 1 (git omits `,1`). */
306
- interface DiffHunk {
307
- oldStart: number;
308
- oldLines: number;
309
- newStart: number;
310
- newLines: number;
311
- }
312
- /** One file's entry in a unified diff. */
313
- interface FileChange {
314
- /** Repo-relative path on the base side, or null for an added file. */
315
- oldPath: string | null;
316
- /** Repo-relative path on the current side, or null for a deleted file. */
317
- newPath: string | null;
318
- status: 'added' | 'modified' | 'deleted' | 'renamed';
319
- hunks: DiffHunk[];
320
- }
321
- /**
322
- * Parse `git diff` / `diff -u` output into per-file changes. Handles
323
- * `diff --git`, `new file mode`, `deleted file mode`, `rename from/to`,
324
- * `---`/`+++` (including `/dev/null`), and `@@` headers with omitted counts.
325
- */
326
- declare function parseUnifiedDiff(text: string): FileChange[];
327
- /**
328
- * Working-tree diff against `baseRef`, rename-aware and hunk-minimal.
329
- * Includes non-ignored untracked files and reliable exact-content renames.
330
- */
331
- declare function readWorkingTreeDiff(root: string, baseRef: string): Promise<string>;
332
- /** Read one repo-relative file at a ref; null when the path/ref is absent. */
333
- declare function readGitFileAtRef(root: string, ref: string, repoRelativePath: string): Promise<string | null>;
334
-
335
- /**
336
- * Change-aware context (design §3): map a git/working-tree diff (or an explicit
337
- * file/symbol selection) onto indexed symbols, then walk the provenance-labeled
338
- * reference graph to surface callers, import dependents, transitive impact,
339
- * entry-point paths, and likely affected tests.
340
- *
341
- * Every relation keeps the reference graph's honest label (`exact` /
342
- * `import-scoped` / `name-only`); a diff hunk intersecting a symbol's declared
343
- * line range is the only thing treated as `exact`.
344
- */
345
-
346
- type ChangeKind = 'added' | 'modified' | 'deleted' | 'renamed' | 'unclassified';
347
- interface ChangedSymbol {
348
- symbol: SymbolInfo;
349
- change: ChangeKind;
350
- side: 'current' | 'base';
351
- /** A hunk range intersecting the declaration is structural, not inferred. */
352
- resolution: 'exact';
353
- /** First intersecting changed line, used for large-declaration windows. */
354
- focusLine?: number;
355
- }
356
- interface UnmappedChange {
357
- file: string;
358
- side: 'current' | 'base';
359
- ranges: Array<{
360
- startLine: number;
361
- endLine: number;
362
- }>;
363
- reason: 'outside-symbol' | 'base-content-unavailable';
364
- }
365
- interface ImpactHop {
366
- fromId: SymbolId | null;
367
- toId: SymbolId;
368
- callSite: {
369
- file: string;
370
- line: number;
371
- };
372
- resolution: ResolutionLabel;
373
- reason: ResolutionProvenance;
374
- }
375
- interface ImpactRow {
376
- symbol: SymbolInfo;
377
- depth: number;
378
- via: ImpactHop;
379
- resolution: ResolutionLabel;
380
- }
381
- interface SymbolPath {
382
- entry: SymbolInfo;
383
- changed: SymbolInfo;
384
- hops: ImpactHop[];
385
- resolution: ResolutionLabel;
386
- }
387
- interface ImportDependent {
388
- file: string;
389
- changedFile: string;
390
- specifier: string;
391
- resolution: 'import-scoped';
392
- }
393
- interface AffectedTest {
394
- file: string;
395
- resolution: ResolutionLabel;
396
- reason: 'changed-test' | 'imports-changed-file' | 'imports-impact-file' | 'references-symbol-name' | 'path-convention';
397
- distance?: number;
398
- }
399
- interface ChangeContextResult {
400
- root: string;
401
- source: 'git' | 'diff' | 'files' | 'symbols';
402
- baseRef?: string;
403
- changed: ChangedSymbol[];
404
- unmapped: UnmappedChange[];
405
- directCallers: ImpactRow[];
406
- importDependents: ImportDependent[];
407
- paths: SymbolPath[];
408
- impact: ImpactRow[];
409
- tests: AffectedTest[];
410
- warnings: string[];
411
- truncated: {
412
- callers: boolean;
413
- dependents: boolean;
414
- paths: boolean;
415
- impact: boolean;
416
- tests: boolean;
417
- };
418
- }
419
- interface CodeChangeContextArgs {
420
- outputFormat?: 'text' | 'xray';
421
- repoRoot?: string;
422
- diff?: string;
423
- baseRef?: string;
424
- files?: string[];
425
- symbols?: SymbolId[];
426
- maxDepth?: number;
427
- maxImpact?: number;
428
- maxPaths?: number;
429
- maxTests?: number;
430
- }
431
- interface ChangeContextOptions {
432
- maxDepth?: number;
433
- maxImpact?: number;
434
- maxPaths?: number;
435
- maxTests?: number;
436
- }
437
- /** Normalized input: exactly one selection mode. */
438
- type ChangeContextInput = {
439
- kind: 'git';
440
- root: string;
441
- baseRef: string;
442
- } | {
443
- kind: 'diff';
444
- root: string;
445
- text: string;
446
- baseRef?: string;
447
- } | {
448
- kind: 'files';
449
- files: string[];
450
- } | {
451
- kind: 'symbols';
452
- symbolIds: SymbolId[];
453
- };
454
- /** Validate flat tool args and normalize them into one input mode. */
455
- declare function changeContextInputFromArgs(args: Pick<CodeChangeContextArgs, 'diff' | 'baseRef' | 'files' | 'symbols'>, root: string): ChangeContextInput;
456
- declare function buildChangeContext(index: RepoIndex, input: ChangeContextInput, options?: ChangeContextOptions): Promise<ChangeContextResult>;
457
- /**
458
- * Render the result as fixed skeleton sections. Section headers and warnings
459
- * are always kept; rows are trimmed to the final character cap, which then
460
- * appends an explicit truncation line.
461
- */
462
- declare function renderChangeContext(result: ChangeContextResult, maxChars?: number): string;
463
-
464
- interface SourceExcerpt {
465
- file: string;
466
- startLine: number;
467
- endLine: number;
468
- side: 'current' | 'base';
469
- ref?: string;
470
- mode: 'complete' | 'window' | 'signature';
471
- code?: string;
472
- signature?: string;
473
- }
474
-
475
- interface ContextPackItem extends Partial<SourceExcerpt> {
476
- kind: 'primary' | 'caller' | 'callee' | 'import' | 'test' | 'change' | 'file' | 'relationship';
477
- name?: string;
478
- reason: string;
479
- resolution?: ResolutionLabel;
480
- provenance?: string;
481
- change?: string;
482
- text?: string;
483
- }
484
- /** The only final presentation DTO. Items here have already passed selection. */
485
- interface ContextPack {
486
- version: 1;
487
- root: string;
488
- task: string;
489
- route: TaskContextResult['route']['kind'];
490
- items: ContextPackItem[];
491
- gaps: string[];
492
- budget: {
493
- budgetChars: number;
494
- usedChars: number;
495
- packChars: number;
496
- truncated: boolean;
497
- };
498
- }
499
- declare function renderContextPack(pack: ContextPack): string;
500
-
501
- /**
502
- * Task-aware structural context orchestration.
503
- *
504
- * This module deliberately contains no parser, search index, graph, or git
505
- * implementation of its own. It ranks the existing primitives into a compact
506
- * package that answers the question: which code matters for this task?
507
- */
508
-
509
- type ContextTaskKind = 'change' | 'symbol' | 'architecture' | 'test' | 'exploration' | 'ambiguous';
510
- interface ContextRoute {
511
- kind: ContextTaskKind;
512
- queries: string[];
513
- mentionedFiles: string[];
514
- exactSymbolNames: string[];
515
- sources: string[];
516
- includeChangeContext: boolean;
517
- includeRelationships: boolean;
518
- }
519
- interface ContextOptions {
520
- budgetChars?: number;
521
- maxFiles?: number;
522
- maxSymbols?: number;
523
- }
524
- interface ContextSymbol {
525
- symbol: SymbolInfo;
526
- score: number;
527
- provenance: 'exact' | 'lexical';
528
- reason: string;
529
- }
530
- interface ContextFile {
531
- path: string;
532
- score: number;
533
- reason: string;
534
- }
535
- interface ContextRelationship {
536
- text: string;
537
- resolution: ResolutionLabel;
538
- priority: number;
539
- key: string;
540
- provenance: string;
541
- }
542
- interface ContextConfidence {
543
- exact: number;
544
- 'import-scoped': number;
545
- 'name-only': number;
546
- }
547
- interface TaskContextResult {
548
- pack: ContextPack;
549
- root: string;
550
- task: string;
551
- route: ContextRoute;
552
- primarySymbols: ContextSymbol[];
553
- relevantFiles: ContextFile[];
554
- relationships: ContextRelationship[];
555
- changeContext: ChangeContextResult | null;
556
- tests: string[];
557
- testEvidence: AffectedTest[];
558
- confidence: ContextConfidence;
559
- warnings: string[];
560
- budget: {
561
- usedChars: number;
562
- budgetChars: number;
563
- truncated: boolean;
564
- };
565
- }
566
- /** Classify a task and decide which existing primitives should be composed. */
567
- declare function routeTask(task: string, index?: RepoIndex): ContextRoute;
568
- /** Build a deterministic, bounded context package from the current task. */
569
- declare function buildTaskContext(index: RepoIndex, task: string, options?: ContextOptions): Promise<TaskContextResult>;
570
- /** Text always renders the final selected pack. */
571
- declare function renderTaskContext(result: TaskContextResult): string;
572
-
573
- declare const tools: _deepseek_ai_dsh_tools.ToolDefinition[];
574
-
575
- /** Browser-safe presentation contract. Persisted v1 PoCs remain readable. */
576
- declare const XRAY_LIMITS: {
577
- readonly nodes: 32;
578
- readonly edges: 48;
579
- readonly paths: 12;
580
- readonly evidenceChars: 900;
581
- readonly metadataBytes: 96000;
582
- };
583
- interface XrayEvidence {
584
- file: string;
585
- line: number;
586
- startLine: number;
587
- side: 'current' | 'base';
588
- ref?: string;
589
- type?: 'declaration' | 'call-site' | 'import-site' | 'test-lead' | 'unmapped-change';
590
- code?: string;
591
- gap?: string;
592
- }
593
- interface XrayNode {
594
- id: string;
595
- name: string;
596
- kind: string;
597
- file: string;
598
- line: number;
599
- changed: boolean;
600
- category?: 'change' | 'caller' | 'impact' | 'module' | 'test';
601
- depth?: number;
602
- resolution?: ImpactHop['resolution'];
603
- change?: string;
604
- reason: string;
605
- evidence: XrayEvidence;
606
- }
607
- interface XrayEdge {
608
- id: string;
609
- from: string;
610
- to: string;
611
- kind?: 'call' | 'import';
612
- resolution: ImpactHop['resolution'];
613
- reason: string;
614
- evidence: XrayEvidence;
615
- }
616
- interface XrayPath {
617
- id: string;
618
- from: string;
619
- to: string;
620
- edgeIds: string[];
621
- resolution: ImpactHop['resolution'];
622
- omitted: boolean;
623
- }
624
- interface ImpactXray {
625
- card: 'impact-xray';
626
- version: 1 | 2;
627
- root: string;
628
- source: ChangeContextResult['source'];
629
- nodes: XrayNode[];
630
- edges: XrayEdge[];
631
- tests: Array<ChangeContextResult['tests'][number] & {
632
- nodeId?: string;
633
- }>;
634
- imports: Array<ChangeContextResult['importDependents'][number] & {
635
- edgeId?: string;
636
- }>;
637
- paths?: XrayPath[];
638
- unmapped?: Array<ChangeContextResult['unmapped'][number] & {
639
- evidence: XrayEvidence;
640
- }>;
641
- bounds?: {
642
- analysis: ChangeContextResult['truncated'];
643
- projection: boolean;
644
- text?: boolean;
645
- totals: {
646
- changed: number;
647
- callers: number;
648
- impact: number;
649
- imports: number;
650
- tests: number;
651
- paths: number;
652
- unmapped: number;
653
- };
654
- };
655
- gaps: string[];
656
- truncated: boolean;
657
- }
658
-
659
- /** Presentation of existing analysis. Never resolves new function-call edges. */
660
- declare function buildImpactXray(index: RepoIndex, result: ChangeContextResult): Promise<ImpactXray>;
661
-
662
- /** Plugin configuration: merged once at apply time, read wherever needed. */
663
-
664
- /** DSH 0.1.7+ renders fields marked volatile in its per-plugin config forms. */
665
- declare const Config: Schema<Schemastery.ObjectS<NoInfer<{
666
- excludeDirs: Schema<NoInfer<string[]>, NoInfer<string[]>, "volatile-defined">;
667
- mapTopFiles: Schema<number, number, "volatile-defined">;
668
- mapMaxChars: Schema<number, number, "volatile-defined">;
669
- mapTtlMs: Schema<number, number, "volatile-defined">;
670
- autoInject: Schema<boolean, boolean, "volatile-defined">;
671
- codeHealth: Schema<boolean, boolean, "volatile-defined">;
672
- toolSurface: Schema<string, string, "volatile-defined">;
673
- externalWatch: Schema<boolean, boolean, "volatile-defined">;
674
- watchDebounceMs: Schema<number, number, "volatile-defined">;
675
- }>>, Schemastery.ObjectT<NoInfer<{
676
- excludeDirs: Schema<NoInfer<string[]>, NoInfer<string[]>, "volatile-defined">;
677
- mapTopFiles: Schema<number, number, "volatile-defined">;
678
- mapMaxChars: Schema<number, number, "volatile-defined">;
679
- mapTtlMs: Schema<number, number, "volatile-defined">;
680
- autoInject: Schema<boolean, boolean, "volatile-defined">;
681
- codeHealth: Schema<boolean, boolean, "volatile-defined">;
682
- toolSurface: Schema<string, string, "volatile-defined">;
683
- externalWatch: Schema<boolean, boolean, "volatile-defined">;
684
- watchDebounceMs: Schema<number, number, "volatile-defined">;
685
- }>>, "plain">;
686
- interface PluginConfig {
687
- /** Extra directories to exclude from indexing (appended to defaults). */
688
- excludeDirs?: string[];
689
- /** Max files in the ranked repo map (code_map / auto section). */
690
- mapTopFiles?: number;
691
- /** Hard char cap for rendered maps. */
692
- mapMaxChars?: number;
693
- /** Refresh interval for the auto-injected map (ms, min 1000). */
694
- mapTtlMs?: number;
695
- /** Set false to disable the auto-injected system section. */
696
- autoInject?: boolean;
697
- /** Register the code_health tool (circles / orphans). Off by default. */
698
- codeHealth?: boolean;
699
- /** Experimental tool surface; full preserves the complete v0.6 API. */
700
- toolSurface?: 'full' | 'compact';
701
- /** Observe source changes made by editors and external tools. */
702
- externalWatch?: boolean;
703
- /** Coalesce filesystem events before refreshing affected files. */
704
- watchDebounceMs?: number;
705
- }
1
+ export { buildIndex, buildIndexWithCache, findRepoRoot } from './buildIndex.js';
2
+ export { extractAll, extractSymbols, languageForFile, parseFileToSymbols } from './extract.js';
3
+ export { DEFAULT_EXCLUDED_DIRS, SUPPORTED_EXTS, scanRepo } from './scan.js';
4
+ export { CACHE_DIR_NAME, defaultCachePath, loadIndex, saveIndex } from './store.js';
5
+ export { IndexOptions, IndexedFile, ParseDiagnostic, RepoIndex, SymbolInfo, SymbolKind, symbolCount } from './types.js';
6
+ export { indexIntegrityWarnings } from './integrity.js';
7
+ export { renderHit, searchSymbols } from './search.js';
8
+ export { rankRepoMap, renderRepoMap, scoreFile } from './repomap.js';
9
+ export { buildSymbolTable, callerCounts, symbolRefs } from './refgraph.js';
10
+ export { buildModuleGraph, findCycles, findOrphanModules } from './health.js';
11
+ export { DiffHunk, FileChange, parseUnifiedDiff, readGitFileAtRef, readWorkingTreeDiff } from './git-diff.js';
12
+ export { ContextFile, ContextOptions, ContextRelationship, ContextRoute, ContextSymbol, ContextTaskKind, TaskContextResult, buildTaskContext, renderTaskContext, routeTask } from './context.js';
13
+ export { ContextPack, ContextPackItem, renderContextPack } from './context-pack.js';
14
+ export { AffectedTest, ChangeContextInput, ChangeContextOptions, ChangeContextResult, ChangeKind, ChangedSymbol, CodeChangeContextArgs, ImpactHop, ImpactRow, ImportDependent, SymbolPath, UnmappedChange, buildChangeContext, changeContextInputFromArgs, renderChangeContext } from './change-context.js';
15
+ export { tools } from './tools.js';
16
+ export { XRAY_LIMITS, buildImpactXray } from './impact-xray.js';
17
+ export { ImpactXray, XrayEdge, XrayEvidence, XrayNode, XrayPath } from './impact-xray-model.js';
18
+ import { PluginConfig } from './config.js';
19
+ export { Config } from './config.js';
706
20
 
707
21
  /**
708
22
  * dsh-code-index — DeepSeek Harness bundle entry.
@@ -738,4 +52,4 @@ declare const name = "dsh-code-index";
738
52
  declare const inject: readonly ["tools", "systemPrompt"];
739
53
  declare function apply(ctx: MinimalContext, pluginConfig?: PluginConfig): void;
740
54
 
741
- export { type AffectedTest, CACHE_DIR_NAME, type ChangeContextInput, type ChangeContextOptions, type ChangeContextResult, type ChangeKind, type ChangedSymbol, type CodeChangeContextArgs, Config, type ContextFile, type ContextOptions, type ContextPack, type ContextPackItem, type ContextRelationship, type ContextRoute, type ContextSymbol, type ContextTaskKind, DEFAULT_EXCLUDED_DIRS, type DiffHunk, type FileChange, type ImpactHop, type ImpactRow, type ImpactXray, type ImportDependent, type IndexOptions, type IndexedFile, type ParseDiagnostic, type RepoIndex, SUPPORTED_EXTS, type SymbolInfo, type SymbolKind, type SymbolPath, type TaskContextResult, type UnmappedChange, XRAY_LIMITS, type XrayEdge, type XrayEvidence, type XrayNode, type XrayPath, apply, buildChangeContext, buildImpactXray, buildIndex, buildIndexWithCache, buildModuleGraph, buildSymbolTable, buildTaskContext, callerCounts, changeContextInputFromArgs, defaultCachePath, extractAll, extractSymbols, findCycles, findOrphanModules, findRepoRoot, indexIntegrityWarnings, inject, languageForFile, loadIndex, name, parseFileToSymbols, parseUnifiedDiff, rankRepoMap, readGitFileAtRef, readWorkingTreeDiff, renderChangeContext, renderContextPack, renderHit, renderRepoMap, renderTaskContext, routeTask, saveIndex, scanRepo, scoreFile, searchSymbols, symbolCount, symbolRefs, tools };
55
+ export { apply, inject, name };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-code-index",
3
- "version": "0.11.0",
3
+ "version": "0.11.2",
4
4
  "description": "Impact X-Ray for DSH: inspect potential code-change impact, provenance and real source evidence before AI edits.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -51,7 +51,7 @@
51
51
  },
52
52
  "peerDependencies": {
53
53
  "@deepseek-ai/cordis": "^4.0.1",
54
- "@deepseek-ai/dsh-tools": "0.2.0-rc.2 || 0.2.1-rc.2"
54
+ "@deepseek-ai/dsh-tools": ">=0.2.0-rc.2"
55
55
  },
56
56
  "peerDependenciesMeta": {
57
57
  "@deepseek-ai/cordis": {
@@ -64,6 +64,7 @@
64
64
  "@types/node": "^26.2.0",
65
65
  "@types/react": "^18.3.31",
66
66
  "react": "^18.3.1",
67
+ "semver": "^7.8.5",
67
68
  "tsup": "^8.5.0",
68
69
  "typescript": "^6.0.3",
69
70
  "vitest": "^4.1.8"
@@ -4,6 +4,7 @@ import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'nod
4
4
  import os from 'node:os'
5
5
  import { createRequire } from 'node:module'
6
6
  import path from 'node:path'
7
+ import semver from 'semver'
7
8
  import { fileURLToPath, pathToFileURL } from 'node:url'
8
9
 
9
10
  const root = path.resolve(fileURLToPath(new URL('..', import.meta.url)))
@@ -66,10 +67,10 @@ function parseJsonArrayOutput(output, command) {
66
67
 
67
68
  // A release gate can reuse one immutable candidate across Node versions.
68
69
  const suppliedTarball = process.argv[2] ? path.resolve(process.argv[2]) : null
69
- // Exercise each supported host group against the same immutable candidate.
70
- const toolsVersion = process.argv[3] ?? '0.2.1-rc.2'
71
- const supportedToolsVersions = packageJson.peerDependencies['@deepseek-ai/dsh-tools'].split(' || ')
72
- assert.ok(supportedToolsVersions.includes(toolsVersion), 'smoke requires an explicitly supported DSH tools version')
70
+ // Exercise a selected host version against the same immutable candidate.
71
+ const toolsVersion = process.argv[3] ?? '0.2.1-rc.3'
72
+ const toolsRange = packageJson.peerDependencies['@deepseek-ai/dsh-tools']
73
+ assert.ok(semver.satisfies(toolsVersion, toolsRange, { includePrerelease: true }), 'smoke requires a DSH tools version matching the peer range')
73
74
  const packed = suppliedTarball ? null : parseJsonArrayOutput(run(npm, ['pack', '--ignore-scripts', '--json'], root), 'npm pack')
74
75
  if (packed) assert.equal(packed.length, 1, 'npm pack must produce exactly one artifact')
75
76
  const tarball = suppliedTarball ?? path.resolve(root, packed[0].filename)
@@ -97,7 +98,11 @@ for (const file of expectedFiles) assert.ok(listed.has(file), `tarball is missin
97
98
  const smokeDir = mkdtempSync(path.join(os.tmpdir(), 'dsh-code-index-release-'))
98
99
  try {
99
100
  run(npm, ['init', '--yes'], smokeDir)
100
- run(npm, ['install', '--ignore-scripts', '--no-save', tarball, `@deepseek-ai/dsh-tools@${toolsVersion}`], smokeDir)
101
+ // npm's default peer checks exclude prereleases that DSH explicitly accepts.
102
+ // --force only prepares this disposable runtime fixture; it does not prove
103
+ // normal npm peer resolution. The range assertion above uses DSH's rules.
104
+ console.log('smoke fixture: npm --force bypasses peer resolution; validating DSH range and runtime only')
105
+ run(npm, ['install', '--ignore-scripts', '--no-save', '--force', tarball, `@deepseek-ai/dsh-tools@${toolsVersion}`], smokeDir)
101
106
 
102
107
  const installedPackage = JSON.parse(
103
108
  readFileSync(path.join(smokeDir, 'node_modules', packageJson.name, 'package.json'), 'utf8'),
@@ -108,7 +113,7 @@ try {
108
113
  assert.match(installedPackage.engines.node, />=22/)
109
114
  assert.equal(installedPackage.license, 'MIT')
110
115
  const installedTools = JSON.parse(readFileSync(path.join(smokeDir, 'node_modules', '@deepseek-ai', 'dsh-tools', 'package.json'), 'utf8'))
111
- assert.equal(installedTools.version, toolsVersion, 'consumer must use the selected matching RC group')
116
+ assert.equal(installedTools.version, toolsVersion, 'consumer must use the selected DSH tools version')
112
117
 
113
118
  const plugin = await import(
114
119
  pathToFileURL(path.join(smokeDir, 'node_modules', packageJson.name, 'dist', 'index.js')).href,
@@ -294,6 +299,8 @@ try {
294
299
  assert.ok(rustSymbols.value.some(symbol => symbol.name === 'CrateOnly' && symbol.signature === 'CrateOnly' && !symbol.exported))
295
300
  assert.ok(rustSymbols.value.some(symbol => symbol.name === 'Restricted' && symbol.signature === 'Restricted' && !symbol.exported))
296
301
  const rustMap = await nativeInvoke('code_map', { repoRoot: rustRoot })
302
+ const health = await nativeInvoke('code_health', { repoRoot: rustRoot })
303
+ assert.match(health.value, /repo health/)
297
304
  for (const name of ['PublicOne', 'PublicEnum', 'PublicTrait']) {
298
305
  const search = await nativeInvoke('code_search', { query: name, repoRoot: rustRoot })
299
306
  assert.equal(search.value[0]?.name, name)
@@ -337,7 +344,7 @@ try {
337
344
  for (const dispose of nativeDisposers.reverse()) dispose()
338
345
  await nativeContext.fiber.dispose()
339
346
  }
340
- console.log(`release smoke passed for ${packageJson.name}@${packageJson.version} with dsh-tools@${toolsVersion}`)
347
+ console.log(`release smoke passed (DSH range/runtime; npm peer resolution bypassed) for ${packageJson.name}@${packageJson.version} with dsh-tools@${toolsVersion}`)
341
348
  } finally {
342
349
  rmSync(smokeDir, { recursive: true, force: true, maxRetries: 3, retryDelay: 100 })
343
350
  if (!suppliedTarball) rmSync(tarball, { force: true })