@anionex/dsh-tool-search 0.1.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.
Files changed (62) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/LICENSE +21 -0
  3. package/README.md +160 -0
  4. package/README.zh.md +160 -0
  5. package/cordis.patch.yml +3 -0
  6. package/docs/benchmark-results.json +51 -0
  7. package/lib/bm25.js +83 -0
  8. package/lib/bm25.js.map +1 -0
  9. package/lib/catalog.js +53 -0
  10. package/lib/catalog.js.map +1 -0
  11. package/lib/client.js +388 -0
  12. package/lib/client.js.map +1 -0
  13. package/lib/index.js +24 -0
  14. package/lib/index.js.map +1 -0
  15. package/lib/runtime.js +286 -0
  16. package/lib/runtime.js.map +1 -0
  17. package/lib/settings.js +50 -0
  18. package/lib/settings.js.map +1 -0
  19. package/lib/shared.js +40 -0
  20. package/lib/shared.js.map +1 -0
  21. package/lib/types/bm25.d.ts +20 -0
  22. package/lib/types/bm25.d.ts.map +1 -0
  23. package/lib/types/catalog.d.ts +26 -0
  24. package/lib/types/catalog.d.ts.map +1 -0
  25. package/lib/types/client/index.d.ts +65 -0
  26. package/lib/types/client/index.d.ts.map +1 -0
  27. package/lib/types/index.d.ts +14 -0
  28. package/lib/types/index.d.ts.map +1 -0
  29. package/lib/types/runtime.d.ts +37 -0
  30. package/lib/types/runtime.d.ts.map +1 -0
  31. package/lib/types/settings.d.ts +16 -0
  32. package/lib/types/settings.d.ts.map +1 -0
  33. package/lib/types/shared.d.ts +31 -0
  34. package/lib/types/shared.d.ts.map +1 -0
  35. package/lib/types/web.d.ts +5 -0
  36. package/lib/types/web.d.ts.map +1 -0
  37. package/lib/web.js +28 -0
  38. package/lib/web.js.map +1 -0
  39. package/package.json +149 -0
  40. package/pnpm-workspace.yaml +11 -0
  41. package/scripts/benchmark.mjs +124 -0
  42. package/scripts/profile-e2e.mjs +366 -0
  43. package/scripts/validate.mjs +170 -0
  44. package/src/bm25.ts +104 -0
  45. package/src/catalog.ts +72 -0
  46. package/src/client/index.tsx +344 -0
  47. package/src/index.ts +32 -0
  48. package/src/runtime.ts +326 -0
  49. package/src/settings.ts +63 -0
  50. package/src/shared.ts +63 -0
  51. package/src/web.ts +34 -0
  52. package/src/wink-porter2-stemmer.d.ts +3 -0
  53. package/tests/bm25.spec.ts +75 -0
  54. package/tests/catalog.spec.ts +63 -0
  55. package/tests/client.spec.tsx +39 -0
  56. package/tests/execution-regression.spec.ts +200 -0
  57. package/tests/runtime.spec.ts +271 -0
  58. package/tests/settings.spec.ts +33 -0
  59. package/tsconfig.client.json +31 -0
  60. package/tsconfig.json +30 -0
  61. package/tsconfig.test.json +23 -0
  62. package/tsdown.config.mjs +37 -0
