dsh-memory-eternal 0.6.1 → 0.6.2-rc.1
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/index.js +60 -1
- package/lib/api.js +23 -2
- package/lib/client.js +5 -5
- package/package.json +1 -1
- package/web/app.js +10 -10
package/index.js
CHANGED
|
@@ -277,7 +277,18 @@ export function apply(ctx, config) {
|
|
|
277
277
|
|
|
278
278
|
const webServer = ctx.get('webServer')
|
|
279
279
|
if (webServer !== undefined) {
|
|
280
|
-
const handleApi = createApi({
|
|
280
|
+
const handleApi = createApi({
|
|
281
|
+
vaultDir, vaultRoots, getSettings: settings.get,
|
|
282
|
+
getDshInfo: () => ({
|
|
283
|
+
name: 'dsh',
|
|
284
|
+
label: 'DSH (当前宿主)',
|
|
285
|
+
installed: true,
|
|
286
|
+
memoryRecallTool: !!ctx.get('tools'),
|
|
287
|
+
autoCapture: (settings.get() ?? {}).autoCapture !== false,
|
|
288
|
+
autoRecall: (settings.get() ?? {}).autoRecall !== false,
|
|
289
|
+
vaultDir: vaultDir(),
|
|
290
|
+
}),
|
|
291
|
+
})
|
|
281
292
|
webServer.register({
|
|
282
293
|
kind: 'prefix',
|
|
283
294
|
path: API_PREFIX,
|
|
@@ -287,6 +298,54 @@ export function apply(ctx, config) {
|
|
|
287
298
|
if (pathname === API_PREFIX + '/web-info') {
|
|
288
299
|
return json(res, 200, { ok: true, ...webInfo })
|
|
289
300
|
}
|
|
301
|
+
if (pathname === API_PREFIX + '/config') {
|
|
302
|
+
const method = req.method || 'GET'
|
|
303
|
+
if (method === 'GET') {
|
|
304
|
+
const cfg = settings.get() ?? {}
|
|
305
|
+
// 只暴露可安全展示/回填的字段
|
|
306
|
+
const safe = {
|
|
307
|
+
autoCapture: cfg.autoCapture, autoRecall: cfg.autoRecall, recallLimit: cfg.recallLimit, recallSummaryLen: cfg.recallSummaryLen, recallIncludeBody: cfg.recallIncludeBody,
|
|
308
|
+
captureMinChars: cfg.captureMinChars, captureCooldownMs: cfg.captureCooldownMs, dedupThreshold: cfg.dedupThreshold, maxCardsPerDay: cfg.maxCardsPerDay,
|
|
309
|
+
autoWeb: cfg.autoWeb, autoWebMode: cfg.autoWebMode, webPort: cfg.webPort, webCheckIntervalMs: cfg.webCheckIntervalMs, webMaxRestart: cfg.webMaxRestart, watchdogAutoSpawn: cfg.watchdogAutoSpawn, autoMcpSetup: cfg.autoMcpSetup,
|
|
310
|
+
}
|
|
311
|
+
const descriptor = (ctx.get('settings') ?? {}).describe?.({ redactSecrets: true }) ?? []
|
|
312
|
+
const me = descriptor.find((d) => d.ns === 'memory-eternal')
|
|
313
|
+
const dshInfo = {
|
|
314
|
+
name: 'dsh',
|
|
315
|
+
label: 'DSH (当前宿主)',
|
|
316
|
+
installed: true,
|
|
317
|
+
memoryRecallTool: !!ctx.get('tools'),
|
|
318
|
+
autoCapture: cfg.autoCapture !== false,
|
|
319
|
+
autoRecall: cfg.autoRecall !== false,
|
|
320
|
+
vaultDir: vaultDir(),
|
|
321
|
+
}
|
|
322
|
+
return json(res, 200, { ok: true, config: safe, revision: me?.revision ?? 0, schema: me?.schema ?? null, dsh: dshInfo })
|
|
323
|
+
}
|
|
324
|
+
if (method === 'POST') {
|
|
325
|
+
let raw = ''
|
|
326
|
+
for await (const chunk of req) raw += chunk
|
|
327
|
+
let body = {}
|
|
328
|
+
try { body = JSON.parse(raw || '{}') } catch { return json(res, 400, { ok: false, error: 'JSON 解析失败' }) }
|
|
329
|
+
const patch = body.patch ?? {}
|
|
330
|
+
const expectedRevision = Number.isInteger(body.expectedRevision) ? body.expectedRevision : undefined
|
|
331
|
+
// 仅允许写入 Config 中声明过的键(白名单,防注入)。schemastery 用 .dict 存 object schema 字段表。
|
|
332
|
+
const allowed = new Set(Object.keys(Config.dict || {}))
|
|
333
|
+
const clean = {}
|
|
334
|
+
for (const k of Object.keys(patch)) { if (allowed.has(k)) clean[k] = patch[k] }
|
|
335
|
+
if (Object.keys(clean).length === 0) return json(res, 400, { ok: false, error: '无可写入字段' })
|
|
336
|
+
if (typeof settings.update === 'function') {
|
|
337
|
+
try {
|
|
338
|
+
await settings.update(clean)
|
|
339
|
+
return json(res, 200, { ok: true, applied: Object.keys(clean), note: '已保存。autoWebMode/watchdogAutoSpawn 等需重启 DSH 生效' })
|
|
340
|
+
} catch (e) {
|
|
341
|
+
if (e && e.code === 'SETTINGS_CONFLICT') return json(res, 409, { ok: false, error: '配置已被外部修改,请刷新后重试(revision conflict)' })
|
|
342
|
+
return json(res, 500, { ok: false, error: String(e?.message || e) })
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
return json(res, 501, { ok: false, error: '当前环境不支持写配置' })
|
|
346
|
+
}
|
|
347
|
+
return json(res, 405, { ok: false, error: 'method not allowed' })
|
|
348
|
+
}
|
|
290
349
|
await handleApi(req, res)
|
|
291
350
|
} catch (error) {
|
|
292
351
|
json(res, 500, { ok: false, error: String(error?.message || error) })
|
package/lib/api.js
CHANGED
|
@@ -20,6 +20,8 @@ export function createApi(deps = {}) {
|
|
|
20
20
|
const vaultDir = deps.vaultDir ?? (() => '')
|
|
21
21
|
const vaultRoots = deps.vaultRoots ?? (() => [{ name: '', root: vaultDir() }])
|
|
22
22
|
const getSettings = deps.getSettings ?? (() => ({}))
|
|
23
|
+
// DSH 宿主信息(独立 web server 无 DSH 环境时为 null)。head DSH 状态行用。
|
|
24
|
+
const getDshInfo = deps.getDshInfo ?? (() => null)
|
|
23
25
|
|
|
24
26
|
return async function handleApi(req, res) {
|
|
25
27
|
const vaultRoot = vaultDir()
|
|
@@ -154,6 +156,11 @@ export function createApi(deps = {}) {
|
|
|
154
156
|
case '/setup-status': {
|
|
155
157
|
// 只读查询各 agent MCP 配置状态,不写任何文件
|
|
156
158
|
const status = await getSetupStatus()
|
|
159
|
+
// prepend DSH 宿主行(独立 web server 无 DSH 环境时只有外部 agent)
|
|
160
|
+
const dsh = getDshInfo ? getDshInfo() : null
|
|
161
|
+
if (dsh) {
|
|
162
|
+
status.agents = [{ name: 'dsh', label: dsh.label || 'DSH (当前宿主)', installed: true, mcpConfigured: true, isDsh: true, recallTool: dsh.memoryRecallTool, autoCapture: dsh.autoCapture, autoRecall: dsh.autoRecall, vaultDir: dsh.vaultDir }, ...(status.agents || [])]
|
|
163
|
+
}
|
|
157
164
|
json(res, 200, status)
|
|
158
165
|
return
|
|
159
166
|
}
|
|
@@ -170,10 +177,24 @@ export function createApi(deps = {}) {
|
|
|
170
177
|
case '/budget': {
|
|
171
178
|
try {
|
|
172
179
|
const cfg = getSettings() ?? {}
|
|
173
|
-
|
|
180
|
+
const env = typeof process !== 'undefined' ? process.env : {}
|
|
181
|
+
json(res, 200, {
|
|
182
|
+
ok: true,
|
|
183
|
+
budgetChars: cfg.sessionBudgetChars ?? 80000,
|
|
184
|
+
recallLimit: cfg.recallLimit ?? 5,
|
|
185
|
+
embedding: cfg.recallEmbedding || '',
|
|
186
|
+
// 服务自管理配置(DSH host 从 settings 读;独立 web server 从 env 兜底)
|
|
187
|
+
autoWeb: cfg.autoWeb ?? env.MEMORY_AUTO_WEB !== '0',
|
|
188
|
+
autoWebMode: cfg.autoWebMode || 'init',
|
|
189
|
+
webPort: Number(cfg.webPort) || Number(env.MEMORY_WEB_PORT) || 7999,
|
|
190
|
+
webCheckIntervalMs: Number(cfg.webCheckIntervalMs) || 5000,
|
|
191
|
+
webMaxRestart: Number(cfg.webMaxRestart) || 10,
|
|
192
|
+
watchdogAutoSpawn: cfg.watchdogAutoSpawn ?? env.MEMORY_WATCHDOG === '1',
|
|
193
|
+
autoMcpSetup: cfg.autoMcpSetup ?? false,
|
|
194
|
+
})
|
|
174
195
|
} catch (e) {
|
|
175
196
|
// 配置读取异常时降级返回默认值,避免面板整块红屏
|
|
176
|
-
json(res, 200, { ok: true, budgetChars: 80000, recallLimit: 5, embedding: '' })
|
|
197
|
+
json(res, 200, { ok: true, budgetChars: 80000, recallLimit: 5, embedding: '', autoWeb: true, autoWebMode: 'init', webPort: 7999, webCheckIntervalMs: 5000, webMaxRestart: 10, watchdogAutoSpawn: true, autoMcpSetup: false })
|
|
177
198
|
}
|
|
178
199
|
return
|
|
179
200
|
}
|