openpets 1.0.5 → 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.
Files changed (96) hide show
  1. package/dist/data/api.json +3172 -0
  2. package/dist/src/core/ai-client-base/index.d.ts +47 -0
  3. package/dist/src/core/ai-client-base/index.d.ts.map +1 -0
  4. package/dist/src/core/ai-client-base/index.js +168 -0
  5. package/dist/src/core/ai-client-base/index.js.map +1 -0
  6. package/dist/src/core/browser.d.ts +10 -0
  7. package/dist/src/core/browser.d.ts.map +1 -0
  8. package/{browser.ts → dist/src/core/browser.js} +4 -4
  9. package/dist/src/core/browser.js.map +1 -0
  10. package/dist/src/core/build-pet.d.ts +2 -0
  11. package/dist/src/core/build-pet.d.ts.map +1 -0
  12. package/dist/src/core/build-pet.js +364 -0
  13. package/dist/src/core/build-pet.js.map +1 -0
  14. package/dist/src/core/cli.d.ts +3 -0
  15. package/dist/src/core/cli.d.ts.map +1 -0
  16. package/dist/src/core/cli.js +244 -0
  17. package/dist/src/core/cli.js.map +1 -0
  18. package/dist/src/core/config-manager.d.ts +13 -0
  19. package/dist/src/core/config-manager.d.ts.map +1 -0
  20. package/dist/src/core/config-manager.js +59 -0
  21. package/dist/src/core/config-manager.js.map +1 -0
  22. package/dist/src/core/deploy-pet.d.ts +2 -0
  23. package/dist/src/core/deploy-pet.d.ts.map +1 -0
  24. package/dist/src/core/deploy-pet.js +66 -0
  25. package/dist/src/core/deploy-pet.js.map +1 -0
  26. package/dist/src/core/index.d.ts +11 -0
  27. package/dist/src/core/index.d.ts.map +1 -0
  28. package/dist/src/core/index.js +11 -0
  29. package/dist/src/core/index.js.map +1 -0
  30. package/dist/src/core/local-cache.d.ts +69 -0
  31. package/dist/src/core/local-cache.d.ts.map +1 -0
  32. package/dist/src/core/local-cache.js +212 -0
  33. package/dist/src/core/local-cache.js.map +1 -0
  34. package/dist/src/core/logger.d.ts.map +1 -0
  35. package/{logger.js → dist/src/core/logger.js} +8 -9
  36. package/dist/src/core/logger.js.map +1 -0
  37. package/dist/src/core/mcp-factory.d.ts +12 -0
  38. package/dist/src/core/mcp-factory.d.ts.map +1 -0
  39. package/dist/src/core/mcp-factory.js +143 -0
  40. package/dist/src/core/mcp-factory.js.map +1 -0
  41. package/dist/src/core/mcp-server.d.ts +3 -0
  42. package/dist/src/core/mcp-server.d.ts.map +1 -0
  43. package/dist/src/core/mcp-server.js +55 -0
  44. package/dist/src/core/mcp-server.js.map +1 -0
  45. package/dist/src/core/migrate-plugin.d.ts +15 -0
  46. package/dist/src/core/migrate-plugin.d.ts.map +1 -0
  47. package/dist/src/core/migrate-plugin.js +181 -0
  48. package/dist/src/core/migrate-plugin.js.map +1 -0
  49. package/dist/src/core/pets-registry.d.ts +47 -0
  50. package/dist/src/core/pets-registry.d.ts.map +1 -0
  51. package/dist/src/core/pets-registry.js +109 -0
  52. package/dist/src/core/pets-registry.js.map +1 -0
  53. package/dist/src/core/plugin-factory.d.ts +58 -0
  54. package/dist/src/core/plugin-factory.d.ts.map +1 -0
  55. package/dist/src/core/plugin-factory.js +212 -0
  56. package/dist/src/core/plugin-factory.js.map +1 -0
  57. package/dist/src/core/prompt-utils.d.ts +14 -0
  58. package/dist/src/core/prompt-utils.d.ts.map +1 -0
  59. package/dist/src/core/prompt-utils.js +106 -0
  60. package/dist/src/core/prompt-utils.js.map +1 -0
  61. package/dist/src/core/schema-helpers.d.ts +33 -0
  62. package/dist/src/core/schema-helpers.d.ts.map +1 -0
  63. package/dist/src/core/schema-helpers.js +46 -0
  64. package/dist/src/core/schema-helpers.js.map +1 -0
  65. package/dist/src/core/search-pets.d.ts +29 -0
  66. package/dist/src/core/search-pets.d.ts.map +1 -0
  67. package/dist/src/core/search-pets.js +196 -0
  68. package/dist/src/core/search-pets.js.map +1 -0
  69. package/dist/src/core/types.d.ts +63 -0
  70. package/dist/src/core/types.d.ts.map +1 -0
  71. package/dist/src/core/types.js +2 -0
  72. package/dist/src/core/types.js.map +1 -0
  73. package/dist/src/core/validate-pet.d.ts +40 -0
  74. package/dist/src/core/validate-pet.d.ts.map +1 -0
  75. package/dist/src/core/validate-pet.js +650 -0
  76. package/dist/src/core/validate-pet.js.map +1 -0
  77. package/package.json +8 -21
  78. package/ai-client-base/index.ts +0 -229
  79. package/build-pet.ts +0 -429
  80. package/cli.ts +0 -268
  81. package/config-manager.ts +0 -82
  82. package/deploy-pet.ts +0 -91
  83. package/index.ts +0 -10
  84. package/local-cache.ts +0 -280
  85. package/logger.ts +0 -143
  86. package/mcp-factory.ts +0 -180
  87. package/mcp-server.ts +0 -69
  88. package/migrate-plugin.ts +0 -220
  89. package/pets-registry.ts +0 -160
  90. package/plugin-factory.ts +0 -300
  91. package/prompt-utils.ts +0 -130
  92. package/schema-helpers.ts +0 -59
  93. package/search-pets.ts +0 -267
  94. package/types.ts +0 -68
  95. package/validate-pet.ts +0 -749
  96. /package/{logger.d.ts → dist/src/core/logger.d.ts} +0 -0
