@ottocode/sdk 0.1.264 → 0.1.266
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 +3 -2
- package/src/config/src/index.ts +1 -0
- package/src/core/src/providers/resolver.ts +33 -64
- package/src/core/src/tools/bin-manager/cache.ts +13 -0
- package/src/core/src/tools/bin-manager/filesystem.ts +32 -0
- package/src/core/src/tools/bin-manager/paths.ts +36 -0
- package/src/core/src/tools/bin-manager/vendor.ts +80 -0
- package/src/core/src/tools/bin-manager.ts +14 -140
- package/src/core/src/tools/builtin/patch/apply-hunk.ts +308 -0
- package/src/core/src/tools/builtin/patch/apply-report.ts +99 -0
- package/src/core/src/tools/builtin/patch/apply.ts +6 -663
- package/src/core/src/tools/builtin/patch/hunk-header.ts +17 -0
- package/src/core/src/tools/builtin/patch/indentation.ts +160 -0
- package/src/core/src/tools/builtin/patch/matching.ts +58 -0
- package/src/core/src/tools/builtin/patch/parse-enveloped.ts +10 -72
- package/src/core/src/tools/builtin/patch/parse-unified.ts +15 -105
- package/src/core/src/tools/builtin/patch/replace-builder.ts +64 -0
- package/src/core/src/tools/builtin/patch/unified-state.ts +86 -0
- package/src/core/src/tools/builtin/websearch-strategies.ts +197 -0
- package/src/core/src/tools/builtin/websearch.ts +9 -187
- package/src/core/src/tools/loader.ts +6 -49
- package/src/core/src/tools/plugin-discovery.ts +86 -0
- package/src/core/src/utils/logger/format.ts +50 -0
- package/src/core/src/utils/logger/sinks.ts +61 -0
- package/src/core/src/utils/logger.ts +2 -119
- package/src/index.ts +4 -0
- package/src/providers/src/catalog.ts +1126 -220
- package/src/providers/src/env.ts +1 -0
- package/src/providers/src/index.ts +6 -0
- package/src/providers/src/model-resolution.ts +21 -0
- package/src/providers/src/pricing.ts +3 -0
- package/src/providers/src/registry.ts +2 -0
- package/src/providers/src/utils.ts +3 -0
- package/src/providers/src/xai-client.ts +15 -0
- package/src/providers/src/zai-client.ts +5 -2
- package/src/types/src/provider.ts +1 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ottocode/sdk",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.266",
|
|
4
4
|
"description": "AI agent SDK for building intelligent assistants - tree-shakable and comprehensive",
|
|
5
5
|
"author": "nitishxyz",
|
|
6
6
|
"license": "MIT",
|
|
@@ -98,10 +98,11 @@
|
|
|
98
98
|
"@ai-sdk/google": "^3.0.0",
|
|
99
99
|
"@ai-sdk/openai": "^3.0.0",
|
|
100
100
|
"@ai-sdk/openai-compatible": "^2.0.0",
|
|
101
|
+
"@ai-sdk/xai": "^3.0.0",
|
|
101
102
|
"@modelcontextprotocol/sdk": "^1.12",
|
|
102
103
|
"@openauthjs/openauth": "^0.4.3",
|
|
103
104
|
"@openrouter/ai-sdk-provider": "^1.2.0",
|
|
104
|
-
"@ottorouter/ai-sdk": "0.2.
|
|
105
|
+
"@ottorouter/ai-sdk": "0.2.2",
|
|
105
106
|
"@solana/web3.js": "^1.98.0",
|
|
106
107
|
"ai": "^6.0.170",
|
|
107
108
|
"ai-sdk-ollama": "^3.8.3",
|
package/src/config/src/index.ts
CHANGED
|
@@ -18,6 +18,7 @@ const DEFAULT_PROVIDER_SETTINGS: OttoConfig['providers'] = {
|
|
|
18
18
|
opencode: { enabled: false },
|
|
19
19
|
copilot: { enabled: false },
|
|
20
20
|
ottorouter: { enabled: true },
|
|
21
|
+
xai: { enabled: false },
|
|
21
22
|
zai: { enabled: false },
|
|
22
23
|
'zai-coding': { enabled: false },
|
|
23
24
|
moonshot: { enabled: false },
|
|
@@ -6,30 +6,20 @@ import { createOpenRouter } from '@openrouter/ai-sdk-provider';
|
|
|
6
6
|
import { createOpenAICompatible } from '@ai-sdk/openai-compatible';
|
|
7
7
|
import {
|
|
8
8
|
catalog,
|
|
9
|
+
createMinimaxModel,
|
|
10
|
+
createMoonshotModel,
|
|
9
11
|
createOttoRouterModel,
|
|
10
12
|
createOpenAIOAuthModel,
|
|
13
|
+
createXaiModel,
|
|
14
|
+
createZaiCodingModel,
|
|
15
|
+
createZaiModel,
|
|
11
16
|
normalizeOllamaBaseURL,
|
|
17
|
+
resolveOpenAIResponsesModel,
|
|
18
|
+
shouldUseOpenAIResponsesApi,
|
|
12
19
|
} from '../../../providers/src/index.ts';
|
|
13
20
|
import { createCopilotModel } from '../../../providers/src/copilot-client.ts';
|
|
14
21
|
import type { OAuth } from '../../../types/src/index.ts';
|
|
15
22
|
|
|
16
|
-
function needsResponsesApi(model: string): boolean {
|
|
17
|
-
const m = model.toLowerCase();
|
|
18
|
-
if (m.includes('gpt-5')) return true;
|
|
19
|
-
if (m.startsWith('o1')) return true;
|
|
20
|
-
if (m.startsWith('o3')) return true;
|
|
21
|
-
if (m.startsWith('o4')) return true;
|
|
22
|
-
if (m.includes('codex-mini')) return true;
|
|
23
|
-
return false;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
function resolveOpenAIModel(
|
|
27
|
-
instance: ReturnType<typeof createOpenAI>,
|
|
28
|
-
model: string,
|
|
29
|
-
) {
|
|
30
|
-
return needsResponsesApi(model) ? instance.responses(model) : instance(model);
|
|
31
|
-
}
|
|
32
|
-
|
|
33
23
|
export type ProviderName =
|
|
34
24
|
| 'openai'
|
|
35
25
|
| 'anthropic'
|
|
@@ -39,6 +29,7 @@ export type ProviderName =
|
|
|
39
29
|
| 'opencode'
|
|
40
30
|
| 'copilot'
|
|
41
31
|
| 'ottorouter'
|
|
32
|
+
| 'xai'
|
|
42
33
|
| 'zai'
|
|
43
34
|
| 'zai-coding'
|
|
44
35
|
| 'moonshot'
|
|
@@ -69,13 +60,15 @@ export async function resolveModel(
|
|
|
69
60
|
apiKey: config.apiKey || 'oauth-token',
|
|
70
61
|
fetch: config.customFetch,
|
|
71
62
|
});
|
|
72
|
-
return
|
|
63
|
+
return resolveOpenAIResponsesModel(instance, model);
|
|
73
64
|
}
|
|
74
65
|
if (config.apiKey) {
|
|
75
66
|
const instance = createOpenAI({ apiKey: config.apiKey });
|
|
76
|
-
return
|
|
67
|
+
return resolveOpenAIResponsesModel(instance, model);
|
|
77
68
|
}
|
|
78
|
-
return
|
|
69
|
+
return shouldUseOpenAIResponsesApi(model)
|
|
70
|
+
? openai.responses(model)
|
|
71
|
+
: openai(model);
|
|
79
72
|
}
|
|
80
73
|
|
|
81
74
|
if (provider === 'anthropic') {
|
|
@@ -201,63 +194,39 @@ export async function resolveModel(
|
|
|
201
194
|
);
|
|
202
195
|
}
|
|
203
196
|
|
|
197
|
+
if (provider === 'xai') {
|
|
198
|
+
return createXaiModel(model, {
|
|
199
|
+
apiKey: config.apiKey,
|
|
200
|
+
baseURL: config.baseURL,
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
|
|
204
204
|
if (provider === 'zai') {
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
config.
|
|
208
|
-
process.env.ZAI_API_KEY ||
|
|
209
|
-
process.env.ZHIPU_API_KEY ||
|
|
210
|
-
'';
|
|
211
|
-
const baseURL =
|
|
212
|
-
config.baseURL || entry?.api || 'https://api.z.ai/api/paas/v4';
|
|
213
|
-
const headers = apiKey ? { Authorization: `Bearer ${apiKey}` } : undefined;
|
|
214
|
-
const instance = createOpenAICompatible({
|
|
215
|
-
name: entry?.label ?? 'Z.AI',
|
|
216
|
-
baseURL,
|
|
217
|
-
headers,
|
|
205
|
+
return createZaiModel(model, {
|
|
206
|
+
apiKey: config.apiKey,
|
|
207
|
+
baseURL: config.baseURL,
|
|
218
208
|
});
|
|
219
|
-
return instance(model);
|
|
220
209
|
}
|
|
221
210
|
|
|
222
211
|
if (provider === 'zai-coding') {
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
config.
|
|
226
|
-
process.env.ZAI_CODING_API_KEY ||
|
|
227
|
-
process.env.ZHIPU_API_KEY ||
|
|
228
|
-
'';
|
|
229
|
-
const baseURL =
|
|
230
|
-
config.baseURL || entry?.api || 'https://api.z.ai/api/coding/paas/v4';
|
|
231
|
-
const headers = apiKey ? { Authorization: `Bearer ${apiKey}` } : undefined;
|
|
232
|
-
const instance = createOpenAICompatible({
|
|
233
|
-
name: entry?.label ?? 'Z.AI Coding',
|
|
234
|
-
baseURL,
|
|
235
|
-
headers,
|
|
212
|
+
return createZaiCodingModel(model, {
|
|
213
|
+
apiKey: config.apiKey,
|
|
214
|
+
baseURL: config.baseURL,
|
|
236
215
|
});
|
|
237
|
-
return instance(model);
|
|
238
216
|
}
|
|
239
217
|
|
|
240
218
|
if (provider === 'moonshot') {
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
config.baseURL || entry?.api || 'https://api.moonshot.ai/v1';
|
|
245
|
-
const headers = apiKey ? { Authorization: `Bearer ${apiKey}` } : undefined;
|
|
246
|
-
const instance = createOpenAICompatible({
|
|
247
|
-
name: entry?.label ?? 'Moonshot AI',
|
|
248
|
-
baseURL,
|
|
249
|
-
headers,
|
|
219
|
+
return createMoonshotModel(model, {
|
|
220
|
+
apiKey: config.apiKey,
|
|
221
|
+
baseURL: config.baseURL,
|
|
250
222
|
});
|
|
251
|
-
return instance(model);
|
|
252
223
|
}
|
|
253
224
|
|
|
254
225
|
if (provider === 'minimax') {
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
const instance = createAnthropic({ apiKey, baseURL });
|
|
260
|
-
return instance(model);
|
|
226
|
+
return createMinimaxModel(model, {
|
|
227
|
+
apiKey: config.apiKey,
|
|
228
|
+
baseURL: config.baseURL,
|
|
229
|
+
});
|
|
261
230
|
}
|
|
262
231
|
|
|
263
232
|
throw new Error(`Unsupported provider: ${provider}`);
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
const resolvedPaths = new Map<string, string>();
|
|
2
|
+
|
|
3
|
+
export function getCachedBinary(name: string): string | undefined {
|
|
4
|
+
return resolvedPaths.get(name);
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export function setCachedBinary(name: string, path: string): void {
|
|
8
|
+
resolvedPaths.set(name, path);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function clearCachedBinaries(): void {
|
|
12
|
+
resolvedPaths.clear();
|
|
13
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { promises as fs } from 'node:fs';
|
|
2
|
+
|
|
3
|
+
export async function ensureDir(dir: string): Promise<void> {
|
|
4
|
+
await fs.mkdir(dir, { recursive: true });
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export async function fileExists(p: string): Promise<boolean> {
|
|
8
|
+
try {
|
|
9
|
+
await fs.access(p);
|
|
10
|
+
return true;
|
|
11
|
+
} catch {
|
|
12
|
+
return false;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export async function isExecutable(p: string): Promise<boolean> {
|
|
17
|
+
try {
|
|
18
|
+
await fs.access(p, 0o1);
|
|
19
|
+
return true;
|
|
20
|
+
} catch {
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export async function makeExecutable(p: string): Promise<void> {
|
|
26
|
+
if (process.platform === 'win32') return;
|
|
27
|
+
try {
|
|
28
|
+
await fs.chmod(p, 0o755);
|
|
29
|
+
} catch {}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export { fs };
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { join } from 'node:path';
|
|
2
|
+
|
|
3
|
+
const OTTO_BIN_DIR_NAME = 'bin';
|
|
4
|
+
|
|
5
|
+
let cachedBinDir: string | null = null;
|
|
6
|
+
|
|
7
|
+
function getConfigHome(): string {
|
|
8
|
+
const cfgHome = process.env.XDG_CONFIG_HOME;
|
|
9
|
+
if (cfgHome?.trim()) return cfgHome.replace(/\\/g, '/');
|
|
10
|
+
const home = process.env.HOME || process.env.USERPROFILE || '';
|
|
11
|
+
return join(home, '.config');
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function getAgiBinDir(): string {
|
|
15
|
+
if (cachedBinDir) return cachedBinDir;
|
|
16
|
+
cachedBinDir = join(getConfigHome(), 'otto', OTTO_BIN_DIR_NAME);
|
|
17
|
+
return cachedBinDir;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function getPlatformKey(): string {
|
|
21
|
+
const platform = process.platform;
|
|
22
|
+
const arch = process.arch;
|
|
23
|
+
const os =
|
|
24
|
+
platform === 'darwin'
|
|
25
|
+
? 'darwin'
|
|
26
|
+
: platform === 'win32'
|
|
27
|
+
? 'windows'
|
|
28
|
+
: 'linux';
|
|
29
|
+
const cpu = arch === 'arm64' ? 'arm64' : 'x64';
|
|
30
|
+
return `${os}-${cpu}`;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function getBinaryFileName(name: string): string {
|
|
34
|
+
if (process.platform === 'win32') return `${name}.exe`;
|
|
35
|
+
return name;
|
|
36
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { join } from 'node:path';
|
|
2
|
+
import {
|
|
3
|
+
ensureDir,
|
|
4
|
+
fileExists,
|
|
5
|
+
fs,
|
|
6
|
+
isExecutable,
|
|
7
|
+
makeExecutable,
|
|
8
|
+
} from './filesystem.ts';
|
|
9
|
+
import { getAgiBinDir, getBinaryFileName, getPlatformKey } from './paths.ts';
|
|
10
|
+
|
|
11
|
+
function getVendorSearchPaths(binaryName: string): string[] {
|
|
12
|
+
const platformKey = getPlatformKey();
|
|
13
|
+
const paths: string[] = [];
|
|
14
|
+
|
|
15
|
+
const tauriResource = process.env.TAURI_RESOURCE_DIR;
|
|
16
|
+
if (tauriResource) {
|
|
17
|
+
paths.push(join(tauriResource, 'vendor', 'bin', platformKey, binaryName));
|
|
18
|
+
paths.push(join(tauriResource, 'vendor', 'bin', binaryName));
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
try {
|
|
22
|
+
const exePath = process.execPath;
|
|
23
|
+
if (exePath) {
|
|
24
|
+
const exeDir = join(exePath, '..');
|
|
25
|
+
paths.push(join(exeDir, 'vendor', 'bin', platformKey, binaryName));
|
|
26
|
+
paths.push(
|
|
27
|
+
join(
|
|
28
|
+
exeDir,
|
|
29
|
+
'..',
|
|
30
|
+
'Resources',
|
|
31
|
+
'vendor',
|
|
32
|
+
'bin',
|
|
33
|
+
platformKey,
|
|
34
|
+
binaryName,
|
|
35
|
+
),
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
} catch {}
|
|
39
|
+
|
|
40
|
+
if (process.env.CARGO_MANIFEST_DIR) {
|
|
41
|
+
paths.push(
|
|
42
|
+
join(
|
|
43
|
+
process.env.CARGO_MANIFEST_DIR,
|
|
44
|
+
'resources',
|
|
45
|
+
'vendor',
|
|
46
|
+
'bin',
|
|
47
|
+
platformKey,
|
|
48
|
+
binaryName,
|
|
49
|
+
),
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const cwd = process.cwd();
|
|
54
|
+
paths.push(join(cwd, 'vendor', 'bin', platformKey, binaryName));
|
|
55
|
+
|
|
56
|
+
return paths;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export async function extractFromVendor(name: string): Promise<string | null> {
|
|
60
|
+
const binaryName = getBinaryFileName(name);
|
|
61
|
+
const binDir = getAgiBinDir();
|
|
62
|
+
const targetPath = join(binDir, binaryName);
|
|
63
|
+
|
|
64
|
+
if ((await fileExists(targetPath)) && (await isExecutable(targetPath))) {
|
|
65
|
+
return targetPath;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const searchPaths = getVendorSearchPaths(binaryName);
|
|
69
|
+
|
|
70
|
+
for (const src of searchPaths) {
|
|
71
|
+
if (await fileExists(src)) {
|
|
72
|
+
await ensureDir(binDir);
|
|
73
|
+
await fs.copyFile(src, targetPath);
|
|
74
|
+
await makeExecutable(targetPath);
|
|
75
|
+
return targetPath;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
@@ -1,73 +1,18 @@
|
|
|
1
1
|
import { join } from 'node:path';
|
|
2
|
-
import { promises as fs } from 'node:fs';
|
|
3
2
|
import { spawn, execSync } from 'node:child_process';
|
|
4
3
|
import { homedir } from 'node:os';
|
|
4
|
+
import {
|
|
5
|
+
clearCachedBinaries,
|
|
6
|
+
getCachedBinary,
|
|
7
|
+
setCachedBinary,
|
|
8
|
+
} from './bin-manager/cache.ts';
|
|
9
|
+
import { fileExists, isExecutable } from './bin-manager/filesystem.ts';
|
|
10
|
+
import { getAgiBinDir, getBinaryFileName } from './bin-manager/paths.ts';
|
|
11
|
+
import { extractFromVendor } from './bin-manager/vendor.ts';
|
|
5
12
|
|
|
6
|
-
const OTTO_BIN_DIR_NAME = 'bin';
|
|
7
|
-
|
|
8
|
-
let cachedBinDir: string | null = null;
|
|
9
|
-
const resolvedPaths = new Map<string, string>();
|
|
10
13
|
let cachedLoginPath: string | null = null;
|
|
11
14
|
|
|
12
|
-
|
|
13
|
-
const cfgHome = process.env.XDG_CONFIG_HOME;
|
|
14
|
-
if (cfgHome?.trim()) return cfgHome.replace(/\\/g, '/');
|
|
15
|
-
const home = process.env.HOME || process.env.USERPROFILE || '';
|
|
16
|
-
return join(home, '.config');
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export function getAgiBinDir(): string {
|
|
20
|
-
if (cachedBinDir) return cachedBinDir;
|
|
21
|
-
cachedBinDir = join(getConfigHome(), 'otto', OTTO_BIN_DIR_NAME);
|
|
22
|
-
return cachedBinDir;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
function getPlatformKey(): string {
|
|
26
|
-
const platform = process.platform;
|
|
27
|
-
const arch = process.arch;
|
|
28
|
-
const os =
|
|
29
|
-
platform === 'darwin'
|
|
30
|
-
? 'darwin'
|
|
31
|
-
: platform === 'win32'
|
|
32
|
-
? 'windows'
|
|
33
|
-
: 'linux';
|
|
34
|
-
const cpu = arch === 'arm64' ? 'arm64' : 'x64';
|
|
35
|
-
return `${os}-${cpu}`;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
function getBinaryFileName(name: string): string {
|
|
39
|
-
if (process.platform === 'win32') return `${name}.exe`;
|
|
40
|
-
return name;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
async function ensureDir(dir: string): Promise<void> {
|
|
44
|
-
await fs.mkdir(dir, { recursive: true });
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
async function fileExists(p: string): Promise<boolean> {
|
|
48
|
-
try {
|
|
49
|
-
await fs.access(p);
|
|
50
|
-
return true;
|
|
51
|
-
} catch {
|
|
52
|
-
return false;
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
async function isExecutable(p: string): Promise<boolean> {
|
|
57
|
-
try {
|
|
58
|
-
await fs.access(p, 0o1);
|
|
59
|
-
return true;
|
|
60
|
-
} catch {
|
|
61
|
-
return false;
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
async function makeExecutable(p: string): Promise<void> {
|
|
66
|
-
if (process.platform === 'win32') return;
|
|
67
|
-
try {
|
|
68
|
-
await fs.chmod(p, 0o755);
|
|
69
|
-
} catch {}
|
|
70
|
-
}
|
|
15
|
+
export { getAgiBinDir } from './bin-manager/paths.ts';
|
|
71
16
|
|
|
72
17
|
async function whichBinary(name: string): Promise<string | null> {
|
|
73
18
|
const cmd = process.platform === 'win32' ? 'where' : 'which';
|
|
@@ -85,79 +30,8 @@ async function whichBinary(name: string): Promise<string | null> {
|
|
|
85
30
|
});
|
|
86
31
|
}
|
|
87
32
|
|
|
88
|
-
function getVendorSearchPaths(binaryName: string): string[] {
|
|
89
|
-
const platformKey = getPlatformKey();
|
|
90
|
-
const paths: string[] = [];
|
|
91
|
-
|
|
92
|
-
const tauriResource = process.env.TAURI_RESOURCE_DIR;
|
|
93
|
-
if (tauriResource) {
|
|
94
|
-
paths.push(join(tauriResource, 'vendor', 'bin', platformKey, binaryName));
|
|
95
|
-
paths.push(join(tauriResource, 'vendor', 'bin', binaryName));
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
try {
|
|
99
|
-
const exePath = process.execPath;
|
|
100
|
-
if (exePath) {
|
|
101
|
-
const exeDir = join(exePath, '..');
|
|
102
|
-
paths.push(join(exeDir, 'vendor', 'bin', platformKey, binaryName));
|
|
103
|
-
paths.push(
|
|
104
|
-
join(
|
|
105
|
-
exeDir,
|
|
106
|
-
'..',
|
|
107
|
-
'Resources',
|
|
108
|
-
'vendor',
|
|
109
|
-
'bin',
|
|
110
|
-
platformKey,
|
|
111
|
-
binaryName,
|
|
112
|
-
),
|
|
113
|
-
);
|
|
114
|
-
}
|
|
115
|
-
} catch {}
|
|
116
|
-
|
|
117
|
-
if (process.env.CARGO_MANIFEST_DIR) {
|
|
118
|
-
paths.push(
|
|
119
|
-
join(
|
|
120
|
-
process.env.CARGO_MANIFEST_DIR,
|
|
121
|
-
'resources',
|
|
122
|
-
'vendor',
|
|
123
|
-
'bin',
|
|
124
|
-
platformKey,
|
|
125
|
-
binaryName,
|
|
126
|
-
),
|
|
127
|
-
);
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
const cwd = process.cwd();
|
|
131
|
-
paths.push(join(cwd, 'vendor', 'bin', platformKey, binaryName));
|
|
132
|
-
|
|
133
|
-
return paths;
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
async function extractFromVendor(name: string): Promise<string | null> {
|
|
137
|
-
const binaryName = getBinaryFileName(name);
|
|
138
|
-
const binDir = getAgiBinDir();
|
|
139
|
-
const targetPath = join(binDir, binaryName);
|
|
140
|
-
|
|
141
|
-
if ((await fileExists(targetPath)) && (await isExecutable(targetPath))) {
|
|
142
|
-
return targetPath;
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
const searchPaths = getVendorSearchPaths(binaryName);
|
|
146
|
-
|
|
147
|
-
for (const src of searchPaths) {
|
|
148
|
-
if (await fileExists(src)) {
|
|
149
|
-
await ensureDir(binDir);
|
|
150
|
-
await fs.copyFile(src, targetPath);
|
|
151
|
-
await makeExecutable(targetPath);
|
|
152
|
-
return targetPath;
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
return null;
|
|
157
|
-
}
|
|
158
|
-
|
|
159
33
|
export async function resolveBinary(name: string): Promise<string> {
|
|
160
|
-
const cached =
|
|
34
|
+
const cached = getCachedBinary(name);
|
|
161
35
|
if (cached) return cached;
|
|
162
36
|
|
|
163
37
|
const binaryName = getBinaryFileName(name);
|
|
@@ -167,19 +41,19 @@ export async function resolveBinary(name: string): Promise<string> {
|
|
|
167
41
|
(await fileExists(installedPath)) &&
|
|
168
42
|
(await isExecutable(installedPath))
|
|
169
43
|
) {
|
|
170
|
-
|
|
44
|
+
setCachedBinary(name, installedPath);
|
|
171
45
|
return installedPath;
|
|
172
46
|
}
|
|
173
47
|
|
|
174
48
|
const vendorPath = await extractFromVendor(name);
|
|
175
49
|
if (vendorPath) {
|
|
176
|
-
|
|
50
|
+
setCachedBinary(name, vendorPath);
|
|
177
51
|
return vendorPath;
|
|
178
52
|
}
|
|
179
53
|
|
|
180
54
|
const systemPath = await whichBinary(binaryName);
|
|
181
55
|
if (systemPath) {
|
|
182
|
-
|
|
56
|
+
setCachedBinary(name, systemPath);
|
|
183
57
|
return systemPath;
|
|
184
58
|
}
|
|
185
59
|
|
|
@@ -187,7 +61,7 @@ export async function resolveBinary(name: string): Promise<string> {
|
|
|
187
61
|
}
|
|
188
62
|
|
|
189
63
|
export function clearBinaryCache(): void {
|
|
190
|
-
|
|
64
|
+
clearCachedBinaries();
|
|
191
65
|
}
|
|
192
66
|
|
|
193
67
|
function getLoginShellPath(): string | null {
|