dsh-lost-and-found 0.1.1 → 0.1.3
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 +16 -2
- package/client.js +7 -4
- package/config.mjs +22 -3
- package/index.mjs +73 -33
- package/package.json +2 -3
package/README.md
CHANGED
|
@@ -90,7 +90,9 @@ Requires DSH with the web profile and Node.js `^22` or `>=24`. Windows-focused
|
|
|
90
90
|
|
|
91
91
|
## 环境要求
|
|
92
92
|
|
|
93
|
-
- DSH
|
|
93
|
+
- DSH **0.1.7 或更高**,使用 `web` profile
|
|
94
|
+
(设置页依赖 0.1.7 才有的 `configForms` 客户端服务与 `Config` 导出契约。更早的 0.1.x 上
|
|
95
|
+
**host 功能仍然可用** —— 扫描、检索、工具调用都不受影响 —— 但设置页不会出现)
|
|
94
96
|
- Node.js `^22` 或 `>=24`(用到内置 `node:sqlite`)
|
|
95
97
|
- 无需 API key、无需联网;扫描与检索全部在本机完成
|
|
96
98
|
|
|
@@ -122,7 +124,7 @@ dsh plugin --profile web add link:/path/to/dsh-lost-and-found
|
|
|
122
124
|
| --- | --- | --- |
|
|
123
125
|
| `enabled` | `true` | 关闭后不再自动扫描,也不再提供找文件工具 |
|
|
124
126
|
| `roots` | `[]` | 要监视的目录,每个目录带自己的 `policy` |
|
|
125
|
-
| `dbPath` | 空 | 索引库位置;留空用 `%LOCALAPPDATA%\dsh-lost-and-found\index.db` |
|
|
127
|
+
| `dbPath` | 空 | 索引库位置;留空用 `%LOCALAPPDATA%\dsh-lost-and-found\index.db`。可以填**文件**路径,也可以直接填**文件夹**(会用该文件夹下的 `index.db`) |
|
|
126
128
|
| `intervalDays` | `1` | 自动扫描间隔;`0` = 只手动 |
|
|
127
129
|
| `firstScanMode` | `full` | 一个目录**第一次**被扫时收多久:`full` 全部历史 / `window` 最近 `firstRunWindowDays` 天 / `none` 只收今后新增 |
|
|
128
130
|
| `firstRunWindowDays` | `7` | 仅当 `firstScanMode = window` 时生效 |
|
|
@@ -132,6 +134,18 @@ dsh plugin --profile web add link:/path/to/dsh-lost-and-found
|
|
|
132
134
|
| `backupKeep` | `7` | 每日备份保留份数,`0` = 不备份 |
|
|
133
135
|
| `extraExcludeDirs` / `extraExcludePatterns` | `[]` | 追加的排除目录名 / 路径片段(`re:` 前缀表示正则) |
|
|
134
136
|
|
|
137
|
+
### 配置存在哪(DSH 0.1.7 起)
|
|
138
|
+
|
|
139
|
+
DSH 0.1.7 起,设置服务**不再替插件另存一份配置** —— 它只把 Loader 里本插件条目的
|
|
140
|
+
`Config` *投影*成表单,权威值始终在 profile 的补丁文件里:
|
|
141
|
+
|
|
142
|
+
- 设置页里改的值会写进 `$DSH_HOME/profiles/web/cordis.patch.yml` 中 `id: dsh-lost-and-found` 那段
|
|
143
|
+
- 想手改也行,直接编辑那个文件,效果与设置页完全一致
|
|
144
|
+
- **改完立刻生效,不需要重启 DSH**:0.1.7 移除了旧版的 `watch`,插件改为在**每次用到配置之前**
|
|
145
|
+
重新读一遍投影(`settings.describe()`),所以面板里加完目录就能直接点「立即扫描」
|
|
146
|
+
- 从 0.1.2 升级上来的话注意:0.1.2 只在插件加载那一刻读一次配置,会表现为
|
|
147
|
+
「面板里明明加了文件夹,点扫描却说还没设置」—— 0.1.3 修的就是这个
|
|
148
|
+
|
|
135
149
|
## 扫描目录的内容深度(每个目录可不同)
|
|
136
150
|
|
|
137
151
|
- **完整**:记基本信息,并允许把图片交给模型看过之后写回描述(默认)
|
package/client.js
CHANGED
|
@@ -45,7 +45,7 @@ window.__ModuleLoader__.load({
|
|
|
45
45
|
policyMeta: "只记基本信息",
|
|
46
46
|
storageTitle: "记录存放在哪",
|
|
47
47
|
dbPath: "记忆库文件位置",
|
|
48
|
-
dbPathHint: "留空使用默认位置(在系统盘的 AppData\\Local\\dsh-lost-and-found\\index.db
|
|
48
|
+
dbPathHint: "留空使用默认位置(在系统盘的 AppData\\Local\\dsh-lost-and-found\\index.db)。想换地方可以填文件路径,例如 D:\\file-index\\index.db;填一个文件夹也行,会用该文件夹下的 index.db。",
|
|
49
49
|
freqTitle: "多久看一次",
|
|
50
50
|
interval: "自动扫描间隔",
|
|
51
51
|
freqHint: "打开 DSH 时会检查:距离上次扫描超过这个间隔,就自动补扫一次。",
|
|
@@ -97,7 +97,7 @@ window.__ModuleLoader__.load({
|
|
|
97
97
|
policyMeta: "Metadata only",
|
|
98
98
|
storageTitle: "Where records are stored",
|
|
99
99
|
dbPath: "Database file",
|
|
100
|
-
dbPathHint: "Leave empty for the default location under AppData\\Local\\dsh-lost-and-found\\.
|
|
100
|
+
dbPathHint: "Leave empty for the default location under AppData\\Local\\dsh-lost-and-found\\. You can also give a file path such as D:\\file-index\\index.db, or just a folder \u2014 the index.db inside it will be used.",
|
|
101
101
|
freqTitle: "How often to look",
|
|
102
102
|
interval: "Automatic scan interval",
|
|
103
103
|
freqHint: "When you open DSH it checks whether this interval has passed, and catches up if needed.",
|
|
@@ -323,7 +323,10 @@ window.__ModuleLoader__.load({
|
|
|
323
323
|
ctx.effect(() => ctx.locale.register(NS, { zh, en }), "dsh-lost-and-found: dictionaries");
|
|
324
324
|
|
|
325
325
|
const t = ctx.locale.bind(NS);
|
|
326
|
-
|
|
326
|
+
// 0.1.7:`ctx.settingsScope` 已被整个移除,改为 `ctx.configForms.get(条目 id)`。
|
|
327
|
+
// 新 API 与旧 API 同名同义(getSnapshot / subscribe / set / unset / mutate),
|
|
328
|
+
// 快照结构 `{status,value,base,user,revision,writable,mode}` 也没变,所以组件体无需改动。
|
|
329
|
+
const scope = ctx.configForms.get(SETTINGS_NAMESPACE);
|
|
327
330
|
// 客户端远程命名空间挂在 `remote.<namespace>` 服务上(DSH 0.1.5-rc.1 起;
|
|
328
331
|
// 旧的 connection.api.* 已不存在,写它会报 reading 'sessions')。
|
|
329
332
|
// 触发斜杠命令必须走 remote.commands.execute:往会话里塞一条 "/cmd" 文本
|
|
@@ -399,7 +402,7 @@ window.__ModuleLoader__.load({
|
|
|
399
402
|
|
|
400
403
|
module.exports = {
|
|
401
404
|
name: "dsh-lost-and-found",
|
|
402
|
-
inject: ["slots", "locale", "
|
|
405
|
+
inject: ["slots", "locale", "configForms", "remote", "remote.commands", "sessions"],
|
|
403
406
|
apply,
|
|
404
407
|
};
|
|
405
408
|
return module.exports;
|
package/config.mjs
CHANGED
|
@@ -7,9 +7,9 @@
|
|
|
7
7
|
* 会把一份「运行快照」写到 ~/.dsh-lost-and-found/run.json。
|
|
8
8
|
* - 用户数据目录只放运行快照/日志,索引库默认在 %LOCALAPPDATA%\dsh-lost-and-found\。
|
|
9
9
|
*/
|
|
10
|
-
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
10
|
+
import { existsSync, mkdirSync, readFileSync, statSync, writeFileSync } from "node:fs";
|
|
11
11
|
import { homedir } from "node:os";
|
|
12
|
-
import { join } from "node:path";
|
|
12
|
+
import { basename, join } from "node:path";
|
|
13
13
|
|
|
14
14
|
/** 每个扫描目录的内容深度策略 */
|
|
15
15
|
export const POLICY = Object.freeze({
|
|
@@ -120,9 +120,28 @@ export function defaultDbPath() {
|
|
|
120
120
|
return join(base, "dsh-lost-and-found", "index.db");
|
|
121
121
|
}
|
|
122
122
|
|
|
123
|
+
/**
|
|
124
|
+
* 用户填的「记忆库位置」是不是一个**目录**(而不是库文件本身)?
|
|
125
|
+
* 实测坑(v0.1.3):那一格要的是文件路径,但很自然会填成文件夹(如 `D:\findtext`),
|
|
126
|
+
* 而 `new DatabaseSync("D:\findtext")` 会直接抛 `unable to open database file` —— 扫描整个失败。
|
|
127
|
+
*/
|
|
128
|
+
export function isDirDbPath(p) {
|
|
129
|
+
if (/[\\/]$/.test(p)) return true;
|
|
130
|
+
try {
|
|
131
|
+
if (existsSync(p) && statSync(p).isDirectory()) return true;
|
|
132
|
+
} catch { /* 读不到就按文件名处理 */ }
|
|
133
|
+
const base = basename(p);
|
|
134
|
+
return base !== "" && !base.includes(".");
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* 把「记忆库位置」规整成一个**文件**路径:
|
|
139
|
+
* 空 → 默认位置;看着像目录(已存在的目录 / 以分隔符结尾 / 没有扩展名)→ 用该目录下的 index.db。
|
|
140
|
+
*/
|
|
123
141
|
export function resolveDbPath(config) {
|
|
124
142
|
const p = (config && config.dbPath ? String(config.dbPath) : "").trim();
|
|
125
|
-
|
|
143
|
+
if (!p) return defaultDbPath();
|
|
144
|
+
return isDirDbPath(p) ? join(p.replace(/[\\/]+$/, ""), "index.db") : p;
|
|
126
145
|
}
|
|
127
146
|
|
|
128
147
|
/** 规整扫描目录列表:去空、去重、补默认策略 */
|
package/index.mjs
CHANGED
|
@@ -41,20 +41,30 @@ export const inject = ["tools", "commands"];
|
|
|
41
41
|
const SETTINGS_NS = "dsh-lost-and-found";
|
|
42
42
|
const AUTO_CHECK_THROTTLE_MS = 15 * 60 * 1000;
|
|
43
43
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
44
|
+
/**
|
|
45
|
+
* 0.1.7 设置契约:插件用**纯具名导出**的 `Config` 声明可配置项,settings 服务照着它投影出表单。
|
|
46
|
+
* 两条硬要求:
|
|
47
|
+
* ① 不能有 `export default` —— 剥壳后会把 `Config` 一起丢掉,条目被静默过滤;
|
|
48
|
+
* ② 每个可写字段都要标 `.volatile()`(= 「能现场改、改完不用重挂载」),否则 `volatileForm()`
|
|
49
|
+
* 返回 undefined,整个条目被 `describe()` **静默过滤**(面板消失,且不报任何错)。
|
|
50
|
+
* `.volatile()` 需要 schemastery >= 3.18.4;下面降级包装保证在老版本上仍能正常加载。
|
|
51
|
+
*/
|
|
52
|
+
const vol = (schema) => (typeof schema.volatile === "function" ? schema.volatile() : schema);
|
|
53
|
+
|
|
54
|
+
export const Config = z.object({
|
|
55
|
+
enabled: vol(z.boolean().default(true)),
|
|
56
|
+
dbPath: vol(z.string().default("")),
|
|
57
|
+
intervalDays: vol(z.number().min(0).max(365).default(1)),
|
|
58
|
+
firstRunWindowDays: vol(z.number().min(0).max(365).default(7)),
|
|
49
59
|
/** 目录首次扫描收多久:full=全部历史(默认)/ window=最近 N 天 / none=只收今后新增 */
|
|
50
|
-
firstScanMode: z.string().default("full"),
|
|
51
|
-
maxFileMB: z.number().min(0).max(10240).default(50),
|
|
52
|
-
patrolEnabled: z.boolean().default(true),
|
|
53
|
-
imageQuotaPerRun: z.number().min(0).max(500).default(20),
|
|
54
|
-
backupKeep: z.number().min(0).max(60).default(7),
|
|
55
|
-
roots: z.array(z.object({ path: z.string(), policy: z.string().default("full") })).default([]),
|
|
56
|
-
extraExcludeDirs: z.array(z.string()).default([]),
|
|
57
|
-
extraExcludePatterns: z.array(z.string()).default([]),
|
|
60
|
+
firstScanMode: vol(z.string().default("full")),
|
|
61
|
+
maxFileMB: vol(z.number().min(0).max(10240).default(50)),
|
|
62
|
+
patrolEnabled: vol(z.boolean().default(true)),
|
|
63
|
+
imageQuotaPerRun: vol(z.number().min(0).max(500).default(20)),
|
|
64
|
+
backupKeep: vol(z.number().min(0).max(60).default(7)),
|
|
65
|
+
roots: vol(z.array(z.object({ path: z.string(), policy: z.string().default("full") })).default([])),
|
|
66
|
+
extraExcludeDirs: vol(z.array(z.string()).default([])),
|
|
67
|
+
extraExcludePatterns: vol(z.array(z.string()).default([])),
|
|
58
68
|
});
|
|
59
69
|
|
|
60
70
|
function textTool(definition) {
|
|
@@ -105,23 +115,48 @@ export function apply(ctx, input = {}) {
|
|
|
105
115
|
let lastAutoCheck = 0;
|
|
106
116
|
let childRunning = false;
|
|
107
117
|
|
|
108
|
-
// ----------
|
|
109
|
-
|
|
118
|
+
// ---------- 设置读取(0.1.7 契约) ----------
|
|
119
|
+
// 旧写法 `settings.register(ns, schema, {base})` + `scope.get()` + `scope.watch()` 在 0.1.7 已废:
|
|
120
|
+
// settings 服务改为**投影** Loader 里本插件条目的 `Config`(命名空间 = patch 条目的 id,即
|
|
121
|
+
// `SETTINGS_NS`),不再维护独立的值,也不再提供 watch。所以读改走 `describe()`。
|
|
122
|
+
//
|
|
123
|
+
// ⚠️ 0.1.7 实测更正(v0.1.3):面板写入**不会**让宿主重新 apply 本插件 —— 写进去的值只落在
|
|
124
|
+
// profile 的 `cordis.patch.yml` 上,本进程内存里的 `liveConfig` 一直是加载那一刻的旧值。
|
|
125
|
+
// 后果不是「显示没跟上」这种小事,而是功能级故障:面板里刚加的扫描目录,点「立即扫描」会报
|
|
126
|
+
// 「还没设置要扫描的文件夹」;改了库位置也仍然读写旧库。所以下面所有**入口**都先过 `freshConfig()`。
|
|
127
|
+
let settingsService = null;
|
|
128
|
+
|
|
129
|
+
function syncFromSettings() {
|
|
130
|
+
if (!settingsService) return false;
|
|
110
131
|
try {
|
|
111
|
-
const
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
if (!next) return;
|
|
116
|
-
liveConfig = { ...liveConfig, ...next, roots: normalizeRoots(next.roots) };
|
|
117
|
-
});
|
|
132
|
+
const row = settingsService.describe().find((it) => it && it.ns === SETTINGS_NS);
|
|
133
|
+
if (!row || row.value === undefined || row.value === null) return false;
|
|
134
|
+
liveConfig = { ...liveConfig, ...row.value, roots: normalizeRoots(row.value.roots) };
|
|
135
|
+
return true;
|
|
118
136
|
} catch (err) {
|
|
119
|
-
ctx.logger.warn(`dsh-lost-and-found:
|
|
137
|
+
ctx.logger.warn(`dsh-lost-and-found: 读取设置失败(继续用传入配置) - ${err.message}`);
|
|
138
|
+
return false;
|
|
120
139
|
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* 取「当前最新」的配置:每次调用都重读一遍设置投影。
|
|
144
|
+
* 面板改完立刻生效,不需要重启 DSH(`describe()` 读的就是刚写入的权威值,纯内存操作,成本可忽略)。
|
|
145
|
+
* 所有对外入口(工具 / 斜杠命令 / 自动扫描检查)都必须先走这里,不要直接读 `liveConfig` 的闭包快照。
|
|
146
|
+
*/
|
|
147
|
+
function freshConfig() {
|
|
148
|
+
syncFromSettings();
|
|
149
|
+
return liveConfig;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
ctx.inject(["settings"], (settingsCtx) => {
|
|
153
|
+
settingsService = settingsCtx.settings;
|
|
154
|
+
freshConfig();
|
|
121
155
|
});
|
|
122
156
|
|
|
123
157
|
// ---------- 派生扫描子进程 ----------
|
|
124
158
|
async function spawnScan({ trigger = "manual", wait = false, forceFull = false } = {}) {
|
|
159
|
+
freshConfig();
|
|
125
160
|
if (childRunning && wait) throw new Error("已有扫描在进行中");
|
|
126
161
|
if (!liveConfig.enabled) throw new Error("插件已关闭(可在设置页打开)");
|
|
127
162
|
const roots = normalizeRoots(liveConfig.roots);
|
|
@@ -192,6 +227,7 @@ export function apply(ctx, input = {}) {
|
|
|
192
227
|
// ---------- 到期自动扫描:会话一开就检查(用户选了「每天」) ----------
|
|
193
228
|
function maybeAutoScan(reason) {
|
|
194
229
|
try {
|
|
230
|
+
freshConfig();
|
|
195
231
|
if (!liveConfig.enabled) return;
|
|
196
232
|
const days = Number(liveConfig.intervalDays);
|
|
197
233
|
if (!days || days <= 0) return;
|
|
@@ -241,7 +277,7 @@ export function apply(ctx, input = {}) {
|
|
|
241
277
|
fallback: { type: "boolean", description: "索引没命中时是否实时扫描扫描目录兜底,默认 true" },
|
|
242
278
|
},
|
|
243
279
|
async execute(args = {}) {
|
|
244
|
-
const cfg =
|
|
280
|
+
const cfg = freshConfig();
|
|
245
281
|
const roots = normalizeRoots(cfg.roots);
|
|
246
282
|
const opts = {
|
|
247
283
|
keywords: args.keywords,
|
|
@@ -318,7 +354,7 @@ export function apply(ctx, input = {}) {
|
|
|
318
354
|
full: { type: "boolean", description: "强制全量重扫(忽略已有锚点),默认 false" },
|
|
319
355
|
},
|
|
320
356
|
async execute(args = {}) {
|
|
321
|
-
const cfg =
|
|
357
|
+
const cfg = freshConfig();
|
|
322
358
|
if (!normalizeRoots(cfg.roots).length) {
|
|
323
359
|
return "还没设置要扫描的文件夹。请在插件设置页点「一键扫描」或手动添加目录后再试。";
|
|
324
360
|
}
|
|
@@ -351,7 +387,7 @@ export function apply(ctx, input = {}) {
|
|
|
351
387
|
description: "查看「文件快速寻回」的概况:上次扫描时间、库内文件数、扫描目录、待处理项、野文件提示、库位置与错误。",
|
|
352
388
|
parameters: {},
|
|
353
389
|
async execute() {
|
|
354
|
-
const cfg =
|
|
390
|
+
const cfg = freshConfig();
|
|
355
391
|
const dbPath = resolveDbPath(cfg);
|
|
356
392
|
const { db } = openLiveDb(cfg);
|
|
357
393
|
try {
|
|
@@ -429,7 +465,8 @@ export function apply(ctx, input = {}) {
|
|
|
429
465
|
async execute(args = {}) {
|
|
430
466
|
const paths = (args.paths || []).map((x) => (typeof x === "string" ? x : x && x.path)).filter(Boolean);
|
|
431
467
|
if (!paths.length) return "请提供要忘掉的路径";
|
|
432
|
-
const
|
|
468
|
+
const cfg = freshConfig();
|
|
469
|
+
const { db } = openLiveDb(cfg);
|
|
433
470
|
try {
|
|
434
471
|
const n = forgetPaths(db, paths);
|
|
435
472
|
return `已从记忆库删除 ${n} 条记录(用户文件未被改动)。`;
|
|
@@ -445,7 +482,8 @@ export function apply(ctx, input = {}) {
|
|
|
445
482
|
description: "手动检查一批已记录文件是否还在原处(用于清理「已经不在了」的记录)。",
|
|
446
483
|
parameters: { limit: { type: "number", description: "本批检查条数,默认 500" } },
|
|
447
484
|
async execute(args = {}) {
|
|
448
|
-
const
|
|
485
|
+
const cfg = freshConfig();
|
|
486
|
+
const { db } = openLiveDb(cfg);
|
|
449
487
|
try {
|
|
450
488
|
const r = verifyBatch(db, Number(args.limit) || 500);
|
|
451
489
|
return `检查了 ${r.checked} 个文件,其中 ${r.missing} 个已不在原处(连续两次确认后才会标记)。`;
|
|
@@ -462,8 +500,9 @@ export function apply(ctx, input = {}) {
|
|
|
462
500
|
"取出「还没看过内容」的图片清单(供模型用 read_image 逐张看图并写描述)。返回路径+名字+时间。",
|
|
463
501
|
parameters: { limit: { type: "number", description: "本次取几张,默认用配置里的看图配额" } },
|
|
464
502
|
async execute(args = {}) {
|
|
465
|
-
const
|
|
466
|
-
const
|
|
503
|
+
const cfg = freshConfig();
|
|
504
|
+
const limit = Number(args.limit) || Number(cfg.imageQuotaPerRun) || 20;
|
|
505
|
+
const { db } = openLiveDb(cfg);
|
|
467
506
|
try {
|
|
468
507
|
const rows = db.prepare(`
|
|
469
508
|
SELECT path, name, ext, size, appeared_ms, origin FROM files
|
|
@@ -495,7 +534,8 @@ export function apply(ctx, input = {}) {
|
|
|
495
534
|
async execute(args = {}) {
|
|
496
535
|
const p = String(args.path || "").trim();
|
|
497
536
|
if (!p) return "请提供图片路径";
|
|
498
|
-
const
|
|
537
|
+
const cfg = freshConfig();
|
|
538
|
+
const { db } = openLiveDb(cfg);
|
|
499
539
|
try {
|
|
500
540
|
const r = db.prepare("UPDATE files SET image_desc = ?, tags = ?, enrich = 'described', last_seen_ms = ? WHERE path = ?")
|
|
501
541
|
.run(String(args.description || ""), String(args.tags || ""), Date.now(), p);
|
|
@@ -514,7 +554,7 @@ export function apply(ctx, input = {}) {
|
|
|
514
554
|
input: { hint: "扫描一次:新目录首次扫描会回填其历史文件,其余只收新增。", images: false },
|
|
515
555
|
handler: async () => {
|
|
516
556
|
try {
|
|
517
|
-
const roots = normalizeRoots(
|
|
557
|
+
const roots = normalizeRoots(freshConfig().roots);
|
|
518
558
|
if (!roots.length) return { kind: "error", text: "还没设置要扫描的文件夹:请在插件设置页点「一键扫描」或手动添加目录。" };
|
|
519
559
|
const r = await spawnScan({ trigger: "settings", wait: true });
|
|
520
560
|
if (!r.result || r.result.ok === false) {
|
|
@@ -544,7 +584,7 @@ export function apply(ctx, input = {}) {
|
|
|
544
584
|
input: { hint: "查看上次扫描时间、库内文件数、扫描目录。", images: false },
|
|
545
585
|
handler: async () => {
|
|
546
586
|
try {
|
|
547
|
-
const cfg =
|
|
587
|
+
const cfg = freshConfig();
|
|
548
588
|
const dbPath = resolveDbPath(cfg);
|
|
549
589
|
const { db } = openLiveDb(cfg);
|
|
550
590
|
try {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-lost-and-found",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"description": "Local file recall for DeepSeek Harness: it watches the folders you choose and keeps a SQLite index of what appeared — name, type, size, appeared-at, location and origin — so \"where did I put that file?\" becomes a single question. Every folder carries its own incremental anchor, and a folder added later is backfilled in full on its first scan. Search is SQL hard filtering plus multi-keyword hit weighting, with a live fallback scan when the index has no hit. Read-only: it never modifies, moves or deletes your files. 文件快速寻回:定期扫描你指定的文件夹,把新出现的文件(名字/类型/大小/出现时间/位置/来源)记进本地 SQLite 索引,忘了东西放哪问一句就能找回。每个文件夹各有自己的增量锚点,新加入的文件夹第一次会回填全部历史;检索用 SQL 硬过滤加多关键词加权,索引没命中时当场兜底实时扫描一遍。只读,绝不修改、移动或删除你的文件。",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.mjs",
|
|
@@ -27,7 +27,6 @@
|
|
|
27
27
|
"client": {
|
|
28
28
|
"inject": [
|
|
29
29
|
"@deepseek-ai/dsh-client-locale",
|
|
30
|
-
"@deepseek-ai/dsh-client-runtime",
|
|
31
30
|
"@deepseek-ai/dsh-client-ui-settings"
|
|
32
31
|
],
|
|
33
32
|
"platform": "web"
|
|
@@ -48,7 +47,7 @@
|
|
|
48
47
|
},
|
|
49
48
|
"devDependencies": {
|
|
50
49
|
"@deepseek-ai/dsh-tools": "0.1.5-rc.1",
|
|
51
|
-
"@deepseek-ai/schemastery": "^3.18.
|
|
50
|
+
"@deepseek-ai/schemastery": "^3.18.4"
|
|
52
51
|
},
|
|
53
52
|
"engines": {
|
|
54
53
|
"node": "^22.0.0 || >=24"
|