u1s1-cli 1.11.2 → 1.11.6

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/config.d.ts CHANGED
@@ -172,6 +172,8 @@ export declare const agentSettingsFile: string;
172
172
  export interface AgentSettings {
173
173
  showStartupBanner?: boolean;
174
174
  autoUpdate?: boolean;
175
+ /** HTTP proxy applied to all startup and kernel network requests. */
176
+ httpProxy?: string;
175
177
  /** false 时关闭客户端事件上报(见 telemetry.ts;环境变量 U1S1_TELEMETRY=0 同效) */
176
178
  telemetry?: boolean;
177
179
  /** pi 自己的 compaction 设置块;u1s1 额外认 maxContextTokens(自动压缩预算,0 = 关) */
@@ -48,6 +48,7 @@ export function writeConvertedSession(converted, destCwd) {
48
48
  type: "toolCall",
49
49
  id: block.id,
50
50
  name: block.name,
51
+ // 导入的参数本来就是从会话 JSON 解析出来的,一定是 JSON 值
51
52
  arguments: block.arguments,
52
53
  };
53
54
  }),
package/dist/index.js CHANGED
@@ -17,6 +17,19 @@ import { createGatewayTelemetry } from "./telemetry.js";
17
17
  const PACKAGE_NAME = "u1s1-cli";
18
18
  /** 启动时检测到的可自动安装的新版;TUI 退出后才装(见 installPendingUpdate)。 */
19
19
  let pendingUpdate;
20
+ /**
21
+ * Configure the same undici dispatcher used by the embedded kernel before any
22
+ * CLI startup request runs. The kernel keeps this helper in an internal file,
23
+ * so resolve it relative to its public entry instead of relying on an
24
+ * unsupported package subpath export.
25
+ */
26
+ async function configureStartupHttp() {
27
+ const piEntry = import.meta.resolve("@earendil-works/pi-coding-agent");
28
+ const dispatcherUrl = new URL("./core/http-dispatcher.js", piEntry).href;
29
+ const dispatcher = await import(dispatcherUrl);
30
+ dispatcher.applyHttpProxySettings(readSettings().httpProxy);
31
+ dispatcher.configureHttpDispatcher();
32
+ }
20
33
  /**
21
34
  * 启动时自动检查 npm 最新版:autoUpdate 开着就记下退出后安装,关着也在启动横幅的
22
35
  * 版本号后面提示一句(u1s1 vX.Y.Z 后跟升级状态,见 setUpdateNotice)。
@@ -679,6 +692,10 @@ async function run() {
679
692
  const args = process.argv.slice(2);
680
693
  const cmd = args[0];
681
694
  const rest = args.slice(1);
695
+ // Must precede ensureAuth/login, fetchModels, and every command that can
696
+ // issue network requests. No proxy configured means direct connections via
697
+ // EnvHttpProxyAgent, preserving the existing fallback behavior.
698
+ await configureStartupHttp();
682
699
  if (cmd === "--version" || cmd === "-v") {
683
700
  console.log(`u1s1 v${VERSION}`);
684
701
  return;
package/dist/update.d.ts CHANGED
@@ -5,6 +5,8 @@ export declare function detectPackageManager(): string;
5
5
  /** Fetch the latest published version from npm registry. */
6
6
  export declare function getLatestVersion(): Promise<string | undefined>;
7
7
  export declare function compareVersions(a: string, b: string): number;
8
+ /** 生成 Windows 更新启动器:优先使用 PowerShell 7,没有时回退 Windows PowerShell。 */
9
+ export declare function buildWindowsUpdateLauncherScript(): string;
8
10
  /** 从固定发布源拉一个文本文件:强制 https、拒绝重定向、限长。 */
9
11
  export declare function fetchReleaseText(name: string, maxBytes: number, timeoutMs?: number): Promise<string>;
10
12
  /** 在 sha256sum 格式的清单里找某个文件的哈希("<hex> <name>" 或 "<hex> *<name>")。 */
