@fishdivinity/dsh-local-search 0.2.1 → 0.3.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/lib/tools.js CHANGED
@@ -29,13 +29,12 @@ async function guard(fn) {
29
29
  }
30
30
 
31
31
  /**
32
- * Coerce an optional numeric argument into `[1, cap]`. A non-numeric argument
33
- * falls back to the configured default instead of turning the window into NaN,
34
- * which would silently return nothing.
35
- * @param value - the argument as the model sent it
36
- * @param fallback - default to use when it is not a finite number
37
- * @param cap - inclusive upper bound
38
- * @returns the usable count
32
+ * 把可选的数字参数收进 `[1, cap]`。非数字参数回落到配置的默认值,而不是让窗口变成 NaN
33
+ * ——那样会静默返回空结果。
34
+ * @param value - 模型发来的参数原样
35
+ * @param fallback - 不是有限数字时用的默认值
36
+ * @param cap - 闭区间上界
37
+ * @returns 可用的条数
39
38
  */
40
39
  function clampCount(value, fallback, cap) {
41
40
  const number = Number.isFinite(value) ? Math.floor(value) : fallback
@@ -64,6 +63,19 @@ function validateEngine(engine, allowed) {
64
63
  return value
65
64
  }
66
65
 
66
+ /**
67
+ * 这次调用该用哪个后端。
68
+ *
69
+ * `auto`(或没传)跟随配置里选的后端,而不是「注册表里的第一个」:配置里的 backend 就是
70
+ * 「默认用哪个」的声明,自动选第一个会让那个字段变成死配置。
71
+ * @param {string|undefined} requested - 调用参数里的 engine
72
+ * @param {string} configured - 配置里选的后端
73
+ * @returns {string} 要解析的后端名
74
+ */
75
+ function engineFor(requested, configured) {
76
+ return requested === undefined || requested === '' || requested === 'auto' ? configured : requested
77
+ }
78
+
67
79
  function presentSearchCall(label) {
68
80
  return (args) => ({
69
81
  card: 'generic',
@@ -188,20 +200,19 @@ const statusOutput = {
188
200
  }
189
201
 
190
202
  /**
191
- * Build and register the five model-facing tools.
203
+ * 构建并注册五个面向模型的工具。
192
204
  * @param {import('@deepseek-ai/cordis').Context} ctx
193
205
  * @param {object} config
194
- * @returns {Array<() => void>} tool disposers
206
+ * @returns {Array<() => void>} 工具的 disposer
195
207
  */
196
208
  export function createTools(ctx, config) {
197
- // Registration fixes the tool deadlines and the text describing defaults;
198
- // everything a call acts on is read per operation, so a save on the config
199
- // page applies to the next call instead of the next reload.
209
+ // 注册时就固定了工具的截止时间与描述默认值的文案;一次调用真正用到的一切都是每次操作现读
210
+ // 的,所以配置页上的保存对下一次调用生效,而不是对下一次重载生效。
200
211
  const initial = readConfig(config)
201
212
  const names = engineNames()
202
213
 
203
214
  async function resolveWorkspace(exec, cfg) {
204
- if (cfg.workspaceRoot) return cfg.workspaceRoot
215
+ if (cfg.scopes.workspaceRoot) return cfg.scopes.workspaceRoot
205
216
  if (exec.agent && ctx.workingDirectory?.ensure) {
206
217
  try {
207
218
  return await ctx.workingDirectory.ensure(exec.agent, exec.signal)
@@ -238,11 +249,11 @@ export function createTools(ctx, config) {
238
249
  },
239
250
  engine: {
240
251
  type: 'string',
241
- description: `auto (default) or ${names.files.join(', ')}. Use auto unless the user asks for a specific engine.`,
252
+ description: `auto (default) follows the configured files backend; ${names.files.join(', ')} otherwise. Name one only when the user asks for a specific engine.`,
242
253
  },
243
254
  limit: {
244
255
  type: 'number',
245
- description: `Max results (default ${initial.maxResults}; max ${MAX_LIMIT}).`,
256
+ description: `Max results (default ${initial.limits.maxResults}; max ${MAX_LIMIT}).`,
246
257
  },
247
258
  },
248
259
  timeoutMs: initial.timeoutMs,
@@ -251,7 +262,7 @@ export function createTools(ctx, config) {
251
262
  return guard(async () => {
252
263
  const cfg = readConfig(config)
253
264
  const query = requireQuery(args.query)
254
- const engine = resolveFilesEngine(args.engine)
265
+ const engine = resolveFilesEngine(engineFor(args.engine, cfg.files.backend))
255
266
  const scope = args.scope || 'workspace'
256
267
  const workspace = await resolveWorkspace(exec, cfg)
257
268
  let dir
@@ -263,11 +274,11 @@ export function createTools(ctx, config) {
263
274
  return await engine.search({
264
275
  query,
265
276
  dir,
266
- limit: clampLimit(args.limit, cfg.maxResults),
267
- esPath: cfg.esPath,
277
+ limit: clampLimit(args.limit, cfg.limits.maxResults),
278
+ esPath: cfg.files.everything.esPath,
268
279
  timeoutMs: initial.timeoutMs,
269
280
  signal: exec.signal,
270
- encoding: cfg.esEncoding,
281
+ encoding: cfg.files.everything.esEncoding,
271
282
  })
272
283
  })
273
284
  },
@@ -302,11 +313,11 @@ export function createTools(ctx, config) {
302
313
  },
303
314
  engine: {
304
315
  type: 'string',
305
- description: `auto (default) or ${names.content.join(', ')}. Use auto unless the user asks for a specific engine.`,
316
+ description: `auto (default) follows the configured content backend; ${names.content.join(', ')} otherwise. Name one only when the user asks for a specific engine.`,
306
317
  },
307
318
  limit: {
308
319
  type: 'number',
309
- description: `Max files (default ${initial.maxResults}; max ${MAX_LIMIT}).`,
320
+ description: `Max files (default ${initial.limits.maxResults}; max ${MAX_LIMIT}).`,
310
321
  },
311
322
  },
312
323
  timeoutMs: initial.timeoutMs,
@@ -315,15 +326,15 @@ export function createTools(ctx, config) {
315
326
  return guard(async () => {
316
327
  const cfg = readConfig(config)
317
328
  const query = requireQuery(args.query)
318
- const engine = resolveContentEngine(args.engine)
329
+ const engine = resolveContentEngine(engineFor(args.engine, cfg.content.backend))
319
330
  const workspace = await resolveWorkspace(exec, cfg)
320
331
  const roots = rootsFor(args.scope || 'workspace', args.path, cfg, workspace)
321
332
  const result = await engine.search({
322
333
  query,
323
334
  roots,
324
335
  ext: args.ext,
325
- limit: clampLimit(args.limit, cfg.maxResults),
326
- url: cfg.anytxtUrl,
336
+ limit: clampLimit(args.limit, cfg.limits.maxResults),
337
+ url: cfg.content.anytxt.url,
327
338
  timeoutMs: initial.timeoutMs,
328
339
  signal: exec.signal,
329
340
  })
@@ -381,7 +392,7 @@ export function createTools(ctx, config) {
381
392
  const fragments = await engine.fragments({
382
393
  ref: args.ref,
383
394
  query,
384
- url: cfg.anytxtUrl,
395
+ url: cfg.content.anytxt.url,
385
396
  timeoutMs: initial.timeoutMs,
386
397
  signal: exec.signal,
387
398
  })
@@ -411,7 +422,7 @@ export function createTools(ctx, config) {
411
422
  },
412
423
  max: {
413
424
  type: 'number',
414
- description: `Max characters (default ${initial.readMaxChars}; max ${MAX_READ}).`,
425
+ description: `Max characters (default ${initial.limits.readMaxChars}; max ${MAX_READ}).`,
415
426
  },
416
427
  },
417
428
  timeoutMs: initial.timeoutMs,
@@ -422,7 +433,7 @@ export function createTools(ctx, config) {
422
433
  if (typeof args.ref !== 'string' || args.ref.trim().length === 0) {
423
434
  throw new Error('ref must be a non-empty string')
424
435
  }
425
- const max = clampCount(args.max, cfg.readMaxChars, MAX_READ)
436
+ const max = clampCount(args.max, cfg.limits.readMaxChars, MAX_READ)
426
437
  const offset = clampOffset(args.offset)
427
438
  const parsed = parseRef(args.ref)
428
439
  const requested = args.engine && args.engine !== 'auto' ? args.engine : parsed.engine
@@ -435,7 +446,7 @@ export function createTools(ctx, config) {
435
446
  }
436
447
  const text = await engine.read({
437
448
  ref: args.ref,
438
- url: cfg.anytxtUrl,
449
+ url: cfg.content.anytxt.url,
439
450
  timeoutMs: initial.timeoutMs,
440
451
  signal: exec.signal,
441
452
  })
@@ -462,21 +473,21 @@ export function createTools(ctx, config) {
462
473
  return guard(async () => {
463
474
  const cfg = readConfig(config)
464
475
  const engine = validateEngine(args.engine, STATUS_ENGINES)
465
- let workspace = cfg.workspaceRoot || ctx.workingDirectory?.defaultDirectory || process.cwd()
476
+ let workspace = cfg.scopes.workspaceRoot || ctx.workingDirectory?.defaultDirectory || process.cwd()
466
477
  try {
467
478
  workspace = await resolveWorkspace(exec, cfg)
468
479
  } catch {
469
- // Status must still report the engines even when the workspace is gone.
480
+ // 工作区没了也得把引擎报出来。
470
481
  }
471
482
 
472
- // The same probe the configuration page's Test control asks for.
483
+ // 与配置页测试按钮要的是同一个探测。
473
484
  const { everything, anytxt } = await probeEngines(config, {
474
485
  only: engine,
475
486
  workspace,
476
487
  signal: exec.signal,
477
488
  })
478
489
 
479
- const all = cfg.allRoots ? parseAllRoots(cfg.allRoots) : defaultAllRoots()
490
+ const all = cfg.scopes.allRoots ? parseAllRoots(cfg.scopes.allRoots) : defaultAllRoots()
480
491
  return {
481
492
  text: formatStatus({
482
493
  everything,
@@ -484,8 +495,8 @@ export function createTools(ctx, config) {
484
495
  engines: engineNames(),
485
496
  roots: {
486
497
  workspace,
487
- work: cfg.workRoot,
488
- personal: cfg.personalRoot,
498
+ work: cfg.scopes.workRoot,
499
+ personal: cfg.scopes.personalRoot,
489
500
  all,
490
501
  },
491
502
  }),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fishdivinity/dsh-local-search",
3
- "version": "0.2.1",
3
+ "version": "0.3.0",
4
4
  "description": "Local file and document search for DeepSeek Harness: Everything filenames plus Anytxt document contents, read-only, with a configuration page on the Plugins page.",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",
@@ -23,7 +23,8 @@
23
23
  ],
24
24
  "scripts": {
25
25
  "test": "node --test",
26
- "check": "node --check lib/index.js && node --check lib/tools.js && node --check lib/engines.js && node --check lib/ref.js && node --check lib/everything.js && node --check lib/anytxt.js && node --check lib/roots.js && node --check lib/format.js && node --check lib/errors.js && node --check lib/config.js && node --check lib/limits.js && node --check lib/probe.js && node --check lib/route.js && node --check lib/client.js && node --check scripts/expand-release-links.mjs",
26
+ "check": "node --check lib/index.js && node --check lib/tools.js && node --check lib/engines.js && node --check lib/ref.js && node --check lib/everything.js && node --check lib/anytxt.js && node --check lib/roots.js && node --check lib/format.js && node --check lib/errors.js && node --check lib/config.js && node --check lib/schema.js && node --check lib/describe.js && node --check lib/bootstrap.js && node --check lib/limits.js && node --check lib/probe.js && node --check lib/route.js && node --check lib/client.js && node --check scripts/expand-release-links.mjs && node --check scripts/privacy-scan.mjs",
27
+ "privacy": "node scripts/privacy-scan.mjs",
27
28
  "pack:check": "npm pack --dry-run"
28
29
  },
29
30
  "keywords": [