From b7eb448216c6e1bcf83f92271f9dae1b8e1b6884 Mon Sep 17 00:00:00 2001 From: 0neStep <146049978+AperturePlus@users.noreply.github.com> Date: Fri, 22 May 2026 17:38:28 +0800 Subject: [PATCH 001/123] changed lauch script --- app/pyproject.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/pyproject.toml b/app/pyproject.toml index 6a8e1c7..2fa6b3a 100644 --- a/app/pyproject.toml +++ b/app/pyproject.toml @@ -21,7 +21,7 @@ dependencies = [ "python-multipart>=0.0.24", ] [project.scripts] -fileflash = "fileflash.main:main" +fileflash = "fileflash.scripts.run_with_workers:main" fileflash-dev = "fileflash.scripts.run_with_workers:main" [dependency-groups] @@ -50,4 +50,4 @@ requires = ["hatchling"] build-backend = "hatchling.build" [tool.hatch.build.targets.wheel] -packages = ["src/fileflash"] \ No newline at end of file +packages = ["src/fileflash"] From 5c3ff38e08c2c63f4b63337fe04200c2348e019a Mon Sep 17 00:00:00 2001 From: 0neStep <146049978+AperturePlus@users.noreply.github.com> Date: Fri, 22 May 2026 17:38:44 +0800 Subject: [PATCH 002/123] removed mock notification --- web/src/pages/login/Login.vue | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/web/src/pages/login/Login.vue b/web/src/pages/login/Login.vue index c22443e..8824df1 100644 --- a/web/src/pages/login/Login.vue +++ b/web/src/pages/login/Login.vue @@ -56,13 +56,6 @@ async function onSubmit(payload: AuthSubmitPayload) { :initial="initial" @submit="onSubmit" > - @@ -74,23 +67,6 @@ async function onSubmit(payload: AuthSubmitPayload) { diff --git a/web/src/composables/useVideoPlayer.ts b/web/src/composables/useVideoPlayer.ts new file mode 100644 index 0000000..876b405 --- /dev/null +++ b/web/src/composables/useVideoPlayer.ts @@ -0,0 +1,75 @@ +import { onBeforeUnmount, ref, type Ref } from 'vue'; +import Hls from 'hls.js'; +import Plyr from 'plyr'; +import 'plyr/dist/plyr.css'; + +export interface MountVideoOptions { + source: string; + isHls: boolean; + onFatalError?: (message: string) => void; +} + +export function useVideoPlayer(videoRef: Ref) { + const isReady = ref(false); + let hlsPlayer: Hls | null = null; + let plyrPlayer: Plyr | null = null; + + const destroy = () => { + if (hlsPlayer) { + hlsPlayer.destroy(); + hlsPlayer = null; + } + if (plyrPlayer) { + plyrPlayer.destroy(); + plyrPlayer = null; + } + const video = videoRef.value; + if (video) { + video.removeAttribute('src'); + video.load(); + } + isReady.value = false; + }; + + const mount = ({ source, isHls, onFatalError }: MountVideoOptions) => { + const video = videoRef.value; + if (!video || !source) return; + + destroy(); + + if (isHls && Hls.isSupported()) { + hlsPlayer = new Hls({ enableWorker: true, lowLatencyMode: true }); + hlsPlayer.loadSource(source); + hlsPlayer.attachMedia(video); + hlsPlayer.on(Hls.Events.ERROR, (_event, data) => { + if (data.fatal) { + onFatalError?.('Unable to play this HLS stream.'); + } + }); + } else { + video.src = source; + } + + plyrPlayer = new Plyr(video, { + controls: [ + 'play-large', + 'play', + 'progress', + 'current-time', + 'mute', + 'volume', + 'settings', + 'pip', + 'fullscreen', + ], + settings: ['speed'], + speed: { selected: 1, options: [0.75, 1, 1.25, 1.5, 2] }, + keyboard: { focused: true, global: false }, + }); + isReady.value = true; + }; + + onBeforeUnmount(destroy); + + return { mount, destroy, isReady }; +} From e9a8359ac759470dbee9b787fa9c36d807def1d7 Mon Sep 17 00:00:00 2001 From: 0neStep <146049978+AperturePlus@users.noreply.github.com> Date: Sun, 24 May 2026 00:03:57 +0800 Subject: [PATCH 007/123] feat(web): integrate i18n into agent organisms - PlanInspector, SessionItem, SessionList, SkillCard, SkillEditorPanel, SkillImportPanel, TaskInputDock, TaskTimeline, TurnEntry - Update specs (SessionList.spec, SkillCard.spec, TurnEntry.spec) for i18n assertions --- .../organisms/agent/PlanInspector.vue | 24 +++++++------ .../organisms/agent/SessionItem.vue | 20 ++++++++--- .../organisms/agent/SessionList.spec.ts | 2 +- .../organisms/agent/SessionList.vue | 10 ++++-- .../organisms/agent/SkillCard.spec.ts | 4 +-- .../components/organisms/agent/SkillCard.vue | 8 +++-- .../organisms/agent/SkillEditorPanel.vue | 30 +++++++++------- .../organisms/agent/SkillImportPanel.vue | 30 +++++++++------- .../organisms/agent/TaskInputDock.vue | 19 ++++++---- .../organisms/agent/TaskTimeline.vue | 36 ++++++++++--------- .../organisms/agent/TurnEntry.spec.ts | 4 +-- .../components/organisms/agent/TurnEntry.vue | 28 ++++++++++----- 12 files changed, 132 insertions(+), 83 deletions(-) diff --git a/web/src/components/organisms/agent/PlanInspector.vue b/web/src/components/organisms/agent/PlanInspector.vue index 217e825..1af2e86 100644 --- a/web/src/components/organisms/agent/PlanInspector.vue +++ b/web/src/components/organisms/agent/PlanInspector.vue @@ -1,10 +1,14 @@ @@ -25,7 +35,7 @@ const relativeTime = (iso: string): string => { ({ describe('organisms/agent/SessionList', () => { it('renders empty placeholder when no sessions', () => { const w = mount(SessionList, { props: { sessions: [], activeId: null } }); - expect(w.text()).toContain('No sessions yet'); + expect(w.text()).toContain('暂无会话'); }); it('emits select with id when an item is clicked', async () => { diff --git a/web/src/components/organisms/agent/SessionList.vue b/web/src/components/organisms/agent/SessionList.vue index 1a14b58..075e38d 100644 --- a/web/src/components/organisms/agent/SessionList.vue +++ b/web/src/components/organisms/agent/SessionList.vue @@ -1,6 +1,7 @@ diff --git a/web/src/components/organisms/agent/SkillCard.spec.ts b/web/src/components/organisms/agent/SkillCard.spec.ts index ae0863a..8f8c463 100644 --- a/web/src/components/organisms/agent/SkillCard.spec.ts +++ b/web/src/components/organisms/agent/SkillCard.spec.ts @@ -30,8 +30,8 @@ describe('organisms/agent/SkillCard', () => { const w = mount(SkillCard, { props: { skill, editable: true } }); const buttons = w.findAll('button'); expect(buttons.length).toBeGreaterThanOrEqual(2); - const edit = buttons.find((b) => /edit/i.test(b.text()))!; - const del = buttons.find((b) => /delete/i.test(b.text()))!; + const edit = buttons.find((b) => /edit|编辑/i.test(b.text()))!; + const del = buttons.find((b) => /delete|删除/i.test(b.text()))!; await edit.trigger('click'); await del.trigger('click'); expect(w.emitted('edit')).toHaveLength(1); diff --git a/web/src/components/organisms/agent/SkillCard.vue b/web/src/components/organisms/agent/SkillCard.vue index a761ecc..4ba8955 100644 --- a/web/src/components/organisms/agent/SkillCard.vue +++ b/web/src/components/organisms/agent/SkillCard.vue @@ -1,10 +1,14 @@ diff --git a/web/src/components/organisms/agent/SkillEditorPanel.vue b/web/src/components/organisms/agent/SkillEditorPanel.vue index 5c929e2..e3eee95 100644 --- a/web/src/components/organisms/agent/SkillEditorPanel.vue +++ b/web/src/components/organisms/agent/SkillEditorPanel.vue @@ -3,6 +3,7 @@ import { reactive, ref, watch } from 'vue'; import Modal from '../../molecules/Modal.vue'; import Button from '../../molecules/Button.vue'; import TextField from '../../molecules/TextField.vue'; +import { useLocaleStore } from '../../../store/locale'; import type { SkillForm } from '../../../composables/useAgentSkills'; const props = defineProps<{ @@ -17,6 +18,9 @@ const emit = defineEmits<{ submit: [form: SkillForm]; }>(); +const localeStore = useLocaleStore(); +const t = localeStore.t; + const local = reactive({ name: '', description: '', @@ -48,14 +52,14 @@ const parseJsonOrError = (raw: string, label: string): Record => { try { return raw.trim() ? JSON.parse(raw) : {}; } catch { - throw new Error(`${label} JSON invalid`); + throw new Error(t('agent.v2.skills.editor.error.invalidJson').replace('{field}', label)); } }; const onSubmit = () => { error.value = null; if (!local.name.trim() || !local.description.trim()) { - error.value = 'Name and description are required.'; + error.value = t('agent.v2.skills.editor.error.required'); return; } let plan: Record, inputs: Record, outputs: Record; @@ -82,30 +86,30 @@ const onSubmit = () => {