@prompd/cli 0.3.3

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 (223) hide show
  1. package/README.md +162 -0
  2. package/bin/prompd.js +23 -0
  3. package/dist/commands/cache.d.ts +3 -0
  4. package/dist/commands/cache.d.ts.map +1 -0
  5. package/dist/commands/cache.js +199 -0
  6. package/dist/commands/cache.js.map +1 -0
  7. package/dist/commands/compile.d.ts +9 -0
  8. package/dist/commands/compile.d.ts.map +1 -0
  9. package/dist/commands/compile.js +104 -0
  10. package/dist/commands/compile.js.map +1 -0
  11. package/dist/commands/config.d.ts +7 -0
  12. package/dist/commands/config.d.ts.map +1 -0
  13. package/dist/commands/config.js +212 -0
  14. package/dist/commands/config.js.map +1 -0
  15. package/dist/commands/create.d.ts +3 -0
  16. package/dist/commands/create.d.ts.map +1 -0
  17. package/dist/commands/create.js +183 -0
  18. package/dist/commands/create.js.map +1 -0
  19. package/dist/commands/deps.d.ts +3 -0
  20. package/dist/commands/deps.d.ts.map +1 -0
  21. package/dist/commands/deps.js +192 -0
  22. package/dist/commands/deps.js.map +1 -0
  23. package/dist/commands/explain.d.ts +3 -0
  24. package/dist/commands/explain.d.ts.map +1 -0
  25. package/dist/commands/explain.js +227 -0
  26. package/dist/commands/explain.js.map +1 -0
  27. package/dist/commands/git.d.ts +3 -0
  28. package/dist/commands/git.d.ts.map +1 -0
  29. package/dist/commands/git.js +306 -0
  30. package/dist/commands/git.js.map +1 -0
  31. package/dist/commands/init.d.ts +3 -0
  32. package/dist/commands/init.d.ts.map +1 -0
  33. package/dist/commands/init.js +177 -0
  34. package/dist/commands/init.js.map +1 -0
  35. package/dist/commands/list.d.ts +3 -0
  36. package/dist/commands/list.d.ts.map +1 -0
  37. package/dist/commands/list.js +126 -0
  38. package/dist/commands/list.js.map +1 -0
  39. package/dist/commands/mcp.d.ts +3 -0
  40. package/dist/commands/mcp.d.ts.map +1 -0
  41. package/dist/commands/mcp.js +326 -0
  42. package/dist/commands/mcp.js.map +1 -0
  43. package/dist/commands/namespace.d.ts +3 -0
  44. package/dist/commands/namespace.d.ts.map +1 -0
  45. package/dist/commands/namespace.js +113 -0
  46. package/dist/commands/namespace.js.map +1 -0
  47. package/dist/commands/package.d.ts +23 -0
  48. package/dist/commands/package.d.ts.map +1 -0
  49. package/dist/commands/package.js +746 -0
  50. package/dist/commands/package.js.map +1 -0
  51. package/dist/commands/provider.d.ts +3 -0
  52. package/dist/commands/provider.d.ts.map +1 -0
  53. package/dist/commands/provider.js +285 -0
  54. package/dist/commands/provider.js.map +1 -0
  55. package/dist/commands/registry.d.ts +9 -0
  56. package/dist/commands/registry.d.ts.map +1 -0
  57. package/dist/commands/registry.js +361 -0
  58. package/dist/commands/registry.js.map +1 -0
  59. package/dist/commands/run.d.ts +3 -0
  60. package/dist/commands/run.d.ts.map +1 -0
  61. package/dist/commands/run.js +157 -0
  62. package/dist/commands/run.js.map +1 -0
  63. package/dist/commands/show.d.ts +3 -0
  64. package/dist/commands/show.d.ts.map +1 -0
  65. package/dist/commands/show.js +90 -0
  66. package/dist/commands/show.js.map +1 -0
  67. package/dist/commands/uninstall.d.ts +3 -0
  68. package/dist/commands/uninstall.d.ts.map +1 -0
  69. package/dist/commands/uninstall.js +95 -0
  70. package/dist/commands/uninstall.js.map +1 -0
  71. package/dist/commands/validate.d.ts +3 -0
  72. package/dist/commands/validate.d.ts.map +1 -0
  73. package/dist/commands/validate.js +57 -0
  74. package/dist/commands/validate.js.map +1 -0
  75. package/dist/commands/version.d.ts +3 -0
  76. package/dist/commands/version.d.ts.map +1 -0
  77. package/dist/commands/version.js +166 -0
  78. package/dist/commands/version.js.map +1 -0
  79. package/dist/index.d.ts +5 -0
  80. package/dist/index.d.ts.map +1 -0
  81. package/dist/index.js +388 -0
  82. package/dist/index.js.map +1 -0
  83. package/dist/lib/auth.d.ts +164 -0
  84. package/dist/lib/auth.d.ts.map +1 -0
  85. package/dist/lib/auth.js +388 -0
  86. package/dist/lib/auth.js.map +1 -0
  87. package/dist/lib/compiler/file-system.d.ts +178 -0
  88. package/dist/lib/compiler/file-system.d.ts.map +1 -0
  89. package/dist/lib/compiler/file-system.js +440 -0
  90. package/dist/lib/compiler/file-system.js.map +1 -0
  91. package/dist/lib/compiler/formatters/anthropic.d.ts +21 -0
  92. package/dist/lib/compiler/formatters/anthropic.d.ts.map +1 -0
  93. package/dist/lib/compiler/formatters/anthropic.js +95 -0
  94. package/dist/lib/compiler/formatters/anthropic.js.map +1 -0
  95. package/dist/lib/compiler/formatters/markdown.d.ts +17 -0
  96. package/dist/lib/compiler/formatters/markdown.d.ts.map +1 -0
  97. package/dist/lib/compiler/formatters/markdown.js +114 -0
  98. package/dist/lib/compiler/formatters/markdown.js.map +1 -0
  99. package/dist/lib/compiler/formatters/openai.d.ts +21 -0
  100. package/dist/lib/compiler/formatters/openai.d.ts.map +1 -0
  101. package/dist/lib/compiler/formatters/openai.js +98 -0
  102. package/dist/lib/compiler/formatters/openai.js.map +1 -0
  103. package/dist/lib/compiler/index.d.ts +56 -0
  104. package/dist/lib/compiler/index.d.ts.map +1 -0
  105. package/dist/lib/compiler/index.js +165 -0
  106. package/dist/lib/compiler/index.js.map +1 -0
  107. package/dist/lib/compiler/language-map.d.ts +31 -0
  108. package/dist/lib/compiler/language-map.d.ts.map +1 -0
  109. package/dist/lib/compiler/language-map.js +156 -0
  110. package/dist/lib/compiler/language-map.js.map +1 -0
  111. package/dist/lib/compiler/package-resolver.d.ts +68 -0
  112. package/dist/lib/compiler/package-resolver.d.ts.map +1 -0
  113. package/dist/lib/compiler/package-resolver.js +254 -0
  114. package/dist/lib/compiler/package-resolver.js.map +1 -0
  115. package/dist/lib/compiler/pipeline.d.ts +53 -0
  116. package/dist/lib/compiler/pipeline.d.ts.map +1 -0
  117. package/dist/lib/compiler/pipeline.js +209 -0
  118. package/dist/lib/compiler/pipeline.js.map +1 -0
  119. package/dist/lib/compiler/prompd-loader.d.ts +108 -0
  120. package/dist/lib/compiler/prompd-loader.d.ts.map +1 -0
  121. package/dist/lib/compiler/prompd-loader.js +270 -0
  122. package/dist/lib/compiler/prompd-loader.js.map +1 -0
  123. package/dist/lib/compiler/section-override.d.ts +40 -0
  124. package/dist/lib/compiler/section-override.d.ts.map +1 -0
  125. package/dist/lib/compiler/section-override.js +296 -0
  126. package/dist/lib/compiler/section-override.js.map +1 -0
  127. package/dist/lib/compiler/stages/assets.d.ts +71 -0
  128. package/dist/lib/compiler/stages/assets.d.ts.map +1 -0
  129. package/dist/lib/compiler/stages/assets.js +456 -0
  130. package/dist/lib/compiler/stages/assets.js.map +1 -0
  131. package/dist/lib/compiler/stages/codegen.d.ts +17 -0
  132. package/dist/lib/compiler/stages/codegen.d.ts.map +1 -0
  133. package/dist/lib/compiler/stages/codegen.js +64 -0
  134. package/dist/lib/compiler/stages/codegen.js.map +1 -0
  135. package/dist/lib/compiler/stages/dependency.d.ts +38 -0
  136. package/dist/lib/compiler/stages/dependency.d.ts.map +1 -0
  137. package/dist/lib/compiler/stages/dependency.js +307 -0
  138. package/dist/lib/compiler/stages/dependency.js.map +1 -0
  139. package/dist/lib/compiler/stages/lexical.d.ts +19 -0
  140. package/dist/lib/compiler/stages/lexical.d.ts.map +1 -0
  141. package/dist/lib/compiler/stages/lexical.js +92 -0
  142. package/dist/lib/compiler/stages/lexical.js.map +1 -0
  143. package/dist/lib/compiler/stages/semantic.d.ts +20 -0
  144. package/dist/lib/compiler/stages/semantic.d.ts.map +1 -0
  145. package/dist/lib/compiler/stages/semantic.js +166 -0
  146. package/dist/lib/compiler/stages/semantic.js.map +1 -0
  147. package/dist/lib/compiler/stages/template.d.ts +94 -0
  148. package/dist/lib/compiler/stages/template.d.ts.map +1 -0
  149. package/dist/lib/compiler/stages/template.js +1044 -0
  150. package/dist/lib/compiler/stages/template.js.map +1 -0
  151. package/dist/lib/compiler/types.d.ts +200 -0
  152. package/dist/lib/compiler/types.d.ts.map +1 -0
  153. package/dist/lib/compiler/types.js +137 -0
  154. package/dist/lib/compiler/types.js.map +1 -0
  155. package/dist/lib/config.d.ts +29 -0
  156. package/dist/lib/config.d.ts.map +1 -0
  157. package/dist/lib/config.js +375 -0
  158. package/dist/lib/config.js.map +1 -0
  159. package/dist/lib/errors.d.ts +19 -0
  160. package/dist/lib/errors.d.ts.map +1 -0
  161. package/dist/lib/errors.js +47 -0
  162. package/dist/lib/errors.js.map +1 -0
  163. package/dist/lib/executor.d.ts +18 -0
  164. package/dist/lib/executor.d.ts.map +1 -0
  165. package/dist/lib/executor.js +372 -0
  166. package/dist/lib/executor.js.map +1 -0
  167. package/dist/lib/git.d.ts +74 -0
  168. package/dist/lib/git.d.ts.map +1 -0
  169. package/dist/lib/git.js +254 -0
  170. package/dist/lib/git.js.map +1 -0
  171. package/dist/lib/index.d.ts +43 -0
  172. package/dist/lib/index.d.ts.map +1 -0
  173. package/dist/lib/index.js +108 -0
  174. package/dist/lib/index.js.map +1 -0
  175. package/dist/lib/mcp.d.ts +42 -0
  176. package/dist/lib/mcp.d.ts.map +1 -0
  177. package/dist/lib/mcp.js +477 -0
  178. package/dist/lib/mcp.js.map +1 -0
  179. package/dist/lib/model-updater.d.ts +51 -0
  180. package/dist/lib/model-updater.d.ts.map +1 -0
  181. package/dist/lib/model-updater.js +275 -0
  182. package/dist/lib/model-updater.js.map +1 -0
  183. package/dist/lib/parser.d.ts +9 -0
  184. package/dist/lib/parser.d.ts.map +1 -0
  185. package/dist/lib/parser.js +197 -0
  186. package/dist/lib/parser.js.map +1 -0
  187. package/dist/lib/registry.d.ts +183 -0
  188. package/dist/lib/registry.d.ts.map +1 -0
  189. package/dist/lib/registry.js +786 -0
  190. package/dist/lib/registry.js.map +1 -0
  191. package/dist/lib/rpc-server.d.ts +78 -0
  192. package/dist/lib/rpc-server.d.ts.map +1 -0
  193. package/dist/lib/rpc-server.js +404 -0
  194. package/dist/lib/rpc-server.js.map +1 -0
  195. package/dist/lib/security.d.ts +120 -0
  196. package/dist/lib/security.d.ts.map +1 -0
  197. package/dist/lib/security.js +478 -0
  198. package/dist/lib/security.js.map +1 -0
  199. package/dist/lib/validation.d.ts +106 -0
  200. package/dist/lib/validation.d.ts.map +1 -0
  201. package/dist/lib/validation.js +398 -0
  202. package/dist/lib/validation.js.map +1 -0
  203. package/dist/lib/version.d.ts +29 -0
  204. package/dist/lib/version.d.ts.map +1 -0
  205. package/dist/lib/version.js +202 -0
  206. package/dist/lib/version.js.map +1 -0
  207. package/dist/lib/workflow-engine.d.ts +161 -0
  208. package/dist/lib/workflow-engine.d.ts.map +1 -0
  209. package/dist/lib/workflow-engine.js +422 -0
  210. package/dist/lib/workflow-engine.js.map +1 -0
  211. package/dist/lib/workflow.d.ts +102 -0
  212. package/dist/lib/workflow.d.ts.map +1 -0
  213. package/dist/lib/workflow.js +228 -0
  214. package/dist/lib/workflow.js.map +1 -0
  215. package/dist/server.d.ts +8 -0
  216. package/dist/server.d.ts.map +1 -0
  217. package/dist/server.js +134 -0
  218. package/dist/server.js.map +1 -0
  219. package/dist/types/index.d.ts +116 -0
  220. package/dist/types/index.d.ts.map +1 -0
  221. package/dist/types/index.js +144 -0
  222. package/dist/types/index.js.map +1 -0
  223. package/package.json +104 -0
