@oh-my-tool/cli 0.2.0
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/LICENSE +21 -0
- package/README.md +13 -0
- package/assets/skills/oh-my-tool/SKILL.md +77 -0
- package/bin/ohmytool.cjs +15 -0
- package/bin/ohmytool.ts +5 -0
- package/package.json +34 -0
- package/src/cli/commands/describe.ts +24 -0
- package/src/cli/commands/extension.ts +24 -0
- package/src/cli/commands/index.ts +7 -0
- package/src/cli/commands/integrate.ts +64 -0
- package/src/cli/commands/run.ts +39 -0
- package/src/cli/commands/search.ts +16 -0
- package/src/cli/commands/secret.ts +72 -0
- package/src/cli/context.ts +44 -0
- package/src/cli/index.ts +296 -0
- package/src/cli/parseArgs.ts +44 -0
- package/src/config/config.ts +63 -0
- package/src/core/executor.ts +99 -0
- package/src/core/registry.ts +33 -0
- package/src/core/result.ts +14 -0
- package/src/core/schema.ts +2 -0
- package/src/extension/discovery.ts +62 -0
- package/src/extension/install.ts +24 -0
- package/src/extension/loader.ts +32 -0
- package/src/extension/manifest.ts +115 -0
- package/src/integration/adapters.ts +98 -0
- package/src/integration/index.ts +4 -0
- package/src/integration/manager.ts +375 -0
- package/src/integration/skill.ts +84 -0
- package/src/integration/types.ts +55 -0
- package/src/migration.ts +44 -0
- package/src/paths.ts +41 -0
- package/src/policy/policy.ts +139 -0
- package/src/runtime/errors.ts +8 -0
- package/src/runtime/executor.ts +66 -0
- package/src/runtime/provider-registry.ts +23 -0
- package/src/runtime/provider.ts +29 -0
- package/src/runtime/providers/native/discovery.ts +2 -0
- package/src/runtime/providers/native/install.ts +2 -0
- package/src/runtime/providers/native/loader.ts +1 -0
- package/src/runtime/providers/native/manifest.ts +6 -0
- package/src/runtime/providers/native/provider.ts +57 -0
- package/src/runtime/result.ts +12 -0
- package/src/runtime/runtime.ts +71 -0
- package/src/runtime/schema.ts +49 -0
- package/src/runtime/tool-registry.ts +54 -0
- package/src/search/search.ts +78 -0
- package/src/secrets/secrets.ts +45 -0
- package/src/version.ts +1 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 oh-my-tool
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# @oh-my-tool/cli
|
|
2
|
+
|
|
3
|
+
The `ohmytool` command-line interface for discovering and running local agent
|
|
4
|
+
tools.
|
|
5
|
+
|
|
6
|
+
```powershell
|
|
7
|
+
npm install --global @oh-my-tool/cli
|
|
8
|
+
ohmytool --help
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Requires Bun 1.4 or newer. Use `ohmytool search`, `ohmytool describe`, then
|
|
12
|
+
`ohmytool run`; see the main [Oh My Tool repository](https://github.com/oh-my-tool/oh-my-tool)
|
|
13
|
+
for configuration and extension installation guidance.
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: oh-my-tool
|
|
3
|
+
description: Discover and invoke local, development, and enterprise tools through the Oh My Tool Agent Tool Runtime.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Oh My Tool — The Agent Tool Runtime
|
|
7
|
+
|
|
8
|
+
Use the canonical `ohmytool` CLI to discover and execute tools exposed by installed native extensions.
|
|
9
|
+
|
|
10
|
+
## When to use
|
|
11
|
+
|
|
12
|
+
Use Oh My Tool when the task requires an external capability that may be available in the user's environment, such as:
|
|
13
|
+
|
|
14
|
+
- querying a database
|
|
15
|
+
- inspecting Redis
|
|
16
|
+
- reading configuration
|
|
17
|
+
- searching internal logs
|
|
18
|
+
- invoking development and operations tools
|
|
19
|
+
|
|
20
|
+
Do not assume a specific extension or tool is installed.
|
|
21
|
+
|
|
22
|
+
## Workflow
|
|
23
|
+
|
|
24
|
+
### 1. Search
|
|
25
|
+
|
|
26
|
+
When you do not know the exact tool ID:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
ohmytool search "<what you need to do>"
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Search returns lightweight summary metadata and does not load handlers or access secrets.
|
|
33
|
+
|
|
34
|
+
### 2. Describe
|
|
35
|
+
|
|
36
|
+
Before using an unfamiliar tool, inspect its complete descriptor and input schema:
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
ohmytool describe <tool-name>
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Use the returned schema, constraints, risk level, and configuration requirements to construct the input.
|
|
43
|
+
|
|
44
|
+
### 3. Run
|
|
45
|
+
|
|
46
|
+
Execute the selected tool through the runtime:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
ohmytool run <tool-name> key=value
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
For structured or complex arguments, prefer JSON through stdin:
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
echo '{"connection":"iot-test","sql":"SELECT 1"}' | ohmytool run mysql.query --stdin
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Rules
|
|
59
|
+
|
|
60
|
+
- Prefer `ohmytool` over directly invoking an underlying database, cache, CLI, API, or service.
|
|
61
|
+
- Do not guess installed tools; use `ohmytool search`.
|
|
62
|
+
- Do not guess tool arguments; use `ohmytool describe`.
|
|
63
|
+
- Do not guess connection names, endpoints, credentials, tokens, or authentication details.
|
|
64
|
+
- Never request or expose secrets managed by Oh My Tool.
|
|
65
|
+
- Respect tool risk levels, policy restrictions, and environment restrictions.
|
|
66
|
+
- Prefer the smallest and safest tool that can complete the task.
|
|
67
|
+
- Treat runtime results as structured tool output and use them to continue the task.
|
|
68
|
+
|
|
69
|
+
## Mental model
|
|
70
|
+
|
|
71
|
+
The CLI is the Agent-facing adapter. ToolRuntime indexes static descriptors and governs execution through ToolProviders; native extension handlers are loaded only when `run` executes a tool.
|
|
72
|
+
|
|
73
|
+
```text
|
|
74
|
+
search → lightweight ToolDescriptor summary
|
|
75
|
+
describe → complete ToolDescriptor and inputSchema
|
|
76
|
+
run → policy → provider → dynamic handler execution
|
|
77
|
+
```
|
package/bin/ohmytool.cjs
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const { spawnSync } = require("node:child_process");
|
|
4
|
+
const { join } = require("node:path");
|
|
5
|
+
|
|
6
|
+
const result = spawnSync("bun", [join(__dirname, "ohmytool.ts"), ...process.argv.slice(2)], {
|
|
7
|
+
stdio: "inherit",
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
if (result.error) {
|
|
11
|
+
console.error("ohmytool requires Bun 1.4 or newer. Install it from https://bun.sh.");
|
|
12
|
+
process.exit(1);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
process.exit(result.status ?? 1);
|
package/bin/ohmytool.ts
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@oh-my-tool/cli",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "Oh My Tool CLI - local and enterprise tools for agents",
|
|
6
|
+
"keywords": ["ai", "agent", "cli", "tools", "extensions", "bun"],
|
|
7
|
+
"homepage": "https://github.com/oh-my-tool/oh-my-tool#readme",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/oh-my-tool/oh-my-tool.git",
|
|
11
|
+
"directory": "packages/cli"
|
|
12
|
+
},
|
|
13
|
+
"bugs": "https://github.com/oh-my-tool/oh-my-tool/issues",
|
|
14
|
+
"bin": {
|
|
15
|
+
"ohmytool": "bin/ohmytool.cjs"
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"assets",
|
|
19
|
+
"bin",
|
|
20
|
+
"src"
|
|
21
|
+
],
|
|
22
|
+
"dependencies": {
|
|
23
|
+
"@clack/prompts": "^1.7.0",
|
|
24
|
+
"@oh-my-tool/sdk": "0.2.0"
|
|
25
|
+
},
|
|
26
|
+
"engines": {
|
|
27
|
+
"node": ">=20",
|
|
28
|
+
"bun": ">=1.4.0"
|
|
29
|
+
},
|
|
30
|
+
"publishConfig": {
|
|
31
|
+
"access": "public"
|
|
32
|
+
},
|
|
33
|
+
"license": "MIT"
|
|
34
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { createRuntime } from "../context";
|
|
2
|
+
|
|
3
|
+
export interface DescribedTool {
|
|
4
|
+
name: string;
|
|
5
|
+
description: string;
|
|
6
|
+
risk: string;
|
|
7
|
+
inputSchema: Record<string, unknown> | undefined;
|
|
8
|
+
extension: string;
|
|
9
|
+
extensionVersion: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export async function runDescribe(toolName: string): Promise<DescribedTool> {
|
|
13
|
+
const runtime = await createRuntime();
|
|
14
|
+
const descriptor = await runtime.describe(toolName);
|
|
15
|
+
return {
|
|
16
|
+
name: descriptor.id,
|
|
17
|
+
description: descriptor.description,
|
|
18
|
+
risk: descriptor.risk,
|
|
19
|
+
inputSchema: descriptor.inputSchema,
|
|
20
|
+
extension: descriptor.source.id,
|
|
21
|
+
extensionVersion: "unknown",
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { discoverExtensions } from "../../extension/discovery";
|
|
2
|
+
import { installLocalExtension, type InstalledRef } from "../../extension/install";
|
|
3
|
+
import { homeDir } from "../context";
|
|
4
|
+
|
|
5
|
+
export interface InstalledInfo {
|
|
6
|
+
id: string;
|
|
7
|
+
version: string;
|
|
8
|
+
entry: string;
|
|
9
|
+
toolCount: number;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export async function runExtensionList(): Promise<InstalledInfo[]> {
|
|
13
|
+
return discoverExtensions(homeDir()).map((e) => ({
|
|
14
|
+
id: e.id,
|
|
15
|
+
version: e.version,
|
|
16
|
+
entry: e.entry,
|
|
17
|
+
toolCount: e.manifest.tools.length,
|
|
18
|
+
}));
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export async function runExtensionInstall(spec: string): Promise<InstalledRef> {
|
|
22
|
+
return installLocalExtension(homeDir(), spec);
|
|
23
|
+
}
|
|
24
|
+
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import type { AgentDetection, AgentId, IntegrationResult } from "../../integration";
|
|
2
|
+
import { AGENT_IDS, createIntegrationManager } from "../../integration";
|
|
3
|
+
import { homeDir } from "../context";
|
|
4
|
+
import { VERSION } from "../../version";
|
|
5
|
+
|
|
6
|
+
export type IntegrateAction = "install" | "status" | "repair" | "uninstall";
|
|
7
|
+
|
|
8
|
+
export interface IntegrateInput {
|
|
9
|
+
action: IntegrateAction;
|
|
10
|
+
agents?: AgentId[];
|
|
11
|
+
force?: boolean;
|
|
12
|
+
dryRun?: boolean;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface IntegrateOutput {
|
|
16
|
+
action: IntegrateAction;
|
|
17
|
+
dryRun: boolean;
|
|
18
|
+
detected: AgentDetection[];
|
|
19
|
+
selected: AgentId[];
|
|
20
|
+
results: IntegrationResult[];
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
type IntegrationManager = ReturnType<typeof createIntegrationManager>;
|
|
24
|
+
|
|
25
|
+
export function defaultIntegrationManager(): IntegrationManager {
|
|
26
|
+
return createIntegrationManager({ omtHome: homeDir(), skillVersion: VERSION });
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export async function runIntegrate(
|
|
30
|
+
input: IntegrateInput,
|
|
31
|
+
manager: IntegrationManager = defaultIntegrationManager(),
|
|
32
|
+
): Promise<IntegrateOutput> {
|
|
33
|
+
const detected = await manager.detect();
|
|
34
|
+
const known = new Set<AgentId>(AGENT_IDS);
|
|
35
|
+
for (const id of input.agents ?? []) {
|
|
36
|
+
if (!known.has(id)) throw new Error(`Unknown agent: ${id}`);
|
|
37
|
+
}
|
|
38
|
+
const selected = input.agents?.length ? input.agents : detected.map((agent) => agent.id);
|
|
39
|
+
const detectedIds = new Set(detected.map((agent) => agent.id));
|
|
40
|
+
for (const id of selected) {
|
|
41
|
+
if (!detectedIds.has(id)) throw new Error(`Agent is not detected: ${id}`);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (input.dryRun) {
|
|
45
|
+
return { action: input.action, dryRun: true, detected, selected, results: [] };
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
let results: IntegrationResult[];
|
|
49
|
+
switch (input.action) {
|
|
50
|
+
case "install":
|
|
51
|
+
results = await manager.install(selected, { force: input.force });
|
|
52
|
+
break;
|
|
53
|
+
case "status":
|
|
54
|
+
results = (await manager.status()).filter((item) => selected.includes(item.agent));
|
|
55
|
+
break;
|
|
56
|
+
case "repair":
|
|
57
|
+
results = await manager.repair(selected);
|
|
58
|
+
break;
|
|
59
|
+
case "uninstall":
|
|
60
|
+
results = await manager.uninstall(selected);
|
|
61
|
+
break;
|
|
62
|
+
}
|
|
63
|
+
return { action: input.action, dryRun: false, detected, selected, results };
|
|
64
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { coerceInput } from "../parseArgs";
|
|
2
|
+
import { createRuntime } from "../context";
|
|
3
|
+
import type { OmtResult } from "../../core/result";
|
|
4
|
+
|
|
5
|
+
export async function runTool(
|
|
6
|
+
toolName: string,
|
|
7
|
+
keyValues: Record<string, string>,
|
|
8
|
+
useStdin: boolean,
|
|
9
|
+
): Promise<OmtResult> {
|
|
10
|
+
let input: Record<string, unknown>;
|
|
11
|
+
if (useStdin) {
|
|
12
|
+
input = await readStdinJson();
|
|
13
|
+
} else {
|
|
14
|
+
input = coerceInput(keyValues);
|
|
15
|
+
}
|
|
16
|
+
const runtime = await createRuntime();
|
|
17
|
+
const result = await runtime.run(toolName, input);
|
|
18
|
+
if (result.ok) {
|
|
19
|
+
return { ok: true, tool: toolName, data: result.output, meta: result.meta ?? {} };
|
|
20
|
+
}
|
|
21
|
+
return { ok: false, tool: toolName, error: result.error ?? { code: "EXECUTION_FAILED", message: "execution failed" } };
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function readStdinJson(): Promise<Record<string, unknown>> {
|
|
25
|
+
return new Promise((resolve, reject) => {
|
|
26
|
+
let data = "";
|
|
27
|
+
const stdin = process.stdin;
|
|
28
|
+
stdin.setEncoding("utf8");
|
|
29
|
+
stdin.on("data", (chunk: string) => (data += chunk));
|
|
30
|
+
stdin.on("end", () => {
|
|
31
|
+
try {
|
|
32
|
+
resolve(JSON.parse(data));
|
|
33
|
+
} catch (e) {
|
|
34
|
+
reject(e);
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
stdin.on("error", reject);
|
|
38
|
+
});
|
|
39
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { createRuntime } from "../context";
|
|
2
|
+
|
|
3
|
+
export async function runSearch(query: string): Promise<{ tools: Array<Record<string, unknown>> }> {
|
|
4
|
+
const runtime = await createRuntime();
|
|
5
|
+
const descriptors = await runtime.search(query);
|
|
6
|
+
return {
|
|
7
|
+
tools: descriptors.map((descriptor) => ({
|
|
8
|
+
name: descriptor.id,
|
|
9
|
+
description: descriptor.description,
|
|
10
|
+
extension: descriptor.source.id,
|
|
11
|
+
risk: descriptor.risk,
|
|
12
|
+
provider: descriptor.provider,
|
|
13
|
+
})),
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { SecretsManager } from "../../secrets/secrets";
|
|
2
|
+
import type { SecretStore } from "@oh-my-tool/sdk";
|
|
3
|
+
|
|
4
|
+
export interface SecretSetResult {
|
|
5
|
+
ok: true;
|
|
6
|
+
name: string;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export async function runSecretSet(
|
|
10
|
+
name: string,
|
|
11
|
+
value: string,
|
|
12
|
+
store?: SecretStore,
|
|
13
|
+
): Promise<SecretSetResult> {
|
|
14
|
+
const mgr = new SecretsManager(store);
|
|
15
|
+
await mgr.set(name, value);
|
|
16
|
+
return { ok: true, name };
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface SecretListResult {
|
|
20
|
+
names: string[];
|
|
21
|
+
supported: boolean;
|
|
22
|
+
hint?: string;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/** 从 cmdkey /list 输出解析 oh-my-tool 命名空间下的 secret 名(不返回值)。 */
|
|
26
|
+
export function parseSecretNamesFromCmdkey(output: string): string[] {
|
|
27
|
+
const names = new Set<string>();
|
|
28
|
+
const re = /oh-my-tool\/([A-Za-z0-9:._@-]+)/g;
|
|
29
|
+
let m: RegExpExecArray | null;
|
|
30
|
+
while ((m = re.exec(output)) !== null) {
|
|
31
|
+
names.add(m[1]);
|
|
32
|
+
}
|
|
33
|
+
return [...names].sort();
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
type CmdkeyExec = (args: string[]) => Promise<string>;
|
|
37
|
+
|
|
38
|
+
async function defaultCmdkeyList(): Promise<string> {
|
|
39
|
+
const proc = Bun.spawn(["cmdkey", "/list"], { stdout: "pipe", stderr: "pipe" });
|
|
40
|
+
const output = await Bun.readableStreamToArrayBuffer(proc.stdout);
|
|
41
|
+
const out = new TextDecoder().decode(output);
|
|
42
|
+
const code = await proc.exited;
|
|
43
|
+
if (code !== 0) throw new Error(`cmdkey /list exited ${code}`);
|
|
44
|
+
return out;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* 列出已设置的 secret 名(只列名、不显值)。
|
|
49
|
+
* Bun.secrets 无枚举 API,Windows 下通过 cmdkey 解析 oh-my-tool/ 前缀;
|
|
50
|
+
* 非 Windows 不支持枚举,返回 supported=false。
|
|
51
|
+
*/
|
|
52
|
+
export async function runSecretList(
|
|
53
|
+
exec: CmdkeyExec = defaultCmdkeyList,
|
|
54
|
+
): Promise<SecretListResult> {
|
|
55
|
+
if (process.platform !== "win32") {
|
|
56
|
+
return {
|
|
57
|
+
names: [],
|
|
58
|
+
supported: false,
|
|
59
|
+
hint: "Bun.secrets 无枚举 API;secret list 仅在 Windows(通过 cmdkey)支持",
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
try {
|
|
63
|
+
const out = await exec(["cmdkey", "/list"]);
|
|
64
|
+
return { names: parseSecretNamesFromCmdkey(out), supported: true };
|
|
65
|
+
} catch (e) {
|
|
66
|
+
return {
|
|
67
|
+
names: [],
|
|
68
|
+
supported: false,
|
|
69
|
+
hint: `cmdkey 调用失败: ${e instanceof Error ? e.message : String(e)}`,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { createPaths } from "../paths";
|
|
2
|
+
import { prepareHome } from "../migration";
|
|
3
|
+
import { loadConfig, getConnectionConfig } from "../config/config";
|
|
4
|
+
import { SecretsManager } from "../secrets/secrets";
|
|
5
|
+
import { applyLimits, validateConnectionInput } from "../policy/policy";
|
|
6
|
+
import { NativeExtensionProvider } from "../runtime/providers/native/provider";
|
|
7
|
+
import { createToolRuntime } from "../runtime/runtime";
|
|
8
|
+
import type { ToolDescriptor } from "../runtime/provider";
|
|
9
|
+
|
|
10
|
+
export function homeDir(): string {
|
|
11
|
+
return createPaths().home;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export async function createRuntime() {
|
|
15
|
+
const paths = createPaths();
|
|
16
|
+
await prepareHome(paths);
|
|
17
|
+
const config = loadConfig(paths.home);
|
|
18
|
+
const secrets = new SecretsManager();
|
|
19
|
+
return createToolRuntime({
|
|
20
|
+
providers: [new NativeExtensionProvider(paths)],
|
|
21
|
+
policy: {
|
|
22
|
+
preflight(descriptor, input) {
|
|
23
|
+
const limits = applyLimits(input);
|
|
24
|
+
input.maxRows = limits.maxRows;
|
|
25
|
+
input.timeoutMs = limits.timeoutMs;
|
|
26
|
+
const extensionId = descriptor.source.id;
|
|
27
|
+
const schema = descriptor.inputSchema as { properties?: Record<string, unknown> } | undefined;
|
|
28
|
+
const needsConnection = Boolean(schema?.properties && "connection" in schema.properties) || "connection" in input;
|
|
29
|
+
if (needsConnection) validateConnectionInput(input, config, extensionId);
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
createExecutionContext(descriptor: ToolDescriptor, input: Record<string, unknown>) {
|
|
33
|
+
const extensionId = descriptor.source.id;
|
|
34
|
+
const connection = typeof input.connection === "string"
|
|
35
|
+
? getConnectionConfig(config, extensionId, input.connection)
|
|
36
|
+
: undefined;
|
|
37
|
+
return {
|
|
38
|
+
logger: { debug() {}, info() {}, warn() {}, error() {} },
|
|
39
|
+
config: (connection ?? {}) as Record<string, unknown>,
|
|
40
|
+
secrets,
|
|
41
|
+
};
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
}
|