openpets 1.0.8 → 1.0.10

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 (46) hide show
  1. package/dist/data/api.json +6746 -4404
  2. package/dist/src/core/cli.js +1160 -36
  3. package/dist/src/core/cli.js.map +1 -1
  4. package/dist/src/core/discovery.d.ts +130 -0
  5. package/dist/src/core/discovery.d.ts.map +1 -0
  6. package/dist/src/core/discovery.js +327 -0
  7. package/dist/src/core/discovery.js.map +1 -0
  8. package/dist/src/core/index.d.ts +5 -5
  9. package/dist/src/core/index.d.ts.map +1 -1
  10. package/dist/src/core/index.js +7 -5
  11. package/dist/src/core/index.js.map +1 -1
  12. package/dist/src/core/mautrix-bridge.d.ts +17 -0
  13. package/dist/src/core/mautrix-bridge.d.ts.map +1 -1
  14. package/dist/src/core/mautrix-bridge.js +257 -0
  15. package/dist/src/core/mautrix-bridge.js.map +1 -1
  16. package/dist/src/core/pet-config.d.ts +611 -0
  17. package/dist/src/core/pet-config.d.ts.map +1 -0
  18. package/dist/src/core/pet-config.js +281 -0
  19. package/dist/src/core/pet-config.js.map +1 -0
  20. package/dist/src/core/pet-downloader.d.ts +50 -0
  21. package/dist/src/core/pet-downloader.d.ts.map +1 -0
  22. package/dist/src/core/pet-downloader.js +298 -0
  23. package/dist/src/core/pet-downloader.js.map +1 -0
  24. package/dist/src/core/pet-scanner.d.ts +14 -0
  25. package/dist/src/core/pet-scanner.d.ts.map +1 -0
  26. package/dist/src/core/pet-scanner.js +87 -0
  27. package/dist/src/core/pet-scanner.js.map +1 -0
  28. package/dist/src/core/registry-client.d.ts +97 -0
  29. package/dist/src/core/registry-client.d.ts.map +1 -0
  30. package/dist/src/core/registry-client.js +283 -0
  31. package/dist/src/core/registry-client.js.map +1 -0
  32. package/dist/src/core/search-pets.d.ts.map +1 -1
  33. package/dist/src/core/search-pets.js +31 -1
  34. package/dist/src/core/search-pets.js.map +1 -1
  35. package/dist/src/core/validate-pet.d.ts.map +1 -1
  36. package/dist/src/core/validate-pet.js +17 -19
  37. package/dist/src/core/validate-pet.js.map +1 -1
  38. package/dist/src/sdk/logger.d.ts +32 -0
  39. package/dist/src/sdk/logger.d.ts.map +1 -0
  40. package/dist/src/sdk/logger.js +119 -0
  41. package/dist/src/sdk/logger.js.map +1 -0
  42. package/dist/src/sdk/plugin-factory.d.ts +104 -0
  43. package/dist/src/sdk/plugin-factory.d.ts.map +1 -0
  44. package/dist/src/sdk/plugin-factory.js +540 -0
  45. package/dist/src/sdk/plugin-factory.js.map +1 -0
  46. package/package.json +3 -3
