pzero-operator 0.1.5 → 0.1.7
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/core/tools/bash.js
CHANGED
|
@@ -36,7 +36,7 @@ export function createLocalBashOperations(options) {
|
|
|
36
36
|
return new Promise((resolve, reject) => {
|
|
37
37
|
const { shell, args } = getShellConfig(options?.shellPath);
|
|
38
38
|
if (!existsSync(cwd)) {
|
|
39
|
-
reject(new Error(`Working directory does not exist: ${cwd}\nCannot execute
|
|
39
|
+
reject(new Error(`Working directory does not exist: ${cwd}\nCannot execute shell commands.`));
|
|
40
40
|
return;
|
|
41
41
|
}
|
|
42
42
|
const child = spawn(shell, [...args, command], {
|
|
@@ -119,6 +119,30 @@ class BashResultRenderComponent extends Container {
|
|
|
119
119
|
function formatDuration(ms) {
|
|
120
120
|
return `${(ms / 1000).toFixed(1)}s`;
|
|
121
121
|
}
|
|
122
|
+
function getShellPromptText(shellPath) {
|
|
123
|
+
try {
|
|
124
|
+
const shellConfig = getShellConfig(shellPath);
|
|
125
|
+
if (process.platform === "win32") {
|
|
126
|
+
if (shellConfig.kind === "powershell") {
|
|
127
|
+
return {
|
|
128
|
+
description: `Execute a ${shellConfig.displayName} command in the current working directory. Returns stdout and stderr. Prefer Windows-native commands and PowerShell syntax. Output is truncated to last ${DEFAULT_MAX_LINES} lines or ${DEFAULT_MAX_BYTES / 1024}KB (whichever is hit first). If truncated, full output is saved to a temp file. Optionally provide a timeout in seconds.`,
|
|
129
|
+
promptSnippet: "Execute PowerShell commands on Windows (Get-ChildItem, Select-String, Test-Path, Remove-Item, etc.)",
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
return {
|
|
133
|
+
description: `Execute a shell command in the current working directory using ${shellConfig.displayName}. Returns stdout and stderr. Output is truncated to last ${DEFAULT_MAX_LINES} lines or ${DEFAULT_MAX_BYTES / 1024}KB (whichever is hit first). If truncated, full output is saved to a temp file. Optionally provide a timeout in seconds.`,
|
|
134
|
+
promptSnippet: "Execute shell commands on Windows using Bash (ls, grep, find, etc.)",
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
catch {
|
|
139
|
+
// Fall back to the default Unix-oriented prompt text if shell discovery fails.
|
|
140
|
+
}
|
|
141
|
+
return {
|
|
142
|
+
description: `Execute a bash command in the current working directory. Returns stdout and stderr. Output is truncated to last ${DEFAULT_MAX_LINES} lines or ${DEFAULT_MAX_BYTES / 1024}KB (whichever is hit first). If truncated, full output is saved to a temp file. Optionally provide a timeout in seconds.`,
|
|
143
|
+
promptSnippet: "Execute bash commands (ls, grep, find, etc.)",
|
|
144
|
+
};
|
|
145
|
+
}
|
|
122
146
|
function formatBashCall(args) {
|
|
123
147
|
const command = str(args?.command);
|
|
124
148
|
const timeout = args?.timeout;
|
|
@@ -192,11 +216,12 @@ export function createBashToolDefinition(cwd, options) {
|
|
|
192
216
|
const ops = options?.operations ?? createLocalBashOperations({ shellPath: options?.shellPath });
|
|
193
217
|
const commandPrefix = options?.commandPrefix;
|
|
194
218
|
const spawnHook = options?.spawnHook;
|
|
219
|
+
const promptText = getShellPromptText(options?.shellPath);
|
|
195
220
|
return {
|
|
196
221
|
name: "bash",
|
|
197
222
|
label: "terminal.exec",
|
|
198
|
-
description:
|
|
199
|
-
promptSnippet:
|
|
223
|
+
description: promptText.description,
|
|
224
|
+
promptSnippet: promptText.promptSnippet,
|
|
200
225
|
parameters: bashSchema,
|
|
201
226
|
async execute(_toolCallId, { command, timeout }, signal, onUpdate, _ctx) {
|
|
202
227
|
const resolvedCommand = commandPrefix ? `${commandPrefix}\n${command}` : command;
|
package/dist/migrations.js
CHANGED
|
@@ -16,7 +16,7 @@ const DEFAULT_MODELS_CONFIG = {
|
|
|
16
16
|
authHeader: true,
|
|
17
17
|
compat: {
|
|
18
18
|
supportsDeveloperRole: true,
|
|
19
|
-
supportsReasoningEffort:
|
|
19
|
+
supportsReasoningEffort: false,
|
|
20
20
|
},
|
|
21
21
|
models: [
|
|
22
22
|
{
|
|
@@ -69,9 +69,9 @@ const DEFAULT_MODELS_CONFIG = {
|
|
|
69
69
|
},
|
|
70
70
|
};
|
|
71
71
|
const DEFAULT_SETTINGS_CONFIG = {
|
|
72
|
-
defaultProvider: "alem-ai-plus-
|
|
73
|
-
defaultModel: "
|
|
74
|
-
defaultThinkingLevel: "
|
|
72
|
+
defaultProvider: "alem-ai-plus-gpt-oss",
|
|
73
|
+
defaultModel: "gpt-oss",
|
|
74
|
+
defaultThinkingLevel: "low",
|
|
75
75
|
};
|
|
76
76
|
function ensureDefaultRuntimeConfig() {
|
|
77
77
|
const agentDir = getAgentDir();
|
|
@@ -107,6 +107,13 @@ function migrateAlemBaseUrls() {
|
|
|
107
107
|
gptOssProvider.baseUrl = "https://llm.alem.ai";
|
|
108
108
|
changed = true;
|
|
109
109
|
}
|
|
110
|
+
if (!gptOssProvider.compat || typeof gptOssProvider.compat !== "object") {
|
|
111
|
+
gptOssProvider.compat = {};
|
|
112
|
+
}
|
|
113
|
+
if (gptOssProvider.compat.supportsReasoningEffort !== false) {
|
|
114
|
+
gptOssProvider.compat.supportsReasoningEffort = false;
|
|
115
|
+
changed = true;
|
|
116
|
+
}
|
|
110
117
|
}
|
|
111
118
|
for (const providerName of ["alem-ai-plus-qwen3-6", "alem-ai-plus-gemma4"]) {
|
|
112
119
|
const provider = parsed.providers[providerName];
|
|
@@ -129,6 +136,43 @@ function migrateAlemBaseUrls() {
|
|
|
129
136
|
return false;
|
|
130
137
|
}
|
|
131
138
|
}
|
|
139
|
+
function migrateAlemDefaultSettings() {
|
|
140
|
+
const settingsPath = getSettingsPath();
|
|
141
|
+
if (!existsSync(settingsPath))
|
|
142
|
+
return false;
|
|
143
|
+
try {
|
|
144
|
+
const parsed = JSON.parse(readFileSync(settingsPath, "utf-8"));
|
|
145
|
+
if (!parsed || typeof parsed !== "object") {
|
|
146
|
+
return false;
|
|
147
|
+
}
|
|
148
|
+
let changed = false;
|
|
149
|
+
if (!parsed.defaultProvider) {
|
|
150
|
+
parsed.defaultProvider = DEFAULT_SETTINGS_CONFIG.defaultProvider;
|
|
151
|
+
changed = true;
|
|
152
|
+
}
|
|
153
|
+
if (!parsed.defaultModel) {
|
|
154
|
+
parsed.defaultModel = DEFAULT_SETTINGS_CONFIG.defaultModel;
|
|
155
|
+
changed = true;
|
|
156
|
+
}
|
|
157
|
+
if (!parsed.defaultThinkingLevel) {
|
|
158
|
+
parsed.defaultThinkingLevel = DEFAULT_SETTINGS_CONFIG.defaultThinkingLevel;
|
|
159
|
+
changed = true;
|
|
160
|
+
}
|
|
161
|
+
if (parsed.defaultProvider === "alem-ai-plus-qwen3-6" &&
|
|
162
|
+
parsed.defaultModel === "qwen3-6" &&
|
|
163
|
+
parsed.defaultThinkingLevel === "high") {
|
|
164
|
+
parsed.defaultThinkingLevel = "low";
|
|
165
|
+
changed = true;
|
|
166
|
+
}
|
|
167
|
+
if (changed) {
|
|
168
|
+
writeFileSync(settingsPath, `${JSON.stringify(parsed, null, 2)}\n`, "utf-8");
|
|
169
|
+
}
|
|
170
|
+
return changed;
|
|
171
|
+
}
|
|
172
|
+
catch {
|
|
173
|
+
return false;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
132
176
|
/**
|
|
133
177
|
* Migrate legacy oauth.json and settings.json apiKeys to auth.json.
|
|
134
178
|
*
|
|
@@ -394,6 +438,7 @@ export async function showDeprecationWarnings(warnings) {
|
|
|
394
438
|
export function runMigrations(cwd) {
|
|
395
439
|
ensureDefaultRuntimeConfig();
|
|
396
440
|
migrateAlemBaseUrls();
|
|
441
|
+
migrateAlemDefaultSettings();
|
|
397
442
|
const migratedAuthProviders = migrateAuthToAuthJson();
|
|
398
443
|
migrateSessionsFromAgentRoot();
|
|
399
444
|
migrateToolsToBin();
|
|
@@ -2145,7 +2145,7 @@ export class InteractiveMode {
|
|
|
2145
2145
|
const command = isExcluded ? text.slice(2).trim() : text.slice(1).trim();
|
|
2146
2146
|
if (command) {
|
|
2147
2147
|
if (this.session.isBashRunning) {
|
|
2148
|
-
this.showWarning("A
|
|
2148
|
+
this.showWarning("A shell command is already running. Press Ctrl+C to cancel it first.");
|
|
2149
2149
|
this.editor.setText(text);
|
|
2150
2150
|
return;
|
|
2151
2151
|
}
|
|
@@ -4320,7 +4320,7 @@ export class InteractiveMode {
|
|
|
4320
4320
|
if (this.bashComponent) {
|
|
4321
4321
|
this.bashComponent.setComplete(undefined, false);
|
|
4322
4322
|
}
|
|
4323
|
-
this.showError(`
|
|
4323
|
+
this.showError(`Shell command failed: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
4324
4324
|
}
|
|
4325
4325
|
this.bashComponent = undefined;
|
|
4326
4326
|
this.ui.requestRender();
|
package/dist/utils/shell.js
CHANGED
|
@@ -2,17 +2,15 @@ import { existsSync } from "node:fs";
|
|
|
2
2
|
import { delimiter } from "node:path";
|
|
3
3
|
import { spawn, spawnSync } from "child_process";
|
|
4
4
|
import { getBinDir } from "../config.js";
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
if (process.platform === "win32") {
|
|
10
|
-
// Windows: Use 'where' and verify file exists (where can return non-existent paths)
|
|
5
|
+
function findExecutableOnPath(candidates) {
|
|
6
|
+
const commands = Array.isArray(candidates) ? candidates : [candidates];
|
|
7
|
+
const lookupCommand = process.platform === "win32" ? "where" : "which";
|
|
8
|
+
for (const candidate of commands) {
|
|
11
9
|
try {
|
|
12
|
-
const result = spawnSync(
|
|
10
|
+
const result = spawnSync(lookupCommand, [candidate], { encoding: "utf-8", timeout: 5000 });
|
|
13
11
|
if (result.status === 0 && result.stdout) {
|
|
14
12
|
const firstMatch = result.stdout.trim().split(/\r?\n/)[0];
|
|
15
|
-
if (firstMatch && existsSync(firstMatch)) {
|
|
13
|
+
if (firstMatch && (process.platform !== "win32" || existsSync(firstMatch))) {
|
|
16
14
|
return firstMatch;
|
|
17
15
|
}
|
|
18
16
|
}
|
|
@@ -20,74 +18,107 @@ function findBashOnPath() {
|
|
|
20
18
|
catch {
|
|
21
19
|
// Ignore errors
|
|
22
20
|
}
|
|
23
|
-
return null;
|
|
24
21
|
}
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
function getShellConfigForExecutable(shellPath) {
|
|
25
|
+
const normalized = shellPath.toLowerCase();
|
|
26
|
+
if (process.platform === "win32") {
|
|
27
|
+
if (normalized.endsWith("pwsh.exe") || normalized.endsWith("\\pwsh")) {
|
|
28
|
+
return {
|
|
29
|
+
shell: shellPath,
|
|
30
|
+
args: ["-NoLogo", "-NoProfile", "-NonInteractive", "-Command"],
|
|
31
|
+
kind: "powershell",
|
|
32
|
+
displayName: "PowerShell",
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
if (normalized.endsWith("powershell.exe") || normalized.endsWith("\\powershell")) {
|
|
36
|
+
return {
|
|
37
|
+
shell: shellPath,
|
|
38
|
+
args: ["-NoLogo", "-NoProfile", "-NonInteractive", "-Command"],
|
|
39
|
+
kind: "powershell",
|
|
40
|
+
displayName: "Windows PowerShell",
|
|
41
|
+
};
|
|
33
42
|
}
|
|
34
43
|
}
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
44
|
+
return {
|
|
45
|
+
shell: shellPath,
|
|
46
|
+
args: ["-c"],
|
|
47
|
+
kind: "bash",
|
|
48
|
+
displayName: process.platform === "win32" ? "Bash" : "Shell",
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Find bash executable on PATH (cross-platform)
|
|
53
|
+
*/
|
|
54
|
+
function findBashOnPath() {
|
|
55
|
+
return process.platform === "win32" ? findExecutableOnPath("bash.exe") : findExecutableOnPath("bash");
|
|
39
56
|
}
|
|
40
57
|
/**
|
|
41
58
|
* Resolve shell configuration based on platform and an optional explicit shell path.
|
|
42
59
|
* Resolution order:
|
|
43
60
|
* 1. User-specified shellPath
|
|
44
|
-
* 2. On Windows:
|
|
61
|
+
* 2. On Windows: PowerShell Core, Windows PowerShell, Git Bash, then bash on PATH
|
|
45
62
|
* 3. On Unix: /bin/bash, then bash on PATH, then fallback to sh
|
|
46
63
|
*/
|
|
47
64
|
export function getShellConfig(customShellPath) {
|
|
48
65
|
// 1. Check user-specified shell path
|
|
49
66
|
if (customShellPath) {
|
|
50
67
|
if (existsSync(customShellPath)) {
|
|
51
|
-
return
|
|
68
|
+
return getShellConfigForExecutable(customShellPath);
|
|
52
69
|
}
|
|
53
70
|
throw new Error(`Custom shell path not found: ${customShellPath}`);
|
|
54
71
|
}
|
|
55
72
|
if (process.platform === "win32") {
|
|
56
|
-
// 2.
|
|
57
|
-
const
|
|
73
|
+
// 2. Prefer native PowerShell shells on Windows.
|
|
74
|
+
const pwshOnPath = findExecutableOnPath(["pwsh.exe", "pwsh"]);
|
|
75
|
+
if (pwshOnPath) {
|
|
76
|
+
return getShellConfigForExecutable(pwshOnPath);
|
|
77
|
+
}
|
|
78
|
+
const powershellPaths = [];
|
|
58
79
|
const programFiles = process.env.ProgramFiles;
|
|
59
80
|
if (programFiles) {
|
|
60
|
-
|
|
81
|
+
powershellPaths.push(`${programFiles}\\PowerShell\\7\\pwsh.exe`);
|
|
82
|
+
powershellPaths.push(`${programFiles}\\Git\\bin\\bash.exe`);
|
|
61
83
|
}
|
|
62
84
|
const programFilesX86 = process.env["ProgramFiles(x86)"];
|
|
63
85
|
if (programFilesX86) {
|
|
64
|
-
|
|
86
|
+
powershellPaths.push(`${programFilesX86}\\Git\\bin\\bash.exe`);
|
|
65
87
|
}
|
|
66
|
-
|
|
88
|
+
const systemRoot = process.env.SystemRoot;
|
|
89
|
+
if (systemRoot) {
|
|
90
|
+
powershellPaths.push(`${systemRoot}\\System32\\WindowsPowerShell\\v1.0\\powershell.exe`);
|
|
91
|
+
}
|
|
92
|
+
for (const path of powershellPaths) {
|
|
67
93
|
if (existsSync(path)) {
|
|
68
|
-
return
|
|
94
|
+
return getShellConfigForExecutable(path);
|
|
69
95
|
}
|
|
70
96
|
}
|
|
97
|
+
const powershellOnPath = findExecutableOnPath(["powershell.exe", "powershell"]);
|
|
98
|
+
if (powershellOnPath) {
|
|
99
|
+
return getShellConfigForExecutable(powershellOnPath);
|
|
100
|
+
}
|
|
71
101
|
// 3. Fallback: search bash.exe on PATH (Cygwin, MSYS2, WSL, etc.)
|
|
72
102
|
const bashOnPath = findBashOnPath();
|
|
73
103
|
if (bashOnPath) {
|
|
74
|
-
return
|
|
104
|
+
return getShellConfigForExecutable(bashOnPath);
|
|
75
105
|
}
|
|
76
|
-
throw new Error(`No
|
|
77
|
-
` 1. Install
|
|
78
|
-
` 2.
|
|
79
|
-
|
|
80
|
-
|
|
106
|
+
throw new Error(`No supported shell found on Windows. Options:\n` +
|
|
107
|
+
` 1. Install PowerShell 7: https://github.com/PowerShell/PowerShell\n` +
|
|
108
|
+
` 2. Use built-in Windows PowerShell\n` +
|
|
109
|
+
` 3. Install Git for Windows: https://git-scm.com/download/win\n` +
|
|
110
|
+
" 4. Set shellPath in settings.json\n\n" +
|
|
111
|
+
`Searched common paths:\n${powershellPaths.map((p) => ` ${p}`).join("\n")}`);
|
|
81
112
|
}
|
|
82
113
|
// Unix: try /bin/bash, then bash on PATH, then fallback to sh
|
|
83
114
|
if (existsSync("/bin/bash")) {
|
|
84
|
-
return
|
|
115
|
+
return getShellConfigForExecutable("/bin/bash");
|
|
85
116
|
}
|
|
86
117
|
const bashOnPath = findBashOnPath();
|
|
87
118
|
if (bashOnPath) {
|
|
88
|
-
return
|
|
119
|
+
return getShellConfigForExecutable(bashOnPath);
|
|
89
120
|
}
|
|
90
|
-
return { shell: "sh", args: ["-c"] };
|
|
121
|
+
return { shell: "sh", args: ["-c"], kind: "sh", displayName: "Shell" };
|
|
91
122
|
}
|
|
92
123
|
export function getShellEnv() {
|
|
93
124
|
const binDir = getBinDir();
|
|
@@ -187,4 +218,4 @@ export function killProcessTree(pid) {
|
|
|
187
218
|
}
|
|
188
219
|
}
|
|
189
220
|
}
|
|
190
|
-
//# sourceMappingURL=shell.js.map
|
|
221
|
+
//# sourceMappingURL=shell.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pzero-operator",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.7",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"description": "Operator is a coding-first terminal AI agent from ProjectZero for software development, shell execution, local project workflows, and broader device-level operator control.",
|