package/dist/update.js CHANGED
@@ -69,6 +69,17 @@ export function compareVersions(a, b) {
69
69
  const RELEASE_ORIGIN = "https://u1s1.io";
70
70
  const INSTALL_SCRIPT_NAME = "install.sh";
71
71
  const MAX_SUMS_BYTES = 64 * 1024;
72
+ /** 生成 Windows 更新启动器:优先使用 PowerShell 7,没有时回退 Windows PowerShell。 */
73
+ export function buildWindowsUpdateLauncherScript() {
74
+ return [
75
+ "$inner = '-NoProfile -ExecutionPolicy Bypass -NoExit -File \"' + $PSScriptRoot + '\\update.ps1\"'",
76
+ "$ps = (Get-Command pwsh -ErrorAction SilentlyContinue).Source",
77
+ "if (-not $ps) { $ps = (Get-Command powershell -ErrorAction SilentlyContinue).Source }",
78
+ "if (-not $ps) { throw '找不到可用的 PowerShell' }",
79
+ "Start-Process -FilePath $ps -ArgumentList $inner",
80
+ "",
81
+ ].join("\n");
82
+ }
72
83
  /** 从固定发布源拉一个文本文件:强制 https、拒绝重定向、限长。 */
73
84
  export async function fetchReleaseText(name, maxBytes, timeoutMs = 30_000) {
74
85
  const url = new URL(`/releases/${name}`, RELEASE_ORIGIN);
@@ -135,8 +146,7 @@ async function portableSelfUpdate(latest) {
135
146
  // 拼字符串,没有引号二次解析问题。
136
147
  const dir = mkdtempSync(join(tmpdir(), "u1s1-update-"));
137
148
  writeFileSync(join(dir, "update.ps1"), "irm https://u1s1.io/releases/install.ps1 | iex\n");
138
- writeFileSync(join(dir, "launch.ps1"), "$inner = '-NoProfile -ExecutionPolicy Bypass -NoExit -File \"' + $PSScriptRoot + '\\update.ps1\"'\n" +
139
- "Start-Process powershell -ArgumentList $inner\n");
149
+ writeFileSync(join(dir, "launch.ps1"), buildWindowsUpdateLauncherScript());
140
150
  const res = spawnSync("powershell.exe", ["-NoProfile", "-ExecutionPolicy", "Bypass", "-File", join(dir, "launch.ps1")], { stdio: "ignore", windowsHide: true, timeout: 30_000 });
141
151
  if (res.error || res.status !== 0) {
142
152
  console.error("无法拉起更新窗口。请手动在 PowerShell 里运行:");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "u1s1-cli",
3
- "version": "1.11.2",
3
+ "version": "1.11.6",
4
4
  "description": "u1s1 — 有一说一,最省心的 AI 编程搭子。终端里用中文说需求,AI 帮你读文件、改代码、跑命令。",
5
5
  "type": "module",
6
6
  "bin": {
@@ -42,8 +42,8 @@
42
42
  "license": "MIT",
43
43
  "homepage": "https://u1s1.io",
44
44
  "dependencies": {
45
- "@earendil-works/pi-coding-agent": "0.84.4",
46
- "@earendil-works/pi-tui": "0.84.4",
45
+ "@earendil-works/pi-coding-agent": "0.87.1",
46
+ "@earendil-works/pi-tui": "0.87.1",
47
47
  "typebox": "1.3.7"
48
48
  },
49
49
  "devDependencies": {
@@ -64,15 +64,10 @@ const COMPACT_UI_REPLACEMENTS = [
64
64
  '|| (c.type === "thinking" && c.thinking.trim())',
65
65
  '|| (c.type === "thinking" && !this.hideThinkingBlock && c.thinking.trim())',
66
66
  ],
67
- // Skip an empty collapsed-thinking label instead of rendering an ANSI-only row.
67
+ // Skip a hidden thinking run with an empty label entirely: no ANSI-only row, no trailing spacer.
68
68
  [
69
- 'this.contentContainer.addChild(new Text(theme.italic(theme.fg("thinkingText", this.hiddenThinkingLabel)), this.outputPad, 0));',
70
- 'if (this.hiddenThinkingLabel !== "") { this.contentContainer.addChild(new Text(theme.italic(theme.fg("thinkingText", this.hiddenThinkingLabel)), this.outputPad, 0)); }',
71
- ],
72
- // Do not add spacing after a fully hidden thinking block.
73
- [
74
- "if (hasVisibleContentAfter) {",
75
- 'if (hasVisibleContentAfter && !(this.hideThinkingBlock && this.hiddenThinkingLabel === "")) {',
69
+ "const hidden = this.thinkingVisibilityOverrides.get(runIndex) ?? this.hideThinkingBlock;",
70
+ 'const hidden = this.thinkingVisibilityOverrides.get(runIndex) ?? this.hideThinkingBlock;\nif (hidden && this.hiddenThinkingLabel === "") { continue; }',
76
71
  ],
77
72
  ];
78
73
 
@@ -86,6 +81,8 @@ const SLASH_COMMANDS_REPLACEMENTS = [
86
81
  ['{ name: "export", description: "Export session (HTML default, or specify path: .html/.jsonl)" },', '{ name: "export", description: "导出会话(默认 HTML,也可指定 .html/.jsonl 路径)" },'],
87
82
  ['{ name: "import", description: "Import and resume a session from a JSONL file" },', '{ name: "import", description: "从 JSONL 文件导入并继续会话" },'],
88
83
  ['{ name: "share", description: "Share session as a secret GitHub gist" },', '{ name: "share", description: "把会话分享为 GitHub 私密 gist" },'],
84
+ // /bug 会把诊断信息上传给 Pi 上游开发者,u1s1 用户的问题应走 /feedback 到我们这边,从候选列表里去掉
85
+ ['{ name: "bug", description: "Report a bug to the Pi developers", argumentHint: "<description>" },', ''],
89
86
  ['{ name: "copy", description: "Copy last agent message to clipboard" },', '{ name: "copy", description: "复制上一条回复到剪贴板" },'],
90
87
  ['{ name: "name", description: "Set session display name" },', '{ name: "name", description: "给当前会话起个名字" },'],
91
88
  ['{ name: "session", description: "Show session info and stats" },', '{ name: "session", description: "查看会话信息与统计" },'],
@@ -174,7 +171,7 @@ const HOTKEYS_REPLACEMENTS = [
174
171
  ["| Toggle tool output expansion |", "| 展开 / 收起工具输出 |"],
175
172
  ["| Toggle thinking block visibility |", "| 显示 / 隐藏思考过程 |"],
176
173
  ["| Edit message in external editor |", "| 用外部编辑器写消息 |"],
177
- ["| Copy last assistant message |", "| 复制最近一条回复 |"],
174
+ ["| Copy selection or last assistant message |", "| 复制选中内容或最近一条回复 |"],
178
175
  ["| Queue follow-up message |", "| 把消息排到当前回复之后 |"],
179
176
  ["| Restore queued messages |", "| 取回排队中的消息 |"],
180
177
  ["| Paste image or text from clipboard |", "| 从剪贴板粘贴图片或文本 |"],
@@ -282,7 +279,7 @@ const ASSISTANT_TEXT_REPLACEMENTS = [
282
279
  ['theme.fg("error", `Error: ${errorMsg}`)', 'theme.fg("error", `出错:${errorMsg}`)'],
283
280
  ];
284
281
  const WORKING_TEXT_REPLACEMENTS = [
285
- ['defaultWorkingMessage = "Working...";', 'defaultWorkingMessage = "思考中…";'],
282
+ ['defaultWorkingMessage = "Working";', 'defaultWorkingMessage = "思考中…";'],
286
283
  ['defaultHiddenThinkingLabel = "Thinking...";', 'defaultHiddenThinkingLabel = "思考中…";'],
287
284
  ];
288
285
  // 脚注提示(↑↓ navigate · enter select · esc cancel …)在十几个组件里各写各的,
@@ -295,8 +292,7 @@ const KEY_HINT_REPLACEMENTS = [
295
292
  { from: 'theme.fg("muted", ` ${description}`)', to: 'theme.fg("muted", ` ${u1s1Hint(description)}`)', expected: 2 },
296
293
  ];
297
294
  const MODEL_SELECTOR_REPLACEMENTS = [
298
- // 两处 modelText(有/无两空格缩进)同一规则覆盖;测试的空白折叠匹配不认双空格
299
- { from: '${item.id}`;', to: '${item.model.name || item.id}`;', expected: 2 },
295
+ ['const modelText = isSelected ? theme.fg("accent", item.id) : item.id;', 'const modelText = isSelected ? theme.fg("accent", item.model.name || item.id) : (item.model.name || item.id);'],
300
296
  ['Model Name: ${selected.model.name}`)', '模型 ID: ${selected.model.id}`)'],
301
297
  ['No matching models")', '没有匹配的模型")'],
302
298
  ['theme.fg("muted", " · default")', 'theme.fg("muted", " · 默认")'],
@@ -320,7 +316,7 @@ const SETTINGS_REPLACEMENTS = [
320
316
  ['always: "Always trust",', 'always: "始终信任",'],
321
317
  ['never: "Never trust",', 'never: "从不信任",'],
322
318
  ['new SelectSubmenu("Theme", "Select a theme, or choose Automatic to follow terminal appearance."', 'new SelectSubmenu("主题", "选择一个主题,或选「自动」跟随终端明暗。"'],
323
- ['label: "Automatic",', 'label: "自动",'],
319
+ ['label: " Automatic",', 'label: " 自动",'],
324
320
  ['description: "Use separate themes for light and dark terminal appearance",', 'description: "终端明暗各用一套主题",'],
325
321
  ['theme.fg("accent", "Automatic Theme")', 'theme.fg("accent", "自动主题")'],
326
322
  ['theme.fg("muted", "Choose themes for terminal light and dark appearance.")', 'theme.fg("muted", "分别为终端的浅色/深色外观选主题。")'],
@@ -341,6 +337,8 @@ const SETTINGS_REPLACEMENTS = [
341
337
  ['description: `${followUpKey} queues follow-up messages until agent stops. \'one-at-a-time\': deliver one, wait for response. \'all\': deliver all at once.`,', 'description: `${followUpKey} 把追问排队到本轮结束再发。one-at-a-time:发一条等回复;all:一次全发。`,'],
342
338
  ['label: "Transport",', 'label: "传输方式",'],
343
339
  ['description: "Preferred transport for providers that support multiple transports",', 'description: "支持多种传输方式的渠道优先用哪种",'],
340
+ ['label: "Cache warming",', 'label: "缓存预热",'],
341
+ ['description: "off; streaming while the agent runs; idle also between runs while continuation stays profitable",', 'description: "off:不预热;streaming:回复进行中保温;idle:两轮之间只要续聊划算也保温",'],
344
342
  ['label: "HTTP idle timeout",', 'label: "HTTP 空闲超时",'],
345
343
  ['description: "Maximum idle gap while waiting for HTTP headers or body chunks. Disable for local models that pause longer than five minutes.",', 'description: "等待响应头或数据块的最长空闲间隔;本地模型停顿超过五分钟可关闭。",'],
346
344
  ['label: "Hide thinking",', 'label: "隐藏思考过程",'],
@@ -348,7 +346,7 @@ const SETTINGS_REPLACEMENTS = [
348
346
  ['label: "Mermaid diagrams",', 'label: "Mermaid 图表",'],
349
347
  ['description: "Render Mermaid code blocks as Unicode diagrams",', 'description: "把 Mermaid 代码块渲染成字符图",'],
350
348
  ['label: "Cache miss notices",', 'label: "缓存未命中提示",'],
351
- ['description: "Show transcript notices for significant prompt-cache misses and compaction costs",', 'description: "提示明显的提示词缓存未命中与压缩开销",'],
349
+ ['description: "Show transcript notices for cache costs and provider recovery diagnostics",', 'description: "提示缓存开销与渠道恢复诊断",'],
352
350
  ['label: "Collapse changelog",', 'label: "折叠更新日志",'],
353
351
  ['description: "Show condensed changelog after updates",', 'description: "更新后只显示精简的更新日志",'],
354
352
  ['label: "Quiet startup",', 'label: "安静启动",'],
@@ -369,7 +367,7 @@ const SETTINGS_REPLACEMENTS = [
369
367
  ['label: "No models available",', 'label: "没有可用模型",'],
370
368
  ['description: "Log in to a provider or configure an API key first",', 'description: "请先登录",'],
371
369
  ['description: "Select default thinking level for this model",', 'description: "选择这个模型的默认推理强度",'],
372
- ['label: "(clear override)",', 'label: "(清除覆盖)",'],
370
+ ['label: " (clear override)",', 'label: " (清除覆盖)",'],
373
371
  ['description: `Revert to global default (${config.thinkingLevel})`,', 'description: `恢复为全局默认(${config.thinkingLevel})`,'],
374
372
  ['label: "TUI mode",', 'label: "界面模式",'],
375
373
  ['description: "Interface layout; fullscreen mode is experimental",', 'description: "界面布局;全屏模式为实验功能",'],
@@ -383,9 +381,19 @@ const SETTINGS_REPLACEMENTS = [
383
381
  ['description: "Color theme for the interface",', 'description: "界面配色主题",'],
384
382
  ];
385
383
 
384
+ // /bug 入口改指向 u1s1 的 /feedback(dist/modes/interactive/interactive-mode.js):
385
+ // 手动输入 /bug、启动时的上次崩溃提示、崩溃退出说明、报错后的一次性提示,都不再把用户引到 Pi 上游。
386
+ const BUG_REPORT_REPLACEMENTS = [
387
+ ["await this.handleBugCommand(hint ? hint : undefined);", 'this.showStatus("反馈问题请用 /feedback(会附带诊断信息建工单)");'],
388
+ ["this.showWarning(`${APP_NAME} crashed on ${when} (${crash.message}). Run /bug to report it; the crash details are attached automatically.`);", "this.showWarning(`u1s1 上次异常退出(${when}:${crash.message})。反复出现请用 /feedback 反馈,并写上发生时间。`);"],
389
+ ["return `To report this crash: ${resume} run /bug. The crash details are attached automatically.`;", 'return "u1s1 异常退出了。反复出现请运行 u1s1 feedback 反馈。";'],
390
+ ["`If this looks like a ${APP_NAME} bug, /bug sends a report to the developers.`", '"如果这看起来是 u1s1 自身的问题,可以用 /feedback 反馈。"'],
391
+ ];
392
+
386
393
  const TUI_TEXT_TARGETS = [
387
394
  [["modes", "interactive", "components", "assistant-message.js"], ASSISTANT_TEXT_REPLACEMENTS, "回复状态文案"],
388
395
  [["modes", "interactive", "interactive-mode.js"], WORKING_TEXT_REPLACEMENTS, "工作中提示"],
396
+ [["modes", "interactive", "interactive-mode.js"], BUG_REPORT_REPLACEMENTS, "/bug 入口"],
389
397
  [["modes", "interactive", "components", "keybinding-hints.js"], KEY_HINT_REPLACEMENTS, "按键脚注"],
390
398
  [["modes", "interactive", "components", "model-selector.js"], MODEL_SELECTOR_REPLACEMENTS, "模型选择器"],
391
399
  [["modes", "interactive", "components", "settings-selector.js"], SETTINGS_REPLACEMENTS, "设置菜单"],