oh-pi 0.1.65 → 0.1.67
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 +1 -21
- package/dist/tui/confirm-apply.js +1 -1
- package/dist/utils/detect.js +15 -10
- package/dist/utils/install.js +47 -19
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -70,7 +70,7 @@ async function customFlow(env) {
|
|
|
70
70
|
const keybindings = await selectKeybindings();
|
|
71
71
|
const extensions = await selectExtensions();
|
|
72
72
|
const agents = await selectAgents();
|
|
73
|
-
// Advanced: auto-compaction
|
|
73
|
+
// Advanced: auto-compaction is now automatic based on model context window
|
|
74
74
|
const wantAdvanced = await p.confirm({
|
|
75
75
|
message: t("advanced.configure"),
|
|
76
76
|
initialValue: false,
|
|
@@ -79,25 +79,6 @@ async function customFlow(env) {
|
|
|
79
79
|
p.cancel(t("cancelled"));
|
|
80
80
|
process.exit(0);
|
|
81
81
|
}
|
|
82
|
-
let compactThreshold = 0.80;
|
|
83
|
-
if (wantAdvanced) {
|
|
84
|
-
const threshold = await p.text({
|
|
85
|
-
message: t("advanced.compactThreshold"),
|
|
86
|
-
placeholder: "75",
|
|
87
|
-
initialValue: "75",
|
|
88
|
-
validate: (v) => {
|
|
89
|
-
const n = Number(v);
|
|
90
|
-
if (isNaN(n) || n < 10 || n > 100)
|
|
91
|
-
return t("advanced.compactValidation");
|
|
92
|
-
return undefined;
|
|
93
|
-
},
|
|
94
|
-
});
|
|
95
|
-
if (p.isCancel(threshold)) {
|
|
96
|
-
p.cancel(t("cancelled"));
|
|
97
|
-
process.exit(0);
|
|
98
|
-
}
|
|
99
|
-
compactThreshold = Number(threshold) / 100;
|
|
100
|
-
}
|
|
101
82
|
return {
|
|
102
83
|
providers,
|
|
103
84
|
theme,
|
|
@@ -106,6 +87,5 @@ async function customFlow(env) {
|
|
|
106
87
|
prompts: ["review", "fix", "explain", "commit", "test", "refactor", "optimize", "security", "document", "pr"],
|
|
107
88
|
agents,
|
|
108
89
|
thinking: "medium",
|
|
109
|
-
compactThreshold,
|
|
110
90
|
};
|
|
111
91
|
}
|
|
@@ -24,7 +24,7 @@ export async function confirmApply(config, env) {
|
|
|
24
24
|
`${t("confirm.theme")} ${chalk.cyan(config.theme)}`,
|
|
25
25
|
`${t("confirm.keybindings")}${chalk.cyan(config.keybindings)}`,
|
|
26
26
|
`${t("confirm.thinking")} ${chalk.cyan(config.thinking)}`,
|
|
27
|
-
`${t("confirm.compaction")} ${chalk.cyan(
|
|
27
|
+
`${t("confirm.compaction")} ${chalk.cyan("auto")}`,
|
|
28
28
|
`${t("confirm.extensions")} ${chalk.cyan(config.extensions.join(", ") || t("confirm.none"))}`,
|
|
29
29
|
`${t("confirm.prompts")} ${chalk.cyan(t("confirm.promptsValue", { count: config.prompts.length }))}`,
|
|
30
30
|
`${t("confirm.agents")} ${chalk.cyan(config.agents)}`,
|
package/dist/utils/detect.js
CHANGED
|
@@ -81,17 +81,22 @@ function detectProviders(agentDir) {
|
|
|
81
81
|
*/
|
|
82
82
|
export async function detectEnv() {
|
|
83
83
|
const agentDir = join(homedir(), ".pi", "agent");
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
84
|
+
// 并行检测 pi 版本和扫描配置
|
|
85
|
+
const [versionResult, existingFiles] = await Promise.all([
|
|
86
|
+
new Promise((resolve) => {
|
|
87
|
+
try {
|
|
88
|
+
const v = execSync("pi --version", { encoding: "utf8", timeout: 3000 }).trim();
|
|
89
|
+
resolve({ installed: true, version: v });
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
resolve({ installed: false, version: null });
|
|
93
|
+
}
|
|
94
|
+
}),
|
|
95
|
+
Promise.resolve(scanDir(agentDir)),
|
|
96
|
+
]);
|
|
92
97
|
return {
|
|
93
|
-
piInstalled,
|
|
94
|
-
piVersion,
|
|
98
|
+
piInstalled: versionResult.installed,
|
|
99
|
+
piVersion: versionResult.version,
|
|
95
100
|
hasExistingConfig: existsSync(join(agentDir, "settings.json")),
|
|
96
101
|
agentDir,
|
|
97
102
|
terminal: process.env.TERM_PROGRAM ?? process.env.TERM ?? "unknown",
|
package/dist/utils/install.js
CHANGED
|
@@ -12,13 +12,40 @@ function ensureDir(dir) {
|
|
|
12
12
|
mkdirSync(dir, { recursive: true });
|
|
13
13
|
}
|
|
14
14
|
/**
|
|
15
|
-
*
|
|
16
|
-
* @param
|
|
15
|
+
* 增量同步目录:只复制有变化的文件,删除源中不存在的文件
|
|
16
|
+
* @param src - 源目录路径
|
|
17
|
+
* @param dest - 目标目录路径
|
|
17
18
|
*/
|
|
18
|
-
function
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
19
|
+
function syncDir(src, dest) {
|
|
20
|
+
ensureDir(dest);
|
|
21
|
+
const srcEntries = new Set();
|
|
22
|
+
for (const entry of readdirSync(src, { withFileTypes: true })) {
|
|
23
|
+
srcEntries.add(entry.name);
|
|
24
|
+
const srcPath = join(src, entry.name);
|
|
25
|
+
const destPath = join(dest, entry.name);
|
|
26
|
+
if (entry.isDirectory()) {
|
|
27
|
+
syncDir(srcPath, destPath);
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
// 只在文件大小不同时复制
|
|
31
|
+
try {
|
|
32
|
+
if (existsSync(destPath) && statSync(destPath).size === statSync(srcPath).size)
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
catch { /* copy anyway */ }
|
|
36
|
+
copyFileSync(srcPath, destPath);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
// 删除目标中源不存在的文件
|
|
40
|
+
try {
|
|
41
|
+
for (const entry of readdirSync(dest, { withFileTypes: true })) {
|
|
42
|
+
if (!srcEntries.has(entry.name)) {
|
|
43
|
+
const p = join(dest, entry.name);
|
|
44
|
+
rmSync(p, { recursive: true });
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
catch { /* skip */ }
|
|
22
49
|
}
|
|
23
50
|
/**
|
|
24
51
|
* 递归复制目录及其所有内容到目标路径
|
|
@@ -60,14 +87,19 @@ export function applyConfig(config) {
|
|
|
60
87
|
const primary = config.providers.find(p => p.baseUrl && p.defaultModel) ?? config.providers[0];
|
|
61
88
|
const providerInfo = primary ? PROVIDERS[primary.name] : undefined;
|
|
62
89
|
const compactThreshold = config.compactThreshold ?? 0.75;
|
|
63
|
-
|
|
90
|
+
// 根据主模型的 contextWindow 自动计算压缩参数
|
|
91
|
+
const primaryModelId = primary?.defaultModel ?? providerInfo?.models[0];
|
|
92
|
+
const caps = primaryModelId ? MODEL_CAPABILITIES[primaryModelId] : undefined;
|
|
93
|
+
const ctxWindow = caps?.contextWindow ?? primary?.contextWindow ?? 128000;
|
|
94
|
+
const reserveTokens = Math.max(16384, Math.round(ctxWindow * 0.15));
|
|
95
|
+
const keepRecentTokens = Math.max(16384, Math.round(ctxWindow * 0.15));
|
|
64
96
|
const primaryModel = primary?.defaultModel ?? providerInfo?.models[0];
|
|
65
97
|
const settings = {
|
|
66
98
|
...(primary ? { defaultProvider: primary.name, defaultModel: primaryModel } : {}),
|
|
67
99
|
defaultThinkingLevel: config.thinking,
|
|
68
100
|
theme: config.theme,
|
|
69
101
|
enableSkillCommands: true,
|
|
70
|
-
compaction: { enabled: true, reserveTokens, keepRecentTokens
|
|
102
|
+
compaction: { enabled: true, reserveTokens, keepRecentTokens },
|
|
71
103
|
retry: { enabled: true, maxRetries: 3 },
|
|
72
104
|
quietStartup: true,
|
|
73
105
|
};
|
|
@@ -149,12 +181,12 @@ export function applyConfig(config) {
|
|
|
149
181
|
catch { /* template not found, skip */ }
|
|
150
182
|
// 6. Copy extensions (single file .ts or directory with index.ts)
|
|
151
183
|
const extDir = join(agentDir, "extensions");
|
|
152
|
-
|
|
184
|
+
ensureDir(extDir);
|
|
153
185
|
for (const ext of config.extensions) {
|
|
154
186
|
const dirSrc = resources.extension(ext);
|
|
155
187
|
const fileSrc = resources.extensionFile(ext);
|
|
156
188
|
if (existsSync(dirSrc) && statSync(dirSrc).isDirectory()) {
|
|
157
|
-
|
|
189
|
+
syncDir(dirSrc, join(extDir, ext));
|
|
158
190
|
}
|
|
159
191
|
else {
|
|
160
192
|
try {
|
|
@@ -165,7 +197,7 @@ export function applyConfig(config) {
|
|
|
165
197
|
}
|
|
166
198
|
// 7. Copy prompts
|
|
167
199
|
const promptDir = join(agentDir, "prompts");
|
|
168
|
-
|
|
200
|
+
ensureDir(promptDir);
|
|
169
201
|
for (const p of config.prompts) {
|
|
170
202
|
const src = resources.prompt(p);
|
|
171
203
|
try {
|
|
@@ -175,19 +207,15 @@ export function applyConfig(config) {
|
|
|
175
207
|
}
|
|
176
208
|
// 8. Copy skills (auto-discover all from pi-package/skills/)
|
|
177
209
|
const skillDir = join(agentDir, "skills");
|
|
178
|
-
cleanDir(skillDir);
|
|
179
210
|
const skillsSrcDir = resources.skillsDir();
|
|
180
211
|
try {
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
copyDir(join(skillsSrcDir, entry.name), join(skillDir, entry.name));
|
|
184
|
-
}
|
|
185
|
-
}
|
|
212
|
+
if (existsSync(skillsSrcDir))
|
|
213
|
+
syncDir(skillsSrcDir, skillDir);
|
|
186
214
|
}
|
|
187
215
|
catch { /* skills dir not found, skip */ }
|
|
188
216
|
// 9. Copy themes (only custom ones)
|
|
189
217
|
const themeDir = join(agentDir, "themes");
|
|
190
|
-
|
|
218
|
+
ensureDir(themeDir);
|
|
191
219
|
const themeSrc = resources.theme(config.theme);
|
|
192
220
|
try {
|
|
193
221
|
copyFileSync(themeSrc, join(themeDir, `${config.theme}.json`));
|
|
@@ -199,7 +227,7 @@ export function applyConfig(config) {
|
|
|
199
227
|
*/
|
|
200
228
|
export function installPi() {
|
|
201
229
|
try {
|
|
202
|
-
execSync("npm install -g @mariozechner/pi-coding-agent", { stdio: "
|
|
230
|
+
execSync("npm install -g @mariozechner/pi-coding-agent", { stdio: "pipe", timeout: 120000 });
|
|
203
231
|
}
|
|
204
232
|
catch {
|
|
205
233
|
throw new Error("Failed to install pi-coding-agent");
|