ocx 1.0.7 → 1.0.9
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 +187 -115
- package/dist/index.js.map +11 -11
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -13026,9 +13026,102 @@ var coerce = {
|
|
|
13026
13026
|
date: (arg) => ZodDate.create({ ...arg, coerce: true })
|
|
13027
13027
|
};
|
|
13028
13028
|
var NEVER = INVALID;
|
|
13029
|
+
// src/utils/errors.ts
|
|
13030
|
+
var EXIT_CODES = {
|
|
13031
|
+
SUCCESS: 0,
|
|
13032
|
+
GENERAL: 1,
|
|
13033
|
+
NOT_FOUND: 66,
|
|
13034
|
+
NETWORK: 69,
|
|
13035
|
+
CONFIG: 78,
|
|
13036
|
+
INTEGRITY: 1
|
|
13037
|
+
};
|
|
13038
|
+
|
|
13039
|
+
class OCXError extends Error {
|
|
13040
|
+
code;
|
|
13041
|
+
exitCode;
|
|
13042
|
+
constructor(message, code, exitCode = EXIT_CODES.GENERAL) {
|
|
13043
|
+
super(message);
|
|
13044
|
+
this.code = code;
|
|
13045
|
+
this.exitCode = exitCode;
|
|
13046
|
+
this.name = "OCXError";
|
|
13047
|
+
}
|
|
13048
|
+
}
|
|
13049
|
+
|
|
13050
|
+
class NotFoundError extends OCXError {
|
|
13051
|
+
constructor(message) {
|
|
13052
|
+
super(message, "NOT_FOUND", EXIT_CODES.NOT_FOUND);
|
|
13053
|
+
this.name = "NotFoundError";
|
|
13054
|
+
}
|
|
13055
|
+
}
|
|
13056
|
+
|
|
13057
|
+
class NetworkError extends OCXError {
|
|
13058
|
+
constructor(message) {
|
|
13059
|
+
super(message, "NETWORK_ERROR", EXIT_CODES.NETWORK);
|
|
13060
|
+
this.name = "NetworkError";
|
|
13061
|
+
}
|
|
13062
|
+
}
|
|
13063
|
+
|
|
13064
|
+
class ConfigError extends OCXError {
|
|
13065
|
+
constructor(message) {
|
|
13066
|
+
super(message, "CONFIG_ERROR", EXIT_CODES.CONFIG);
|
|
13067
|
+
this.name = "ConfigError";
|
|
13068
|
+
}
|
|
13069
|
+
}
|
|
13070
|
+
|
|
13071
|
+
class ValidationError extends OCXError {
|
|
13072
|
+
constructor(message) {
|
|
13073
|
+
super(message, "VALIDATION_ERROR", EXIT_CODES.GENERAL);
|
|
13074
|
+
this.name = "ValidationError";
|
|
13075
|
+
}
|
|
13076
|
+
}
|
|
13077
|
+
|
|
13078
|
+
class ConflictError extends OCXError {
|
|
13079
|
+
constructor(message) {
|
|
13080
|
+
super(message, "CONFLICT", EXIT_CODES.GENERAL);
|
|
13081
|
+
this.name = "ConflictError";
|
|
13082
|
+
}
|
|
13083
|
+
}
|
|
13084
|
+
|
|
13085
|
+
class IntegrityError extends OCXError {
|
|
13086
|
+
constructor(component, expected, found) {
|
|
13087
|
+
const message = `Integrity verification failed for "${component}"
|
|
13088
|
+
` + ` Expected: ${expected}
|
|
13089
|
+
` + ` Found: ${found}
|
|
13090
|
+
|
|
13091
|
+
` + `The registry content has changed since this component was locked.
|
|
13092
|
+
` + `This could indicate tampering or an unauthorized update.`;
|
|
13093
|
+
super(message, "INTEGRITY_ERROR", EXIT_CODES.INTEGRITY);
|
|
13094
|
+
this.name = "IntegrityError";
|
|
13095
|
+
}
|
|
13096
|
+
}
|
|
13097
|
+
|
|
13029
13098
|
// src/schemas/registry.ts
|
|
13030
13099
|
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]+)*$/, {
|
|
13031
|
-
message: "Must be lowercase alphanumeric with single hyphen separators (e.g., 'my-component', '
|
|
13100
|
+
message: "Must be lowercase alphanumeric with single hyphen separators (e.g., 'my-component', 'my-plugin'). Cannot start/end with hyphen or have consecutive hyphens."
|
|
13101
|
+
});
|
|
13102
|
+
var namespaceSchema = openCodeNameSchema;
|
|
13103
|
+
var qualifiedComponentSchema = exports_external.string().regex(/^[a-z0-9]+(-[a-z0-9]+)*\/[a-z0-9]+(-[a-z0-9]+)*$/, {
|
|
13104
|
+
message: 'Must be in format "namespace/component" (e.g., "kdco/librarian"). Both parts must be lowercase alphanumeric with hyphens.'
|
|
13105
|
+
});
|
|
13106
|
+
function parseQualifiedComponent(ref) {
|
|
13107
|
+
if (!ref.includes("/")) {
|
|
13108
|
+
throw new ValidationError(`Invalid component reference: "${ref}". Use format: namespace/component`);
|
|
13109
|
+
}
|
|
13110
|
+
const [namespace, component] = ref.split("/");
|
|
13111
|
+
if (!namespace || !component) {
|
|
13112
|
+
throw new ValidationError(`Invalid component reference: "${ref}". Both namespace and component are required.`);
|
|
13113
|
+
}
|
|
13114
|
+
return { namespace, component };
|
|
13115
|
+
}
|
|
13116
|
+
function createQualifiedComponent(namespace, component) {
|
|
13117
|
+
return `${namespace}/${component}`;
|
|
13118
|
+
}
|
|
13119
|
+
var dependencyRefSchema = exports_external.string().refine((dep) => {
|
|
13120
|
+
const barePattern = /^[a-z0-9]+(-[a-z0-9]+)*$/;
|
|
13121
|
+
const qualifiedPattern = /^[a-z0-9]+(-[a-z0-9]+)*\/[a-z0-9]+(-[a-z0-9]+)*$/;
|
|
13122
|
+
return barePattern.test(dep) || qualifiedPattern.test(dep);
|
|
13123
|
+
}, {
|
|
13124
|
+
message: 'Dependency must be either a bare name (e.g., "utils") or qualified (e.g., "acme/utils")'
|
|
13032
13125
|
});
|
|
13033
13126
|
var componentTypeSchema = exports_external.enum([
|
|
13034
13127
|
"ocx:agent",
|
|
@@ -13072,7 +13165,7 @@ var mcpServerObjectSchema = exports_external.object({
|
|
|
13072
13165
|
}, {
|
|
13073
13166
|
message: "Remote MCP servers require 'url', local servers require 'command'"
|
|
13074
13167
|
});
|
|
13075
|
-
var
|
|
13168
|
+
var mcpServerRefSchema = exports_external.union([exports_external.string().url(), mcpServerObjectSchema]);
|
|
13076
13169
|
var componentFileObjectSchema = exports_external.object({
|
|
13077
13170
|
path: exports_external.string().min(1, "File path cannot be empty"),
|
|
13078
13171
|
target: targetPathSchema
|
|
@@ -13098,10 +13191,10 @@ var componentManifestSchema = exports_external.object({
|
|
|
13098
13191
|
type: componentTypeSchema,
|
|
13099
13192
|
description: exports_external.string().min(1).max(1024),
|
|
13100
13193
|
files: exports_external.array(componentFileSchema),
|
|
13101
|
-
dependencies: exports_external.array(
|
|
13194
|
+
dependencies: exports_external.array(dependencyRefSchema).default([]),
|
|
13102
13195
|
npmDependencies: exports_external.array(exports_external.string()).optional(),
|
|
13103
13196
|
npmDevDependencies: exports_external.array(exports_external.string()).optional(),
|
|
13104
|
-
mcpServers: exports_external.record(
|
|
13197
|
+
mcpServers: exports_external.record(mcpServerRefSchema).optional(),
|
|
13105
13198
|
mcpScope: exports_external.enum(["agent", "global"]).default("agent"),
|
|
13106
13199
|
opencode: opencodeConfigSchema.optional(),
|
|
13107
13200
|
disabledTools: exports_external.array(exports_external.string()).optional()
|
|
@@ -13141,28 +13234,24 @@ function normalizeComponentManifest(manifest) {
|
|
|
13141
13234
|
var semverRegex = /^\d+\.\d+\.\d+(-[a-zA-Z0-9.-]+)?(\+[a-zA-Z0-9.-]+)?$/;
|
|
13142
13235
|
var registrySchema = exports_external.object({
|
|
13143
13236
|
name: exports_external.string().min(1, "Registry name cannot be empty"),
|
|
13144
|
-
|
|
13237
|
+
namespace: namespaceSchema,
|
|
13145
13238
|
version: exports_external.string().regex(semverRegex, {
|
|
13146
13239
|
message: "Version must be valid semver (e.g., '1.0.0', '2.1.0-beta.1')"
|
|
13147
13240
|
}),
|
|
13148
13241
|
author: exports_external.string().min(1, "Author cannot be empty"),
|
|
13149
13242
|
components: exports_external.array(componentManifestSchema)
|
|
13150
|
-
}).refine((data) => {
|
|
13151
|
-
return data.components.every((c2) => c2.name.startsWith(`${data.prefix}-`));
|
|
13152
|
-
}, {
|
|
13153
|
-
message: "All component names must start with the registry prefix"
|
|
13154
13243
|
}).refine((data) => {
|
|
13155
13244
|
const componentNames = new Set(data.components.map((c2) => c2.name));
|
|
13156
13245
|
for (const component of data.components) {
|
|
13157
13246
|
for (const dep of component.dependencies) {
|
|
13158
|
-
if (!componentNames.has(dep)) {
|
|
13247
|
+
if (!dep.includes("/") && !componentNames.has(dep)) {
|
|
13159
13248
|
return false;
|
|
13160
13249
|
}
|
|
13161
13250
|
}
|
|
13162
13251
|
}
|
|
13163
13252
|
return true;
|
|
13164
13253
|
}, {
|
|
13165
|
-
message: "
|
|
13254
|
+
message: "Bare dependencies must reference components that exist in the registry. Use qualified references (e.g., 'other-registry/component') for cross-namespace dependencies."
|
|
13166
13255
|
});
|
|
13167
13256
|
var packumentSchema = exports_external.object({
|
|
13168
13257
|
name: openCodeNameSchema,
|
|
@@ -13173,7 +13262,7 @@ var packumentSchema = exports_external.object({
|
|
|
13173
13262
|
});
|
|
13174
13263
|
var registryIndexSchema = exports_external.object({
|
|
13175
13264
|
name: exports_external.string(),
|
|
13176
|
-
|
|
13265
|
+
namespace: namespaceSchema,
|
|
13177
13266
|
version: exports_external.string(),
|
|
13178
13267
|
author: exports_external.string(),
|
|
13179
13268
|
components: exports_external.array(exports_external.object({
|
|
@@ -13183,67 +13272,6 @@ var registryIndexSchema = exports_external.object({
|
|
|
13183
13272
|
}))
|
|
13184
13273
|
});
|
|
13185
13274
|
|
|
13186
|
-
// src/utils/errors.ts
|
|
13187
|
-
var EXIT_CODES = {
|
|
13188
|
-
SUCCESS: 0,
|
|
13189
|
-
GENERAL: 1,
|
|
13190
|
-
NOT_FOUND: 66,
|
|
13191
|
-
NETWORK: 69,
|
|
13192
|
-
CONFIG: 78,
|
|
13193
|
-
INTEGRITY: 1
|
|
13194
|
-
};
|
|
13195
|
-
|
|
13196
|
-
class OCXError extends Error {
|
|
13197
|
-
code;
|
|
13198
|
-
exitCode;
|
|
13199
|
-
constructor(message, code, exitCode = EXIT_CODES.GENERAL) {
|
|
13200
|
-
super(message);
|
|
13201
|
-
this.code = code;
|
|
13202
|
-
this.exitCode = exitCode;
|
|
13203
|
-
this.name = "OCXError";
|
|
13204
|
-
}
|
|
13205
|
-
}
|
|
13206
|
-
|
|
13207
|
-
class NotFoundError extends OCXError {
|
|
13208
|
-
constructor(message) {
|
|
13209
|
-
super(message, "NOT_FOUND", EXIT_CODES.NOT_FOUND);
|
|
13210
|
-
this.name = "NotFoundError";
|
|
13211
|
-
}
|
|
13212
|
-
}
|
|
13213
|
-
|
|
13214
|
-
class NetworkError extends OCXError {
|
|
13215
|
-
constructor(message) {
|
|
13216
|
-
super(message, "NETWORK_ERROR", EXIT_CODES.NETWORK);
|
|
13217
|
-
this.name = "NetworkError";
|
|
13218
|
-
}
|
|
13219
|
-
}
|
|
13220
|
-
|
|
13221
|
-
class ConfigError extends OCXError {
|
|
13222
|
-
constructor(message) {
|
|
13223
|
-
super(message, "CONFIG_ERROR", EXIT_CODES.CONFIG);
|
|
13224
|
-
this.name = "ConfigError";
|
|
13225
|
-
}
|
|
13226
|
-
}
|
|
13227
|
-
|
|
13228
|
-
class ValidationError extends OCXError {
|
|
13229
|
-
constructor(message) {
|
|
13230
|
-
super(message, "VALIDATION_ERROR", EXIT_CODES.GENERAL);
|
|
13231
|
-
this.name = "ValidationError";
|
|
13232
|
-
}
|
|
13233
|
-
}
|
|
13234
|
-
class IntegrityError extends OCXError {
|
|
13235
|
-
constructor(component, expected, found) {
|
|
13236
|
-
const message = `Integrity verification failed for "${component}"
|
|
13237
|
-
` + ` Expected: ${expected}
|
|
13238
|
-
` + ` Found: ${found}
|
|
13239
|
-
|
|
13240
|
-
` + `The registry content has changed since this component was locked.
|
|
13241
|
-
` + `This could indicate tampering or an unauthorized update.`;
|
|
13242
|
-
super(message, "INTEGRITY_ERROR", EXIT_CODES.INTEGRITY);
|
|
13243
|
-
this.name = "IntegrityError";
|
|
13244
|
-
}
|
|
13245
|
-
}
|
|
13246
|
-
|
|
13247
13275
|
// src/registry/fetcher.ts
|
|
13248
13276
|
var cache = new Map;
|
|
13249
13277
|
async function fetchWithCache(url, parse) {
|
|
@@ -13348,6 +13376,15 @@ function r2(e4, n3) {
|
|
|
13348
13376
|
}
|
|
13349
13377
|
|
|
13350
13378
|
// src/registry/resolver.ts
|
|
13379
|
+
function parseComponentRef(ref, defaultNamespace) {
|
|
13380
|
+
if (ref.includes("/")) {
|
|
13381
|
+
return parseQualifiedComponent(ref);
|
|
13382
|
+
}
|
|
13383
|
+
if (defaultNamespace) {
|
|
13384
|
+
return { namespace: defaultNamespace, component: ref };
|
|
13385
|
+
}
|
|
13386
|
+
throw new ValidationError(`Component '${ref}' must include a namespace (e.g., 'kdco/${ref}')`);
|
|
13387
|
+
}
|
|
13351
13388
|
async function resolveDependencies(registries, componentNames) {
|
|
13352
13389
|
const resolved = new Map;
|
|
13353
13390
|
const visiting = new Set;
|
|
@@ -13359,39 +13396,39 @@ async function resolveDependencies(registries, componentNames) {
|
|
|
13359
13396
|
const plugins = new Set;
|
|
13360
13397
|
const agentConfigs = {};
|
|
13361
13398
|
const instructionsSet = new Set;
|
|
13362
|
-
async function resolve2(
|
|
13363
|
-
|
|
13399
|
+
async function resolve2(componentNamespace, componentName, path3 = []) {
|
|
13400
|
+
const qualifiedName = createQualifiedComponent(componentNamespace, componentName);
|
|
13401
|
+
if (resolved.has(qualifiedName)) {
|
|
13364
13402
|
return;
|
|
13365
13403
|
}
|
|
13366
|
-
if (visiting.has(
|
|
13367
|
-
const cycle = [...path3,
|
|
13404
|
+
if (visiting.has(qualifiedName)) {
|
|
13405
|
+
const cycle = [...path3, qualifiedName].join(" \u2192 ");
|
|
13368
13406
|
throw new ValidationError(`Circular dependency detected: ${cycle}`);
|
|
13369
13407
|
}
|
|
13370
|
-
visiting.add(
|
|
13371
|
-
|
|
13372
|
-
|
|
13373
|
-
|
|
13374
|
-
for (const [regName, regConfig] of registryEntries) {
|
|
13375
|
-
try {
|
|
13376
|
-
const manifest = await fetchComponent(regConfig.url, name);
|
|
13377
|
-
component = manifest;
|
|
13378
|
-
foundRegistry = { name: regName, url: regConfig.url };
|
|
13379
|
-
break;
|
|
13380
|
-
} catch (_err) {}
|
|
13408
|
+
visiting.add(qualifiedName);
|
|
13409
|
+
const regConfig = registries[componentNamespace];
|
|
13410
|
+
if (!regConfig) {
|
|
13411
|
+
throw new ConfigError(`Registry '${componentNamespace}' not configured. Add it to ocx.jsonc registries.`);
|
|
13381
13412
|
}
|
|
13382
|
-
|
|
13383
|
-
|
|
13413
|
+
let component;
|
|
13414
|
+
try {
|
|
13415
|
+
component = await fetchComponent(regConfig.url, componentName);
|
|
13416
|
+
} catch (_err) {
|
|
13417
|
+
throw new OCXError(`Component '${componentName}' not found in registry '${componentNamespace}'.`, "NOT_FOUND");
|
|
13384
13418
|
}
|
|
13385
13419
|
for (const dep of component.dependencies) {
|
|
13386
|
-
|
|
13420
|
+
const depRef = parseComponentRef(dep, componentNamespace);
|
|
13421
|
+
await resolve2(depRef.namespace, depRef.component, [...path3, qualifiedName]);
|
|
13387
13422
|
}
|
|
13388
13423
|
const normalizedComponent = normalizeComponentManifest(component);
|
|
13389
|
-
resolved.set(
|
|
13424
|
+
resolved.set(qualifiedName, {
|
|
13390
13425
|
...normalizedComponent,
|
|
13391
|
-
|
|
13392
|
-
|
|
13426
|
+
namespace: componentNamespace,
|
|
13427
|
+
registryName: componentNamespace,
|
|
13428
|
+
baseUrl: regConfig.url,
|
|
13429
|
+
qualifiedName
|
|
13393
13430
|
});
|
|
13394
|
-
visiting.delete(
|
|
13431
|
+
visiting.delete(qualifiedName);
|
|
13395
13432
|
if (normalizedComponent.mcpServers) {
|
|
13396
13433
|
const serverNames = [];
|
|
13397
13434
|
for (const [serverName, config2] of Object.entries(normalizedComponent.mcpServers)) {
|
|
@@ -13447,7 +13484,8 @@ async function resolveDependencies(registries, componentNames) {
|
|
|
13447
13484
|
}
|
|
13448
13485
|
}
|
|
13449
13486
|
for (const name of componentNames) {
|
|
13450
|
-
|
|
13487
|
+
const ref = parseComponentRef(name);
|
|
13488
|
+
await resolve2(ref.namespace, ref.component);
|
|
13451
13489
|
}
|
|
13452
13490
|
const components = Array.from(resolved.values());
|
|
13453
13491
|
const installOrder = Array.from(resolved.keys());
|
|
@@ -14803,14 +14841,15 @@ var installedComponentSchema = exports_external.object({
|
|
|
14803
14841
|
registry: exports_external.string(),
|
|
14804
14842
|
version: exports_external.string(),
|
|
14805
14843
|
hash: exports_external.string(),
|
|
14806
|
-
|
|
14807
|
-
installedAt: exports_external.string()
|
|
14844
|
+
files: exports_external.array(exports_external.string()),
|
|
14845
|
+
installedAt: exports_external.string(),
|
|
14846
|
+
alias: exports_external.string().optional()
|
|
14808
14847
|
});
|
|
14809
14848
|
var ocxLockSchema = exports_external.object({
|
|
14810
14849
|
lockVersion: exports_external.literal(1),
|
|
14811
|
-
installed: exports_external.record(installedComponentSchema).default({})
|
|
14850
|
+
installed: exports_external.record(qualifiedComponentSchema, installedComponentSchema).default({})
|
|
14812
14851
|
});
|
|
14813
|
-
var opencodeMcpSchema = exports_external.record(
|
|
14852
|
+
var opencodeMcpSchema = exports_external.record(mcpServerRefSchema);
|
|
14814
14853
|
var opencodeAgentSchema = exports_external.object({
|
|
14815
14854
|
disable: exports_external.boolean().optional(),
|
|
14816
14855
|
tools: exports_external.record(exports_external.boolean()).optional(),
|
|
@@ -14906,12 +14945,21 @@ function applyMcpServers(content, config2, mcpServers) {
|
|
|
14906
14945
|
if (server.type === "local" && server.command) {
|
|
14907
14946
|
serverConfig.command = server.command;
|
|
14908
14947
|
}
|
|
14948
|
+
if (server.args) {
|
|
14949
|
+
serverConfig.args = server.args;
|
|
14950
|
+
}
|
|
14909
14951
|
if (server.headers) {
|
|
14910
14952
|
serverConfig.headers = server.headers;
|
|
14911
14953
|
}
|
|
14954
|
+
if (server.oauth !== undefined) {
|
|
14955
|
+
serverConfig.oauth = server.oauth;
|
|
14956
|
+
}
|
|
14912
14957
|
if (server.enabled !== undefined) {
|
|
14913
14958
|
serverConfig.enabled = server.enabled;
|
|
14914
14959
|
}
|
|
14960
|
+
if (server.environment) {
|
|
14961
|
+
serverConfig.environment = server.environment;
|
|
14962
|
+
}
|
|
14915
14963
|
const edits = modify(updatedContent, ["mcp", name], serverConfig, JSONC_OPTIONS);
|
|
14916
14964
|
updatedContent = applyEdits(updatedContent, edits);
|
|
14917
14965
|
added.push(name);
|
|
@@ -16667,17 +16715,31 @@ async function runAdd(componentNames, options3) {
|
|
|
16667
16715
|
files.push({ path: file.path, content: Buffer.from(content) });
|
|
16668
16716
|
}
|
|
16669
16717
|
const computedHash = await hashBundle(files);
|
|
16670
|
-
const existingEntry = lock.installed[component.
|
|
16718
|
+
const existingEntry = lock.installed[component.qualifiedName];
|
|
16671
16719
|
if (existingEntry && existingEntry.hash !== computedHash) {
|
|
16672
|
-
throw new IntegrityError(component.
|
|
16720
|
+
throw new IntegrityError(component.qualifiedName, existingEntry.hash, computedHash);
|
|
16721
|
+
}
|
|
16722
|
+
for (const file of component.files) {
|
|
16723
|
+
const targetPath = join2(cwd, file.target);
|
|
16724
|
+
if (existsSync2(targetPath)) {
|
|
16725
|
+
const conflictingComponent = findComponentByFile(lock, file.target);
|
|
16726
|
+
if (conflictingComponent && conflictingComponent !== component.qualifiedName) {
|
|
16727
|
+
throw new ConflictError(`File conflict: ${file.target} already exists (installed by '${conflictingComponent}').
|
|
16728
|
+
|
|
16729
|
+
` + `To resolve:
|
|
16730
|
+
` + ` 1. Remove existing: rm ${file.target}
|
|
16731
|
+
` + ` 2. Or rename it manually and update references
|
|
16732
|
+
` + ` 3. Then run: ocx add ${component.qualifiedName}`);
|
|
16733
|
+
}
|
|
16734
|
+
}
|
|
16673
16735
|
}
|
|
16674
16736
|
await installComponent(component, files, cwd);
|
|
16675
16737
|
const index = await fetchRegistryIndex(component.baseUrl);
|
|
16676
|
-
lock.installed[component.
|
|
16738
|
+
lock.installed[component.qualifiedName] = {
|
|
16677
16739
|
registry: component.registryName,
|
|
16678
16740
|
version: index.version,
|
|
16679
16741
|
hash: computedHash,
|
|
16680
|
-
|
|
16742
|
+
files: component.files.map((f2) => f2.target),
|
|
16681
16743
|
installedAt: new Date().toISOString()
|
|
16682
16744
|
};
|
|
16683
16745
|
}
|
|
@@ -16763,10 +16825,6 @@ async function installComponent(component, files, cwd) {
|
|
|
16763
16825
|
await writeFile(targetPath, file.content);
|
|
16764
16826
|
}
|
|
16765
16827
|
}
|
|
16766
|
-
function getTargetPath(component) {
|
|
16767
|
-
const typeDir = component.type.replace(/^ocx:/, "");
|
|
16768
|
-
return component.files[0]?.target ?? `.opencode/${typeDir}/${component.name}`;
|
|
16769
|
-
}
|
|
16770
16828
|
async function hashContent(content) {
|
|
16771
16829
|
return createHash("sha256").update(content).digest("hex");
|
|
16772
16830
|
}
|
|
@@ -16822,6 +16880,14 @@ async function installNpmDependencies(dependencies, devDependencies, cwd, option
|
|
|
16822
16880
|
await run(parseNi, [...devDependencies, "-D"], { cwd });
|
|
16823
16881
|
}
|
|
16824
16882
|
}
|
|
16883
|
+
function findComponentByFile(lock, filePath) {
|
|
16884
|
+
for (const [qualifiedName, entry] of Object.entries(lock.installed)) {
|
|
16885
|
+
if (entry.files.includes(filePath)) {
|
|
16886
|
+
return qualifiedName;
|
|
16887
|
+
}
|
|
16888
|
+
}
|
|
16889
|
+
return null;
|
|
16890
|
+
}
|
|
16825
16891
|
|
|
16826
16892
|
// src/commands/build.ts
|
|
16827
16893
|
import { mkdir as mkdir2 } from "fs/promises";
|
|
@@ -16896,7 +16962,7 @@ function registerBuildCommand(program2) {
|
|
|
16896
16962
|
}
|
|
16897
16963
|
const index = {
|
|
16898
16964
|
name: registry.name,
|
|
16899
|
-
|
|
16965
|
+
namespace: registry.namespace,
|
|
16900
16966
|
version: registry.version,
|
|
16901
16967
|
author: registry.author,
|
|
16902
16968
|
components: registry.components.map((c2) => ({
|
|
@@ -17764,7 +17830,11 @@ function registerDiffCommand(program2) {
|
|
|
17764
17830
|
}
|
|
17765
17831
|
continue;
|
|
17766
17832
|
}
|
|
17767
|
-
|
|
17833
|
+
if (!installed.files || installed.files.length === 0) {
|
|
17834
|
+
logger.warn(`No files recorded for component '${name}'`);
|
|
17835
|
+
continue;
|
|
17836
|
+
}
|
|
17837
|
+
const localPath = `${options3.cwd}/${installed.files[0]}`;
|
|
17768
17838
|
const localFile = Bun.file(localPath);
|
|
17769
17839
|
if (!await localFile.exists()) {
|
|
17770
17840
|
results.push({ name, hasChanges: true, diff: "Local file missing" });
|
|
@@ -17777,14 +17847,16 @@ function registerDiffCommand(program2) {
|
|
|
17777
17847
|
continue;
|
|
17778
17848
|
}
|
|
17779
17849
|
try {
|
|
17780
|
-
const
|
|
17850
|
+
const parsed = parseQualifiedComponent(name);
|
|
17851
|
+
const componentName = parsed.component;
|
|
17852
|
+
const upstream = await fetchComponent(registryConfig.url, componentName);
|
|
17781
17853
|
const rawUpstreamFile = upstream.files[0];
|
|
17782
17854
|
if (!rawUpstreamFile) {
|
|
17783
17855
|
results.push({ name, hasChanges: false });
|
|
17784
17856
|
continue;
|
|
17785
17857
|
}
|
|
17786
17858
|
const upstreamFile = normalizeFile(rawUpstreamFile);
|
|
17787
|
-
const upstreamContent = await fetchFileContent(registryConfig.url,
|
|
17859
|
+
const upstreamContent = await fetchFileContent(registryConfig.url, componentName, upstreamFile.path);
|
|
17788
17860
|
if (localContent === upstreamContent) {
|
|
17789
17861
|
results.push({ name, hasChanges: false });
|
|
17790
17862
|
} else {
|
|
@@ -18032,7 +18104,7 @@ function registerSearchCommand(program2) {
|
|
|
18032
18104
|
}
|
|
18033
18105
|
for (const comp of index.components) {
|
|
18034
18106
|
allComponents.push({
|
|
18035
|
-
name: comp.name
|
|
18107
|
+
name: `${index.namespace}/${comp.name}`,
|
|
18036
18108
|
description: comp.description,
|
|
18037
18109
|
type: comp.type,
|
|
18038
18110
|
registry: registryName
|
|
@@ -18076,7 +18148,7 @@ function registerSearchCommand(program2) {
|
|
|
18076
18148
|
}
|
|
18077
18149
|
|
|
18078
18150
|
// src/index.ts
|
|
18079
|
-
var version2 = "1.0.
|
|
18151
|
+
var version2 = "1.0.9";
|
|
18080
18152
|
async function main2() {
|
|
18081
18153
|
const program2 = new Command().name("ocx").description("OpenCode Extensions - Install agents, skills, plugins, and commands").version(version2);
|
|
18082
18154
|
registerInitCommand(program2);
|
|
@@ -18091,4 +18163,4 @@ main2().catch((err) => {
|
|
|
18091
18163
|
handleError(err);
|
|
18092
18164
|
});
|
|
18093
18165
|
|
|
18094
|
-
//# debugId=
|
|
18166
|
+
//# debugId=8F8057E520B12DC364756E2164756E21
|