dsh-vibe-math 2.0.11 → 2.0.13

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 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 — THREE agent presets in one install: vibe-math-v2 (probability-driven: qs.json + Propos knowledge base + explorer→solver→review/debate verdict), vibe-math-v3 (THIRD-generation, recommended: paper-style Markdown knowledge base with Problems/Progress/Propos/Methods/Verified + planner-agent scheduling that decides the next N actions + universal theory/method invention library + agents write their own Markdown directly via a per-file write lock), and vibe-math-v4 (FOURTH-generation: persistent self-organizing resident subagents that message & meet to decide all tasks, verify only by unanimous consensus, /compact at a context threshold, and stop only when all agree the problem is solved). Installing this bundle auto-installs all three presets (v1 was removed at v2.0.0).",
4
- "version": "2.0.11",
4
+ "version": "2.0.13",
5
5
  "type": "module",
6
6
  "engines": {
7
7
  "node": "^22.19.0 || >=24.0.0"
@@ -253,7 +253,7 @@ export function apply(ctx) {
253
253
  residents.set(r.rId,r); await saveAll(); logActivity('spawn',r.rId+' ('+(r.direction||'brainstorm')+')')
254
254
  }
255
255
  async function wakeResident(r, promptText, kind){
256
- if(!r.childId) return false
256
+ if(!r || !r.childId) return false // a removed resident must never be woken (rune: crash on r.childId)
257
257
  clearHeartbeat()
258
258
  busy.add(r.rId); wakeKind.set(r.rId,kind||'normal'); currentResident=r.rId
259
259
  r.lastActiveAt=now(); r.rounds+=1; r.roundsSinceCompact+=1
@@ -305,7 +305,7 @@ export function apply(ctx) {
305
305
  async function recordMethod(rId,o){ const id=o.id||('m-'+shortId()); const lines=['# 方法|'+(o.title||id),'- 标题: '+(o.title||id),'- ID: '+id,'- 类型: '+(o.type||'方法'),'- 状态: 经验','- 可信断言: []','- 价值程度: '+cl(o.value!=null?o.value:0.5),'- 动机用途计划: '+(o.motivation||''),'','## 核心内容',String(o.content||''),'','## 定义与记号',String(o.notation||''),'','## 应用记录','## 改进历史','']; await writeText('Methods/'+rId+'/'+id+'.md',lines.join('\n')); logActivity('record',rId+' 方法 '+id); bumpArtifacts(); return {ok:true,id,file:'Methods/'+rId+'/'+id+'.md'} }
306
306
  async function recordSubproblem(rId,o){ const id=o.id||('s-'+shortId()); const lines=['# 子问题|'+(o.title||id),'- 标题: '+(o.title||id),'- ID: '+id,'- 状态: 求解中','- 价值程度: '+cl(o.value!=null?o.value:0.5),'- 动机用途计划: '+(o.motivation||''),'- 依赖: []','','## 陈述',String(o.statement||''),'','## 进度','']; await writeText('Subproblems/'+rId+'/'+id+'.md',lines.join('\n')); logActivity('record',rId+' 子问题 '+id); bumpArtifacts(); return {ok:true,id,file:'Subproblems/'+rId+'/'+id+'.md'} }
307
307
  // auto-sync meeting: every meetingKeepEvery new artifacts, convene a general coordination meeting
308
- function bumpArtifacts(){ artifactCount+=1; markProgress(); if(!meetingState && !verifyState && Number(params.meetingKeepEvery)>0 && artifactCount % Number(params.meetingKeepEvery)===0){ startMeeting('定期同步:分工/进展/是否需要验证','general',null).catch(()=>{}) } }
308
+ function bumpArtifacts(){ artifactCount+=1; markProgress(); if(!meetingState && !verifyState && !pendingMeeting && Number(params.meetingKeepEvery)>0 && artifactCount % Number(params.meetingKeepEvery)===0){ startMeeting('定期同步:分工/进展/是否需要验证','general',null).catch(()=>{}) } }
309
309
  function listResidents(){ return Array.from(residents.values()).map(r=>({id:r.rId,direction:r.direction,status:r.status,rounds:r.rounds,contextPct:r.contextPct,insight:r.insight?r.insight.slice(0,80):''})) }
310
310
  // identify WHICH resident is calling a resident-facing tool: match the caller's
311
311
  // subagent id to a resident's childId. Fall back to the last-woken resident when
@@ -370,7 +370,11 @@ export function apply(ctx) {
370
370
  // A meeting must NOT preempt an active or pending verification (unanimous-consensus is the
371
371
  // group's truth-making step; preempting it would let every round resurface the same conflict).
372
372
  // Wait instead of stealing the floor: park the request and resume it after the verify settles.
373
- if(verifyState || pendingVerify){ pendingMeeting = { agenda, type:type||'general', targetId:targetId||null }; return {ok:true,deferred:true,during:'verify'} }
373
+ if(verifyState || pendingVerify){
374
+ // Keep the FIRST deferred request (never overwrite an earlier one with a later agenda).
375
+ if(!pendingMeeting) pendingMeeting = { agenda, type:type||'general', targetId:targetId||null }
376
+ return {ok:true,deferred:true,during:'verify'}
377
+ }
374
378
  clearHeartbeat()
375
379
  const ids=Array.from(residents.keys())
376
380
  // Rotate the per-meeting speaking order so the SAME resident isn't always the "first speaker
@@ -723,10 +727,19 @@ export function apply(ctx) {
723
727
  // disk and re-seed the resumed run). Same-process pause→resume keeps continuable ids.
724
728
  const crossProcess = persistedEpoch !== processEpoch
725
729
  if(crossProcess){ for(const [,r] of residents){ r.childId=''; r.status='brainstorm'; r.roundsSinceCompact=0 } }
730
+ // ANY re-spawn (cross-process OR a same-process abort that already cleared childIds) must get a FRESH
731
+ // coordination/concurrency state and a brainstorm phase. Otherwise: re-spawned brainstorm residents run
732
+ // under phase='active' (brainstorm summary never written), and a LATE subagent/end from an interrupted
733
+ // OLD resident (same rId) deletes the NEW resident's busy mark → A-fill can wake it mid-brainstorm.
734
+ const needRespawn = Array.from(residents.values()).some(r=>!r.childId)
735
+ if(needRespawn){
736
+ for(const [,r] of residents){ r.childId=''; r.status='brainstorm'; r.insight=''; r.roundsSinceCompact=0 }
737
+ busy=new Set(); wakeKind=new Map(); currentResident=''; pendingMeeting=null; pendingVerify=null; verifyState=null; meetingState=null
738
+ }
726
739
  for(const [,r] of residents){ if(!r.childId){ await spawnResident(r) } }
727
740
  if(!running){ running=true; autoDone=false; if(phase==='idle') phase='active' }
728
- if(crossProcess && phase==='active') phase='brainstorm' // let re-spawned residents re-bootstrap together
729
- logActivity('resume','restarted'+(crossProcess?' (cross-process: re-spawned)':'')); await saveAll(); await scheduleNext(); return {ok:true,message:'resumed',project:currentProject}
741
+ if(needRespawn && phase!=='brainstorm') phase='brainstorm' // let re-spawned residents re-bootstrap together
742
+ logActivity('resume','restarted'+(crossProcess?' (cross-process: re-spawned)':needRespawn?' (re-spawned)':'')); await saveAll(); await scheduleNext(); return {ok:true,message:'resumed',project:currentProject}
730
743
  }
731
744
  function status(){ return { ok:true, running, phase, autoDone, project:currentProject, residentCount:residents.size,
732
745
  residents:listResidents(), busy:[...busy], taskboard:taskboard.length,
@@ -739,7 +752,14 @@ export function apply(ctx) {
739
752
  pendingVerify: pendingVerify?pendingVerify.targetId:null,
740
753
  meetings:meetings.length, recentActivity: activityLog.slice(-8) } }
741
754
  async function addMember(direction){ const r=newResident(direction||''); await spawnResident(r); return {ok:true,id:r.rId,direction:r.direction} }
742
- async function removeMember(id){ const r=residents.get(id); if(!r) return {ok:false}; if(r.childId){ try{ subagents.interrupt(r.childId,{kind:'ancestor',agent:rootAgent}) }catch(e){} } residents.delete(id); busy.delete(id); mailboxes.delete(id); await saveAll(); return {ok:true} }
755
+ async function removeMember(id){ const r=residents.get(id); if(!r) return {ok:false}; if(r.childId){ try{ subagents.interrupt(r.childId,{kind:'ancestor',agent:rootAgent}) }catch(e){} } residents.delete(id); busy.delete(id); mailboxes.delete(id); wakeKind.delete(id)
756
+ // Reconcile in-progress coordination so a removed member cannot hang consensus or crash a round:
757
+ // drop its meeting speech / verify verdict / deferred-meeting / pending-verify if it owned them, and
758
+ // prune it from the meeting's speaking order so the find() there never selects a ghost.
759
+ if(meetingState){ delete meetingState.inputs[id]; meetingState.order=(meetingState.order||[]).filter(x=>x!==id) }
760
+ if(verifyState){ delete verifyState.verdicts[id] }
761
+ if(pendingVerify && pendingVerify.proposer===id) pendingVerify=null
762
+ await saveAll(); return {ok:true} }
743
763
  // Normalize one parameter value to its intended type so a string from /v4 set or configure
744
764
  // becomes the right number/array. Keeps settings.json clean regardless of how it was set.
745
765
  function normalizeParam(k, v){
@@ -367,6 +367,7 @@ VibeMath/Projects/<project>/
367
367
  | **非全票验证不写回平均概率** | `finalizeVerify` 算出 `avg` 只写进辩论录,源卡 `- 概率:` 保持原值,未兑现设计 §8"留库附概率"。 | 新增 `findSourceRel`/`rewriteSourceProb`,非全票时把 `avg` 写回源卡 `- 概率:`(状态仍 `未定论`)。 |
368
368
  | **方法型验证被误标为"命题"** | `writeVerifiedCard` 把方法目标写进 `Verified/命题/` 且类型=命题。 | 按 `targetType` 标 `类型: 方法`(子问题→问题,方法→方法,其余→命题),来源卡标 `已验证·真/假`。 |
369
369
  | **同进程 abort→resume 不重建常驻** | `processEpoch` 进程级,同进程 abort(interrupt 杀掉常驻)后 resume 判非跨进程→保留死 childId;且 `phase=idle && !running` 时 resume 直接拒绝。 | `initAbort` 清空 `childId` 并 `saveAll()`;`resume` 守卫改为 `phase==='idle' && !running && residents.size===0`(有常驻即可 重建)。 |
370
+ | **abort→resume 重种化不彻底(牵连修复)** | 同进程 abort 后 `phase='idle'`、childId 已清空,但旧居民 `status='active'` 且旧 `insight` 仍在;resume 走"非跨进程"分支不清状态,直接 re-spawn 后落入 `phase='active'`——重种化居民在第一轮 brainstorm 期间就被当作 active 处理(brainstorm 汇总不写);且被 interrupt 的**旧**居民迟到的 `subagent/end`(同名 rId)会删除**新**居民的 busy 标记。 | `resume()` 用 `needRespawn`(任一 childId 为空)统一判定:**任何 re-spawn(跨进程或同进程 abort)** 都清空 busy/wakeKind/currentResident/pendingMeeting/pendingVerify/verifyState/meetingState,并把居民 `status='brainstorm'`、`insight=''`、`phase='brainstorm'`——让重种化居民真正重新头脑风暴、汇总正常写出、旧居民的迟到 end 不会污染新居民的 busy。 |
370
371
  | **自动同步会议计数不一致** | `bumpArtifacts` 只在记录方法/子问题时调用,`recordProposition`/`publish_progress` 不计;`artifactCount` 未持久化。 | `recordProposition` 也 `bumpArtifacts()`;`artifactCount` 持久化到 `session.json` 并在 `start()` 时清零。 |
371
372
  | **唤醒信号硬编码 60s** | `spawnResident`/`wakeResident` 用 `makeSignal(60000)`,比 `activityTimeoutMs`(120s) 短。 | 改用 `makeSignal(params.activityTimeoutMs||60000)`。 |
372
373
  | **`verdictMaxRounds`/`meetingKeepEvery` 不可调/不展示** | `verdictMaxRounds` 不在 `vibe_v4_set` schema;两者都不在 `status()` 参数串。 | `vibe_v4_set` 增加 `verdictMaxRounds`;`status()` 参数串补 `meetingKeepEvery` 与 `verdictMaxRounds`。 |
@@ -553,7 +554,8 @@ VibeMath/Projects/<project>/
553
554
  - 分级保活 B 增加 `busy.size===0` 守卫:任何常驻正在工作时不触发,避免预抢占在途轮次。
554
555
 
555
556
  ### 会议与验证互斥(不抢占)
556
- - 并行填充常驻后,一个常驻可能"提议验证(propose_verify)"而另一个同时"提议开会(propose_meeting)"。**会议不得抢占验证**:`startMeeting` 在 `verifyState || pendingVerify` 时改为把会议请求**暂存**(`pendingMeeting`,仅记录 agenda/type/target)并返回 `{deferred:true}`;`scheduleNext` 在所有 meeting/verify/pending 都清空后才恢复该暂存会议。这样统一共识验证(全真/全假)作为"求真"环节不会被会议的协调讨论打断,验证做完后再开会开会协调下一步——两者互斥但都不丢失(暂存会议之后补开)。
557
+ - 并行填充常驻后,一个常驻可能"提议验证(propose_verify)"而另一个同时"提议开会(propose_meeting)"。**会议不得抢占验证**:`startMeeting` 在 `verifyState || pendingVerify` 时改为把会议请求**暂存**(`pendingMeeting`,仅记录 agenda/type/target)并返回 `{deferred:true}`;`scheduleNext` 在所有 meeting/verify/pending 都清空后才恢复该暂存会议。这样统一共识验证(全真/全假)作为"求真"环节不会被会议的协调讨论打断,验证做完后再开会开会协调下一步——两者互斥但都不丢失(暂存会议之后补开)。**暂存只保留第一条**(`!pendingMeeting` 才写入),避免后到的请求覆盖先到的。
558
+ - **进行中增删常驻的一致性**:在会议/验证进行中 `removeMember` 会**同步清理**该常驻的会议发言(`delete meetingState.inputs[id]`)、验证投票(`delete verifyState.verdicts[id]`)、若它是待验证的提出者则清 `pendingVerify`,并从会议发言顺序 `st.order` 里剔除它;`wakeResident` 对已经不存在的常驻**防御性返回 false**(不再因 `r.childId` 抛 TypeError)。这样移除一个常驻不会让共识**卡在幽灵身上**,也不会让会议/验证循环去唤醒一个已删除的常驻而导致崩溃。
557
559
 
558
560
  > 效果:一个卡死/坏掉的会议或验证最多阻塞 `activityTimeoutMs`×2 后自动释放,团队重新回到 A/B 分级保活,**不会永久停死**。仍符合"框架只促成、从不指派任务"(放弃只是终止一个无法推进的会议,把控制权交还团队的自组织循环)。
559
561
  >