dsh-code-index 0.4.0 → 0.5.0
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 +6 -1
- package/README.zh.md +6 -1
- package/dist/client.js +279 -0
- package/dist/client.js.map +1 -0
- package/dist/index.js +428 -7
- package/dist/index.js.map +1 -1
- package/package.json +21 -4
package/README.md
CHANGED
|
@@ -17,6 +17,8 @@ Fits a niche the ecosystem took a while to fill: alongside git/voice/browser/mem
|
|
|
17
17
|
| `code_symbols` | List symbols (functions, classes, interfaces, types, methods…) with file:line — filtered by name, path, kind, exported |
|
|
18
18
|
| `code_search` | Ranked lookup: exact > prefix > substring > subsequence-fuzzy, exports first, relevance score + file:line |
|
|
19
19
|
| `code_map` | Bounded ranked repo map (top files by symbol density + import-graph PageRank, key symbols + lines) |
|
|
20
|
+
| `code_refs` | Trace a symbol through the call graph: callers (who calls it) and callees (what it calls), resolved to file:line |
|
|
21
|
+
| `code_health` | Opt-in (`codeHealth: true`): circular dependencies (import cycles) and orphan modules |
|
|
20
22
|
|
|
21
23
|
Plus an optional **auto-injected system prompt section** (`code-index:repo-map`, order 60): a compact ranked map of the default workspace, refreshed on a TTL (`mapTtlMs`, default 60s). Set `autoInject: false` to disable and rely on the `code_map` tool only.
|
|
22
24
|
|
|
@@ -96,6 +98,7 @@ Options are passed as the plugin row's `config` in the profile patch (or default
|
|
|
96
98
|
| `mapMaxChars` | `3200` | Hard cap on rendered map characters |
|
|
97
99
|
| `mapTtlMs` | `60000` | Refresh interval for the auto-injected map (ms, min 1000) |
|
|
98
100
|
| `autoInject` | `true` | Register the system prompt section |
|
|
101
|
+
| `codeHealth` | `false` | Register the `code_health` tool (cycles / orphan modules) |
|
|
99
102
|
|
|
100
103
|
## Supported languages
|
|
101
104
|
|
|
@@ -106,6 +109,8 @@ TypeScript, JavaScript, Python, Go, Rust, Java, C++ and C (`.ts .tsx .mts .cts .
|
|
|
106
109
|
- **Index build** (`src/buildIndex.ts`): recursive scan (excludes applied), per-file tree-sitter extraction (`src/extract.ts`), JSON cache under `<repo>/.dsh-code-index/`, incremental refresh by mtime (only touched files re-parse).
|
|
107
110
|
- **Search** (`src/search.ts`): pure scoring — exact `1` / prefix `0.8` / substring `0.5`, export boost, name order tiebreak.
|
|
108
111
|
- **Repo map** (`src/repomap.ts`): personalized PageRank over the import graph (teleport = per-file density share, so hub files that are themselves imported by other hubs rise above flat in-degree counting), seeded by the density-aware file score (class/interface/function weighted, test paths damped), top-N files, per-file symbol cap, hard char truncation.
|
|
112
|
+
- **Call graph** (`src/refgraph.ts`): call sites extracted per file (per language, with their enclosing function) are resolved by name into callers and callees — `code_refs` exposes this directly, and `code_search` uses call fan-in as a ranking tie-break.
|
|
113
|
+
- **Health** (`src/health.ts`): Tarjan SCC over the import graph yields circular dependencies; orphan-module detection lists symbol-bearing files with no inbound or outbound imports (entry points and tests excluded).
|
|
109
114
|
- **Workspace resolution**: each tool resolves the session cwd (`agent.session.header.cwd`) and walks up to the nearest `.git` (bounded — a directory without a repo marker is never indexed).
|
|
110
115
|
|
|
111
116
|
## Known limitations
|
|
@@ -119,7 +124,7 @@ TypeScript, JavaScript, Python, Go, Rust, Java, C++ and C (`.ts .tsx .mts .cts .
|
|
|
119
124
|
|
|
120
125
|
```sh
|
|
121
126
|
pnpm install
|
|
122
|
-
pnpm test # vitest — extractor, scan, cache, search, repo map
|
|
127
|
+
pnpm test # vitest — extractor, scan, cache, search, repo map, call graph, health
|
|
123
128
|
pnpm typecheck
|
|
124
129
|
pnpm build # tsup → dist/index.js (ESM, external deps)
|
|
125
130
|
```
|
package/README.zh.md
CHANGED
|
@@ -14,6 +14,8 @@
|
|
|
14
14
|
| `code_symbols` | 列出符号(函数、类、接口、类型、方法……),带 file:line——支持按名称、路径、类型、是否导出过滤 |
|
|
15
15
|
| `code_search` | 排名检索:精确 > 前缀 > 子串 > 子序列模糊,导出优先,带相关度分数与 file:line |
|
|
16
16
|
| `code_map` | 限量排名仓库地图(按符号密度 + import 图 PageRank 取核心文件 + 关键符号与行号) |
|
|
17
|
+
| `code_refs` | 沿调用图追踪符号:callers(谁调用了它)与 callees(它调用了谁),解析到 file:line |
|
|
18
|
+
| `code_health` | 可选开启(`codeHealth: true`):环依赖(import 环)与孤儿模块 |
|
|
17
19
|
|
|
18
20
|
外加一个可选的**自动注入系统提示词段**(`code-index:repo-map`,序 60):默认工作区的精简排名地图,按 TTL 自动刷新(`mapTtlMs`,默认 60 秒)。将 `autoInject: false` 可关闭,只依赖 `code_map` 工具。
|
|
19
21
|
|
|
@@ -93,6 +95,7 @@ export function extractSymbols(code, id) — src/extract.ts:121
|
|
|
93
95
|
| `mapMaxChars` | `3200` | 渲染地图的硬性字符上限 |
|
|
94
96
|
| `mapTtlMs` | `60000` | 自动注入地图的刷新间隔(毫秒,最小 1000) |
|
|
95
97
|
| `autoInject` | `true` | 是否注册系统提示词段 |
|
|
98
|
+
| `codeHealth` | `false` | 是否注册 `code_health` 工具(环/孤儿模块) |
|
|
96
99
|
|
|
97
100
|
## 支持的语言
|
|
98
101
|
|
|
@@ -103,6 +106,8 @@ TypeScript、JavaScript、Python、Go、Rust、Java、C++、C(`.ts .tsx .mts .ct
|
|
|
103
106
|
- **索引构建**(`src/buildIndex.ts`):递归扫描(应用排除规则),逐文件 tree-sitter 提取(`src/extract.ts`),JSON 缓存置于 `<repo>/.dsh-code-index/`,按 mtime 增量刷新(只有被改动的文件才重新解析)。
|
|
104
107
|
- **搜索**(`src/search.ts`):纯打分——精确 `1` / 前缀 `0.8` / 子串 `0.5`,导出加权,名称序平局裁决。
|
|
105
108
|
- **仓库地图**(`src/repomap.ts`):import 图上的个性化 PageRank(传送向量 = 各文件密度份额,被其他枢纽文件引用的枢纽会比平铺入度统计排得更靠前),以密度感知的文件打分为底(class/interface/function 加权,测试路径衰减),取 Top-N 文件,每文件符号上限,硬截断。
|
|
109
|
+
- **调用图**(`src/refgraph.ts`):逐文件提取调用点(按语言,并记录其所属函数),按名称解析成 callers 与 callees——`code_refs` 直接暴露,`code_search` 也把调用热度作为排名平局裁决。
|
|
110
|
+
- **健康检查**(`src/health.ts`):对 import 图跑 Tarjan SCC 得到环依赖;孤儿模块检测列出既不被 import、也不 import 任何文件的含符号文件(排除入口与测试)。
|
|
106
111
|
- **工作区解析**:每个工具解析会话 cwd(`agent.session.header.cwd`)并向上查找最近的 `.git`(有界——没有仓库标记的目录绝不会被索引)。
|
|
107
112
|
|
|
108
113
|
## 已知限制
|
|
@@ -116,7 +121,7 @@ TypeScript、JavaScript、Python、Go、Rust、Java、C++、C(`.ts .tsx .mts .ct
|
|
|
116
121
|
|
|
117
122
|
```sh
|
|
118
123
|
pnpm install
|
|
119
|
-
pnpm test # vitest ——
|
|
124
|
+
pnpm test # vitest —— 提取器、扫描、缓存、搜索、仓库地图、调用图、健康检查
|
|
120
125
|
pnpm typecheck
|
|
121
126
|
pnpm build # tsup → dist/index.js(ESM,外部依赖)
|
|
122
127
|
```
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
window.__ModuleLoader__.load({ id: "dsh-code-index", factory: (require) => {
|
|
2
|
+
var module = { exports: {} }; var exports = module.exports;
|
|
3
|
+
"use strict";
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name2 in all)
|
|
10
|
+
__defProp(target, name2, { get: all[name2], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
21
|
+
|
|
22
|
+
// src/client/index.tsx
|
|
23
|
+
var client_exports = {};
|
|
24
|
+
__export(client_exports, {
|
|
25
|
+
apply: () => apply,
|
|
26
|
+
inject: () => inject,
|
|
27
|
+
name: () => name
|
|
28
|
+
});
|
|
29
|
+
module.exports = __toCommonJS(client_exports);
|
|
30
|
+
var import_react = require("react");
|
|
31
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
32
|
+
var CARD_STYLE = {
|
|
33
|
+
border: "1px solid var(--dsh-border, #333)",
|
|
34
|
+
borderRadius: 6,
|
|
35
|
+
padding: "6px 8px",
|
|
36
|
+
fontFamily: "var(--dsh-mono-font, monospace)",
|
|
37
|
+
fontSize: 12,
|
|
38
|
+
margin: "4px 0"
|
|
39
|
+
};
|
|
40
|
+
var ROW_STYLE = {
|
|
41
|
+
display: "flex",
|
|
42
|
+
gap: 8,
|
|
43
|
+
alignItems: "baseline"
|
|
44
|
+
};
|
|
45
|
+
function parseArgs(raw) {
|
|
46
|
+
if (!raw) return {};
|
|
47
|
+
try {
|
|
48
|
+
const value = JSON.parse(raw);
|
|
49
|
+
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : {};
|
|
50
|
+
} catch {
|
|
51
|
+
return {};
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
function summarizeArgs(args) {
|
|
55
|
+
const parts = [];
|
|
56
|
+
for (const key of ["query", "symbol", "action", "direction", "kind"]) {
|
|
57
|
+
const value = args[key];
|
|
58
|
+
if (typeof value === "string" && value) parts.push(`${key}=${value}`);
|
|
59
|
+
}
|
|
60
|
+
return parts.join(" ");
|
|
61
|
+
}
|
|
62
|
+
function asSearchView(view) {
|
|
63
|
+
if (typeof view !== "object" || view === null || Array.isArray(view)) return void 0;
|
|
64
|
+
const record = view;
|
|
65
|
+
return record.card === "search" ? record : void 0;
|
|
66
|
+
}
|
|
67
|
+
function resultText(block) {
|
|
68
|
+
return (block.content ?? []).filter((part) => part.type === "text" && typeof part.text === "string").map((part) => part.text ?? "").join("\n");
|
|
69
|
+
}
|
|
70
|
+
function CodeToolCard(props) {
|
|
71
|
+
const { toolName, block, openFile } = props;
|
|
72
|
+
const head = block.call ?? block;
|
|
73
|
+
const summary = summarizeArgs(parseArgs(head.argsRaw));
|
|
74
|
+
const search = asSearchView(block.resultView);
|
|
75
|
+
const isError = block.isError === true;
|
|
76
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: CARD_STYLE, children: [
|
|
77
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: ROW_STYLE, children: [
|
|
78
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("strong", { children: toolName }),
|
|
79
|
+
summary ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { opacity: 0.75 }, children: summary }) : null,
|
|
80
|
+
isError ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { color: "#e5534b" }, children: "error" }) : null
|
|
81
|
+
] }),
|
|
82
|
+
search?.shape === "matches" && search.files ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { marginTop: 4 }, children: [
|
|
83
|
+
search.files.map((file) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
|
|
84
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { opacity: 0.85 }, children: file.path }),
|
|
85
|
+
(file.matches ?? []).map((match, index) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
86
|
+
"div",
|
|
87
|
+
{
|
|
88
|
+
style: { paddingLeft: 12, cursor: openFile ? "pointer" : "default" },
|
|
89
|
+
onClick: () => openFile?.(file.path, { line: match.lineNumber }),
|
|
90
|
+
children: [
|
|
91
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { opacity: 0.6 }, children: match.lineNumber }),
|
|
92
|
+
" ",
|
|
93
|
+
match.line
|
|
94
|
+
]
|
|
95
|
+
},
|
|
96
|
+
`${match.lineNumber}-${index}`
|
|
97
|
+
))
|
|
98
|
+
] }, file.path)),
|
|
99
|
+
search.truncated ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { opacity: 0.6 }, children: [
|
|
100
|
+
"\u2026 truncated (",
|
|
101
|
+
search.total,
|
|
102
|
+
" total)"
|
|
103
|
+
] }) : null
|
|
104
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("pre", { style: { margin: "4px 0 0", whiteSpace: "pre-wrap", maxHeight: 220, overflow: "auto" }, children: resultText(block) })
|
|
105
|
+
] });
|
|
106
|
+
}
|
|
107
|
+
var activeScope = null;
|
|
108
|
+
var CARD_CSS = `
|
|
109
|
+
.dci-card{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:12px;list-style:none;transition:border-color .16s,background .16s}
|
|
110
|
+
.dci-card:hover{border-color:var(--dsw-alias-label-dimmed)}
|
|
111
|
+
.dci-cardOpen{background:var(--dsw-alias-bg-layer-2);border-color:var(--dsw-alias-label-dimmed)}
|
|
112
|
+
.dci-header{appearance:none;width:100%;font:inherit;color:inherit;text-align:left;cursor:pointer;background:0 0;border:0;border-radius:12px;align-items:center;gap:12px;padding:14px 16px;display:flex}
|
|
113
|
+
.dci-header:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:-2px}
|
|
114
|
+
.dci-headText{flex-direction:column;flex:1 1 0%;gap:4px;min-width:0;display:flex}
|
|
115
|
+
.dci-name{color:var(--dsw-alias-label-primary);font-size:15px;font-weight:600;line-height:1.4}
|
|
116
|
+
.dci-description{color:var(--dsw-alias-label-tertiary);font-size:13px;line-height:1.5}
|
|
117
|
+
.dci-chevron{color:var(--dsw-alias-label-tertiary);flex:0 0 auto;transition:transform .16s}
|
|
118
|
+
.dci-chevronOpen{transform:rotate(180deg)}
|
|
119
|
+
.dci-body{border-top:1px solid var(--dsw-alias-border-l2);margin:0 16px;padding-bottom:8px}
|
|
120
|
+
.dci-field{flex-direction:column;gap:6px;padding:12px 0;display:flex}
|
|
121
|
+
.dci-field+.dci-field{border-top:1px solid var(--dsw-alias-border-l2)}
|
|
122
|
+
.dci-head{align-items:center;gap:8px;display:flex}
|
|
123
|
+
.dci-label{min-width:0;color:var(--dsw-alias-label-primary);flex:1 1 0%;font-size:13px;font-weight:500;line-height:1.5}
|
|
124
|
+
.dci-input{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);height:34px;color:var(--dsw-alias-label-primary);border-radius:8px;padding:0 12px;font:inherit;font-size:13px;line-height:1.5}
|
|
125
|
+
.dci-input:focus-visible{border-color:var(--dsw-alias-brand-primary);outline:none}
|
|
126
|
+
.dci-input:disabled{color:var(--dsw-alias-label-tertiary);cursor:default}
|
|
127
|
+
.dci-check{width:16px;height:16px;flex:0 0 auto;accent-color:var(--dsw-alias-brand-primary)}
|
|
128
|
+
.dci-hint{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:1.5}
|
|
129
|
+
.dci-footer{border-top:1px solid var(--dsw-alias-border-l2);justify-content:flex-end;align-items:center;gap:8px;padding:12px 0 4px;display:flex}
|
|
130
|
+
.dci-discard,.dci-save{appearance:none;font:inherit;cursor:pointer;border:1px solid transparent;border-radius:8px;padding:5px 14px;font-size:13px;line-height:1.5}
|
|
131
|
+
.dci-discard{border-color:var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);background:0 0}
|
|
132
|
+
.dci-discard:hover:not(:disabled){color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-label-dimmed)}
|
|
133
|
+
.dci-save{background:var(--dsw-alias-label-primary);color:var(--dsw-alias-bg-layer-3)}
|
|
134
|
+
.dci-discard:disabled,.dci-save:disabled{opacity:.4;cursor:default}
|
|
135
|
+
`;
|
|
136
|
+
var CHEVRON_PATH = "M11.8486 5.5L11.4238 5.92383L8.69727 8.65137C8.44157 8.90706 8.21562 9.13382 8.01172 9.29785C7.79912 9.46883 7.55595 9.61756 7.25 9.66602C7.08435 9.69222 6.91565 9.69222 6.75 9.66602C6.44405 9.61756 6.20088 9.46883 5.98828 9.29785C5.78438 9.13382 5.55843 8.90706 5.30273 8.65137L2.57617 5.92383L2.15137 5.5L3 4.65137L3.42383 5.07617L6.15137 7.80273C6.42595 8.07732 6.59876 8.24849 6.74023 8.3623C6.87291 8.46904 6.92272 8.47813 6.9375 8.48047C6.97895 8.48703 7.02105 8.48703 7.0625 8.48047C7.07728 8.47813 7.12709 8.46904 7.25977 8.3623C7.40124 8.24849 7.57405 8.07732 7.84863 7.80273L10.5762 5.07617L11 4.65137L11.8486 5.5Z";
|
|
137
|
+
var SETTINGS_DEFAULTS = { autoInject: true, codeHealth: false, mapTopFiles: 24 };
|
|
138
|
+
var SETTINGS_FIELDS = ["autoInject", "codeHealth", "mapTopFiles"];
|
|
139
|
+
function CodeIndexSettingsCard() {
|
|
140
|
+
const scope = activeScope;
|
|
141
|
+
const [open, setOpen] = (0, import_react.useState)(false);
|
|
142
|
+
const [snapshot, setSnapshot] = (0, import_react.useState)(
|
|
143
|
+
scope ? scope.getSnapshot() : null
|
|
144
|
+
);
|
|
145
|
+
const [draft, setDraft] = (0, import_react.useState)(null);
|
|
146
|
+
(0, import_react.useEffect)(() => {
|
|
147
|
+
if (!scope) return;
|
|
148
|
+
setSnapshot(scope.getSnapshot());
|
|
149
|
+
return scope.subscribe(() => setSnapshot(scope.getSnapshot()));
|
|
150
|
+
}, [scope]);
|
|
151
|
+
const resolved = snapshot?.value ?? {};
|
|
152
|
+
const form = { ...SETTINGS_DEFAULTS, ...resolved, ...draft };
|
|
153
|
+
const writable = snapshot?.writable ?? false;
|
|
154
|
+
const changed = (key) => form[key] !== (resolved[key] ?? SETTINGS_DEFAULTS[key]);
|
|
155
|
+
const dirty = draft !== null && SETTINGS_FIELDS.some(changed);
|
|
156
|
+
const edit = (key, value) => {
|
|
157
|
+
setDraft({ ...form, [key]: value });
|
|
158
|
+
};
|
|
159
|
+
const save = () => {
|
|
160
|
+
if (!scope) return;
|
|
161
|
+
for (const key of SETTINGS_FIELDS) {
|
|
162
|
+
if (changed(key)) {
|
|
163
|
+
scope.set(key, form[key]).catch((error) => {
|
|
164
|
+
console.error("[dsh-code-index] settings save failed", error);
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
setDraft(null);
|
|
169
|
+
};
|
|
170
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("li", { className: open ? "dci-card dci-cardOpen" : "dci-card", children: [
|
|
171
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("style", { children: CARD_CSS }),
|
|
172
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
173
|
+
"button",
|
|
174
|
+
{
|
|
175
|
+
type: "button",
|
|
176
|
+
className: "dci-header",
|
|
177
|
+
"aria-expanded": open,
|
|
178
|
+
"aria-label": `${open ? "\u6536\u8D77\u8BBE\u7F6E" : "\u5C55\u5F00\u8BBE\u7F6E"}: dsh-code-index`,
|
|
179
|
+
onClick: () => {
|
|
180
|
+
setOpen(!open);
|
|
181
|
+
},
|
|
182
|
+
children: [
|
|
183
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "dci-headText", children: [
|
|
184
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "dci-name", children: "dsh-code-index" }),
|
|
185
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "dci-description", children: "\u8BED\u4E49\u4ED3\u5E93\u7D22\u5F15\uFF1A\u7B26\u53F7\u641C\u7D22\u3001\u4ED3\u5E93\u5730\u56FE\u4E0E\u8C03\u7528\u56FE\u3002" })
|
|
186
|
+
] }),
|
|
187
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { className: open ? "dci-chevron dci-chevronOpen" : "dci-chevron", width: "14", height: "14", viewBox: "0 0 14 14", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: CHEVRON_PATH, fill: "currentColor" }) })
|
|
188
|
+
]
|
|
189
|
+
}
|
|
190
|
+
),
|
|
191
|
+
open ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dci-body", children: [
|
|
192
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dci-field", children: [
|
|
193
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dci-head", children: [
|
|
194
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("label", { className: "dci-label", htmlFor: "dci-auto-inject", children: "\u81EA\u52A8\u6CE8\u5165\u4ED3\u5E93\u5730\u56FE" }),
|
|
195
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
196
|
+
"input",
|
|
197
|
+
{
|
|
198
|
+
id: "dci-auto-inject",
|
|
199
|
+
className: "dci-check",
|
|
200
|
+
type: "checkbox",
|
|
201
|
+
checked: form.autoInject,
|
|
202
|
+
disabled: !writable,
|
|
203
|
+
onChange: (event) => {
|
|
204
|
+
edit("autoInject", event.target.checked);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
)
|
|
208
|
+
] }),
|
|
209
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "dci-hint", children: "\u628A\u7CBE\u7B80\u7684\u6392\u540D\u4ED3\u5E93\u5730\u56FE\u6CE8\u5165\u7CFB\u7EDF\u63D0\u793A\u8BCD\u3002" })
|
|
210
|
+
] }),
|
|
211
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dci-field", children: [
|
|
212
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dci-head", children: [
|
|
213
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("label", { className: "dci-label", htmlFor: "dci-code-health", children: "\u4EE3\u7801\u5065\u5EB7\u5DE5\u5177" }),
|
|
214
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
215
|
+
"input",
|
|
216
|
+
{
|
|
217
|
+
id: "dci-code-health",
|
|
218
|
+
className: "dci-check",
|
|
219
|
+
type: "checkbox",
|
|
220
|
+
checked: form.codeHealth,
|
|
221
|
+
disabled: !writable,
|
|
222
|
+
onChange: (event) => {
|
|
223
|
+
edit("codeHealth", event.target.checked);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
)
|
|
227
|
+
] }),
|
|
228
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "dci-hint", children: "\u6CE8\u518C code_health \u5DE5\u5177\uFF0C\u62A5\u544A\u73AF\u4F9D\u8D56\u4E0E\u5B64\u513F\u6A21\u5757\uFF08\u91CD\u542F\u540E\u751F\u6548\uFF09\u3002" })
|
|
229
|
+
] }),
|
|
230
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dci-field", children: [
|
|
231
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "dci-head", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("label", { className: "dci-label", htmlFor: "dci-map-files", children: "\u5730\u56FE\u6587\u4EF6\u6570" }) }),
|
|
232
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
233
|
+
"input",
|
|
234
|
+
{
|
|
235
|
+
id: "dci-map-files",
|
|
236
|
+
className: "dci-input",
|
|
237
|
+
type: "text",
|
|
238
|
+
inputMode: "numeric",
|
|
239
|
+
value: String(form.mapTopFiles),
|
|
240
|
+
disabled: !writable,
|
|
241
|
+
onChange: (event) => {
|
|
242
|
+
edit("mapTopFiles", Number(event.target.value));
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
),
|
|
246
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "dci-hint", children: "\u4ED3\u5E93\u5730\u56FE\u4E2D\u6700\u591A\u5C55\u793A\u7684\u6587\u4EF6\u6570\u3002" })
|
|
247
|
+
] }),
|
|
248
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "dci-footer", children: [
|
|
249
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", className: "dci-discard", disabled: !dirty || !writable, onClick: () => {
|
|
250
|
+
setDraft(null);
|
|
251
|
+
}, children: "\u653E\u5F03\u4FEE\u6539" }),
|
|
252
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", className: "dci-save", disabled: !dirty || !writable, onClick: save, children: "\u4FDD\u5B58" })
|
|
253
|
+
] })
|
|
254
|
+
] }) : null,
|
|
255
|
+
scope ? null : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "dci-hint", style: { padding: "0 16px 12px" }, children: "\u8BBE\u7F6E\u670D\u52A1\u4E0D\u53EF\u7528\u3002" })
|
|
256
|
+
] });
|
|
257
|
+
}
|
|
258
|
+
var name = "dsh-code-index";
|
|
259
|
+
var inject = ["slots"];
|
|
260
|
+
var TOOLVIEW_KEYS = ["code_index", "code_symbols", "code_search", "code_map", "code_refs", "code_health"];
|
|
261
|
+
function apply(ctx) {
|
|
262
|
+
const card = CodeToolCard;
|
|
263
|
+
ctx.slots.inject("tool.call.toolview", function* () {
|
|
264
|
+
for (const key of TOOLVIEW_KEYS) {
|
|
265
|
+
yield ctx.slots.register({ name: "tool.call.toolview", key }, card);
|
|
266
|
+
}
|
|
267
|
+
});
|
|
268
|
+
ctx.inject(["settingsScope"], (scoped) => {
|
|
269
|
+
activeScope = scoped.settingsScope?.bind({ namespace: "code-index" }) ?? null;
|
|
270
|
+
ctx.slots.inject("settings.plugin.item", function* () {
|
|
271
|
+
yield ctx.slots.register(
|
|
272
|
+
{ name: "settings.plugin.item", key: "code-index" },
|
|
273
|
+
CodeIndexSettingsCard
|
|
274
|
+
);
|
|
275
|
+
});
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
return module.exports; } });
|
|
279
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/client/index.tsx"],"sourcesContent":["/**\n * Browser half of dsh-code-index: structured result cards for the code_* tools\n * plus a settings card for the `code-index` namespace.\n *\n * Deliberately imports no harness client package: this bundle only needs\n * `react` (a shell platform module) plus the slot registry and settings scope\n * services reached through the plugin context. Keeping the surface local avoids\n * a dependency on a synchronized client-package version.\n */\n\nimport { useEffect, useState, type ReactNode } from 'react'\n\n/** Minimal structural view of the client plugin context this bundle uses. */\ninterface ClientContextLike {\n slots: {\n inject(name: string, run: () => Iterable<unknown>): void\n register(entry: Record<string, unknown>, component: (props: never) => ReactNode): () => void\n }\n inject(deps: string[], run: (ctx: ClientContextLike) => void): unknown\n settingsScope?: { bind(spec: { namespace: string }): SettingsScopeLike<CodeIndexSettings> }\n}\n\ninterface SettingsSnapshot<T> {\n status: 'loading' | 'ready' | 'unavailable'\n value: T | undefined\n writable: boolean\n}\n\ninterface SettingsScopeLike<T> {\n getSnapshot(): SettingsSnapshot<T>\n subscribe(listener: () => void): () => void\n set(field: string, value: unknown): Promise<void>\n unset(field: string): Promise<void>\n}\n\ninterface CodeIndexSettings {\n excludeDirs?: string[]\n mapTopFiles?: number\n mapMaxChars?: number\n mapTtlMs?: number\n autoInject?: boolean\n codeHealth?: boolean\n}\n\ninterface ToolCallHead {\n name?: string\n argsRaw?: string\n}\n\ninterface TextContent {\n type?: string\n text?: string\n}\n\ninterface ToolResultLike {\n call?: ToolCallHead | null\n content?: readonly TextContent[]\n isError?: boolean\n resultView?: unknown\n}\n\ninterface SearchView {\n card: 'search'\n shape?: 'matches' | 'paths'\n files?: Array<{ path: string; matches?: Array<{ lineNumber: number; line: string }> }>\n paths?: string[]\n truncated?: boolean\n total?: number\n}\n\ninterface ToolViewProps {\n toolName: string\n block: ToolResultLike & ToolCallHead\n openFile?: (path: string, options?: unknown) => void\n}\n\nconst CARD_STYLE: Record<string, string | number> = {\n border: '1px solid var(--dsh-border, #333)',\n borderRadius: 6,\n padding: '6px 8px',\n fontFamily: 'var(--dsh-mono-font, monospace)',\n fontSize: 12,\n margin: '4px 0',\n}\n\nconst ROW_STYLE: Record<string, string | number> = {\n display: 'flex',\n gap: 8,\n alignItems: 'baseline',\n}\n\nfunction parseArgs(raw: string | undefined): Record<string, unknown> {\n if (!raw) return {}\n try {\n const value: unknown = JSON.parse(raw)\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n ? (value as Record<string, unknown>)\n : {}\n } catch {\n return {}\n }\n}\n\nfunction summarizeArgs(args: Record<string, unknown>): string {\n const parts: string[] = []\n for (const key of ['query', 'symbol', 'action', 'direction', 'kind']) {\n const value = args[key]\n if (typeof value === 'string' && value) parts.push(`${key}=${value}`)\n }\n return parts.join(' ')\n}\n\nfunction asSearchView(view: unknown): SearchView | undefined {\n if (typeof view !== 'object' || view === null || Array.isArray(view)) return undefined\n const record = view as Record<string, unknown>\n return record.card === 'search' ? (record as unknown as SearchView) : undefined\n}\n\nfunction resultText(block: ToolResultLike): string {\n return (block.content ?? [])\n .filter((part) => part.type === 'text' && typeof part.text === 'string')\n .map((part) => part.text ?? '')\n .join('\\n')\n}\n\n/** One code tool's card: argument summary, structured search matches, or text. */\nfunction CodeToolCard(props: ToolViewProps): ReactNode {\n const { toolName, block, openFile } = props\n const head: ToolCallHead = block.call ?? block\n const summary = summarizeArgs(parseArgs(head.argsRaw))\n const search = asSearchView(block.resultView)\n const isError = block.isError === true\n\n return (\n <div style={CARD_STYLE}>\n <div style={ROW_STYLE}>\n <strong>{toolName}</strong>\n {summary ? <span style={{ opacity: 0.75 }}>{summary}</span> : null}\n {isError ? <span style={{ color: '#e5534b' }}>error</span> : null}\n </div>\n {search?.shape === 'matches' && search.files ? (\n <div style={{ marginTop: 4 }}>\n {search.files.map((file) => (\n <div key={file.path}>\n <div style={{ opacity: 0.85 }}>{file.path}</div>\n {(file.matches ?? []).map((match, index) => (\n <div\n key={`${match.lineNumber}-${index}`}\n style={{ paddingLeft: 12, cursor: openFile ? 'pointer' : 'default' }}\n onClick={() => openFile?.(file.path, { line: match.lineNumber })}\n >\n <span style={{ opacity: 0.6 }}>{match.lineNumber}</span> {match.line}\n </div>\n ))}\n </div>\n ))}\n {search.truncated ? <div style={{ opacity: 0.6 }}>… truncated ({search.total} total)</div> : null}\n </div>\n ) : (\n <pre style={{ margin: '4px 0 0', whiteSpace: 'pre-wrap', maxHeight: 220, overflow: 'auto' }}>\n {resultText(block)}\n </pre>\n )}\n </div>\n )\n}\n\n/** The scope is captured at apply() time; the card reads it through React state. */\nlet activeScope: SettingsScopeLike<CodeIndexSettings> | null = null\n\n/** Mirrors the first-party plugin card + field CSS modules, under our own class names. */\nconst CARD_CSS = `\n.dci-card{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:12px;list-style:none;transition:border-color .16s,background .16s}\n.dci-card:hover{border-color:var(--dsw-alias-label-dimmed)}\n.dci-cardOpen{background:var(--dsw-alias-bg-layer-2);border-color:var(--dsw-alias-label-dimmed)}\n.dci-header{appearance:none;width:100%;font:inherit;color:inherit;text-align:left;cursor:pointer;background:0 0;border:0;border-radius:12px;align-items:center;gap:12px;padding:14px 16px;display:flex}\n.dci-header:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:-2px}\n.dci-headText{flex-direction:column;flex:1 1 0%;gap:4px;min-width:0;display:flex}\n.dci-name{color:var(--dsw-alias-label-primary);font-size:15px;font-weight:600;line-height:1.4}\n.dci-description{color:var(--dsw-alias-label-tertiary);font-size:13px;line-height:1.5}\n.dci-chevron{color:var(--dsw-alias-label-tertiary);flex:0 0 auto;transition:transform .16s}\n.dci-chevronOpen{transform:rotate(180deg)}\n.dci-body{border-top:1px solid var(--dsw-alias-border-l2);margin:0 16px;padding-bottom:8px}\n.dci-field{flex-direction:column;gap:6px;padding:12px 0;display:flex}\n.dci-field+.dci-field{border-top:1px solid var(--dsw-alias-border-l2)}\n.dci-head{align-items:center;gap:8px;display:flex}\n.dci-label{min-width:0;color:var(--dsw-alias-label-primary);flex:1 1 0%;font-size:13px;font-weight:500;line-height:1.5}\n.dci-input{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);height:34px;color:var(--dsw-alias-label-primary);border-radius:8px;padding:0 12px;font:inherit;font-size:13px;line-height:1.5}\n.dci-input:focus-visible{border-color:var(--dsw-alias-brand-primary);outline:none}\n.dci-input:disabled{color:var(--dsw-alias-label-tertiary);cursor:default}\n.dci-check{width:16px;height:16px;flex:0 0 auto;accent-color:var(--dsw-alias-brand-primary)}\n.dci-hint{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:1.5}\n.dci-footer{border-top:1px solid var(--dsw-alias-border-l2);justify-content:flex-end;align-items:center;gap:8px;padding:12px 0 4px;display:flex}\n.dci-discard,.dci-save{appearance:none;font:inherit;cursor:pointer;border:1px solid transparent;border-radius:8px;padding:5px 14px;font-size:13px;line-height:1.5}\n.dci-discard{border-color:var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);background:0 0}\n.dci-discard:hover:not(:disabled){color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-label-dimmed)}\n.dci-save{background:var(--dsw-alias-label-primary);color:var(--dsw-alias-bg-layer-3)}\n.dci-discard:disabled,.dci-save:disabled{opacity:.4;cursor:default}\n`\n\nconst CHEVRON_PATH =\n 'M11.8486 5.5L11.4238 5.92383L8.69727 8.65137C8.44157 8.90706 8.21562 9.13382 8.01172 9.29785C7.79912 9.46883 7.55595 9.61756 7.25 9.66602C7.08435 9.69222 6.91565 9.69222 6.75 9.66602C6.44405 9.61756 6.20088 9.46883 5.98828 9.29785C5.78438 9.13382 5.55843 8.90706 5.30273 8.65137L2.57617 5.92383L2.15137 5.5L3 4.65137L3.42383 5.07617L6.15137 7.80273C6.42595 8.07732 6.59876 8.24849 6.74023 8.3623C6.87291 8.46904 6.92272 8.47813 6.9375 8.48047C6.97895 8.48703 7.02105 8.48703 7.0625 8.48047C7.07728 8.47813 7.12709 8.46904 7.25977 8.3623C7.40124 8.24849 7.57405 8.07732 7.84863 7.80273L10.5762 5.07617L11 4.65137L11.8486 5.5Z'\n\nconst SETTINGS_DEFAULTS = { autoInject: true, codeHealth: false, mapTopFiles: 24 }\nconst SETTINGS_FIELDS = ['autoInject', 'codeHealth', 'mapTopFiles'] as const\n\n/** Settings card for `code-index`, laid out like the first-party plugin cards. */\nfunction CodeIndexSettingsCard(): ReactNode {\n const scope = activeScope\n const [open, setOpen] = useState(false)\n const [snapshot, setSnapshot] = useState<SettingsSnapshot<CodeIndexSettings> | null>(\n scope ? scope.getSnapshot() : null,\n )\n const [draft, setDraft] = useState<CodeIndexSettings | null>(null)\n\n useEffect(() => {\n if (!scope) return\n setSnapshot(scope.getSnapshot())\n return scope.subscribe(() => setSnapshot(scope.getSnapshot()))\n }, [scope])\n\n const resolved = snapshot?.value ?? {}\n const form: CodeIndexSettings = { ...SETTINGS_DEFAULTS, ...resolved, ...draft }\n const writable = snapshot?.writable ?? false\n const changed = (key: (typeof SETTINGS_FIELDS)[number]): boolean =>\n form[key] !== (resolved[key] ?? SETTINGS_DEFAULTS[key])\n const dirty = draft !== null && SETTINGS_FIELDS.some(changed)\n\n const edit = (key: (typeof SETTINGS_FIELDS)[number], value: string | number | boolean): void => {\n setDraft({ ...form, [key]: value })\n }\n const save = (): void => {\n if (!scope) return\n for (const key of SETTINGS_FIELDS) {\n if (changed(key)) {\n scope.set(key, form[key]).catch((error: unknown) => {\n console.error('[dsh-code-index] settings save failed', error)\n })\n }\n }\n setDraft(null)\n }\n\n return (\n <li className={open ? 'dci-card dci-cardOpen' : 'dci-card'}>\n <style>{CARD_CSS}</style>\n <button\n type=\"button\"\n className=\"dci-header\"\n aria-expanded={open}\n aria-label={`${open ? '收起设置' : '展开设置'}: dsh-code-index`}\n onClick={() => { setOpen(!open) }}\n >\n <span className=\"dci-headText\">\n <span className=\"dci-name\">dsh-code-index</span>\n <span className=\"dci-description\">语义仓库索引:符号搜索、仓库地图与调用图。</span>\n </span>\n <svg className={open ? 'dci-chevron dci-chevronOpen' : 'dci-chevron'} width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d={CHEVRON_PATH} fill=\"currentColor\" />\n </svg>\n </button>\n {open ? (\n <div className=\"dci-body\">\n <div className=\"dci-field\">\n <div className=\"dci-head\">\n <label className=\"dci-label\" htmlFor=\"dci-auto-inject\">自动注入仓库地图</label>\n <input\n id=\"dci-auto-inject\"\n className=\"dci-check\"\n type=\"checkbox\"\n checked={form.autoInject}\n disabled={!writable}\n onChange={(event) => { edit('autoInject', event.target.checked) }}\n />\n </div>\n <p className=\"dci-hint\">把精简的排名仓库地图注入系统提示词。</p>\n </div>\n <div className=\"dci-field\">\n <div className=\"dci-head\">\n <label className=\"dci-label\" htmlFor=\"dci-code-health\">代码健康工具</label>\n <input\n id=\"dci-code-health\"\n className=\"dci-check\"\n type=\"checkbox\"\n checked={form.codeHealth}\n disabled={!writable}\n onChange={(event) => { edit('codeHealth', event.target.checked) }}\n />\n </div>\n <p className=\"dci-hint\">注册 code_health 工具,报告环依赖与孤儿模块(重启后生效)。</p>\n </div>\n <div className=\"dci-field\">\n <div className=\"dci-head\">\n <label className=\"dci-label\" htmlFor=\"dci-map-files\">地图文件数</label>\n </div>\n <input\n id=\"dci-map-files\"\n className=\"dci-input\"\n type=\"text\"\n inputMode=\"numeric\"\n value={String(form.mapTopFiles)}\n disabled={!writable}\n onChange={(event) => { edit('mapTopFiles', Number(event.target.value)) }}\n />\n <p className=\"dci-hint\">仓库地图中最多展示的文件数。</p>\n </div>\n <div className=\"dci-footer\">\n <button type=\"button\" className=\"dci-discard\" disabled={!dirty || !writable} onClick={() => { setDraft(null) }}>\n 放弃修改\n </button>\n <button type=\"button\" className=\"dci-save\" disabled={!dirty || !writable} onClick={save}>保存</button>\n </div>\n </div>\n ) : null}\n {scope ? null : <p className=\"dci-hint\" style={{ padding: '0 16px 12px' }}>设置服务不可用。</p>}\n </li>\n )\n}\n\nexport const name = 'dsh-code-index'\n\n/** `slots` is required for direct access; `settingsScope` binds lazily below. */\nexport const inject = ['slots']\n\nconst TOOLVIEW_KEYS = ['code_index', 'code_symbols', 'code_search', 'code_map', 'code_refs', 'code_health']\n\nexport function apply(ctx: ClientContextLike): void {\n const card = CodeToolCard as unknown as (props: never) => ReactNode\n ctx.slots.inject('tool.call.toolview', function* () {\n for (const key of TOOLVIEW_KEYS) {\n yield ctx.slots.register({ name: 'tool.call.toolview', key }, card)\n }\n })\n\n ctx.inject(['settingsScope'], (scoped: ClientContextLike) => {\n activeScope = scoped.settingsScope?.bind({ namespace: 'code-index' }) ?? null\n ctx.slots.inject('settings.plugin.item', function* () {\n yield ctx.slots.register(\n { name: 'settings.plugin.item', key: 'code-index' },\n CodeIndexSettingsCard as unknown as (props: never) => ReactNode,\n )\n })\n })\n}\n"],"mappings":"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","names":[]}
|