u1s1-cli 0.13.1 → 0.13.3

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/index.js CHANGED
@@ -1,5 +1,5 @@
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";
@@ -9,12 +9,19 @@ import { applyBrandUi, setUpdateNotice } from "./style.js";
9
9
  import { offerStarterTemplates } from "./templates.js";
10
10
  import { fetchModels, loadCustomEndpoints } from "./api.js";
11
11
  const PACKAGE_NAME = "u1s1-cli";
12
+ /** 启动时检测到的可自动安装的新版;TUI 退出后才装(见 installPendingUpdate)。 */
13
+ let pendingUpdate;
12
14
  /**
13
- * 启动时自动检查 npm 最新版:autoUpdate 开着就静默安装,关着也在启动横幅的
15
+ * 启动时自动检查 npm 最新版:autoUpdate 开着就记下退出后安装,关着也在启动横幅的
14
16
  * 版本号后面提示一句(u1s1 vX.Y.Z 后跟升级状态,见 setUpdateNotice)。
15
17
  * 不阻塞启动流程,失败也不报错(留到手动 `u1s1 update`)。
18
+ *
19
+ * 绝不能边跑 TUI 边后台 npm install -g 原地更新:npm 会整棵重铺
20
+ * u1s1-cli/node_modules,而 pi-ai 的 API 适配器要到首次模型调用才按路径懒加载
21
+ * (openai-completions.lazy.js),路径被砸掉就 ERR_MODULE_NOT_FOUND 当场炸
22
+ * (0.13.2 之前云端沙箱首任务必崩的现场)。所以这里只记 pending,退出后再装。
16
23
  */
