diff --git a/apps/docs/content/docs/assigning-issues.ja.mdx b/apps/docs/content/docs/assigning-issues.ja.mdx index 12b78e765..a8af58c01 100644 --- a/apps/docs/content/docs/assigning-issues.ja.mdx +++ b/apps/docs/content/docs/assigning-issues.ja.mdx @@ -13,12 +13,11 @@ import { Callout } from "fumadocs-ui/components/callout"; 1. タスクを開き、**担当者**をクリックします。 2. エージェントまたはスクワッドを選択します。 -3. 確認ダイアログで、これから開始するエージェントを確認します。 -4. 必要に応じて引き継ぎメモを記入し、**開始**を選択します。 +3. 確認ダイアログで、これから開始するエージェントを確認し、**開始**を選択します。 -![割り当ての確認ダイアログ:引き継ぎメモを記入するか、まだ開始しないことを選べます](/images/docs/assign-confirm-dialog.webp) +![割り当ての確認ダイアログ:割り当てを確認するか、まだ開始しないことを選べます](/images/docs/assign-confirm-dialog.webp) -引き継ぎメモは今回の実行にのみ適用されます。範囲、順序、今回とくに注目してほしい点の補足に使ってください。長期的に有効な要件は、タスク本文、プロジェクトの説明、またはエージェントの指示に書きます。 +エージェントに伝えたいことは、タスク本文とその議論、あるいはプロジェクトの説明やエージェントの指示に書きます。 スクワッドに割り当てると、タスクの担当者はスクワッドになり、最初に実行を開始するのはスクワッドのリーダーです。リーダーはスクワッドの運用方針に従って、他のメンバーに作業を渡すかどうかを判断します。 @@ -43,7 +42,7 @@ Multica はエージェントのために[作業](/tasks)を作成します。 `backlog` のタスクも、割り当てだけでは実行を開始しません。タスクを `backlog` から移動するか、コメントで担当者に依頼を続けたときに、はじめて後続の実行が生まれます。 -すでにエージェントまたはスカッドの担当者がいる作業を `backlog` から移動すると、同じ確認ダイアログが開きます。実行を開始するのはこのステータス変更そのものなので、同じ引き継ぎメモを書けますし、**まだ開始しない**も同じように使えます(ステータスだけ変えて、エージェントは起こしません)。この確認ダイアログは、`backlog`・`done`・`cancelled` 以外のカテゴリへ移動するときに表示されます。 +すでにエージェントまたはスカッドの担当者がいる作業を `backlog` から移動すると、同じ確認ダイアログが開きます。実行を開始するのはこのステータス変更そのものなので、**まだ開始しない**も同じように使えます(ステータスだけ変えて、エージェントは起こしません)。この確認ダイアログは、`backlog`・`done`・`cancelled` 以外のカテゴリへ移動するときに表示されます。 この挙動は `backlog` カテゴリだけで、そのカテゴリの[カスタムステータス](/issues#カスタムステータス)もまったく同じように振る舞います。すでに `done` や `cancelled` にあるタスクは、エージェントに割り当て・再割り当てすると、すぐに実行が開始されます。 diff --git a/apps/docs/content/docs/assigning-issues.ko.mdx b/apps/docs/content/docs/assigning-issues.ko.mdx index 7ff9581b7..d052303ba 100644 --- a/apps/docs/content/docs/assigning-issues.ko.mdx +++ b/apps/docs/content/docs/assigning-issues.ko.mdx @@ -13,12 +13,11 @@ import { Callout } from "fumadocs-ui/components/callout"; 1. 태스크를 열고 **담당자**를 클릭합니다. 2. 에이전트 또는 스쿼드를 선택합니다. -3. 확인 창에서 시작될 에이전트를 확인합니다. -4. 필요하면 인계 설명을 입력한 뒤 **시작**을 선택합니다. +3. 확인 창에서 시작될 에이전트를 확인한 뒤 **시작**을 선택합니다. -![할당 확인 창: 인계 설명을 입력하거나 지금은 시작하지 않도록 선택할 수 있습니다.](/images/docs/assign-confirm-dialog.webp) +![할당 확인 창: 할당을 확인하거나 지금은 시작하지 않도록 선택할 수 있습니다.](/images/docs/assign-confirm-dialog.webp) -인계 설명은 이번 실행에만 사용됩니다. 범위, 순서, 이번에 특히 주의할 점을 보충하기에 적합합니다. 장기적으로 적용할 요구 사항은 태스크, 프로젝트 설명, 에이전트 지시문에 작성하세요. +에이전트가 알아야 할 내용은 태스크 본문과 그 논의, 또는 프로젝트 설명과 에이전트 지시문에 작성하세요. 스쿼드에 할당하면 태스크 담당자는 스쿼드가 되고 스쿼드 리더가 먼저 실행을 시작합니다. 리더는 스쿼드의 작업 방식에 따라 다른 멤버에게 넘길지 판단합니다. @@ -43,7 +42,7 @@ Multica가 에이전트의 [작업](/tasks)를 만듭니다. 온라인 런타임 `backlog` 상태에서도 에이전트를 할당하는 것만으로 실행이 시작되지 않습니다. 태스크를 `backlog`에서 다른 상태로 옮기거나 댓글에서 담당자에게 추가 요청을 해야 이후 실행이 생성됩니다. -이미 에이전트나 스쿼드 담당자가 있는 작업을 `backlog` 밖으로 옮기면 같은 확인 대화상자가 열립니다. 실행을 시작하는 것이 바로 이 상태 변경이므로 동일한 인계 메모를 남길 수 있고, **아직 시작 안 함**도 그대로 사용할 수 있습니다(상태만 옮기고 에이전트는 깨우지 않습니다). 이 대화상자는 `backlog`·`done`·`cancelled` 이외 카테고리로 옮길 때 나타납니다. +이미 에이전트나 스쿼드 담당자가 있는 작업을 `backlog` 밖으로 옮기면 같은 확인 대화상자가 열립니다. 실행을 시작하는 것이 바로 이 상태 변경이므로 **아직 시작 안 함**도 그대로 사용할 수 있습니다(상태만 옮기고 에이전트는 깨우지 않습니다). 이 대화상자는 `backlog`·`done`·`cancelled` 이외 카테고리로 옮길 때 나타납니다. 이 효과는 `backlog` 카테고리에만 적용되며, 그 카테고리의 [사용자 지정 상태](/issues#사용자-지정-상태)도 똑같이 동작합니다. 이미 `done` 또는 `cancelled` 상태인 태스크도 에이전트에게 할당하거나 다시 할당하면 즉시 실행이 시작됩니다. diff --git a/apps/docs/content/docs/assigning-issues.mdx b/apps/docs/content/docs/assigning-issues.mdx index 770f57937..27da7242e 100644 --- a/apps/docs/content/docs/assigning-issues.mdx +++ b/apps/docs/content/docs/assigning-issues.mdx @@ -13,12 +13,11 @@ When you only need the agent to handle one specific request without changing own 1. Open an issue and click **Assignee**. 2. Pick an agent or a squad. -3. Review the agent about to start in the confirmation dialog. -4. Add a handoff note if needed, then choose **Start**. +3. Review the agent about to start in the confirmation dialog, then choose **Start**. -![Assignment confirmation dialog: add a handoff note, or choose not to start yet](/images/docs/assign-confirm-dialog.webp) +![Assignment confirmation dialog: confirm the assignment, or choose not to start yet](/images/docs/assign-confirm-dialog.webp) -The handoff note applies to this run only — use it for scope, ordering, or what to focus on this time. Requirements that should hold long term belong in the issue, the project description, or the agent instructions. +Everything the agent should know about this work belongs in the issue itself — its description, its discussion, or the project description and agent instructions. When you assign to a squad, the squad becomes the issue's assignee and the squad leader starts first. It decides whether to hand work to other members, following how the squad operates. @@ -47,7 +46,7 @@ When the assignee is a [squad](/squads), the same rule applies: Multica enqueues `backlog` doesn't start a run on assignment either. Execution only follows after you move the issue out of `backlog`, or ask the assignee for something in a follow-up comment. -When the issue already has an agent or squad owner, moving it out of `backlog` opens the same dialog: that status change is what starts the run, so it offers the same handoff note and the same **Don't start yet**, which moves the issue without waking the agent. The dialog appears for every target outside the `backlog`, `done`, and `cancelled` categories. +When the issue already has an agent or squad owner, moving it out of `backlog` opens the same dialog: that status change is what starts the run, so it offers the same **Don't start yet**, which moves the issue without waking the agent. The dialog appears for every target outside the `backlog`, `done`, and `cancelled` categories. Only the `backlog` category works this way, and a [custom status](/issues#custom-statuses) in that category behaves identically. Issues already in `done` or `cancelled` still start a run immediately when assigned or reassigned to an agent. diff --git a/apps/docs/content/docs/assigning-issues.zh.mdx b/apps/docs/content/docs/assigning-issues.zh.mdx index 0b2d0a2cc..0bed38c74 100644 --- a/apps/docs/content/docs/assigning-issues.zh.mdx +++ b/apps/docs/content/docs/assigning-issues.zh.mdx @@ -13,12 +13,11 @@ import { Callout } from "fumadocs-ui/components/callout"; 1. 打开一条任务,点击**负责人**。 2. 选择一个智能体或小队。 -3. 在确认窗口中检查即将启动的智能体。 -4. 如有必要,填写一段交接说明,然后选择**开始**。 +3. 在确认窗口中检查即将启动的智能体,然后选择**开始**。 -![分配确认窗:可填写交接说明,或选择暂不开始](/images/docs/assign-confirm-dialog.webp) +![分配确认窗:确认分配,或选择暂不开始](/images/docs/assign-confirm-dialog.webp) -交接说明只用于这一次执行,适合补充范围、顺序或本次的注意重点。长期有效的要求写进任务、项目说明或智能体指令中。 +这次执行需要智能体知道的信息,都写在任务本身——它的说明、讨论,或者项目说明与智能体指令中。 分配给小队时,任务的负责人是小队,首先开始执行的是小队 leader。它会按照小队的工作方式判断是否需要交给其他成员。 @@ -47,7 +46,7 @@ Multica 会为智能体创建一条[Task](/tasks)。在线运行时领取 task `backlog` 也不会因为分配智能体而启动执行。把任务移出 `backlog`,或者在评论中继续向负责人提出要求后,才会产生后续执行。 -如果任务已经有智能体或小队负责人,把它移出 `backlog` 会弹出同一个确认窗:真正启动执行的正是这次状态变更,所以同样可以填写交接说明,也同样有**暂不开始**——只改状态,不叫醒智能体。目标状态只要不属于 `backlog`、`done`、`cancelled` 分类,都会弹这个确认窗。 +如果任务已经有智能体或小队负责人,把它移出 `backlog` 会弹出同一个确认窗:真正启动执行的正是这次状态变更,所以同样有**暂不开始**——只改状态,不叫醒智能体。目标状态只要不属于 `backlog`、`done`、`cancelled` 分类,都会弹这个确认窗。 只有 `backlog` 分类有这个效果,该分类下的[自定义状态](/issues#自定义状态)表现完全一致。已经处于 `done` 或 `cancelled` 的任务,分配或重新分配给智能体时同样会立即开始执行。 diff --git a/apps/docs/public/images/docs/assign-confirm-dialog.webp b/apps/docs/public/images/docs/assign-confirm-dialog.webp index d0a71fcf2..b97f1150f 100644 Binary files a/apps/docs/public/images/docs/assign-confirm-dialog.webp and b/apps/docs/public/images/docs/assign-confirm-dialog.webp differ diff --git a/packages/core/api/schemas.test.ts b/packages/core/api/schemas.test.ts index 96442deaa..d22714bc2 100644 --- a/packages/core/api/schemas.test.ts +++ b/packages/core/api/schemas.test.ts @@ -478,14 +478,14 @@ describe("IssueTriggerPreviewSchema", () => { it("parses a well-formed response", () => { const parsed = IssueTriggerPreviewSchema.parse({ triggers: [ - { issue_id: "i1", agent_id: "a1", source: "assign", handoff_supported: true }, - { issue_id: "i2", agent_id: "a2", source: "status", handoff_supported: false }, + { issue_id: "i1", agent_id: "a1", source: "assign" }, + { issue_id: "i2", agent_id: "a2", source: "status" }, ], total_count: 2, }); expect(parsed.total_count).toBe(2); expect(parsed.triggers).toHaveLength(2); - expect(parsed.triggers[0]).toMatchObject({ issue_id: "i1", agent_id: "a1", source: "assign", handoff_supported: true }); + expect(parsed.triggers[0]).toMatchObject({ issue_id: "i1", agent_id: "a1", source: "assign" }); }); it("defaults missing top-level fields (empty / older backend)", () => { @@ -500,7 +500,6 @@ describe("IssueTriggerPreviewSchema", () => { issue_id: "i1", agent_id: "", source: "", - handoff_supported: false, }); }); diff --git a/packages/core/api/schemas.ts b/packages/core/api/schemas.ts index 05350ab69..0bb00c902 100644 --- a/packages/core/api/schemas.ts +++ b/packages/core/api/schemas.ts @@ -1073,7 +1073,6 @@ const IssueTriggerPreviewItemSchema = z.object({ issue_id: z.string(), agent_id: z.string().default(""), source: z.string().default(""), - handoff_supported: z.boolean().default(false), }).loose(); export const IssueTriggerPreviewSchema = z.object({ @@ -1767,7 +1766,6 @@ export const AgentTaskSchema = z.object({ coalesced_comment_ids: OptionalStringArraySchema, delivered_comment_ids: OptionalStringArraySchema, trigger_summary: z.string().optional(), - handoff_note: z.string().optional(), kind: z.string().optional(), work_dir: z.string().optional().catch(undefined), relative_work_dir: z.string().optional().catch(undefined), diff --git a/packages/core/issues/mutations.ts b/packages/core/issues/mutations.ts index a4b825180..4b8365925 100644 --- a/packages/core/issues/mutations.ts +++ b/packages/core/issues/mutations.ts @@ -132,15 +132,14 @@ export function useUpdateIssue() { return api.moveIssue(id, { ...target, ...moveIntent }); }, onMutate: ({ id, move_intent: _moveIntent, ...data }) => { - // suppress_run / handoff_note are write-time control fields, not Issue - // columns. description_base is merge metadata, while description itself + // suppress_run is a write-time control field, not an Issue column. + // description_base is merge metadata, while description itself // is resolved against that base on the server and therefore is not safe // to predict optimistically. Keep the authoritative raw description in // cache so hidden channel-media markers remain available as the base for // a rapid follow-up edit. mutationFn still sends the full payload. const { suppress_run: _suppressRun, - handoff_note: _handoffNote, description: _description, description_base: _descriptionBase, title_base: _titleBase, @@ -251,7 +250,6 @@ export function useUpdateIssue() { // is the plain surgical patch it always was. const { suppress_run: _suppressRun, - handoff_note: _handoffNote, description_base: _descriptionBase, move_intent: _moveIntent, id: _id, @@ -445,7 +443,6 @@ export function useBatchUpdateIssues() { // until a refetch returns the committed result. const { suppress_run: _suppressRun, - handoff_note: _handoffNote, description: _description, description_base: _descriptionBase, ...patch diff --git a/packages/core/runtimes/cli-version.test.ts b/packages/core/runtimes/cli-version.test.ts index 4e77538ac..ccc0f3cc9 100644 --- a/packages/core/runtimes/cli-version.test.ts +++ b/packages/core/runtimes/cli-version.test.ts @@ -3,9 +3,7 @@ import { chatProjectContextSupported, checkQuickCreateCliVersion, checkQuickCreateFieldsCliVersion, - handoffSupported, MIN_CHAT_PROJECT_CONTEXT_CLI_VERSION, - MIN_HANDOFF_CLI_VERSION, runtimeAdvertisesLocalWorktree, } from "./cli-version"; @@ -41,33 +39,6 @@ describe("checkQuickCreateFieldsCliVersion", () => { }); }); -// Mirrors server/pkg/agent/handoff_version_test.go so the frontend soft-gate -// signal and the server's authoritative one agree by construction. -describe("handoffSupported", () => { - it("supports a tagged release at or above the minimum", () => { - expect(handoffSupported(MIN_HANDOFF_CLI_VERSION)).toBe(true); - expect(handoffSupported("0.4.0")).toBe(true); - expect(handoffSupported("v0.3.28")).toBe(true); - }); - - it("does not support a tagged release below the minimum", () => { - expect(handoffSupported("0.3.26")).toBe(false); - expect(handoffSupported("0.2.21")).toBe(false); - }); - - it("fails closed on empty or unparsable input", () => { - expect(handoffSupported("")).toBe(false); - expect(handoffSupported(undefined)).toBe(false); - expect(handoffSupported(null)).toBe(false); - expect(handoffSupported("garbage")).toBe(false); - }); - - it("treats git-describe dev builds as supported regardless of base tag", () => { - expect(handoffSupported("v0.3.0-5-gabc1234")).toBe(true); - expect(handoffSupported("v0.1.0-235-gdaf0e935-dirty")).toBe(true); - }); -}); - describe("chatProjectContextSupported", () => { it("supports a tagged release at or above the minimum", () => { expect(chatProjectContextSupported(MIN_CHAT_PROJECT_CONTEXT_CLI_VERSION)).toBe(true); diff --git a/packages/core/runtimes/cli-version.ts b/packages/core/runtimes/cli-version.ts index bdc46830c..62dd91731 100644 --- a/packages/core/runtimes/cli-version.ts +++ b/packages/core/runtimes/cli-version.ts @@ -88,31 +88,6 @@ export function readRuntimeCliVersion(metadata: Record | undefi return typeof v === "string" ? v : ""; } -/** - * Frontend mirror of the server's `MinHandoffCLIVersion` soft gate - * (`server/pkg/agent/version.go`). The assignment handoff note is only rendered - * into the run's opening prompt by daemons at or above this multica CLI version - * (MUL-3375); older daemons silently drop it. Unlike the quick-create gate this - * never blocks the assignment — the UI just grays out the note box and warns. - * - * Keep in lockstep with the server constant; the two are enforced independently - * (the server is authoritative) but must agree so the warning matches reality. - */ -export const MIN_HANDOFF_CLI_VERSION = "0.3.28"; - -/** - * Whether a daemon-reported CLI version is new enough to render a handoff note. - * Mirrors server `agent.HandoffSupported`: missing / unparsable / below-minimum - * all degrade to `false`, and dev-built daemons (git-describe shape) always - * pass — the version string is the shared signal, so frontend and server agree - * by construction. Pure and synchronous, so the note box can settle from the - * already-warm runtime cache instead of waiting on the trigger-preview - * round-trip, exactly like the quick-create version gate. - */ -export function handoffSupported(detected: string | undefined | null): boolean { - return meetsMinCliVersion(detected, MIN_HANDOFF_CLI_VERSION); -} - /** * First release whose daemon renders the chat session's project context * (description + resources) into the run brief (PR #5765, ships in v0.4.10). @@ -121,16 +96,15 @@ export function handoffSupported(detected: string | undefined | null): boolean { * the Project Context section, so the durable description never reaches the * agent. SOFT gate: selecting a project always works; the UI only warns. * - * Frontend-only constant: unlike handoff there is no server preview endpoint - * computing this, so there is no server twin to keep in lockstep with. + * Frontend-only constant: there is no server preview endpoint computing this, + * so there is no server twin to keep in lockstep with. */ export const MIN_CHAT_PROJECT_CONTEXT_CLI_VERSION = "0.4.10"; /** * Whether a daemon-reported CLI version is new enough to inject a chat - * session's project description into the run brief. Same degrade rules as - * `handoffSupported`: missing / unparsable / below-minimum are `false`, - * dev-built daemons (git-describe shape) always pass. + * session's project description into the run brief. Missing / unparsable / + * below-minimum are `false`; dev-built daemons (git-describe shape) always pass. */ export function chatProjectContextSupported(detected: string | undefined | null): boolean { return meetsMinCliVersion(detected, MIN_CHAT_PROJECT_CONTEXT_CLI_VERSION); diff --git a/packages/core/types/agent.ts b/packages/core/types/agent.ts index b77e4deb6..4d28b5cd6 100644 --- a/packages/core/types/agent.ts +++ b/packages/core/types/agent.ts @@ -347,13 +347,6 @@ export interface AgentTask { * or deleted. */ trigger_summary?: string; - /** - * Handoff instruction the assigner attached when starting this run (MUL-3375). - * Present only on assignment-triggered runs that carried a note; the execution - * log shows it inline as the trigger reason. Absent (legacy / no note) falls - * back to the generic "initial run" label. - */ - handoff_note?: string; /** * Server-computed source discriminator used by the activity row to label * tasks that have no linked issue (so e.g. quick-create tasks render diff --git a/packages/core/types/api.ts b/packages/core/types/api.ts index d45a47a70..4e6b22a54 100644 --- a/packages/core/types/api.ts +++ b/packages/core/types/api.ts @@ -77,10 +77,6 @@ export interface UpdateIssueRequest { * MUL-3375). The assignee/status change still applies. Control field — * strip from optimistic cache patches; never written onto the Issue. */ suppress_run?: boolean; - /** Free-text handoff instruction injected into the started run's opening - * context (MUL-3375). Only consumed when a run actually starts. Control - * field — strip from optimistic cache patches. */ - handoff_note?: string; } /** @@ -112,14 +108,11 @@ export interface IssueTriggerPreviewParams { } /** One issue that WILL start a run under the prospective write. `agent_id` is - * the runnable agent (squad leader for squads). `handoff_supported` is the - * soft-gate signal: false when the target runtime is too old to render a - * handoff note (gray the note box; the assignment still works). */ + * the runnable agent (squad leader for squads). */ export interface IssueTriggerPreviewItem { issue_id: string; agent_id: string; source: string; - handoff_supported: boolean; } export interface IssueTriggerPreview { diff --git a/packages/views/chat/components/use-chat-project-context-support.ts b/packages/views/chat/components/use-chat-project-context-support.ts index b53330d2a..26673f53c 100644 --- a/packages/views/chat/components/use-chat-project-context-support.ts +++ b/packages/views/chat/components/use-chat-project-context-support.ts @@ -12,8 +12,7 @@ import { * project description into the run brief. `null` means "cannot tell" (no * agent, no bound runtime, or the runtime row not in cache yet) and must NOT * warn: this is a soft gate, and a spurious warning is worse than a - * description an old daemon drops — same policy as the handoff note gate in - * run-confirm. + * description an old daemon drops. * * Shared by both send chains (chat tab controller and floating ChatWindow) so * the resolution rule cannot drift between the two surfaces. diff --git a/packages/views/common/task-transcript/agent-transcript-dialog.tsx b/packages/views/common/task-transcript/agent-transcript-dialog.tsx index dddc41528..2cbc1771c 100644 --- a/packages/views/common/task-transcript/agent-transcript-dialog.tsx +++ b/packages/views/common/task-transcript/agent-transcript-dialog.tsx @@ -801,7 +801,7 @@ export function AgentTranscriptDialog({ ? t(($) => $.transcript.trigger_chat) : task.kind === "quick_create" ? t(($) => $.transcript.trigger_quick_create) - : task.kind === "direct" || task.handoff_note + : task.kind === "direct" ? t(($) => $.transcript.trigger_direct) : t(($) => $.transcript.trigger_initial); diff --git a/packages/views/issues/components/task-run-labels.ts b/packages/views/issues/components/task-run-labels.ts index d97863413..fdd06dd11 100644 --- a/packages/views/issues/components/task-run-labels.ts +++ b/packages/views/issues/components/task-run-labels.ts @@ -42,12 +42,6 @@ export function useTriggerText(task: AgentTask): string { } if (task.autopilot_run_id) return t(($) => $.execution_log.trigger_autopilot); if (task.trigger_comment_id) return t(($) => $.execution_log.trigger_comment); - // Assignment-triggered run that carried a handoff note: show the note inline - // (truncated by the caller) the way comment triggers show their text, so the - // row reads as the handoff instead of the generic "initial run". - if (task.handoff_note) { - return retryPrefix + t(($) => $.execution_log.trigger_handoff_prefix) + stripMentionMarkdown(task.handoff_note); - } return t(($) => $.execution_log.trigger_initial); } diff --git a/packages/views/issues/hooks/use-issue-trigger-preview.ts b/packages/views/issues/hooks/use-issue-trigger-preview.ts index 4ec4c03f7..283ddff45 100644 --- a/packages/views/issues/hooks/use-issue-trigger-preview.ts +++ b/packages/views/issues/hooks/use-issue-trigger-preview.ts @@ -22,9 +22,6 @@ export interface UseIssueTriggerPreviewResult { triggers: IssueTriggerPreviewItem[]; totalCount: number; isLoading: boolean; - /** True when every trigger's target runtime can render a handoff note, so - * the note box is safe to enable. False if any started run would drop it. */ - handoffSupported: boolean; } const EMPTY: IssueTriggerPreviewItem[] = []; @@ -90,6 +87,5 @@ export function useIssueTriggerPreview( // Only the first load (no prior data) is "loading"; a background/placeholder // refetch is not, so reveal animations gated on this never collapse mid-fetch. isLoading: enabled && previewQuery.isLoading, - handoffSupported: triggers.length > 0 && triggers.every((t) => t.handoff_supported === true), }; } diff --git a/packages/views/locales/en/issues.json b/packages/views/locales/en/issues.json index 9c69b1f8e..a53ec8024 100644 --- a/packages/views/locales/en/issues.json +++ b/packages/views/locales/en/issues.json @@ -612,7 +612,6 @@ "trigger_autopilot": "Autopilot run", "trigger_comment": "Comment trigger", "trigger_initial": "Initial run", - "trigger_handoff_prefix": "Handoff: ", "included_comments_one": "Includes {{count}} comment", "included_comments_other": "Includes {{count}} comments", "status_queued": "Queued", diff --git a/packages/views/locales/en/modals.json b/packages/views/locales/en/modals.json index 1d2759529..4c2a1a833 100644 --- a/packages/views/locales/en/modals.json +++ b/packages/views/locales/en/modals.json @@ -56,9 +56,6 @@ "assign_batch": "Assign {{count}} issues to {{name}}. They'll start right away if the run conditions are met.", "title_promote": "Start work now?", "promote_single": "Move this issue to {{status}}. {{name}} will start right away if the run conditions are met.", - "note_label": "Handoff note (optional)", - "note_placeholder": "Tell them what matters — scope, focus, or what to avoid…", - "note_unsupported": "Their runtime is too old to receive this handoff note; it may not be read.", "confirm_assign": "Confirm assignment", "confirm_promote": "Move and start", "dont_start": "Don't start yet", diff --git a/packages/views/locales/ja/issues.json b/packages/views/locales/ja/issues.json index c546ba486..4ec7a4503 100644 --- a/packages/views/locales/ja/issues.json +++ b/packages/views/locales/ja/issues.json @@ -589,7 +589,6 @@ "trigger_autopilot": "オートパイロット実行", "trigger_comment": "コメントトリガー", "trigger_initial": "初回実行", - "trigger_handoff_prefix": "引き継ぎ:", "included_comments_other": "{{count}} 件のコメントを含む", "status_queued": "待機中", "status_dispatched": "開始中", diff --git a/packages/views/locales/ja/modals.json b/packages/views/locales/ja/modals.json index 2988f3065..bde60480f 100644 --- a/packages/views/locales/ja/modals.json +++ b/packages/views/locales/ja/modals.json @@ -56,9 +56,6 @@ "assign_batch": "{{count}} 件のタスクを {{name}} に割り当てます。実行条件を満たす場合はすぐに作業を開始します。", "title_promote": "今すぐ作業を開始しますか?", "promote_single": "このタスクを {{status}} に移します。実行条件を満たす場合は {{name}} がすぐに作業を開始します。", - "note_label": "引き継ぎメモ(任意)", - "note_placeholder": "範囲・重点・触れてほしくない点などを一言で…", - "note_unsupported": "相手の実行環境が古いため、この引き継ぎメモは読み取れない可能性があります。", "confirm_assign": "割り当てを確認", "confirm_promote": "移動して開始", "dont_start": "まだ開始しない", diff --git a/packages/views/locales/ko/issues.json b/packages/views/locales/ko/issues.json index af2d5998b..268001d0e 100644 --- a/packages/views/locales/ko/issues.json +++ b/packages/views/locales/ko/issues.json @@ -589,7 +589,6 @@ "trigger_autopilot": "오토파일럿 실행", "trigger_comment": "댓글 트리거", "trigger_initial": "초기 실행", - "trigger_handoff_prefix": "인계: ", "included_comments_other": "댓글 {{count}}개 포함", "status_queued": "대기 중", "status_dispatched": "시작 중", diff --git a/packages/views/locales/ko/modals.json b/packages/views/locales/ko/modals.json index d473df568..82899b8c5 100644 --- a/packages/views/locales/ko/modals.json +++ b/packages/views/locales/ko/modals.json @@ -56,9 +56,6 @@ "assign_batch": "{{count}}개 태스크를 {{name}}에게 할당합니다. 실행 조건을 충족하면 바로 시작합니다.", "title_promote": "지금 작업을 시작할까요?", "promote_single": "이 태스크를 {{status}}(으)로 옮깁니다. 실행 조건을 충족하면 {{name}}이(가) 바로 시작합니다.", - "note_label": "인계 메모 (선택)", - "note_placeholder": "범위·핵심·건드리지 말 것 등을 한마디로…", - "note_unsupported": "상대 런타임이 오래되어 이 인계 메모를 읽지 못할 수 있습니다.", "confirm_assign": "할당 확인", "confirm_promote": "옮기고 시작", "dont_start": "아직 시작 안 함", diff --git a/packages/views/locales/zh-Hans/issues.json b/packages/views/locales/zh-Hans/issues.json index 18fd36d5c..f420718f1 100644 --- a/packages/views/locales/zh-Hans/issues.json +++ b/packages/views/locales/zh-Hans/issues.json @@ -589,7 +589,6 @@ "trigger_autopilot": "自动化运行", "trigger_comment": "评论触发", "trigger_initial": "首次运行", - "trigger_handoff_prefix": "交接:", "included_comments_other": "包含 {{count}} 条评论", "status_queued": "排队中", "status_dispatched": "启动中", diff --git a/packages/views/locales/zh-Hans/modals.json b/packages/views/locales/zh-Hans/modals.json index 12872daef..2fb46e936 100644 --- a/packages/views/locales/zh-Hans/modals.json +++ b/packages/views/locales/zh-Hans/modals.json @@ -56,9 +56,6 @@ "assign_batch": "将 {{count}} 个任务指派给 {{name}};符合运行条件时会立即开始处理。", "title_promote": "现在开始处理?", "promote_single": "把这个任务移到 {{status}};符合运行条件时 {{name}} 会立即开始处理。", - "note_label": "交接说明(可选)", - "note_placeholder": "交代一句——范围、重点、或别碰什么……", - "note_unsupported": "对方的运行环境版本较旧,这条交接说明可能读不到。", "confirm_assign": "确认指派", "confirm_promote": "移动并开始", "dont_start": "暂不开始", diff --git a/packages/views/modals/create-issue.test.tsx b/packages/views/modals/create-issue.test.tsx index 0bd886c2f..4cd4f4180 100644 --- a/packages/views/modals/create-issue.test.tsx +++ b/packages/views/modals/create-issue.test.tsx @@ -227,7 +227,6 @@ vi.mock("../issues/hooks/use-issue-trigger-preview", () => ({ triggers: [], totalCount: 0, isLoading: false, - handoffSupported: false, }), })); diff --git a/packages/views/modals/run-confirm.test.tsx b/packages/views/modals/run-confirm.test.tsx index 1cd6bd106..27526b5c4 100644 --- a/packages/views/modals/run-confirm.test.tsx +++ b/packages/views/modals/run-confirm.test.tsx @@ -8,26 +8,6 @@ import { } from "@multica/core/shortcuts"; import { RunConfirmModal } from "./run-confirm"; -// --- Warm agent / squad / runtime caches (prefetched in the real app) -------- -// The modal resolves the target runtime's cli_version locally — an agent's own -// runtime, or a squad leader's — so nothing in the dialog waits on the network. -// Tests drive the verdict by swapping the runtime's reported cli_version here. -const cache = { - agents: [{ id: "agent-1", runtime_id: "runtime-1" }] as Array<{ id: string; runtime_id: string }>, - runtimes: [{ id: "runtime-1", metadata: { cli_version: "0.4.0" } }] as Array<{ - id: string; - metadata: Record; - }>, - squads: [{ id: "squad-1", leader_id: "agent-1" }] as Array<{ id: string; leader_id: string }>, -}; -vi.mock("@tanstack/react-query", () => ({ - useQuery: ({ queryKey }: { queryKey: string[] }) => { - if (queryKey[0] === "runtimes") return { data: cache.runtimes }; - if (queryKey[0] === "workspaces" && queryKey[2] === "agents") return { data: cache.agents }; - if (queryKey[0] === "workspaces" && queryKey[2] === "squads") return { data: cache.squads }; - return { data: [] }; - }, -})); vi.mock("@multica/core/hooks", () => ({ useWorkspaceId: () => "ws-test" })); vi.mock("@multica/core/issue-statuses/hooks", () => ({ useIssueStatuses: () => @@ -48,26 +28,6 @@ vi.mock("@multica/core/issue-statuses/hooks", () => ({ }, ]), })); -vi.mock("@multica/core/workspace/queries", () => ({ - agentListOptions: (wsId: string) => ({ queryKey: ["workspaces", wsId, "agents"] }), - squadListOptions: (wsId: string) => ({ queryKey: ["workspaces", wsId, "squads"] }), -})); -// Stub the runtimes barrel: the query-options builder would otherwise drag the -// network layer in, and the deep cli-version module isn't an exported subpath. -// `handoffSupported`'s real semver/dev-build logic is exhaustively covered in -// packages/core/runtimes/cli-version.test.ts; here we only need a faithful -// stand-in for the >= 0.3.28 threshold so the cache → version → verdict wiring -// is exercised end to end. -vi.mock("@multica/core/runtimes", () => ({ - runtimeListOptions: (wsId: string) => ({ queryKey: ["runtimes", wsId, "list"] }), - readRuntimeCliVersion: (m?: { cli_version?: unknown }) => - typeof m?.cli_version === "string" ? m.cli_version : "", - handoffSupported: (v?: string | null) => { - const m = /(\d+)\.(\d+)\.(\d+)/.exec((v ?? "").trim()); - if (!m) return false; - return Number(m[1]) * 1e6 + Number(m[2]) * 1e3 + Number(m[3]) >= 3028; // 0.3.28 - }, -})); const mockUpdate = vi.fn().mockResolvedValue({ id: "issue-1" }); const mockBatch = vi.fn().mockResolvedValue({ updated: 2 }); @@ -94,9 +54,6 @@ vi.mock("../i18n", () => ({ title_assign: "Confirm assignment?", assign_single: "assign to {{name}}", assign_batch: "assign {{count}} to {{name}}", - note_label: "Handoff note", - note_placeholder: "scope...", - note_unsupported: "runtime too old", confirm_assign: "Confirm assignment", dont_start: "Don't start yet", toast_failed: "failed", @@ -130,9 +87,6 @@ vi.mock("@multica/ui/components/ui/button", () => ({ ), })); -vi.mock("@multica/ui/components/ui/textarea", () => ({ - Textarea: (props: React.TextareaHTMLAttributes) =>