[codex] integrate goal command workflow (#1025)

* feat: integrate goal command workflow

* fix: keep goal done visible

* fix: add goal done slash command

* fix: promote queued message on run start
This commit is contained in:
ekko
2026-05-25 19:26:23 +08:00
committed by GitHub
parent 0eab6a1125
commit badb17cf8e
30 changed files with 1535 additions and 85 deletions
@@ -29,6 +29,13 @@ const bridgeCommands = computed(() => [
{ name: 'abort', args: '', description: t('chat.slashCommands.abort') },
{ name: 'queue', args: t('chat.slashCommandArgs.message'), description: t('chat.slashCommands.queue') },
{ name: 'plan', args: t('chat.slashCommandArgs.text'), description: t('chat.slashCommands.plan') },
{ name: 'goal', args: t('chat.slashCommandArgs.text'), description: t('chat.slashCommands.goal') },
{ name: 'goal', args: 'status', insertText: 'goal status', description: t('chat.slashCommands.goalStatus') },
{ name: 'goal', args: 'pause', insertText: 'goal pause', description: t('chat.slashCommands.goalPause') },
{ name: 'goal', args: 'resume', insertText: 'goal resume', description: t('chat.slashCommands.goalResume') },
{ name: 'goal', args: 'done', insertText: 'goal done', description: t('chat.slashCommands.goalDone') },
{ name: 'goal', args: 'clear', insertText: 'goal clear', description: t('chat.slashCommands.goalClear') },
{ name: 'subgoal', args: t('chat.slashCommandArgs.text'), description: t('chat.slashCommands.subgoal') },
{ name: 'clear', args: '', description: t('chat.slashCommands.clear') },
{ name: 'clear', args: '--history', insertText: 'clear --history', description: t('chat.slashCommands.clearHistory') },
{ name: 'title', args: t('chat.slashCommandArgs.title'), description: t('chat.slashCommands.title') },
@@ -38,7 +38,11 @@ const isAgentError = computed(() => props.message.role === "assistant" && props.
const effectiveHeadingIdPrefix = computed(() => props.headingIdPrefix || `msg-${props.message.id}`);
const isCommandMessage = computed(() => props.message.role === "command" || props.message.systemType === "command");
const isCommandError = computed(() => props.message.role === "command" && props.message.systemType === "error");
const isStatusCommand = computed(() => isCommandMessage.value && props.message.commandAction === "status");
const isStatusCommand = computed(() =>
isCommandMessage.value
&& props.message.commandAction === "status"
&& props.message.commandData?.type !== "goal"
);
const statusItems = computed(() => {
const data = props.message.commandData || {};
return [
@@ -3,8 +3,8 @@ import { ref, computed, watch, nextTick } from "vue";
import { useI18n } from "vue-i18n";
import MessageItem from "./MessageItem.vue";
import { useChatStore } from "@/stores/hermes/chat";
import thinkingVideoLight from "@/assets/thinking-light.mp4";
import thinkingVideoDark from "@/assets/thinking-dark.mp4";
import thinkingImageLight from "@/assets/thinking-light.gif";
import thinkingImageDark from "@/assets/thinking-dark.gif";
import { useTheme } from "@/composables/useTheme";
import { useToolTraceVisibility } from "@/composables/useToolTraceVisibility";
@@ -172,14 +172,12 @@ watch(currentToolCalls, () => {
/>
<Transition name="fade">
<div v-if="chatStore.isRunActive || chatStore.abortState" class="streaming-indicator">
<video
:src="isDark ? thinkingVideoDark : thinkingVideoLight"
autoplay
loop
muted
playsinline
<img
:src="isDark ? thinkingImageDark : thinkingImageLight"
alt=""
aria-hidden="true"
class="thinking-video"
/>
>
<div v-if="visibleToolCalls.length > 0 || chatStore.compressionState || chatStore.abortState" class="tool-calls-panel">
<!-- Abort indicator -->
<div v-if="chatStore.abortState" class="tool-call-item compression-item">