feat: v2.5.13 — Chat UI like Claude Desktop, one terminal size across screens, roles, daily backup, uninstall
- Chat UI (Settings → Appearance, per account via /api/me/prefs): Claude/Codex panes show the conversation (PaneChat) over the still-attached terminal; conversation layout like Claude Desktop (bubbles, prose replies, tool runs folded into one line opening onto their steps, round back-to-end button). - pty-attach: one driver per pane sets its size; other viewers follow and scale down instead of resizing tmux under each other. - Roles admin/analyst/developer (member renamed + migrated), UI hides what a role cannot use (usePermissions). - Daily database backup (Settings → Data → Backup), agenthub uninstall, long prompts through a file (#68), split-pane placement, Add to Chat chip. Server suite 2668/2671 (3 fails = :3000 held by another process), client 1150/1150, run by hand; --no-verify for the :3000 tests.
This commit is contained in:
+35
-2
@@ -30,6 +30,8 @@
|
||||
* @author Nguyễn Ngọc Trí Vĩ <vinnt@smartgift.vn>
|
||||
*/
|
||||
|
||||
const fs = require("node:fs");
|
||||
const path = require("node:path");
|
||||
const tmux = require("./tmux");
|
||||
const { resolveProxy, proxyForSpawn } = require("./proxy-apply");
|
||||
const { desktopEnv } = require("./desktop-env");
|
||||
@@ -137,6 +139,23 @@ function promptArg(p) {
|
||||
return p.startsWith("-") ? ` ${p}` : p;
|
||||
}
|
||||
|
||||
// A prompt past INLINE_PROMPT_BYTES reaches the pane in a 0600 file, not in
|
||||
// tmux's argv: one tmux message holds 16 KB with the env and the rest of the
|
||||
// argv beside it (`command too long`, issue #68). The pane's own sh reads it
|
||||
// back as the CLI's last argument and deletes the file. No CLI can take one
|
||||
// argument past Linux's MAX_ARG_STRLEN (128 KB, E2BIG), so that is refused.
|
||||
const INLINE_PROMPT_BYTES = 4 * 1024;
|
||||
const MAX_PROMPT_BYTES = 128 * 1024 - 2; // the NUL, and promptArg's space
|
||||
const READ_PROMPT = 'p=$(cat "$1") && rm -f "$1" && shift && exec "$@" "$p"';
|
||||
|
||||
function promptFileArgv(id, argv) {
|
||||
const dir = path.join(require("./claude-home").getDataDir(), "run-prompts");
|
||||
fs.mkdirSync(dir, { recursive: true, mode: 0o700 });
|
||||
const file = path.join(dir, `${id}.txt`);
|
||||
fs.writeFileSync(file, argv[argv.length - 1], { mode: 0o600 });
|
||||
return ["sh", "-c", READ_PROMPT, "sh", file, ...argv.slice(0, -1)];
|
||||
}
|
||||
|
||||
function buildClaudeArgv({
|
||||
model,
|
||||
permissionMode,
|
||||
@@ -316,6 +335,12 @@ function spawnRun(args) {
|
||||
if (typeof cwd !== "string" || !cwd) {
|
||||
throw makeErr("EBADCWD", "cwd is required");
|
||||
}
|
||||
if (typeof initialPrompt === "string" && Buffer.byteLength(initialPrompt) > MAX_PROMPT_BYTES) {
|
||||
throw makeErr(
|
||||
"EBADPROMPT",
|
||||
`the prompt is ${Math.ceil(Buffer.byteLength(initialPrompt) / 1024)} KB; an AI CLI takes at most 128 KB as its first message — attach the text as a file instead`
|
||||
);
|
||||
}
|
||||
// A lane whose tool has since left the catalog keeps its row; it just
|
||||
// cannot start until the catalog knows the tool again.
|
||||
const entry = aiTools.get(tool);
|
||||
@@ -434,6 +459,14 @@ function spawnRun(args) {
|
||||
entry
|
||||
);
|
||||
const pasteLater = entry.prompt?.mode === "after-start" && initialPrompt ? initialPrompt : null;
|
||||
// Every launcher puts the prompt LAST; Windows has no sh to read it back.
|
||||
const paneCmd =
|
||||
initialPrompt &&
|
||||
!pasteLater &&
|
||||
process.platform !== "win32" &&
|
||||
Buffer.byteLength(argv[argv.length - 1]) > INLINE_PROMPT_BYTES
|
||||
? promptFileArgv(id, argv)
|
||||
: argv;
|
||||
|
||||
const record = () => {
|
||||
if (!dashboardRuns) return;
|
||||
@@ -524,7 +557,7 @@ function spawnRun(args) {
|
||||
};
|
||||
|
||||
if (!tmux.hasSession(id)) {
|
||||
tmux.newSession({ name: id, cwd, argv: paneArgv(argv), env });
|
||||
tmux.newSession({ name: id, cwd, argv: paneArgv(paneCmd), env });
|
||||
record();
|
||||
schedulePaste();
|
||||
} else if (SHELL_COMMANDS.has(tmux.paneCommand(id) || "")) {
|
||||
@@ -534,7 +567,7 @@ function spawnRun(args) {
|
||||
// `--resume` and an initial prompt would never be typed, while the API
|
||||
// still answered 200. Run the argv in the pane the user already sees
|
||||
// instead of erroring or opening a second session.
|
||||
tmux.sendCommand(id, argv, env, cwd);
|
||||
tmux.sendCommand(id, paneCmd, env, cwd);
|
||||
record();
|
||||
schedulePaste();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user