17
- async function checkAndAutoUpdate() {
24
+ async function checkForUpdate() {
18
25
  let latest;
19
26
  try {
20
27
  const url = `https://registry.npmjs.org/${PACKAGE_NAME}/latest`;
@@ -59,19 +66,29 @@ async function checkAndAutoUpdate() {
59
66
  : userAgent.startsWith("bun") ? "bun"
60
67
  : "npm";
61
68
  const installCmd = pm === "npm"
62
- ? `npm install -g ${PACKAGE_NAME}@latest`
69
+ ? `npm install -g --loglevel=error ${PACKAGE_NAME}@latest`
63
70
  : `${pm} add -g ${PACKAGE_NAME}@latest`;
64
- setUpdateNotice(`⬆ 发现新版 v${latest},自动更新中…`);
71
+ pendingUpdate = { latest, installCmd };
72
+ setUpdateNotice(`⬆ 发现新版 v${latest},退出后自动更新`);
73
+ }
74
+ /**
75
+ * TUI 退出后前台安装新版:此刻不再有模型调用和懒加载,重铺 node_modules 才安全。
76
+ * 不设 timeout——半路杀掉 npm 会留下残缺的全局安装,之后连启动都起不来;
77
+ * stdio 直通,装多久用户看得见。(同机另开的 u1s1 实例仍会被重铺波及,属残余
78
+ * 风险,但远好于更新自己脚下这棵树。)
79
+ */
80
+ function installPendingUpdate() {
81
+ if (!pendingUpdate)
82
+ return;
83
+ const { latest, installCmd } = pendingUpdate;
84
+ console.log(`\n⬆ 正在更新到 v${latest}…`);
65
85
  try {
66
- // 异步安装:execSync 会卡死事件循环,TUI 打字会冻住
67
- const { exec } = await import("node:child_process");
68
- const { promisify } = await import("node:util");
69
- await promisify(exec)(installCmd, { timeout: 60_000 });
70
- setUpdateNotice(`✨ 已更新到 v${latest},重启后生效`);
86
+ execSync(installCmd, { stdio: "inherit" });
87
+ console.log(`✅ 已更新到 v${latest},下次运行 u1s1 生效。`);
71
88
  }
72
89
  catch {
73
- // 自动更新失败不阻塞,用户可手动 `u1s1 update`
74
- setUpdateNotice(`⬆ 新版 v${latest} 可用 · u1s1 update 升级`);
90
+ // 失败不挡退出,下次启动还会再试;也可手动 `u1s1 update`
91
+ console.error("自动更新失败。可稍后手动运行:u1s1 update");
75
92
  }
76
93
  }
77
94
  /**
@@ -160,13 +177,14 @@ async function runAgent(cfg, args) {
160
177
  if (data === "\r" || data === "\n") {
161
178
  const text = this.getText().trim();
162
179
  if (text.startsWith("/login")) {
163
- console.log(" u1s1 不需要额外登录,直接用 /model 切换模型即可");
180
+ console.log(" 切换模型用 /model;要换 u1s1 账号的话,先 /exit 退出,再在终端运行:");
181
+ console.log(" u1s1 logout && u1s1 login(浏览器里选要用的账号)");
164
182
  this.setText("");
165
183
  this.addToHistory?.(text);
166
184
  return;
167
185
  }
168
186
  if (text === "/logout") {
169
- console.log(" u1s1 统一使用同一个 API Key,不需要单独登出");
187
+ console.log(" 退出登录请先 /exit 回到终端,再运行:u1s1 logout");
170
188
  this.setText("");
171
189
  this.addToHistory?.(text);
172
190
  return;
@@ -308,8 +326,10 @@ async function run() {
308
326
  const { ensureAuth } = await import("./login.js");
309
327
  const cfg = await ensureAuth();
310
328
  // 在后台检查更新(非阻塞,不影响启动速度)
311
- void checkAndAutoUpdate();
329
+ void checkForUpdate();
312
330
  await runAgent(cfg, args);
331
+ // autoUpdate 开着且启动时发现了新版:现在装(TUI 已退出,原地重铺安全)
332
+ installPendingUpdate();
313
333
  }
314
334
  run().catch((e) => {
315
335
  console.error(e instanceof Error ? e.message : e);
package/dist/update.js CHANGED
@@ -65,11 +65,13 @@ async function portableSelfUpdate(latest) {
65
65
  if (process.platform === "win32") {
66
66
  console.log(`正在打开更新窗口(升级到 v${latest})…`);
67
67
  console.log("更新在新窗口里进行,本窗口会退出;装完后重新打开终端运行 u1s1 即可。");
68
- // 命令写进临时 .ps1 start,避开 cmd/start 对内联命令的引号地狱;
69
- // start 的第一个引号参数是窗口标题,必须占位,否则带空格的路径会被吞掉
68
+ // 不走 `cmd /c start`:start 只把**带引号**的首参当窗口标题,而 node 对
69
+ // 无空格参数不加引号,标题会被当成命令执行(0.13.1 翻车现场)。node 在
70
+ // Windows 上 detached + stdio ignore 的子进程自带新控制台,直接 spawn
71
+ // powershell 即可,参数按 Win32 规则原样传递,没有二次解析。
70
72
  const tmp = join(mkdtempSync(join(tmpdir(), "u1s1-update-")), "update.ps1");
71
73
  writeFileSync(tmp, "irm https://u1s1.io/releases/install.ps1 | iex\n");
72
- const child = spawn("cmd.exe", ["/c", "start", "u1s1", "powershell", "-NoProfile", "-ExecutionPolicy", "Bypass", "-NoExit", "-File", tmp], { detached: true, stdio: "ignore" });
74
+ const child = spawn("powershell.exe", ["-NoProfile", "-ExecutionPolicy", "Bypass", "-NoExit", "-File", tmp], { detached: true, stdio: "ignore" });
73
75
  child.unref();
74
76
  // 立刻退出释放 node.exe 的文件锁,让安装器能替换安装目录
75
77
  process.exit(0);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "u1s1-cli",
3
- "version": "0.13.1",
3
+ "version": "0.13.3",
4
4
  "description": "u1s1 — 有一说一,最省心的 AI 编程搭子。终端里用中文说需求,AI 帮你读文件、改代码、跑命令。",
5
5
  "type": "module",
6
6
  "bin": {