ocx 1.0.20 → 1.0.21

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
@@ -10420,7 +10420,7 @@ class GhostConfigProvider {
10420
10420
  // package.json
10421
10421
  var package_default = {
10422
10422
  name: "ocx",
10423
- version: "1.0.20",
10423
+ version: "1.0.21",
10424
10424
  description: "OCX CLI - ShadCN-style registry for OpenCode extensions. Install agents, plugins, skills, and MCP servers.",
10425
10425
  author: "kdcokenny",
10426
10426
  license: "MIT",
@@ -10691,6 +10691,7 @@ async function resolveDependencies(registries, componentNames) {
10691
10691
  }
10692
10692
 
10693
10693
  // src/updaters/update-opencode-config.ts
10694
+ import path3 from "path";
10694
10695
  var JSONC_OPTIONS = {
10695
10696
  formattingOptions: {
10696
10697
  tabSize: 2,
@@ -10699,9 +10700,28 @@ var JSONC_OPTIONS = {
10699
10700
  `
10700
10701
  }
10701
10702
  };
10703
+ var OPENCODE_CONFIG_TEMPLATE = `{
10704
+ "$schema": "https://opencode.ai/config.json"
10705
+ // Add MCP servers, tools, plugins here
10706
+ }
10707
+ `;
10708
+ async function ensureOpencodeConfig(cwd) {
10709
+ const jsoncPath = path3.join(cwd, "opencode.jsonc");
10710
+ const jsonPath = path3.join(cwd, "opencode.json");
10711
+ const jsoncFile = Bun.file(jsoncPath);
10712
+ if (await jsoncFile.exists()) {
10713
+ return { path: jsoncPath, created: false };
10714
+ }
10715
+ const jsonFile = Bun.file(jsonPath);
10716
+ if (await jsonFile.exists()) {
10717
+ return { path: jsonPath, created: false };
10718
+ }
10719
+ await Bun.write(jsoncPath, OPENCODE_CONFIG_TEMPLATE);
10720
+ return { path: jsoncPath, created: true };
10721
+ }
10702
10722
  async function readOpencodeJsonConfig(cwd) {
10703
- const jsonPath = `${cwd}/opencode.json`;
10704
- const jsoncPath = `${cwd}/opencode.jsonc`;
10723
+ const jsonPath = path3.join(cwd, "opencode.json");
10724
+ const jsoncPath = path3.join(cwd, "opencode.jsonc");
10705
10725
  for (const configPath of [jsoncPath, jsonPath]) {
10706
10726
  const file = Bun.file(configPath);
10707
10727
  if (await file.exists()) {
@@ -10715,13 +10735,13 @@ async function readOpencodeJsonConfig(cwd) {
10715
10735
  }
10716
10736
  return null;
10717
10737
  }
10718
- async function writeOpencodeJsonConfig(path3, content) {
10719
- await Bun.write(path3, content);
10738
+ async function writeOpencodeJsonConfig(path4, content) {
10739
+ await Bun.write(path4, content);
10720
10740
  }
10721
- function getValueAtPath(content, path3) {
10741
+ function getValueAtPath(content, path4) {
10722
10742
  const parsed = parse2(content, [], { allowTrailingComma: true });
10723
10743
  let current = parsed;
10724
- for (const segment of path3) {
10744
+ for (const segment of path4) {
10725
10745
  if (current === null || current === undefined)
10726
10746
  return;
10727
10747
  if (typeof current !== "object")
@@ -10730,27 +10750,27 @@ function getValueAtPath(content, path3) {
10730
10750
  }
10731
10751
  return current;
10732
10752
  }
10733
- function applyValueAtPath(content, path3, value) {
10753
+ function applyValueAtPath(content, path4, value) {
10734
10754
  if (value === null || value === undefined) {
10735
10755
  return content;
10736
10756
  }
10737
10757
  if (typeof value === "object" && !Array.isArray(value)) {
10738
- const existingValue = getValueAtPath(content, path3);
10758
+ const existingValue = getValueAtPath(content, path4);
10739
10759
  if (existingValue !== undefined && (existingValue === null || typeof existingValue !== "object")) {
10740
- const edits2 = modify(content, path3, value, JSONC_OPTIONS);
10760
+ const edits2 = modify(content, path4, value, JSONC_OPTIONS);
10741
10761
  return applyEdits(content, edits2);
10742
10762
  }
10743
10763
  let updatedContent = content;
10744
10764
  for (const [key, val] of Object.entries(value)) {
10745
- updatedContent = applyValueAtPath(updatedContent, [...path3, key], val);
10765
+ updatedContent = applyValueAtPath(updatedContent, [...path4, key], val);
10746
10766
  }
10747
10767
  return updatedContent;
10748
10768
  }
10749
10769
  if (Array.isArray(value)) {
10750
- const edits2 = modify(content, path3, value, JSONC_OPTIONS);
10770
+ const edits2 = modify(content, path4, value, JSONC_OPTIONS);
10751
10771
  return applyEdits(content, edits2);
10752
10772
  }
10753
- const edits = modify(content, path3, value, JSONC_OPTIONS);
10773
+ const edits = modify(content, path4, value, JSONC_OPTIONS);
10754
10774
  return applyEdits(content, edits);
10755
10775
  }
10756
10776
  async function updateOpencodeJsonConfig(cwd, opencode) {
@@ -10764,7 +10784,7 @@ async function updateOpencodeJsonConfig(cwd, opencode) {
10764
10784
  } else {
10765
10785
  const config = { $schema: "https://opencode.ai/config.json" };
10766
10786
  content = JSON.stringify(config, null, "\t");
10767
- configPath = `${cwd}/opencode.jsonc`;
10787
+ configPath = path3.join(cwd, "opencode.jsonc");
10768
10788
  created = true;
10769
10789
  }
10770
10790
  const originalContent = content;
@@ -10983,8 +11003,8 @@ function handleError(error, options2 = {}) {
10983
11003
  if (error instanceof ZodError) {
10984
11004
  logger.error("Validation failed:");
10985
11005
  for (const issue of error.issues) {
10986
- const path3 = issue.path.join(".");
10987
- logger.error(` ${path3}: ${issue.message}`);
11006
+ const path4 = issue.path.join(".");
11007
+ logger.error(` ${path4}: ${issue.message}`);
10988
11008
  }
10989
11009
  process.exit(EXIT_CODES.CONFIG);
10990
11010
  }
@@ -11042,14 +11062,14 @@ function outputJson(data) {
11042
11062
  console.log(JSON.stringify(data, null, 2));
11043
11063
  }
11044
11064
  // src/utils/path-safety.ts
11045
- import path3 from "path";
11065
+ import path4 from "path";
11046
11066
  function isPathInside(childPath, parentPath) {
11047
- const resolvedChild = path3.resolve(childPath);
11048
- const resolvedParent = path3.resolve(parentPath);
11067
+ const resolvedChild = path4.resolve(childPath);
11068
+ const resolvedParent = path4.resolve(parentPath);
11049
11069
  if (resolvedChild === resolvedParent) {
11050
11070
  return true;
11051
11071
  }
11052
- const relative = path3.relative(resolvedParent, resolvedChild);
11072
+ const relative = path4.relative(resolvedParent, resolvedChild);
11053
11073
  return !!relative && !relative.startsWith("..") && !isAbsolutePath(relative);
11054
11074
  }
11055
11075
  function assertPathInside(childPath, parentPath) {
@@ -12912,9 +12932,9 @@ async function buildRegistry(options2) {
12912
12932
 
12913
12933
  // src/commands/build.ts
12914
12934
  function registerBuildCommand(program2) {
12915
- 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 (path4, options2) => {
12935
+ 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 (path5, options2) => {
12916
12936
  try {
12917
- const sourcePath = join4(options2.cwd, path4);
12937
+ const sourcePath = join4(options2.cwd, path5);
12918
12938
  const outPath = join4(options2.cwd, options2.out);
12919
12939
  const spinner2 = createSpinner({
12920
12940
  text: "Building registry...",
@@ -13059,16 +13079,16 @@ class Diff {
13059
13079
  }
13060
13080
  }
13061
13081
  }
13062
- addToPath(path4, added, removed, oldPosInc, options2) {
13063
- const last = path4.lastComponent;
13082
+ addToPath(path5, added, removed, oldPosInc, options2) {
13083
+ const last = path5.lastComponent;
13064
13084
  if (last && !options2.oneChangePerToken && last.added === added && last.removed === removed) {
13065
13085
  return {
13066
- oldPos: path4.oldPos + oldPosInc,
13086
+ oldPos: path5.oldPos + oldPosInc,
13067
13087
  lastComponent: { count: last.count + 1, added, removed, previousComponent: last.previousComponent }
13068
13088
  };
13069
13089
  } else {
13070
13090
  return {
13071
- oldPos: path4.oldPos + oldPosInc,
13091
+ oldPos: path5.oldPos + oldPosInc,
13072
13092
  lastComponent: { count: 1, added, removed, previousComponent: last }
13073
13093
  };
13074
13094
  }
@@ -13946,13 +13966,22 @@ async function runGhostInit(options2) {
13946
13966
  }
13947
13967
  throw err;
13948
13968
  }
13969
+ const opencodeResult = await ensureOpencodeConfig(configDir);
13949
13970
  if (options2.json) {
13950
- console.log(JSON.stringify({ success: true, path: configPath }));
13971
+ console.log(JSON.stringify({
13972
+ success: true,
13973
+ path: configPath,
13974
+ opencodePath: opencodeResult.path,
13975
+ opencodeCreated: opencodeResult.created
13976
+ }));
13951
13977
  return;
13952
13978
  }
13953
13979
  if (!options2.quiet) {
13954
13980
  logger.success("Ghost mode initialized");
13955
13981
  logger.info(`Created ${configPath}`);
13982
+ if (opencodeResult.created) {
13983
+ logger.info(`Created ${opencodeResult.path}`);
13984
+ }
13956
13985
  logger.info("");
13957
13986
  logger.info("Next steps:");
13958
13987
  logger.info(" 1. Edit your config: ocx ghost config");
@@ -14009,14 +14038,14 @@ async function discoverProjectFiles(start, stop) {
14009
14038
  const excluded = new Set;
14010
14039
  for (const file of CONFIG_FILES) {
14011
14040
  const found = await findUp(file, start, stop);
14012
- for (const path4 of found) {
14013
- excluded.add(path4);
14041
+ for (const path5 of found) {
14042
+ excluded.add(path5);
14014
14043
  }
14015
14044
  }
14016
14045
  for (const file of RULE_FILES) {
14017
14046
  const found = await findUp(file, start, stop);
14018
- for (const path4 of found) {
14019
- excluded.add(path4);
14047
+ for (const path5 of found) {
14048
+ excluded.add(path5);
14020
14049
  }
14021
14050
  }
14022
14051
  for await (const dir of up({ targets: CONFIG_DIRS, start, stop })) {
@@ -14037,13 +14066,13 @@ function filterExcludedPaths(excludedPaths, includePatterns, excludePatterns) {
14037
14066
  const includeGlobs = includePatterns.map((p) => new Glob2(p));
14038
14067
  const excludeGlobs = excludePatterns?.map((p) => new Glob2(p)) ?? [];
14039
14068
  const filteredExclusions = new Set;
14040
- for (const path4 of excludedPaths) {
14041
- const matchesInclude = matchesAnyGlob(path4, includeGlobs);
14042
- const matchesExclude = matchesAnyGlob(path4, excludeGlobs);
14069
+ for (const path5 of excludedPaths) {
14070
+ const matchesInclude = matchesAnyGlob(path5, includeGlobs);
14071
+ const matchesExclude = matchesAnyGlob(path5, excludeGlobs);
14043
14072
  if (matchesInclude && !matchesExclude) {
14044
14073
  continue;
14045
14074
  }
14046
- filteredExclusions.add(path4);
14075
+ filteredExclusions.add(path5);
14047
14076
  }
14048
14077
  return filteredExclusions;
14049
14078
  }
@@ -14151,7 +14180,7 @@ async function runGhostOpenCode(args, options2) {
14151
14180
  const openCodeConfig = await loadGhostOpencodeConfig();
14152
14181
  const ghostConfigDir = getGhostConfigDir();
14153
14182
  if (Object.keys(openCodeConfig).length === 0 && !options2.quiet) {
14154
- logger.warn(`No opencode.jsonc found at ${getGhostOpencodeConfigPath()}. Run 'ocx ghost add' first.`);
14183
+ logger.warn(`No opencode.jsonc found at ${getGhostOpencodeConfigPath()}. Run 'ocx ghost init' first.`);
14155
14184
  }
14156
14185
  const cwd = process.cwd();
14157
14186
  const gitContext = await detectGitRepo(cwd);
@@ -14613,14 +14642,20 @@ async function runInit(options2) {
14613
14642
  const config = ocxConfigSchema.parse(rawConfig);
14614
14643
  const content2 = JSON.stringify(config, null, 2);
14615
14644
  await writeFile3(configPath, content2, "utf-8");
14616
- if (!options2.quiet && !options2.json) {
14617
- logger.success("Initialized OCX configuration");
14618
- }
14645
+ const opencodeResult = await ensureOpencodeConfig(cwd);
14619
14646
  spin?.succeed("Initialized OCX configuration");
14620
14647
  if (options2.json) {
14621
- console.log(JSON.stringify({ success: true, path: configPath }));
14648
+ console.log(JSON.stringify({
14649
+ success: true,
14650
+ path: configPath,
14651
+ opencodePath: opencodeResult.path,
14652
+ opencodeCreated: opencodeResult.created
14653
+ }));
14622
14654
  } else if (!options2.quiet) {
14623
14655
  logger.info(`Created ${configPath}`);
14656
+ if (opencodeResult.created) {
14657
+ logger.info(`Created ${opencodeResult.path}`);
14658
+ }
14624
14659
  logger.info("");
14625
14660
  logger.info("Next steps:");
14626
14661
  logger.info(" 1. Add a registry: ocx registry add <url>");
@@ -15021,7 +15056,7 @@ async function hashBundle2(files) {
15021
15056
  `));
15022
15057
  }
15023
15058
  // src/index.ts
15024
- var version = "1.0.20";
15059
+ var version = "1.0.21";
15025
15060
  async function main2() {
15026
15061
  const program2 = new Command().name("ocx").description("OpenCode Extensions - Install agents, skills, plugins, and commands").version(version);
15027
15062
  registerInitCommand(program2);
@@ -15048,4 +15083,4 @@ export {
15048
15083
  buildRegistry
15049
15084
  };
15050
15085
 
15051
- //# debugId=88A0B09CD885AC2664756E2164756E21
15086
+ //# debugId=4A28ED9CEDFE469F64756E2164756E21