u1s1-cli 1.2.7 → 1.2.8

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/scripts/patch-pi.js +94 -73
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "u1s1-cli",
3
- "version": "1.2.7",
3
+ "version": "1.2.8",
4
4
  "description": "u1s1 — 有一说一,最省心的 AI 编程搭子。终端里用中文说需求,AI 帮你读文件、改代码、跑命令。",
5
5
  "type": "module",
6
6
  "bin": {
@@ -12,7 +12,7 @@
12
12
  * - Never fails installation; mismatches only emit a notice and exit 0
13
13
  */
14
14
 
15
- import { readFileSync, writeFileSync, existsSync } from "node:fs";
15
+ import { readFileSync, writeFileSync, existsSync, realpathSync } from "node:fs";
16
16
  import { join, dirname } from "node:path";
17
17
  import { fileURLToPath } from "node:url";
18
18
  import { createRequire } from "node:module";
@@ -21,21 +21,40 @@ const pkgRoot = join(dirname(fileURLToPath(import.meta.url)), "..");
21
21
 
22
22
  // npm may hoist dependencies above the package, especially for global installs.
23
23
  // Resolve packages through Node first, then walk upward as a fallback.
24
- function findPackageDir(packageName) {
24
+ function addPackageDir(found, candidate) {
25
+ if (!existsSync(join(candidate, "package.json"))) return;
26
+ try {
27
+ found.add(realpathSync(candidate));
28
+ } catch {
29
+ found.add(candidate);
30
+ }
31
+ }
32
+
33
+ function findPackageDirs(packageName) {
34
+ const found = new Set();
25
35
  try {
26
36
  const req = createRequire(join(pkgRoot, "package.json"));
27
- return dirname(req.resolve(`${packageName}/package.json`));
37
+ addPackageDir(found, dirname(req.resolve(`${packageName}/package.json`)));
28
38
  } catch {
29
- const [scope, name] = packageName.split("/");
30
- let dir = pkgRoot;
31
- while (true) {
32
- const candidate = join(dir, "node_modules", scope, name);
33
- if (existsSync(candidate)) return candidate;
34
- const parent = dirname(dir);
35
- if (parent === dir) return null;
36
- dir = parent;
37
- }
39
+ // The package may block package.json through exports; the upward scan below still finds it.
38
40
  }
41
+ const [scope, name] = packageName.split("/");
42
+ let dir = pkgRoot;
43
+ while (true) {
44
+ addPackageDir(found, join(dir, "node_modules", scope, name));
45
+ const parent = dirname(dir);
46
+ if (parent === dir) break;
47
+ dir = parent;
48
+ }
49
+ return [...found];
50
+ }
51
+
52
+ function findTuiDirs() {
53
+ const found = new Set(findPackageDirs("@earendil-works/pi-tui"));
54
+ for (const codingAgentDir of findPackageDirs("@earendil-works/pi-coding-agent")) {
55
+ addPackageDir(found, join(codingAgentDir, "node_modules", "@earendil-works", "pi-tui"));
56
+ }
57
+ return [...found];
39
58
  }
40
59
 
41
60
  // Each tuple is [original, replacement], matching the pnpm coding-agent patch.
@@ -58,88 +77,90 @@ const COMPACT_UI_REPLACEMENTS = [
58
77
  ];
59
78
 
60
79
  function patchCompactUi() {
61
- const piDir = findPackageDir("@earendil-works/pi-coding-agent");
62
- const target = piDir
63
- ? join(piDir, "dist", "modes", "interactive", "components", "assistant-message.js")
64
- : null;
65
- if (!target) {
80
+ const piDirs = findPackageDirs("@earendil-works/pi-coding-agent");
81
+ if (piDirs.length === 0) {
66
82
  console.log("[u1s1] 提示: 未找到 @earendil-works/pi-coding-agent,精简 UI 空行补丁未应用(不影响使用)");
67
83
  return;
68
84
  }
69
- try {
70
- let text = readFileSync(target, "utf8");
71
- if (text.includes("!this.hideThinkingBlock && c.thinking.trim()")) return;
85
+ for (const piDir of piDirs) {
86
+ const target = join(piDir, "dist", "modes", "interactive", "components", "assistant-message.js");
87
+ try {
88
+ let text = readFileSync(target, "utf8");
89
+ if (text.includes("!this.hideThinkingBlock && c.thinking.trim()")) continue;
72
90
 
73
- let applied = 0;
74
- for (const [from, to] of COMPACT_UI_REPLACEMENTS) {
75
- if (text.includes(to)) {
91
+ let applied = 0;
92
+ for (const [from, to] of COMPACT_UI_REPLACEMENTS) {
93
+ if (text.includes(to)) {
94
+ applied++;
95
+ continue;
96
+ }
97
+ if (!text.includes(from)) continue;
98
+ text = text.split(from).join(to);
76
99
  applied++;
77
- continue;
78
100
  }
79
- if (!text.includes(from)) continue;
80
- text = text.split(from).join(to);
81
- applied++;
82
- }
83
101
 
84
- if (applied < COMPACT_UI_REPLACEMENTS.length) {
85
- console.log(
86
- `[u1s1] 提示: pi 版本可能已更新,精简 UI 空行补丁只应用了 ${applied}/${COMPACT_UI_REPLACEMENTS.length} 处(不影响使用)`,
87
- );
102
+ if (applied < COMPACT_UI_REPLACEMENTS.length) {
103
+ console.log(
104
+ `[u1s1] 提示: pi 版本可能已更新,精简 UI 空行补丁只应用了 ${applied}/${COMPACT_UI_REPLACEMENTS.length} 处(不影响使用)`,
105
+ );
106
+ }
107
+ writeFileSync(target, text);
108
+ } catch {
109
+ continue;
88
110
  }
89
- writeFileSync(target, text);
90
- } catch {
91
- return;
92
111
  }
93
112
  }
94
113
 
95
114
  function patchMainScreenAutowrap() {
96
- const tuiDir = findPackageDir("@earendil-works/pi-tui");
97
- const target = tuiDir ? join(tuiDir, "dist", "tui-main-screen.js") : null;
98
- if (!target) {
115
+ const tuiDirs = findTuiDirs();
116
+ if (tuiDirs.length === 0) {
99
117
  console.log("[u1s1] 提示: 未找到 @earendil-works/pi-tui,Windows 重绘补丁未应用(不影响安装)");
100
118
  return;
101
119
  }
102
- try {
103
- let text = readFileSync(target, "utf8");
104
- if (text.includes('const DISABLE_AUTOWRAP = "\\x1b[?7l";')) return;
120
+ for (const tuiDir of tuiDirs) {
121
+ const target = join(tuiDir, "dist", "tui-main-screen.js");
122
+ try {
123
+ let text = readFileSync(target, "utf8");
124
+ if (text.includes('const DISABLE_AUTOWRAP = "\\x1b[?7l";')) continue;
105
125
 
106
- const rules = [
107
- {
108
- from: 'const KITTY_SEQUENCE_PREFIX = "\\x1b_G";',
109
- to: `const KITTY_SEQUENCE_PREFIX = "\\x1b_G";
126
+ const rules = [
127
+ {
128
+ from: 'const KITTY_SEQUENCE_PREFIX = "\\x1b_G";',
129
+ to: `const KITTY_SEQUENCE_PREFIX = "\\x1b_G";
110
130
  // Windows ConPTY eagerly wraps full-width lines, which desynchronizes cursor-row tracking.
111
131
  const DISABLE_AUTOWRAP = "\\x1b[?7l";
112
132
  const ENABLE_AUTOWRAP = "\\x1b[?7h";`,
113
- expected: 1,
114
- },
115
- {
116
- from: 'let buffer = "\\x1b[?2026h";',
117
- to: 'let buffer = "\\x1b[?2026h" + DISABLE_AUTOWRAP;',
118
- expected: 3,
119
- },
120
- {
121
- from: 'buffer += "\\x1b[?2026l";',
122
- to: 'buffer += ENABLE_AUTOWRAP + "\\x1b[?2026l";',
123
- expected: 3,
124
- },
125
- ];
126
- let applied = 0;
127
- let expected = 0;
128
- for (const rule of rules) {
129
- expected += rule.expected;
130
- const occurrences = text.split(rule.from).length - 1;
131
- if (occurrences !== rule.expected) continue;
132
- text = text.split(rule.from).join(rule.to);
133
- applied += occurrences;
134
- }
133
+ expected: 1,
134
+ },
135
+ {
136
+ from: 'let buffer = "\\x1b[?2026h";',
137
+ to: 'let buffer = "\\x1b[?2026h" + DISABLE_AUTOWRAP;',
138
+ expected: 3,
139
+ },
140
+ {
141
+ from: 'buffer += "\\x1b[?2026l";',
142
+ to: 'buffer += ENABLE_AUTOWRAP + "\\x1b[?2026l";',
143
+ expected: 3,
144
+ },
145
+ ];
146
+ let applied = 0;
147
+ let expected = 0;
148
+ for (const rule of rules) {
149
+ expected += rule.expected;
150
+ const occurrences = text.split(rule.from).length - 1;
151
+ if (occurrences !== rule.expected) continue;
152
+ text = text.split(rule.from).join(rule.to);
153
+ applied += occurrences;
154
+ }
135
155
 
136
- if (applied !== expected) {
137
- console.log(`[u1s1] 提示: pi-tui 版本可能已更新,Windows 重绘补丁只应用了 ${applied}/${expected} 处(不影响安装)`);
138
- return;
156
+ if (applied !== expected) {
157
+ console.log(`[u1s1] 提示: pi-tui 版本可能已更新,Windows 重绘补丁只应用了 ${applied}/${expected} 处(不影响安装)`);
158
+ continue;
159
+ }
160
+ writeFileSync(target, text);
161
+ } catch {
162
+ continue;
139
163
  }
140
- writeFileSync(target, text);
141
- } catch {
142
- return;
143
164
  }
144
165
  }
145
166