Файли
openidea/src/features/agents/references.ts
T
l0ng-ai c199a56c3f feat(agents): Dispatch and supervise coding agents over ACP
Adds an Agents feature: start coding agents (Claude Code, Codex, Gemini CLI,
Copilot, Cursor, OpenCode and more, plus custom ones from
<config>/agents/<id>.toml) on a task, each in its own git worktree or in the
checkout, and follow them from the IDE.

- ide-agent crate: one ACP agent process per task (newline-delimited
  JSON-RPC), the timeline folded from session/update, permission requests,
  session settings (model, mode, thinking effort), slash commands, context
  usage, a message queue with "send now", @-referenced files (embedded when
  the agent takes embedded context) and images. Tasks persist and their
  sessions are reloaded with session/load.
- Agents tool window grouped by what each task needs; a task opens as an
  editor tab with the conversation, a permission banner and its changes
  (diff against the task's base). New Task is an editor page.
- Composer: @ file references from the project index, / commands,
  up/down history, pasted or dropped images, Shift+Tab cycles the mode.
  "Send to Agent" adds the editor selection or Project view files.
- Editor: the Switcher lists every open editor, not only files; editor
  kinds can mark their tabs restorable, so agent tabs survive a reload.
- Select popups size to fit short option details.
2026-10-27 14:27:57 +08:00

37 рядки
1.6 KiB
TypeScript

/** "Send to Agent": the editor selection or Project view files as `@` references. */
import { activeEditor } from "@/editor/api";
import { useProject } from "@/platform/project";
import { isVirtualUri } from "@/platform/virtualDocs";
import { mentionOf } from "./composerModel";
import { addReferences } from "./store";
const relTo = (root: string, path: string) => (path.startsWith(`${root}/`) ? path.slice(root.length + 1) : null);
/** The active editor's file, with the selected lines when there is a selection. */
export function sendSelection(): boolean {
const handle = activeEditor();
const root = useProject.getState().project?.root;
if (!handle || !root || isVirtualUri(handle.ctx.path)) return false;
const rel = relTo(root, handle.ctx.path);
if (!rel) return false;
const { state } = handle.view;
const sel = state.selection.main;
// A selection ending at a line start does not include that line.
const end = sel.to > sel.from && state.doc.lineAt(sel.to).from === sel.to ? sel.to - 1 : sel.to;
const lines = sel.empty ? undefined : { from: state.doc.lineAt(sel.from).number, to: state.doc.lineAt(end).number };
addReferences([{ path: handle.ctx.path, rel, mention: mentionOf(rel, lines) }]);
return true;
}
/** Files and folders from the Project view. */
export function sendPaths(paths: readonly string[]): boolean {
const root = useProject.getState().project?.root;
if (!root) return false;
const refs = paths.flatMap((path) => {
const rel = relTo(root, path);
return rel ? [{ path, rel, mention: mentionOf(rel) }] : [];
});
if (refs.length) addReferences(refs);
return refs.length > 0;
}