feat: align conversation state, composer and scoped approvals
This commit is contained in:
1 parent
771ca540f7
commit
308b98df23
61 files changed
+1701
-292
No files matched your search
@@ -0,0 +1,50 @@
|
||||
/** Mock SDK transport: tests host replay lifecycle, NOT SDK permission matching. */
|
||||
import assert from 'node:assert/strict'
|
||||
import { mkdtemp, rm } from 'node:fs/promises'
|
||||
import { tmpdir } from 'node:os'
|
||||
import { join } from 'node:path'
|
||||
import { ClaudeKernel } from '../src/main/agent/claude/claude-kernel'
|
||||
import { rememberSessionGrant, sessionGrantProposal, clearSessionGrants } from '../src/main/agent/claude/session-grants'
|
||||
const temp=await mkdtemp(join(tmpdir(),'grant-replay-unit-'));process.env.CLAUDE_TEST_USER_DATA=temp
|
||||
const instances:any[]=[]
|
||||
let fail=true
|
||||
;(globalThis as any).__SDK_QUERY_FIXTURE=(input:any)=>{
|
||||
let end!:()=>void;const done=new Promise<void>(resolve=>{end=resolve})
|
||||
const instance={input,closed:false,settings:[] as any[],async *[Symbol.asyncIterator](){await done},close(){this.closed=true;end()},async applyFlagSettings(value:any){this.settings.push(value);if(fail)throw new Error('fixture replay failure')},async setPermissionMode(){},async getContextUsage(){return {categories:[]}}}
|
||||
instances.push(instance);return instance
|
||||
}
|
||||
const model={profile:{id:'fixture',model:'fixture',authMode:'api-key'},config:{model:'fixture',baseUrl:'http://127.0.0.1:1',apiKey:'not-used',authMode:'api-key'}}
|
||||
const kernel=new ClaudeKernel({sessionId:'a',workspaceRoot:temp,model:model as any,permissionMode:'default-sandbox',agentMode:'craft',onSessionId:()=>{}})
|
||||
try{
|
||||
const grant=sessionGrantProposal([{type:'addRules',behavior:'allow',destination:'session',rules:[{toolName:'Bash',ruleContent:'echo safe:*'}]}])!
|
||||
rememberSessionGrant('a',grant,temp)
|
||||
await assert.rejects(kernel.ensureStarted(),/恢复本会话授权失败/)
|
||||
assert.equal(instances.length,1);assert.equal(instances[0].closed,true)
|
||||
assert.equal((kernel as any).instance,null);assert.equal((kernel as any).input,null)
|
||||
// Complete retired iterator cleanup before attempting a second kernel start.
|
||||
await (kernel as any).draining
|
||||
await assert.rejects(kernel.ensureStarted(),/恢复本会话授权失败/)
|
||||
assert.equal(instances.length,2,'failure never silently reuses poisoned query')
|
||||
await (kernel as any).draining
|
||||
fail=false;await kernel.ensureStarted()
|
||||
assert.equal(instances.length,3)
|
||||
assert.equal((kernel as any).draining,null,'retired consumer draining lock cleared')
|
||||
assert.deepEqual(await kernel.getContextSummary(),{categories:[]},'context queries recover after failed replay')
|
||||
const raw=kernel as any
|
||||
raw.active={settled:false,appends:new Map(),groupIds:['original'],request:{signal:new AbortController().signal,onSegmentStart:async()=>{},onSegmentComplete:async()=>{}}}
|
||||
const append=kernel.appendInput({userMessageId:'append',prompt:'fixture'})
|
||||
assert.equal(raw.active.appends.size,1,'append accepted after retry, no stale draining lock')
|
||||
raw.active.appends.get('append').resolve();await append
|
||||
raw.active=null
|
||||
assert.deepEqual(instances[2].settings,[{permissions:{allow:['Bash(echo safe:*)']}}])
|
||||
const hook=instances[2].input.options.hooks.PreToolUse[0].hooks[0]
|
||||
;(kernel as any).active={request:{signal:new AbortController().signal}}
|
||||
await kernel.setPolicy('full-access','plan')
|
||||
const denied=await hook({hook_event_name:'PreToolUse',tool_name:'Bash',tool_input:{command:'echo safe'}})
|
||||
assert.equal(denied.hookSpecificOutput.permissionDecision,'deny','plan denies even matching replay grant')
|
||||
;(kernel as any).active=null
|
||||
const other=new ClaudeKernel({sessionId:'other',workspaceRoot:temp,model:model as any,permissionMode:'default-sandbox',agentMode:'craft',onSessionId:()=>{}})
|
||||
await other.ensureStarted();assert.equal(instances.at(-1).settings.length,0,'other session receives no grants')
|
||||
await other.close()
|
||||
console.log('Mock SDK replay lifecycle passed: fail closed, retry, session isolation, independent mode guard')
|
||||
}finally{(kernel as any).active=null;await kernel.close();clearSessionGrants();await rm(temp,{recursive:true,force:true})}
|
||||
Reference in new issue
Block a user