@bahulam/code 0.1.14 → 0.1.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/commands/install.mjs +126 -4
- package/src/terminal/main.mjs +3 -1
package/package.json
CHANGED
package/src/commands/install.mjs
CHANGED
|
@@ -40,6 +40,9 @@ const CYAN = '\x1b[36m';
|
|
|
40
40
|
const GREEN = '\x1b[32m';
|
|
41
41
|
const YELLOW = '\x1b[33m';
|
|
42
42
|
|
|
43
|
+
const DEFAULT_BAHULAM_PLUGIN_REGISTRY_URL =
|
|
44
|
+
'https://raw.githubusercontent.com/BahulamAI/awesome-bahulam-plugins/main/registry.json';
|
|
45
|
+
|
|
43
46
|
function parseArgs(argv) {
|
|
44
47
|
const parsed = {
|
|
45
48
|
source: null,
|
|
@@ -152,10 +155,13 @@ export async function handleInstallCommand(argv, { cwd = process.cwd() } = {}) {
|
|
|
152
155
|
|
|
153
156
|
Install a pack. For pi sources, pulls the ingredient and scaffolds a
|
|
154
157
|
full Bahulam pack (composition + state layer + workspace + agent), then
|
|
155
|
-
installs it. For git/tarball/local sources, installs the
|
|
158
|
+
installs it. For registry/git/tarball/local sources, installs the
|
|
159
|
+
existing pack.
|
|
156
160
|
|
|
157
161
|
Sources:
|
|
158
162
|
pi:<npm-package>[@<version>] Scaffold + install from a pi package
|
|
163
|
+
<registry-name> Install from awesome-bahulam-plugins
|
|
164
|
+
bahulam:<registry-name> Explicit awesome-bahulam-plugins lookup
|
|
159
165
|
<git-url>[.git] Clone a hand-authored pack
|
|
160
166
|
<tarball-url> Download + install a pack tarball
|
|
161
167
|
<local-path> Copy + install a local pack directory
|
|
@@ -166,7 +172,7 @@ export async function handleInstallCommand(argv, { cwd = process.cwd() } = {}) {
|
|
|
166
172
|
--no-state Skip the persistent state layer (pi sources only)
|
|
167
173
|
--no-workspace Skip the reactive workspace panel (pi sources only)
|
|
168
174
|
--project Install into ./.bahulam/plugins/ instead of ~/.bahulam/plugins/
|
|
169
|
-
--ref <ref> Git branch/tag/commit (git sources
|
|
175
|
+
--ref <ref> Git branch/tag/commit (git or registry sources)
|
|
170
176
|
--json Machine-readable output
|
|
171
177
|
|
|
172
178
|
`);
|
|
@@ -186,6 +192,12 @@ export async function handleInstallCommand(argv, { cwd = process.cwd() } = {}) {
|
|
|
186
192
|
throw new Error(`unrecognized source: ${args.source}`);
|
|
187
193
|
}
|
|
188
194
|
|
|
195
|
+
const registryName = registryNameFromSource(args.source, classified);
|
|
196
|
+
if (registryName) {
|
|
197
|
+
await installFromBahulamRegistry({ name: registryName, targetDir, cwd, args });
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
|
|
189
201
|
// Non-pi paths reuse the plugin-manage install machinery.
|
|
190
202
|
let dest;
|
|
191
203
|
if (classified.kind === 'git') {
|
|
@@ -194,8 +206,6 @@ export async function handleInstallCommand(argv, { cwd = process.cwd() } = {}) {
|
|
|
194
206
|
dest = await installFromTarball({ url: classified.url, targetDir, force: args.force });
|
|
195
207
|
} else if (classified.kind === 'local') {
|
|
196
208
|
dest = await installFromLocal({ src: classified.path, targetDir, force: args.force });
|
|
197
|
-
} else if (classified.kind === 'name') {
|
|
198
|
-
throw new Error(`registry lookup for bare names is not yet wired into \`bahulam install\`. Provide a git URL, tarball URL, local path, or pi: source.`);
|
|
199
209
|
} else {
|
|
200
210
|
throw new Error(`could not resolve source: ${args.source}`);
|
|
201
211
|
}
|
|
@@ -207,6 +217,118 @@ export async function handleInstallCommand(argv, { cwd = process.cwd() } = {}) {
|
|
|
207
217
|
}
|
|
208
218
|
}
|
|
209
219
|
|
|
220
|
+
export function registryNameFromSource(source, classified = null) {
|
|
221
|
+
const raw = String(source || '').trim();
|
|
222
|
+
const prefix = 'bahulam:';
|
|
223
|
+
if (raw.toLowerCase().startsWith(prefix)) {
|
|
224
|
+
const name = raw.slice(prefix.length).trim();
|
|
225
|
+
if (!name) {
|
|
226
|
+
throw new Error(`bahulam registry source requires a plugin name, e.g. ${CYAN}bahulam:manim-studio${RESET}`);
|
|
227
|
+
}
|
|
228
|
+
return name;
|
|
229
|
+
}
|
|
230
|
+
if (classified?.kind === 'name') return classified.name;
|
|
231
|
+
return null;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
async function installFromBahulamRegistry({ name, targetDir, cwd, args }) {
|
|
235
|
+
const entry = await resolveBahulamRegistryPlugin(name, { cwd });
|
|
236
|
+
const repository = entry.repository || entry.repo || entry.url;
|
|
237
|
+
if (!repository) {
|
|
238
|
+
throw new Error(`registry entry "${entry.name}" is missing a repository URL`);
|
|
239
|
+
}
|
|
240
|
+
const ref = args.ref || entry.ref || null;
|
|
241
|
+
const subdir = entry.subdir || entry.path || null;
|
|
242
|
+
|
|
243
|
+
process.stderr.write(
|
|
244
|
+
`${DIM}registry${RESET} ${entry.name} → ${repository}` +
|
|
245
|
+
`${subdir ? `#${subdir}` : ''}${ref ? ` @ ${ref}` : ''}\n`,
|
|
246
|
+
);
|
|
247
|
+
|
|
248
|
+
const dest = await installFromGit({
|
|
249
|
+
url: repository,
|
|
250
|
+
targetDir,
|
|
251
|
+
name: entry.name,
|
|
252
|
+
ref,
|
|
253
|
+
subdir,
|
|
254
|
+
force: args.force,
|
|
255
|
+
});
|
|
256
|
+
await preflightAndReport({ dest, args, cwd });
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
export async function resolveBahulamRegistryPlugin(name, { cwd = process.cwd(), registry = null } = {}) {
|
|
260
|
+
const doc = registry || await loadBahulamPluginRegistry({ cwd });
|
|
261
|
+
const entries = Array.isArray(doc) ? doc : Array.isArray(doc?.plugins) ? doc.plugins : [];
|
|
262
|
+
if (!entries.length) {
|
|
263
|
+
throw new Error('Bahulam plugin registry did not contain any plugins');
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
const needle = normalizeRegistryName(name);
|
|
267
|
+
const entry = entries.find(item => {
|
|
268
|
+
const names = [
|
|
269
|
+
item?.name,
|
|
270
|
+
item?.slug,
|
|
271
|
+
item?.id,
|
|
272
|
+
...(Array.isArray(item?.aliases) ? item.aliases : []),
|
|
273
|
+
];
|
|
274
|
+
return names.some(candidate => normalizeRegistryName(candidate) === needle);
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
if (!entry) {
|
|
278
|
+
throw new Error(
|
|
279
|
+
`plugin not found in Bahulam registry: ${name}\n` +
|
|
280
|
+
`Available: ${entries.map(item => item.name).filter(Boolean).join(', ') || '(none)'}`,
|
|
281
|
+
);
|
|
282
|
+
}
|
|
283
|
+
return entry;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
async function loadBahulamPluginRegistry({ cwd = process.cwd() } = {}) {
|
|
287
|
+
const explicit =
|
|
288
|
+
process.env.BAHULAM_PLUGIN_REGISTRY ||
|
|
289
|
+
process.env.BAHULAM_PLUGIN_REGISTRY_PATH ||
|
|
290
|
+
process.env.BAHULAM_PLUGIN_REGISTRY_URL;
|
|
291
|
+
if (explicit) return readRegistryLocation(explicit, cwd);
|
|
292
|
+
|
|
293
|
+
try {
|
|
294
|
+
return await readRegistryLocation(DEFAULT_BAHULAM_PLUGIN_REGISTRY_URL, cwd);
|
|
295
|
+
} catch (err) {
|
|
296
|
+
const localPath = findLocalRegistry(cwd);
|
|
297
|
+
if (localPath) return readRegistryJson(localPath);
|
|
298
|
+
throw new Error(`failed to load Bahulam plugin registry: ${err.message}`);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
async function readRegistryLocation(location, cwd) {
|
|
303
|
+
if (/^https?:\/\//i.test(location)) {
|
|
304
|
+
const res = await fetch(location, { headers: { accept: 'application/json' } });
|
|
305
|
+
if (!res.ok) throw new Error(`${location} returned HTTP ${res.status}`);
|
|
306
|
+
return res.json();
|
|
307
|
+
}
|
|
308
|
+
const filePath = path.isAbsolute(location) ? location : path.resolve(cwd, location);
|
|
309
|
+
return readRegistryJson(filePath);
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
function readRegistryJson(filePath) {
|
|
313
|
+
try {
|
|
314
|
+
return JSON.parse(fs.readFileSync(filePath, 'utf-8'));
|
|
315
|
+
} catch (err) {
|
|
316
|
+
throw new Error(`failed to read registry ${filePath}: ${err.message}`);
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
function findLocalRegistry(cwd) {
|
|
321
|
+
const candidates = [
|
|
322
|
+
path.resolve(cwd, '../awesome-bahulam-plugins/registry.json'),
|
|
323
|
+
path.resolve(cwd, 'awesome-bahulam-plugins/registry.json'),
|
|
324
|
+
];
|
|
325
|
+
return candidates.find(candidate => fs.existsSync(candidate)) || null;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
function normalizeRegistryName(name) {
|
|
329
|
+
return String(name || '').trim().replace(/^bahulam:/i, '').toLowerCase();
|
|
330
|
+
}
|
|
331
|
+
|
|
210
332
|
async function installPiWithScaffolding({ classified, targetDir, cwd, args }) {
|
|
211
333
|
const { bahulamHome } = await import('../core/paths.mjs');
|
|
212
334
|
const { discoverPiTools } = await import('../plugins/pi-compat/probe.mjs');
|
package/src/terminal/main.mjs
CHANGED
|
@@ -297,7 +297,7 @@ async function main() {
|
|
|
297
297
|
const verb = subcommandArgs[0];
|
|
298
298
|
const rest = subcommandArgs.slice(1);
|
|
299
299
|
process.stderr.write(`\x1b[33m!\x1b[0m \`bahulam plugin ${verb}\` moved to top-level. Use:\n`);
|
|
300
|
-
process.stderr.write(` \x1b[36mbahulam install ${rest.join(' ')}\x1b[0m (pack — scaffolds around pi:,
|
|
300
|
+
process.stderr.write(` \x1b[36mbahulam install ${rest.join(' ')}\x1b[0m (pack — registry, scaffolds around pi:, git/tarball/local)\n`);
|
|
301
301
|
process.stderr.write(` \x1b[36mbahulam pull ${rest.join(' ')}\x1b[0m (ingredient only — pi: sources)\n`);
|
|
302
302
|
process.exit(2);
|
|
303
303
|
}
|
|
@@ -356,6 +356,8 @@ async function main() {
|
|
|
356
356
|
\x1b[1mPacks & ingredients:\x1b[0m
|
|
357
357
|
bahulam pull pi:<name> Pull a pi ingredient (composable, not runnable on its own)
|
|
358
358
|
bahulam install pi:<name> Pull ingredient + scaffold a full Bahulam pack around it
|
|
359
|
+
bahulam install <name> Install from awesome-bahulam-plugins
|
|
360
|
+
bahulam install bahulam:<name> Explicit awesome-bahulam-plugins lookup
|
|
359
361
|
bahulam install <git-url> Install a hand-authored pack from git
|
|
360
362
|
bahulam install <local-path> Install a hand-authored pack from disk
|
|
361
363
|
bahulam plugin list List installed packs and pi ingredients
|