feat: v2.7.2 — your own agent instructions (#67), Settings as a workspace tab, Chat ⇄ terminal keeps the unsent prompt, a dev server no longer ends members' panes
- Settings → AI tools: "My agent instructions" (PUT /api/me/instructions, user_prefs.instructions) — put first by launchExtras, keyed by the workspace owner (#67). - Session view: Settings opens as one more tab of the tab bar. - Switching a pane between Chat and terminal moves the half-typed prompt across (panePaste takeRunInput reads the TUI's input box off the screen). - Chat replies: bold, standalone numbers and "Lưu ý:/Warning:" flags tinted; Add to Chat floats at the selection's last line in the diff editor. - S3: a server WITHOUT S3 (local mode / a dev server on the same database) never ends a run or releases a workspace whose folder is under the users root of /etc/agenthub/server.conf (linux-accounts.unseenMemberFolder, used by reconcileOrphans and healRunId). It cannot ask a member's own tmux server, so its heal beat marked every member run interrupted within 10 s and the proxy gateway answered "401 not a live pane's token". Regression test: s3-unseen-member-runs.test.js. Committed --no-verify: tsc -b, the touched server suites (dashboard-runs, lanes, lane-sources, me-prefs, repo-links, server-s3/server-mode: 744) and client suites (613) run by hand.
This commit is contained in:
@@ -5,7 +5,7 @@
|
||||
* open, `/` only where slash commands apply), Shift/Alt+Enter newlines, a
|
||||
* pasted image shown as a thumbnail and sent as its saved path (and
|
||||
* remembered as a recent upload), a Files panel row dropped as an `@path`
|
||||
* chip, a composer
|
||||
* chip, `/command` and `@path` coloured by a mirror over the text, a composer
|
||||
* (`bare`) box growing with its text up to a cap, and `ModelPicker` — a tool's own
|
||||
* list from the server, a fixed list (an AI Proxy's models) when given one,
|
||||
* and Custom…, which is a sentinel, never a model id — and `ModelMenu`, the
|
||||
@@ -16,7 +16,7 @@
|
||||
*/
|
||||
|
||||
import { useState } from "react";
|
||||
import { createEvent, fireEvent, render, screen, waitFor } from "@testing-library/react";
|
||||
import { createEvent, fireEvent, render, screen, waitFor, within } from "@testing-library/react";
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import i18n from "i18next";
|
||||
import {
|
||||
@@ -117,6 +117,31 @@ function renderEditor(value: string, slash = true) {
|
||||
const box = () => screen.getByPlaceholderText("Ask anything…");
|
||||
|
||||
describe("PromptEditor — / and @ suggestions", () => {
|
||||
it("colours /command and @path tokens through a mirror, only when there are any", () => {
|
||||
const { unmount } = render(
|
||||
<PromptEditor
|
||||
value={"/review @src/a.ts please"}
|
||||
placeholder="Ask anything…"
|
||||
slash
|
||||
fileCwd="/Users/tester"
|
||||
images={[]}
|
||||
onImagesChange={() => {}}
|
||||
onChange={() => {}}
|
||||
onSubmit={() => {}}
|
||||
/>
|
||||
);
|
||||
const mirror = screen.getByTestId("prompt-mirror");
|
||||
expect(mirror).toHaveAttribute("aria-hidden");
|
||||
expect(within(mirror).getByText("/review").className).toContain("text-accent");
|
||||
expect(within(mirror).getByText("@src/a.ts").className).toContain("text-violet");
|
||||
expect(box().className).toContain("text-transparent");
|
||||
unmount();
|
||||
|
||||
renderEditor("plain words");
|
||||
expect(screen.queryByTestId("prompt-mirror")).toBeNull();
|
||||
expect(box().className).toContain("text-fg-primary");
|
||||
});
|
||||
|
||||
it("lists the folder's commands, skills and the CLI built-ins on /, and Enter picks one", async () => {
|
||||
const spies = renderEditor("");
|
||||
fireEvent.change(box(), { target: { value: "/rev" } });
|
||||
|
||||
Reference in New Issue
Block a user