@kenz1117/dsh-engram 0.2.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/package.json ADDED
@@ -0,0 +1,68 @@
1
+ {
2
+ "name": "@kenz1117/dsh-engram",
3
+ "description": "Cross-session long-term memory for DeepSeek Harness: dual-scope SQLite memory graph, hybrid retrieval, provenance audit, and a knowledge flywheel.",
4
+ "version": "0.2.0",
5
+ "publishConfig": {
6
+ "access": "public"
7
+ },
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/kenz1117/dsh-engram.git"
11
+ },
12
+ "type": "module",
13
+ "main": "./lib/index.mjs",
14
+ "types": "./lib/index.d.mts",
15
+ "exports": {
16
+ ".": {
17
+ "types": "./lib/index.d.mts",
18
+ "default": "./lib/index.mjs"
19
+ },
20
+ "./src/*": "./src/*",
21
+ "./package.json": "./package.json"
22
+ },
23
+ "files": [
24
+ "lib/",
25
+ "scripts/",
26
+ "cordis.patch.yml"
27
+ ],
28
+ "dsh": {
29
+ "bundle": {
30
+ "patch": "./cordis.patch.yml"
31
+ }
32
+ },
33
+ "scripts": {
34
+ "postinstall": "node scripts/link-peers.mjs",
35
+ "bundle": "tsdown",
36
+ "watch": "tsdown --watch",
37
+ "test": "vitest run",
38
+ "typecheck": "tsc --noEmit",
39
+ "backfill": "node scripts/backfill-embeddings.mjs"
40
+ },
41
+ "license": "MIT",
42
+ "engines": {
43
+ "node": "^22.19.0 || >=24.0.0"
44
+ },
45
+ "peerDependencies": {
46
+ "@deepseek-ai/cordis": "*",
47
+ "@deepseek-ai/dsh-agent": "*",
48
+ "@deepseek-ai/dsh-llm": "*",
49
+ "@deepseek-ai/dsh-tools": "*",
50
+ "@deepseek-ai/schemastery": "*"
51
+ },
52
+ "dependencies": {
53
+ "@huggingface/transformers": "^4.2.0"
54
+ },
55
+ "devDependencies": {
56
+ "@types/node": "^26.4.0",
57
+ "tsdown": "^0.22.14",
58
+ "typescript": "^5.9.3",
59
+ "vitest": "^4.1.11"
60
+ },
61
+ "pnpm": {
62
+ "onlyBuiltDependencies": [
63
+ "onnxruntime-node",
64
+ "sharp",
65
+ "protobufjs"
66
+ ]
67
+ }
68
+ }
@@ -0,0 +1,63 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * 嵌入回填:给已有但缺向量的记忆补算 embedding。
4
+ * 场景:嵌入器曾降级(模型未就绪)时摄取/保存的记忆没有向量,
5
+ * 语义检索上线后运行本脚本一次,让存量记忆参与向量道。
6
+ *
7
+ * 用法:node scripts/backfill-embeddings.mjs [dbDir]
8
+ * 默认 dbDir = ~/.dsh/engram;只处理 active 且 embedding IS NULL 的条目。
9
+ */
10
+
11
+ import { DatabaseSync } from 'node:sqlite'
12
+ import { join } from 'node:path'
13
+ import { homedir } from 'node:os'
14
+ import { pipeline, env } from '@huggingface/transformers'
15
+
16
+ const dbDir = process.argv[2] ?? join(homedir(), '.dsh', 'engram')
17
+ const modelCacheDir = join(dbDir, 'models')
18
+ const MODEL_ID = 'Xenova/bge-small-zh-v1.5'
19
+
20
+ const dbs = ['user.db', 'project-db'].map(name => join(dbDir, name)).filter(p => {
21
+ try { return new DatabaseSync(p, { readOnly: true }) && true } catch { return false }
22
+ })
23
+ if (dbs.length === 0) {
24
+ console.log('[backfill] 未找到任何记忆分库,无需回填')
25
+ process.exit(0)
26
+ }
27
+
28
+ env.cacheDir = modelCacheDir
29
+ // 下载端点可经 HF_ENDPOINT 覆盖(镜像);模型已在缓存时不会访问网络。
30
+ if (process.env.HF_ENDPOINT) env.remoteHost = process.env.HF_ENDPOINT
31
+ const extractor = await pipeline('feature-extraction', MODEL_ID, { dtype: 'q8' })
32
+ const embed = async text => {
33
+ const output = await extractor([text], { pooling: 'mean', normalize: true })
34
+ return new Float32Array(output.tolist()[0])
35
+ }
36
+
37
+ let patched = 0
38
+ for (const path of dbs) {
39
+ const db = new DatabaseSync(path)
40
+ const rows = db.prepare("SELECT id, content FROM nodes WHERE status = 'active' AND embedding IS NULL").all()
41
+ if (rows.length === 0) {
42
+ console.log(`[backfill] ${path}: 无缺向量条目`)
43
+ db.close()
44
+ continue
45
+ }
46
+ db.exec('BEGIN')
47
+ try {
48
+ for (const row of rows) {
49
+ const vector = await embed(row.content)
50
+ db.prepare('UPDATE nodes SET embedding = ? WHERE id = ?')
51
+ .run(new Uint8Array(vector.buffer, vector.byteOffset, vector.byteLength), row.id)
52
+ patched += 1
53
+ console.log(`[backfill] ${path}: ${row.content.slice(0, 24)}… ✓`)
54
+ }
55
+ db.exec('COMMIT')
56
+ } catch (error) {
57
+ db.exec('ROLLBACK')
58
+ db.close()
59
+ throw error
60
+ }
61
+ db.close()
62
+ }
63
+ console.log(`[backfill] 完成:共补算 ${patched} 条向量`)
@@ -0,0 +1,57 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * 把本插件的 @deepseek-ai/* peer 依赖从 deepseek-harness 工作区 symlink 进 node_modules。
4
+ *
5
+ * 为什么不用 file:/npm 安装:harness 内部包的 dependencies 使用 workspace:^ 协议,
6
+ * 脱离其工作区无法经 pnpm 解析;npm 上的 @deepseek-ai 依赖链也不完整(dsh-type-meta 未发布)。
7
+ * symlink 后,被链接包内部对其他 @deepseek-ai/* 的 import 会沿真实路径(harness 树内)
8
+ * 向上解析到 harness 自己的 workspace node_modules,传递链自动闭合。
9
+ *
10
+ * 前置:deepseek-harness 已执行 pnpm install && pnpm run build(存在 lib/ 产物)。
11
+ * 幂等:已存在的链接跳过。发布形态下这些包是 peerDependencies,由 dsh profile 提供。
12
+ */
13
+
14
+ import { existsSync, mkdirSync, readdirSync, readFileSync, symlinkSync, statSync } from 'node:fs'
15
+ import { dirname, join, resolve } from 'node:path'
16
+ import { fileURLToPath } from 'node:url'
17
+
18
+ const repoRoot = resolve(dirname(fileURLToPath(import.meta.url)), '..')
19
+ const harnessRoot = resolve(repoRoot, '..', 'deepseek-harness')
20
+
21
+ /** 直接 import 的包:类型与运行时的真实入口;其传递依赖由 harness 树内解析闭合。 */
22
+ const LINKED_PACKAGES = [
23
+ ['@deepseek-ai/cordis', 'vendor/cordis'],
24
+ ['@deepseek-ai/cosmokit', 'vendor/cosmokit'],
25
+ ['@deepseek-ai/schemastery', 'vendor/schemastery'],
26
+ ['@deepseek-ai/cordis-plugin-loader', 'vendor/loader'],
27
+ ['@deepseek-ai/cordis-plugin-include', 'vendor/include'],
28
+ ['@deepseek-ai/dsh-tools', 'packages/core/tools'],
29
+ ['@deepseek-ai/dsh-system-prompt', 'packages/core/system-prompt'],
30
+ ['@deepseek-ai/dsh-session', 'packages/core/session'],
31
+ ['@deepseek-ai/dsh-llm', 'packages/llm/llm'],
32
+ ['@deepseek-ai/dsh-agent', 'packages/core/agent'],
33
+ ['@deepseek-ai/dsh-scope', 'packages/core/scope'],
34
+ ['@deepseek-ai/dsh-util-values', 'packages/util/values'],
35
+ ['@deepseek-ai/dsh-brand', 'packages/util/brand'],
36
+ ['@deepseek-ai/dsh-invariants', 'packages/runtime-diagnostics/invariants'],
37
+ ]
38
+
39
+ const scopeDir = join(repoRoot, 'node_modules', '@deepseek-ai')
40
+ mkdirSync(scopeDir, { recursive: true })
41
+
42
+ let created = 0
43
+ let skipped = 0
44
+ for (const [name, rel] of LINKED_PACKAGES) {
45
+ const target = join(harnessRoot, rel)
46
+ const link = join(scopeDir, name.split('/')[1])
47
+ if (existsSync(link)) continue
48
+ // 温和跳过:发布形态或 profile 安装环境没有 harness 源码树,peer 由
49
+ // profile 的 node_modules 提供;链接缺失绝不使安装失败。
50
+ if (!existsSync(target)) {
51
+ skipped += 1
52
+ continue
53
+ }
54
+ symlinkSync(target, link, 'dir')
55
+ created += 1
56
+ }
57
+ console.log(`[link-peers] ok(新建 ${created} 个链接,跳过 ${skipped} 个无源码环境的 peer,共 ${LINKED_PACKAGES.length} 个)`)