package/lib/client.js ADDED
@@ -0,0 +1,388 @@
1
+ window.__ModuleLoader__.load({ id: "@anionex/dsh-tool-search", factory: (require) => {
2
+ var module = { exports: {} }; var exports = module.exports;
3
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
4
+ let react = require("react");
5
+ let react_jsx_runtime = require("react/jsx-runtime");
6
+
7
+ //#region src/shared.ts
8
+ /** Values shared by the Host runtime and Web settings client. */
9
+ const TOOL_SEARCH_NAME = "tool_search";
10
+ const TOOL_SEARCH_SETTINGS_NAMESPACE = "tool-search";
11
+ const TOOL_SEARCH_CATALOG_ROUTE = "/_dsh/tool-search/catalog";
12
+ const DEFAULT_RESULT_LIMIT = 5;
13
+ /**
14
+ * Stable bootstrap surface for current DSH releases. Unknown future first-party
15
+ * names are deferred until this list or the user allowlist is updated because
16
+ * ToolDefinition does not expose package provenance.
17
+ */
18
+ const DEFAULT_CORE_TOOLS = Object.freeze([
19
+ "apply_patch",
20
+ "ask_user_question",
21
+ "bash",
22
+ "create_goal",
23
+ "dsh_im_return_file",
24
+ "exit_plan_mode",
25
+ "get_goal",
26
+ "interrupt_agent",
27
+ "job_kill",
28
+ "job_list",
29
+ "job_output",
30
+ "list_agents",
31
+ "ralph",
32
+ "report",
33
+ "send_message",
34
+ "skill",
35
+ "subagent",
36
+ "subagent_fork",
37
+ "todo_write",
38
+ "update_goal",
39
+ "workflow"
40
+ ]);
41
+ const DEFAULT_SETTINGS = Object.freeze({
42
+ defaultLimit: 5,
43
+ alwaysVisible: [],
44
+ neverSearch: []
45
+ });
46
+
47
+ //#endregion
48
+ //#region src/client/index.tsx
49
+ /** DSH Web settings surface for deferred tool policy. */
50
+ const en = {
51
+ nav: "Tool Search",
52
+ topK: "Default results",
53
+ alwaysVisible: "Always visible",
54
+ neverSearch: "Never searchable",
55
+ catalog: "Tool catalog",
56
+ filter: "Filter tools",
57
+ refresh: "Refresh",
58
+ tool: "Tool",
59
+ policy: "Policy",
60
+ selected: "Live agents",
61
+ defaultPolicy: "Default",
62
+ alwaysPolicy: "Always",
63
+ blockedPolicy: "Blocked",
64
+ loading: "Loading...",
65
+ empty: "No matching tools",
66
+ saved: "Saved",
67
+ onePerLine: "One exact tool name per line"
68
+ };
69
+ const zh = {
70
+ nav: "工具搜索",
71
+ topK: "默认结果数",
72
+ alwaysVisible: "常驻白名单",
73
+ neverSearch: "搜索黑名单",
74
+ catalog: "工具目录",
75
+ filter: "筛选工具",
76
+ refresh: "刷新",
77
+ tool: "工具",
78
+ policy: "策略",
79
+ selected: "活跃 Agent",
80
+ defaultPolicy: "默认",
81
+ alwaysPolicy: "常驻",
82
+ blockedPolicy: "禁用",
83
+ loading: "加载中...",
84
+ empty: "没有匹配工具",
85
+ saved: "已保存",
86
+ onePerLine: "每行一个精确工具名"
87
+ };
88
+ const EMPTY_SETTINGS = {
89
+ status: "unavailable",
90
+ value: void 0,
91
+ writable: false
92
+ };
93
+ const styles = `
94
+ .dts-settings{container-type:inline-size;display:flex;flex-direction:column;gap:20px;width:100%;min-width:0;color:var(--dsw-alias-label-primary)}
95
+ .dts-toolbar{display:grid;grid-template-columns:minmax(160px,220px) minmax(220px,1fr) auto;align-items:end;gap:12px}
96
+ .dts-field{display:flex;flex-direction:column;gap:6px;min-width:0}
97
+ .dts-field>span,.dts-section-title{font-size:13px;font-weight:600;color:var(--dsw-alias-label-primary)}
98
+ .dts-input,.dts-textarea,.dts-select{box-sizing:border-box;width:100%;min-width:0;border:1px solid var(--dsw-alias-border-l2);border-radius:6px;background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary);font:inherit}
99
+ .dts-input,.dts-select{height:34px;padding:0 9px}.dts-textarea{min-height:104px;padding:8px 9px;resize:vertical;line-height:20px}
100
+ .dts-input:focus,.dts-textarea:focus,.dts-select:focus{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:1px}
101
+ .dts-lists{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:16px}
102
+ .dts-hint{font-size:11px;color:var(--dsw-alias-label-tertiary)}
103
+ .dts-button{height:34px;padding:0 12px;border:1px solid var(--dsw-alias-border-l2);border-radius:6px;background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary);cursor:pointer}
104
+ .dts-button:hover{background:var(--dsw-alias-interactive-bg-hover)}.dts-button:disabled{opacity:.5;cursor:not-allowed}
105
+ .dts-status{min-height:18px;font-size:12px;color:var(--dsw-alias-label-secondary)}.dts-status[data-error=true]{color:var(--dsw-alias-state-error-primary)}
106
+ .dts-table-wrap{min-width:0;overflow:auto;border-top:1px solid var(--dsw-alias-border-l2);border-bottom:1px solid var(--dsw-alias-border-l2)}
107
+ .dts-table{width:100%;min-width:620px;border-collapse:collapse;table-layout:fixed}
108
+ .dts-table th,.dts-table td{box-sizing:border-box;padding:9px 10px;border-bottom:1px solid var(--dsw-alias-border-l1);text-align:left;vertical-align:middle;font-size:12px}
109
+ .dts-table th{position:sticky;top:0;background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-secondary);font-weight:600}
110
+ .dts-table tr:last-child td{border-bottom:0}.dts-tool{width:52%}.dts-tool code{display:block;overflow:hidden;text-overflow:ellipsis;overflow-wrap:anywhere;white-space:nowrap;color:var(--dsw-alias-label-primary)}
111
+ .dts-description{display:block;margin-top:3px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--dsw-alias-label-tertiary)}
112
+ .dts-policy{width:26%}.dts-selected{width:22%;color:var(--dsw-alias-label-secondary)}
113
+ @container(max-width:620px){.dts-toolbar{grid-template-columns:1fr auto}.dts-toolbar .dts-limit{grid-column:1/-1}.dts-lists{grid-template-columns:1fr}.dts-table{min-width:0}.dts-table thead{display:none}.dts-table tr{display:grid;grid-template-columns:minmax(0,1fr) 132px;padding:8px 10px;border-bottom:1px solid var(--dsw-alias-border-l1)}.dts-table td{padding:4px 0;border:0}.dts-table .dts-tool,.dts-table .dts-policy{width:auto}.dts-table .dts-selected{grid-column:1/-1;width:auto;font-size:11px}.dts-table .dts-selected::before{content:attr(data-label) ": ";color:var(--dsw-alias-label-tertiary);font-weight:600}}
114
+ `;
115
+ function namesFromText(value) {
116
+ return [...new Set(value.split(/\r?\n/u).map((name) => name.trim()).filter(Boolean))].sort();
117
+ }
118
+ function overrideFor(name, settings) {
119
+ if (settings.neverSearch.includes(name)) return "blocked";
120
+ if (settings.alwaysVisible.includes(name)) return "always";
121
+ return "default";
122
+ }
123
+ function decodeCatalog(value) {
124
+ if (typeof value !== "object" || value === null || Array.isArray(value)) throw new Error("Invalid catalog response");
125
+ const record = value;
126
+ if (record["schemaVersion"] !== 1 || !Array.isArray(record["tools"]) || typeof record["generation"] !== "number") throw new Error("Invalid catalog response");
127
+ return value;
128
+ }
129
+ function ToolSearchSettingsSection({ scope, t }) {
130
+ const snapshot = (0, react.useSyncExternalStore)((0, react.useCallback)((notify) => scope?.subscribe(notify) ?? (() => {}), [scope]), (0, react.useCallback)(() => scope?.getSnapshot() ?? EMPTY_SETTINGS, [scope]));
131
+ const [catalog, setCatalog] = (0, react.useState)();
132
+ const [filter, setFilter] = (0, react.useState)("");
133
+ const [alwaysText, setAlwaysText] = (0, react.useState)("");
134
+ const [blockedText, setBlockedText] = (0, react.useState)("");
135
+ const [limitText, setLimitText] = (0, react.useState)(String(5));
136
+ const [status, setStatus] = (0, react.useState)();
137
+ const translate = t ?? ((key) => en[key]);
138
+ const settings = snapshot.value;
139
+ const refresh = (0, react.useCallback)(async () => {
140
+ try {
141
+ const response = await fetch(TOOL_SEARCH_CATALOG_ROUTE, { cache: "no-store" });
142
+ if (!response.ok) throw new Error(`HTTP ${response.status}`);
143
+ setCatalog(decodeCatalog(await response.json()));
144
+ setStatus(void 0);
145
+ } catch (error) {
146
+ setStatus({
147
+ text: error instanceof Error ? error.message : String(error),
148
+ error: true
149
+ });
150
+ }
151
+ }, []);
152
+ (0, react.useEffect)(() => {
153
+ refresh();
154
+ }, [refresh]);
155
+ (0, react.useEffect)(() => {
156
+ if (settings === void 0) return;
157
+ setAlwaysText(settings.alwaysVisible.join("\n"));
158
+ setBlockedText(settings.neverSearch.join("\n"));
159
+ setLimitText(String(settings.defaultLimit));
160
+ }, [settings]);
161
+ const commit = (0, react.useCallback)((field, value) => {
162
+ if (scope === void 0 || !snapshot.writable) return;
163
+ setStatus(void 0);
164
+ scope.set(field, value).then(() => {
165
+ setStatus({
166
+ text: translate("saved"),
167
+ error: false
168
+ });
169
+ refresh();
170
+ }, (error) => {
171
+ setStatus({
172
+ text: error instanceof Error ? error.message : String(error),
173
+ error: true
174
+ });
175
+ });
176
+ }, [
177
+ refresh,
178
+ scope,
179
+ snapshot.writable,
180
+ translate
181
+ ]);
182
+ const visibleTools = (0, react.useMemo)(() => {
183
+ const query = filter.trim().toLowerCase();
184
+ if (query.length === 0) return catalog?.tools ?? [];
185
+ return (catalog?.tools ?? []).filter((tool) => tool.name.toLowerCase().includes(query) || tool.description.toLowerCase().includes(query));
186
+ }, [catalog, filter]);
187
+ const changePolicy = (name, next) => {
188
+ if (settings === void 0 || name === "tool_search") return;
189
+ const always = new Set(settings.alwaysVisible);
190
+ const blocked = new Set(settings.neverSearch);
191
+ always.delete(name);
192
+ blocked.delete(name);
193
+ if (next === "always") always.add(name);
194
+ if (next === "blocked") blocked.add(name);
195
+ commit("alwaysVisible", [...always].sort());
196
+ commit("neverSearch", [...blocked].sort());
197
+ };
198
+ const core = new Set(DEFAULT_CORE_TOOLS);
199
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
200
+ className: "dts-settings",
201
+ children: [
202
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
203
+ className: "dts-toolbar",
204
+ children: [
205
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
206
+ className: "dts-field dts-limit",
207
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: translate("topK") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
208
+ className: "dts-input",
209
+ type: "number",
210
+ min: 1,
211
+ max: 20,
212
+ value: limitText,
213
+ disabled: !snapshot.writable,
214
+ onChange: (event) => setLimitText(event.target.value),
215
+ onBlur: () => {
216
+ const value = Number.parseInt(limitText, 10);
217
+ if (Number.isSafeInteger(value) && value >= 1 && value <= 20) commit("defaultLimit", value);
218
+ else setLimitText(String(settings?.defaultLimit ?? 5));
219
+ }
220
+ })]
221
+ }),
222
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
223
+ className: "dts-field",
224
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: translate("filter") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
225
+ className: "dts-input",
226
+ type: "search",
227
+ value: filter,
228
+ onChange: (event) => setFilter(event.target.value)
229
+ })]
230
+ }),
231
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
232
+ className: "dts-button",
233
+ type: "button",
234
+ onClick: () => {
235
+ refresh();
236
+ },
237
+ children: translate("refresh")
238
+ })
239
+ ]
240
+ }),
241
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
242
+ className: "dts-lists",
243
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
244
+ className: "dts-field",
245
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: translate("alwaysVisible") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("textarea", {
246
+ className: "dts-textarea",
247
+ value: alwaysText,
248
+ disabled: !snapshot.writable,
249
+ placeholder: translate("onePerLine"),
250
+ onChange: (event) => setAlwaysText(event.target.value),
251
+ onBlur: () => commit("alwaysVisible", namesFromText(alwaysText))
252
+ })]
253
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
254
+ className: "dts-field",
255
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: translate("neverSearch") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("textarea", {
256
+ className: "dts-textarea",
257
+ value: blockedText,
258
+ disabled: !snapshot.writable,
259
+ placeholder: translate("onePerLine"),
260
+ onChange: (event) => setBlockedText(event.target.value),
261
+ onBlur: () => commit("neverSearch", namesFromText(blockedText).filter((name) => name !== TOOL_SEARCH_NAME))
262
+ })]
263
+ })]
264
+ }),
265
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
266
+ className: "dts-field",
267
+ children: [
268
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
269
+ className: "dts-section-title",
270
+ children: translate("catalog")
271
+ }),
272
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
273
+ className: "dts-table-wrap",
274
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("table", {
275
+ className: "dts-table",
276
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("thead", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("tr", { children: [
277
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("th", {
278
+ className: "dts-tool",
279
+ children: translate("tool")
280
+ }),
281
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("th", {
282
+ className: "dts-policy",
283
+ children: translate("policy")
284
+ }),
285
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("th", {
286
+ className: "dts-selected",
287
+ children: translate("selected")
288
+ })
289
+ ] }) }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("tbody", { children: [visibleTools.map((tool) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("tr", { children: [
290
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("td", {
291
+ className: "dts-tool",
292
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("code", {
293
+ title: tool.name,
294
+ children: tool.name
295
+ }), tool.description.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
296
+ className: "dts-description",
297
+ title: tool.description,
298
+ children: tool.description
299
+ }) : null]
300
+ }),
301
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", {
302
+ className: "dts-policy",
303
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
304
+ className: "dts-select",
305
+ "aria-label": `${translate("policy")}: ${tool.name}`,
306
+ value: tool.name === "tool_search" ? "always" : overrideFor(tool.name, settings ?? {
307
+ defaultLimit: 5,
308
+ alwaysVisible: [],
309
+ neverSearch: []
310
+ }),
311
+ disabled: !snapshot.writable || tool.name === "tool_search",
312
+ onChange: (event) => changePolicy(tool.name, event.target.value),
313
+ children: [
314
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
315
+ value: "default",
316
+ children: core.has(tool.name) ? `${translate("defaultPolicy")} (${translate("alwaysPolicy")})` : translate("defaultPolicy")
317
+ }),
318
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
319
+ value: "always",
320
+ children: translate("alwaysPolicy")
321
+ }),
322
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
323
+ value: "blocked",
324
+ children: translate("blockedPolicy")
325
+ })
326
+ ]
327
+ })
328
+ }),
329
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", {
330
+ className: "dts-selected",
331
+ "data-label": translate("selected"),
332
+ "aria-label": `${translate("selected")}: ${tool.selectedBy.length}`,
333
+ children: tool.selectedBy.length
334
+ })
335
+ ] }, tool.name)), catalog !== void 0 && visibleTools.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("tr", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", {
336
+ colSpan: 3,
337
+ children: translate("empty")
338
+ }) }) : null] })]
339
+ })
340
+ }),
341
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
342
+ className: "dts-status",
343
+ "data-error": status?.error || void 0,
344
+ children: status?.text ?? (catalog === void 0 ? translate("loading") : "")
345
+ })
346
+ ]
347
+ })
348
+ ]
349
+ });
350
+ }
351
+ const inject = [
352
+ "slots",
353
+ "locale",
354
+ "settingsScope"
355
+ ];
356
+ function apply(ctx) {
357
+ ctx.effect(() => {
358
+ if (document.querySelector("style[data-plugin-css=\"@anionex/dsh-tool-search\"]") !== null) return () => {};
359
+ const tag = document.createElement("style");
360
+ tag.dataset.pluginCss = "@anionex/dsh-tool-search";
361
+ tag.textContent = styles;
362
+ document.head.append(tag);
363
+ return () => tag.remove();
364
+ }, "dsh-tool-search: styles");
365
+ ctx.effect(() => ctx.locale.register("settings.toolSearch", {
366
+ en,
367
+ zh
368
+ }), "dsh-tool-search: locale");
369
+ const t = ctx.locale.bind("settings.toolSearch");
370
+ const scope = ctx.settingsScope.bind({ namespace: TOOL_SEARCH_SETTINGS_NAMESPACE });
371
+ ctx.slots.inject("settings.section", () => ctx.slots.register({
372
+ name: "settings.section",
373
+ id: "tool-search",
374
+ order: 34,
375
+ label: () => t("nav"),
376
+ inject: () => ({
377
+ scope,
378
+ t
379
+ })
380
+ }, ToolSearchSettingsSection));
381
+ }
382
+
383
+ //#endregion
384
+ exports.ToolSearchSettingsSection = ToolSearchSettingsSection;
385
+ exports.apply = apply;
386
+ exports.inject = inject;
387
+ return module.exports; } });
388
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","names":["useSyncExternalStore","useCallback","useState","useMemo"],"sources":["../src/shared.ts","../src/client/index.tsx"],"sourcesContent":["/** Values shared by the Host runtime and Web settings client. */\n\nexport const TOOL_SEARCH_NAME = 'tool_search'\nexport const TOOL_SEARCH_SETTINGS_NAMESPACE = 'tool-search'\nexport const TOOL_SEARCH_CATALOG_ROUTE = '/_dsh/tool-search/catalog'\nexport const DEFAULT_RESULT_LIMIT = 5\nexport const MAX_RESULT_LIMIT = 20\n\n/**\n * Stable bootstrap surface for current DSH releases. Unknown future first-party\n * names are deferred until this list or the user allowlist is updated because\n * ToolDefinition does not expose package provenance.\n */\nexport const DEFAULT_CORE_TOOLS = Object.freeze([\n 'apply_patch',\n 'ask_user_question',\n 'bash',\n 'create_goal',\n 'dsh_im_return_file',\n 'exit_plan_mode',\n 'get_goal',\n 'interrupt_agent',\n 'job_kill',\n 'job_list',\n 'job_output',\n 'list_agents',\n 'ralph',\n 'report',\n 'send_message',\n 'skill',\n 'subagent',\n 'subagent_fork',\n 'todo_write',\n 'update_goal',\n 'workflow',\n] as const)\n\nexport interface ToolSearchSettings {\n defaultLimit: number\n alwaysVisible: string[]\n neverSearch: string[]\n}\n\nexport const DEFAULT_SETTINGS: Readonly<ToolSearchSettings> = Object.freeze({\n defaultLimit: DEFAULT_RESULT_LIMIT,\n alwaysVisible: [],\n neverSearch: [],\n})\n\nexport type ToolPolicy = 'always' | 'deferred' | 'blocked'\n\nexport interface CatalogToolSummary {\n name: string\n description: string\n policy: ToolPolicy\n selectedBy: string[]\n}\n\nexport interface CatalogSnapshot {\n schemaVersion: 1\n generation: number\n tools: CatalogToolSummary[]\n}\n","/** DSH Web settings surface for deferred tool policy. */\n\nimport {\n useCallback,\n useEffect,\n useMemo,\n useState,\n useSyncExternalStore,\n type ReactNode,\n} from 'react'\nimport {\n DEFAULT_CORE_TOOLS,\n DEFAULT_RESULT_LIMIT,\n MAX_RESULT_LIMIT,\n TOOL_SEARCH_CATALOG_ROUTE,\n TOOL_SEARCH_NAME,\n TOOL_SEARCH_SETTINGS_NAMESPACE,\n type CatalogSnapshot,\n type ToolPolicy,\n type ToolSearchSettings,\n} from '../shared.ts'\n\ninterface SettingsScopeSnapshot<T> {\n status: 'loading' | 'ready' | 'unavailable'\n value: T | undefined\n writable: boolean\n}\n\ninterface SettingsScope<T> {\n getSnapshot(): SettingsScopeSnapshot<T>\n subscribe(listener: () => void): () => void\n set(field: string, value: unknown): Promise<void>\n}\n\ntype Disposer = () => void\n\ninterface ClientContext {\n effect(setup: () => Disposer | void, label: string): void\n locale: {\n register(namespace: string, catalogs: Record<string, Record<string, string>>): Disposer\n bind(namespace: string): (key: string) => string\n }\n settingsScope: {\n bind<T>(options: { namespace: string }): SettingsScope<T>\n }\n slots: {\n inject(name: string, callback: () => Disposer): Disposer\n register<P>(\n options: {\n name: string\n id: string\n order: number\n label: () => string\n inject: () => P\n },\n component: (props: P) => ReactNode,\n ): Disposer\n }\n}\n\ntype Translate = (key: keyof typeof en) => string\n\nconst en = {\n nav: 'Tool Search',\n topK: 'Default results',\n alwaysVisible: 'Always visible',\n neverSearch: 'Never searchable',\n catalog: 'Tool catalog',\n filter: 'Filter tools',\n refresh: 'Refresh',\n tool: 'Tool',\n policy: 'Policy',\n selected: 'Live agents',\n defaultPolicy: 'Default',\n alwaysPolicy: 'Always',\n blockedPolicy: 'Blocked',\n loading: 'Loading...',\n empty: 'No matching tools',\n saved: 'Saved',\n onePerLine: 'One exact tool name per line',\n}\n\nconst zh: typeof en = {\n nav: '工具搜索',\n topK: '默认结果数',\n alwaysVisible: '常驻白名单',\n neverSearch: '搜索黑名单',\n catalog: '工具目录',\n filter: '筛选工具',\n refresh: '刷新',\n tool: '工具',\n policy: '策略',\n selected: '活跃 Agent',\n defaultPolicy: '默认',\n alwaysPolicy: '常驻',\n blockedPolicy: '禁用',\n loading: '加载中...',\n empty: '没有匹配工具',\n saved: '已保存',\n onePerLine: '每行一个精确工具名',\n}\n\nconst EMPTY_SETTINGS: SettingsScopeSnapshot<ToolSearchSettings> = {\n status: 'unavailable',\n value: undefined,\n writable: false,\n}\n\nconst styles = `\n.dts-settings{container-type:inline-size;display:flex;flex-direction:column;gap:20px;width:100%;min-width:0;color:var(--dsw-alias-label-primary)}\n.dts-toolbar{display:grid;grid-template-columns:minmax(160px,220px) minmax(220px,1fr) auto;align-items:end;gap:12px}\n.dts-field{display:flex;flex-direction:column;gap:6px;min-width:0}\n.dts-field>span,.dts-section-title{font-size:13px;font-weight:600;color:var(--dsw-alias-label-primary)}\n.dts-input,.dts-textarea,.dts-select{box-sizing:border-box;width:100%;min-width:0;border:1px solid var(--dsw-alias-border-l2);border-radius:6px;background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary);font:inherit}\n.dts-input,.dts-select{height:34px;padding:0 9px}.dts-textarea{min-height:104px;padding:8px 9px;resize:vertical;line-height:20px}\n.dts-input:focus,.dts-textarea:focus,.dts-select:focus{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:1px}\n.dts-lists{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:16px}\n.dts-hint{font-size:11px;color:var(--dsw-alias-label-tertiary)}\n.dts-button{height:34px;padding:0 12px;border:1px solid var(--dsw-alias-border-l2);border-radius:6px;background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary);cursor:pointer}\n.dts-button:hover{background:var(--dsw-alias-interactive-bg-hover)}.dts-button:disabled{opacity:.5;cursor:not-allowed}\n.dts-status{min-height:18px;font-size:12px;color:var(--dsw-alias-label-secondary)}.dts-status[data-error=true]{color:var(--dsw-alias-state-error-primary)}\n.dts-table-wrap{min-width:0;overflow:auto;border-top:1px solid var(--dsw-alias-border-l2);border-bottom:1px solid var(--dsw-alias-border-l2)}\n.dts-table{width:100%;min-width:620px;border-collapse:collapse;table-layout:fixed}\n.dts-table th,.dts-table td{box-sizing:border-box;padding:9px 10px;border-bottom:1px solid var(--dsw-alias-border-l1);text-align:left;vertical-align:middle;font-size:12px}\n.dts-table th{position:sticky;top:0;background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-secondary);font-weight:600}\n.dts-table tr:last-child td{border-bottom:0}.dts-tool{width:52%}.dts-tool code{display:block;overflow:hidden;text-overflow:ellipsis;overflow-wrap:anywhere;white-space:nowrap;color:var(--dsw-alias-label-primary)}\n.dts-description{display:block;margin-top:3px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--dsw-alias-label-tertiary)}\n.dts-policy{width:26%}.dts-selected{width:22%;color:var(--dsw-alias-label-secondary)}\n@container(max-width:620px){.dts-toolbar{grid-template-columns:1fr auto}.dts-toolbar .dts-limit{grid-column:1/-1}.dts-lists{grid-template-columns:1fr}.dts-table{min-width:0}.dts-table thead{display:none}.dts-table tr{display:grid;grid-template-columns:minmax(0,1fr) 132px;padding:8px 10px;border-bottom:1px solid var(--dsw-alias-border-l1)}.dts-table td{padding:4px 0;border:0}.dts-table .dts-tool,.dts-table .dts-policy{width:auto}.dts-table .dts-selected{grid-column:1/-1;width:auto;font-size:11px}.dts-table .dts-selected::before{content:attr(data-label) \": \";color:var(--dsw-alias-label-tertiary);font-weight:600}}\n`\n\nfunction namesFromText(value: string): string[] {\n return [...new Set(value.split(/\\r?\\n/u).map(name => name.trim()).filter(Boolean))].sort()\n}\n\nfunction overrideFor(name: string, settings: ToolSearchSettings): ToolPolicy | 'default' {\n if (settings.neverSearch.includes(name)) return 'blocked'\n if (settings.alwaysVisible.includes(name)) return 'always'\n return 'default'\n}\n\nfunction decodeCatalog(value: unknown): CatalogSnapshot {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) throw new Error('Invalid catalog response')\n const record = value as Record<string, unknown>\n if (record['schemaVersion'] !== 1 || !Array.isArray(record['tools']) || typeof record['generation'] !== 'number') {\n throw new Error('Invalid catalog response')\n }\n return value as CatalogSnapshot\n}\n\ntype SettingsProps = {\n scope?: SettingsScope<ToolSearchSettings>\n t?: Translate\n}\n\nexport function ToolSearchSettingsSection({ scope, t }: SettingsProps): ReactNode {\n const snapshot = useSyncExternalStore(\n useCallback((notify: () => void) => scope?.subscribe(notify) ?? (() => {}), [scope]),\n useCallback(() => scope?.getSnapshot() ?? EMPTY_SETTINGS, [scope]),\n )\n const [catalog, setCatalog] = useState<CatalogSnapshot>()\n const [filter, setFilter] = useState('')\n const [alwaysText, setAlwaysText] = useState('')\n const [blockedText, setBlockedText] = useState('')\n const [limitText, setLimitText] = useState(String(DEFAULT_RESULT_LIMIT))\n const [status, setStatus] = useState<{ text: string; error: boolean }>()\n const translate = t ?? ((key: keyof typeof en) => en[key])\n const settings = snapshot.value\n\n const refresh = useCallback(async (): Promise<void> => {\n try {\n const response = await fetch(TOOL_SEARCH_CATALOG_ROUTE, { cache: 'no-store' })\n if (!response.ok) throw new Error(`HTTP ${response.status}`)\n setCatalog(decodeCatalog(await response.json()))\n setStatus(undefined)\n } catch (error) {\n setStatus({ text: error instanceof Error ? error.message : String(error), error: true })\n }\n }, [])\n\n useEffect(() => { void refresh() }, [refresh])\n useEffect(() => {\n if (settings === undefined) return\n setAlwaysText(settings.alwaysVisible.join('\\n'))\n setBlockedText(settings.neverSearch.join('\\n'))\n setLimitText(String(settings.defaultLimit))\n }, [settings])\n\n const commit = useCallback((field: keyof ToolSearchSettings, value: unknown): void => {\n if (scope === undefined || !snapshot.writable) return\n setStatus(undefined)\n void scope.set(field, value).then(() => {\n setStatus({ text: translate('saved'), error: false })\n void refresh()\n }, error => {\n setStatus({ text: error instanceof Error ? error.message : String(error), error: true })\n })\n }, [refresh, scope, snapshot.writable, translate])\n\n const visibleTools = useMemo(() => {\n const query = filter.trim().toLowerCase()\n if (query.length === 0) return catalog?.tools ?? []\n return (catalog?.tools ?? []).filter(tool =>\n tool.name.toLowerCase().includes(query) || tool.description.toLowerCase().includes(query),\n )\n }, [catalog, filter])\n\n const changePolicy = (name: string, next: ToolPolicy | 'default'): void => {\n if (settings === undefined || name === TOOL_SEARCH_NAME) return\n const always = new Set(settings.alwaysVisible)\n const blocked = new Set(settings.neverSearch)\n always.delete(name)\n blocked.delete(name)\n if (next === 'always') always.add(name)\n if (next === 'blocked') blocked.add(name)\n commit('alwaysVisible', [...always].sort())\n commit('neverSearch', [...blocked].sort())\n }\n\n const core = new Set<string>(DEFAULT_CORE_TOOLS)\n return <div className=\"dts-settings\">\n <div className=\"dts-toolbar\">\n <label className=\"dts-field dts-limit\">\n <span>{translate('topK')}</span>\n <input\n className=\"dts-input\"\n type=\"number\"\n min={1}\n max={MAX_RESULT_LIMIT}\n value={limitText}\n disabled={!snapshot.writable}\n onChange={event => setLimitText(event.target.value)}\n onBlur={() => {\n const value = Number.parseInt(limitText, 10)\n if (Number.isSafeInteger(value) && value >= 1 && value <= MAX_RESULT_LIMIT) commit('defaultLimit', value)\n else setLimitText(String(settings?.defaultLimit ?? DEFAULT_RESULT_LIMIT))\n }}\n />\n </label>\n <label className=\"dts-field\">\n <span>{translate('filter')}</span>\n <input className=\"dts-input\" type=\"search\" value={filter} onChange={event => setFilter(event.target.value)} />\n </label>\n <button className=\"dts-button\" type=\"button\" onClick={() => { void refresh() }}>{translate('refresh')}</button>\n </div>\n\n <div className=\"dts-lists\">\n <label className=\"dts-field\">\n <span>{translate('alwaysVisible')}</span>\n <textarea\n className=\"dts-textarea\"\n value={alwaysText}\n disabled={!snapshot.writable}\n placeholder={translate('onePerLine')}\n onChange={event => setAlwaysText(event.target.value)}\n onBlur={() => commit('alwaysVisible', namesFromText(alwaysText))}\n />\n </label>\n <label className=\"dts-field\">\n <span>{translate('neverSearch')}</span>\n <textarea\n className=\"dts-textarea\"\n value={blockedText}\n disabled={!snapshot.writable}\n placeholder={translate('onePerLine')}\n onChange={event => setBlockedText(event.target.value)}\n onBlur={() => commit('neverSearch', namesFromText(blockedText).filter(name => name !== TOOL_SEARCH_NAME))}\n />\n </label>\n </div>\n\n <section className=\"dts-field\">\n <div className=\"dts-section-title\">{translate('catalog')}</div>\n <div className=\"dts-table-wrap\">\n <table className=\"dts-table\">\n <thead><tr>\n <th className=\"dts-tool\">{translate('tool')}</th>\n <th className=\"dts-policy\">{translate('policy')}</th>\n <th className=\"dts-selected\">{translate('selected')}</th>\n </tr></thead>\n <tbody>\n {visibleTools.map(tool => <tr key={tool.name}>\n <td className=\"dts-tool\">\n <code title={tool.name}>{tool.name}</code>\n {tool.description.length > 0 ? <span className=\"dts-description\" title={tool.description}>{tool.description}</span> : null}\n </td>\n <td className=\"dts-policy\">\n <select\n className=\"dts-select\"\n aria-label={`${translate('policy')}: ${tool.name}`}\n value={tool.name === TOOL_SEARCH_NAME ? 'always' : overrideFor(tool.name, settings ?? {\n defaultLimit: DEFAULT_RESULT_LIMIT,\n alwaysVisible: [],\n neverSearch: [],\n })}\n disabled={!snapshot.writable || tool.name === TOOL_SEARCH_NAME}\n onChange={event => changePolicy(tool.name, event.target.value as ToolPolicy | 'default')}\n >\n <option value=\"default\">{core.has(tool.name) ? `${translate('defaultPolicy')} (${translate('alwaysPolicy')})` : translate('defaultPolicy')}</option>\n <option value=\"always\">{translate('alwaysPolicy')}</option>\n <option value=\"blocked\">{translate('blockedPolicy')}</option>\n </select>\n </td>\n <td\n className=\"dts-selected\"\n data-label={translate('selected')}\n aria-label={`${translate('selected')}: ${tool.selectedBy.length}`}\n >{tool.selectedBy.length}</td>\n </tr>)}\n {catalog !== undefined && visibleTools.length === 0\n ? <tr><td colSpan={3}>{translate('empty')}</td></tr>\n : null}\n </tbody>\n </table>\n </div>\n <div className=\"dts-status\" data-error={status?.error || undefined}>\n {status?.text ?? (catalog === undefined ? translate('loading') : '')}\n </div>\n </section>\n </div>\n}\n\nexport const inject = ['slots', 'locale', 'settingsScope']\n\nexport function apply(ctx: ClientContext): void {\n ctx.effect(() => {\n if (document.querySelector('style[data-plugin-css=\"@anionex/dsh-tool-search\"]') !== null) return () => {}\n const tag = document.createElement('style')\n tag.dataset.pluginCss = '@anionex/dsh-tool-search'\n tag.textContent = styles\n document.head.append(tag)\n return () => tag.remove()\n }, 'dsh-tool-search: styles')\n ctx.effect(() => ctx.locale.register('settings.toolSearch', { en, zh }), 'dsh-tool-search: locale')\n const t = ctx.locale.bind('settings.toolSearch') as Translate\n const scope = ctx.settingsScope.bind<ToolSearchSettings>({ namespace: TOOL_SEARCH_SETTINGS_NAMESPACE })\n ctx.slots.inject('settings.section', () => ctx.slots.register({\n name: 'settings.section',\n id: 'tool-search',\n order: 34,\n label: () => t('nav'),\n inject: () => ({ scope, t }),\n }, ToolSearchSettingsSection))\n}\n"],"mappings":"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"}
package/lib/index.js ADDED
@@ -0,0 +1,24 @@
1
+ /** DSH bundle entry for Codex-style deferred tool loading. */
2
+ import { ToolSearchRuntime } from "./runtime.js";
3
+ import { Config, TOOL_SEARCH_SETTINGS_NS } from "./settings.js";
4
+ import { installCatalogRoute } from "./web.js";
5
+ export const name = '@anionex/dsh-tool-search';
6
+ export const inject = ['agents', 'tools', 'systemPrompt', 'settings'];
7
+ export { Config };
8
+ export function apply(ctx, config) {
9
+ const settings = ctx.settings.register(TOOL_SEARCH_SETTINGS_NS, Config, {
10
+ base: config,
11
+ applies: 'live',
12
+ });
13
+ const runtime = new ToolSearchRuntime(ctx, settings.get());
14
+ ctx.tools.register(runtime.definition);
15
+ ctx.effect(() => runtime.install(), 'dsh-tool-search: agent visibility');
16
+ ctx.effect(() => settings.watch(next => { runtime.updateSettings(next); }), 'dsh-tool-search: settings');
17
+ installCatalogRoute(ctx, runtime);
18
+ }
19
+ export { Bm25Index, tokenize } from "./bm25.js";
20
+ export { appendSchemaSearchText, buildCatalog, toolSearchText } from "./catalog.js";
21
+ export { ToolSearchRuntime } from "./runtime.js";
22
+ export { normalizeSettings, ToolPolicyResolver } from "./settings.js";
23
+ export * from "./shared.js";
24
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,8DAA8D;AAM9D,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAA;AAChD,OAAO,EAAE,MAAM,EAAE,uBAAuB,EAAE,MAAM,eAAe,CAAA;AAE/D,OAAO,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAA;AAE9C,MAAM,CAAC,MAAM,IAAI,GAAG,0BAA0B,CAAA;AAC9C,MAAM,CAAC,MAAM,MAAM,GAAG,CAAC,QAAQ,EAAE,OAAO,EAAE,cAAc,EAAE,UAAU,CAAC,CAAA;AACrE,OAAO,EAAE,MAAM,EAAE,CAAA;AAEjB,MAAM,UAAU,KAAK,CAAC,GAAY,EAAE,MAA0B;IAC5D,MAAM,QAAQ,GAAG,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC,uBAAuB,EAAE,MAAM,EAAE;QACtE,IAAI,EAAE,MAAM;QACZ,OAAO,EAAE,MAAM;KAChB,CAAC,CAAA;IACF,MAAM,OAAO,GAAG,IAAI,iBAAiB,CAAC,GAAG,EAAE,QAAQ,CAAC,GAAG,EAAE,CAAC,CAAA;IAC1D,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC,UAAU,CAAC,CAAA;IACtC,GAAG,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,mCAAmC,CAAC,CAAA;IACxE,GAAG,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,GAAG,OAAO,CAAC,cAAc,CAAC,IAAI,CAAC,CAAA,CAAC,CAAC,CAAC,EAAE,2BAA2B,CAAC,CAAA;IACvG,mBAAmB,CAAC,GAAG,EAAE,OAAO,CAAC,CAAA;AACnC,CAAC;AAED,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAA;AAC/C,OAAO,EAAE,sBAAsB,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,cAAc,CAAA;AACnF,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAA;AAChD,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAA;AACrE,cAAc,aAAa,CAAA"}