---
phase: 06-
plan: 02
type: execute
wave: 2
depends_on:
  - 06-01
files_modified:
  - frontend/src/components/workspace/input-box.tsx
  - frontend/src/components/ai-elements/prompt-input.tsx
  - frontend/src/core/uploads/hooks.ts
  - frontend/src/components/ui/dropdown-menu.tsx
autonomous: true
requirements:
  - ATREF-01
  - ATREF-02
must_haves:
  truths:
    - "用户在输入框输入 @ 后可立即看到当前线程文件候选，并可继续输入过滤。"
    - "用户选择候选后在输入区看到可删除 chip，而不是纯文本 @文件名。"
    - "同名文件可通过类型徽标和路径尾段区分，且超过 10 个引用会被阻止。"
  artifacts:
    - path: "frontend/src/components/workspace/input-box.tsx"
      provides: "@候选收集、过滤、dropdown 展示、chip 管理"
    - path: "frontend/src/components/ai-elements/prompt-input.tsx"
      provides: "textarea 键盘事件和 chip 删除协同"
  key_links:
    - from: "frontend/src/components/workspace/input-box.tsx"
      to: "frontend/src/core/uploads/hooks.ts"
      via: "useUploadedFiles(threadId)"
      pattern: "useUploadedFiles"
    - from: "frontend/src/components/workspace/input-box.tsx"
      to: "frontend/src/components/ui/dropdown-menu.tsx"
      via: "DropdownMenu 候选面板"
      pattern: "DropdownMenuContent"
---

<objective>
实现输入态 `@` 引用交互，覆盖候选展示、过滤、选择、chip、上限与键盘操作。

Purpose: 把 D-01/D-02/D-03/D-04/D-08/D-09 直接转成可见交互，且不突破线程边界。
Output: 输入框引用交互闭环（dropdown + chip + 限制策略）。
</objective>

<execution_context>
@/home/mt/.codex/get-shit-done/workflows/execute-plan.md
@/home/mt/.codex/get-shit-done/templates/summary.md
</execution_context>

<context>
@.planning/PROJECT.md
@.planning/ROADMAP.md
@.planning/phases/06-/06-CONTEXT.md
@.planning/phases/06-/06-RESEARCH.md
@frontend/src/components/workspace/input-box.tsx
@frontend/src/components/ai-elements/prompt-input.tsx
@frontend/src/core/uploads/hooks.ts
@frontend/src/components/workspace/chats/chat-box.tsx
@frontend/src/components/ui/dropdown-menu.tsx
</context>

<interfaces>
From `frontend/src/core/uploads/hooks.ts`:
```typescript
export function useUploadedFiles(threadId: string)
```

From `frontend/src/components/ui/dropdown-menu.tsx`:
```typescript
export {
  DropdownMenu,
  DropdownMenuTrigger,
  DropdownMenuContent,
  DropdownMenuItem
}
```

From `frontend/src/components/workspace/chats/chat-box.tsx`:
```typescript
const { thread } = useThread();
// artifacts 来源：thread.values.artifacts
```
</interfaces>

<tasks>

<task type="auto">
  <name>Task 1: 构建 thread-scoped @ 候选聚合与 dropdown 触发过滤</name>
  <files>frontend/src/components/workspace/input-box.tsx, frontend/src/core/uploads/hooks.ts</files>
  <read_first>
    - frontend/src/components/workspace/input-box.tsx
    - frontend/src/components/workspace/chats/chat-box.tsx
    - frontend/src/core/uploads/hooks.ts
    - frontend/src/components/ui/dropdown-menu.tsx
    - .planning/phases/06-/06-CONTEXT.md
  </read_first>
  <action>在 `InputBox` 增加 `referenceCandidates` 与 `mentionQuery` 状态；候选源固定为当前 `threadId` 的 `artifacts + uploads`（按 D-01）；检测 textarea 输入中最后一个 `@` token：输入 `@` 立即打开 dropdown（按 D-02），继续输入做前缀过滤；候选项渲染包含“文件名 + 类型徽标 + 路径尾段”（按 D-04）；面板必须使用 `DropdownMenu*` 组件（按 D-09），禁止自定义绝对定位浮层。</action>
  <acceptance_criteria>
    - `rg -n "useUploadedFiles\\(" frontend/src/components/workspace/input-box.tsx` 命中候选上传源。
    - `rg -n "thread\\.values\\.artifacts|artifacts" frontend/src/components/workspace/input-box.tsx` 命中 artifact 源。
    - `rg -n "DropdownMenu|DropdownMenuContent|DropdownMenuItem" frontend/src/components/workspace/input-box.tsx` 命中 dropdown 实现。
    - `rg -n "mentionQuery|@\"|lastIndexOf\\(\"@\"" frontend/src/components/workspace/input-box.tsx` 命中触发过滤逻辑。
  </acceptance_criteria>
  <verify>
    <automated>cd frontend && pnpm -s typecheck</automated>
  </verify>
  <done>输入 `@` 可见 thread 内候选，过滤生效，且候选 UI 满足去歧义展示。</done>
