dsh-vibe-math 0.3.4 → 0.3.5

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 (3) hide show
  1. package/README.md +2 -1
  2. package/installer.js +127 -29
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -43,6 +43,7 @@ dsh plugin --profile <你的 profile> add github:ChongCyrus/Vibe-Mathematics
43
43
 
44
44
  安装时插件会自动把两个 preset 写入 `~/.dsh/.agent-presets/`:`vibe-math-v1/` 与 `vibe-math-v2/`。
45
45
  之后新建会话,预设选择器里选择 **Vibe Math**(v1)或 **Vibe Math V2**(v2)即可。
46
+ **升级包版本后重启 DSH,未手动改过的 preset 文件会自动更新到新版本**(细节见文末「v2」安装器说明)。
46
47
 
47
48
  ### 方式 B:作为 agent preset 手动安装
48
49
 
@@ -456,7 +457,7 @@ flowchart TB
456
457
  - manual 模式在第一个未决关键节点暂停整条主循环。
457
458
 
458
459
  **v2**:
459
- - 安装器只**补装缺失**的 preset 文件,不覆盖你已编辑的预设(删除对应目录即可重新安装)。
460
+ - 安装器带**版本化自动更新**:每次 DSH 启动时对比包版本与 `<presetRoot>/.vibe-math-installed.json` 记录——版本升级会自动替换**未被手动修改**的 preset 文件(哈希一致才覆盖);你改过的文件会被保留并在日志中提示。无记录的老安装首次会一次性刷新到当前版本。想强制全量重装:删除 `~/.dsh/.agent-presets/vibe-math-v1` 与 `vibe-math-v2` 目录后重启 DSH。
460
461
  - `flat` 裁决在辩论不一致时直接判 `0.5`;`forced` 按历史准确率+置信度加权。
461
462
  - `never` 优先级的问题/命题**永不调度**,且不阻塞严格终止(视为主动弃权)。
462
463
  - 两个 preset 文件互相独立、可共存;同一会话同时只能选一个预设。
package/installer.js CHANGED
@@ -1,51 +1,149 @@
1
- // dsh-vibe-math merged bundle installer.
1
+ // dsh-vibe-math merged bundle installer — VERSIONED AUTO-UPDATE.
2
2
  // When this bundle is installed (e.g. `dsh plugin add dsh-vibe-math` or from the
3
3
  // dsh-market), this plugin copies BOTH agent presets out of the package into the
4
4
  // DSH preset root, so the user immediately gets two presets in the picker:
5
5
  // vibe-math-v1/ (classic pipeline architecture)
6
6
  // vibe-math-v2/ (new probability-driven architecture)
7
- // Copy is per-file and only installs MISSING files (idempotent; never clobbers
8
- // a preset the user already edited — delete the dir to force a reinstall).
9
- import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'
7
+ //
8
+ // UPDATE POLICY (state recorded in <presetRoot>/.vibe-math-installed.json):
9
+ // - baseline (no state file e.g. upgrading from an installer that predates
10
+ // this mechanism): every existing owned file is refreshed to the current
11
+ // package version and recorded as package-owned (user policy: auto-update
12
+ // old installs; any manual edits made before this baseline are overwritten
13
+ // once — from then on edits are protected).
14
+ // - upgrade (recorded version != current package.json version): every owned
15
+ // file that is byte-identical to the previously installed copy (i.e. NOT
16
+ // user-edited since) is overwritten with the new version; user-edited files
17
+ // are preserved and reported via the logger.
18
+ // - same version: no-op (idempotent). Missing files are ALWAYS restored.
19
+ // - force a full refresh at any time: delete the preset dirs and restart DSH.
20
+ import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from 'node:fs'
21
+ import { createHash } from 'node:crypto'
10
22
  import { homedir } from 'node:os'
11
23
  import { dirname, join } from 'node:path'
12
24
  import { fileURLToPath } from 'node:url'
13
25
 
14
26
  export const name = 'vibe-math-preset-installer'
15
27
 
