feat: align conversation state, composer and scoped approvals

This commit is contained in:
dot committed 2026-10-21 03:46:53 +09:00
1 parent 771ca540f7
commit 308b98df23
61 files changed
+1701 -292

No files matched your search

@@ -0,0 +1,52 @@
import assert from 'node:assert/strict'
import { build } from 'esbuild'
import { mkdtemp, mkdir, writeFile, rm } from 'node:fs/promises'
import { tmpdir } from 'node:os'
import { join } from 'node:path'
import { pathToFileURL } from 'node:url'
import { resolveSelectedModel } from '../src/shared/model-selection'
import type { CustomModelProfile, CustomModelInput } from '../src/shared/models'
const temp = await mkdtemp(join(tmpdir(), 'ycode-model-alignment-'))
const state = { path: join(temp, 'fresh') }
;(globalThis as any).__modelAlignment = state
let count = 0
try {
const outfile = join(temp, 'models.mjs')
await build({ entryPoints: ['src/main/models.ts'], outfile, bundle: true, platform: 'node', format: 'esm', logLevel: 'silent',
plugins: [{ name: 'offline-host', setup(b) {
b.onResolve({filter:/^electron$/},()=>({path:'host',namespace:'fixture'}))
b.onLoad({filter:/.*/,namespace:'fixture'},()=>({contents:`export const app={getPath:()=>globalThis.__modelAlignment.path}; export const safeStorage={isEncryptionAvailable:()=>false};`,loader:'js'}))
b.onResolve({filter:/^\.\/model-connection$/},()=>({path:'connection',namespace:'offline'}))
b.onResolve({filter:/^\.\/model-metadata$/},()=>({path:'metadata',namespace:'offline'}))
b.onLoad({filter:/.*/,namespace:'offline'},args=>({contents:args.path==='metadata'
? `export const modelMetadata=async()=>null;`
: `export const cachedConnection=()=>undefined,cachedGeneration=()=>undefined,discoverModelConnection=async()=>undefined,modelFetch=()=>{throw Error('external network forbidden in regression')},readModelJson=()=>{},rememberGeneration=()=>{};`,loader:'js'}))
}}] })
const reload=()=>import(`${pathToFileURL(outfile).href}?${++count}`) as Promise<typeof import('../src/main/models')>
let models=await reload()
assert.deepEqual(await models.listModels(),{models:[],selectedModelId:null},'fresh install must not synthesize deepseek')
const input=(id:string):CustomModelInput=>({id,name:id,model:id,baseUrl:'https://offline.invalid',providerId:'custom',authMode:'none',protocol:'anthropic'})
assert.equal((await models.saveModel(input('one'))).selectedModelId,'one')
assert.equal((await models.saveModel(input('two'))).selectedModelId,'two','new model becomes default')
assert.equal((await models.saveModel({...input('one'),previousId:'one'})).selectedModelId,'two','editing another model preserves selection')
const before=(await models.listModels()).models
assert.equal(resolveSelectedModel(before,'stale','two')?.id,'two')
assert.equal(resolveSelectedModel(before,'one','two')?.id,'one')
assert.equal(resolveSelectedModel(before,'stale','stale')?.id,'one')
assert.equal(resolveSelectedModel([],'one','two'),null)
assert.equal((await models.deleteModel('two')).selectedModelId,'one')
await models.deleteModel('one'); models=await reload()
assert.deepEqual(await models.listModels(),{models:[],selectedModelId:null})
assert.equal((await models.saveModel(input('three'))).selectedModelId,'three')
state.path=join(temp,'legacy'); await mkdir(state.path)
await writeFile(join(state.path,'config.json'),JSON.stringify({model:'user-model',baseUrl:'https://configured.invalid',temperature:0.2,maxToolRounds:4}))
models=await reload(); assert.equal((await models.listModels()).models[0]?.model,'user-model','explicit legacy config preserved')
state.path=join(temp,'preferences-only');await mkdir(state.path)
await writeFile(join(state.path,'config.json'),JSON.stringify({preventSleep:true}))
models=await reload();assert.deepEqual(await models.listModels(),{models:[],selectedModelId:null},'preferences are not a model')
state.path=join(temp,'serialized-defaults');await mkdir(state.path)
await writeFile(join(state.path,'config.json'),JSON.stringify({model:'deepseek-chat',baseUrl:'https://api.deepseek.com/v1',preventSleep:true}))
models=await reload();assert.deepEqual(await models.listModels(),{models:[],selectedModelId:null},'old preference writes of defaults are not real configuration')
console.log('PASS model alignment: fresh/legacy migration, new/edit/default/delete/reload, valid selection (offline host fixtures)')
} finally { delete (globalThis as any).__modelAlignment; await rm(temp,{recursive:true,force:true}) }