@oh-my-tool/cli 0.2.0 → 0.3.1

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.
Files changed (49) hide show
  1. package/README.md +7 -2
  2. package/assets/skills/oh-my-tool/SKILL.md +11 -3
  3. package/bin/ohmytool.cjs +0 -0
  4. package/package.json +20 -11
  5. package/src/cli/commands/connections.ts +98 -0
  6. package/src/cli/commands/describe.ts +23 -22
  7. package/src/cli/commands/extension.ts +24 -24
  8. package/src/cli/commands/index.ts +8 -6
  9. package/src/cli/commands/integrate.ts +64 -64
  10. package/src/cli/commands/mcp.ts +86 -0
  11. package/src/cli/commands/run.ts +14 -8
  12. package/src/cli/commands/search.ts +14 -13
  13. package/src/cli/commands/secret.ts +68 -68
  14. package/src/cli/context.ts +37 -4
  15. package/src/cli/index.ts +338 -273
  16. package/src/cli/output.ts +165 -0
  17. package/src/cli/parseArgs.ts +64 -44
  18. package/src/config/config.ts +207 -63
  19. package/src/core/executor.ts +89 -89
  20. package/src/core/registry.ts +31 -31
  21. package/src/core/result.ts +14 -14
  22. package/src/extension/discovery.ts +61 -61
  23. package/src/extension/install.ts +23 -23
  24. package/src/extension/loader.ts +32 -32
  25. package/src/extension/manifest.ts +114 -114
  26. package/src/integration/adapters.ts +98 -98
  27. package/src/integration/index.ts +4 -4
  28. package/src/integration/manager.ts +375 -375
  29. package/src/integration/skill.ts +84 -84
  30. package/src/integration/types.ts +55 -55
  31. package/src/policy/policy.ts +136 -136
  32. package/src/runtime/errors.ts +7 -2
  33. package/src/runtime/executor.ts +6 -1
  34. package/src/runtime/provider.ts +2 -1
  35. package/src/runtime/providers/mcp/normalize.ts +36 -0
  36. package/src/runtime/providers/mcp/oauth-callback.ts +91 -0
  37. package/src/runtime/providers/mcp/oauth-provider.ts +348 -0
  38. package/src/runtime/providers/mcp/oauth-store.ts +106 -0
  39. package/src/runtime/providers/mcp/provider.ts +99 -0
  40. package/src/runtime/providers/mcp/safe-errors.ts +63 -0
  41. package/src/runtime/providers/mcp/session.ts +117 -0
  42. package/src/runtime/providers/mcp/transport.ts +140 -0
  43. package/src/runtime/providers/native/provider.ts +1 -1
  44. package/src/runtime/result.ts +1 -1
  45. package/src/runtime/runtime.ts +38 -12
  46. package/src/runtime/schema.ts +14 -4
  47. package/src/search/search.ts +78 -78
  48. package/src/secrets/secrets.ts +45 -45
  49. package/src/version.ts +1 -1
@@ -1,72 +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
-
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
38
  async function defaultCmdkeyList(): Promise<string> {
39
39
  const proc = Bun.spawn(["cmdkey", "/list"], { stdout: "pipe", stderr: "pipe" });
40
40
  const output = await Bun.readableStreamToArrayBuffer(proc.stdout);
41
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
- }
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
+ }
@@ -1,9 +1,11 @@
1
1
  import { createPaths } from "../paths";
2
2
  import { prepareHome } from "../migration";
3
- import { loadConfig, getConnectionConfig } from "../config/config";
3
+ import { loadConfig, getConnectionConfig, sanitizeExtensionConnections, type McpEnabledServerConfig } from "../config/config";
4
4
  import { SecretsManager } from "../secrets/secrets";
5
5
  import { applyLimits, validateConnectionInput } from "../policy/policy";
6
6
  import { NativeExtensionProvider } from "../runtime/providers/native/provider";
7
+ import { McpProvider } from "../runtime/providers/mcp/provider";
8
+ import { discoverExtensions } from "../extension/discovery";
7
9
  import { createToolRuntime } from "../runtime/runtime";
8
10
  import type { ToolDescriptor } from "../runtime/provider";
9
11
 
@@ -11,15 +13,29 @@ export function homeDir(): string {
11
13
  return createPaths().home;
12
14
  }
13
15
 
14
- export async function createRuntime() {
16
+ export interface RuntimeOptions {
17
+ readonly includeMcp?: boolean;
18
+ readonly targetTool?: string;
19
+ }
20
+
21
+ export async function createRuntime(options: RuntimeOptions = {}) {
15
22
  const paths = createPaths();
16
23
  await prepareHome(paths);
17
24
  const config = loadConfig(paths.home);
18
25
  const secrets = new SecretsManager();
26
+ const extensionConnections = sanitizeExtensionConnections(config);
27
+ const nativeTarget = options.targetTool !== undefined && discoverExtensions(paths.home)
28
+ .some((extension) => extension.manifest.tools.some((tool) => tool.name === options.targetTool));
29
+ const mcpProviders = options.includeMcp === false || nativeTarget ? [] : Object.entries(config.mcp.servers)
30
+ .sort(([a], [b]) => a.localeCompare(b))
31
+ .filter((entry): entry is [string, McpEnabledServerConfig] => entry[1].enabled)
32
+ .map(([serverId, server]) => new McpProvider({ serverId, config: server, secrets }));
33
+ const providers = [new NativeExtensionProvider(paths), ...mcpProviders];
19
34
  return createToolRuntime({
20
- providers: [new NativeExtensionProvider(paths)],
35
+ providers,
21
36
  policy: {
22
37
  preflight(descriptor, input) {
38
+ if (descriptor.provider.kind !== "native") return;
23
39
  const limits = applyLimits(input);
24
40
  input.maxRows = limits.maxRows;
25
41
  input.timeoutMs = limits.timeoutMs;
@@ -36,9 +52,26 @@ export async function createRuntime() {
36
52
  : undefined;
37
53
  return {
38
54
  logger: { debug() {}, info() {}, warn() {}, error() {} },
39
- config: (connection ?? {}) as Record<string, unknown>,
55
+ config: (connection ?? { connections: extensionConnections[extensionId] ?? {} }) as Record<string, unknown>,
40
56
  secrets,
41
57
  };
42
58
  },
43
59
  });
44
60
  }
61
+
62
+ export async function withRuntime<T>(operation: (runtime: Awaited<ReturnType<typeof createRuntime>>) => Promise<T>, options: RuntimeOptions = {}): Promise<T> {
63
+ const runtime = await createRuntime(options);
64
+ let operationFailed = false;
65
+ try {
66
+ return await operation(runtime);
67
+ } catch (error) {
68
+ operationFailed = true;
69
+ throw error;
70
+ } finally {
71
+ try {
72
+ await runtime.close();
73
+ } catch (closeError) {
74
+ if (!operationFailed) throw closeError;
75
+ }
76
+ }
77
+ }