feat(web): export the session log from the trajectory toolbar

The 导出 button fetches GET /api/session.export and saves the ZIP (root
artifact plus subagent descendants). The plugin exposes exportLog through
the view's inject face, resolves the tab label through the locale service,
and disables the button while in flight; fixture mode answers 404 so the
error bar explains the gap.
This commit is contained in:
_Kerman
2026-08-10 17:47:49 +08:00
parent ded90bffba
commit 9574a99f45
18 changed files with 369 additions and 10 deletions

View File

@@ -61,7 +61,7 @@ describe('tsdown client artifact', () => {
const { handoff, surface } = await loadArtifact()
expect(handoff.id).toBe(PLUGIN_ID)
expect(surface.apply).toBeTypeOf('function')
expect(surface.inject).toEqual(['slots', 'sessionHistory'])
expect(surface.inject).toEqual(['slots', 'sessionHistory', 'locale'])
})
it.skipIf(code === undefined)('mounted as an object plugin, apply registers the view tab on the real ring', async () => {
@@ -74,8 +74,11 @@ describe('tsdown client artifact', () => {
children: { 'conversation.view': { kind: 'list', scope: 'session' } },
}, (_p: { renderSlot?: unknown }) => null)
// The plugin reads sessionHistory for its per-session history source;
// slot availability is tracked by slots.inject.
// slot availability is tracked by slots.inject, and the locale plugin
// backs the locale-aware view tab label.
ctx.provide('sessionHistory', {})
const locale = await import('@deepseek-ai/dsh-client-locale/client')
ctx.plugin({ inject: [...locale.inject], apply: locale.apply })
const fiber = ctx.plugin(surface as { apply: (ctx: Context) => void })
await fiber.await()
expect(slots.entries('conversation.view').map(e => e.options.id)).toEqual(['trajectory'])