u1s1-cli 0.13.2 → 0.13.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agent-setup.d.ts +2 -1
- package/dist/agent-setup.js +35 -3
- package/dist/index.js +37 -16
- package/dist/shell-doctor.d.ts +22 -0
- package/dist/shell-doctor.js +129 -0
- package/dist/web.js +2 -1
- package/package.json +1 -1
package/dist/agent-setup.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { type CliConfig, type CustomEndpoint, type ModelDef } from "./config.js";
|
|
2
|
+
import type { ShellDoctorResult } from "./shell-doctor.js";
|
|
2
3
|
/** pi auto-appends <agentDir>/APPEND_SYSTEM.md to its system prompt — our branding hook. */
|
|
3
|
-
export declare function ensureBrandPrompt(): void;
|
|
4
|
+
export declare function ensureBrandPrompt(shell: ShellDoctorResult): void;
|
|
4
5
|
/** Defaults that don't overwrite values the user already set. */
|
|
5
6
|
export declare function ensureDefaultSettings(): void;
|
|
6
7
|
/** ≤0.4.0 wrote u1s1-dark/u1s1-light into the pi themes dir; remove them. */
|
package/dist/agent-setup.js
CHANGED
|
@@ -10,12 +10,44 @@ const BRAND_APPEND = `## u1s1
|
|
|
10
10
|
- 改动前先说明打算做什么,改完用一两句话总结改了哪里。
|
|
11
11
|
- 用户描述模糊时,先猜最可能的意图并确认,不要长篇追问。
|
|
12
12
|
`;
|
|
13
|
+
const EXEC_RULES = `
|
|
14
|
+
## 命令执行
|
|
15
|
+
|
|
16
|
+
- 能用 bash 工具执行的命令,自己执行并展示输出,不要让用户手动执行。
|
|
17
|
+
- 只有需要管理员权限、交互式输入(登录、装系统组件等),或必须开新终端窗口的操作,才让用户执行,并给出可直接粘贴的完整命令。
|
|
18
|
+
`;
|
|
19
|
+
/**
|
|
20
|
+
* pi 的系统提示不含任何 OS/平台信息,模型只能拿 uname 之类盲探,Windows 上
|
|
21
|
+
* 第一步就撞墙。这里按 shell 体检结果告诉模型:系统是什么、命令实际跑在哪、
|
|
22
|
+
* 坏了该怎么引导用户修(而不是反复重试)。
|
|
23
|
+
*/
|
|
24
|
+
function envSection(shell) {
|
|
25
|
+
if (shell.status === "posix") {
|
|
26
|
+
return `\n## 运行环境\n\n- 操作系统: ${process.platform === "darwin" ? "macOS" : "Linux"}。\n`;
|
|
27
|
+
}
|
|
28
|
+
const lines = ["", "## 运行环境", "", "- 操作系统: Windows。环境信息以本节为准,不要用 uname 探测。"];
|
|
29
|
+
switch (shell.status) {
|
|
30
|
+
case "bash":
|
|
31
|
+
lines.push(`- 命令通过 bash 执行(${shell.shellPath}),ls/grep/curl 等 POSIX 工具可用。`, '- 查 Windows 原生信息或调 Windows 程序,用 cmd.exe /c "..." 或 powershell.exe -NoProfile -Command "..."。', "- 默认在 Windows 本机干活;只有用户要求或任务确实需要 Linux 时才考虑 WSL。");
|
|
32
|
+
break;
|
|
33
|
+
case "wsl":
|
|
34
|
+
lines.push("- 注意:命令通过 WSL 的 bash 执行,实际跑在 Linux 发行版里,不是 Windows 本机。", "- 访问 Windows 文件用 /mnt/c/... 路径;调 Windows 程序用带 .exe 的名字(cmd.exe、powershell.exe)。", "- 适时提醒用户:安装 Git for Windows(PowerShell 运行 winget install --id Git.Git)并重启 u1s1,命令就能回到 Windows 本机执行。");
|
|
35
|
+
break;
|
|
36
|
+
case "none":
|
|
37
|
+
lines.push("- 严重:当前没有可用的 bash,bash 工具执行任何命令都会立刻失败,反复重试没有意义。", "- 第一要务是引导用户修复:让用户在 PowerShell 运行 winget install --id Git.Git 安装 Git for Windows,装完重启 u1s1。", "- 修复之前只用读写文件等其他工具帮用户。");
|
|
38
|
+
break;
|
|
39
|
+
case "unknown":
|
|
40
|
+
break;
|
|
41
|
+
}
|
|
42
|
+
return lines.join("\n") + "\n";
|
|
43
|
+
}
|
|
13
44
|
/** pi auto-appends <agentDir>/APPEND_SYSTEM.md to its system prompt — our branding hook. */
|
|
14
|
-
export function ensureBrandPrompt() {
|
|
45
|
+
export function ensureBrandPrompt(shell) {
|
|
15
46
|
mkdirSync(agentDir, { recursive: true });
|
|
47
|
+
const content = BRAND_APPEND + envSection(shell) + EXEC_RULES;
|
|
16
48
|
const p = join(agentDir, "APPEND_SYSTEM.md");
|
|
17
|
-
if (!existsSync(p) || readFileSync(p, "utf8") !==
|
|
18
|
-
writeFileSync(p,
|
|
49
|
+
if (!existsSync(p) || readFileSync(p, "utf8") !== content) {
|
|
50
|
+
writeFileSync(p, content);
|
|
19
51
|
}
|
|
20
52
|
}
|
|
21
53
|
/** Defaults that don't overwrite values the user already set. */
|
package/dist/index.js
CHANGED
|
@@ -1,20 +1,28 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { spawnSync } from "node:child_process";
|
|
2
|
+
import { execSync, spawnSync } from "node:child_process";
|
|
3
3
|
import { writeFileSync } from "node:fs";
|
|
4
4
|
import { cleanupBrandThemes, endpointKeyEnv, endpointProviderEntry, ensureBrandPrompt, ensureDefaultSettings, ensureProviderModels, scrubForeignProviderEnv, toProviderModels, writeWebToolsExtension, } from "./agent-setup.js";
|
|
5
5
|
import { printConsoleBanner } from "./brand.js";
|
|
6
6
|
import { agentDir, apiModelToDef, CUSTOM_ENDPOINTS, isPortableInstall, loadConfig, MODELS, persistPreferredModel, PROVIDER_ID, readSettings, refValid, resolvePreferredModel, setModelsFromApi, VERSION, } from "./config.js";
|
|
7
7
|
import { ensureSearchTools } from "./search-tools.js";
|
|
8
|
+
import { ensureUsableShell } from "./shell-doctor.js";
|
|
8
9
|
import { applyBrandUi, setUpdateNotice } from "./style.js";
|
|
9
10
|
import { offerStarterTemplates } from "./templates.js";
|
|
10
11
|
import { fetchModels, loadCustomEndpoints } from "./api.js";
|
|
11
12
|
const PACKAGE_NAME = "u1s1-cli";
|
|
13
|
+
/** 启动时检测到的可自动安装的新版;TUI 退出后才装(见 installPendingUpdate)。 */
|
|
14
|
+
let pendingUpdate;
|
|
12
15
|
/**
|
|
13
|
-
* 启动时自动检查 npm 最新版:autoUpdate
|
|
16
|
+
* 启动时自动检查 npm 最新版:autoUpdate 开着就记下退出后安装,关着也在启动横幅的
|
|
14
17
|
* 版本号后面提示一句(u1s1 vX.Y.Z 后跟升级状态,见 setUpdateNotice)。
|
|
15
18
|
* 不阻塞启动流程,失败也不报错(留到手动 `u1s1 update`)。
|
|
19
|
+
*
|
|
20
|
+
* 绝不能边跑 TUI 边后台 npm install -g 原地更新:npm 会整棵重铺
|
|
21
|
+
* u1s1-cli/node_modules,而 pi-ai 的 API 适配器要到首次模型调用才按路径懒加载
|
|
22
|
+
* (openai-completions.lazy.js),路径被砸掉就 ERR_MODULE_NOT_FOUND 当场炸
|
|
23
|
+
* (0.13.2 之前云端沙箱首任务必崩的现场)。所以这里只记 pending,退出后再装。
|
|
16
24
|
*/
|
|
17
|
-
async function
|
|
25
|
+
async function checkForUpdate() {
|
|
18
26
|
let latest;
|
|
19
27
|
try {
|
|
20
28
|
const url = `https://registry.npmjs.org/${PACKAGE_NAME}/latest`;
|
|
@@ -59,19 +67,29 @@ async function checkAndAutoUpdate() {
|
|
|
59
67
|
: userAgent.startsWith("bun") ? "bun"
|
|
60
68
|
: "npm";
|
|
61
69
|
const installCmd = pm === "npm"
|
|
62
|
-
? `npm install -g ${PACKAGE_NAME}@latest`
|
|
70
|
+
? `npm install -g --loglevel=error ${PACKAGE_NAME}@latest`
|
|
63
71
|
: `${pm} add -g ${PACKAGE_NAME}@latest`;
|
|
64
|
-
|
|
72
|
+
pendingUpdate = { latest, installCmd };
|
|
73
|
+
setUpdateNotice(`⬆ 发现新版 v${latest},退出后自动更新`);
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* TUI 退出后前台安装新版:此刻不再有模型调用和懒加载,重铺 node_modules 才安全。
|
|
77
|
+
* 不设 timeout——半路杀掉 npm 会留下残缺的全局安装,之后连启动都起不来;
|
|
78
|
+
* stdio 直通,装多久用户看得见。(同机另开的 u1s1 实例仍会被重铺波及,属残余
|
|
79
|
+
* 风险,但远好于更新自己脚下这棵树。)
|
|
80
|
+
*/
|
|
81
|
+
function installPendingUpdate() {
|
|
82
|
+
if (!pendingUpdate)
|
|
83
|
+
return;
|
|
84
|
+
const { latest, installCmd } = pendingUpdate;
|
|
85
|
+
console.log(`\n⬆ 正在更新到 v${latest}…`);
|
|
65
86
|
try {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
const { promisify } = await import("node:util");
|
|
69
|
-
await promisify(exec)(installCmd, { timeout: 60_000 });
|
|
70
|
-
setUpdateNotice(`✨ 已更新到 v${latest},重启后生效`);
|
|
87
|
+
execSync(installCmd, { stdio: "inherit" });
|
|
88
|
+
console.log(`✅ 已更新到 v${latest},下次运行 u1s1 生效。`);
|
|
71
89
|
}
|
|
72
90
|
catch {
|
|
73
|
-
//
|
|
74
|
-
|
|
91
|
+
// 失败不挡退出,下次启动还会再试;也可手动 `u1s1 update`
|
|
92
|
+
console.error("自动更新失败。可稍后手动运行:u1s1 update");
|
|
75
93
|
}
|
|
76
94
|
}
|
|
77
95
|
/**
|
|
@@ -116,7 +134,7 @@ function ensureTmuxKeyboardProtocol() {
|
|
|
116
134
|
}
|
|
117
135
|
async function runAgent(cfg, args) {
|
|
118
136
|
cleanupBrandThemes();
|
|
119
|
-
ensureBrandPrompt();
|
|
137
|
+
ensureBrandPrompt(ensureUsableShell());
|
|
120
138
|
ensureDefaultSettings();
|
|
121
139
|
// 预 seed fd/rg(国内直连 GitHub 不通,pi 自己下不动);与取模型列表并行,
|
|
122
140
|
// 但必须在进 pi 之前就位,否则 pi 会自己去 GitHub 下载
|
|
@@ -160,13 +178,14 @@ async function runAgent(cfg, args) {
|
|
|
160
178
|
if (data === "\r" || data === "\n") {
|
|
161
179
|
const text = this.getText().trim();
|
|
162
180
|
if (text.startsWith("/login")) {
|
|
163
|
-
console.log(" u1s1
|
|
181
|
+
console.log(" 切换模型用 /model;要换 u1s1 账号的话,先 /exit 退出,再在终端运行:");
|
|
182
|
+
console.log(" u1s1 logout && u1s1 login(浏览器里选要用的账号)");
|
|
164
183
|
this.setText("");
|
|
165
184
|
this.addToHistory?.(text);
|
|
166
185
|
return;
|
|
167
186
|
}
|
|
168
187
|
if (text === "/logout") {
|
|
169
|
-
console.log("
|
|
188
|
+
console.log(" 退出登录请先 /exit 回到终端,再运行:u1s1 logout");
|
|
170
189
|
this.setText("");
|
|
171
190
|
this.addToHistory?.(text);
|
|
172
191
|
return;
|
|
@@ -308,8 +327,10 @@ async function run() {
|
|
|
308
327
|
const { ensureAuth } = await import("./login.js");
|
|
309
328
|
const cfg = await ensureAuth();
|
|
310
329
|
// 在后台检查更新(非阻塞,不影响启动速度)
|
|
311
|
-
void
|
|
330
|
+
void checkForUpdate();
|
|
312
331
|
await runAgent(cfg, args);
|
|
332
|
+
// autoUpdate 开着且启动时发现了新版:现在装(TUI 已退出,原地重铺安全)
|
|
333
|
+
installPendingUpdate();
|
|
313
334
|
}
|
|
314
335
|
run().catch((e) => {
|
|
315
336
|
console.error(e instanceof Error ? e.message : e);
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Windows shell 体检。pi 的 shell 兜底顺序是 Program Files 的 Git Bash →
|
|
3
|
+
* PATH 上第一个 bash.exe,后者经常命中 System32 的 WSL 转发器:默认发行版
|
|
4
|
+
* 没有 /bin/bash 时(装过 Docker Desktop 的机器把 docker-desktop 当默认很
|
|
5
|
+
* 常见),所有命令 0.1s 内失败,stderr 还是 UTF-16 乱码,模型只能干瞪眼。
|
|
6
|
+
* 这里在进 pi 之前把一个「验过活」的 bash 写进 settings.json 的 shellPath;
|
|
7
|
+
* 找不到就当场把修复指引打给用户,并让品牌 prompt 告知模型别撞墙。
|
|
8
|
+
*/
|
|
9
|
+
export type ShellDoctorResult = {
|
|
10
|
+
status: "posix";
|
|
11
|
+
} | {
|
|
12
|
+
status: "bash";
|
|
13
|
+
shellPath: string;
|
|
14
|
+
} | {
|
|
15
|
+
status: "wsl";
|
|
16
|
+
shellPath: string;
|
|
17
|
+
} | {
|
|
18
|
+
status: "none";
|
|
19
|
+
} | {
|
|
20
|
+
status: "unknown";
|
|
21
|
+
};
|
|
22
|
+
export declare function ensureUsableShell(): ShellDoctorResult;
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { spawnSync } from "node:child_process";
|
|
2
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
3
|
+
import { dirname, join } from "node:path";
|
|
4
|
+
import { agentDir, agentSettingsFile } from "./config.js";
|
|
5
|
+
/** System32/Sysnative 的 bash.exe 是 WSL 转发器,不是真 bash(与 pi 同款判断)。 */
|
|
6
|
+
function isWslRelayBash(p) {
|
|
7
|
+
const normalized = p.replace(/\//g, "\\").toLowerCase();
|
|
8
|
+
return /^[a-z]:\\windows\\(?:system32|sysnative)\\bash\.exe$/.test(normalized);
|
|
9
|
+
}
|
|
10
|
+
/** 真跑一条 echo 验活。WSL 转发器不支持 -c 传参(pi 对它走 stdin),探活同款。 */
|
|
11
|
+
function bashWorks(bashPath) {
|
|
12
|
+
const viaStdin = isWslRelayBash(bashPath);
|
|
13
|
+
try {
|
|
14
|
+
const res = spawnSync(bashPath, viaStdin ? ["-s"] : ["-c", "echo u1s1-shell-ok"], {
|
|
15
|
+
input: viaStdin ? "echo u1s1-shell-ok\n" : undefined,
|
|
16
|
+
encoding: "utf-8",
|
|
17
|
+
timeout: 5000,
|
|
18
|
+
windowsHide: true,
|
|
19
|
+
});
|
|
20
|
+
// WSL 转发器可能按 UTF-16LE 输出(ASCII 字符间夹 NUL),剔掉再找标记
|
|
21
|
+
return res.status === 0 && (res.stdout ?? "").replace(/\u0000/g, "").includes("u1s1-shell-ok");
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
function runWhere(name) {
|
|
28
|
+
try {
|
|
29
|
+
const res = spawnSync("where", [name], { encoding: "utf-8", timeout: 5000, windowsHide: true });
|
|
30
|
+
if (res.status !== 0 || !res.stdout)
|
|
31
|
+
return [];
|
|
32
|
+
return res.stdout
|
|
33
|
+
.trim()
|
|
34
|
+
.split(/\r?\n/)
|
|
35
|
+
.map((l) => l.trim())
|
|
36
|
+
.filter(Boolean);
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
return [];
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Git Bash 候选位置:pi 只认 Program Files 两处,漏掉 winget 默认的用户级
|
|
44
|
+
* 安装(%LOCALAPPDATA%\Programs\Git)和 scoop;再从 git.exe 反推兜住
|
|
45
|
+
* portable 安装。只返回磁盘上真实存在的路径。
|
|
46
|
+
*/
|
|
47
|
+
function candidateGitBashPaths() {
|
|
48
|
+
const out = [];
|
|
49
|
+
const add = (p) => {
|
|
50
|
+
if (!out.includes(p))
|
|
51
|
+
out.push(p);
|
|
52
|
+
};
|
|
53
|
+
for (const [envKey, ...rest] of [
|
|
54
|
+
["ProgramFiles", "Git", "bin", "bash.exe"],
|
|
55
|
+
["ProgramFiles(x86)", "Git", "bin", "bash.exe"],
|
|
56
|
+
["LOCALAPPDATA", "Programs", "Git", "bin", "bash.exe"],
|
|
57
|
+
["USERPROFILE", "scoop", "apps", "git", "current", "bin", "bash.exe"],
|
|
58
|
+
]) {
|
|
59
|
+
const base = process.env[envKey];
|
|
60
|
+
if (base)
|
|
61
|
+
add(join(base, ...rest));
|
|
62
|
+
}
|
|
63
|
+
// git.exe 在 <root>\cmd、<root>\bin 或 <root>\mingw64\bin 下,向上找 root
|
|
64
|
+
for (const gitPath of runWhere("git.exe")) {
|
|
65
|
+
const dir = dirname(gitPath);
|
|
66
|
+
for (const root of [dirname(dir), dirname(dirname(dir))]) {
|
|
67
|
+
add(join(root, "bin", "bash.exe"));
|
|
68
|
+
add(join(root, "usr", "bin", "bash.exe"));
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return out.filter((p) => existsSync(p));
|
|
72
|
+
}
|
|
73
|
+
export function ensureUsableShell() {
|
|
74
|
+
if (process.platform !== "win32")
|
|
75
|
+
return { status: "posix" };
|
|
76
|
+
mkdirSync(agentDir, { recursive: true });
|
|
77
|
+
let settings = {};
|
|
78
|
+
if (existsSync(agentSettingsFile)) {
|
|
79
|
+
try {
|
|
80
|
+
settings = JSON.parse(readFileSync(agentSettingsFile, "utf8"));
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
return { status: "unknown" }; // 不动损坏的文件,pi 启动时会自己报
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
// 已配置且文件还在:信它,不每次启动都探活(坏了 pi 会在会话里报错)
|
|
87
|
+
const configured = settings["shellPath"];
|
|
88
|
+
if (typeof configured === "string" && configured && existsSync(configured)) {
|
|
89
|
+
return isWslRelayBash(configured)
|
|
90
|
+
? { status: "wsl", shellPath: configured }
|
|
91
|
+
: { status: "bash", shellPath: configured };
|
|
92
|
+
}
|
|
93
|
+
// shellPath 缺失或指向已卸载的文件:探测 + 验活,找到就固定下来
|
|
94
|
+
for (const candidate of candidateGitBashPaths()) {
|
|
95
|
+
if (bashWorks(candidate)) {
|
|
96
|
+
settings["shellPath"] = candidate;
|
|
97
|
+
writeFileSync(agentSettingsFile, JSON.stringify(settings, null, 2) + "\n");
|
|
98
|
+
if (typeof configured === "string") {
|
|
99
|
+
console.error(` 原 shellPath 已失效,自动改用: ${candidate}`);
|
|
100
|
+
}
|
|
101
|
+
return { status: "bash", shellPath: candidate };
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
// 没有 Git Bash:看 PATH 上还有什么(与 pi 的兜底一致,但这里要验活)
|
|
105
|
+
const fallback = runWhere("bash.exe").find((p) => existsSync(p));
|
|
106
|
+
if (fallback && bashWorks(fallback)) {
|
|
107
|
+
if (isWslRelayBash(fallback)) {
|
|
108
|
+
// 能用但跑在 Linux 里。不写进 settings:一旦用户装了 Git Bash,
|
|
109
|
+
// 下次启动就能自动切回 Windows 本机执行。
|
|
110
|
+
console.error(" ⚠ 未找到 Git Bash,将使用 WSL 的 bash:命令会在 WSL 的 Linux 里执行,不是 Windows 本机。");
|
|
111
|
+
console.error(" 建议安装 Git for Windows(PowerShell 运行: winget install --id Git.Git)后重启 u1s1。");
|
|
112
|
+
return { status: "wsl", shellPath: fallback };
|
|
113
|
+
}
|
|
114
|
+
settings["shellPath"] = fallback;
|
|
115
|
+
writeFileSync(agentSettingsFile, JSON.stringify(settings, null, 2) + "\n");
|
|
116
|
+
return { status: "bash", shellPath: fallback };
|
|
117
|
+
}
|
|
118
|
+
if (fallback) {
|
|
119
|
+
console.error(` ⚠ 检测到的 bash(${fallback})无法执行命令,u1s1 的命令工具会全部失败。`);
|
|
120
|
+
if (isWslRelayBash(fallback)) {
|
|
121
|
+
console.error(" 它是 WSL 转发器,当前默认发行版里没有 /bin/bash(docker-desktop 被设为默认时就会这样)。");
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
else {
|
|
125
|
+
console.error(" ⚠ 没找到 bash,u1s1 无法执行命令。");
|
|
126
|
+
}
|
|
127
|
+
console.error(" 修复:PowerShell 里运行 winget install --id Git.Git 安装 Git for Windows,装完重启 u1s1。");
|
|
128
|
+
return { status: "none" };
|
|
129
|
+
}
|
package/dist/web.js
CHANGED
|
@@ -5,6 +5,7 @@ import { dirname, join } from "node:path";
|
|
|
5
5
|
import { cleanupBrandThemes, endpointKeyEnv, ensureAuthCredential, ensureBrandPrompt, ensureDefaultSettings, ensureProviderModels, scrubForeignProviderEnv, writeWebToolsExtension, } from "./agent-setup.js";
|
|
6
6
|
import { agentDir, apiModelToDef, resolvePreferredModel, setModelsFromApi, u1s1Dir, writeAgentDefaultModel, } from "./config.js";
|
|
7
7
|
import { ensureSearchTools } from "./search-tools.js";
|
|
8
|
+
import { ensureUsableShell } from "./shell-doctor.js";
|
|
8
9
|
import { applyWebUiBranding, applyWebUiFrontend } from "./webui-brand.js";
|
|
9
10
|
import { fetchModels, loadCustomEndpoints } from "./api.js";
|
|
10
11
|
const require = createRequire(import.meta.url);
|
|
@@ -20,7 +21,7 @@ const require = createRequire(import.meta.url);
|
|
|
20
21
|
*/
|
|
21
22
|
export async function prepareWebEnv(cfg) {
|
|
22
23
|
cleanupBrandThemes();
|
|
23
|
-
ensureBrandPrompt();
|
|
24
|
+
ensureBrandPrompt(ensureUsableShell());
|
|
24
25
|
ensureDefaultSettings();
|
|
25
26
|
// 网页版/App 的 agent 会话同样依赖 fd/rg(同一个 agentDir);与取模型列表并行
|
|
26
27
|
const searchToolsReady = ensureSearchTools(cfg);
|