@@ -0,0 +1,281 @@
1
+ import { z } from "zod/v3";
2
+ import { readFileSync, existsSync, writeFileSync } from "fs";
3
+ import { join } from "path";
4
+ import { createLogger } from "./logger";
5
+ const logger = createLogger("pet-config");
6
+ const EnvVariableSchema = z.object({
7
+ name: z.string(),
8
+ description: z.string(),
9
+ required: z.boolean().optional().default(false),
10
+ default: z.string().optional(),
11
+ secret: z.boolean().optional().default(false)
12
+ });
13
+ const ProviderSchema = z.object({
14
+ id: z.string().optional(),
15
+ name: z.string(),
16
+ description: z.string().optional(),
17
+ homepage: z.string().url().optional(),
18
+ credentialsUrl: z.string().url().optional(),
19
+ envVariables: z.array(EnvVariableSchema).optional()
20
+ });
21
+ const ToolSchema = z.object({
22
+ name: z.string(),
23
+ description: z.string(),
24
+ inputSchema: z.record(z.unknown()).optional()
25
+ });
26
+ const BuildConfigSchema = z.object({
27
+ entrypoint: z.string().optional().default("index.ts"),
28
+ outDir: z.string().optional().default("dist"),
29
+ target: z.enum(["node", "bun", "browser"]).optional().default("node"),
30
+ format: z.enum(["esm", "cjs"]).optional().default("esm"),
31
+ minify: z.boolean().optional().default(false),
32
+ sourcemap: z.boolean().optional().default(true)
33
+ });
34
+ const RuntimeConfigSchema = z.object({
35
+ runtime: z.enum(["typescript", "bun", "node", "container"]).optional().default("typescript"),
36
+ transport: z.enum(["stdio", "http"]).optional().default("stdio"),
37
+ port: z.number().optional(),
38
+ healthCheck: z.string().optional()
39
+ });
40
+ const ContainerConfigSchema = z.object({
41
+ dockerfile: z.string().optional().default("Dockerfile"),
42
+ dockerBuildPath: z.string().optional().default("."),
43
+ image: z.string().optional(),
44
+ registry: z.string().optional()
45
+ });
46
+ const SessionConfigSchema = z.object({
47
+ configSchema: z.record(z.unknown()).optional(),
48
+ exampleConfig: z.record(z.unknown()).optional()
49
+ });
50
+ export const OpenPetsConfigSchema = z.object({
51
+ $schema: z.string().optional(),
52
+ name: z.string(),
53
+ version: z.string().regex(/^\d+\.\d+\.\d+(-[\w.]+)?$/),
54
+ title: z.string().optional(),
55
+ subtitle: z.string().optional(),
56
+ description: z.string(),
57
+ homepage: z.string().url().optional(),
58
+ repository: z.string().url().optional(),
59
+ license: z.string().optional().default("MIT"),
60
+ author: z.union([
61
+ z.string(),
62
+ z.object({ name: z.string(), email: z.string().email().optional() })
63
+ ]).optional(),
64
+ categories: z.array(z.string()).optional().default([]),
65
+ keywords: z.array(z.string()).optional().default([]),
66
+ icon: z.string().optional(),
67
+ runtime: RuntimeConfigSchema.optional(),
68
+ build: BuildConfigSchema.optional(),
69
+ container: ContainerConfigSchema.optional(),
70
+ session: SessionConfigSchema.optional(),
71
+ env: z.record(z.string()).optional(),
72
+ envVariables: z.object({
73
+ required: z.array(EnvVariableSchema).optional(),
74
+ optional: z.array(EnvVariableSchema).optional()
75
+ }).optional(),
76
+ providers: z.array(ProviderSchema).optional(),
77
+ tools: z.array(ToolSchema).optional(),
78
+ queries: z.array(z.string()).optional(),
79
+ scenarios: z.record(z.array(z.string())).optional(),
80
+ faq: z.array(z.object({
81
+ question: z.string(),
82
+ answer: z.string()
83
+ })).optional(),
84
+ scripts: z.record(z.string()).optional(),
85
+ dependencies: z.record(z.string()).optional(),
86
+ peerDependencies: z.record(z.string()).optional(),
87
+ devDependencies: z.record(z.string()).optional(),
88
+ publishConfig: z.object({
89
+ access: z.enum(["public", "restricted"]).optional().default("public"),
90
+ registry: z.string().url().optional(),
91
+ tag: z.string().optional().default("latest")
92
+ }).optional(),
93
+ files: z.array(z.string()).optional()
94
+ });
95
+ export function loadPetConfig(petDir) {
96
+ const packageJsonPath = join(petDir, "package.json");
97
+ const openpetsYamlPath = join(petDir, "openpets.yaml");
98
+ const openpetsJsonPath = join(petDir, "openpets.json");
99
+ let config = {};
100
+ if (existsSync(openpetsYamlPath)) {
101
+ try {
102
+ const yaml = require("yaml");
103
+ config = yaml.parse(readFileSync(openpetsYamlPath, "utf-8"));
104
+ logger.debug(`Loaded openpets.yaml from ${petDir}`);
105
+ }
106
+ catch (error) {
107
+ logger.error(`Failed to parse openpets.yaml: ${error.message}`);
108
+ return null;
109
+ }
110
+ }
111
+ else if (existsSync(openpetsJsonPath)) {
112
+ try {
113
+ config = JSON.parse(readFileSync(openpetsJsonPath, "utf-8"));
114
+ logger.debug(`Loaded openpets.json from ${petDir}`);
115
+ }
116
+ catch (error) {
117
+ logger.error(`Failed to parse openpets.json: ${error.message}`);
118
+ return null;
119
+ }
120
+ }
121
+ else if (existsSync(packageJsonPath)) {
122
+ try {
123
+ const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf-8"));
124
+ config = convertPackageJsonToConfig(packageJson);
125
+ logger.debug(`Loaded config from package.json in ${petDir}`);
126
+ }
127
+ catch (error) {
128
+ logger.error(`Failed to parse package.json: ${error.message}`);
129
+ return null;
130
+ }
131
+ }
132
+ else {
133
+ logger.warn(`No configuration file found in ${petDir}`);
134
+ return null;
135
+ }
136
+ try {
137
+ return OpenPetsConfigSchema.parse(config);
138
+ }
139
+ catch (error) {
140
+ if (error instanceof z.ZodError) {
141
+ logger.error(`Configuration validation failed:`);
142
+ error.errors.forEach(err => {
143
+ logger.error(` - ${err.path.join(".")}: ${err.message}`);
144
+ });
145
+ }
146
+ return null;
147
+ }
148
+ }
149
+ export function savePetConfig(petDir, config, format = "json") {
150
+ try {
151
+ const validated = OpenPetsConfigSchema.parse(config);
152
+ if (format === "yaml") {
153
+ const yaml = require("yaml");
154
+ const yamlPath = join(petDir, "openpets.yaml");
155
+ writeFileSync(yamlPath, yaml.stringify(validated));
156
+ logger.info(`Saved configuration to ${yamlPath}`);
157
+ }
158
+ else {
159
+ const jsonPath = join(petDir, "openpets.json");
160
+ writeFileSync(jsonPath, JSON.stringify(validated, null, 2));
161
+ logger.info(`Saved configuration to ${jsonPath}`);
162
+ }
163
+ return true;
164
+ }
165
+ catch (error) {
166
+ logger.error(`Failed to save configuration: ${error.message}`);
167
+ return false;
168
+ }
169
+ }
170
+ function convertPackageJsonToConfig(packageJson) {
171
+ return {
172
+ name: packageJson.name,
173
+ version: packageJson.version || "1.0.0",
174
+ title: packageJson.title,
175
+ subtitle: packageJson.subtitle,
176
+ description: packageJson.description || "",
177
+ homepage: packageJson.homepage,
178
+ repository: typeof packageJson.repository === "string"
179
+ ? packageJson.repository
180
+ : packageJson.repository?.url,
181
+ license: packageJson.license,
182
+ author: packageJson.author,
183
+ categories: packageJson.categories,
184
+ keywords: packageJson.keywords,
185
+ icon: packageJson.icon,
186
+ envVariables: packageJson.envVariables,
187
+ providers: packageJson.providers,
188
+ tools: packageJson.tools,
189
+ queries: packageJson.queries,
190
+ scenarios: packageJson.scenarios,
191
+ faq: packageJson.faq,
192
+ scripts: packageJson.scripts,
193
+ dependencies: packageJson.dependencies,
194
+ peerDependencies: packageJson.peerDependencies,
195
+ devDependencies: packageJson.devDependencies,
196
+ publishConfig: packageJson.publishConfig,
197
+ files: packageJson.files
198
+ };
199
+ }
200
+ export function generateOpenpetsYamlTemplate(options) {
201
+ const yaml = require("yaml");
202
+ const template = {
203
+ $schema: "https://pets.studio/config.yaml.json",
204
+ name: options.name,
205
+ version: "1.0.0",
206
+ description: options.description || `${options.name} plugin for OpenPets`,
207
+ categories: ["general"],
208
+ keywords: ["openpets", "plugin"],
209
+ runtime: {
210
+ runtime: options.runtime || "typescript",
211
+ transport: "stdio"
212
+ },
213
+ build: {
214
+ entrypoint: "index.ts",
215
+ outDir: "dist",
216
+ target: "node",
217
+ format: "esm"
218
+ },
219
+ envVariables: {
220
+ optional: [
221
+ {
222
+ name: "EXAMPLE_API_KEY",
223
+ description: "API key for your service",
224
+ secret: true
225
+ }
226
+ ]
227
+ },
228
+ queries: [
229
+ "example query",
230
+ "another example query"
231
+ ],
232
+ scenarios: {
233
+ "basic-test": [
234
+ "example query",
235
+ "another example query"
236
+ ]
237
+ }
238
+ };
239
+ return yaml.stringify(template);
240
+ }
241
+ export function validatePetConfig(config) {
242
+ const errors = [];
243
+ const warnings = [];
244
+ try {
245
+ OpenPetsConfigSchema.parse(config);
246
+ }
247
+ catch (error) {
248
+ if (error instanceof z.ZodError) {
249
+ error.errors.forEach(err => {
250
+ errors.push(`${err.path.join(".")}: ${err.message}`);
251
+ });
252
+ }
253
+ else {
254
+ errors.push(`Unknown validation error: ${error}`);
255
+ }
256
+ }
257
+ if (typeof config === "object" && config !== null) {
258
+ const c = config;
259
+ if (!c.description || c.description.length < 10) {
260
+ warnings.push("Description should be at least 10 characters");
261
+ }
262
+ if (!c.categories || c.categories.length === 0) {
263
+ warnings.push("Consider adding categories for better discoverability");
264
+ }
265
+ if (!c.keywords || c.keywords.length === 0) {
266
+ warnings.push("Consider adding keywords for better searchability");
267
+ }
268
+ if (!c.queries || c.queries.length === 0) {
269
+ warnings.push("Consider adding example queries for documentation");
270
+ }
271
+ if (!c.homepage) {
272
+ warnings.push("Consider adding a homepage URL");
273
+ }
274
+ }
275
+ return {
276
+ valid: errors.length === 0,
277
+ errors,
278
+ warnings
279
+ };
280
+ }
281
+ //# sourceMappingURL=pet-config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pet-config.js","sourceRoot":"","sources":["../../../pet-config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,50 @@
1
+ import { type OpenPetsConfig } from "./pet-config";
2
+ export interface DownloadResult {
3
+ success: boolean;
4
+ message: string;
5
+ packagePath?: string;
6
+ config?: OpenPetsConfig;
7
+ envVariables?: EnvVariableInfo[];
8
+ }
9
+ export interface EnvVariableInfo {
10
+ name: string;
11
+ description: string;
12
+ required: boolean;
13
+ secret: boolean;
14
+ provider?: string;
15
+ currentValue?: string;
16
+ }
17
+ export interface AddOptions {
18
+ targetDir?: string;
19
+ version?: string;
20
+ skipConfig?: boolean;
21
+ envValues?: Record<string, string>;
22
+ }
23
+ export interface OpencodeConfig {
24
+ $schema?: string;
25
+ plugin?: string[];
26
+ env?: Record<string, string>;
27
+ }
28
+ export declare class PetDownloader {
29
+ private cacheDir;
30
+ private petsDir;
31
+ constructor(baseDir?: string);
32
+ private ensureDirs;
33
+ add(packageName: string, options?: AddOptions): Promise<DownloadResult>;
34
+ private downloadPackage;
35
+ private fetchFullPackageInfo;
36
+ private downloadTarball;
37
+ private extractTarball;
38
+ private extractEnvVariables;
39
+ updateOpencodeConfig(targetDir: string, shortName: string, packagePath: string, envValues?: Record<string, string>): Promise<void>;
40
+ /**
41
+ * Update .pets/config.json with pet-specific environment variables
42
+ */
43
+ private updatePetsConfig;
44
+ private getRelativePath;
45
+ getInstalledPetPath(shortName: string): string | null;
46
+ listInstalledPets(): string[];
47
+ removePet(shortName: string): boolean;
48
+ }
49
+ export declare function getPetDownloader(): PetDownloader;
50
+ //# sourceMappingURL=pet-downloader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pet-downloader.d.ts","sourceRoot":"","sources":["../../../pet-downloader.ts"],"names":[],"mappings":"AAQA,OAAO,EAAiB,KAAK,cAAc,EAAE,MAAM,cAAc,CAAA;AAOjE,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,OAAO,CAAA;IAChB,OAAO,EAAE,MAAM,CAAA;IACf,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,MAAM,CAAC,EAAE,cAAc,CAAA;IACvB,YAAY,CAAC,EAAE,eAAe,EAAE,CAAA;CACjC;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,EAAE,MAAM,CAAA;IACnB,QAAQ,EAAE,OAAO,CAAA;IACjB,MAAM,EAAE,OAAO,CAAA;IACf,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB;AAED,MAAM,WAAW,UAAU;IACzB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CACnC;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAA;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAC7B;AAED,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAQ;IACxB,OAAO,CAAC,OAAO,CAAQ;gBAEX,OAAO,CAAC,EAAE,MAAM;IAO5B,OAAO,CAAC,UAAU;IASZ,GAAG,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,GAAE,UAAe,GAAG,OAAO,CAAC,cAAc,CAAC;YAuCnE,eAAe;YA0Cf,oBAAoB;YAcpB,eAAe;YAUf,cAAc;IAkB5B,OAAO,CAAC,mBAAmB;IAkDrB,oBAAoB,CACxB,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,MAAM,EACnB,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GACjC,OAAO,CAAC,IAAI,CAAC;IAmChB;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAoExB,OAAO,CAAC,eAAe;IAmBvB,mBAAmB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAKrD,iBAAiB,IAAI,MAAM,EAAE;IAS7B,SAAS,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO;CAOtC;AAID,wBAAgB,gBAAgB,IAAI,aAAa,CAKhD"}
@@ -0,0 +1,298 @@
1
+ import { existsSync, mkdirSync, writeFileSync, readFileSync, rmSync } from "fs";
2
+ import { join, resolve } from "path";
3
+ import { createGunzip } from "zlib";
4
+ import { extract } from "tar";
5
+ import { createLogger } from "./logger";
6
+ import { getRegistryClient } from "./registry-client";
7
+ import { loadPetConfig } from "./pet-config";
8
+ const logger = createLogger("pet-downloader");
9
+ const NPM_REGISTRY = "https://registry.npmjs.org";
10
+ const OPENPETS_SCOPE = "@openpets";
11
+ export class PetDownloader {
12
+ cacheDir;
13
+ petsDir;
14
+ constructor(baseDir) {
15
+ const home = process.env.HOME || process.env.USERPROFILE || "~";
16
+ this.cacheDir = baseDir || join(home, ".openpets", "cache");
17
+ this.petsDir = join(home, ".cache", "opencode", "node_modules", "@openpets");
18
+ this.ensureDirs();
19
+ }
20
+ ensureDirs() {
21
+ if (!existsSync(this.cacheDir)) {
22
+ mkdirSync(this.cacheDir, { recursive: true });
23
+ }
24
+ if (!existsSync(this.petsDir)) {
25
+ mkdirSync(this.petsDir, { recursive: true });
26
+ }
27
+ }
28
+ async add(packageName, options = {}) {
29
+ const { targetDir = process.cwd(), version, skipConfig = false, envValues } = options;
30
+ const fullName = packageName.startsWith(OPENPETS_SCOPE)
31
+ ? packageName
32
+ : packageName.startsWith("@")
33
+ ? packageName
34
+ : `${OPENPETS_SCOPE}/${packageName}`;
35
+ const shortName = fullName.replace(`${OPENPETS_SCOPE}/`, "").replace("@", "").replace("/", "-");
36
+ logger.info(`Adding pet: ${fullName}`);
37
+ const registryClient = getRegistryClient();
38
+ const pkgInfo = await registryClient.fetchPackageInfo(packageName, version);
39
+ if (!pkgInfo) {
40
+ return { success: false, message: `Package not found: ${fullName}` };
41
+ }
42
+ const downloadResult = await this.downloadPackage(pkgInfo, shortName);
43
+ if (!downloadResult.success) {
44
+ return downloadResult;
45
+ }
46
+ const petConfig = loadPetConfig(downloadResult.packagePath);
47
+ const envVariables = this.extractEnvVariables(petConfig, pkgInfo);
48
+ await this.updateOpencodeConfig(targetDir, shortName, downloadResult.packagePath, envValues);
49
+ return {
50
+ success: true,
51
+ message: `Successfully added ${fullName}@${pkgInfo.version}`,
52
+ packagePath: downloadResult.packagePath,
53
+ config: petConfig || undefined,
54
+ envVariables
55
+ };
56
+ }
57
+ async downloadPackage(pkgInfo, shortName) {
58
+ if (!pkgInfo.dist?.tarball) {
59
+ const fullPkgInfo = await this.fetchFullPackageInfo(pkgInfo.name);
60
+ if (!fullPkgInfo?.dist?.tarball) {
61
+ return { success: false, message: `No tarball URL found for ${pkgInfo.name}` };
62
+ }
63
+ pkgInfo = fullPkgInfo;
64
+ }
65
+ const tarballUrl = pkgInfo.dist.tarball;
66
+ const tarballPath = join(this.cacheDir, `${shortName}-${pkgInfo.version}.tgz`);
67
+ const extractPath = join(this.petsDir, shortName);
68
+ try {
69
+ if (existsSync(extractPath)) {
70
+ const existingPkgPath = join(extractPath, "package.json");
71
+ if (existsSync(existingPkgPath)) {
72
+ const existingPkg = JSON.parse(readFileSync(existingPkgPath, "utf-8"));
73
+ if (existingPkg.version === pkgInfo.version) {
74
+ logger.info(`Package ${pkgInfo.name}@${pkgInfo.version} already exists`);
75
+ return { success: true, message: "Already installed", packagePath: extractPath };
76
+ }
77
+ }
78
+ rmSync(extractPath, { recursive: true, force: true });
79
+ }
80
+ logger.info(`Downloading ${tarballUrl}`);
81
+ await this.downloadTarball(tarballUrl, tarballPath);
82
+ logger.info(`Extracting to ${extractPath}`);
83
+ mkdirSync(extractPath, { recursive: true });
84
+ await this.extractTarball(tarballPath, extractPath);
85
+ rmSync(tarballPath, { force: true });
86
+ return { success: true, message: "Downloaded successfully", packagePath: extractPath };
87
+ }
88
+ catch (error) {
89
+ logger.error(`Download failed: ${error.message}`);
90
+ return { success: false, message: `Download failed: ${error.message}` };
91
+ }
92
+ }
93
+ async fetchFullPackageInfo(packageName) {
94
+ const fullName = packageName.startsWith(OPENPETS_SCOPE)
95
+ ? packageName
96
+ : `${OPENPETS_SCOPE}/${packageName}`;
97
+ try {
98
+ const response = await fetch(`${NPM_REGISTRY}/${fullName}/latest`);
99
+ if (!response.ok)
100
+ return null;
101
+ return await response.json();
102
+ }
103
+ catch {
104
+ return null;
105
+ }
106
+ }
107
+ async downloadTarball(url, destPath) {
108
+ const response = await fetch(url);
109
+ if (!response.ok) {
110
+ throw new Error(`Failed to download: ${response.statusText}`);
111
+ }
112
+ const buffer = await response.arrayBuffer();
113
+ writeFileSync(destPath, Buffer.from(buffer));
114
+ }
115
+ async extractTarball(tarPath, destPath) {
116
+ return new Promise((resolve, reject) => {
117
+ const extractStream = extract({
118
+ cwd: destPath,
119
+ strip: 1
120
+ });
121
+ const gunzip = createGunzip();
122
+ const fileStream = require("fs").createReadStream(tarPath);
123
+ fileStream
124
+ .pipe(gunzip)
125
+ .pipe(extractStream)
126
+ .on("finish", resolve)
127
+ .on("error", reject);
128
+ });
129
+ }
130
+ extractEnvVariables(config, pkgInfo) {
131
+ const variables = [];
132
+ if (config?.envVariables) {
133
+ const required = config.envVariables.required || [];
134
+ const optional = config.envVariables.optional || [];
135
+ for (const v of required) {
136
+ variables.push({
137
+ name: v.name,
138
+ description: v.description,
139
+ required: true,
140
+ secret: v.secret || false,
141
+ currentValue: process.env[v.name]
142
+ });
143
+ }
144
+ for (const v of optional) {
145
+ variables.push({
146
+ name: v.name,
147
+ description: v.description,
148
+ required: false,
149
+ secret: v.secret || false,
150
+ currentValue: process.env[v.name]
151
+ });
152
+ }
153
+ }
154
+ if (config?.providers) {
155
+ for (const provider of config.providers) {
156
+ if (provider.envVariables) {
157
+ for (const v of provider.envVariables) {
158
+ if (!variables.find(existing => existing.name === v.name)) {
159
+ variables.push({
160
+ name: v.name,
161
+ description: v.description,
162
+ required: v.required || false,
163
+ secret: v.secret || false,
164
+ provider: provider.name,
165
+ currentValue: process.env[v.name]
166
+ });
167
+ }
168
+ }
169
+ }
170
+ }
171
+ }
172
+ return variables;
173
+ }
174
+ async updateOpencodeConfig(targetDir, shortName, packagePath, envValues) {
175
+ const opencodeJsonPath = join(targetDir, "opencode.json");
176
+ let config = {
177
+ $schema: "https://opencode.ai/config.json",
178
+ plugin: []
179
+ };
180
+ if (existsSync(opencodeJsonPath)) {
181
+ try {
182
+ config = JSON.parse(readFileSync(opencodeJsonPath, "utf-8"));
183
+ }
184
+ catch {
185
+ logger.warn("Could not parse existing opencode.json, creating new one");
186
+ }
187
+ }
188
+ if (!config.plugin) {
189
+ config.plugin = [];
190
+ }
191
+ const pluginEntry = `@openpets/${shortName}`;
192
+ if (!config.plugin.includes(pluginEntry)) {
193
+ config.plugin.push(pluginEntry);
194
+ }
195
+ // Write plugin list to opencode.json (without env vars)
196
+ writeFileSync(opencodeJsonPath, JSON.stringify(config, null, 2));
197
+ logger.info(`Updated opencode.json with plugin: ${pluginEntry}`);
198
+ // Write env values to .pets/config.json (proper location for pet-specific config)
199
+ if (envValues && Object.keys(envValues).length > 0) {
200
+ this.updatePetsConfig(targetDir, shortName, envValues);
201
+ }
202
+ }
203
+ /**
204
+ * Update .pets/config.json with pet-specific environment variables
205
+ */
206
+ updatePetsConfig(targetDir, petId, envValues) {
207
+ const petsConfigDir = join(targetDir, ".pets");
208
+ const petsConfigPath = join(petsConfigDir, "config.json");
209
+ // Ensure .pets directory exists
210
+ if (!existsSync(petsConfigDir)) {
211
+ mkdirSync(petsConfigDir, { recursive: true });
212
+ logger.debug(`Created .pets directory at ${petsConfigDir}`);
213
+ }
214
+ let petsConfig = {
215
+ enabled: [],
216
+ disabled: [],
217
+ envConfig: {},
218
+ };
219
+ if (existsSync(petsConfigPath)) {
220
+ try {
221
+ const existing = JSON.parse(readFileSync(petsConfigPath, "utf-8"));
222
+ petsConfig = {
223
+ enabled: existing.enabled || [],
224
+ disabled: existing.disabled || [],
225
+ envConfig: existing.envConfig || {},
226
+ ...existing
227
+ };
228
+ }
229
+ catch {
230
+ logger.warn("Could not parse existing .pets/config.json, creating new structure");
231
+ }
232
+ }
233
+ // Ensure envConfig structure exists
234
+ if (!petsConfig.envConfig) {
235
+ petsConfig.envConfig = {};
236
+ }
237
+ // Create or update pet-specific env config
238
+ if (!petsConfig.envConfig[petId]) {
239
+ petsConfig.envConfig[petId] = {};
240
+ }
241
+ // Set the environment variables
242
+ for (const [key, value] of Object.entries(envValues)) {
243
+ if (value && value.trim()) {
244
+ petsConfig.envConfig[petId][key] = value.trim();
245
+ logger.debug(`Set ${key} for pet ${petId}`);
246
+ }
247
+ }
248
+ // Update timestamp
249
+ petsConfig.last_updated = new Date().toISOString();
250
+ // Write config
251
+ writeFileSync(petsConfigPath, JSON.stringify(petsConfig, null, 2));
252
+ logger.info(`Saved environment variables for ${petId} to .pets/config.json`);
253
+ }
254
+ getRelativePath(from, to) {
255
+ const fromParts = resolve(from).split("/");
256
+ const toParts = resolve(to).split("/");
257
+ let commonLength = 0;
258
+ for (let i = 0; i < Math.min(fromParts.length, toParts.length); i++) {
259
+ if (fromParts[i] === toParts[i]) {
260
+ commonLength++;
261
+ }
262
+ else {
263
+ break;
264
+ }
265
+ }
266
+ const upCount = fromParts.length - commonLength;
267
+ const relativeParts = [...Array(upCount).fill(".."), ...toParts.slice(commonLength)];
268
+ return relativeParts.join("/");
269
+ }
270
+ getInstalledPetPath(shortName) {
271
+ const petPath = join(this.petsDir, shortName);
272
+ return existsSync(petPath) ? petPath : null;
273
+ }
274
+ listInstalledPets() {
275
+ if (!existsSync(this.petsDir))
276
+ return [];
277
+ const { readdirSync } = require("fs");
278
+ return readdirSync(this.petsDir).filter((name) => {
279
+ const pkgPath = join(this.petsDir, name, "package.json");
280
+ return existsSync(pkgPath);
281
+ });
282
+ }
283
+ removePet(shortName) {
284
+ const petPath = join(this.petsDir, shortName);
285
+ if (!existsSync(petPath))
286
+ return false;
287
+ rmSync(petPath, { recursive: true, force: true });
288
+ return true;
289
+ }
290
+ }
291
+ let defaultDownloader = null;
292
+ export function getPetDownloader() {
293
+ if (!defaultDownloader) {
294
+ defaultDownloader = new PetDownloader();
295
+ }
296
+ return defaultDownloader;
297
+ }
298
+ //# sourceMappingURL=pet-downloader.js.map