@ottocode/sdk 0.1.193 → 0.1.195
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/package.json
CHANGED
|
@@ -30,6 +30,16 @@ function resolveSafePath(projectRoot: string, p: string) {
|
|
|
30
30
|
return abs;
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
+
function killProcessTree(pid: number) {
|
|
34
|
+
try {
|
|
35
|
+
process.kill(-pid, 'SIGTERM');
|
|
36
|
+
} catch {
|
|
37
|
+
try {
|
|
38
|
+
process.kill(pid, 'SIGTERM');
|
|
39
|
+
} catch {}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
33
43
|
export function buildBashTool(projectRoot: string): {
|
|
34
44
|
name: string;
|
|
35
45
|
tool: Tool;
|
|
@@ -55,23 +65,34 @@ export function buildBashTool(projectRoot: string): {
|
|
|
55
65
|
.describe('Timeout in milliseconds (default: 300000 = 5 minutes)'),
|
|
56
66
|
})
|
|
57
67
|
.strict(),
|
|
58
|
-
async execute(
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
68
|
+
async execute(
|
|
69
|
+
{
|
|
70
|
+
cmd,
|
|
71
|
+
cwd,
|
|
72
|
+
allowNonZeroExit,
|
|
73
|
+
timeout = 300000,
|
|
74
|
+
}: {
|
|
75
|
+
cmd: string;
|
|
76
|
+
cwd?: string;
|
|
77
|
+
allowNonZeroExit?: boolean;
|
|
78
|
+
timeout?: number;
|
|
79
|
+
},
|
|
80
|
+
options?: { abortSignal?: AbortSignal },
|
|
81
|
+
): Promise<
|
|
69
82
|
ToolResponse<{
|
|
70
83
|
exitCode: number;
|
|
71
84
|
stdout: string;
|
|
72
85
|
stderr: string;
|
|
73
86
|
}>
|
|
74
87
|
> {
|
|
88
|
+
const abortSignal = options?.abortSignal;
|
|
89
|
+
|
|
90
|
+
if (abortSignal?.aborted) {
|
|
91
|
+
return createToolError('Command aborted before execution', 'abort', {
|
|
92
|
+
cmd,
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
|
|
75
96
|
const absCwd = resolveSafePath(projectRoot, cwd || '.');
|
|
76
97
|
|
|
77
98
|
return new Promise((resolve) => {
|
|
@@ -80,17 +101,48 @@ export function buildBashTool(projectRoot: string): {
|
|
|
80
101
|
shell: true,
|
|
81
102
|
stdio: ['ignore', 'pipe', 'pipe'],
|
|
82
103
|
env: { ...process.env, PATH: getAugmentedPath() },
|
|
104
|
+
detached: true,
|
|
83
105
|
});
|
|
84
106
|
|
|
85
107
|
let stdout = '';
|
|
86
108
|
let stderr = '';
|
|
87
109
|
let didTimeout = false;
|
|
110
|
+
let didAbort = false;
|
|
111
|
+
let settled = false;
|
|
88
112
|
let timeoutId: ReturnType<typeof setTimeout> | null = null;
|
|
89
113
|
|
|
114
|
+
const settle = (
|
|
115
|
+
result: ToolResponse<{
|
|
116
|
+
exitCode: number;
|
|
117
|
+
stdout: string;
|
|
118
|
+
stderr: string;
|
|
119
|
+
}>,
|
|
120
|
+
) => {
|
|
121
|
+
if (settled) return;
|
|
122
|
+
settled = true;
|
|
123
|
+
if (timeoutId) clearTimeout(timeoutId);
|
|
124
|
+
if (abortSignal) {
|
|
125
|
+
abortSignal.removeEventListener('abort', onAbort);
|
|
126
|
+
}
|
|
127
|
+
resolve(result);
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
const onAbort = () => {
|
|
131
|
+
if (settled) return;
|
|
132
|
+
didAbort = true;
|
|
133
|
+
if (proc.pid) killProcessTree(proc.pid);
|
|
134
|
+
else proc.kill('SIGTERM');
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
if (abortSignal) {
|
|
138
|
+
abortSignal.addEventListener('abort', onAbort, { once: true });
|
|
139
|
+
}
|
|
140
|
+
|
|
90
141
|
if (timeout > 0) {
|
|
91
142
|
timeoutId = setTimeout(() => {
|
|
92
143
|
didTimeout = true;
|
|
93
|
-
proc.
|
|
144
|
+
if (proc.pid) killProcessTree(proc.pid);
|
|
145
|
+
else proc.kill();
|
|
94
146
|
}, timeout);
|
|
95
147
|
}
|
|
96
148
|
|
|
@@ -103,10 +155,16 @@ export function buildBashTool(projectRoot: string): {
|
|
|
103
155
|
});
|
|
104
156
|
|
|
105
157
|
proc.on('close', (exitCode) => {
|
|
106
|
-
if (
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
158
|
+
if (didAbort) {
|
|
159
|
+
settle(
|
|
160
|
+
createToolError(`Command aborted by user: ${cmd}`, 'abort', {
|
|
161
|
+
cmd,
|
|
162
|
+
stdout,
|
|
163
|
+
stderr,
|
|
164
|
+
}),
|
|
165
|
+
);
|
|
166
|
+
} else if (didTimeout) {
|
|
167
|
+
settle(
|
|
110
168
|
createToolError(
|
|
111
169
|
`Command timed out after ${timeout}ms: ${cmd}`,
|
|
112
170
|
'timeout',
|
|
@@ -120,7 +178,7 @@ export function buildBashTool(projectRoot: string): {
|
|
|
120
178
|
} else if (exitCode !== 0 && !allowNonZeroExit) {
|
|
121
179
|
const errorDetail = stderr.trim() || stdout.trim() || '';
|
|
122
180
|
const errorMsg = `Command failed with exit code ${exitCode}${errorDetail ? `\n\n${errorDetail}` : ''}`;
|
|
123
|
-
|
|
181
|
+
settle(
|
|
124
182
|
createToolError(errorMsg, 'execution', {
|
|
125
183
|
exitCode,
|
|
126
184
|
stdout,
|
|
@@ -131,7 +189,7 @@ export function buildBashTool(projectRoot: string): {
|
|
|
131
189
|
}),
|
|
132
190
|
);
|
|
133
191
|
} else {
|
|
134
|
-
|
|
192
|
+
settle({
|
|
135
193
|
ok: true,
|
|
136
194
|
exitCode: exitCode ?? 0,
|
|
137
195
|
stdout,
|
|
@@ -141,8 +199,7 @@ export function buildBashTool(projectRoot: string): {
|
|
|
141
199
|
});
|
|
142
200
|
|
|
143
201
|
proc.on('error', (err) => {
|
|
144
|
-
|
|
145
|
-
resolve(
|
|
202
|
+
settle(
|
|
146
203
|
createToolError(
|
|
147
204
|
`Command execution failed: ${err.message}`,
|
|
148
205
|
'execution',
|
|
@@ -30,7 +30,7 @@ const PREFERRED_FAST_MODELS: Partial<Record<ProviderId, string[]>> = {
|
|
|
30
30
|
google: ['gemini-2.0-flash-lite'],
|
|
31
31
|
openrouter: ['anthropic/claude-3.5-haiku'],
|
|
32
32
|
opencode: ['claude-3-5-haiku'],
|
|
33
|
-
setu: ['kimi-k2'],
|
|
33
|
+
setu: ['kimi-k2-turbo-preview'],
|
|
34
34
|
zai: ['glm-4.5-flash'],
|
|
35
35
|
copilot: ['gpt-4.1-mini'],
|
|
36
36
|
};
|