28
+ const PRESETS = [
29
+ {
30
+ src: 'vibe-math-v1',
31
+ dst: 'vibe-math-v1',
32
+ files: ['agent.cordis.yml', 'preset.yml', 'vibe-math.js', '实现方案-多代理数学问题求解与验证框架.md'],
33
+ },
34
+ {
35
+ src: 'vibe-math-v2',
36
+ dst: 'vibe-math-v2',
37
+ files: ['agent.cordis.yml', 'preset.yml', 'vibe-math-v2.js', '实现方案.md'],
38
+ },
39
+ ]
40
+
41
+ const STATE_FILE = '.vibe-math-installed.json'
42
+
43
+ function sha256(buf) { return createHash('sha256').update(buf).digest('hex') }
44
+
45
+ function readState(path) {
46
+ try {
47
+ const raw = readFileSync(path, 'utf8')
48
+ const obj = JSON.parse(raw)
49
+ if (obj && typeof obj === 'object' && obj.files && typeof obj.files === 'object') return obj
50
+ } catch (e) { /* missing or corrupt — treat as no state (baseline) */ }
51
+ return null
52
+ }
53
+
54
+ function writeState(path, state) {
55
+ try {
56
+ const tmp = path + '.tmp'
57
+ writeFileSync(tmp, JSON.stringify(state, null, 2) + '\n', 'utf8')
58
+ renameSync(tmp, path)
59
+ } catch (e) {
60
+ // best-effort: state persistence failure must not break the copy step
61
+ }
62
+ }
63
+
16
64
  export function apply(ctx) {
17
65
  const logger = ctx && ctx.logger
18
66
  try {
19
67
  const dshHome = process.env.DSH_HOME || join(homedir(), '.dsh')
20
68
  const here = dirname(fileURLToPath(import.meta.url))
21
- const targets = [
22
- {
23
- src: join(here, 'vibe-math-v1'),
24
- dst: join(dshHome, '.agent-presets', 'vibe-math-v1'),
25
- files: ['agent.cordis.yml', 'preset.yml', 'vibe-math.js', '实现方案-多代理数学问题求解与验证框架.md'],
26
- },
27
- {
28
- src: join(here, 'vibe-math-v2'),
29
- dst: join(dshHome, '.agent-presets', 'vibe-math-v2'),
30
- files: ['agent.cordis.yml', 'preset.yml', 'vibe-math-v2.js', '实现方案.md'],
31
- },
32
- ]
33
- let installed = 0
34
- for (const t of targets) {
35
- if (!existsSync(t.src)) continue
36
- mkdirSync(t.dst, { recursive: true })
37
- for (const f of t.files) {
38
- const s = join(t.src, f)
39
- const d = join(t.dst, f)
40
- if (!existsSync(s) || existsSync(d)) continue
41
- writeFileSync(d, readFileSync(s))
42
- installed += 1
69
+ const presetRoot = join(dshHome, '.agent-presets')
70
+ const stateFile = join(presetRoot, STATE_FILE)
71
+
72
+ // current package version (the source of truth for "is this an upgrade?")
73
+ let pkgVersion = ''
74
+ try { pkgVersion = String((JSON.parse(readFileSync(join(here, 'package.json'), 'utf8')).version) || '') } catch (e) { pkgVersion = '' }
75
+
76
+ const state = readState(stateFile)
77
+ const prevFiles = (state && state.files) || {}
78
+ const isUpgrade = state !== null && pkgVersion !== '' && state.version !== pkgVersion
79
+ const isBaseline = state === null // no recorded history → refresh everything (user policy: auto-update old installs)
80
+
81
+ const nextFiles = {}
82
+ let installed = 0, updated = 0, kept = 0
83
+ const keptList = []
84
+
85
+ for (const p of PRESETS) {
86
+ const srcDir = join(here, p.src)
87
+ const dstDir = join(presetRoot, p.dst)
88
+ if (!existsSync(srcDir)) continue
89
+ mkdirSync(dstDir, { recursive: true })
90
+ for (const f of p.files) {
91
+ const s = join(srcDir, f)
92
+ const d = join(dstDir, f)
93
+ if (!existsSync(s)) continue
94
+ const key = p.src + '/' + f
95
+ const cur = readFileSync(s)
96
+ const curHash = sha256(cur)
97
+ if (!existsSync(d)) {
98
+ // missing file: always restore, whatever the version
99
+ writeFileSync(d, cur)
100
+ installed += 1
101
+ nextFiles[key] = { hash: curHash, provenance: 'package' }
102
+ continue
103
+ }
104
+ const destHash = sha256(readFileSync(d))
105
+ if (isBaseline) {
106
+ // no recorded history: refresh to the current package (one-time; edits
107
+ // made before this mechanism are overwritten, later edits are protected)
108
+ if (destHash === curHash) { nextFiles[key] = { hash: curHash, provenance: 'package' } }
109
+ else { writeFileSync(d, cur); updated += 1; nextFiles[key] = { hash: curHash, provenance: 'package' } }
110
+ continue
111
+ }
112
+ const prev = prevFiles[key]
113
+ const prevRec = (prev && typeof prev === 'object') ? prev : { hash: prev, provenance: 'package' }
114
+ const prevProv = (prevRec.provenance === 'user') ? 'user' : 'package' // 未知来源按包文件处理
115
+ if (prevProv === 'package' && destHash === prevRec.hash) {
116
+ // 包文件且未被改动 → 可安全升级(内容相同则跳过写入)
117
+ if (destHash !== curHash) { writeFileSync(d, cur); updated += 1 }
118
+ nextFiles[key] = { hash: curHash, provenance: 'package' }
119
+ } else if (prevProv === 'user') {
120
+ // 用户持有 → 永不覆盖
121
+ kept += 1
122
+ if (isUpgrade) keptList.push(key + ' (用户持有)')
123
+ nextFiles[key] = { hash: destHash, provenance: 'user' }
124
+ } else {
125
+ // 包文件但自上次安装后已被用户改动
126
+ kept += 1
127
+ if (isUpgrade) keptList.push(key + ' (已修改)')
128
+ nextFiles[key] = { hash: destHash, provenance: 'user' }
129
+ }
43
130
  }
44
131
  }
45
- if (installed > 0) {
46
- logger?.info?.('[dsh-vibe-math] installed ' + installed + ' preset file(s) — presets vibe-math-v1 & vibe-math-v2 are now available in the preset picker (new session)')
132
+
133
+ writeState(stateFile, { version: pkgVersion, files: nextFiles, updatedAt: Date.now() })
134
+
135
+ if (isUpgrade) {
136
+ logger?.info?.('[dsh-vibe-math] preset auto-update: version ' + (state.version || '(none)') + ' → ' + pkgVersion +
137
+ ' — 新增 ' + installed + ' 个文件,更新 ' + updated + ' 个文件' +
138
+ (kept > 0 ? ',保留 ' + kept + ' 个未覆盖文件(' + keptList.join('; ') + ')' : '') +
139
+ '。新版本 preset 将在新会话生效。')
140
+ } else if (isBaseline) {
141
+ logger?.info?.('[dsh-vibe-math] preset baseline: refreshed ' + (installed + updated) + ' file(s) to v' + pkgVersion +
142
+ ' — 已启用自动更新(后续版本升级将自动替换未被手动修改的 preset 文件)。')
143
+ } else if (installed > 0) {
144
+ logger?.info?.('[dsh-vibe-math] restored ' + installed + ' missing preset file(s)')
47
145
  }
48
146
  } catch (err) {
49
- logger?.warn?.('[dsh-vibe-math] preset install failed: %s', String((err && err.message) || err))
147
+ logger?.warn?.('[dsh-vibe-math] preset install/update failed: %s', String((err && err.message) || err))
50
148
  }
51
149
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "dsh-vibe-math",
3
3
  "description": "Multi-agent mathematical problem-solving & verification frameworks for DeepSeek Harness — TWO agent presets in one install: vibe-math-v1 (classic pipeline: brainstorm → solver iteration → multi-verifier debate → Verified) and vibe-math-v2 (new probability-driven architecture: qs.json + Propos knowledge base + explorer→solver→review/debate verdict). Installing this bundle auto-installs both presets into the DSH preset root.",
4
- "version": "0.3.4",
4
+ "version": "0.3.5",
5
5
  "type": "module",
6
6
  "main": "installer.js",
7
7
  "exports": {