🐛 fix(vscode): 修复看板缓存并增加问答默认模型
This commit is contained in:
1 parent
c38f1dc468
commit
012daf95b5
25 files changed
+1753
-164
No files matched your search
@@ -38,6 +38,51 @@ function fakeCtx(dir: string, memento: Record<string, unknown> = {}): ExtensionC
|
||||
}
|
||||
|
||||
describe('saveSettings 落盘', () => {
|
||||
it('目录配置落盘后才切换候选目录,随后通知问答刷新', async () => {
|
||||
const ctx = fakeCtx(tempDir())
|
||||
const profileModule = await import('../cc/profiles.js')
|
||||
const setDirectory = vi.spyOn(profileModule, 'setProfilesDirOverride').mockImplementation(() => {
|
||||
expect(getSettings(ctx).profilesDirectory).toBe('/new/profiles')
|
||||
})
|
||||
const { onDidChangeSettings } = await import('./store.js')
|
||||
const subscription = onDidChangeSettings(ctx, () => {
|
||||
expect(setDirectory).toHaveBeenCalledWith('/new/profiles')
|
||||
})
|
||||
try {
|
||||
await saveSettings(ctx, { profilesDirectory: '/new/profiles' })
|
||||
expect(setDirectory).toHaveBeenCalledOnce()
|
||||
}
|
||||
finally {
|
||||
subscription.dispose()
|
||||
setDirectory.mockRestore()
|
||||
}
|
||||
})
|
||||
|
||||
it('文件问答默认模型独立落盘,重启读取且不受旧的上次选择影响', async () => {
|
||||
const dir = tempDir()
|
||||
const ctx = fakeCtx(dir, { 'superpowers.codeReader.askProfile': 'sonnet' })
|
||||
expect(getSettings(ctx).defaultAskProfilePath).toBe('')
|
||||
await saveSettings(ctx, { defaultAskProfilePath: '/p/dsflash.json' })
|
||||
expect(JSON.parse(readFileSync(path.join(dir, 'settings.json'), 'utf8')).defaultAskProfilePath).toBe('/p/dsflash.json')
|
||||
expect(getSettings(fakeCtx(dir)).defaultAskProfilePath).toBe('/p/dsflash.json')
|
||||
await saveSettings(ctx, { webhookPort: 9000 })
|
||||
expect(getSettings(ctx).defaultAskProfilePath).toBe('/p/dsflash.json')
|
||||
await saveSettings(ctx, { defaultAskProfilePath: '' })
|
||||
expect(getSettings(fakeCtx(dir)).defaultAskProfilePath).toBe('')
|
||||
})
|
||||
|
||||
it('默认配置保存后通知订阅者,取消订阅后不再通知', async () => {
|
||||
const ctx = fakeCtx(tempDir())
|
||||
const { onDidChangeSettings } = await import('./store.js')
|
||||
const listener = vi.fn(() => getSettings(ctx).defaultAskProfilePath)
|
||||
const subscription = onDidChangeSettings(ctx, listener)
|
||||
await saveSettings(ctx, { defaultAskProfilePath: '/p/sonnet.json' })
|
||||
expect(listener).toHaveLastReturnedWith('/p/sonnet.json')
|
||||
subscription.dispose()
|
||||
await saveSettings(ctx, { defaultAskProfilePath: '' })
|
||||
expect(listener).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
|
||||
it('写入 globalStorage 的 settings.json,清空 memento 后仍能读到 commitProfilePath', async () => {
|
||||
const dir = tempDir()
|
||||
const ctx = fakeCtx(dir)
|
||||
|
||||
@@ -11,12 +11,13 @@
|
||||
* a field.
|
||||
*/
|
||||
|
||||
import type { ExtensionContext } from 'vscode'
|
||||
import type { Disposable, ExtensionContext } from 'vscode'
|
||||
import type { MigrationNote } from './promptMigration'
|
||||
import { EventEmitter } from 'node:events'
|
||||
import { copyFileSync, existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from 'node:fs'
|
||||
import path from 'node:path'
|
||||
import { seedCommitProfilePath } from '../cc/commitProfile'
|
||||
import { listClaudeProfiles } from '../cc/profiles'
|
||||
import { listClaudeProfiles, setProfilesDirOverride } from '../cc/profiles'
|
||||
import { normalizeReleasePrefix } from '../git/release'
|
||||
import { PREVIOUS_DEFAULT_REVIEW_PROMPT } from './previousReviewPrompt'
|
||||
import { planPromptMigration, planReviewPromptMigration } from './promptMigration'
|
||||
@@ -210,6 +211,7 @@ export interface Settings {
|
||||
defaultTestProfilePath: string
|
||||
/** 原型会话的默认 Claude profile;工单级「原型配置文件」为空时用它。 */
|
||||
defaultPrototypeProfilePath: string
|
||||
defaultAskProfilePath: string
|
||||
/**
|
||||
* Claude settings profile path for the conflict-resolution cc session
|
||||
* (drag to 完成 when PR merge conflicts). Empty = DEFAULT_PROFILE_PATH.
|
||||
@@ -314,6 +316,7 @@ function defaults(ctx: ExtensionContext): Settings {
|
||||
defaultImplementProfilePath: '',
|
||||
defaultTestProfilePath: '',
|
||||
defaultPrototypeProfilePath: '',
|
||||
defaultAskProfilePath: '',
|
||||
conflictResolutionProfilePath: '',
|
||||
commitProfilePath: '',
|
||||
prDiffSummaryProfilePath: '',
|
||||
@@ -429,6 +432,9 @@ export function getSettings(ctx: ExtensionContext): Settings {
|
||||
const defaultPrototypeProfilePath = typeof stored.defaultPrototypeProfilePath === 'string'
|
||||
? stored.defaultPrototypeProfilePath
|
||||
: base.defaultPrototypeProfilePath
|
||||
const defaultAskProfilePath = typeof stored.defaultAskProfilePath === 'string'
|
||||
? stored.defaultAskProfilePath.trim()
|
||||
: base.defaultAskProfilePath
|
||||
// conflict-resolution profile: '' is meaningful (= DEFAULT_PROFILE_PATH at
|
||||
// launch time), so don't coerce. Non-string legacy values collapse to ''.
|
||||
const conflictResolutionProfilePath = typeof stored.conflictResolutionProfilePath === 'string'
|
||||
@@ -489,6 +495,7 @@ export function getSettings(ctx: ExtensionContext): Settings {
|
||||
defaultImplementProfilePath,
|
||||
defaultTestProfilePath,
|
||||
defaultPrototypeProfilePath,
|
||||
defaultAskProfilePath,
|
||||
conflictResolutionProfilePath,
|
||||
commitProfilePath,
|
||||
prDiffSummaryProfilePath,
|
||||
@@ -524,9 +531,24 @@ export async function getEffectivePrDiffSummaryProfilePath(ctx: ExtensionContext
|
||||
return seedCommitProfilePath(undefined, profiles)
|
||||
}
|
||||
|
||||
const settingsChanges = new EventEmitter()
|
||||
|
||||
export function onDidChangeSettings(ctx: ExtensionContext, listener: () => void): Disposable {
|
||||
const key = settingsFilePath(ctx)
|
||||
settingsChanges.on(key, listener)
|
||||
return {
|
||||
dispose: () => {
|
||||
settingsChanges.off(key, listener)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
export async function saveSettings(ctx: ExtensionContext, next: Partial<Settings>): Promise<void> {
|
||||
const merged: Partial<Settings> = { ...readStoredSettings(ctx), ...next }
|
||||
writeStoredSettings(ctx, merged)
|
||||
if (next.profilesDirectory !== undefined)
|
||||
setProfilesDirOverride(next.profilesDirectory.trim() || undefined)
|
||||
settingsChanges.emit(settingsFilePath(ctx))
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in new issue
Block a user