feat: ship skill and MCP workflows with signed updater for v0.0.7

This commit is contained in:
xiaohan.yuan committed 2026-10-21 00:04:17 +08:00
1 parent 1b52df0603
commit a01085c656
136 files changed
+18646 -217

No files matched your search

+47 -2
View File
@@ -92,7 +92,7 @@ function resetStore(): void {
})
}
function installFakeWindow(send: (payload: { sessionId: string; text: string }) => Promise<SendResult>): void {
function installFakeWindow(send: (payload: Parameters<typeof window.ycode.chat.send>[0]) => Promise<SendResult>): void {
const api = {
session: {
list: async () => [session],
@@ -718,7 +718,7 @@ async function testEarlyOrderedEventsAndDuplicateGuard(): Promise<void> {
const firstSend = useChatStore.getState().send('question')
assert.equal(useChatStore.getState().sending, true, 'sending should cover the pending IPC request')
assert.equal(useChatStore.getState().messages.length, 0, 'early events wait for the send result placeholder')
await useChatStore.getState().send('duplicate')
await assert.rejects(useChatStore.getState().send('duplicate'), /提交/)
assert.equal(sendCalls, 1, 'a second send must be ignored while the first send is pending')
response.resolve(result)
@@ -929,7 +929,32 @@ async function testParallelSessionsAndStaleLoads(): Promise<void> {
assert.equal(useChatStore.getState().messages[0].content, 'fast', 'stale session fetch cannot replace a newer selection')
}
async function testNativeSegmentBoundaryBeforeSendResponse(): Promise<void> {
resetStore()
const gate = deferred<SendResult>()
installFakeWindow(async () => gate.promise)
const sending = useChatStore.getState().send('root')
const runId = 'native-segment'
const root = sendResult(runId)
useChatStore.getState().applyEvent({ runId, sessionId: session.id, sequence: 1, type: 'text', delta: 'root answer' })
const guide: ChatMessage = { id: 'guide-user', role: 'user', content: 'guidance', createdAt: 12, status: 'done' }
const answer: ChatMessage = { id: 'guide-assistant', role: 'assistant', content: '', createdAt: 13, status: 'streaming', requestId: runId }
useChatStore.getState().observeRun({ ...root, sessionId: session.id, sequence: 2, segmentBoundary: true,
assistantMessageId: answer.id, userMessage: guide, messages: [root.userMessage,
{ id: root.assistantMessageId, role: 'assistant', content: 'root answer', createdAt: 11, status: 'done' }, guide, answer] })
useChatStore.getState().applyEvent({ runId, sessionId: session.id, sequence: 3, type: 'text', delta: 'guide answer' })
gate.resolve(root)
await sending
useChatStore.getState().applyEvent({ runId, sessionId: session.id, sequence: 4, type: 'done', content: 'guide answer', tools: [] })
const messages = useChatStore.getState().messages
assert.equal(messages.find(message => message.id === root.assistantMessageId)?.content, 'root answer')
assert.equal(messages.find(message => message.id === answer.id)?.content, 'guide answer')
assert.equal(messages.find(message => message.id === answer.id)?.status, 'done')
assert.equal(useChatStore.getState().running, null)
}
async function main(): Promise<void> {
await testNativeSegmentBoundaryBeforeSendResponse()
resetStore()
let inlinePayload: Parameters<typeof window.ycode.chat.send>[0] | undefined
installFakeWindow(async payload => { inlinePayload = payload; return sendResult('inline-layout') })
@@ -947,6 +972,26 @@ async function main(): Promise<void> {
installFakeWindow(async () => { referenceOnlySends++; return sendResult('skill-only') })
await useChatStore.getState().send('', { skillIds: ['skill'] })
assert.equal(referenceOnlySends, 2, 'a skill-only draft must reach IPC')
let capabilityPayload: Parameters<typeof window.ycode.chat.send>[0] | undefined
resetStore()
installFakeWindow(async payload => { capabilityPayload = payload; return sendResult('mcp-only') })
await useChatStore.getState().send('', { mcpServerIds: ['server'] })
assert.deepEqual(capabilityPayload?.mcpServerIds, ['server'], 'an MCP-only draft must reach IPC with its selected server')
resetStore()
installFakeWindow(async payload => { capabilityPayload = payload; return sendResult('compact-only') })
await useChatStore.getState().send('/compact', { command: 'compact' })
assert.equal(capabilityPayload?.command, 'compact', 'a command-only draft must reach IPC as a native command')
resetStore()
useChatStore.setState({ currentSessionId: null, messages: [], draftContext: {}, draftId: 7 })
const deferredResult = deferred<SendResult>()
installFakeWindow(async () => deferredResult.promise)
const optimisticSend = useChatStore.getState().send('', { skillIds: ['optimistic-skill'], mcpServerIds: ['optimistic-server'] })
const optimisticUser = useChatStore.getState().messages.find(message => message.role === 'user')
assert.deepEqual(optimisticUser?.skills?.map(item => item.id), ['optimistic-skill'], 'the optimistic user message must retain selected skill metadata')
assert.deepEqual(optimisticUser?.mcpServerIds, ['optimistic-server'], 'the optimistic user message must retain MCP selection metadata')
deferredResult.resolve(sendResult('optimistic-mcp'))
await optimisticSend
await testFailedCreatedSessionIsRemoved()
await testFailedCreatedSessionWithMessagesIsRetained()
await testUnsafeCleanupDoesNotMasqueradeAsHome()