ocx 1.0.12 → 1.0.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +299 -153
- package/dist/index.js.map +9 -9
- package/package.json +62 -63
package/dist/index.js
CHANGED
|
@@ -8486,7 +8486,7 @@ var coerce = {
|
|
|
8486
8486
|
date: (arg) => ZodDate.create({ ...arg, coerce: true })
|
|
8487
8487
|
};
|
|
8488
8488
|
var NEVER = INVALID;
|
|
8489
|
-
//
|
|
8489
|
+
// src/schemas/registry.ts
|
|
8490
8490
|
var openCodeNameSchema = exports_external.string().min(1, "Name cannot be empty").max(64, "Name cannot exceed 64 characters").regex(/^[a-z0-9]+(-[a-z0-9]+)*$/, {
|
|
8491
8491
|
message: "Must be lowercase alphanumeric with single hyphen separators (e.g., 'my-component', 'my-plugin'). Cannot start/end with hyphen or have consecutive hyphens."
|
|
8492
8492
|
});
|
|
@@ -8671,28 +8671,6 @@ var registryIndexSchema = exports_external.object({
|
|
|
8671
8671
|
}))
|
|
8672
8672
|
});
|
|
8673
8673
|
|
|
8674
|
-
// ../schemas/dist/config.js
|
|
8675
|
-
var registryConfigSchema = exports_external.object({
|
|
8676
|
-
url: exports_external.string().url("Registry URL must be a valid URL"),
|
|
8677
|
-
version: exports_external.string().optional(),
|
|
8678
|
-
headers: exports_external.record(exports_external.string()).optional()
|
|
8679
|
-
});
|
|
8680
|
-
var ocxConfigSchema = exports_external.object({
|
|
8681
|
-
$schema: exports_external.string().optional(),
|
|
8682
|
-
registries: exports_external.record(registryConfigSchema).default({}),
|
|
8683
|
-
lockRegistries: exports_external.boolean().default(false)
|
|
8684
|
-
});
|
|
8685
|
-
var installedComponentSchema = exports_external.object({
|
|
8686
|
-
registry: exports_external.string(),
|
|
8687
|
-
version: exports_external.string(),
|
|
8688
|
-
hash: exports_external.string(),
|
|
8689
|
-
files: exports_external.array(exports_external.string()),
|
|
8690
|
-
installedAt: exports_external.string()
|
|
8691
|
-
});
|
|
8692
|
-
var ocxLockSchema = exports_external.object({
|
|
8693
|
-
lockVersion: exports_external.literal(1),
|
|
8694
|
-
installed: exports_external.record(qualifiedComponentSchema, installedComponentSchema).default({})
|
|
8695
|
-
});
|
|
8696
8674
|
// src/utils/errors.ts
|
|
8697
8675
|
var EXIT_CODES = {
|
|
8698
8676
|
SUCCESS: 0,
|
|
@@ -10279,6 +10257,27 @@ function applyEdits(text, edits) {
|
|
|
10279
10257
|
}
|
|
10280
10258
|
|
|
10281
10259
|
// src/schemas/config.ts
|
|
10260
|
+
var registryConfigSchema = exports_external.object({
|
|
10261
|
+
url: exports_external.string().url("Registry URL must be a valid URL"),
|
|
10262
|
+
version: exports_external.string().optional(),
|
|
10263
|
+
headers: exports_external.record(exports_external.string()).optional()
|
|
10264
|
+
});
|
|
10265
|
+
var ocxConfigSchema = exports_external.object({
|
|
10266
|
+
$schema: exports_external.string().optional(),
|
|
10267
|
+
registries: exports_external.record(registryConfigSchema).default({}),
|
|
10268
|
+
lockRegistries: exports_external.boolean().default(false)
|
|
10269
|
+
});
|
|
10270
|
+
var installedComponentSchema = exports_external.object({
|
|
10271
|
+
registry: exports_external.string(),
|
|
10272
|
+
version: exports_external.string(),
|
|
10273
|
+
hash: exports_external.string(),
|
|
10274
|
+
files: exports_external.array(exports_external.string()),
|
|
10275
|
+
installedAt: exports_external.string()
|
|
10276
|
+
});
|
|
10277
|
+
var ocxLockSchema = exports_external.object({
|
|
10278
|
+
lockVersion: exports_external.literal(1),
|
|
10279
|
+
installed: exports_external.record(qualifiedComponentSchema, installedComponentSchema).default({})
|
|
10280
|
+
});
|
|
10282
10281
|
var CONFIG_FILE = "ocx.jsonc";
|
|
10283
10282
|
var LOCK_FILE = "ocx.lock";
|
|
10284
10283
|
async function readOcxConfig(cwd) {
|
|
@@ -10296,9 +10295,9 @@ async function readOcxConfig(cwd) {
|
|
|
10296
10295
|
throw error;
|
|
10297
10296
|
}
|
|
10298
10297
|
}
|
|
10299
|
-
async function writeOcxConfig(cwd,
|
|
10298
|
+
async function writeOcxConfig(cwd, config) {
|
|
10300
10299
|
const configPath = `${cwd}/${CONFIG_FILE}`;
|
|
10301
|
-
const content = JSON.stringify(
|
|
10300
|
+
const content = JSON.stringify(config, null, 2);
|
|
10302
10301
|
await Bun.write(configPath, content);
|
|
10303
10302
|
}
|
|
10304
10303
|
async function readOcxLock(cwd) {
|
|
@@ -10367,8 +10366,8 @@ async function updateOpencodeJsonConfig(cwd, opencode) {
|
|
|
10367
10366
|
content = existing.content;
|
|
10368
10367
|
configPath = existing.path;
|
|
10369
10368
|
} else {
|
|
10370
|
-
const
|
|
10371
|
-
content = JSON.stringify(
|
|
10369
|
+
const config = { $schema: "https://opencode.ai/config.json" };
|
|
10370
|
+
content = JSON.stringify(config, null, "\t");
|
|
10372
10371
|
configPath = `${cwd}/opencode.jsonc`;
|
|
10373
10372
|
created = true;
|
|
10374
10373
|
}
|
|
@@ -11932,8 +11931,8 @@ function registerAddCommand(program2) {
|
|
|
11932
11931
|
async function runAdd(componentNames, options2) {
|
|
11933
11932
|
const cwd = options2.cwd ?? process.cwd();
|
|
11934
11933
|
const lockPath = join(cwd, "ocx.lock");
|
|
11935
|
-
const
|
|
11936
|
-
if (!
|
|
11934
|
+
const config = await readOcxConfig(cwd);
|
|
11935
|
+
if (!config) {
|
|
11937
11936
|
throw new ConfigError("No ocx.jsonc found. Run 'ocx init' first.");
|
|
11938
11937
|
}
|
|
11939
11938
|
let lock = { lockVersion: 1, installed: {} };
|
|
@@ -11944,7 +11943,7 @@ async function runAdd(componentNames, options2) {
|
|
|
11944
11943
|
const spin = options2.quiet ? null : createSpinner({ text: "Resolving dependencies..." });
|
|
11945
11944
|
spin?.start();
|
|
11946
11945
|
try {
|
|
11947
|
-
const resolved = await resolveDependencies(
|
|
11946
|
+
const resolved = await resolveDependencies(config.registries, componentNames);
|
|
11948
11947
|
spin?.succeed(`Resolved ${resolved.components.length} components`);
|
|
11949
11948
|
if (options2.verbose) {
|
|
11950
11949
|
logger.info("Install order:");
|
|
@@ -12243,111 +12242,133 @@ function findComponentByFile(lock, filePath) {
|
|
|
12243
12242
|
}
|
|
12244
12243
|
|
|
12245
12244
|
// src/commands/build.ts
|
|
12245
|
+
import { join as join3, relative } from "path";
|
|
12246
|
+
|
|
12247
|
+
// src/lib/build-registry.ts
|
|
12246
12248
|
import { mkdir as mkdir2 } from "fs/promises";
|
|
12247
|
-
import { dirname as dirname2, join as join2
|
|
12249
|
+
import { dirname as dirname2, join as join2 } from "path";
|
|
12250
|
+
class BuildRegistryError extends Error {
|
|
12251
|
+
errors;
|
|
12252
|
+
constructor(message, errors3 = []) {
|
|
12253
|
+
super(message);
|
|
12254
|
+
this.errors = errors3;
|
|
12255
|
+
this.name = "BuildRegistryError";
|
|
12256
|
+
}
|
|
12257
|
+
}
|
|
12258
|
+
async function buildRegistry(options2) {
|
|
12259
|
+
const { source: sourcePath, out: outPath } = options2;
|
|
12260
|
+
const registryFile = Bun.file(join2(sourcePath, "registry.json"));
|
|
12261
|
+
if (!await registryFile.exists()) {
|
|
12262
|
+
throw new BuildRegistryError("No registry.json found in source directory");
|
|
12263
|
+
}
|
|
12264
|
+
const registryData = await registryFile.json();
|
|
12265
|
+
const parseResult = registrySchema.safeParse(registryData);
|
|
12266
|
+
if (!parseResult.success) {
|
|
12267
|
+
const errors3 = parseResult.error.errors.map((e3) => `${e3.path.join(".")}: ${e3.message}`);
|
|
12268
|
+
throw new BuildRegistryError("Registry validation failed", errors3);
|
|
12269
|
+
}
|
|
12270
|
+
const registry = parseResult.data;
|
|
12271
|
+
const validationErrors = [];
|
|
12272
|
+
const componentsDir = join2(outPath, "components");
|
|
12273
|
+
await mkdir2(componentsDir, { recursive: true });
|
|
12274
|
+
for (const component of registry.components) {
|
|
12275
|
+
const packument = {
|
|
12276
|
+
name: component.name,
|
|
12277
|
+
versions: {
|
|
12278
|
+
[registry.version]: component
|
|
12279
|
+
},
|
|
12280
|
+
"dist-tags": {
|
|
12281
|
+
latest: registry.version
|
|
12282
|
+
}
|
|
12283
|
+
};
|
|
12284
|
+
const packumentPath = join2(componentsDir, `${component.name}.json`);
|
|
12285
|
+
await Bun.write(packumentPath, JSON.stringify(packument, null, 2));
|
|
12286
|
+
for (const rawFile of component.files) {
|
|
12287
|
+
const file = normalizeFile(rawFile);
|
|
12288
|
+
const sourceFilePath = join2(sourcePath, "files", file.path);
|
|
12289
|
+
const destFilePath = join2(componentsDir, component.name, file.path);
|
|
12290
|
+
const destFileDir = dirname2(destFilePath);
|
|
12291
|
+
if (!await Bun.file(sourceFilePath).exists()) {
|
|
12292
|
+
validationErrors.push(`${component.name}: Source file not found at ${sourceFilePath}`);
|
|
12293
|
+
continue;
|
|
12294
|
+
}
|
|
12295
|
+
await mkdir2(destFileDir, { recursive: true });
|
|
12296
|
+
const sourceFile = Bun.file(sourceFilePath);
|
|
12297
|
+
await Bun.write(destFilePath, sourceFile);
|
|
12298
|
+
}
|
|
12299
|
+
}
|
|
12300
|
+
if (validationErrors.length > 0) {
|
|
12301
|
+
throw new BuildRegistryError(`Build failed with ${validationErrors.length} errors`, validationErrors);
|
|
12302
|
+
}
|
|
12303
|
+
const index = {
|
|
12304
|
+
name: registry.name,
|
|
12305
|
+
namespace: registry.namespace,
|
|
12306
|
+
version: registry.version,
|
|
12307
|
+
author: registry.author,
|
|
12308
|
+
components: registry.components.map((c) => ({
|
|
12309
|
+
name: c.name,
|
|
12310
|
+
type: c.type,
|
|
12311
|
+
description: c.description
|
|
12312
|
+
}))
|
|
12313
|
+
};
|
|
12314
|
+
await Bun.write(join2(outPath, "index.json"), JSON.stringify(index, null, 2));
|
|
12315
|
+
const wellKnownDir = join2(outPath, ".well-known");
|
|
12316
|
+
await mkdir2(wellKnownDir, { recursive: true });
|
|
12317
|
+
const discovery = { registry: "/index.json" };
|
|
12318
|
+
await Bun.write(join2(wellKnownDir, "ocx.json"), JSON.stringify(discovery, null, 2));
|
|
12319
|
+
return {
|
|
12320
|
+
name: registry.name,
|
|
12321
|
+
namespace: registry.namespace,
|
|
12322
|
+
version: registry.version,
|
|
12323
|
+
componentsCount: registry.components.length,
|
|
12324
|
+
outputPath: outPath
|
|
12325
|
+
};
|
|
12326
|
+
}
|
|
12327
|
+
|
|
12328
|
+
// src/commands/build.ts
|
|
12248
12329
|
function registerBuildCommand(program2) {
|
|
12249
12330
|
program2.command("build").description("Build a registry from source (for registry authors)").argument("[path]", "Registry source directory", ".").option("--out <dir>", "Output directory", "./dist").option("--cwd <path>", "Working directory", process.cwd()).option("--json", "Output as JSON", false).option("-q, --quiet", "Suppress output", false).action(async (path, options2) => {
|
|
12250
12331
|
try {
|
|
12251
|
-
const sourcePath =
|
|
12252
|
-
const outPath =
|
|
12332
|
+
const sourcePath = join3(options2.cwd, path);
|
|
12333
|
+
const outPath = join3(options2.cwd, options2.out);
|
|
12253
12334
|
const spinner2 = createSpinner({
|
|
12254
12335
|
text: "Building registry...",
|
|
12255
12336
|
quiet: options2.quiet || options2.json
|
|
12256
12337
|
});
|
|
12257
12338
|
if (!options2.json)
|
|
12258
12339
|
spinner2.start();
|
|
12259
|
-
const
|
|
12260
|
-
|
|
12261
|
-
|
|
12262
|
-
|
|
12263
|
-
process.exit(1);
|
|
12264
|
-
}
|
|
12265
|
-
const registryData = await registryFile.json();
|
|
12266
|
-
const parseResult = registrySchema.safeParse(registryData);
|
|
12267
|
-
if (!parseResult.success) {
|
|
12268
|
-
if (!options2.json) {
|
|
12269
|
-
spinner2.fail("Registry validation failed");
|
|
12270
|
-
const errors3 = parseResult.error.errors.map((e3) => ` ${e3.path.join(".")}: ${e3.message}`);
|
|
12271
|
-
for (const err of errors3) {
|
|
12272
|
-
console.log(kleur_default.red(err));
|
|
12273
|
-
}
|
|
12274
|
-
}
|
|
12275
|
-
process.exit(1);
|
|
12276
|
-
}
|
|
12277
|
-
const registry2 = parseResult.data;
|
|
12278
|
-
const validationErrors = [];
|
|
12279
|
-
const componentsDir = join2(outPath, "components");
|
|
12280
|
-
await mkdir2(componentsDir, { recursive: true });
|
|
12281
|
-
for (const component of registry2.components) {
|
|
12282
|
-
const packument = {
|
|
12283
|
-
name: component.name,
|
|
12284
|
-
versions: {
|
|
12285
|
-
[registry2.version]: component
|
|
12286
|
-
},
|
|
12287
|
-
"dist-tags": {
|
|
12288
|
-
latest: registry2.version
|
|
12289
|
-
}
|
|
12290
|
-
};
|
|
12291
|
-
const packumentPath = join2(componentsDir, `${component.name}.json`);
|
|
12292
|
-
await Bun.write(packumentPath, JSON.stringify(packument, null, 2));
|
|
12293
|
-
for (const rawFile of component.files) {
|
|
12294
|
-
const file = normalizeFile(rawFile);
|
|
12295
|
-
const sourceFilePath = join2(sourcePath, "files", file.path);
|
|
12296
|
-
const destFilePath = join2(componentsDir, component.name, file.path);
|
|
12297
|
-
const destFileDir = dirname2(destFilePath);
|
|
12298
|
-
if (!await Bun.file(sourceFilePath).exists()) {
|
|
12299
|
-
validationErrors.push(`${component.name}: Source file not found at ${sourceFilePath}`);
|
|
12300
|
-
continue;
|
|
12301
|
-
}
|
|
12302
|
-
await mkdir2(destFileDir, { recursive: true });
|
|
12303
|
-
const sourceFile = Bun.file(sourceFilePath);
|
|
12304
|
-
await Bun.write(destFilePath, sourceFile);
|
|
12305
|
-
}
|
|
12306
|
-
}
|
|
12307
|
-
if (validationErrors.length > 0) {
|
|
12308
|
-
if (!options2.json) {
|
|
12309
|
-
spinner2.fail(`Build failed with ${validationErrors.length} errors`);
|
|
12310
|
-
for (const err of validationErrors) {
|
|
12311
|
-
console.log(kleur_default.red(` ${err}`));
|
|
12312
|
-
}
|
|
12313
|
-
}
|
|
12314
|
-
process.exit(1);
|
|
12315
|
-
}
|
|
12316
|
-
const index = {
|
|
12317
|
-
name: registry2.name,
|
|
12318
|
-
namespace: registry2.namespace,
|
|
12319
|
-
version: registry2.version,
|
|
12320
|
-
author: registry2.author,
|
|
12321
|
-
components: registry2.components.map((c) => ({
|
|
12322
|
-
name: c.name,
|
|
12323
|
-
type: c.type,
|
|
12324
|
-
description: c.description
|
|
12325
|
-
}))
|
|
12326
|
-
};
|
|
12327
|
-
await Bun.write(join2(outPath, "index.json"), JSON.stringify(index, null, 2));
|
|
12328
|
-
const wellKnownDir = join2(outPath, ".well-known");
|
|
12329
|
-
await mkdir2(wellKnownDir, { recursive: true });
|
|
12330
|
-
const discovery = { registry: "/index.json" };
|
|
12331
|
-
await Bun.write(join2(wellKnownDir, "ocx.json"), JSON.stringify(discovery, null, 2));
|
|
12340
|
+
const result = await buildRegistry({
|
|
12341
|
+
source: sourcePath,
|
|
12342
|
+
out: outPath
|
|
12343
|
+
});
|
|
12332
12344
|
if (!options2.json) {
|
|
12333
|
-
const msg = `Built ${
|
|
12345
|
+
const msg = `Built ${result.componentsCount} components to ${relative(options2.cwd, outPath)}`;
|
|
12334
12346
|
spinner2.succeed(msg);
|
|
12335
12347
|
if (!process.stdout.isTTY) {
|
|
12336
|
-
logger.success(`Built ${
|
|
12348
|
+
logger.success(`Built ${result.componentsCount} components`);
|
|
12337
12349
|
}
|
|
12338
12350
|
}
|
|
12339
12351
|
if (options2.json) {
|
|
12340
12352
|
outputJson({
|
|
12341
12353
|
success: true,
|
|
12342
12354
|
data: {
|
|
12343
|
-
name:
|
|
12344
|
-
version:
|
|
12345
|
-
components:
|
|
12346
|
-
output:
|
|
12355
|
+
name: result.name,
|
|
12356
|
+
version: result.version,
|
|
12357
|
+
components: result.componentsCount,
|
|
12358
|
+
output: result.outputPath
|
|
12347
12359
|
}
|
|
12348
12360
|
});
|
|
12349
12361
|
}
|
|
12350
12362
|
} catch (error) {
|
|
12363
|
+
if (error instanceof BuildRegistryError) {
|
|
12364
|
+
if (!options2.json) {
|
|
12365
|
+
logger.error(error.message);
|
|
12366
|
+
for (const err of error.errors) {
|
|
12367
|
+
console.log(kleur_default.red(` ${err}`));
|
|
12368
|
+
}
|
|
12369
|
+
}
|
|
12370
|
+
process.exit(1);
|
|
12371
|
+
}
|
|
12351
12372
|
handleError(error, { json: options2.json });
|
|
12352
12373
|
}
|
|
12353
12374
|
});
|
|
@@ -13157,8 +13178,8 @@ function registerDiffCommand(program2) {
|
|
|
13157
13178
|
}
|
|
13158
13179
|
return;
|
|
13159
13180
|
}
|
|
13160
|
-
const
|
|
13161
|
-
if (!
|
|
13181
|
+
const config = await readOcxConfig(options2.cwd);
|
|
13182
|
+
if (!config) {
|
|
13162
13183
|
if (options2.json) {
|
|
13163
13184
|
outputJson({
|
|
13164
13185
|
success: false,
|
|
@@ -13198,7 +13219,7 @@ function registerDiffCommand(program2) {
|
|
|
13198
13219
|
continue;
|
|
13199
13220
|
}
|
|
13200
13221
|
const localContent = await localFile.text();
|
|
13201
|
-
const registryConfig =
|
|
13222
|
+
const registryConfig = config.registries[installed.registry];
|
|
13202
13223
|
if (!registryConfig) {
|
|
13203
13224
|
logger.warn(`Registry '${installed.registry}' not configured for component '${name}'.`);
|
|
13204
13225
|
continue;
|
|
@@ -13245,18 +13266,24 @@ Diff for ${res.name}:`));
|
|
|
13245
13266
|
|
|
13246
13267
|
// src/commands/init.ts
|
|
13247
13268
|
import { existsSync as existsSync2 } from "fs";
|
|
13248
|
-
import { writeFile as writeFile2 } from "fs/promises";
|
|
13249
|
-
import { join as
|
|
13269
|
+
import { cp, mkdir as mkdir3, readdir, readFile, rm, writeFile as writeFile2 } from "fs/promises";
|
|
13270
|
+
import { join as join4 } from "path";
|
|
13250
13271
|
|
|
13251
13272
|
// src/constants.ts
|
|
13252
13273
|
var OCX_DOMAIN = "ocx.kdco.dev";
|
|
13253
13274
|
var OCX_SCHEMA_URL = `https://${OCX_DOMAIN}/schema.json`;
|
|
13254
13275
|
|
|
13255
13276
|
// src/commands/init.ts
|
|
13277
|
+
var TEMPLATE_REPO = "kdcokenny/ocx";
|
|
13278
|
+
var TEMPLATE_PATH = "examples/registry-starter";
|
|
13256
13279
|
function registerInitCommand(program2) {
|
|
13257
|
-
program2.command("init").description("Initialize OCX configuration in your project").option("-y, --yes", "Skip prompts and use defaults").option("--cwd <path>", "Working directory", process.cwd()).option("-q, --quiet", "Suppress output").option("-v, --verbose", "Verbose output").option("--json", "Output as JSON").action(async (options2) => {
|
|
13280
|
+
program2.command("init [directory]").description("Initialize OCX configuration in your project").option("-y, --yes", "Skip prompts and use defaults").option("--cwd <path>", "Working directory", process.cwd()).option("-q, --quiet", "Suppress output").option("-v, --verbose", "Verbose output").option("--json", "Output as JSON").option("--registry", "Scaffold a new OCX registry project").option("--namespace <name>", "Registry namespace (e.g., my-org)").option("--author <name>", "Author name for the registry").option("--canary", "Use canary (main branch) instead of latest release").option("--local <path>", "Use local template directory instead of fetching").action(async (directory, options2) => {
|
|
13258
13281
|
try {
|
|
13259
|
-
|
|
13282
|
+
if (options2.registry) {
|
|
13283
|
+
await runInitRegistry(directory, options2);
|
|
13284
|
+
} else {
|
|
13285
|
+
await runInit(options2);
|
|
13286
|
+
}
|
|
13260
13287
|
} catch (error) {
|
|
13261
13288
|
handleError(error, { json: options2.json });
|
|
13262
13289
|
}
|
|
@@ -13264,7 +13291,7 @@ function registerInitCommand(program2) {
|
|
|
13264
13291
|
}
|
|
13265
13292
|
async function runInit(options2) {
|
|
13266
13293
|
const cwd = options2.cwd ?? process.cwd();
|
|
13267
|
-
const configPath =
|
|
13294
|
+
const configPath = join4(cwd, "ocx.jsonc");
|
|
13268
13295
|
if (existsSync2(configPath)) {
|
|
13269
13296
|
if (!options2.yes) {
|
|
13270
13297
|
logger.warn("ocx.jsonc already exists");
|
|
@@ -13280,8 +13307,8 @@ async function runInit(options2) {
|
|
|
13280
13307
|
$schema: OCX_SCHEMA_URL,
|
|
13281
13308
|
registries: {}
|
|
13282
13309
|
};
|
|
13283
|
-
const
|
|
13284
|
-
const content2 = JSON.stringify(
|
|
13310
|
+
const config = ocxConfigSchema.parse(rawConfig);
|
|
13311
|
+
const content2 = JSON.stringify(config, null, 2);
|
|
13285
13312
|
await writeFile2(configPath, content2, "utf-8");
|
|
13286
13313
|
if (!options2.quiet && !options2.json) {
|
|
13287
13314
|
logger.success("Initialized OCX configuration");
|
|
@@ -13301,31 +13328,141 @@ async function runInit(options2) {
|
|
|
13301
13328
|
throw error;
|
|
13302
13329
|
}
|
|
13303
13330
|
}
|
|
13331
|
+
async function runInitRegistry(directory, options2) {
|
|
13332
|
+
const cwd = directory ?? options2.cwd ?? process.cwd();
|
|
13333
|
+
const namespace = options2.namespace ?? "my-registry";
|
|
13334
|
+
const author = options2.author ?? "Your Name";
|
|
13335
|
+
if (!/^[a-z0-9]+(-[a-z0-9]+)*$/.test(namespace)) {
|
|
13336
|
+
throw new ValidationError("Invalid namespace format: must start with letter/number, use hyphens only between segments (e.g., 'my-registry')");
|
|
13337
|
+
}
|
|
13338
|
+
const existingFiles = await readdir(cwd).catch(() => []);
|
|
13339
|
+
const hasVisibleFiles = existingFiles.some((f) => !f.startsWith("."));
|
|
13340
|
+
if (hasVisibleFiles && !options2.yes) {
|
|
13341
|
+
throw new ConflictError("Directory is not empty. Use --yes to overwrite existing files.");
|
|
13342
|
+
}
|
|
13343
|
+
const spin = options2.quiet ? null : createSpinner({ text: "Scaffolding registry..." });
|
|
13344
|
+
spin?.start();
|
|
13345
|
+
try {
|
|
13346
|
+
if (spin)
|
|
13347
|
+
spin.text = options2.local ? "Copying template..." : "Fetching template...";
|
|
13348
|
+
if (options2.local) {
|
|
13349
|
+
await mkdir3(cwd, { recursive: true });
|
|
13350
|
+
await copyDir(options2.local, cwd);
|
|
13351
|
+
} else {
|
|
13352
|
+
const version = options2.canary ? "main" : await getLatestVersion();
|
|
13353
|
+
await fetchAndExtractTemplate(cwd, version, options2.verbose);
|
|
13354
|
+
}
|
|
13355
|
+
if (spin)
|
|
13356
|
+
spin.text = "Configuring project...";
|
|
13357
|
+
await replacePlaceholders(cwd, { namespace, author });
|
|
13358
|
+
spin?.succeed(`Created registry: ${namespace}`);
|
|
13359
|
+
if (options2.json) {
|
|
13360
|
+
console.log(JSON.stringify({ success: true, namespace, path: cwd }));
|
|
13361
|
+
} else if (!options2.quiet) {
|
|
13362
|
+
logger.info("");
|
|
13363
|
+
logger.info("Next steps:");
|
|
13364
|
+
logger.info(" 1. bun install");
|
|
13365
|
+
logger.info(" 2. Edit registry.json with your components");
|
|
13366
|
+
logger.info(" 3. bun run build");
|
|
13367
|
+
logger.info("");
|
|
13368
|
+
logger.info("Deploy to:");
|
|
13369
|
+
logger.info(" Cloudflare: bunx wrangler deploy");
|
|
13370
|
+
logger.info(" Vercel: vercel");
|
|
13371
|
+
logger.info(" Netlify: netlify deploy");
|
|
13372
|
+
}
|
|
13373
|
+
} catch (error) {
|
|
13374
|
+
spin?.fail("Failed to scaffold registry");
|
|
13375
|
+
throw error;
|
|
13376
|
+
}
|
|
13377
|
+
}
|
|
13378
|
+
async function copyDir(src, dest) {
|
|
13379
|
+
await cp(src, dest, { recursive: true });
|
|
13380
|
+
}
|
|
13381
|
+
async function getLatestVersion() {
|
|
13382
|
+
const pkgPath = new URL("../../package.json", import.meta.url);
|
|
13383
|
+
const pkgContent = await readFile(pkgPath);
|
|
13384
|
+
const pkg = JSON.parse(pkgContent.toString());
|
|
13385
|
+
return `v${pkg.version}`;
|
|
13386
|
+
}
|
|
13387
|
+
async function fetchAndExtractTemplate(destDir, version, verbose) {
|
|
13388
|
+
const ref = version === "main" ? "heads/main" : `tags/${version}`;
|
|
13389
|
+
const tarballUrl = `https://github.com/${TEMPLATE_REPO}/archive/refs/${ref}.tar.gz`;
|
|
13390
|
+
if (verbose) {
|
|
13391
|
+
logger.info(`Fetching ${tarballUrl}`);
|
|
13392
|
+
}
|
|
13393
|
+
const response = await fetch(tarballUrl);
|
|
13394
|
+
if (!response.ok || !response.body) {
|
|
13395
|
+
throw new NetworkError(`Failed to fetch template from ${tarballUrl}: ${response.statusText}`);
|
|
13396
|
+
}
|
|
13397
|
+
const tempDir = join4(destDir, ".ocx-temp");
|
|
13398
|
+
await mkdir3(tempDir, { recursive: true });
|
|
13399
|
+
try {
|
|
13400
|
+
const tarPath = join4(tempDir, "template.tar.gz");
|
|
13401
|
+
const arrayBuffer = await response.arrayBuffer();
|
|
13402
|
+
await writeFile2(tarPath, Buffer.from(arrayBuffer));
|
|
13403
|
+
const proc = Bun.spawn(["tar", "-xzf", tarPath, "-C", tempDir], {
|
|
13404
|
+
stdout: "ignore",
|
|
13405
|
+
stderr: "pipe"
|
|
13406
|
+
});
|
|
13407
|
+
const exitCode = await proc.exited;
|
|
13408
|
+
if (exitCode !== 0) {
|
|
13409
|
+
const stderr = await new Response(proc.stderr).text();
|
|
13410
|
+
throw new Error(`Failed to extract template: ${stderr}`);
|
|
13411
|
+
}
|
|
13412
|
+
const extractedDirs = await readdir(tempDir);
|
|
13413
|
+
const extractedDir = extractedDirs.find((d) => d.startsWith("ocx-"));
|
|
13414
|
+
if (!extractedDir) {
|
|
13415
|
+
throw new Error("Failed to find extracted template directory");
|
|
13416
|
+
}
|
|
13417
|
+
const templateDir = join4(tempDir, extractedDir, TEMPLATE_PATH);
|
|
13418
|
+
await copyDir(templateDir, destDir);
|
|
13419
|
+
} finally {
|
|
13420
|
+
await rm(tempDir, { recursive: true, force: true });
|
|
13421
|
+
}
|
|
13422
|
+
}
|
|
13423
|
+
async function replacePlaceholders(dir, values) {
|
|
13424
|
+
const filesToProcess = [
|
|
13425
|
+
"registry.json",
|
|
13426
|
+
"package.json",
|
|
13427
|
+
"wrangler.jsonc",
|
|
13428
|
+
"README.md",
|
|
13429
|
+
"AGENTS.md"
|
|
13430
|
+
];
|
|
13431
|
+
for (const file of filesToProcess) {
|
|
13432
|
+
const filePath = join4(dir, file);
|
|
13433
|
+
if (!existsSync2(filePath))
|
|
13434
|
+
continue;
|
|
13435
|
+
let content2 = await readFile(filePath).then((b) => b.toString());
|
|
13436
|
+
content2 = content2.replace(/my-registry/g, values.namespace);
|
|
13437
|
+
content2 = content2.replace(/Your Name/g, values.author);
|
|
13438
|
+
await writeFile2(filePath, content2);
|
|
13439
|
+
}
|
|
13440
|
+
}
|
|
13304
13441
|
|
|
13305
13442
|
// src/commands/registry.ts
|
|
13306
13443
|
function registerRegistryCommand(program2) {
|
|
13307
|
-
const
|
|
13308
|
-
|
|
13444
|
+
const registry = program2.command("registry").description("Manage registries");
|
|
13445
|
+
registry.command("add").description("Add a registry").argument("<url>", "Registry URL").option("--name <name>", "Registry alias (defaults to hostname)").option("--version <version>", "Pin to specific version").option("--cwd <path>", "Working directory", process.cwd()).option("--json", "Output as JSON", false).option("-q, --quiet", "Suppress output", false).action(async (url, options2) => {
|
|
13309
13446
|
try {
|
|
13310
|
-
const
|
|
13311
|
-
if (!
|
|
13447
|
+
const config = await readOcxConfig(options2.cwd);
|
|
13448
|
+
if (!config) {
|
|
13312
13449
|
logger.error("No ocx.jsonc found. Run 'ocx init' first.");
|
|
13313
13450
|
process.exit(1);
|
|
13314
13451
|
}
|
|
13315
|
-
if (
|
|
13452
|
+
if (config.lockRegistries) {
|
|
13316
13453
|
logger.error("Registries are locked. Cannot add.");
|
|
13317
13454
|
process.exit(1);
|
|
13318
13455
|
}
|
|
13319
13456
|
const name = options2.name || new URL(url).hostname.replace(/\./g, "-");
|
|
13320
|
-
if (
|
|
13457
|
+
if (config.registries[name]) {
|
|
13321
13458
|
logger.warn(`Registry '${name}' already exists. Use a different name.`);
|
|
13322
13459
|
return;
|
|
13323
13460
|
}
|
|
13324
|
-
|
|
13461
|
+
config.registries[name] = {
|
|
13325
13462
|
url,
|
|
13326
13463
|
version: options2.version
|
|
13327
13464
|
};
|
|
13328
|
-
await writeOcxConfig(options2.cwd,
|
|
13465
|
+
await writeOcxConfig(options2.cwd, config);
|
|
13329
13466
|
if (options2.json) {
|
|
13330
13467
|
outputJson({ success: true, data: { name, url } });
|
|
13331
13468
|
} else {
|
|
@@ -13335,23 +13472,23 @@ function registerRegistryCommand(program2) {
|
|
|
13335
13472
|
handleError(error);
|
|
13336
13473
|
}
|
|
13337
13474
|
});
|
|
13338
|
-
|
|
13475
|
+
registry.command("remove").description("Remove a registry").argument("<name>", "Registry name").option("--cwd <path>", "Working directory", process.cwd()).option("--json", "Output as JSON", false).option("-q, --quiet", "Suppress output", false).action(async (name, options2) => {
|
|
13339
13476
|
try {
|
|
13340
|
-
const
|
|
13341
|
-
if (!
|
|
13477
|
+
const config = await readOcxConfig(options2.cwd);
|
|
13478
|
+
if (!config) {
|
|
13342
13479
|
logger.error("No ocx.jsonc found. Run 'ocx init' first.");
|
|
13343
13480
|
process.exit(1);
|
|
13344
13481
|
}
|
|
13345
|
-
if (
|
|
13482
|
+
if (config.lockRegistries) {
|
|
13346
13483
|
logger.error("Registries are locked. Cannot remove.");
|
|
13347
13484
|
process.exit(1);
|
|
13348
13485
|
}
|
|
13349
|
-
if (!
|
|
13486
|
+
if (!config.registries[name]) {
|
|
13350
13487
|
logger.warn(`Registry '${name}' not found.`);
|
|
13351
13488
|
return;
|
|
13352
13489
|
}
|
|
13353
|
-
delete
|
|
13354
|
-
await writeOcxConfig(options2.cwd,
|
|
13490
|
+
delete config.registries[name];
|
|
13491
|
+
await writeOcxConfig(options2.cwd, config);
|
|
13355
13492
|
if (options2.json) {
|
|
13356
13493
|
outputJson({ success: true, data: { removed: name } });
|
|
13357
13494
|
} else {
|
|
@@ -13361,14 +13498,14 @@ function registerRegistryCommand(program2) {
|
|
|
13361
13498
|
handleError(error);
|
|
13362
13499
|
}
|
|
13363
13500
|
});
|
|
13364
|
-
|
|
13501
|
+
registry.command("list").description("List configured registries").option("--cwd <path>", "Working directory", process.cwd()).option("--json", "Output as JSON", false).option("-q, --quiet", "Suppress output", false).action(async (options2) => {
|
|
13365
13502
|
try {
|
|
13366
|
-
const
|
|
13367
|
-
if (!
|
|
13503
|
+
const config = await readOcxConfig(options2.cwd);
|
|
13504
|
+
if (!config) {
|
|
13368
13505
|
logger.warn("No ocx.jsonc found. Run 'ocx init' first.");
|
|
13369
13506
|
return;
|
|
13370
13507
|
}
|
|
13371
|
-
const registries = Object.entries(
|
|
13508
|
+
const registries = Object.entries(config.registries).map(([name, cfg]) => ({
|
|
13372
13509
|
name,
|
|
13373
13510
|
url: cfg.url,
|
|
13374
13511
|
version: cfg.version || "latest"
|
|
@@ -13378,14 +13515,14 @@ function registerRegistryCommand(program2) {
|
|
|
13378
13515
|
success: true,
|
|
13379
13516
|
data: {
|
|
13380
13517
|
registries,
|
|
13381
|
-
locked:
|
|
13518
|
+
locked: config.lockRegistries
|
|
13382
13519
|
}
|
|
13383
13520
|
});
|
|
13384
13521
|
} else {
|
|
13385
13522
|
if (registries.length === 0) {
|
|
13386
13523
|
logger.info("No registries configured.");
|
|
13387
13524
|
} else {
|
|
13388
|
-
logger.info(`Configured registries${
|
|
13525
|
+
logger.info(`Configured registries${config.lockRegistries ? kleur_default.yellow(" (locked)") : ""}:`);
|
|
13389
13526
|
for (const reg of registries) {
|
|
13390
13527
|
console.log(` ${kleur_default.cyan(reg.name)}: ${reg.url} ${kleur_default.dim(`(${reg.version})`)}`);
|
|
13391
13528
|
}
|
|
@@ -13429,13 +13566,13 @@ function registerSearchCommand(program2) {
|
|
|
13429
13566
|
}
|
|
13430
13567
|
return;
|
|
13431
13568
|
}
|
|
13432
|
-
const
|
|
13433
|
-
if (!
|
|
13569
|
+
const config = await readOcxConfig(options2.cwd);
|
|
13570
|
+
if (!config) {
|
|
13434
13571
|
logger.warn("No ocx.jsonc found. Run 'ocx init' first.");
|
|
13435
13572
|
return;
|
|
13436
13573
|
}
|
|
13437
13574
|
if (options2.verbose) {
|
|
13438
|
-
logger.info(`Searching in ${Object.keys(
|
|
13575
|
+
logger.info(`Searching in ${Object.keys(config.registries).length} registries...`);
|
|
13439
13576
|
}
|
|
13440
13577
|
const allComponents = [];
|
|
13441
13578
|
const spinner2 = createSpinner({
|
|
@@ -13445,7 +13582,7 @@ function registerSearchCommand(program2) {
|
|
|
13445
13582
|
if (!options2.json && !options2.verbose) {
|
|
13446
13583
|
spinner2.start();
|
|
13447
13584
|
}
|
|
13448
|
-
for (const [registryName, registryConfig] of Object.entries(
|
|
13585
|
+
for (const [registryName, registryConfig] of Object.entries(config.registries)) {
|
|
13449
13586
|
try {
|
|
13450
13587
|
if (options2.verbose) {
|
|
13451
13588
|
logger.info(`Fetching index from ${registryName} (${registryConfig.url})...`);
|
|
@@ -13498,9 +13635,8 @@ function registerSearchCommand(program2) {
|
|
|
13498
13635
|
}
|
|
13499
13636
|
});
|
|
13500
13637
|
}
|
|
13501
|
-
|
|
13502
13638
|
// src/index.ts
|
|
13503
|
-
var version = "1.0.
|
|
13639
|
+
var version = "1.0.14";
|
|
13504
13640
|
async function main2() {
|
|
13505
13641
|
const program2 = new Command().name("ocx").description("OpenCode Extensions - Install agents, skills, plugins, and commands").version(version);
|
|
13506
13642
|
registerInitCommand(program2);
|
|
@@ -13511,8 +13647,18 @@ async function main2() {
|
|
|
13511
13647
|
registerBuildCommand(program2);
|
|
13512
13648
|
await program2.parseAsync(process.argv);
|
|
13513
13649
|
}
|
|
13514
|
-
|
|
13515
|
-
|
|
13516
|
-
|
|
13650
|
+
if (import.meta.main) {
|
|
13651
|
+
main2().catch((err) => {
|
|
13652
|
+
handleError(err);
|
|
13653
|
+
});
|
|
13654
|
+
}
|
|
13655
|
+
export {
|
|
13656
|
+
registrySchema,
|
|
13657
|
+
packumentSchema,
|
|
13658
|
+
ocxLockSchema,
|
|
13659
|
+
ocxConfigSchema,
|
|
13660
|
+
componentManifestSchema,
|
|
13661
|
+
buildRegistry
|
|
13662
|
+
};
|
|
13517
13663
|
|
|
13518
|
-
//# debugId=
|
|
13664
|
+
//# debugId=8679B4448163A59C64756E2164756E21
|