feat: v2.7.8 — Artifacts hub, clone related repos as extra folders, quieter resume prompt
- Artifacts (/artifacts): claude.ai pages sessions publish (captured from the Artifact tool's hook), pinned workspace files, skills and plugins, each kept as a snapshot; shared ones appear in a Hub and a skill or plugin installs into the viewer's own account (server/lib/artifacts.js, /api/artifacts, docs/plans/artifacts/). - Workspace extra folders: clone one or more related repos beside the workspace and add them in one step (POST /api/lanes/:id/sources/clone). - A pane that ended by itself while tmux kept running is no longer offered for resume (tmux.serverStartedAt in reconcileOrphans). - Changes panel: a folder that is not a git repo opens on Files, and its files open from there. - Plus the parallel sessions' work in this tree: File Explorer button in the panel header, user delete, RSA SSH keys, chat/terminal and pet fixes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -69,6 +69,7 @@ import {
|
||||
addAttachments,
|
||||
droppedAttachments,
|
||||
droppedSkill,
|
||||
droppedText,
|
||||
SKILL_MIME,
|
||||
rememberUploads,
|
||||
} from "../../lib/promptAttach";
|
||||
@@ -412,7 +413,8 @@ export function PromptEditor({
|
||||
// else a `bare` editor's parent, the box every caller draws around it and
|
||||
// its toolbar — not only on the textarea: a panel row (`ATTACH_MIME`)
|
||||
// becomes an `@path` chip, a skill (`SKILL_MIME`) the prompt's leading
|
||||
// `/command`, a file is uploaded.
|
||||
// `/command`, a file is uploaded, a local `file://` list an `@path` chip
|
||||
// and any other text is inserted.
|
||||
const rootRef = useRef<HTMLDivElement | null>(null);
|
||||
const dropRef = useRef<(e: DragEvent) => void>(() => {});
|
||||
dropRef.current = (e) => {
|
||||
@@ -425,6 +427,17 @@ export function PromptEditor({
|
||||
e.preventDefault();
|
||||
onChange(`/${skill} ${value.replace(/^\s+/, "")}`);
|
||||
} else if (attachImages(e.dataTransfer?.files)) e.preventDefault();
|
||||
else {
|
||||
// Only text (a file manager's or an editor's `file://` list, a
|
||||
// selection, a link): what the terminal beneath would paste.
|
||||
// On the textarea itself the browser inserts text at the drop point.
|
||||
const dropped = droppedText(e.dataTransfer);
|
||||
if (!dropped || ("text" in dropped && e.target === taRef.current)) return;
|
||||
e.preventDefault();
|
||||
if ("attachments" in dropped)
|
||||
onImagesChange((prev) => addAttachments(prev, dropped.attachments));
|
||||
else insert(dropped.text);
|
||||
}
|
||||
};
|
||||
useEffect(() => {
|
||||
const zone =
|
||||
@@ -433,7 +446,8 @@ export function PromptEditor({
|
||||
if (!zone) return;
|
||||
const over = (e: DragEvent) => {
|
||||
const types = e.dataTransfer?.types ?? [];
|
||||
if (![ATTACH_MIME, SKILL_MIME, "Files"].some((m) => types.includes(m))) return;
|
||||
const accepts = [ATTACH_MIME, SKILL_MIME, "Files", "text/uri-list", "text/plain"];
|
||||
if (!accepts.some((m) => types.includes(m))) return;
|
||||
e.preventDefault();
|
||||
e.dataTransfer!.dropEffect = "copy";
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user