ocx 1.0.6 → 1.0.8

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 CHANGED
@@ -4533,32 +4533,32 @@ var require_fuzzysort = __commonJS((exports, module) => {
4533
4533
  noResults.total = 0;
4534
4534
  var NULL = null;
4535
4535
  var noTarget = prepare("");
4536
- var fastpriorityqueue = (r2) => {
4537
- var e2 = [], o2 = 0, a3 = {}, v2 = (r3) => {
4538
- for (var a4 = 0, v3 = e2[a4], c2 = 1;c2 < o2; ) {
4536
+ var fastpriorityqueue = (r3) => {
4537
+ var e4 = [], o2 = 0, a3 = {}, v2 = (r4) => {
4538
+ for (var a4 = 0, v3 = e4[a4], c2 = 1;c2 < o2; ) {
4539
4539
  var s2 = c2 + 1;
4540
- a4 = c2, s2 < o2 && e2[s2]._score < e2[c2]._score && (a4 = s2), e2[a4 - 1 >> 1] = e2[a4], c2 = 1 + (a4 << 1);
4540
+ a4 = c2, s2 < o2 && e4[s2]._score < e4[c2]._score && (a4 = s2), e4[a4 - 1 >> 1] = e4[a4], c2 = 1 + (a4 << 1);
4541
4541
  }
4542
- for (var f2 = a4 - 1 >> 1;a4 > 0 && v3._score < e2[f2]._score; f2 = (a4 = f2) - 1 >> 1)
4543
- e2[a4] = e2[f2];
4544
- e2[a4] = v3;
4542
+ for (var f2 = a4 - 1 >> 1;a4 > 0 && v3._score < e4[f2]._score; f2 = (a4 = f2) - 1 >> 1)
4543
+ e4[a4] = e4[f2];
4544
+ e4[a4] = v3;
4545
4545
  };
4546
- return a3.add = (r3) => {
4546
+ return a3.add = (r4) => {
4547
4547
  var a4 = o2;
4548
- e2[o2++] = r3;
4549
- for (var v3 = a4 - 1 >> 1;a4 > 0 && r3._score < e2[v3]._score; v3 = (a4 = v3) - 1 >> 1)
4550
- e2[a4] = e2[v3];
4551
- e2[a4] = r3;
4552
- }, a3.poll = (r3) => {
4548
+ e4[o2++] = r4;
4549
+ for (var v3 = a4 - 1 >> 1;a4 > 0 && r4._score < e4[v3]._score; v3 = (a4 = v3) - 1 >> 1)
4550
+ e4[a4] = e4[v3];
4551
+ e4[a4] = r4;
4552
+ }, a3.poll = (r4) => {
4553
4553
  if (o2 !== 0) {
4554
- var a4 = e2[0];
4555
- return e2[0] = e2[--o2], v2(), a4;
4554
+ var a4 = e4[0];
4555
+ return e4[0] = e4[--o2], v2(), a4;
4556
4556
  }
4557
- }, a3.peek = (r3) => {
4557
+ }, a3.peek = (r4) => {
4558
4558
  if (o2 !== 0)
4559
- return e2[0];
4560
- }, a3.replaceTop = (r3) => {
4561
- e2[0] = r3, v2();
4559
+ return e4[0];
4560
+ }, a3.replaceTop = (r4) => {
4561
+ e4[0] = r4, v2();
4562
4562
  }, a3;
4563
4563
  };
4564
4564
  var q2 = fastpriorityqueue();
@@ -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', 'kdco-plan'). Cannot start/end with hyphen or have consecutive hyphens."
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",
@@ -13052,11 +13145,14 @@ var targetPathSchema = exports_external.string().refine((path3) => path3.startsW
13052
13145
  var skillTargetSchema = exports_external.string().regex(/^\.opencode\/skill\/[a-z0-9]+(-[a-z0-9]+)*\/SKILL\.md$/, {
13053
13146
  message: 'Skill target must match pattern ".opencode/skill/<name>/SKILL.md" where name follows OpenCode naming rules'
13054
13147
  });
13055
- var mcpServerSchema = exports_external.object({
13148
+ var mcpServerObjectSchema = exports_external.object({
13056
13149
  type: exports_external.enum(["remote", "local"]),
13057
13150
  url: exports_external.string().url().optional(),
13058
13151
  command: exports_external.array(exports_external.string()).optional(),
13152
+ args: exports_external.array(exports_external.string()).optional(),
13153
+ environment: exports_external.record(exports_external.string()).optional(),
13059
13154
  headers: exports_external.record(exports_external.string()).optional(),
13155
+ oauth: exports_external.boolean().optional(),
13060
13156
  enabled: exports_external.boolean().default(true)
13061
13157
  }).refine((data) => {
13062
13158
  if (data.type === "remote" && !data.url) {
@@ -13069,47 +13165,93 @@ var mcpServerSchema = exports_external.object({
13069
13165
  }, {
13070
13166
  message: "Remote MCP servers require 'url', local servers require 'command'"
13071
13167
  });
13072
- var componentFileSchema = exports_external.object({
13168
+ var mcpServerSchema = exports_external.union([exports_external.string().url(), mcpServerObjectSchema]);
13169
+ var componentFileObjectSchema = exports_external.object({
13073
13170
  path: exports_external.string().min(1, "File path cannot be empty"),
13074
13171
  target: targetPathSchema
13075
13172
  });
13173
+ var componentFileSchema = exports_external.union([
13174
+ exports_external.string().min(1, "File path cannot be empty"),
13175
+ componentFileObjectSchema
13176
+ ]);
13177
+ var agentConfigSchema = exports_external.object({
13178
+ tools: exports_external.record(exports_external.boolean()).optional(),
13179
+ temperature: exports_external.number().min(0).max(2).optional(),
13180
+ prompt: exports_external.string().optional(),
13181
+ permission: exports_external.record(exports_external.enum(["allow", "deny"])).optional()
13182
+ });
13183
+ var opencodeConfigSchema = exports_external.object({
13184
+ plugins: exports_external.array(exports_external.string()).optional(),
13185
+ tools: exports_external.record(exports_external.boolean()).optional(),
13186
+ agent: exports_external.record(agentConfigSchema).optional(),
13187
+ instructions: exports_external.array(exports_external.string()).optional()
13188
+ });
13076
13189
  var componentManifestSchema = exports_external.object({
13077
13190
  name: openCodeNameSchema,
13078
13191
  type: componentTypeSchema,
13079
13192
  description: exports_external.string().min(1).max(1024),
13080
13193
  files: exports_external.array(componentFileSchema),
13081
- dependencies: exports_external.array(openCodeNameSchema).default([]),
13194
+ dependencies: exports_external.array(dependencyRefSchema).default([]),
13082
13195
  npmDependencies: exports_external.array(exports_external.string()).optional(),
13083
13196
  npmDevDependencies: exports_external.array(exports_external.string()).optional(),
13084
13197
  mcpServers: exports_external.record(mcpServerSchema).optional(),
13085
13198
  mcpScope: exports_external.enum(["agent", "global"]).default("agent"),
13199
+ opencode: opencodeConfigSchema.optional(),
13086
13200
  disabledTools: exports_external.array(exports_external.string()).optional()
13087
13201
  });
13202
+ function inferTargetPath(sourcePath) {
13203
+ return `.opencode/${sourcePath}`;
13204
+ }
13205
+ function normalizeFile(file) {
13206
+ if (typeof file === "string") {
13207
+ return {
13208
+ path: file,
13209
+ target: inferTargetPath(file)
13210
+ };
13211
+ }
13212
+ return file;
13213
+ }
13214
+ function normalizeMcpServer(server) {
13215
+ if (typeof server === "string") {
13216
+ return {
13217
+ type: "remote",
13218
+ url: server,
13219
+ enabled: true
13220
+ };
13221
+ }
13222
+ return server;
13223
+ }
13224
+ function normalizeComponentManifest(manifest) {
13225
+ return {
13226
+ ...manifest,
13227
+ files: manifest.files.map(normalizeFile),
13228
+ mcpServers: manifest.mcpServers ? Object.fromEntries(Object.entries(manifest.mcpServers).map(([name, server]) => [
13229
+ name,
13230
+ normalizeMcpServer(server)
13231
+ ])) : undefined
13232
+ };
13233
+ }
13088
13234
  var semverRegex = /^\d+\.\d+\.\d+(-[a-zA-Z0-9.-]+)?(\+[a-zA-Z0-9.-]+)?$/;
13089
13235
  var registrySchema = exports_external.object({
13090
13236
  name: exports_external.string().min(1, "Registry name cannot be empty"),
13091
- prefix: openCodeNameSchema,
13237
+ namespace: namespaceSchema,
13092
13238
  version: exports_external.string().regex(semverRegex, {
13093
13239
  message: "Version must be valid semver (e.g., '1.0.0', '2.1.0-beta.1')"
13094
13240
  }),
13095
13241
  author: exports_external.string().min(1, "Author cannot be empty"),
13096
13242
  components: exports_external.array(componentManifestSchema)
13097
- }).refine((data) => {
13098
- return data.components.every((c2) => c2.name.startsWith(`${data.prefix}-`));
13099
- }, {
13100
- message: "All component names must start with the registry prefix"
13101
13243
  }).refine((data) => {
13102
13244
  const componentNames = new Set(data.components.map((c2) => c2.name));
13103
13245
  for (const component of data.components) {
13104
13246
  for (const dep of component.dependencies) {
13105
- if (!componentNames.has(dep)) {
13247
+ if (!dep.includes("/") && !componentNames.has(dep)) {
13106
13248
  return false;
13107
13249
  }
13108
13250
  }
13109
13251
  }
13110
13252
  return true;
13111
13253
  }, {
13112
- message: "All dependencies must reference components that exist in the registry"
13254
+ message: "Bare dependencies must reference components that exist in the registry. Use qualified references (e.g., 'other-registry/component') for cross-namespace dependencies."
13113
13255
  });
13114
13256
  var packumentSchema = exports_external.object({
13115
13257
  name: openCodeNameSchema,
@@ -13120,7 +13262,7 @@ var packumentSchema = exports_external.object({
13120
13262
  });
13121
13263
  var registryIndexSchema = exports_external.object({
13122
13264
  name: exports_external.string(),
13123
- prefix: openCodeNameSchema,
13265
+ namespace: namespaceSchema,
13124
13266
  version: exports_external.string(),
13125
13267
  author: exports_external.string(),
13126
13268
  components: exports_external.array(exports_external.object({
@@ -13130,67 +13272,6 @@ var registryIndexSchema = exports_external.object({
13130
13272
  }))
13131
13273
  });
13132
13274
 
13133
- // src/utils/errors.ts
13134
- var EXIT_CODES = {
13135
- SUCCESS: 0,
13136
- GENERAL: 1,
13137
- NOT_FOUND: 66,
13138
- NETWORK: 69,
13139
- CONFIG: 78,
13140
- INTEGRITY: 1
13141
- };
13142
-
13143
- class OCXError extends Error {
13144
- code;
13145
- exitCode;
13146
- constructor(message, code, exitCode = EXIT_CODES.GENERAL) {
13147
- super(message);
13148
- this.code = code;
13149
- this.exitCode = exitCode;
13150
- this.name = "OCXError";
13151
- }
13152
- }
13153
-
13154
- class NotFoundError extends OCXError {
13155
- constructor(message) {
13156
- super(message, "NOT_FOUND", EXIT_CODES.NOT_FOUND);
13157
- this.name = "NotFoundError";
13158
- }
13159
- }
13160
-
13161
- class NetworkError extends OCXError {
13162
- constructor(message) {
13163
- super(message, "NETWORK_ERROR", EXIT_CODES.NETWORK);
13164
- this.name = "NetworkError";
13165
- }
13166
- }
13167
-
13168
- class ConfigError extends OCXError {
13169
- constructor(message) {
13170
- super(message, "CONFIG_ERROR", EXIT_CODES.CONFIG);
13171
- this.name = "ConfigError";
13172
- }
13173
- }
13174
-
13175
- class ValidationError extends OCXError {
13176
- constructor(message) {
13177
- super(message, "VALIDATION_ERROR", EXIT_CODES.GENERAL);
13178
- this.name = "ValidationError";
13179
- }
13180
- }
13181
- class IntegrityError extends OCXError {
13182
- constructor(component, expected, found) {
13183
- const message = `Integrity verification failed for "${component}"
13184
- ` + ` Expected: ${expected}
13185
- ` + ` Found: ${found}
13186
-
13187
- ` + `The registry content has changed since this component was locked.
13188
- ` + `This could indicate tampering or an unauthorized update.`;
13189
- super(message, "INTEGRITY_ERROR", EXIT_CODES.INTEGRITY);
13190
- this.name = "IntegrityError";
13191
- }
13192
- }
13193
-
13194
13275
  // src/registry/fetcher.ts
13195
13276
  var cache = new Map;
13196
13277
  async function fetchWithCache(url, parse) {
@@ -13252,7 +13333,58 @@ async function fetchFileContent(baseUrl, componentName, filePath) {
13252
13333
  return response.text();
13253
13334
  }
13254
13335
 
13336
+ // ../../node_modules/.bun/remeda@2.33.0/node_modules/remeda/dist/lazyDataLastImpl-DtF3cihj.js
13337
+ function e2(e3, t2, n2) {
13338
+ let r2 = (n3) => e3(n3, ...t2);
13339
+ return n2 === undefined ? r2 : Object.assign(r2, { lazy: n2, lazyArgs: t2 });
13340
+ }
13341
+
13342
+ // ../../node_modules/.bun/remeda@2.33.0/node_modules/remeda/dist/purry-GjwKKIlp.js
13343
+ function t2(t3, n2, r2) {
13344
+ let i2 = t3.length - n2.length;
13345
+ if (i2 === 0)
13346
+ return t3(...n2);
13347
+ if (i2 === 1)
13348
+ return e2(t3, n2, r2);
13349
+ throw Error(`Wrong number of arguments`);
13350
+ }
13351
+
13352
+ // ../../node_modules/.bun/remeda@2.33.0/node_modules/remeda/dist/isPlainObject.js
13353
+ function e3(e4) {
13354
+ if (typeof e4 != `object` || !e4)
13355
+ return false;
13356
+ let t3 = Object.getPrototypeOf(e4);
13357
+ return t3 === null || t3 === Object.prototype;
13358
+ }
13359
+
13360
+ // ../../node_modules/.bun/remeda@2.33.0/node_modules/remeda/dist/mergeDeep.js
13361
+ function n2(...t3) {
13362
+ return t2(r2, t3);
13363
+ }
13364
+ function r2(e4, n3) {
13365
+ let i2 = { ...e4, ...n3 };
13366
+ for (let a3 in n3) {
13367
+ if (!(a3 in e4))
13368
+ continue;
13369
+ let { [a3]: o2 } = e4;
13370
+ if (!e3(o2))
13371
+ continue;
13372
+ let { [a3]: s2 } = n3;
13373
+ e3(s2) && (i2[a3] = r2(o2, s2));
13374
+ }
13375
+ return i2;
13376
+ }
13377
+
13255
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
+ }
13256
13388
  async function resolveDependencies(registries, componentNames) {
13257
13389
  const resolved = new Map;
13258
13390
  const visiting = new Set;
@@ -13261,41 +13393,45 @@ async function resolveDependencies(registries, componentNames) {
13261
13393
  const npmDeps = new Set;
13262
13394
  const npmDevDeps = new Set;
13263
13395
  const disabledTools = new Set;
13264
- async function resolve2(name, path3 = []) {
13265
- if (resolved.has(name)) {
13396
+ const plugins = new Set;
13397
+ const agentConfigs = {};
13398
+ const instructionsSet = new Set;
13399
+ async function resolve2(componentNamespace, componentName, path3 = []) {
13400
+ const qualifiedName = createQualifiedComponent(componentNamespace, componentName);
13401
+ if (resolved.has(qualifiedName)) {
13266
13402
  return;
13267
13403
  }
13268
- if (visiting.has(name)) {
13269
- const cycle = [...path3, name].join(" \u2192 ");
13404
+ if (visiting.has(qualifiedName)) {
13405
+ const cycle = [...path3, qualifiedName].join(" \u2192 ");
13270
13406
  throw new ValidationError(`Circular dependency detected: ${cycle}`);
13271
13407
  }
13272
- visiting.add(name);
13273
- let component = null;
13274
- let foundRegistry = null;
13275
- const registryEntries = Object.entries(registries);
13276
- for (const [regName, regConfig] of registryEntries) {
13277
- try {
13278
- const manifest = await fetchComponent(regConfig.url, name);
13279
- component = manifest;
13280
- foundRegistry = { name: regName, url: regConfig.url };
13281
- break;
13282
- } 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.`);
13283
13412
  }
13284
- if (!component || !foundRegistry) {
13285
- throw new OCXError(`Component '${name}' not found in any configured registry.`, "NOT_FOUND");
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");
13286
13418
  }
13287
13419
  for (const dep of component.dependencies) {
13288
- await resolve2(dep, [...path3, name]);
13289
- }
13290
- resolved.set(name, {
13291
- ...component,
13292
- registryName: foundRegistry.name,
13293
- baseUrl: foundRegistry.url
13420
+ const depRef = parseComponentRef(dep, componentNamespace);
13421
+ await resolve2(depRef.namespace, depRef.component, [...path3, qualifiedName]);
13422
+ }
13423
+ const normalizedComponent = normalizeComponentManifest(component);
13424
+ resolved.set(qualifiedName, {
13425
+ ...normalizedComponent,
13426
+ namespace: componentNamespace,
13427
+ registryName: componentNamespace,
13428
+ baseUrl: regConfig.url,
13429
+ qualifiedName
13294
13430
  });
13295
- visiting.delete(name);
13296
- if (component.mcpServers) {
13431
+ visiting.delete(qualifiedName);
13432
+ if (normalizedComponent.mcpServers) {
13297
13433
  const serverNames = [];
13298
- for (const [serverName, config2] of Object.entries(component.mcpServers)) {
13434
+ for (const [serverName, config2] of Object.entries(normalizedComponent.mcpServers)) {
13299
13435
  mcpServers[serverName] = config2;
13300
13436
  serverNames.push(serverName);
13301
13437
  }
@@ -13322,9 +13458,34 @@ async function resolveDependencies(registries, componentNames) {
13322
13458
  disabledTools.add(tool);
13323
13459
  }
13324
13460
  }
13461
+ if (component.opencode) {
13462
+ if (component.opencode.plugins) {
13463
+ for (const plugin of component.opencode.plugins) {
13464
+ plugins.add(plugin);
13465
+ }
13466
+ }
13467
+ if (component.opencode.agent) {
13468
+ for (const [agentName, config2] of Object.entries(component.opencode.agent)) {
13469
+ agentConfigs[agentName] = n2(agentConfigs[agentName] ?? {}, config2);
13470
+ }
13471
+ }
13472
+ if (component.opencode.instructions) {
13473
+ for (const instruction of component.opencode.instructions) {
13474
+ instructionsSet.add(instruction);
13475
+ }
13476
+ }
13477
+ if (component.opencode.tools) {
13478
+ for (const [tool, enabled] of Object.entries(component.opencode.tools)) {
13479
+ if (enabled === false) {
13480
+ disabledTools.add(tool);
13481
+ }
13482
+ }
13483
+ }
13484
+ }
13325
13485
  }
13326
13486
  for (const name of componentNames) {
13327
- await resolve2(name);
13487
+ const ref = parseComponentRef(name);
13488
+ await resolve2(ref.namespace, ref.component);
13328
13489
  }
13329
13490
  const components = Array.from(resolved.values());
13330
13491
  const installOrder = Array.from(resolved.keys());
@@ -13335,7 +13496,10 @@ async function resolveDependencies(registries, componentNames) {
13335
13496
  agentMcpBindings,
13336
13497
  npmDependencies: Array.from(npmDeps),
13337
13498
  npmDevDependencies: Array.from(npmDevDeps),
13338
- disabledTools: Array.from(disabledTools)
13499
+ disabledTools: Array.from(disabledTools),
13500
+ plugins: Array.from(plugins),
13501
+ agentConfigs,
13502
+ instructions: Array.from(instructionsSet)
13339
13503
  };
13340
13504
  }
13341
13505
 
@@ -14651,13 +14815,13 @@ function applyEdits(text2, edits) {
14651
14815
  });
14652
14816
  let lastModifiedOffset = text2.length;
14653
14817
  for (let i2 = sortedEdits.length - 1;i2 >= 0; i2--) {
14654
- let e2 = sortedEdits[i2];
14655
- if (e2.offset + e2.length <= lastModifiedOffset) {
14656
- text2 = applyEdit(text2, e2);
14818
+ let e4 = sortedEdits[i2];
14819
+ if (e4.offset + e4.length <= lastModifiedOffset) {
14820
+ text2 = applyEdit(text2, e4);
14657
14821
  } else {
14658
14822
  throw new Error("Overlapping edit");
14659
14823
  }
14660
- lastModifiedOffset = e2.offset;
14824
+ lastModifiedOffset = e4.offset;
14661
14825
  }
14662
14826
  return text2;
14663
14827
  }
@@ -14677,23 +14841,29 @@ var installedComponentSchema = exports_external.object({
14677
14841
  registry: exports_external.string(),
14678
14842
  version: exports_external.string(),
14679
14843
  hash: exports_external.string(),
14680
- target: exports_external.string(),
14681
- installedAt: exports_external.string()
14844
+ files: exports_external.array(exports_external.string()),
14845
+ installedAt: exports_external.string(),
14846
+ alias: exports_external.string().optional()
14682
14847
  });
14683
14848
  var ocxLockSchema = exports_external.object({
14684
14849
  lockVersion: exports_external.literal(1),
14685
- installed: exports_external.record(installedComponentSchema).default({})
14850
+ installed: exports_external.record(qualifiedComponentSchema, installedComponentSchema).default({})
14686
14851
  });
14687
14852
  var opencodeMcpSchema = exports_external.record(mcpServerSchema);
14688
14853
  var opencodeAgentSchema = exports_external.object({
14689
14854
  disable: exports_external.boolean().optional(),
14690
- tools: exports_external.record(exports_external.boolean()).optional()
14855
+ tools: exports_external.record(exports_external.boolean()).optional(),
14856
+ temperature: exports_external.number().min(0).max(2).optional(),
14857
+ prompt: exports_external.string().optional(),
14858
+ permission: exports_external.record(exports_external.enum(["allow", "deny"])).optional()
14691
14859
  });
14692
14860
  var opencodeConfigPatchSchema = exports_external.object({
14693
14861
  default_agent: exports_external.string().optional(),
14694
14862
  mcp: opencodeMcpSchema.optional(),
14695
14863
  tools: exports_external.record(exports_external.boolean()).optional(),
14696
- agent: exports_external.record(opencodeAgentSchema).optional()
14864
+ agent: exports_external.record(opencodeAgentSchema).optional(),
14865
+ plugin: exports_external.array(exports_external.string()).optional(),
14866
+ instructions: exports_external.array(exports_external.string()).optional()
14697
14867
  });
14698
14868
  var CONFIG_FILE = "ocx.jsonc";
14699
14869
  var LOCK_FILE = "ocx.lock";
@@ -14826,6 +14996,66 @@ function applyDefaultAgent(content, config2, defaultAgent) {
14826
14996
  const edits = modify(content, ["default_agent"], defaultAgent, JSONC_OPTIONS);
14827
14997
  return applyEdits(content, edits);
14828
14998
  }
14999
+ function applyPlugins(content, config2, plugins) {
15000
+ const added = [];
15001
+ let updatedContent = content;
15002
+ const existingPlugins = config2.plugin ?? [];
15003
+ for (const plugin of plugins) {
15004
+ if (existingPlugins.includes(plugin)) {
15005
+ continue;
15006
+ }
15007
+ const newIndex = existingPlugins.length + added.length;
15008
+ const edits = modify(updatedContent, ["plugin", newIndex], plugin, JSONC_OPTIONS);
15009
+ updatedContent = applyEdits(updatedContent, edits);
15010
+ added.push(plugin);
15011
+ }
15012
+ return { content: updatedContent, added };
15013
+ }
15014
+ function applyAgentConfigs(content, existingConfig, agentConfigs) {
15015
+ let updatedContent = content;
15016
+ const agentsConfigured = [];
15017
+ for (const [agentName, componentAgentConfig] of Object.entries(agentConfigs)) {
15018
+ const existingAgentConfig = existingConfig.agent?.[agentName] ?? {};
15019
+ const merged = n2(componentAgentConfig, existingAgentConfig);
15020
+ if (merged.tools) {
15021
+ for (const [toolPattern, enabled] of Object.entries(merged.tools)) {
15022
+ const edits = modify(updatedContent, ["agent", agentName, "tools", toolPattern], enabled, JSONC_OPTIONS);
15023
+ updatedContent = applyEdits(updatedContent, edits);
15024
+ }
15025
+ }
15026
+ if (merged.temperature !== undefined) {
15027
+ const edits = modify(updatedContent, ["agent", agentName, "temperature"], merged.temperature, JSONC_OPTIONS);
15028
+ updatedContent = applyEdits(updatedContent, edits);
15029
+ }
15030
+ if (merged.prompt) {
15031
+ const edits = modify(updatedContent, ["agent", agentName, "prompt"], merged.prompt, JSONC_OPTIONS);
15032
+ updatedContent = applyEdits(updatedContent, edits);
15033
+ }
15034
+ if (merged.permission) {
15035
+ for (const [pattern, permission] of Object.entries(merged.permission)) {
15036
+ const edits = modify(updatedContent, ["agent", agentName, "permission", pattern], permission, JSONC_OPTIONS);
15037
+ updatedContent = applyEdits(updatedContent, edits);
15038
+ }
15039
+ }
15040
+ agentsConfigured.push(agentName);
15041
+ }
15042
+ return { content: updatedContent, agentsConfigured };
15043
+ }
15044
+ function applyInstructions(content, config2, instructions) {
15045
+ const added = [];
15046
+ let updatedContent = content;
15047
+ const existingInstructions = config2.instructions ?? [];
15048
+ for (const instruction of instructions) {
15049
+ if (existingInstructions.includes(instruction)) {
15050
+ continue;
15051
+ }
15052
+ const newIndex = existingInstructions.length + added.length;
15053
+ const edits = modify(updatedContent, ["instructions", newIndex], instruction, JSONC_OPTIONS);
15054
+ updatedContent = applyEdits(updatedContent, edits);
15055
+ added.push(instruction);
15056
+ }
15057
+ return { content: updatedContent, added };
15058
+ }
14829
15059
  async function updateOpencodeConfig(cwd, options2) {
14830
15060
  const existing = await readOpencodeConfig(cwd);
14831
15061
  let content;
@@ -14846,6 +15076,8 @@ async function updateOpencodeConfig(cwd, options2) {
14846
15076
  let mcpSkipped = [];
14847
15077
  let agentsConfigured = [];
14848
15078
  let toolsDisabled = [];
15079
+ let pluginsAdded = [];
15080
+ let instructionsAdded = [];
14849
15081
  if (options2.mcpServers && Object.keys(options2.mcpServers).length > 0) {
14850
15082
  const result = applyMcpServers(content, config2, options2.mcpServers);
14851
15083
  content = result.content;
@@ -14869,6 +15101,24 @@ async function updateOpencodeConfig(cwd, options2) {
14869
15101
  content = applyDisabledTools(content, options2.disabledTools);
14870
15102
  toolsDisabled = options2.disabledTools;
14871
15103
  }
15104
+ if (options2.plugins && options2.plugins.length > 0) {
15105
+ const updatedConfig = parse2(content, [], { allowTrailingComma: true });
15106
+ const result = applyPlugins(content, updatedConfig, options2.plugins);
15107
+ content = result.content;
15108
+ pluginsAdded = result.added;
15109
+ }
15110
+ if (options2.agentConfigs && Object.keys(options2.agentConfigs).length > 0) {
15111
+ const updatedConfig = parse2(content, [], { allowTrailingComma: true });
15112
+ const result = applyAgentConfigs(content, updatedConfig, options2.agentConfigs);
15113
+ content = result.content;
15114
+ agentsConfigured = [...new Set([...agentsConfigured, ...result.agentsConfigured])];
15115
+ }
15116
+ if (options2.instructions && options2.instructions.length > 0) {
15117
+ const updatedConfig = parse2(content, [], { allowTrailingComma: true });
15118
+ const result = applyInstructions(content, updatedConfig, options2.instructions);
15119
+ content = result.content;
15120
+ instructionsAdded = result.added;
15121
+ }
14872
15122
  await writeOpencodeConfig(configPath, content);
14873
15123
  return {
14874
15124
  path: configPath,
@@ -14876,7 +15126,9 @@ async function updateOpencodeConfig(cwd, options2) {
14876
15126
  mcpAdded,
14877
15127
  mcpSkipped,
14878
15128
  agentsConfigured,
14879
- toolsDisabled
15129
+ toolsDisabled,
15130
+ pluginsAdded,
15131
+ instructionsAdded
14880
15132
  };
14881
15133
  }
14882
15134
 
@@ -16454,28 +16706,48 @@ async function runAdd(componentNames, options3) {
16454
16706
  files.push({ path: file.path, content: Buffer.from(content) });
16455
16707
  }
16456
16708
  const computedHash = await hashBundle(files);
16457
- const existingEntry = lock.installed[component.name];
16709
+ const existingEntry = lock.installed[component.qualifiedName];
16458
16710
  if (existingEntry && existingEntry.hash !== computedHash) {
16459
- throw new IntegrityError(component.name, existingEntry.hash, computedHash);
16711
+ throw new IntegrityError(component.qualifiedName, existingEntry.hash, computedHash);
16712
+ }
16713
+ for (const file of component.files) {
16714
+ const targetPath = join2(cwd, file.target);
16715
+ if (existsSync2(targetPath)) {
16716
+ const conflictingComponent = findComponentByFile(lock, file.target);
16717
+ if (conflictingComponent && conflictingComponent !== component.qualifiedName) {
16718
+ throw new ConflictError(`File conflict: ${file.target} already exists (installed by '${conflictingComponent}').
16719
+
16720
+ ` + `To resolve:
16721
+ ` + ` 1. Remove existing: rm ${file.target}
16722
+ ` + ` 2. Or rename it manually and update references
16723
+ ` + ` 3. Then run: ocx add ${component.qualifiedName}`);
16724
+ }
16725
+ }
16460
16726
  }
16461
16727
  await installComponent(component, files, cwd);
16462
16728
  const index = await fetchRegistryIndex(component.baseUrl);
16463
- lock.installed[component.name] = {
16729
+ lock.installed[component.qualifiedName] = {
16464
16730
  registry: component.registryName,
16465
16731
  version: index.version,
16466
16732
  hash: computedHash,
16467
- target: getTargetPath(component),
16733
+ files: component.files.map((f2) => f2.target),
16468
16734
  installedAt: new Date().toISOString()
16469
16735
  };
16470
16736
  }
16471
16737
  installSpin?.succeed(`Installed ${resolved.components.length} components`);
16472
16738
  const hasMcpChanges = Object.keys(resolved.mcpServers).length > 0 || resolved.agentMcpBindings.length > 0;
16473
16739
  const hasDisabledTools = resolved.disabledTools.length > 0;
16474
- if (hasMcpChanges || hasDisabledTools) {
16740
+ const hasPlugins = resolved.plugins.length > 0;
16741
+ const hasAgentConfigs = Object.keys(resolved.agentConfigs).length > 0;
16742
+ const hasInstructions = resolved.instructions.length > 0;
16743
+ if (hasMcpChanges || hasDisabledTools || hasPlugins || hasAgentConfigs || hasInstructions) {
16475
16744
  const result = await updateOpencodeConfig(cwd, {
16476
16745
  mcpServers: resolved.mcpServers,
16477
16746
  agentMcpBindings: resolved.agentMcpBindings,
16478
- disabledTools: resolved.disabledTools
16747
+ disabledTools: resolved.disabledTools,
16748
+ plugins: resolved.plugins,
16749
+ agentConfigs: resolved.agentConfigs,
16750
+ instructions: resolved.instructions
16479
16751
  });
16480
16752
  if (result.mcpSkipped.length > 0 && !options3.quiet) {
16481
16753
  for (const name of result.mcpSkipped) {
@@ -16491,6 +16763,15 @@ async function runAdd(componentNames, options3) {
16491
16763
  if (!options3.quiet && result.toolsDisabled.length > 0) {
16492
16764
  logger.info(`Disabled ${result.toolsDisabled.length} tools: ${result.toolsDisabled.join(", ")}`);
16493
16765
  }
16766
+ if (!options3.quiet && result.pluginsAdded.length > 0) {
16767
+ logger.info(`Added ${result.pluginsAdded.length} plugins: ${result.pluginsAdded.join(", ")}`);
16768
+ }
16769
+ if (!options3.quiet && result.agentsConfigured.length > 0) {
16770
+ logger.info(`Configured ${result.agentsConfigured.length} agents: ${result.agentsConfigured.join(", ")}`);
16771
+ }
16772
+ if (!options3.quiet && result.instructionsAdded.length > 0) {
16773
+ logger.info(`Added ${result.instructionsAdded.length} instructions`);
16774
+ }
16494
16775
  }
16495
16776
  const hasNpmDeps = resolved.npmDependencies.length > 0;
16496
16777
  const hasNpmDevDeps = resolved.npmDevDependencies.length > 0;
@@ -16535,9 +16816,6 @@ async function installComponent(component, files, cwd) {
16535
16816
  await writeFile(targetPath, file.content);
16536
16817
  }
16537
16818
  }
16538
- function getTargetPath(component) {
16539
- return component.files[0]?.target ?? `.opencode/${component.type}/${component.name}`;
16540
- }
16541
16819
  async function hashContent(content) {
16542
16820
  return createHash("sha256").update(content).digest("hex");
16543
16821
  }
@@ -16593,6 +16871,14 @@ async function installNpmDependencies(dependencies, devDependencies, cwd, option
16593
16871
  await run(parseNi, [...devDependencies, "-D"], { cwd });
16594
16872
  }
16595
16873
  }
16874
+ function findComponentByFile(lock, filePath) {
16875
+ for (const [qualifiedName, entry] of Object.entries(lock.installed)) {
16876
+ if (entry.files.includes(filePath)) {
16877
+ return qualifiedName;
16878
+ }
16879
+ }
16880
+ return null;
16881
+ }
16596
16882
 
16597
16883
  // src/commands/build.ts
16598
16884
  import { mkdir as mkdir2 } from "fs/promises";
@@ -16619,7 +16905,7 @@ function registerBuildCommand(program2) {
16619
16905
  if (!parseResult.success) {
16620
16906
  if (!options3.json) {
16621
16907
  spinner2.fail("Registry validation failed");
16622
- const errors3 = parseResult.error.errors.map((e2) => ` ${e2.path.join(".")}: ${e2.message}`);
16908
+ const errors3 = parseResult.error.errors.map((e4) => ` ${e4.path.join(".")}: ${e4.message}`);
16623
16909
  for (const err of errors3) {
16624
16910
  console.log(kleur_default.red(err));
16625
16911
  }
@@ -16642,7 +16928,8 @@ function registerBuildCommand(program2) {
16642
16928
  };
16643
16929
  const packumentPath = join3(componentsDir, `${component.name}.json`);
16644
16930
  await Bun.write(packumentPath, JSON.stringify(packument, null, 2));
16645
- for (const file of component.files) {
16931
+ for (const rawFile of component.files) {
16932
+ const file = normalizeFile(rawFile);
16646
16933
  const sourceFilePath = join3(sourcePath, "files", file.path);
16647
16934
  const destFilePath = join3(componentsDir, component.name, file.path);
16648
16935
  const destFileDir = dirname3(destFilePath);
@@ -16666,7 +16953,7 @@ function registerBuildCommand(program2) {
16666
16953
  }
16667
16954
  const index = {
16668
16955
  name: registry.name,
16669
- prefix: registry.prefix,
16956
+ namespace: registry.namespace,
16670
16957
  version: registry.version,
16671
16958
  author: registry.author,
16672
16959
  components: registry.components.map((c2) => ({
@@ -17534,7 +17821,11 @@ function registerDiffCommand(program2) {
17534
17821
  }
17535
17822
  continue;
17536
17823
  }
17537
- const localPath = `${options3.cwd}/${installed.target}`;
17824
+ if (!installed.files || installed.files.length === 0) {
17825
+ logger.warn(`No files recorded for component '${name}'`);
17826
+ continue;
17827
+ }
17828
+ const localPath = `${options3.cwd}/${installed.files[0]}`;
17538
17829
  const localFile = Bun.file(localPath);
17539
17830
  if (!await localFile.exists()) {
17540
17831
  results.push({ name, hasChanges: true, diff: "Local file missing" });
@@ -17547,13 +17838,16 @@ function registerDiffCommand(program2) {
17547
17838
  continue;
17548
17839
  }
17549
17840
  try {
17550
- const upstream = await fetchComponent(registryConfig.url, name);
17551
- const upstreamFile = upstream.files[0];
17552
- if (!upstreamFile) {
17841
+ const parsed = parseQualifiedComponent(name);
17842
+ const componentName = parsed.component;
17843
+ const upstream = await fetchComponent(registryConfig.url, componentName);
17844
+ const rawUpstreamFile = upstream.files[0];
17845
+ if (!rawUpstreamFile) {
17553
17846
  results.push({ name, hasChanges: false });
17554
17847
  continue;
17555
17848
  }
17556
- const upstreamContent = await fetchFileContent(registryConfig.url, name, upstreamFile.path);
17849
+ const upstreamFile = normalizeFile(rawUpstreamFile);
17850
+ const upstreamContent = await fetchFileContent(registryConfig.url, componentName, upstreamFile.path);
17557
17851
  if (localContent === upstreamContent) {
17558
17852
  results.push({ name, hasChanges: false });
17559
17853
  } else {
@@ -17801,7 +18095,7 @@ function registerSearchCommand(program2) {
17801
18095
  }
17802
18096
  for (const comp of index.components) {
17803
18097
  allComponents.push({
17804
- name: comp.name,
18098
+ name: `${index.namespace}/${comp.name}`,
17805
18099
  description: comp.description,
17806
18100
  type: comp.type,
17807
18101
  registry: registryName
@@ -17822,7 +18116,7 @@ function registerSearchCommand(program2) {
17822
18116
  keys: ["name", "description"],
17823
18117
  limit
17824
18118
  });
17825
- results = fuzzyResults.map((r2) => r2.obj);
18119
+ results = fuzzyResults.map((r3) => r3.obj);
17826
18120
  } else {
17827
18121
  results = results.slice(0, limit);
17828
18122
  }
@@ -17845,7 +18139,7 @@ function registerSearchCommand(program2) {
17845
18139
  }
17846
18140
 
17847
18141
  // src/index.ts
17848
- var version2 = "1.0.6";
18142
+ var version2 = "1.0.8";
17849
18143
  async function main2() {
17850
18144
  const program2 = new Command().name("ocx").description("OpenCode Extensions - Install agents, skills, plugins, and commands").version(version2);
17851
18145
  registerInitCommand(program2);
@@ -17860,4 +18154,4 @@ main2().catch((err) => {
17860
18154
  handleError(err);
17861
18155
  });
17862
18156
 
17863
- //# debugId=1145245802C7C7C964756E2164756E21
18157
+ //# debugId=4504091B3609ACE764756E2164756E21