ocx 1.4.3 → 1.4.4
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 +53 -121
- package/dist/index.js.map +6 -6
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -9924,8 +9924,9 @@ class ProfileNotFoundError extends OCXError {
|
|
|
9924
9924
|
|
|
9925
9925
|
class ProfileExistsError extends OCXError {
|
|
9926
9926
|
profile;
|
|
9927
|
-
constructor(profile) {
|
|
9928
|
-
|
|
9927
|
+
constructor(profile, hint) {
|
|
9928
|
+
const message = hint ? `Profile "${profile}" already exists. ${hint}` : `Profile "${profile}" already exists.`;
|
|
9929
|
+
super(message, "CONFLICT", EXIT_CODES.CONFLICT);
|
|
9929
9930
|
this.profile = profile;
|
|
9930
9931
|
this.name = "ProfileExistsError";
|
|
9931
9932
|
}
|
|
@@ -10366,8 +10367,16 @@ var installedComponentSchema = exports_external.object({
|
|
|
10366
10367
|
installedAt: exports_external.string(),
|
|
10367
10368
|
updatedAt: exports_external.string().optional()
|
|
10368
10369
|
});
|
|
10370
|
+
var installedFromSchema = exports_external.object({
|
|
10371
|
+
registry: exports_external.string(),
|
|
10372
|
+
component: exports_external.string(),
|
|
10373
|
+
version: exports_external.string().optional(),
|
|
10374
|
+
hash: exports_external.string(),
|
|
10375
|
+
installedAt: exports_external.string()
|
|
10376
|
+
});
|
|
10369
10377
|
var ocxLockSchema = exports_external.object({
|
|
10370
10378
|
lockVersion: exports_external.literal(1),
|
|
10379
|
+
installedFrom: installedFromSchema.optional(),
|
|
10371
10380
|
installed: exports_external.record(qualifiedComponentSchema, installedComponentSchema).default({})
|
|
10372
10381
|
});
|
|
10373
10382
|
var CONFIG_FILE = "ocx.jsonc";
|
|
@@ -11116,7 +11125,7 @@ class ConfigResolver {
|
|
|
11116
11125
|
// package.json
|
|
11117
11126
|
var package_default = {
|
|
11118
11127
|
name: "ocx",
|
|
11119
|
-
version: "1.4.
|
|
11128
|
+
version: "1.4.4",
|
|
11120
11129
|
description: "OCX CLI - ShadCN-style registry for OpenCode extensions. Install agents, plugins, skills, and MCP servers.",
|
|
11121
11130
|
author: "kdcokenny",
|
|
11122
11131
|
license: "MIT",
|
|
@@ -15805,7 +15814,7 @@ async function copyDir(src, dest) {
|
|
|
15805
15814
|
}
|
|
15806
15815
|
function getReleaseTag() {
|
|
15807
15816
|
if (false) {}
|
|
15808
|
-
return `v${"1.4.
|
|
15817
|
+
return `v${"1.4.4"}`;
|
|
15809
15818
|
}
|
|
15810
15819
|
function getTemplateUrl(version) {
|
|
15811
15820
|
const ref = version === "main" ? "heads/main" : `tags/${version}`;
|
|
@@ -16048,7 +16057,7 @@ function hashBundle2(files) {
|
|
|
16048
16057
|
`));
|
|
16049
16058
|
}
|
|
16050
16059
|
async function installProfileFromRegistry(options2) {
|
|
16051
|
-
const { namespace, component, profileName,
|
|
16060
|
+
const { namespace, component, profileName, registryUrl, registries, quiet } = options2;
|
|
16052
16061
|
const parseResult = profileNameSchema.safeParse(profileName);
|
|
16053
16062
|
if (!parseResult.success) {
|
|
16054
16063
|
throw new ValidationError(`Invalid profile name: "${profileName}". ` + `Profile names must start with a letter and contain only alphanumeric characters, dots, underscores, or hyphens.`);
|
|
@@ -16056,9 +16065,8 @@ async function installProfileFromRegistry(options2) {
|
|
|
16056
16065
|
const profileDir = getProfileDir(profileName);
|
|
16057
16066
|
const qualifiedName = `${namespace}/${component}`;
|
|
16058
16067
|
const profileExists = existsSync9(profileDir);
|
|
16059
|
-
if (profileExists
|
|
16060
|
-
throw new ConflictError(`Profile "${profileName}" already exists.
|
|
16061
|
-
Use --force to overwrite.`);
|
|
16068
|
+
if (profileExists) {
|
|
16069
|
+
throw new ConflictError(`Profile "${profileName}" already exists. Remove it first with 'ocx profile rm ${profileName}'.`);
|
|
16062
16070
|
}
|
|
16063
16071
|
const fetchSpin = quiet ? null : createSpinner({ text: `Fetching ${qualifiedName}...` });
|
|
16064
16072
|
fetchSpin?.start();
|
|
@@ -16100,46 +16108,10 @@ Use --force to overwrite.`);
|
|
|
16100
16108
|
}
|
|
16101
16109
|
}
|
|
16102
16110
|
filesSpin?.succeed(`Downloaded ${normalized.files.length} files`);
|
|
16103
|
-
let resolvedDeps = null;
|
|
16104
|
-
const dependencyBundles = [];
|
|
16105
|
-
if (manifest.dependencies.length > 0) {
|
|
16106
|
-
const depsSpin = quiet ? null : createSpinner({ text: "Resolving dependencies..." });
|
|
16107
|
-
depsSpin?.start();
|
|
16108
|
-
try {
|
|
16109
|
-
const depRefs = manifest.dependencies.map((dep) => dep.includes("/") ? dep : `${namespace}/${dep}`);
|
|
16110
|
-
resolvedDeps = await resolveDependencies(registries, depRefs);
|
|
16111
|
-
for (const depComponent of resolvedDeps.components) {
|
|
16112
|
-
const files = [];
|
|
16113
|
-
for (const file of depComponent.files) {
|
|
16114
|
-
const content2 = await fetchFileContent(depComponent.baseUrl, depComponent.name, file.path);
|
|
16115
|
-
const resolvedTarget = resolveTargetPath(file.target, true);
|
|
16116
|
-
files.push({
|
|
16117
|
-
path: file.path,
|
|
16118
|
-
target: resolvedTarget,
|
|
16119
|
-
content: Buffer.from(content2)
|
|
16120
|
-
});
|
|
16121
|
-
}
|
|
16122
|
-
const registryIndex = await fetchRegistryIndex(depComponent.baseUrl);
|
|
16123
|
-
dependencyBundles.push({
|
|
16124
|
-
qualifiedName: depComponent.qualifiedName,
|
|
16125
|
-
registryName: depComponent.registryName,
|
|
16126
|
-
files,
|
|
16127
|
-
hash: hashBundle2(files),
|
|
16128
|
-
version: registryIndex.version
|
|
16129
|
-
});
|
|
16130
|
-
}
|
|
16131
|
-
depsSpin?.succeed(`Resolved ${resolvedDeps.components.length} dependencies`);
|
|
16132
|
-
} catch (error) {
|
|
16133
|
-
depsSpin?.fail("Failed to resolve dependencies");
|
|
16134
|
-
throw error;
|
|
16135
|
-
}
|
|
16136
|
-
}
|
|
16137
16111
|
const profilesDir = getProfilesDir();
|
|
16138
16112
|
await mkdir8(profilesDir, { recursive: true, mode: 448 });
|
|
16139
16113
|
const stagingDir = await mkdtemp(join8(profilesDir, ".staging-"));
|
|
16140
|
-
const stagingOpencodeDir = join8(stagingDir, ".opencode");
|
|
16141
16114
|
try {
|
|
16142
|
-
await mkdir8(stagingOpencodeDir, { recursive: true, mode: 448 });
|
|
16143
16115
|
const writeSpin = quiet ? null : createSpinner({ text: "Writing profile files..." });
|
|
16144
16116
|
writeSpin?.start();
|
|
16145
16117
|
for (const file of profileFiles) {
|
|
@@ -16152,7 +16124,7 @@ Use --force to overwrite.`);
|
|
|
16152
16124
|
}
|
|
16153
16125
|
for (const file of embeddedFiles) {
|
|
16154
16126
|
const target = file.target.startsWith(".opencode/") ? file.target.slice(".opencode/".length) : file.target;
|
|
16155
|
-
const targetPath = join8(
|
|
16127
|
+
const targetPath = join8(stagingDir, target);
|
|
16156
16128
|
const targetDir = dirname4(targetPath);
|
|
16157
16129
|
if (!existsSync9(targetDir)) {
|
|
16158
16130
|
await mkdir8(targetDir, { recursive: true });
|
|
@@ -16160,27 +16132,10 @@ Use --force to overwrite.`);
|
|
|
16160
16132
|
await writeFile3(targetPath, file.content);
|
|
16161
16133
|
}
|
|
16162
16134
|
writeSpin?.succeed(`Wrote ${profileFiles.length + embeddedFiles.length} profile files`);
|
|
16163
|
-
if (dependencyBundles.length > 0) {
|
|
16164
|
-
const depWriteSpin = quiet ? null : createSpinner({ text: "Writing dependency files..." });
|
|
16165
|
-
depWriteSpin?.start();
|
|
16166
|
-
let depFileCount = 0;
|
|
16167
|
-
for (const bundle of dependencyBundles) {
|
|
16168
|
-
for (const file of bundle.files) {
|
|
16169
|
-
const targetPath = join8(stagingOpencodeDir, file.target);
|
|
16170
|
-
const targetDir = dirname4(targetPath);
|
|
16171
|
-
if (!existsSync9(targetDir)) {
|
|
16172
|
-
await mkdir8(targetDir, { recursive: true });
|
|
16173
|
-
}
|
|
16174
|
-
await writeFile3(targetPath, file.content);
|
|
16175
|
-
depFileCount++;
|
|
16176
|
-
}
|
|
16177
|
-
}
|
|
16178
|
-
depWriteSpin?.succeed(`Wrote ${depFileCount} dependency files`);
|
|
16179
|
-
}
|
|
16180
16135
|
const profileHash = hashBundle2(profileFiles.map((f) => ({ path: f.path, content: f.content })));
|
|
16181
16136
|
const registryIndex = await fetchRegistryIndex(registryUrl);
|
|
16182
16137
|
const lock = {
|
|
16183
|
-
|
|
16138
|
+
lockVersion: 1,
|
|
16184
16139
|
installedFrom: {
|
|
16185
16140
|
registry: namespace,
|
|
16186
16141
|
component,
|
|
@@ -16190,36 +16145,32 @@ Use --force to overwrite.`);
|
|
|
16190
16145
|
},
|
|
16191
16146
|
installed: {}
|
|
16192
16147
|
};
|
|
16193
|
-
|
|
16194
|
-
|
|
16195
|
-
|
|
16196
|
-
version: bundle.version,
|
|
16197
|
-
hash: bundle.hash,
|
|
16198
|
-
files: bundle.files.map((f) => f.target),
|
|
16199
|
-
installedAt: new Date().toISOString()
|
|
16200
|
-
};
|
|
16201
|
-
}
|
|
16202
|
-
await writeFile3(join8(stagingDir, "ocx.lock"), JSON.stringify(lock, null, "\t"));
|
|
16203
|
-
const moveSpin = quiet ? null : createSpinner({ text: "Finalizing installation..." });
|
|
16204
|
-
moveSpin?.start();
|
|
16148
|
+
await writeOcxLock(stagingDir, lock, join8(stagingDir, "ocx.lock"));
|
|
16149
|
+
const renameSpin = quiet ? null : createSpinner({ text: "Moving to profile directory..." });
|
|
16150
|
+
renameSpin?.start();
|
|
16205
16151
|
const profilesDir2 = dirname4(profileDir);
|
|
16206
16152
|
if (!existsSync9(profilesDir2)) {
|
|
16207
16153
|
await mkdir8(profilesDir2, { recursive: true, mode: 448 });
|
|
16208
16154
|
}
|
|
16209
|
-
|
|
16210
|
-
|
|
16211
|
-
|
|
16155
|
+
await rename3(stagingDir, profileDir);
|
|
16156
|
+
renameSpin?.succeed("Profile installed");
|
|
16157
|
+
if (manifest.dependencies.length > 0) {
|
|
16158
|
+
const depsSpin = quiet ? null : createSpinner({ text: "Installing dependencies..." });
|
|
16159
|
+
depsSpin?.start();
|
|
16212
16160
|
try {
|
|
16213
|
-
|
|
16214
|
-
|
|
16215
|
-
|
|
16216
|
-
|
|
16161
|
+
const depRefs = manifest.dependencies.map((dep) => dep.includes("/") ? dep : `${namespace}/${dep}`);
|
|
16162
|
+
const provider = {
|
|
16163
|
+
cwd: profileDir,
|
|
16164
|
+
getRegistries: () => registries,
|
|
16165
|
+
getComponentPath: () => ""
|
|
16166
|
+
};
|
|
16167
|
+
await runAddCore(depRefs, { profile: profileName }, provider);
|
|
16168
|
+
depsSpin?.succeed(`Installed ${manifest.dependencies.length} dependencies`);
|
|
16169
|
+
} catch (error) {
|
|
16170
|
+
depsSpin?.fail("Failed to install dependencies");
|
|
16171
|
+
throw error;
|
|
16217
16172
|
}
|
|
16218
|
-
await rm3(backupDir, { recursive: true, force: true });
|
|
16219
|
-
} else {
|
|
16220
|
-
await rename3(stagingDir, profileDir);
|
|
16221
16173
|
}
|
|
16222
|
-
moveSpin?.succeed("Installation complete");
|
|
16223
16174
|
if (!quiet) {
|
|
16224
16175
|
logger.info("");
|
|
16225
16176
|
logger.success(`Installed profile "${profileName}" from ${qualifiedName}`);
|
|
@@ -16228,12 +16179,9 @@ Use --force to overwrite.`);
|
|
|
16228
16179
|
for (const file of profileFiles) {
|
|
16229
16180
|
logger.info(` ${file.target}`);
|
|
16230
16181
|
}
|
|
16231
|
-
|
|
16232
|
-
|
|
16233
|
-
logger.info(
|
|
16234
|
-
for (const bundle of dependencyBundles) {
|
|
16235
|
-
logger.info(` ${bundle.qualifiedName}`);
|
|
16236
|
-
}
|
|
16182
|
+
for (const file of embeddedFiles) {
|
|
16183
|
+
const target = file.target.startsWith(".opencode/") ? file.target.slice(".opencode/".length) : file.target;
|
|
16184
|
+
logger.info(` ${target}`);
|
|
16237
16185
|
}
|
|
16238
16186
|
}
|
|
16239
16187
|
} catch (error) {
|
|
@@ -16252,9 +16200,6 @@ function parseFromOption(from) {
|
|
|
16252
16200
|
throw new ValidationError("--from value cannot be empty");
|
|
16253
16201
|
}
|
|
16254
16202
|
const trimmed = from.trim();
|
|
16255
|
-
if (trimmed.startsWith("./") || trimmed.startsWith("~/") || trimmed.startsWith("/")) {
|
|
16256
|
-
return { type: "local-path", path: trimmed };
|
|
16257
|
-
}
|
|
16258
16203
|
const slashCount = (trimmed.match(/\//g) || []).length;
|
|
16259
16204
|
if (slashCount === 1) {
|
|
16260
16205
|
const [namespace, component] = trimmed.split("/").map((s) => s.trim());
|
|
@@ -16302,12 +16247,11 @@ async function requireGlobalRegistry(namespace) {
|
|
|
16302
16247
|
return { config: globalConfig, registryUrl: registry.url };
|
|
16303
16248
|
}
|
|
16304
16249
|
function registerProfileAddCommand(parent) {
|
|
16305
|
-
parent.command("add <name>").description("Create a new profile, clone from existing, or install from registry").option("--from <source>", "Clone from existing profile or install from registry (e.g., kdco/minimal)").
|
|
16250
|
+
parent.command("add <name>").description("Create a new profile, clone from existing, or install from registry").option("--from <source>", "Clone from existing profile or install from registry (e.g., kdco/minimal)").addHelpText("after", `
|
|
16306
16251
|
Examples:
|
|
16307
16252
|
$ ocx profile add work # Create empty profile
|
|
16308
16253
|
$ ocx profile add work --from dev # Clone from existing profile
|
|
16309
16254
|
$ ocx profile add work --from kdco/minimal # Install from registry
|
|
16310
|
-
$ ocx profile add work --from kdco/minimal --force # Overwrite existing
|
|
16311
16255
|
`).action(async (name, options2) => {
|
|
16312
16256
|
try {
|
|
16313
16257
|
await runProfileAdd(name, options2);
|
|
@@ -16318,28 +16262,15 @@ Examples:
|
|
|
16318
16262
|
}
|
|
16319
16263
|
async function runProfileAdd(name, options2) {
|
|
16320
16264
|
const manager = await ProfileManager.requireInitialized();
|
|
16321
|
-
const profileExists = await manager.exists(name);
|
|
16322
|
-
if (profileExists && !options2.force) {
|
|
16323
|
-
logger.error(`\u2717 Profile "${name}" already exists`);
|
|
16324
|
-
logger.error("");
|
|
16325
|
-
logger.error("Use --force to overwrite the existing profile.");
|
|
16326
|
-
throw new ProfileExistsError(name);
|
|
16327
|
-
}
|
|
16328
16265
|
if (!options2.from) {
|
|
16329
|
-
await createEmptyProfile(manager, name
|
|
16266
|
+
await createEmptyProfile(manager, name);
|
|
16330
16267
|
return;
|
|
16331
16268
|
}
|
|
16332
16269
|
const fromInput = parseFromOption(options2.from);
|
|
16333
16270
|
switch (fromInput.type) {
|
|
16334
16271
|
case "local-profile":
|
|
16335
|
-
await cloneFromLocalProfile(manager, name, fromInput.name
|
|
16272
|
+
await cloneFromLocalProfile(manager, name, fromInput.name);
|
|
16336
16273
|
break;
|
|
16337
|
-
case "local-path":
|
|
16338
|
-
throw new ValidationError(`Local path installation is not yet implemented: "${fromInput.path}"
|
|
16339
|
-
|
|
16340
|
-
` + `Currently supported sources:
|
|
16341
|
-
` + ` - Existing profile: --from <profile-name>
|
|
16342
|
-
` + ` - Registry: --from <namespace>/<component>`);
|
|
16343
16274
|
case "registry": {
|
|
16344
16275
|
const { config: globalConfig, registryUrl } = await requireGlobalRegistry(fromInput.namespace);
|
|
16345
16276
|
const registries = {};
|
|
@@ -16350,7 +16281,6 @@ async function runProfileAdd(name, options2) {
|
|
|
16350
16281
|
namespace: fromInput.namespace,
|
|
16351
16282
|
component: fromInput.component,
|
|
16352
16283
|
profileName: name,
|
|
16353
|
-
force: options2.force,
|
|
16354
16284
|
registryUrl,
|
|
16355
16285
|
registries
|
|
16356
16286
|
});
|
|
@@ -16358,18 +16288,20 @@ async function runProfileAdd(name, options2) {
|
|
|
16358
16288
|
}
|
|
16359
16289
|
}
|
|
16360
16290
|
}
|
|
16361
|
-
async function createEmptyProfile(manager, name
|
|
16291
|
+
async function createEmptyProfile(manager, name) {
|
|
16292
|
+
const exists = await manager.exists(name);
|
|
16362
16293
|
if (exists) {
|
|
16363
|
-
|
|
16294
|
+
throw new ProfileExistsError(name, `Remove it first with 'ocx profile rm ${name}'.`);
|
|
16364
16295
|
}
|
|
16365
16296
|
await manager.add(name);
|
|
16366
16297
|
logger.success(`Created profile "${name}"`);
|
|
16367
16298
|
}
|
|
16368
|
-
async function cloneFromLocalProfile(manager, name, sourceName
|
|
16369
|
-
const
|
|
16299
|
+
async function cloneFromLocalProfile(manager, name, sourceName) {
|
|
16300
|
+
const exists = await manager.exists(name);
|
|
16370
16301
|
if (exists) {
|
|
16371
|
-
|
|
16302
|
+
throw new ProfileExistsError(name, `Remove it first with 'ocx profile rm ${name}'.`);
|
|
16372
16303
|
}
|
|
16304
|
+
const source = await manager.get(sourceName);
|
|
16373
16305
|
await manager.add(name);
|
|
16374
16306
|
await atomicWrite(getProfileOcxConfig(name), source.ocx);
|
|
16375
16307
|
logger.success(`Created profile "${name}" (cloned from "${sourceName}")`);
|
|
@@ -17270,7 +17202,7 @@ function registerSelfUninstallCommand(parent) {
|
|
|
17270
17202
|
|
|
17271
17203
|
// src/self-update/version-provider.ts
|
|
17272
17204
|
class BuildTimeVersionProvider {
|
|
17273
|
-
version = "1.4.
|
|
17205
|
+
version = "1.4.4";
|
|
17274
17206
|
}
|
|
17275
17207
|
var defaultVersionProvider = new BuildTimeVersionProvider;
|
|
17276
17208
|
|
|
@@ -17927,7 +17859,7 @@ function registerUpdateCheckHook(program2) {
|
|
|
17927
17859
|
});
|
|
17928
17860
|
}
|
|
17929
17861
|
// src/index.ts
|
|
17930
|
-
var version = "1.4.
|
|
17862
|
+
var version = "1.4.4";
|
|
17931
17863
|
async function main2() {
|
|
17932
17864
|
const program2 = new Command().name("ocx").description("OpenCode Extensions - Install agents, skills, plugins, and commands").version(version);
|
|
17933
17865
|
registerInitCommand(program2);
|
|
@@ -17959,4 +17891,4 @@ export {
|
|
|
17959
17891
|
buildRegistry
|
|
17960
17892
|
};
|
|
17961
17893
|
|
|
17962
|
-
//# debugId=
|
|
17894
|
+
//# debugId=C29AE4337E16008A64756E2164756E21
|