dsh-vibe-math 1.3.0 → 1.3.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/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 — FOUR agent presets in one install: vibe-math-v1 (classic pipeline), 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 four presets into the DSH preset root.",
4
- "version": "1.3.0",
4
+ "version": "1.3.1",
5
5
  "type": "module",
6
6
  "main": "installer.js",
7
7
  "exports": {
@@ -26,6 +26,7 @@ export function apply(ctx) {
26
26
  const DEFAULT_PARAMS = {
27
27
  residentCount: 4, compactThreshold: 66, compactAfterRounds: 8,
28
28
  maxParallel: 3, activityTimeoutMs: 120000, verdictMaxRounds: 3,
29
+ meetingKeepEvery: 5, // 每积累 N 个新产物自动触发一次同步会议
29
30
  provider: '', model: '', residentPersona: '',
30
31
  }
31
32
  let params = Object.assign({}, DEFAULT_PARAMS)
@@ -35,7 +36,7 @@ export function apply(ctx) {
35
36
  let problemText = '', problemId = 'problem', runId = 'run-' + shortId()
36
37
  let meetingState = null, verifyState = null, pendingVerify = null
37
38
  let busy = new Set(), wakeKind = new Map(), currentResident = ''
38
- let lastActivityAt = now()
39
+ let lastActivityAt = now(), artifactCount = 0, lastSyncMeetingAt = 0
39
40
  const activityLogCap = 200
40
41
 
41
42
  // ---- utils ----
@@ -111,22 +112,24 @@ export function apply(ctx) {
111
112
  +'This is your round (#'+r.rounds+'). You decide what to do — there is NO external assignment. Typical actions:\n'
112
113
  +'- advance your direction; verify your own claims; record valuable artifacts to YOUR library (vibe_v4_publish_progress / record_proposition / record_method / record_subproblem), each with 价值程度 / 动机用途计划 / 自身概率估计;\n'
113
114
  +'- message a specific resident (vibe_v4_send_message) or broadcast;\n'
115
+ +'- propose / claim / complete a shared task (vibe_v4_propose_task / vibe_v4_claim_task / vibe_v4_task_done / vibe_v4_list_tasks) — the task board is how you coordinate work;\n'
114
116
  +'- call a meeting (vibe_v4_meeting) to coordinate / allocate tasks / propose a verification;\n'
115
- +'- propose an object for unanimous verification (set propose_verify in your reply).\n'
117
+ +'- propose an object for unanimous verification (set propose_verify in your reply);\n'
118
+ +'- report your context usage (vibe_v4_report_context) so the framework compacts you when needed.\n'
116
119
  +'You may READ any other resident\'s Progress/Propos/Methods/Subproblems (read-only via vibe_v4_read_progress / fs); you only WRITE your own '+r.rId+' library.\n'
117
120
  +'Rules:\n- Only Verified/ is established. Verification requires ALL residents unanimous; you trust only unanimous results.\n'
118
121
  +'- If the ORIGINAL problem is solved, set solved=true (we stop only when ALL residents agree).\n'
119
122
  +'New items:\n'+ (await inboxText(r.rId))
120
123
  +'\nReply with ONLY a JSON object in a ```json fence (no prose outside):\n'
121
- +'{"summary":"<what you did this round, 1-3 sentences>","solved":false,"propose_verify":"<a target id like p-xxx / m-xxx / s-xxx, or null>"}'
124
+ +'{"summary":"<what you did this round, 1-3 sentences>","solved":false,"propose_verify":"<id|null>","propose_task":"<task title|null>","claim_task":"<task id|null>","contextPct":40}'
122
125
  }
123
126
  function meetingPrompt(r, st){
124
127
  return (params.residentPersona?params.residentPersona+'\n':'')
125
128
  +'You are resident '+r.rId+'. A meeting is in progress (agenda: '+st.agenda+').'
126
129
  +(st.type==='verify'?('\nThe group is verifying object: '+st.targetId+'. Give your independent verdict.'):'')
127
- +'\nGive your input. If the agenda is about whether the original problem is solved, set voteSolved.\n'
130
+ +'\nGive your input. You may: propose a task (propose_task), claim an open task (claim_task), propose an object for unanimous verification (propose_verify), or vote on whether the original problem is solved (voteSolved).\n'
128
131
  +'Reply with ONLY a JSON object (```json fence):\n'
129
- +'{"input":"<your contribution>","voteSolved":true,"propose_verify":"<id or null>"}'
132
+ +'{"input":"<your contribution>","propose_task":"<task title or null>","task_desc":"...","claim_task":"<task id or null>","propose_verify":"<id or null>","voteSolved":true}'
130
133
  }
131
134
  function verifyPrompt(r, vs){
132
135
  const others=Object.entries(vs.verdicts).map(([k,v])=>'- '+k+': '+v.verdict+' ('+v.confidence+') '+v.reason).join('\n')
@@ -140,7 +143,7 @@ export function apply(ctx) {
140
143
  }
141
144
 
142
145
  // ---- resident lifecycle ----
143
- function newResident(dir){ const rId='r-'+(residents.size+1); return {rId,childId:'',direction:dir||'',status:'brainstorm',rounds:0,roundsSinceCompact:0,lastActiveAt:now(),insight:''} }
146
+ function newResident(dir){ const rId='r-'+(residents.size+1); return {rId,childId:'',direction:dir||'',status:'brainstorm',rounds:0,roundsSinceCompact:0,lastActiveAt:now(),insight:'',contextPct:0,contextSeed:'',needCompact:false} }
144
147
  async function spawnResident(r){
145
148
  const started=await subagents.startContinuable({provider:pickProvider(),label:r.rId,request:{prompt:[textBlock(brainstormPrompt(r))],parent:rootAgent,agentOptions:{}},signal:makeSignal(60000)})
146
149
  r.childId=started.childId; r.status='brainstorm'; r.lastActiveAt=now()
@@ -151,7 +154,17 @@ export function apply(ctx) {
151
154
  if(!r.childId) return false
152
155
  busy.add(r.rId); wakeKind.set(r.rId,kind||'normal'); currentResident=r.rId
153
156
  r.lastActiveAt=now(); r.rounds+=1; r.roundsSinceCompact+=1
154
- try { await subagents.followup(rootAgent,r.childId,[textBlock(promptText)],{source:{kind:'user'},signal:makeSignal(60000)}); return true }
157
+ // context / /compact: if the resident reports high context (or reached the round proxy),
158
+ // prepend a compact directive — it condenses its working state to a self-summary that the
159
+ // framework uses as the next context seed (equivalent to /compact's "consolidate & forget").
160
+ let prompt = promptText
161
+ if(r.needCompact || (Number(r.contextPct)>=Number(params.compactThreshold)) || (r.roundsSinceCompact>=Number(params.compactAfterRounds))){
162
+ prompt = '[CONTEXT COMPACT — your conversation is at/near the limit. Do NOT re-derive history.\n' +
163
+ 'Condense your current working state into ONE tight self-summary (findings so far, active direction, key artifacts you recorded, next concrete steps, open questions), then answer this round in the normal JSON format as usual.\n' +
164
+ 'Set "contextPct": 15 (your post-compact usage) and "compacted": true in the reply so the framework records the condensed seed.]\n\n' + promptText
165
+ r.needCompact = true
166
+ }
167
+ try { await subagents.followup(rootAgent,r.childId,[textBlock(prompt)],{source:{kind:'user'},signal:makeSignal(60000)}); return true }
155
168
  catch(e){ console.error('vibe-v4 wake '+r.rId+' failed: '+String((e&&e.message)||e)); busy.delete(r.rId); return false }
156
169
  }
157
170
  function byChild(childId){ for(const [,r] of residents){ if(r.childId===childId) return r } return undefined }
@@ -159,9 +172,23 @@ export function apply(ctx) {
159
172
  // ---- artifact writers (resident-facing) ----
160
173
  async function publishProgress(rId,content){ const rel='Progress/'+rId+'/progress.md'; const prev=(await readText(rel))||''; await writeText(rel, prev+'\n### '+fmtTime()+'|'+rId+'\n'+String(content||'')+'\n'); return {ok:true} }
161
174
  async function recordProposition(rId,o){ const id=o.id||('p-'+shortId()); const lines=['# 命题|'+(o.title||id),'- 标题: '+(o.title||id),'- ID: '+id,'- 类型: 命题','- 状态: 未定论','- 概率: '+cl(o.prob!=null?o.prob:0.5),'- 价值程度: '+cl(o.value!=null?o.value:0.5),'- 动机用途计划: '+(o.motivation||''),'- 依赖: []','','## 陈述',String(o.statement||''),'','## 证明尝试','','## 证伪尝试','']; await writeText('Propos/'+rId+'/'+id+'.md',lines.join('\n')); logActivity('record',rId+' 命题 '+id); return {ok:true,id,file:'Propos/'+rId+'/'+id+'.md'} }
162
- 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); return {ok:true,id,file:'Methods/'+rId+'/'+id+'.md'} }
163
- 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); return {ok:true,id,file:'Subproblems/'+rId+'/'+id+'.md'} }
164
- function listResidents(){ return Array.from(residents.values()).map(r=>({id:r.rId,direction:r.direction,status:r.status,rounds:r.rounds,insight:r.insight?r.insight.slice(0,80):''})) }
175
+ 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'} }
176
+ 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'} }
177
+ // auto-sync meeting: every meetingKeepEvery new artifacts, convene a general coordination meeting
178
+ function bumpArtifacts(){ artifactCount+=1; if(!meetingState && !verifyState && Number(params.meetingKeepEvery)>0 && artifactCount % Number(params.meetingKeepEvery)===0){ startMeeting('定期同步:分工/进展/是否需要验证','general',null).catch(()=>{}) } }
179
+ 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):''})) }
180
+
181
+ // ---- task board (residents propose / claim / complete; framework wakes the claimer) ----
182
+ async function writeTaskboard(){ const lines=['# 任务板','']; for(const t of taskboard){ lines.push('- ['+t.status+'] '+t.title+(t.claimer?('(认领:'+t.claimer+')'):'')+(t.proposer?('(提议:'+t.proposer+')'):'')+(t.description?(':'+t.description):'')) } await writeText('Shared/taskboard.md',lines.join('\n')) }
183
+ async function proposeTask(title,description,proposer){ const id='t-'+shortId(); taskboard.push({id,title:String(title),description:String(description||''),status:'open',proposer:proposer||'',claimer:'',source:''}); await saveTaskboard(); logActivity('task','proposed '+id+'「'+title+'」'); return {ok:true,id} }
184
+ async function claimTask(id,claimer){ const t=taskboard.find(x=>x.id===id); if(!t) return {ok:false,message:'no such task'}; if(t.status!=='open') return {ok:false,message:'task already '+t.status}; t.status='claimed'; t.claimer=claimer; await saveTaskboard(); logActivity('task',claimer+' claimed '+id);
185
+ // wake the claimer to work on it (framework moves the task, resident decides how)
186
+ const r=residents.get(claimer); if(r && !busy.has(claimer)){ currentResident=claimer; await wakeResident(r, (await normalPrompt(r))+'\n\n[YOU CLAIMED TASK '+id+'] '+t.title+' — '+t.description,'normal'); await saveAll() }
187
+ return {ok:true} }
188
+ async function taskDone(id,claimer){ const t=taskboard.find(x=>x.id===id); if(!t) return {ok:false}; t.status='done'; t.doneBy=claimer; await saveTaskboard(); await writeTaskboard(); logActivity('task','done '+id); return {ok:true} }
189
+ async function saveTaskboard(){ await writeJson('State/taskboard.json',taskboard); await writeTaskboard() }
190
+ function listTasks(){ return taskboard.filter(t=>t.status!=='done') }
191
+ async function reportContext(rId,pct){ const r=residents.get(rId); if(r){ r.contextPct=cl(pct); if(Number(pct)<30) r.needCompact=false; } return {ok:true} }
165
192
 