</task>

<task type="auto">
  <name>Task 2: 实现 chip 选择/删除、上限控制与键盘行为</name>
  <files>frontend/src/components/workspace/input-box.tsx, frontend/src/components/ai-elements/prompt-input.tsx</files>
  <read_first>
    - frontend/src/components/workspace/input-box.tsx
    - frontend/src/components/ai-elements/prompt-input.tsx
    - .planning/phases/06-/06-CONTEXT.md
    - .planning/phases/06-/06-RESEARCH.md
  </read_first>
  <action>选中候选后写入 `references` 状态并在输入区展示可删除 chip（按 D-03），不把引用作为纯文本提交；按 `source+path` 去重；引用数量达到 10 时用 `toast.error` 提示并阻止新增（按 D-08）；实现键盘交互：`ArrowUp/ArrowDown` 切换候选、`Enter` 选中、`Escape` 关闭、空输入时 `Backspace` 删除最后一个 chip；与 IME 组合输入状态兼容（`isComposing` 时不触发选择提交）。</action>
  <acceptance_criteria>
    - `rg -n "references|chip|Tag" frontend/src/components/workspace/input-box.tsx` 命中 chip 渲染与状态。
    - `rg -n "10|MAX_.*REFERENCE|超限|toast\\.error" frontend/src/components/workspace/input-box.tsx` 命中上限控制。
    - `rg -n "ArrowDown|ArrowUp|Escape|Backspace|isComposing" frontend/src/components/workspace/input-box.tsx frontend/src/components/ai-elements/prompt-input.tsx` 命中键盘实现。
  </acceptance_criteria>
  <verify>
    <automated>cd frontend && pnpm -s typecheck</automated>
  </verify>
  <done>chip 交互、上限、键盘行为与 IME 保护均实现并可编译。</done>
</task>

</tasks>

<threat_model>
## Trust Boundaries

| Boundary | Description |
|----------|-------------|
| textarea 输入→候选匹配 | 用户输入内容驱动候选过滤 |
| 候选列表→引用状态 | 可展示文件元数据进入可提交状态 |

## STRIDE Threat Register

| Threat ID | Category | Component | Disposition | Mitigation Plan |
|-----------|----------|-----------|-------------|-----------------|
| T-06-02-01 | I | `input-box.tsx` 候选聚合 | mitigate | 候选严格绑定当前 `threadId` 的 artifacts/uploads，禁止全局池（ASVS V4，per D-01）。 |
| T-06-02-02 | T | `@` 查询与选择 | mitigate | 选择仅可来自候选对象，提交不信任自由文本路径（ASVS V5）。 |
| T-06-02-03 | D | 引用数量控制 | mitigate | 强制 10 个上限并阻止继续添加，降低前端/提交膨胀风险（per D-08）。 |
</threat_model>

<verification>
- `cd frontend && pnpm -s typecheck`
- `cd frontend && pnpm -s lint -- src/components/workspace/input-box.tsx src/components/ai-elements/prompt-input.tsx`
</verification>

<success_criteria>
- `@` 触发、过滤、选择、关闭行为完整可用。
- 引用展示为 chip，支持删除、去重、键盘操作。
- 候选来源与组件实现满足 D-01/D-09 的硬约束。
</success_criteria>

<output>
After completion, create `.planning/phases/06-/06-02-SUMMARY.md`
</output>
