Skip to content

feat(composer): @ 文件 / 技能 提及弹窗 - #979

Merged
jackwener merged 3 commits into
mainfrom
feat/composer-mentions
Jul 14, 2026
Merged

feat(composer): @ 文件 / 技能 提及弹窗#979
jackwener merged 3 commits into
mainfrom
feat/composer-mentions

Conversation

@jackwener

Copy link
Copy Markdown
Member

Chat composer now supports @ to reference workspace files and / to reference skills — the gap vs QoderWork/WorkBuddy the user reported. Interaction spec was reverse-engineered from both competitors' compiled bundles (decompiled source-level evidence); architecture mapped by a read-only recon agent; full spec + v2 path recorded in notes/composer-mentions-spec-2026-07-14.md.

Interaction (decompiled competitor rules)

  • Triggers fire only at word boundaries (foo@bar never fires). @ queries tolerate single spaces (filenames with spaces) and die on newline/double-space; / queries die on any space. One deliberate divergence from the literal competitor rule: only boundary-anchored trigger chars are candidates, so the / inside @src/app doesn't hijack the @ popup (competitor rule breaks on paths; documented).
  • Matcher: case-insensitive AND-of-substring tokens (theirs exactly).
  • Keyboard: ↑/↓ wrap, Enter/Tab select (intercepted before the send branch), Esc closes the popup only — drag-clear and streaming-stop branches untouched and contract-pinned.

V1 model (documented decision)

Composer stays an uncontrolled textarea; selections insert plain-text tokens — @<relativePath> for files (the agent reads paths via tools; no wire-format change), 使用 <技能名> 技能: for skills (house human-in-the-loop convention, never auto-send). Competitor-style contenteditable chips + typed @[file:…] tokens recorded as the v2 upgrade path.

Net-new infrastructure

  • workspace:searchFiles IPC — first workspace file search in the app: git ls-files --cached --others --exclude-standard (gitignore-honoring, untracked included) with a bounded non-git readdir fallback (≤5000 entries, node_modules/.git skipped, symlink dirs not followed, root containment), AND-of-substring filter, shorter-path ranking, cap 50.
  • use-composer-mentions.ts renderer hook (fail-soft IPC wrapper + enabled-only skills) — attachment-owner contract forbids inline window.maka state in app-shell.
  • composer-mention-popup.tsx — role=listbox overlay (absolute, constant-footprint-safe), aria-activedescendant on the textarea, 加载中…/未找到文件/暂无技能 states, 150ms debounce.

Coverage & gates

New: trigger-detection boundary matrix, matcher tests, IPC tests (gitignore/containment/symlink/fallback/cap), composer-mention contract (Enter-intercept precedes send; Esc popup-only; SSR-inert without props). One contract caught a cursor:pointer violation during development — fixed. Merged-with-main tree: desktop 2510/2510 · ui 151/151 · typecheck · check-dead-css · knip ×2 = 0. CDP evidence: @ popup listing 50 real files, arrow+Enter inserting @packages/cli/src/cli.ts ; / popup inserting 使用 深度研究 技能:.

Add composer mention popups: typing @ (at a word boundary) opens a
workspace-file reference popup, / opens a skill reference popup. v1
inserts plain-text tokens into the uncontrolled textarea —
'@<relativePath> ' for files, '使用 <skillName> 技能:' for skills
(human-in-the-loop, never auto-send). See
notes/composer-mentions-spec-2026-07-14.md.
- packages/ui/src/chat-input-behavior.ts: detectMentionTrigger +
mentionQueryMatches (pure, unit-pinned). Boundary-anchored nearest
trigger so a path-internal slash never hijacks an @ file query.
- packages/ui/src/composer-mention-popup.tsx: presentational listbox
overlay (a11y: role=listbox/option, aria-activedescendant).
- packages/ui/src/composer.tsx: trigger detection on input/keyup/
selectionchange; keyboard branch (arrows/Enter/Tab/Esc) before the
Esc-drag + send branches; splice insertion. New optional props
mentionSkills + onSearchMentionFiles, inert when absent (SSR-safe).
- apps/desktop workspace:searchFiles IPC (git ls-files + bounded walk,
path-contained), preload + global.d.ts typing, use-composer-mentions
hook, app-shell wiring.
- styles/composer-mention.css (absolute overlay; no cursor:pointer per
native-cursor convention).
Tests: trigger-detection boundary matrix + matcher; workspace file
search (git/walk/containment/cap/no_project); popup contract
(Enter-intercept precedes send, Esc closes popup only, SSR inert).
@jackwener
jackwener merged commit 8a89e0f into mainJul 14, 2026
3 checks passed
Astro-Han added a commit that referenced this pull request Jul 16, 2026
* docs: retire tracked notes into the archive
notes/ regrew tracked files after the archive README retired it as an
undocumented parallel authority. Move the simplification baseline map
(#871-#887) and the shipped composer-mentions v1 spec (#979) into
docs/archive/, register them under Former repository notes, and point
the citing source comments at the archived path.
* docs: archive computer-use chronicles and research records
The #857-#985 computer-use chain left one root document per PR:
follow-up fix records, an incident investigation, and run logs that
duplicate the kept contracts. Archive the seven chronicles, mark the
foundation contract validation matrix as the #857 split-gate baseline
(current state lives in source and contract tests), and register each
archived file in the archive README with a pointer to its current
authority.
Also archive the WorkBuddy/QoderWork reverse-engineering records (the
shipped design contract stays at docs/expert-team-runtime.md) and the
synthesis-cache benchmark log (progress belongs in issues #481/#578),
and fix the two surviving links to the moved paths.
* docs: map current contracts in the documentation README
Seventeen root documents existed outside the authority map with zero
incoming links. After archiving the chronicles, list the surviving
computer-use contracts and the expert-teams runtime contract, and
write down the maintenance rule that PR follow-up records, incident
investigations, and run logs belong in pull requests or the archive —
with notes/ and docs/local/ as untracked local scratch.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@jackwener