166
193
  // ---- messaging ----
167
194
  async function postMessage(from,to,content){
@@ -196,6 +223,12 @@ export function apply(ctx) {
196
223
  await writeText('Shared/meetings/'+st.id+'.md', lines.join('\n'))
197
224
  meetings.push({id:st.id,agenda:st.agenda,at:now(),inputs:st.inputs})
198
225
  logDecision('meeting',st.agenda)
226
+ // handle what the meeting produced: task proposals/claims, verify targets, stop vote
227
+ for(const [id,iv] of Object.entries(st.inputs)){
228
+ if(iv.propose_task) await proposeTask(iv.propose_task, iv.task_desc||'', id)
229
+ if(iv.claim_task) await claimTask(iv.claim_task, id)
230
+ if(iv.propose_verify) pendingVerify={targetId:iv.propose_verify,targetType:guessTargetType(iv.propose_verify),proposer:id,at:now()}
231
+ }
199
232
  const votes=Object.values(st.inputs).map(x=>x.voteSolved).filter(v=>typeof v==='boolean')
200
233
  const allSolved=votes.length>0 && votes.every(v=>v===true)
201
234
  logActivity('meeting', 'concluded'+(allSolved?' → ALL agree solved':''))
@@ -303,7 +336,7 @@ export function apply(ctx) {
303
336
  const parsed=parseReply(output)
304
337
  const kind=wakeKind.get(r.rId)||'normal'
305
338
  if(kind==='meeting' && meetingState){
306
- meetingState.inputs[r.rId]={input:parsed.input||parsed.summary||'',voteSolved:typeof parsed.voteSolved==='boolean'?parsed.voteSolved:null,propose_verify:parsed.propose_verify||null}
339
+ meetingState.inputs[r.rId]={input:parsed.input||parsed.summary||'',voteSolved:typeof parsed.voteSolved==='boolean'?parsed.voteSolved:null,propose_verify:parsed.propose_verify||null,propose_task:parsed.propose_task||null,task_desc:parsed.task_desc||'',claim_task:parsed.claim_task||null}
307
340
  if(parsed.propose_verify) pendingVerify={targetId:parsed.propose_verify,targetType:guessTargetType(parsed.propose_verify),proposer:r.rId,at:now()}
308
341
  await saveAll(); await continueMeetingRound(); return
309
342
  }
@@ -316,7 +349,14 @@ export function apply(ctx) {
316
349
  // normal turn
317
350
  if(r.status==='brainstorm'){ r.insight=parsed.summary||output; r.status='active' }
318
351
  if(typeof parsed.solved==='boolean') reports.push({rId:r.rId,solved:parsed.solved,summary:parsed.summary||'',at:now()})
352
+ // context / compact: record the condensed seed + post-compact usage, clear the flag
353
+ if(typeof parsed.contextPct==='number'){ r.contextPct=cl(parsed.contextPct) }
354
+ if(parsed.compacted===true || (r.needCompact && parsed.summary)){ r.contextSeed=String(parsed.summary||''); r.contextPct=Math.min(r.contextPct||15,25); r.roundsSinceCompact=0; r.needCompact=false; logActivity('compact',r.rId+' consolidated context') }
319
355
  if(parsed.propose_verify) pendingVerify={targetId:parsed.propose_verify,targetType:guessTargetType(parsed.propose_verify),proposer:r.rId,at:now()}
356
+ // task actions via reply (a resident may propose or claim a task in its round)
357
+ if(parsed.propose_task) await proposeTask(parsed.propose_task, parsed.task_desc||'', r.rId)
358
+ if(parsed.claim_task) await claimTask(parsed.claim_task, r.rId)
359
+ if(parsed.task_done) await taskDone(parsed.task_done, r.rId)
320
360
  // a resident may self-trigger a meeting (resident-driven coordination, closest to the philosophy)
321
361
  if(parsed.propose_meeting && !meetingState){ await startMeeting(String(parsed.propose_meeting),'general',null); await saveAll(); return }
322
362
  await saveAll(); await scheduleNext()
@@ -362,7 +402,8 @@ export function apply(ctx) {
362
402
  setPause, initAbort, postMessage, startMeeting, saveAll,
363
403
  currentResident:()=>currentResident,
364
404
  useResident:(id)=>{ currentResident=id },
365
- publishProgress, recordProposition, recordMethod, recordSubproblem, listResidents,
405
+ publishProgress, recordProposition, recordMethod, recordSubproblem, listResidents, reportContext,
406
+ proposeTask, claimTask, taskDone, listTasks,
366
407
  readProgress: async (rid)=>({text:(await readText('Progress/'+rid+'/progress.md'))||''}),
367
408
  frameworkRoot:frameworkRoot, currentProject:()=>currentProject, problemText:()=>problemText,
368
409
  residentCount:()=>residents.size,
@@ -392,7 +433,7 @@ export function apply(ctx) {
392
433
  registerTool('vibe_v4_list_members','List residents.',objParams({}),(s)=>({ok:true,residents:s.listResidents()}))
393
434
  registerTool('vibe_v4_add_member','Add a resident.',objParams({direction:{type:'string'}}),(s,a)=>s.addMember(a.direction))
394
435
  registerTool('vibe_v4_remove_member','Close a resident.',objParams({id:{type:'string'}},['id']),(s,a)=>s.removeMember(a.id))
395
- registerTool('vibe_v4_set','Set V4 parameters.',objParams({residentCount:{type:'integer'},compactAfterRounds:{type:'integer'},compactThreshold:{type:'integer'},maxParallel:{type:'integer'},activityTimeoutMs:{type:'integer'}}),(s,a)=>{ s.setParams(a); return {ok:true} })
436
+ registerTool('vibe_v4_set','Set V4 parameters.',objParams({residentCount:{type:'integer'},compactAfterRounds:{type:'integer'},compactThreshold:{type:'integer'},meetingKeepEvery:{type:'integer'},maxParallel:{type:'integer'},activityTimeoutMs:{type:'integer'}}),(s,a)=>{ s.setParams(a); return {ok:true} })
396
437
  // resident-facing tools: route to the CURRENT (last-woken) resident of the session
397
438
  registerTool('vibe_v4_send_message','(resident) Send a message to another resident.',objParams({to:{type:'string'},content:{type:'string'}},['to','content']),(s,a)=>s.postMessage(s.currentResident(),a.to,a.content))
398
439
  registerTool('vibe_v4_publish_progress','(resident) Append to your own progress markdown.',objParams({content:{type:'string'}},['content']),(s,a)=>s.publishProgress(s.currentResident(),a.content))
@@ -401,6 +442,13 @@ export function apply(ctx) {
401
442
  registerTool('vibe_v4_record_subproblem','(resident) Record a sub-problem to your library.',objParams({id:{type:'string'},title:{type:'string'},statement:{type:'string'},value:{type:'number'},motivation:{type:'string'}}),(s,a)=>s.recordSubproblem(s.currentResident(),a))
402
443
  registerTool('vibe_v4_read_progress','(resident) Read another resident\'s progress (read-only).',objParams({id:{type:'string'}},['id']),(s,a)=>({ok:true,text:(s.readProgress(a.id))}))
403
444
  registerTool('vibe_v4_list_residents','(resident) List fellow residents.',objParams({}),(s)=>({ok:true,residents:s.listResidents()}))
445
+ // task board (residents; board is the residents' own allocation mechanism)
446
+ registerTool('vibe_v4_propose_task','(resident) Propose a task to the shared task board.',objParams({title:{type:'string'},description:{type:'string'}},['title']),(s,a)=>s.proposeTask(a.title,a.description,s.currentResident()))
447
+ registerTool('vibe_v4_claim_task','(resident) Claim an open task from the board (framework then wakes you to work it).',objParams({id:{type:'string'}},['id']),(s,a)=>s.claimTask(a.id,s.currentResident()))
448
+ registerTool('vibe_v4_task_done','(resident) Mark a claimed task done.',objParams({id:{type:'string'},claimer:{type:'string'}},['id']),(s,a)=>s.taskDone(a.id,a.claimer||s.currentResident()))
449
+ registerTool('vibe_v4_list_tasks','(resident) List open tasks.',objParams({}),(s)=>({ok:true,tasks:s.listTasks()}))
450
+ // context / compact (resident reports its context usage so the framework can /compact-equivalent)
451
+ registerTool('vibe_v4_report_context','(resident) Report your context usage %; the framework compacts (self-summary) when it reaches compactThreshold.',objParams({pct:{type:'number'}},['pct']),(s,a)=>s.reportContext(s.currentResident(),a.pct))
404
452
  registerTool('vibe_v4_claim_write','Reserved: shared-file write lock (framework-managed).',objParams({target:{type:'string'}},['target']),(s,a)=>({ok:true,key:a.target}))
405
453
  registerTool('vibe_v4_release_write','Reserved: shared-file write lock release.',objParams({target:{type:'string'}},['target']),(s,a)=>({ok:true,key:a.target}))
406
454
 
@@ -325,3 +325,17 @@ VibeMath/Projects/<project>/
325
325
  - `verdictQuorum` 是否始终为 `all`(哲学强调一致,默认不改)。
326
326
  - `perResidentLibs`(每常驻独立目录 vs 共享库+署名)——默认独立。
327
327
  - DSH `/compact` 的精确触发 API(实现 P1 时确认)。
328
+
329
+ ---
330
+
331
+ ## 16. 实现现状备注(P5/P6 已落地,v1.3.x)
332
+
333
+ **任务板认领(P5)**:`vibe_v4_propose_task / claim_task / task_done / list_tasks`。常驻可在回复或会议中提议/认领任务;认领后框架**唤醒认领者**带任务工作;任务板落盘 `Shared/taskboard.md` + `State/taskboard.json`;会议结束落任务板/触发验证目标。
334
+
335
+ **上下文 / /compact(P5)**:DSH 打包未暴露"子代理上下文占比 + `/compact`" RPC,故实现**等效真实压缩**——常驻用 `vibe_v4_report_context {pct}` 上报占比;达 `compactThreshold`(66) 或 `compactAfterRounds` 轮数时,框架在下次唤醒前注入"[CONTEXT COMPACT — 浓缩自述]"指令,常驻把工作状态浓缩为一段自述并在回复里带 `contextPct`(低)、`compacted:true`;框架记录**浓缩种子**为后续上下文并复位 `roundsSinceCompact/needCompact`。`compactThreshold/compactAfterRounds/meetingKeepEvery` 均可调。
336
+
337
+ **会议主动触发(P6)**:
338
+ - 常驻 normal 回复里 `propose_meeting` 自触发会议;助手亦可 `vibe_v4_meeting`。
339
+ - **自动同步会议**:每积累 `meetingKeepEvery`(默认 5) 个新产物,框架自动发起"分工/进展/是否需要验证"同步会议。
340
+ - 会议输入可含 `propose_task/claim_task/propose_verify/voteSolved`,结束统一落任务板、触发验证、记停止表决;仍"全体一致 voteSolved=true 才停止"。
341
+