openpets 1.0.4 → 1.0.6
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/data/api.json +3172 -0
- package/dist/src/core/ai-client-base/index.d.ts +47 -0
- package/dist/src/core/ai-client-base/index.d.ts.map +1 -0
- package/dist/src/core/ai-client-base/index.js +168 -0
- package/dist/src/core/ai-client-base/index.js.map +1 -0
- package/dist/src/core/browser.d.ts +10 -0
- package/dist/src/core/browser.d.ts.map +1 -0
- package/{browser.ts → dist/src/core/browser.js} +4 -4
- package/dist/src/core/browser.js.map +1 -0
- package/dist/src/core/build-pet.d.ts +2 -0
- package/dist/src/core/build-pet.d.ts.map +1 -0
- package/dist/src/core/build-pet.js +364 -0
- package/dist/src/core/build-pet.js.map +1 -0
- package/dist/src/core/cli.d.ts +3 -0
- package/dist/src/core/cli.d.ts.map +1 -0
- package/dist/src/core/cli.js +244 -0
- package/dist/src/core/cli.js.map +1 -0
- package/dist/src/core/config-manager.d.ts +13 -0
- package/dist/src/core/config-manager.d.ts.map +1 -0
- package/dist/src/core/config-manager.js +59 -0
- package/dist/src/core/config-manager.js.map +1 -0
- package/dist/src/core/deploy-pet.d.ts +2 -0
- package/dist/src/core/deploy-pet.d.ts.map +1 -0
- package/dist/src/core/deploy-pet.js +66 -0
- package/dist/src/core/deploy-pet.js.map +1 -0
- package/dist/src/core/index.d.ts +11 -0
- package/dist/src/core/index.d.ts.map +1 -0
- package/dist/src/core/index.js +11 -0
- package/dist/src/core/index.js.map +1 -0
- package/dist/src/core/local-cache.d.ts +69 -0
- package/dist/src/core/local-cache.d.ts.map +1 -0
- package/dist/src/core/local-cache.js +212 -0
- package/dist/src/core/local-cache.js.map +1 -0
- package/dist/src/core/logger.d.ts.map +1 -0
- package/{logger.js → dist/src/core/logger.js} +8 -9
- package/dist/src/core/logger.js.map +1 -0
- package/dist/src/core/mcp-factory.d.ts +12 -0
- package/dist/src/core/mcp-factory.d.ts.map +1 -0
- package/dist/src/core/mcp-factory.js +143 -0
- package/dist/src/core/mcp-factory.js.map +1 -0
- package/dist/src/core/mcp-server.d.ts +3 -0
- package/dist/src/core/mcp-server.d.ts.map +1 -0
- package/dist/src/core/mcp-server.js +55 -0
- package/dist/src/core/mcp-server.js.map +1 -0
- package/dist/src/core/migrate-plugin.d.ts +15 -0
- package/dist/src/core/migrate-plugin.d.ts.map +1 -0
- package/dist/src/core/migrate-plugin.js +181 -0
- package/dist/src/core/migrate-plugin.js.map +1 -0
- package/dist/src/core/pets-registry.d.ts +47 -0
- package/dist/src/core/pets-registry.d.ts.map +1 -0
- package/dist/src/core/pets-registry.js +109 -0
- package/dist/src/core/pets-registry.js.map +1 -0
- package/dist/src/core/plugin-factory.d.ts +58 -0
- package/dist/src/core/plugin-factory.d.ts.map +1 -0
- package/dist/src/core/plugin-factory.js +212 -0
- package/dist/src/core/plugin-factory.js.map +1 -0
- package/dist/src/core/prompt-utils.d.ts +14 -0
- package/dist/src/core/prompt-utils.d.ts.map +1 -0
- package/dist/src/core/prompt-utils.js +106 -0
- package/dist/src/core/prompt-utils.js.map +1 -0
- package/dist/src/core/schema-helpers.d.ts +33 -0
- package/dist/src/core/schema-helpers.d.ts.map +1 -0
- package/dist/src/core/schema-helpers.js +46 -0
- package/dist/src/core/schema-helpers.js.map +1 -0
- package/dist/src/core/search-pets.d.ts +29 -0
- package/dist/src/core/search-pets.d.ts.map +1 -0
- package/dist/src/core/search-pets.js +196 -0
- package/dist/src/core/search-pets.js.map +1 -0
- package/dist/src/core/types.d.ts +63 -0
- package/dist/src/core/types.d.ts.map +1 -0
- package/dist/src/core/types.js +2 -0
- package/dist/src/core/types.js.map +1 -0
- package/dist/src/core/validate-pet.d.ts +40 -0
- package/dist/src/core/validate-pet.d.ts.map +1 -0
- package/dist/src/core/validate-pet.js +650 -0
- package/dist/src/core/validate-pet.js.map +1 -0
- package/package.json +7 -11
- package/ai-client-base/index.ts +0 -117
- package/build-pet.ts +0 -429
- package/cli.ts +0 -179
- package/config-manager.ts +0 -82
- package/deploy-pet.ts +0 -91
- package/index.ts +0 -10
- package/local-cache.ts +0 -280
- package/logger.ts +0 -143
- package/mcp-factory.ts +0 -180
- package/mcp-server.ts +0 -69
- package/migrate-plugin.ts +0 -220
- package/pets-registry.ts +0 -160
- package/plugin-factory.ts +0 -309
- package/prompt-utils.ts +0 -130
- package/schema-helpers.ts +0 -59
- package/search-pets.ts +0 -267
- package/types.ts +0 -68
- package/validate-pet.ts +0 -594
- /package/{logger.d.ts → dist/src/core/logger.d.ts} +0 -0
package/logger.ts
DELETED
|
@@ -1,143 +0,0 @@
|
|
|
1
|
-
export enum LogLevel {
|
|
2
|
-
DEBUG = 0,
|
|
3
|
-
INFO = 1,
|
|
4
|
-
WARN = 2,
|
|
5
|
-
ERROR = 3,
|
|
6
|
-
NONE = 4
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
const LOG_LEVEL_NAMES: Record<LogLevel, string> = {
|
|
10
|
-
[LogLevel.DEBUG]: 'DEBUG',
|
|
11
|
-
[LogLevel.INFO]: 'INFO',
|
|
12
|
-
[LogLevel.WARN]: 'WARN',
|
|
13
|
-
[LogLevel.ERROR]: 'ERROR',
|
|
14
|
-
[LogLevel.NONE]: 'NONE'
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
interface LoggerOptions {
|
|
18
|
-
namespace: string
|
|
19
|
-
level?: LogLevel
|
|
20
|
-
enabled?: boolean
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export class Logger {
|
|
24
|
-
private namespace: string
|
|
25
|
-
private level: LogLevel
|
|
26
|
-
private enabled: boolean
|
|
27
|
-
|
|
28
|
-
constructor(options: LoggerOptions) {
|
|
29
|
-
this.namespace = options.namespace
|
|
30
|
-
this.enabled = options.enabled ?? this.detectLoggingEnabled()
|
|
31
|
-
this.level = options.level ?? this.detectLogLevel()
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
private detectLoggingEnabled(): boolean {
|
|
35
|
-
return process.env.ENABLE_LOGGING === 'true' ||
|
|
36
|
-
process.env.DEBUG === 'true' ||
|
|
37
|
-
process.argv.includes('--print-logs')
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
private detectLogLevel(): LogLevel {
|
|
41
|
-
const envLevel = process.env.LOG_LEVEL?.toUpperCase()
|
|
42
|
-
const argLevel = this.getArgLogLevel()
|
|
43
|
-
|
|
44
|
-
const levelStr = argLevel || envLevel || 'INFO'
|
|
45
|
-
|
|
46
|
-
switch (levelStr) {
|
|
47
|
-
case 'DEBUG':
|
|
48
|
-
return LogLevel.DEBUG
|
|
49
|
-
case 'INFO':
|
|
50
|
-
return LogLevel.INFO
|
|
51
|
-
case 'WARN':
|
|
52
|
-
return LogLevel.WARN
|
|
53
|
-
case 'ERROR':
|
|
54
|
-
return LogLevel.ERROR
|
|
55
|
-
case 'NONE':
|
|
56
|
-
return LogLevel.NONE
|
|
57
|
-
default:
|
|
58
|
-
return LogLevel.INFO
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
private getArgLogLevel(): string | undefined {
|
|
63
|
-
const logLevelIndex = process.argv.indexOf('--log-level')
|
|
64
|
-
if (logLevelIndex !== -1 && process.argv[logLevelIndex + 1]) {
|
|
65
|
-
return process.argv[logLevelIndex + 1].toUpperCase()
|
|
66
|
-
}
|
|
67
|
-
return undefined
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
private shouldLog(level: LogLevel): boolean {
|
|
71
|
-
return this.enabled && level >= this.level
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
private formatTimestamp(): string {
|
|
75
|
-
const now = new Date()
|
|
76
|
-
const year = now.getFullYear()
|
|
77
|
-
const month = String(now.getMonth() + 1).padStart(2, '0')
|
|
78
|
-
const day = String(now.getDate()).padStart(2, '0')
|
|
79
|
-
const hours = String(now.getHours()).padStart(2, '0')
|
|
80
|
-
const minutes = String(now.getMinutes()).padStart(2, '0')
|
|
81
|
-
const seconds = String(now.getSeconds()).padStart(2, '0')
|
|
82
|
-
return `${year}-${month}-${day}T${hours}:${minutes}:${seconds}`
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
private formatMessage(level: LogLevel, message: string, ...args: any[]): string {
|
|
86
|
-
const timestamp = this.formatTimestamp()
|
|
87
|
-
const levelName = LOG_LEVEL_NAMES[level].padEnd(5, ' ')
|
|
88
|
-
const prefix = `${levelName} ${timestamp} service=${this.namespace}`
|
|
89
|
-
|
|
90
|
-
if (args.length === 0) {
|
|
91
|
-
return `${prefix} ${message}`
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
const formattedArgs = args.map(arg => {
|
|
95
|
-
if (typeof arg === 'object') {
|
|
96
|
-
return JSON.stringify(arg, null, 2)
|
|
97
|
-
}
|
|
98
|
-
return String(arg)
|
|
99
|
-
}).join(' ')
|
|
100
|
-
|
|
101
|
-
return `${prefix} ${message} ${formattedArgs}`
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
debug(message: string, ...args: any[]): void {
|
|
105
|
-
if (this.shouldLog(LogLevel.DEBUG)) {
|
|
106
|
-
console.log(this.formatMessage(LogLevel.DEBUG, message, ...args))
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
info(message: string, ...args: any[]): void {
|
|
111
|
-
if (this.shouldLog(LogLevel.INFO)) {
|
|
112
|
-
console.log(this.formatMessage(LogLevel.INFO, message, ...args))
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
warn(message: string, ...args: any[]): void {
|
|
117
|
-
if (this.shouldLog(LogLevel.WARN)) {
|
|
118
|
-
console.warn(this.formatMessage(LogLevel.WARN, message, ...args))
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
error(message: string, ...args: any[]): void {
|
|
123
|
-
if (this.shouldLog(LogLevel.ERROR)) {
|
|
124
|
-
console.error(this.formatMessage(LogLevel.ERROR, message, ...args))
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
child(subNamespace: string): Logger {
|
|
129
|
-
return new Logger({
|
|
130
|
-
namespace: `${this.namespace}:${subNamespace}`,
|
|
131
|
-
level: this.level,
|
|
132
|
-
enabled: this.enabled
|
|
133
|
-
})
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
export function createLogger(namespace: string, options?: Partial<LoggerOptions>): Logger {
|
|
138
|
-
return new Logger({
|
|
139
|
-
namespace,
|
|
140
|
-
level: options?.level,
|
|
141
|
-
enabled: options?.enabled
|
|
142
|
-
})
|
|
143
|
-
}
|
package/mcp-factory.ts
DELETED
|
@@ -1,180 +0,0 @@
|
|
|
1
|
-
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
2
|
-
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
3
|
-
import {
|
|
4
|
-
CallToolRequestSchema,
|
|
5
|
-
ListToolsRequestSchema,
|
|
6
|
-
Tool,
|
|
7
|
-
} from "@modelcontextprotocol/sdk/types.js";
|
|
8
|
-
import type { ToolDefinition, ToolRecord } from "./plugin-factory";
|
|
9
|
-
import { createLogger } from "./logger";
|
|
10
|
-
|
|
11
|
-
const logger = createLogger("mcp-factory");
|
|
12
|
-
|
|
13
|
-
export interface MCPServerConfig {
|
|
14
|
-
name: string;
|
|
15
|
-
version: string;
|
|
16
|
-
description?: string;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export function extractToolsFromPlugin(pluginModule: any): ToolDefinition[] {
|
|
20
|
-
const tools: ToolDefinition[] = [];
|
|
21
|
-
|
|
22
|
-
if (pluginModule.tool && typeof pluginModule.tool === "object") {
|
|
23
|
-
const toolRecord = pluginModule.tool as ToolRecord;
|
|
24
|
-
|
|
25
|
-
for (const [name, toolDef] of Object.entries(toolRecord)) {
|
|
26
|
-
tools.push({
|
|
27
|
-
name: name,
|
|
28
|
-
description: toolDef.description,
|
|
29
|
-
schema: toolDef.args,
|
|
30
|
-
execute: toolDef.execute,
|
|
31
|
-
});
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
return tools;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
function convertToolToMCPSchema(tool: ToolDefinition): Tool {
|
|
39
|
-
const schema = tool.schema as any;
|
|
40
|
-
const shape = schema.shape || schema._def?.shape?.();
|
|
41
|
-
|
|
42
|
-
const properties: Record<string, any> = {};
|
|
43
|
-
const required: string[] = [];
|
|
44
|
-
|
|
45
|
-
if (shape) {
|
|
46
|
-
for (const [key, value] of Object.entries(shape)) {
|
|
47
|
-
const fieldSchema = value as any;
|
|
48
|
-
const fieldType = fieldSchema._def?.typeName;
|
|
49
|
-
|
|
50
|
-
if (fieldType === "ZodString") {
|
|
51
|
-
properties[key] = {
|
|
52
|
-
type: "string",
|
|
53
|
-
description: fieldSchema._def?.description || "",
|
|
54
|
-
};
|
|
55
|
-
} else if (fieldType === "ZodNumber") {
|
|
56
|
-
properties[key] = {
|
|
57
|
-
type: "number",
|
|
58
|
-
description: fieldSchema._def?.description || "",
|
|
59
|
-
};
|
|
60
|
-
} else if (fieldType === "ZodBoolean") {
|
|
61
|
-
properties[key] = {
|
|
62
|
-
type: "boolean",
|
|
63
|
-
description: fieldSchema._def?.description || "",
|
|
64
|
-
};
|
|
65
|
-
} else if (fieldType === "ZodArray") {
|
|
66
|
-
const elementType = fieldSchema._def?.type?._def?.typeName;
|
|
67
|
-
properties[key] = {
|
|
68
|
-
type: "array",
|
|
69
|
-
items: {
|
|
70
|
-
type: elementType === "ZodString" ? "string" : elementType === "ZodNumber" ? "number" : "string",
|
|
71
|
-
},
|
|
72
|
-
description: fieldSchema._def?.description || "",
|
|
73
|
-
};
|
|
74
|
-
} else {
|
|
75
|
-
properties[key] = {
|
|
76
|
-
type: "string",
|
|
77
|
-
description: fieldSchema._def?.description || "",
|
|
78
|
-
};
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
if (!fieldSchema._def?.checks?.some((check: any) => check.kind === "optional")) {
|
|
82
|
-
if (fieldSchema._def?.typeName !== "ZodOptional") {
|
|
83
|
-
required.push(key);
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
return {
|
|
90
|
-
name: tool.name.replace(/-/g, "_"),
|
|
91
|
-
description: tool.description,
|
|
92
|
-
inputSchema: {
|
|
93
|
-
type: "object",
|
|
94
|
-
properties,
|
|
95
|
-
...(required.length > 0 ? { required } : {}),
|
|
96
|
-
},
|
|
97
|
-
};
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
export function createMCPServer(
|
|
101
|
-
config: MCPServerConfig,
|
|
102
|
-
tools: ToolDefinition[]
|
|
103
|
-
): Server {
|
|
104
|
-
const server = new Server(
|
|
105
|
-
{
|
|
106
|
-
name: config.name,
|
|
107
|
-
version: config.version,
|
|
108
|
-
},
|
|
109
|
-
{
|
|
110
|
-
capabilities: {
|
|
111
|
-
tools: {},
|
|
112
|
-
},
|
|
113
|
-
}
|
|
114
|
-
);
|
|
115
|
-
|
|
116
|
-
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
117
|
-
tools: tools.map((tool) => convertToolToMCPSchema(tool)),
|
|
118
|
-
}));
|
|
119
|
-
|
|
120
|
-
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
121
|
-
const { name, arguments: args } = request.params as {
|
|
122
|
-
name: string;
|
|
123
|
-
arguments: any;
|
|
124
|
-
};
|
|
125
|
-
|
|
126
|
-
const tool = tools.find((t) => t.name.replace(/-/g, "_") === name);
|
|
127
|
-
|
|
128
|
-
if (!tool) {
|
|
129
|
-
return {
|
|
130
|
-
content: [
|
|
131
|
-
{
|
|
132
|
-
type: "text",
|
|
133
|
-
text: `Error: Unknown tool: ${name}`,
|
|
134
|
-
},
|
|
135
|
-
],
|
|
136
|
-
isError: true,
|
|
137
|
-
};
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
try {
|
|
141
|
-
const result = await tool.execute(args);
|
|
142
|
-
return {
|
|
143
|
-
content: [
|
|
144
|
-
{
|
|
145
|
-
type: "text",
|
|
146
|
-
text: result,
|
|
147
|
-
},
|
|
148
|
-
],
|
|
149
|
-
};
|
|
150
|
-
} catch (error) {
|
|
151
|
-
return {
|
|
152
|
-
content: [
|
|
153
|
-
{
|
|
154
|
-
type: "text",
|
|
155
|
-
text: `Error executing ${name}: ${error}`,
|
|
156
|
-
},
|
|
157
|
-
],
|
|
158
|
-
isError: true,
|
|
159
|
-
};
|
|
160
|
-
}
|
|
161
|
-
});
|
|
162
|
-
|
|
163
|
-
return server;
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
export async function startMCPServer(server: Server): Promise<void> {
|
|
167
|
-
const transport = new StdioServerTransport();
|
|
168
|
-
await server.connect(transport);
|
|
169
|
-
console.error(`MCP server running on stdio`);
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
export function createMCPServerFromTools(
|
|
173
|
-
config: MCPServerConfig,
|
|
174
|
-
tools: ToolDefinition[]
|
|
175
|
-
): () => Promise<void> {
|
|
176
|
-
return async () => {
|
|
177
|
-
const server = createMCPServer(config, tools);
|
|
178
|
-
await startMCPServer(server);
|
|
179
|
-
};
|
|
180
|
-
}
|
package/mcp-server.ts
DELETED
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
import { createMCPServer, startMCPServer, extractToolsFromPlugin } from "./mcp-factory";
|
|
4
|
-
import { createLogger } from "./logger";
|
|
5
|
-
import { resolve } from "path";
|
|
6
|
-
import { readFileSync } from "fs";
|
|
7
|
-
|
|
8
|
-
const logger = createLogger("mcp-server");
|
|
9
|
-
|
|
10
|
-
async function main() {
|
|
11
|
-
const petName = process.argv[2] || process.env.PET_NAME;
|
|
12
|
-
|
|
13
|
-
if (!petName) {
|
|
14
|
-
logger.error("Pet name is required. Usage: node mcp-server.js <pet-name>");
|
|
15
|
-
logger.error("Example: node mcp-server.js polar");
|
|
16
|
-
logger.error("Or set PET_NAME environment variable");
|
|
17
|
-
process.exit(1);
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
logger.info("Starting MCP server for pet", { petName });
|
|
21
|
-
|
|
22
|
-
try {
|
|
23
|
-
const petPath = resolve(__dirname, `../../pets/${petName}`);
|
|
24
|
-
const packageJsonPath = resolve(petPath, "package.json");
|
|
25
|
-
|
|
26
|
-
let packageJson: any;
|
|
27
|
-
try {
|
|
28
|
-
packageJson = JSON.parse(readFileSync(packageJsonPath, "utf-8"));
|
|
29
|
-
} catch (error) {
|
|
30
|
-
logger.error("Failed to read package.json", { petPath: packageJsonPath, error: String(error) });
|
|
31
|
-
process.exit(1);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
const pluginModule = await import(`../../pets/${petName}/index.js`);
|
|
35
|
-
|
|
36
|
-
let plugin;
|
|
37
|
-
if (typeof pluginModule.default === "function") {
|
|
38
|
-
plugin = await pluginModule.default();
|
|
39
|
-
} else {
|
|
40
|
-
plugin = pluginModule.default;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
const tools = extractToolsFromPlugin(plugin);
|
|
44
|
-
|
|
45
|
-
if (tools.length === 0) {
|
|
46
|
-
logger.error("No tools found in plugin", { petName });
|
|
47
|
-
process.exit(1);
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
logger.info("Extracted tools from plugin", { petName, toolCount: tools.length });
|
|
51
|
-
|
|
52
|
-
const server = createMCPServer(
|
|
53
|
-
{
|
|
54
|
-
name: packageJson.name || `openpets/${petName}`,
|
|
55
|
-
version: packageJson.version || "1.0.0",
|
|
56
|
-
description: packageJson.description || `${petName} MCP server`,
|
|
57
|
-
},
|
|
58
|
-
tools
|
|
59
|
-
);
|
|
60
|
-
|
|
61
|
-
await startMCPServer(server);
|
|
62
|
-
} catch (error) {
|
|
63
|
-
logger.error("Fatal error starting MCP server", { petName, error: String(error) });
|
|
64
|
-
console.error(error);
|
|
65
|
-
process.exit(1);
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
main();
|
package/migrate-plugin.ts
DELETED
|
@@ -1,220 +0,0 @@
|
|
|
1
|
-
import { readFileSync, writeFileSync, existsSync } from 'fs'
|
|
2
|
-
import { join } from 'path'
|
|
3
|
-
|
|
4
|
-
export interface MigrationResult {
|
|
5
|
-
success: boolean
|
|
6
|
-
changes: string[]
|
|
7
|
-
errors: string[]
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export class PluginMigrator {
|
|
11
|
-
migratePlugin(pluginPath: string): MigrationResult {
|
|
12
|
-
const indexPath = join(pluginPath, 'index.ts')
|
|
13
|
-
const changes: string[] = []
|
|
14
|
-
const errors: string[] = []
|
|
15
|
-
|
|
16
|
-
if (!existsSync(indexPath)) {
|
|
17
|
-
return {
|
|
18
|
-
success: false,
|
|
19
|
-
changes,
|
|
20
|
-
errors: ['index.ts not found']
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
try {
|
|
25
|
-
let code = readFileSync(indexPath, 'utf-8')
|
|
26
|
-
const original = code
|
|
27
|
-
|
|
28
|
-
code = this.addImports(code, changes)
|
|
29
|
-
code = this.convertInputSchemaToToolBuilder(code, changes)
|
|
30
|
-
|
|
31
|
-
if (code !== original) {
|
|
32
|
-
writeFileSync(indexPath, code, 'utf-8')
|
|
33
|
-
return { success: true, changes, errors }
|
|
34
|
-
} else {
|
|
35
|
-
return { success: true, changes: ['No changes needed'], errors }
|
|
36
|
-
}
|
|
37
|
-
} catch (error) {
|
|
38
|
-
errors.push(`Migration failed: ${error instanceof Error ? error.message : String(error)}`)
|
|
39
|
-
return { success: false, changes, errors }
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
private addImports(code: string, changes: string[]): string {
|
|
44
|
-
const hasToolImport = /import\s+{\s*tool\s*}\s+from\s+['"]@opencode-ai\/plugin['"]/.test(code)
|
|
45
|
-
const hasZodImport = /import.*from\s+['"]zod['"]/.test(code)
|
|
46
|
-
const hasPluginImport = /import.*from\s+['"]@opencode-ai\/plugin['"]/.test(code)
|
|
47
|
-
|
|
48
|
-
if (!hasPluginImport) {
|
|
49
|
-
code = `import type { Plugin } from "@opencode-ai/plugin"\n${code}`
|
|
50
|
-
changes.push('Added Plugin type import')
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
if (!hasToolImport) {
|
|
54
|
-
if (hasPluginImport) {
|
|
55
|
-
code = code.replace(
|
|
56
|
-
/import\s+(type\s+)?\{([^}]+)\}\s+from\s+['"]@opencode-ai\/plugin['"]/,
|
|
57
|
-
(match, typeKeyword, imports) => {
|
|
58
|
-
if (typeKeyword) {
|
|
59
|
-
return match.replace('}', ', tool }').replace('type ', '')
|
|
60
|
-
}
|
|
61
|
-
const cleanImports = imports.split(',').map((s: string) => s.trim()).filter(Boolean)
|
|
62
|
-
if (!cleanImports.includes('tool')) {
|
|
63
|
-
cleanImports.push('tool')
|
|
64
|
-
}
|
|
65
|
-
return `import { ${cleanImports.join(', ')} } from "@opencode-ai/plugin"`
|
|
66
|
-
}
|
|
67
|
-
)
|
|
68
|
-
} else {
|
|
69
|
-
code = `import { tool } from "@opencode-ai/plugin"\n${code}`
|
|
70
|
-
}
|
|
71
|
-
changes.push('Added tool import from @opencode-ai/plugin')
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
if (!hasZodImport) {
|
|
75
|
-
const pluginImportIndex = code.indexOf('import')
|
|
76
|
-
const firstNewline = code.indexOf('\n', pluginImportIndex)
|
|
77
|
-
code = code.slice(0, firstNewline + 1) + `import { z } from "zod"\n` + code.slice(firstNewline + 1)
|
|
78
|
-
changes.push('Added Zod import')
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
return code
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
private convertInputSchemaToToolBuilder(code: string, changes: string[]): string {
|
|
85
|
-
const toolPattern = /"([^"]+)":\s*{\s*description:\s*"([^"]+)",\s*inputSchema:\s*(\{[\s\S]*?\}),\s*async\s+execute\s*\(([^)]*)\)\s*(\{[\s\S]*?\n\s*\})\s*\}/g
|
|
86
|
-
|
|
87
|
-
let matchCount = 0
|
|
88
|
-
code = code.replace(toolPattern, (match, toolName, description, inputSchemaStr, argsParam, executeBody) => {
|
|
89
|
-
matchCount++
|
|
90
|
-
|
|
91
|
-
try {
|
|
92
|
-
const inputSchema = this.parseInputSchema(inputSchemaStr)
|
|
93
|
-
const zodArgs = this.convertToZodSchema(inputSchema)
|
|
94
|
-
|
|
95
|
-
const converted = `"${toolName}": tool({
|
|
96
|
-
description: "${description}",
|
|
97
|
-
args: ${zodArgs},
|
|
98
|
-
async execute(${argsParam}) ${executeBody}
|
|
99
|
-
})`
|
|
100
|
-
|
|
101
|
-
return converted
|
|
102
|
-
} catch (error) {
|
|
103
|
-
console.warn(`Failed to convert tool "${toolName}": ${error}`)
|
|
104
|
-
return match
|
|
105
|
-
}
|
|
106
|
-
})
|
|
107
|
-
|
|
108
|
-
if (matchCount > 0) {
|
|
109
|
-
changes.push(`Converted ${matchCount} tool(s) from inputSchema to tool() builder`)
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
return code
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
private parseInputSchema(schemaStr: string): any {
|
|
116
|
-
const cleaned = schemaStr
|
|
117
|
-
.replace(/\/\/.*$/gm, '')
|
|
118
|
-
.replace(/\/\*[\s\S]*?\*\//g, '')
|
|
119
|
-
.trim()
|
|
120
|
-
|
|
121
|
-
try {
|
|
122
|
-
const jsonStr = cleaned
|
|
123
|
-
.replace(/(\w+):/g, '"$1":')
|
|
124
|
-
.replace(/'/g, '"')
|
|
125
|
-
|
|
126
|
-
return JSON.parse(jsonStr)
|
|
127
|
-
} catch (error) {
|
|
128
|
-
return eval(`(${cleaned})`)
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
private convertToZodSchema(inputSchema: any): string {
|
|
133
|
-
if (!inputSchema.properties) {
|
|
134
|
-
return '{}'
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
const required = new Set(inputSchema.required || [])
|
|
138
|
-
const properties = inputSchema.properties
|
|
139
|
-
|
|
140
|
-
const zodFields: string[] = []
|
|
141
|
-
|
|
142
|
-
for (const [key, propDef] of Object.entries<any>(properties)) {
|
|
143
|
-
const isRequired = required.has(key)
|
|
144
|
-
let zodType = this.getZodType(propDef, isRequired)
|
|
145
|
-
|
|
146
|
-
const description = propDef.description
|
|
147
|
-
if (description) {
|
|
148
|
-
zodType += `.describe("${description.replace(/"/g, '\\"')}")`
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
zodFields.push(`${key}: ${zodType}`)
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
return `{\n ${zodFields.join(',\n ')}\n }`
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
private getZodType(propDef: any, isRequired: boolean): string {
|
|
158
|
-
let zodType: string
|
|
159
|
-
|
|
160
|
-
switch (propDef.type) {
|
|
161
|
-
case 'string':
|
|
162
|
-
if (propDef.enum && Array.isArray(propDef.enum)) {
|
|
163
|
-
zodType = `z.enum([${propDef.enum.map((v: string) => `"${v}"`).join(', ')}])`
|
|
164
|
-
} else {
|
|
165
|
-
zodType = 'z.string()'
|
|
166
|
-
}
|
|
167
|
-
break
|
|
168
|
-
|
|
169
|
-
case 'number':
|
|
170
|
-
zodType = 'z.number()'
|
|
171
|
-
break
|
|
172
|
-
|
|
173
|
-
case 'boolean':
|
|
174
|
-
zodType = 'z.boolean()'
|
|
175
|
-
break
|
|
176
|
-
|
|
177
|
-
case 'array':
|
|
178
|
-
if (propDef.items) {
|
|
179
|
-
const itemType = this.getZodType(propDef.items, true)
|
|
180
|
-
zodType = `z.array(${itemType})`
|
|
181
|
-
} else {
|
|
182
|
-
zodType = 'z.array(z.any())'
|
|
183
|
-
}
|
|
184
|
-
break
|
|
185
|
-
|
|
186
|
-
case 'object':
|
|
187
|
-
if (propDef.additionalProperties) {
|
|
188
|
-
const valueType = this.getZodType(propDef.additionalProperties, true)
|
|
189
|
-
zodType = `z.record(${valueType})`
|
|
190
|
-
} else {
|
|
191
|
-
zodType = 'z.object({})'
|
|
192
|
-
}
|
|
193
|
-
break
|
|
194
|
-
|
|
195
|
-
default:
|
|
196
|
-
zodType = 'z.any()'
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
if (!isRequired) {
|
|
200
|
-
zodType += '.optional()'
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
return zodType
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
printMigrationResult(pluginName: string, result: MigrationResult): void {
|
|
207
|
-
const status = result.success ? '✅' : '❌'
|
|
208
|
-
console.log(`\n${status} ${pluginName}`)
|
|
209
|
-
|
|
210
|
-
if (result.changes.length > 0) {
|
|
211
|
-
console.log(' Changes:')
|
|
212
|
-
result.changes.forEach(change => console.log(` • ${change}`))
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
if (result.errors.length > 0) {
|
|
216
|
-
console.log(' Errors:')
|
|
217
|
-
result.errors.forEach(error => console.log(` ❌ ${error}`))
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
}
|