@@ -0,0 +1,786 @@
1
+ "use strict";
2
+ /**
3
+ * Prompd Package Registry System (Multi-Registry Architecture)
4
+ * Core registry infrastructure for publishing and installing packages with scope-based resolution
5
+ */
6
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
7
+ if (k2 === undefined) k2 = k;
8
+ var desc = Object.getOwnPropertyDescriptor(m, k);
9
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
10
+ desc = { enumerable: true, get: function() { return m[k]; } };
11
+ }
12
+ Object.defineProperty(o, k2, desc);
13
+ }) : (function(o, m, k, k2) {
14
+ if (k2 === undefined) k2 = k;
15
+ o[k2] = m[k];
16
+ }));
17
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
18
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
19
+ }) : function(o, v) {
20
+ o["default"] = v;
21
+ });
22
+ var __importStar = (this && this.__importStar) || (function () {
23
+ var ownKeys = function(o) {
24
+ ownKeys = Object.getOwnPropertyNames || function (o) {
25
+ var ar = [];
26
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
27
+ return ar;
28
+ };
29
+ return ownKeys(o);
30
+ };
31
+ return function (mod) {
32
+ if (mod && mod.__esModule) return mod;
33
+ var result = {};
34
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
35
+ __setModuleDefault(result, mod);
36
+ return result;
37
+ };
38
+ })();
39
+ Object.defineProperty(exports, "__esModule", { value: true });
40
+ exports.createDefaultRegistryConfig = exports.RegistryClient = void 0;
41
+ const fs = __importStar(require("fs-extra"));
42
+ const path = __importStar(require("path"));
43
+ const semver = __importStar(require("semver"));
44
+ const tar = __importStar(require("tar"));
45
+ const events_1 = require("events");
46
+ const security_1 = require("./security");
47
+ const config_1 = require("./config");
48
+ const file_system_1 = require("./compiler/file-system");
49
+ /**
50
+ * Package Registry Client
51
+ */
52
+ class RegistryClient extends events_1.EventEmitter {
53
+ constructor(options) {
54
+ super();
55
+ this.cache = new Map();
56
+ // Handle legacy string parameter (registry name)
57
+ const opts = typeof options === 'string'
58
+ ? { registryName: options }
59
+ : options || {};
60
+ const configManager = config_1.ConfigManager.getInstance();
61
+ // Load config synchronously - this is critical!
62
+ this.config = this.loadConfigSync(configManager);
63
+ // Resolve registry name
64
+ this.registryName = opts.registryName || this.config.registry.default || 'prompdhub';
65
+ // Get registry config
66
+ const registries = this.config.registry.registries;
67
+ if (!registries[this.registryName]) {
68
+ throw new Error(`Registry '${this.registryName}' not found in configuration`);
69
+ }
70
+ this.registryConfig = registries[this.registryName];
71
+ // Override URL if provided directly (for server-side usage)
72
+ if (opts.registryUrl) {
73
+ this.registryConfig = { ...this.registryConfig, url: opts.registryUrl };
74
+ }
75
+ this.ensureCacheDir();
76
+ }
77
+ get registryUrl() {
78
+ return this.registryConfig.url;
79
+ }
80
+ get authToken() {
81
+ return this.registryConfig.token;
82
+ }
83
+ get cacheDir() {
84
+ return path.join(require('os').homedir(), '.prompd', 'cache');
85
+ }
86
+ get maxPackageSize() {
87
+ return 50 * 1024 * 1024; // 50MB
88
+ }
89
+ /**
90
+ * Load config synchronously - required for constructor
91
+ */
92
+ loadConfigSync(configManager) {
93
+ // If config is already loaded, use it
94
+ if (configManager.config) {
95
+ return configManager.config;
96
+ }
97
+ // Otherwise load it synchronously (this is a hack but necessary)
98
+ const fs = require('fs');
99
+ const yaml = require('yaml');
100
+ const os = require('os');
101
+ const path = require('path');
102
+ const configPath = path.join(os.homedir(), '.prompd', 'config.yaml');
103
+ // Use env var for registry URL if set (useful for local development)
104
+ const registryUrl = process.env.PROMPD_REGISTRY_URL || 'https://registry.prompdhub.ai';
105
+ const defaultConfig = {
106
+ apiKeys: {},
107
+ customProviders: {},
108
+ registry: {
109
+ registries: {
110
+ prompdhub: {
111
+ url: registryUrl
112
+ }
113
+ },
114
+ default: 'prompdhub'
115
+ },
116
+ scopes: {},
117
+ maxRetries: 3,
118
+ timeout: 30,
119
+ verbose: false
120
+ };
121
+ try {
122
+ if (fs.existsSync(configPath)) {
123
+ const configContent = fs.readFileSync(configPath, 'utf-8');
124
+ const fileConfig = yaml.parse(configContent);
125
+ // Merge with default config
126
+ const mergedConfig = { ...defaultConfig, ...fileConfig };
127
+ // Ensure registry structure exists
128
+ if (!mergedConfig.registry) {
129
+ mergedConfig.registry = defaultConfig.registry;
130
+ }
131
+ if (!mergedConfig.registry.registries) {
132
+ mergedConfig.registry.registries = defaultConfig.registry.registries;
133
+ }
134
+ if (!mergedConfig.scopes) {
135
+ mergedConfig.scopes = {};
136
+ }
137
+ return mergedConfig;
138
+ }
139
+ }
140
+ catch (error) {
141
+ console.warn(`Warning: Error loading config: ${error}`);
142
+ }
143
+ return defaultConfig;
144
+ }
145
+ /**
146
+ * Authenticate with registry using token
147
+ */
148
+ async loginWithToken(token) {
149
+ // Verify token by getting user profile
150
+ const response = await fetch(`${this.registryUrl}/v1/user/me`, {
151
+ headers: {
152
+ 'Authorization': `Bearer ${token}`,
153
+ 'Content-Type': 'application/json'
154
+ }
155
+ });
156
+ if (response.status === 401) {
157
+ throw new Error('Invalid token. Please check your API token.');
158
+ }
159
+ else if (response.status === 404) {
160
+ throw new Error(`User endpoint not found. Registry URL: ${this.registryUrl}`);
161
+ }
162
+ else if (response.status >= 500) {
163
+ throw new Error(`Registry server error (${response.status}). Please try again later.`);
164
+ }
165
+ if (!response.ok) {
166
+ const errorText = await response.text();
167
+ throw new Error(`Authentication failed: ${errorText}`);
168
+ }
169
+ const userData = await response.json();
170
+ if (!userData.username) {
171
+ throw new Error('Invalid response from registry: missing username');
172
+ }
173
+ // Update registry config
174
+ const configManager = config_1.ConfigManager.getInstance();
175
+ await configManager.setRegistryToken(this.registryName, token, userData.username);
176
+ return { username: userData.username };
177
+ }
178
+ /**
179
+ * Clear authentication credentials
180
+ */
181
+ async logout() {
182
+ const configManager = config_1.ConfigManager.getInstance();
183
+ await configManager.setRegistryToken(this.registryName, '', '');
184
+ }
185
+ /**
186
+ * Publish a package to the registry
187
+ */
188
+ async publish(packagePath, options = {
189
+ access: 'public',
190
+ tag: 'latest',
191
+ dryRun: false,
192
+ force: false
193
+ }) {
194
+ this.emit('publishStart', { packagePath, options });
195
+ try {
196
+ // Resolve file system (same pattern as compile)
197
+ const fileSystem = options.fileSystem || new file_system_1.NodeFileSystem();
198
+ // Load and validate package metadata from manifest.json
199
+ const metadata = await this.loadManifestFromFS(packagePath, fileSystem);
200
+ // Security validation using file system abstraction
201
+ await this.validatePackageForPublishFS(packagePath, metadata, fileSystem);
202
+ // Check version conflicts
203
+ if (!options.force) {
204
+ const existingVersions = await this.getPackageVersions(metadata.name);
205
+ if (existingVersions.includes(metadata.version)) {
206
+ throw new Error(`Version ${metadata.version} already exists. Use --force to overwrite.`);
207
+ }
208
+ }
209
+ if (options.dryRun) {
210
+ console.log('Dry run - package would be published:');
211
+ console.log(JSON.stringify(metadata, null, 2));
212
+ return;
213
+ }
214
+ // Create package tarball Buffer (memory or disk)
215
+ const tarballBuffer = await this.createPackageTarballBuffer(packagePath, metadata, fileSystem);
216
+ // Upload to registry
217
+ await this.uploadPackageBuffer(tarballBuffer, metadata, options);
218
+ this.emit('publishComplete', {
219
+ name: metadata.name,
220
+ version: metadata.version,
221
+ access: options.access
222
+ });
223
+ }
224
+ catch (error) {
225
+ this.emit('publishError', { packagePath, error });
226
+ throw error;
227
+ }
228
+ }
229
+ /**
230
+ * Install a package from the registry
231
+ * Accepts both formats:
232
+ * - @namespace/package (with options.version)
233
+ * - @namespace/package@version (embedded version)
234
+ */
235
+ async install(packageName, options = {}) {
236
+ this.emit('installStart', { packageName, options });
237
+ console.log('[RegistryClient.install] Starting install:', packageName);
238
+ console.log('[RegistryClient.install] Options:', JSON.stringify(options));
239
+ try {
240
+ // Parse package reference if it includes @version
241
+ // Format: @namespace/package@version
242
+ // Find last @ to split name from version (scoped packages start with @)
243
+ let name = packageName;
244
+ let versionSpec = options.version || 'latest';
245
+ const lastAtIndex = packageName.lastIndexOf('@');
246
+ if (lastAtIndex > 0) {
247
+ // Has embedded version: @namespace/package@0.1.5
248
+ name = packageName.substring(0, lastAtIndex);
249
+ versionSpec = packageName.substring(lastAtIndex + 1);
250
+ }
251
+ console.log('[RegistryClient.install] Parsed name:', name, 'version:', versionSpec);
252
+ // Resolve version
253
+ const resolvedVersion = await this.resolveVersion(name, versionSpec);
254
+ console.log('[RegistryClient.install] Resolved version:', resolvedVersion);
255
+ // Check cache first
256
+ const cacheKey = `${name}@${resolvedVersion}`;
257
+ if (!options.skipCache && !options.force) {
258
+ const cachedPath = await this.getCachedPackage(cacheKey);
259
+ if (cachedPath) {
260
+ await this.installFromCache(cachedPath, name, resolvedVersion, options);
261
+ return;
262
+ }
263
+ }
264
+ // Download package
265
+ const packageData = await this.downloadPackage(name, resolvedVersion);
266
+ // Install dependencies (skip self-referential dependencies)
267
+ const metadata = packageData.metadata;
268
+ if (metadata.dependencies && Object.keys(metadata.dependencies).length > 0) {
269
+ // Filter out self-referential dependencies to avoid circular resolution
270
+ const filteredDeps = {};
271
+ for (const [depName, depVersion] of Object.entries(metadata.dependencies)) {
272
+ if (depName === name) {
273
+ // Skip self-referential dependency (package depends on itself)
274
+ continue;
275
+ }
276
+ filteredDeps[depName] = depVersion;
277
+ }
278
+ if (Object.keys(filteredDeps).length > 0) {
279
+ await this.installDependencies(filteredDeps, options);
280
+ }
281
+ }
282
+ // Extract and install package
283
+ console.log('[RegistryClient.install] Extracting package to workspace...');
284
+ await this.extractAndInstallPackage(packageData, name, resolvedVersion, options);
285
+ console.log('[RegistryClient.install] Extraction complete');
286
+ // Cache package
287
+ await this.cachePackage(cacheKey, packageData);
288
+ this.emit('installComplete', {
289
+ name: name,
290
+ version: resolvedVersion
291
+ });
292
+ console.log('[RegistryClient.install] Install complete for', name, '@', resolvedVersion);
293
+ }
294
+ catch (error) {
295
+ this.emit('installError', { packageName, error });
296
+ throw error;
297
+ }
298
+ }
299
+ /**
300
+ * Search packages in the registry
301
+ */
302
+ async search(query) {
303
+ try {
304
+ const searchParams = new URLSearchParams();
305
+ if (query.query)
306
+ searchParams.set('q', query.query);
307
+ if (query.category)
308
+ searchParams.set('category', query.category);
309
+ if (query.type)
310
+ searchParams.set('type', query.type);
311
+ if (query.tags)
312
+ searchParams.set('tags', query.tags.join(','));
313
+ if (query.author)
314
+ searchParams.set('author', query.author);
315
+ if (query.limit)
316
+ searchParams.set('limit', query.limit.toString());
317
+ if (query.offset)
318
+ searchParams.set('offset', query.offset.toString());
319
+ if (query.sort)
320
+ searchParams.set('sort', query.sort);
321
+ // Registry uses /packages?search= endpoint, not /search?q=
322
+ const response = await fetch(`${this.registryUrl}/packages?search=${encodeURIComponent(query.query || '')}`, {
323
+ headers: this.getAuthHeaders()
324
+ });
325
+ if (!response.ok) {
326
+ throw new Error(`Search failed: ${response.status} ${response.statusText}`);
327
+ }
328
+ const result = await response.json();
329
+ this.emit('searchComplete', { query, results: result.packages.length });
330
+ return result;
331
+ }
332
+ catch (error) {
333
+ this.emit('searchError', { query, error });
334
+ throw error;
335
+ }
336
+ }
337
+ /**
338
+ * Get package information
339
+ */
340
+ async getPackageInfo(packageName, version) {
341
+ try {
342
+ const url = version
343
+ ? `${this.registryUrl}/packages/${packageName}/${version}`
344
+ : `${this.registryUrl}/packages/${packageName}`;
345
+ const response = await fetch(url, {
346
+ headers: this.getAuthHeaders()
347
+ });
348
+ if (!response.ok) {
349
+ if (response.status === 404) {
350
+ throw new Error(`Package not found: ${packageName}`);
351
+ }
352
+ throw new Error(`Failed to get package info: ${response.status} ${response.statusText}`);
353
+ }
354
+ return await response.json();
355
+ }
356
+ catch (error) {
357
+ this.emit('packageInfoError', { packageName, version, error });
358
+ throw error;
359
+ }
360
+ }
361
+ /**
362
+ * Get available versions for a package
363
+ */
364
+ async getPackageVersions(packageName) {
365
+ try {
366
+ const response = await fetch(`${this.registryUrl}/packages/${packageName}/versions`, {
367
+ headers: this.getAuthHeaders()
368
+ });
369
+ if (!response.ok) {
370
+ if (response.status === 404) {
371
+ return [];
372
+ }
373
+ throw new Error(`Failed to get package versions: ${response.status} ${response.statusText}`);
374
+ }
375
+ const data = await response.json();
376
+ // Handle both response formats (like Python CLI does):
377
+ // 1. Direct array: [{version: "1.0.0", ...}, ...]
378
+ // 2. Wrapped object: {versions: [...]}
379
+ let versionsList;
380
+ if (Array.isArray(data)) {
381
+ versionsList = data;
382
+ }
383
+ else if (data.versions && Array.isArray(data.versions)) {
384
+ versionsList = data.versions;
385
+ }
386
+ else {
387
+ throw new Error('Invalid versions response format');
388
+ }
389
+ // Extract version strings from version objects
390
+ return versionsList.map(v => typeof v === 'string' ? v : v.version);
391
+ }
392
+ catch (error) {
393
+ this.emit('packageVersionsError', { packageName, error });
394
+ throw error;
395
+ }
396
+ }
397
+ async loadPackageMetadata(packageDir) {
398
+ const projectFile = path.join(packageDir, 'project.prmdproj');
399
+ if (!await fs.pathExists(projectFile)) {
400
+ throw new Error('No project.prmdproj file found');
401
+ }
402
+ const content = await fs.readFile(projectFile, 'utf8');
403
+ const yaml = require('yaml');
404
+ // Parse YAML frontmatter
405
+ const match = content.match(/^---\n([\s\S]*?)\n---/);
406
+ if (!match) {
407
+ throw new Error('Invalid project.prmdproj file format');
408
+ }
409
+ const metadata = yaml.parse(match[1]);
410
+ // Validate required fields
411
+ const required = ['name', 'version', 'description', 'author'];
412
+ for (const field of required) {
413
+ if (!metadata[field]) {
414
+ throw new Error(`Missing required field: ${field}`);
415
+ }
416
+ }
417
+ // Validate version format
418
+ if (!semver.valid(metadata.version)) {
419
+ throw new Error(`Invalid version format: ${metadata.version}`);
420
+ }
421
+ // Set defaults
422
+ metadata.license = metadata.license || 'MIT';
423
+ metadata.keywords = metadata.keywords || [];
424
+ metadata.dependencies = metadata.dependencies || {};
425
+ metadata.files = metadata.files || ['**/*'];
426
+ metadata.type = metadata.type || 'collection';
427
+ metadata.category = metadata.category || 'general';
428
+ metadata.tags = metadata.tags || [];
429
+ metadata.prmdVersion = '0.2.3';
430
+ metadata.createdAt = new Date().toISOString();
431
+ metadata.updatedAt = new Date().toISOString();
432
+ return metadata;
433
+ }
434
+ async validatePackageForPublish(packageDir, metadata) {
435
+ // Check package size
436
+ const stats = await this.getDirectorySize(packageDir);
437
+ if (stats.size > this.maxPackageSize) {
438
+ throw new Error(`Package size (${stats.size}) exceeds maximum allowed (${this.maxPackageSize})`);
439
+ }
440
+ // Validate package name
441
+ const sanitizedName = security_1.SecurityManager.sanitizeToolName(metadata.name);
442
+ if (sanitizedName !== metadata.name) {
443
+ throw new Error(`Invalid package name: ${metadata.name}`);
444
+ }
445
+ // Check for required files
446
+ const requiredFiles = [];
447
+ if (metadata.type === 'prompt' && metadata.main) {
448
+ requiredFiles.push(metadata.main);
449
+ }
450
+ for (const file of requiredFiles) {
451
+ const filePath = path.join(packageDir, file);
452
+ if (!await fs.pathExists(filePath)) {
453
+ throw new Error(`Required file not found: ${file}`);
454
+ }
455
+ }
456
+ // Validate dependencies
457
+ for (const [depName, depVersion] of Object.entries(metadata.dependencies)) {
458
+ if (!semver.validRange(depVersion)) {
459
+ throw new Error(`Invalid dependency version range: ${depName}@${depVersion}`);
460
+ }
461
+ }
462
+ }
463
+ async createPackageTarball(packageDir, metadata) {
464
+ const tarballName = `${metadata.name}-${metadata.version}.tgz`;
465
+ const tarballPath = path.join(this.cacheDir, 'temp', tarballName);
466
+ await fs.ensureDir(path.dirname(tarballPath));
467
+ // Create tarball with only specified files
468
+ await tar.create({
469
+ gzip: true,
470
+ file: tarballPath,
471
+ cwd: packageDir,
472
+ prefix: 'package/',
473
+ filter: (path) => {
474
+ // Include files matching patterns in metadata.files
475
+ return this.matchesFilePatterns(path, metadata.files);
476
+ }
477
+ }, ['.']);
478
+ return tarballPath;
479
+ }
480
+ async uploadPackage(tarballPath, metadata, options) {
481
+ const formData = new FormData();
482
+ const tarballBuffer = await fs.readFile(tarballPath);
483
+ formData.append('package', new Blob([tarballBuffer]), `${metadata.name}-${metadata.version}.tgz`);
484
+ formData.append('metadata', JSON.stringify(metadata));
485
+ formData.append('access', options.access);
486
+ formData.append('tag', options.tag);
487
+ const response = await fetch(`${this.registryUrl}/publish`, {
488
+ method: 'POST',
489
+ headers: this.getAuthHeaders(),
490
+ body: formData
491
+ });
492
+ if (!response.ok) {
493
+ const errorText = await response.text();
494
+ throw new Error(`Publish failed: ${response.status} ${response.statusText} - ${errorText}`);
495
+ }
496
+ }
497
+ async resolveVersion(packageName, versionSpec) {
498
+ if (versionSpec === 'latest') {
499
+ const packageInfo = await this.getPackageInfo(packageName);
500
+ return packageInfo.version;
501
+ }
502
+ if (semver.valid(versionSpec)) {
503
+ return versionSpec;
504
+ }
505
+ // Resolve version range
506
+ const versions = await this.getPackageVersions(packageName);
507
+ const resolved = semver.maxSatisfying(versions, versionSpec);
508
+ if (!resolved) {
509
+ throw new Error(`No version found matching: ${versionSpec}`);
510
+ }
511
+ return resolved;
512
+ }
513
+ /**
514
+ * Download a package without installing it to disk.
515
+ * Useful for in-memory package loading.
516
+ *
517
+ * @param packageName - Package name (e.g., "@namespace/package-name")
518
+ * @param version - Package version (e.g., "1.0.0")
519
+ * @returns Object with tarball Buffer and package metadata
520
+ */
521
+ async downloadPackageBuffer(packageName, version) {
522
+ return this.downloadPackage(packageName, version);
523
+ }
524
+ async downloadPackage(packageName, version) {
525
+ // Registry endpoint format: /packages/@scope/name/download/version
526
+ const response = await fetch(`${this.registryUrl}/packages/${packageName}/download/${version}`, {
527
+ headers: this.getAuthHeaders()
528
+ });
529
+ if (!response.ok) {
530
+ throw new Error(`Download failed: ${response.status} ${response.statusText}`);
531
+ }
532
+ const arrayBuffer = await response.arrayBuffer();
533
+ const tarballBuffer = Buffer.from(arrayBuffer);
534
+ // Extract metadata from the .pdpkg (ZIP) file instead of calling getPackageInfo
535
+ // Try prompd.json first, fall back to manifest.json for older packages
536
+ const AdmZip = (await Promise.resolve().then(() => __importStar(require('adm-zip')))).default;
537
+ const zip = new AdmZip(tarballBuffer);
538
+ // Check for prompd.json first (newer format), then manifest.json (legacy)
539
+ let manifestEntry = zip.getEntry('prompd.json');
540
+ if (!manifestEntry) {
541
+ manifestEntry = zip.getEntry('manifest.json');
542
+ }
543
+ if (!manifestEntry) {
544
+ throw new Error(`Invalid package: neither prompd.json nor manifest.json found in ${packageName}@${version}`);
545
+ }
546
+ const manifestContent = manifestEntry.getData().toString('utf8');
547
+ const metadata = JSON.parse(manifestContent);
548
+ return {
549
+ tarball: tarballBuffer,
550
+ metadata
551
+ };
552
+ }
553
+ async installDependencies(dependencies, options) {
554
+ for (const [name, versionSpec] of Object.entries(dependencies)) {
555
+ this.emit('installingDependency', { name, version: versionSpec });
556
+ await this.install(name, { ...options, version: versionSpec });
557
+ }
558
+ }
559
+ async extractAndInstallPackage(packageData, packageName, version, options) {
560
+ // Use workspace root from options if provided, otherwise use cwd
561
+ const workspaceRoot = options.workspaceRoot || process.cwd();
562
+ console.log('[RegistryClient.extractAndInstallPackage] packageName:', packageName);
563
+ console.log('[RegistryClient.extractAndInstallPackage] version:', version);
564
+ console.log('[RegistryClient.extractAndInstallPackage] workspaceRoot:', workspaceRoot);
565
+ console.log('[RegistryClient.extractAndInstallPackage] global:', options.global);
566
+ const installDir = options.global
567
+ ? path.join(this.cacheDir, 'global', 'packages', packageName, version)
568
+ : path.join(workspaceRoot, '.prompd', 'cache', packageName, version);
569
+ console.log('[RegistryClient.extractAndInstallPackage] installDir:', installDir);
570
+ await fs.ensureDir(installDir);
571
+ console.log('[RegistryClient.extractAndInstallPackage] Directory ensured');
572
+ // Extract .pdpkg (ZIP archive) using adm-zip
573
+ const AdmZip = (await Promise.resolve().then(() => __importStar(require('adm-zip')))).default;
574
+ const zip = new AdmZip(packageData.tarball);
575
+ // Log zip contents
576
+ const zipEntries = zip.getEntries();
577
+ console.log('[RegistryClient.extractAndInstallPackage] ZIP contains', zipEntries.length, 'entries:');
578
+ zipEntries.forEach(entry => {
579
+ console.log(' -', entry.entryName);
580
+ });
581
+ zip.extractAllTo(installDir, true);
582
+ console.log('[RegistryClient.extractAndInstallPackage] ZIP extracted to:', installDir);
583
+ // Verify extraction
584
+ const extractedFiles = await fs.readdir(installDir);
585
+ console.log('[RegistryClient.extractAndInstallPackage] Extracted files:', extractedFiles);
586
+ // Write package metadata for cache tracking
587
+ const metadataPath = path.join(installDir, '.prmdmeta');
588
+ await fs.writeJson(metadataPath, packageData.metadata, { spaces: 2 });
589
+ console.log('[RegistryClient.extractAndInstallPackage] Wrote .prmdmeta');
590
+ }
591
+ getAuthHeaders() {
592
+ const headers = {
593
+ 'User-Agent': 'prompd-cli/0.2.4',
594
+ 'Content-Type': 'application/json'
595
+ };
596
+ if (this.authToken) {
597
+ headers['Authorization'] = `Bearer ${this.authToken}`;
598
+ }
599
+ return headers;
600
+ }
601
+ async ensureCacheDir() {
602
+ await fs.ensureDir(this.cacheDir);
603
+ await fs.ensureDir(path.join(this.cacheDir, 'temp'));
604
+ }
605
+ async getDirectorySize(dir) {
606
+ let totalSize = 0;
607
+ let totalFiles = 0;
608
+ const items = await fs.readdir(dir);
609
+ for (const item of items) {
610
+ const fullPath = path.join(dir, item);
611
+ const stats = await fs.stat(fullPath);
612
+ if (stats.isDirectory()) {
613
+ const subStats = await this.getDirectorySize(fullPath);
614
+ totalSize += subStats.size;
615
+ totalFiles += subStats.files;
616
+ }
617
+ else {
618
+ totalSize += stats.size;
619
+ totalFiles++;
620
+ }
621
+ }
622
+ return { size: totalSize, files: totalFiles };
623
+ }
624
+ matchesFilePatterns(filePath, patterns) {
625
+ // Simple glob matching - in production would use proper glob library
626
+ for (const pattern of patterns) {
627
+ if (pattern === '**/*' || pattern === '*') {
628
+ return true;
629
+ }
630
+ if (pattern.includes('*')) {
631
+ const regex = new RegExp(pattern.replace(/\*/g, '.*'));
632
+ if (regex.test(filePath)) {
633
+ return true;
634
+ }
635
+ }
636
+ else if (filePath === pattern) {
637
+ return true;
638
+ }
639
+ }
640
+ return false;
641
+ }
642
+ async getCachedPackage(cacheKey) {
643
+ const cachePath = path.join(this.cacheDir, 'packages', cacheKey);
644
+ return await fs.pathExists(cachePath) ? cachePath : null;
645
+ }
646
+ async installFromCache(cachePath, packageName, version, options) {
647
+ console.log('[RegistryClient.installFromCache] Installing from cache:', cachePath);
648
+ this.emit('installingFromCache', { name: packageName, version });
649
+ // Read the cached tarball
650
+ const tarballBuffer = await fs.readFile(cachePath);
651
+ console.log('[RegistryClient.installFromCache] Read tarball:', tarballBuffer.length, 'bytes');
652
+ // Extract to the workspace
653
+ const packageData = { tarball: tarballBuffer, metadata: { name: packageName, version } };
654
+ await this.extractAndInstallPackage(packageData, packageName, version, options);
655
+ console.log('[RegistryClient.installFromCache] Extraction complete');
656
+ }
657
+ async cachePackage(cacheKey, packageData) {
658
+ const cachePath = path.join(this.cacheDir, 'packages', cacheKey);
659
+ await fs.ensureDir(path.dirname(cachePath));
660
+ await fs.writeFile(cachePath, packageData.tarball);
661
+ }
662
+ /**
663
+ * Load manifest.json from file system abstraction.
664
+ * Supports both disk-based and in-memory file systems.
665
+ */
666
+ async loadManifestFromFS(packagePath, fileSystem) {
667
+ const manifestPath = fileSystem.join(packagePath, 'manifest.json');
668
+ const exists = await Promise.resolve(fileSystem.exists(manifestPath));
669
+ if (!exists) {
670
+ throw new Error('No manifest.json file found');
671
+ }
672
+ const content = await Promise.resolve(fileSystem.readFile(manifestPath));
673
+ const manifest = JSON.parse(content);
674
+ // Validate required fields
675
+ const required = ['name', 'version', 'description', 'author'];
676
+ for (const field of required) {
677
+ if (!manifest[field]) {
678
+ throw new Error(`Missing required field in manifest.json: ${field}`);
679
+ }
680
+ }
681
+ // Validate version format
682
+ if (!semver.valid(manifest.version)) {
683
+ throw new Error(`Invalid version format: ${manifest.version}`);
684
+ }
685
+ // Set defaults
686
+ manifest.license = manifest.license || 'MIT';
687
+ manifest.keywords = manifest.keywords || [];
688
+ manifest.dependencies = manifest.dependencies || {};
689
+ manifest.files = manifest.files || ['**/*.prmd'];
690
+ manifest.type = manifest.type || 'collection';
691
+ manifest.category = manifest.category || 'general';
692
+ manifest.tags = manifest.tags || [];
693
+ manifest.prompdVersion = manifest.prompdVersion || '0.3.3';
694
+ manifest.createdAt = manifest.createdAt || new Date().toISOString();
695
+ manifest.updatedAt = new Date().toISOString();
696
+ return manifest;
697
+ }
698
+ /**
699
+ * Validate package for publish using file system abstraction.
700
+ */
701
+ async validatePackageForPublishFS(packagePath, metadata, fileSystem) {
702
+ // Calculate package size
703
+ const stats = fileSystem instanceof file_system_1.MemoryFileSystem
704
+ ? fileSystem.getTotalSize(packagePath)
705
+ : await this.getDirectorySize(packagePath);
706
+ if (stats.size > this.maxPackageSize) {
707
+ throw new Error(`Package size (${stats.size}) exceeds maximum allowed (${this.maxPackageSize})`);
708
+ }
709
+ // Validate package name (use existing security manager)
710
+ const sanitizedName = security_1.SecurityManager.sanitizeToolName(metadata.name);
711
+ if (sanitizedName !== metadata.name) {
712
+ throw new Error(`Invalid package name: ${metadata.name}`);
713
+ }
714
+ // Validate dependencies
715
+ for (const [depName, depVersion] of Object.entries(metadata.dependencies)) {
716
+ if (!semver.validRange(depVersion)) {
717
+ throw new Error(`Invalid dependency version range: ${depName}@${depVersion}`);
718
+ }
719
+ }
720
+ }
721
+ /**
722
+ * Create package tarball Buffer using file system abstraction.
723
+ * Supports both in-memory and disk-based package creation.
724
+ */
725
+ async createPackageTarballBuffer(packagePath, metadata, fileSystem) {
726
+ // Memory-based path
727
+ if (fileSystem instanceof file_system_1.MemoryFileSystem) {
728
+ return await fileSystem.createPackageBuffer(packagePath, metadata, {
729
+ filter: (filePath) => this.matchesFilePatterns(filePath, metadata.files)
730
+ });
731
+ }
732
+ // Disk-based path (existing logic)
733
+ const tarballName = `${metadata.name}-${metadata.version}.tgz`;
734
+ const tarballPath = path.join(this.cacheDir, 'temp', tarballName);
735
+ await fs.ensureDir(path.dirname(tarballPath));
736
+ await tar.create({
737
+ gzip: true,
738
+ file: tarballPath,
739
+ cwd: packagePath,
740
+ prefix: 'package/',
741
+ filter: (filePath) => this.matchesFilePatterns(filePath, metadata.files)
742
+ }, ['.']);
743
+ const buffer = await fs.readFile(tarballPath);
744
+ await fs.remove(tarballPath); // Cleanup
745
+ return buffer;
746
+ }
747
+ /**
748
+ * Upload package Buffer to registry.
749
+ */
750
+ async uploadPackageBuffer(tarballBuffer, metadata, options) {
751
+ const FormData = require('form-data');
752
+ const formData = new FormData();
753
+ formData.append('package', tarballBuffer, {
754
+ filename: `${metadata.name}-${metadata.version}.pdpkg`,
755
+ contentType: 'application/gzip'
756
+ });
757
+ formData.append('metadata', JSON.stringify(metadata));
758
+ formData.append('access', options.access);
759
+ formData.append('tag', options.tag);
760
+ const response = await fetch(`${this.registryUrl}/publish`, {
761
+ method: 'POST',
762
+ headers: {
763
+ ...this.getAuthHeaders(),
764
+ ...formData.getHeaders()
765
+ },
766
+ body: formData
767
+ });
768
+ if (!response.ok) {
769
+ const errorText = await response.text();
770
+ throw new Error(`Publish failed: ${response.status} ${response.statusText} - ${errorText}`);
771
+ }
772
+ }
773
+ }
774
+ exports.RegistryClient = RegistryClient;
775
+ /**
776
+ * Default registry configuration
777
+ */
778
+ const createDefaultRegistryConfig = () => ({
779
+ registryUrl: process.env.PROMPD_REGISTRY_URL || 'https://registry.prompdhub.ai',
780
+ authToken: process.env.PROMPD_AUTH_TOKEN,
781
+ cacheDir: path.join(require('os').homedir(), '.prmd', 'cache'),
782
+ timeout: 30000,
783
+ maxPackageSize: 50 * 1024 * 1024 // 50MB
784
+ });
785
+ exports.createDefaultRegistryConfig = createDefaultRegistryConfig;
786
+ //# sourceMappingURL=registry.js.map