package/build-pet.ts DELETED
@@ -1,429 +0,0 @@
1
- import { join, dirname } from 'path'
2
- import { fileURLToPath } from 'url'
3
- import { existsSync, readdirSync, readFileSync, statSync, writeFileSync } from 'fs'
4
- import { pathToFileURL } from 'url'
5
- import { PluginValidator } from './validate-pet.js'
6
-
7
- const __filename = fileURLToPath(import.meta.url)
8
- const __dirname = dirname(__filename)
9
- const projectRoot = dirname(dirname(__dirname))
10
-
11
- const DEBUG = process.env.PETS_DEBUG === 'true'
12
-
13
- function debug(...msgs: any[]) {
14
- if (DEBUG) {
15
- console.log('[BUILD-PET]', ...msgs)
16
- }
17
- }
18
-
19
- interface ToolDefinition {
20
- name: string
21
- description: string
22
- schema: any
23
- }
24
-
25
- async function extractToolsFromIndexFile(indexPath: string): Promise<ToolDefinition[]> {
26
- debug('=== EXTRACTING TOOLS FROM INDEX FILE ===')
27
- debug('Index path:', indexPath)
28
- debug('File exists:', existsSync(indexPath))
29
-
30
- try {
31
- const indexUrl = pathToFileURL(indexPath).href
32
- debug('Index URL:', indexUrl)
33
-
34
- debug('Attempting dynamic import...')
35
- const indexModule = await import(/* @vite-ignore */ indexUrl)
36
- debug('Import successful')
37
- debug('Module keys:', Object.keys(indexModule))
38
-
39
- if (indexModule.toolsMetadata && Array.isArray(indexModule.toolsMetadata)) {
40
- console.log(` Found ${indexModule.toolsMetadata.length} tools from exported toolsMetadata`)
41
- debug('Tools metadata:', JSON.stringify(indexModule.toolsMetadata, null, 2))
42
- return indexModule.toolsMetadata
43
- } else {
44
- debug('toolsMetadata not found or not an array')
45
- debug('indexModule.toolsMetadata:', indexModule.toolsMetadata)
46
- }
47
- } catch (error) {
48
- console.warn(` ⚠️ Could not import toolsMetadata, falling back to file parsing`)
49
- console.warn(` Error: ${error instanceof Error ? error.message : String(error)}`)
50
- debug('Import error details:', {
51
- name: error instanceof Error ? error.name : 'Unknown',
52
- message: error instanceof Error ? error.message : String(error),
53
- stack: error instanceof Error ? error.stack : 'No stack trace'
54
- })
55
- }
56
-
57
- debug('Falling back to file parsing')
58
- return extractToolsFromIndexFileByParsing(indexPath)
59
- }
60
-
61
- function extractToolsFromIndexFileByParsing(indexPath: string): ToolDefinition[] {
62
- const content = readFileSync(indexPath, 'utf8')
63
-
64
- const toolsMatch = content.match(/const\s+tools:\s*ToolDefinition\[\]\s*=\s*\[([\s\S]*?)\n\s*\]/m)
65
- if (!toolsMatch) {
66
- console.warn('⚠️ Could not find tools array in index.ts')
67
- return []
68
- }
69
-
70
- const toolsArray = toolsMatch[1]
71
- const toolNames: ToolDefinition[] = []
72
-
73
- const toolsSeparated = toolsArray.split(/\n\s*\{/).filter(part => part.includes('name:'))
74
- const toolBlocks = toolsSeparated.map((part, idx) => {
75
- if (idx === 0) return part
76
- return '{' + part
77
- })
78
-
79
- for (const block of toolBlocks) {
80
- const nameMatch = block.match(/name:\s*["']([^"']+)["']/)
81
- const descMatch = block.match(/description:\s*["']([^"']+)["']/)
82
-
83
- const schemaMatch = block.match(/schema:\s*z\.object\(\{([\s\S]*?)\}\),?\s*(?:async\s+execute|$)/)
84
-
85
- if (nameMatch && descMatch) {
86
- let schemaProperties: any = {}
87
-
88
- if (schemaMatch) {
89
- const schemaContent = schemaMatch[1]
90
-
91
- const lines = schemaContent.split('\n').filter(l => l.trim() && !l.trim().startsWith('//'))
92
-
93
- for (const line of lines) {
94
- const propMatch = line.match(/^\s*(\w+):\s*z\.(.+?),?\s*$/)
95
- if (!propMatch) continue
96
-
97
- const [, propName, zodDef] = propMatch
98
- let propSchema: any = {}
99
-
100
- if (zodDef.includes('string(')) {
101
- propSchema.type = 'string'
102
- } else if (zodDef.includes('number(')) {
103
- propSchema.type = 'number'
104
- const minMatch = zodDef.match(/\.min\((\d+)\)/)
105
- const maxMatch = zodDef.match(/\.max\((\d+)\)/)
106
- if (minMatch) propSchema.minimum = parseInt(minMatch[1])
107
- if (maxMatch) propSchema.maximum = parseInt(maxMatch[1])
108
- } else if (zodDef.includes('boolean(')) {
109
- propSchema.type = 'boolean'
110
- } else if (zodDef.includes('enum(')) {
111
- propSchema.type = 'string'
112
- const enumMatch = zodDef.match(/enum\(\[([^\]]+)\]\)/)
113
- if (enumMatch) {
114
- const enumValues = enumMatch[1].match(/["']([^"']+)["']/g)?.map(v => v.replace(/["']/g, ''))
115
- if (enumValues) propSchema.enum = enumValues
116
- }
117
- } else if (zodDef.includes('array(')) {
118
- propSchema.type = 'array'
119
- const arrayTypeMatch = zodDef.match(/array\(z\.(\w+)\(\)\)/)
120
- if (arrayTypeMatch) {
121
- propSchema.items = { type: arrayTypeMatch[1].toLowerCase() }
122
- }
123
- }
124
-
125
- if (zodDef.includes('.optional()')) {
126
- propSchema.optional = true
127
- }
128
-
129
- const descMatch = zodDef.match(/\.describe\(["']([^"']+)["']\)/)
130
- if (descMatch) {
131
- propSchema.description = descMatch[1]
132
- }
133
-
134
- schemaProperties[propName] = propSchema
135
- }
136
- }
137
-
138
- toolNames.push({
139
- name: nameMatch[1],
140
- description: descMatch[1],
141
- schema: {
142
- type: 'object',
143
- properties: schemaProperties
144
- }
145
- })
146
- }
147
- }
148
-
149
- console.log(` Found ${toolNames.length} tools in index.ts`)
150
- return toolNames
151
- }
152
-
153
- function formatZodSchema(schema: any, depth: number = 0): any {
154
- if (!schema || !schema._def) {
155
- return { type: 'object', properties: {} }
156
- }
157
-
158
- const def = schema._def
159
- const zodType = def.typeName || def.type || schema.constructor?.name || 'unknown'
160
-
161
- if (zodType === 'ZodObject' || zodType === 'object') {
162
- const properties: any = {}
163
- const shapeObj = typeof def.shape === 'function' ? def.shape() : def.shape || {}
164
-
165
- for (const [key, value] of Object.entries(shapeObj)) {
166
- properties[key] = formatZodSchema(value, depth + 1)
167
- }
168
-
169
- return {
170
- type: 'object',
171
- properties
172
- }
173
- }
174
-
175
- if (zodType === 'ZodString' || zodType === 'string') {
176
- return { type: 'string' }
177
- }
178
-
179
- if (zodType === 'ZodNumber' || zodType === 'number') {
180
- const result: any = { type: 'number' }
181
- if (def.checks) {
182
- for (const check of def.checks) {
183
- if (check.kind === 'min') result.minimum = check.value
184
- if (check.kind === 'max') result.maximum = check.value
185
- }
186
- }
187
- return result
188
- }
189
-
190
- if (zodType === 'ZodBoolean' || zodType === 'boolean') {
191
- return { type: 'boolean' }
192
- }
193
-
194
- if (zodType === 'ZodArray' || zodType === 'array') {
195
- return {
196
- type: 'array',
197
- items: formatZodSchema(def.type, depth + 1)
198
- }
199
- }
200
-
201
- if (zodType === 'ZodEnum' || zodType === 'enum') {
202
- let values = def.values
203
- if (!values && schema._def?.values) {
204
- values = schema._def.values
205
- }
206
- if (!values && schema.options) {
207
- values = schema.options
208
- }
209
-
210
- const enumArray = Array.isArray(values) ? values : Object.values(values || {})
211
- return {
212
- type: 'string',
213
- enum: enumArray
214
- }
215
- }
216
-
217
- if (zodType === 'ZodOptional' || zodType === 'optional') {
218
- return {
219
- ...formatZodSchema(def.innerType, depth + 1),
220
- optional: true
221
- }
222
- }
223
-
224
- return { type: zodType }
225
- }
226
-
227
- function generateToolsMetadata(tools: ToolDefinition[]): Array<{ name: string; description: string; schema: any }> {
228
- return tools.map(tool => ({
229
- name: tool.name,
230
- description: tool.description,
231
- schema: tool.schema._def ? formatZodSchema(tool.schema) : tool.schema
232
- }))
233
- }
234
-
235
- function generateScriptsFromTools(tools: ToolDefinition[], petName: string): Record<string, string> {
236
- const scripts: Record<string, string> = {
237
- build: 'pets build',
238
- 'build:tsc': 'tsc',
239
- quickstart: `opencode run "list available ${petName} commands"`,
240
- }
241
-
242
- for (const tool of tools) {
243
- let scriptName = tool.name
244
-
245
- if (scriptName.startsWith(`${petName}-`)) {
246
- scriptName = scriptName.replace(new RegExp(`^${petName}-`), 'test:')
247
- } else {
248
- scriptName = `test:${scriptName}`
249
- }
250
-
251
- const command = `opencode run "${tool.description}"`
252
- scripts[scriptName] = command
253
- }
254
-
255
- scripts['test:all'] = 'echo "Run individual test scripts to test specific tools"'
256
-
257
- return scripts
258
- }
259
-
260
- export async function buildPet(petName?: string): Promise<void> {
261
- debug('=== BUILD PET STARTING ===')
262
- debug('Initial petName:', petName)
263
- debug('CWD:', process.cwd())
264
- debug('Project root:', projectRoot)
265
-
266
- if (!petName) {
267
- const cwd = process.cwd()
268
- const petsDir = join(projectRoot, 'pets')
269
-
270
- debug('Auto-detecting pet from CWD:', cwd)
271
- debug('Pets directory:', petsDir)
272
-
273
- if (cwd.includes('/pets/')) {
274
- petName = cwd.split('/pets/')[1].split('/')[0]
275
- console.log(`📦 Auto-detected pet: ${petName}`)
276
- debug('Auto-detected pet:', petName)
277
- }
278
-
279
- if (!petName) {
280
- console.error('Usage: pets build <pet-name>')
281
- console.error('Example: pets build postgres')
282
- console.error('')
283
- console.error('Available pets:')
284
- if (existsSync(petsDir)) {
285
- const pets = readdirSync(petsDir).filter(dir => {
286
- const petPath = join(petsDir, dir)
287
- return statSync(petPath).isDirectory() && dir !== '_TEMPLATE_'
288
- })
289
- pets.forEach(pet => console.error(` - ${pet}`))
290
- debug('Available pets:', pets)
291
- } else {
292
- debug('Pets directory does not exist:', petsDir)
293
- }
294
- process.exit(1)
295
- }
296
- }
297
-
298
- const petDir = join(projectRoot, 'pets', petName)
299
- const packageJsonPath = join(petDir, 'package.json')
300
- const indexPath = join(petDir, 'index.ts')
301
-
302
- debug('Pet directory:', petDir)
303
- debug('Package.json path:', packageJsonPath)
304
- debug('Index.ts path:', indexPath)
305
-
306
- if (!existsSync(petDir)) {
307
- console.error(`❌ Pet '${petName}' not found in pets/ directory`)
308
- debug('Pet directory does not exist:', petDir)
309
- process.exit(1)
310
- }
311
-
312
- if (!existsSync(packageJsonPath)) {
313
- console.error(`❌ package.json not found for pet '${petName}'`)
314
- debug('Package.json does not exist:', packageJsonPath)
315
- process.exit(1)
316
- }
317
-
318
- if (!existsSync(indexPath)) {
319
- console.error(`❌ index.ts not found for pet '${petName}'`)
320
- debug('Index.ts does not exist:', indexPath)
321
- process.exit(1)
322
- }
323
-
324
- console.log(`🔨 Building ${petName}...`)
325
- debug('All required files found, proceeding with build')
326
-
327
- const packageJsonContent = readFileSync(packageJsonPath, 'utf8')
328
- debug('Package.json content length:', packageJsonContent.length)
329
- const packageJson = JSON.parse(packageJsonContent)
330
- debug('Package.json parsed successfully')
331
- debug('Package name:', packageJson.name)
332
- debug('Package version:', packageJson.version)
333
-
334
- // Auto-generate repository field if missing
335
- if (!packageJson.repository) {
336
- packageJson.repository = {
337
- type: 'git',
338
- url: `https://github.com/raggle-ai/pets/pets/${petName}`
339
- }
340
- debug('Auto-generated repository field:', packageJson.repository.url)
341
- }
342
-
343
- console.log(` Name: ${packageJson.name}`)
344
- console.log(` Version: ${packageJson.version}`)
345
- console.log(` Description: ${packageJson.description || 'No description'}`)
346
-
347
- console.log(`\n🔍 Validating plugin structure...`)
348
- const validator = new PluginValidator()
349
- const validation = validator.validatePlugin(petDir)
350
-
351
- if (validation.result.errors.length > 0) {
352
- console.log(`\n❌ Validation failed with ${validation.result.errors.length} error(s):`)
353
- validation.result.errors.forEach(error => {
354
- console.log(` ❌ ${error}`)
355
- })
356
- console.log(`\n💥 Build aborted due to validation errors.`)
357
- process.exit(1)
358
- }
359
-
360
- if (validation.result.warnings.length > 0) {
361
- console.log(`\n⚠️ Found ${validation.result.warnings.length} warning(s):`)
362
- validation.result.warnings.forEach(warning => {
363
- console.log(` ⚠️ ${warning}`)
364
- })
365
- }
366
-
367
- if (validation.result.codePatternWarnings && validation.result.codePatternWarnings.length > 0) {
368
- console.log(`\n📋 Code pattern analysis:`)
369
- validation.result.codePatternWarnings.forEach(warning => {
370
- console.log(` ${warning}`)
371
- })
372
- }
373
-
374
- if (validation.result.errors.length === 0 && validation.result.warnings.length === 0 && (!validation.result.codePatternWarnings || validation.result.codePatternWarnings.length === 0)) {
375
- console.log(` ✓ All validation checks passed`)
376
- }
377
-
378
- debug('Extracting tools from index file...')
379
- const tools = await extractToolsFromIndexFile(indexPath)
380
- debug(`Extracted ${tools.length} tools`)
381
-
382
- if (tools.length > 0) {
383
- console.log(`\n📝 Generating scripts and metadata for ${tools.length} tools...`)
384
- debug('Tools extracted:', tools.map(t => t.name))
385
-
386
- const scripts = generateScriptsFromTools(tools, petName)
387
- debug('Generated scripts:', Object.keys(scripts))
388
-
389
- const toolsMetadata = generateToolsMetadata(tools)
390
- debug('Generated tools metadata count:', toolsMetadata.length)
391
-
392
- packageJson.scripts = scripts
393
- delete packageJson.tools
394
-
395
- const commandsJsonPath = join(petDir, 'commands.json')
396
- debug('Commands.json path:', commandsJsonPath)
397
-
398
- const commandsData = {
399
- name: packageJson.name,
400
- version: packageJson.version,
401
- description: packageJson.description,
402
- tools: toolsMetadata,
403
- generatedAt: new Date().toISOString()
404
- }
405
-
406
- debug('Writing package.json...')
407
- writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2) + '\n', 'utf8')
408
- debug('Package.json written successfully')
409
-
410
- debug('Writing commands.json...')
411
- writeFileSync(commandsJsonPath, JSON.stringify(commandsData, null, 2) + '\n', 'utf8')
412
- debug('Commands.json written successfully')
413
-
414
- console.log(` ✓ Updated package.json with ${Object.keys(scripts).length} scripts`)
415
- console.log(` ✓ Generated commands.json with ${tools.length} tools`)
416
-
417
- console.log(`\n🔧 Generated test scripts:`)
418
- Object.entries(scripts).forEach(([name, cmd]) => {
419
- if (name.startsWith('test:')) {
420
- console.log(` - npm run ${name}`)
421
- }
422
- })
423
- } else {
424
- debug('No tools found in index file')
425
- }
426
-
427
- console.log(`\n✅ ${petName} built successfully!`)
428
- debug('=== BUILD COMPLETE ===')
429
- }
package/cli.ts DELETED
@@ -1,268 +0,0 @@
1
- #!/usr/bin/env bun
2
-
3
- import { buildPet } from './build-pet.js'
4
- import { deployPet } from './deploy-pet.js'
5
- import { addFolderToHistory } from './config-manager.js'
6
- import { spawn } from 'child_process'
7
- import { resolve } from 'path'
8
- import { readFileSync, existsSync } from 'fs'
9
-
10
- async function publishPet(petName: string | undefined, options: { preview?: boolean; channel?: string } = {}) {
11
- const { preview = false, channel = 'latest' } = options
12
-
13
- // Find the script path - try multiple locations
14
- let scriptPath = resolve(__dirname, '../../scripts/publish-pet.ts')
15
- if (!existsSync(scriptPath)) {
16
- // We might be in a different location, try relative to cwd
17
- scriptPath = resolve(process.cwd(), '../../scripts/publish-pet.ts')
18
- }
19
-
20
- if (!existsSync(scriptPath)) {
21
- console.error(`❌ Publish script not found: ${scriptPath}`)
22
- console.error(` Tried: ${resolve(__dirname, '../../scripts/publish-pet.ts')}`)
23
- console.error(` And: ${resolve(process.cwd(), '../../scripts/publish-pet.ts')}`)
24
- process.exit(1)
25
- }
26
-
27
- // If no petName provided, try to infer from current directory
28
- let finalPetName = petName
29
- if (!finalPetName) {
30
- const cwd = process.cwd()
31
- const pkgPath = resolve(cwd, 'package.json')
32
-
33
- if (existsSync(pkgPath)) {
34
- try {
35
- const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'))
36
- // Extract pet name from @openpets/maps -> maps
37
- if (pkg.name && pkg.name.startsWith('@openpets/')) {
38
- finalPetName = pkg.name.replace('@openpets/', '')
39
- console.log(`📦 Detected pet: ${finalPetName}`)
40
- }
41
- } catch (e) {
42
- // Ignore parse errors
43
- }
44
- }
45
-
46
- if (!finalPetName) {
47
- console.error('❌ Could not determine pet name. Run from pet directory or specify pet name.')
48
- process.exit(1)
49
- }
50
- }
51
-
52
- const bunArgs = [scriptPath, finalPetName]
53
- if (preview) bunArgs.push('--preview')
54
- if (channel && channel !== 'latest') bunArgs.push('--channel', channel)
55
-
56
- return new Promise<void>((resolve, reject) => {
57
- const child = spawn('bun', bunArgs, {
58
- stdio: 'inherit',
59
- shell: true,
60
- env: {
61
- ...process.env,
62
- OPENPETS_PREVIEW: preview ? 'true' : 'false',
63
- OPENPETS_CHANNEL: channel
64
- }
65
- })
66
-
67
- child.on('error', reject)
68
- child.on('exit', (code) => {
69
- if (code !== 0) {
70
- reject(new Error(`Publish exited with code ${code}`))
71
- } else {
72
- resolve()
73
- }
74
- })
75
- })
76
- }
77
-
78
- const args = process.argv.slice(2)
79
- const command = args[0]
80
-
81
- const DEBUG = process.env.PETS_DEBUG === 'true'
82
-
83
- function log(...msgs: any[]) {
84
- if (DEBUG) {
85
- console.log('[PETS-CLI]', ...msgs)
86
- }
87
- }
88
-
89
- function displayInstalledPlugins() {
90
- const opencodeJsonPath = resolve(process.cwd(), 'opencode.json')
91
-
92
- log('Looking for opencode.json at:', opencodeJsonPath)
93
-
94
- if (!existsSync(opencodeJsonPath)) {
95
- log('opencode.json not found')
96
- return
97
- }
98
-
99
- try {
100
- const content = readFileSync(opencodeJsonPath, 'utf-8')
101
- log('opencode.json content length:', content.length)
102
-
103
- const config = JSON.parse(content)
104
- log('Parsed opencode.json config:', Object.keys(config))
105
-
106
- if (config.plugin && Array.isArray(config.plugin) && config.plugin.length > 0) {
107
- const plugins = config.plugin.filter((p: string) => typeof p === 'string' && p.trim())
108
- log('Found plugins:', plugins)
109
-
110
- if (plugins.length > 0) {
111
- console.log('\x1b[36m%s\x1b[0m', '📦 Installed plugins:')
112
- console.log('\x1b[2m%s\x1b[0m', ` ${plugins.join(', ')}`)
113
- console.log('')
114
- }
115
- } else {
116
- log('No plugins found in config')
117
- }
118
- } catch (error) {
119
- log('Error reading opencode.json:', error)
120
- }
121
- }
122
-
123
- function killPort(port: number) {
124
- log(`Attempting to kill processes on port ${port}`)
125
- try {
126
- const { execSync } = require('child_process')
127
- execSync(`lsof -ti:${port} | xargs kill -9 2>/dev/null || true`, { stdio: 'ignore' })
128
- log(`Successfully killed processes on port ${port}`)
129
- } catch (error) {
130
- log(`No processes to kill on port ${port} or error occurred:`, error)
131
- }
132
- }
133
-
134
- function launchManager() {
135
- const startTime = Date.now()
136
- const uiDir = resolve(__dirname, '../../apps/desktop')
137
- const projectDir = process.cwd()
138
-
139
- addFolderToHistory(projectDir)
140
-
141
- console.log('Launching OpenPets Plugin Manager...')
142
- console.log(`Project directory: ${projectDir}`)
143
- console.log(`UI directory: ${uiDir}`)
144
-
145
- log('Launch details:', {
146
- __dirname,
147
- uiDir,
148
- projectDir,
149
- uiDirExists: existsSync(uiDir),
150
- timestamp: new Date().toISOString()
151
- })
152
-
153
- if (!existsSync(uiDir)) {
154
- console.error(`❌ UI directory not found: ${uiDir}`)
155
- log('Contents of parent directory:', require('fs').readdirSync(resolve(__dirname, '../../apps')))
156
- process.exit(1)
157
- }
158
-
159
- log('Checking for package.json in UI directory')
160
- const packageJsonPath = resolve(uiDir, 'package.json')
161
- if (!existsSync(packageJsonPath)) {
162
- console.error(`❌ package.json not found in UI directory: ${packageJsonPath}`)
163
- process.exit(1)
164
- }
165
-
166
- killPort(1420)
167
-
168
- log('Spawning npm process with tauri:dev')
169
- const child = spawn('npm', ['run', 'tauri:dev'], {
170
- cwd: uiDir,
171
- stdio: 'inherit',
172
- shell: true,
173
- env: {
174
- ...process.env,
175
- OPENPETS_PROJECT_DIR: projectDir,
176
- PETS_DEBUG: DEBUG ? 'true' : 'false'
177
- }
178
- })
179
-
180
- log('Child process spawned with PID:', child.pid)
181
-
182
- child.on('error', (error) => {
183
- console.error('Failed to launch manager:', error)
184
- log('Error details:', {
185
- message: error.message,
186
- stack: error.stack,
187
- elapsed: Date.now() - startTime
188
- })
189
- process.exit(1)
190
- })
191
-
192
- child.on('exit', (code) => {
193
- const elapsed = Date.now() - startTime
194
- log(`Manager process exited with code ${code} after ${elapsed}ms`)
195
- if (code !== 0) {
196
- console.error(`Manager exited with code ${code}`)
197
- process.exit(code || 1)
198
- }
199
- })
200
- }
201
-
202
- log('=== PETS CLI STARTUP ===')
203
- log('Command:', command)
204
- log('Args:', args)
205
- log('CWD:', process.cwd())
206
- log('ENV.OPENPETS_PROJECT_DIR:', process.env.OPENPETS_PROJECT_DIR)
207
- log('ENV.PETS_DEBUG:', process.env.PETS_DEBUG)
208
-
209
- displayInstalledPlugins()
210
-
211
- if (command === 'build') {
212
- const petName = args[1]
213
- log('Building pet:', petName)
214
- buildPet(petName).catch(error => {
215
- console.error('Error building pet:', error)
216
- log('Build error details:', error)
217
- process.exit(1)
218
- })
219
- } else if (command === 'deploy') {
220
- const petName = args[1]
221
- log('Deploying pet:', petName)
222
- deployPet(petName).catch(error => {
223
- console.error('Error deploying pet:', error)
224
- log('Deploy error details:', error)
225
- process.exit(1)
226
- })
227
- } else if (command === 'publish') {
228
- const petName = args[1] && !args[1].startsWith('--') ? args[1] : undefined
229
- const preview = args.includes('--preview')
230
- const channelIndex = args.indexOf('--channel')
231
- const channel = channelIndex >= 0 ? args[channelIndex + 1] : 'latest'
232
-
233
- log('Publishing pet:', petName || '(auto-detect)', { preview, channel })
234
- publishPet(petName, { preview, channel }).catch(error => {
235
- console.error('Error publishing pet:', error)
236
- log('Publish error details:', error)
237
- process.exit(1)
238
- })
239
- } else if (!command) {
240
- log('No command provided, launching manager UI')
241
- launchManager()
242
- } else {
243
- log('Unknown command:', command)
244
- console.error('Usage: pets [command] [options]')
245
- console.error('')
246
- console.error('Commands:')
247
- console.error(' (none) Launch the plugin manager UI (default)')
248
- console.error(' build <pet-name> Build and validate a pet package')
249
- console.error(' deploy <pet-name> Build and deploy a pet package with metadata')
250
- console.error(' publish [pet-name] Publish a pet package to npm (auto-detects if in pet dir)')
251
- console.error('')
252
- console.error('Publish Options:')
253
- console.error(' --preview Dry-run mode (no actual publish)')
254
- console.error(' --channel <name> Publish to a specific npm tag (default: latest)')
255
- console.error('')
256
- console.error('Examples:')
257
- console.error(' pets # Launch the desktop plugin manager')
258
- console.error(' pets build postgres')
259
- console.error(' pets deploy maps')
260
- console.error(' pets publish maps # From root directory')
261
- console.error(' cd pets/maps && pets publish # From pet directory')
262
- console.error(' pets publish --preview # Dry-run from pet directory')
263
- console.error(' pets publish maps --channel beta')
264
- console.error('')
265
- console.error('Environment:')
266
- console.error(' PETS_DEBUG=true Enable detailed debug logging')
267
- process.exit(1)
268
- }