ocx 1.4.1 → 1.4.2
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 +333 -185
- package/dist/index.js.map +16 -17
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -9824,7 +9824,8 @@ var EXIT_CODES = {
|
|
|
9824
9824
|
NOT_FOUND: 66,
|
|
9825
9825
|
NETWORK: 69,
|
|
9826
9826
|
CONFIG: 78,
|
|
9827
|
-
INTEGRITY: 1
|
|
9827
|
+
INTEGRITY: 1,
|
|
9828
|
+
CONFLICT: 6
|
|
9828
9829
|
};
|
|
9829
9830
|
|
|
9830
9831
|
class OCXError extends Error {
|
|
@@ -9868,7 +9869,7 @@ class ValidationError extends OCXError {
|
|
|
9868
9869
|
|
|
9869
9870
|
class ConflictError extends OCXError {
|
|
9870
9871
|
constructor(message) {
|
|
9871
|
-
super(message, "CONFLICT", EXIT_CODES.
|
|
9872
|
+
super(message, "CONFLICT", EXIT_CODES.CONFLICT);
|
|
9872
9873
|
this.name = "ConflictError";
|
|
9873
9874
|
}
|
|
9874
9875
|
}
|
|
@@ -9909,11 +9910,32 @@ class ProfileNotFoundError extends OCXError {
|
|
|
9909
9910
|
|
|
9910
9911
|
class ProfileExistsError extends OCXError {
|
|
9911
9912
|
constructor(name) {
|
|
9912
|
-
super(`Profile "${name}" already exists
|
|
9913
|
+
super(`Profile "${name}" already exists. Use --force to overwrite.`, "CONFLICT", EXIT_CODES.CONFLICT);
|
|
9913
9914
|
this.name = "ProfileExistsError";
|
|
9914
9915
|
}
|
|
9915
9916
|
}
|
|
9916
9917
|
|
|
9918
|
+
class RegistryExistsError extends OCXError {
|
|
9919
|
+
registryName;
|
|
9920
|
+
existingUrl;
|
|
9921
|
+
newUrl;
|
|
9922
|
+
targetLabel;
|
|
9923
|
+
constructor(registryName, existingUrl, newUrl, targetLabel) {
|
|
9924
|
+
const target = targetLabel ? ` in ${targetLabel}` : "";
|
|
9925
|
+
const message = `Registry "${registryName}" already exists${target}.
|
|
9926
|
+
` + ` Current: ${existingUrl}
|
|
9927
|
+
` + ` New: ${newUrl}
|
|
9928
|
+
|
|
9929
|
+
` + `Use --force to overwrite.`;
|
|
9930
|
+
super(message, "CONFLICT", EXIT_CODES.CONFLICT);
|
|
9931
|
+
this.registryName = registryName;
|
|
9932
|
+
this.existingUrl = existingUrl;
|
|
9933
|
+
this.newUrl = newUrl;
|
|
9934
|
+
this.targetLabel = targetLabel;
|
|
9935
|
+
this.name = "RegistryExistsError";
|
|
9936
|
+
}
|
|
9937
|
+
}
|
|
9938
|
+
|
|
9917
9939
|
class InvalidProfileNameError extends OCXError {
|
|
9918
9940
|
constructor(name, reason) {
|
|
9919
9941
|
super(`Invalid profile name "${name}": ${reason}`, "VALIDATION_ERROR", EXIT_CODES.GENERAL);
|
|
@@ -9923,7 +9945,7 @@ class InvalidProfileNameError extends OCXError {
|
|
|
9923
9945
|
|
|
9924
9946
|
class ProfilesNotInitializedError extends OCXError {
|
|
9925
9947
|
constructor() {
|
|
9926
|
-
super("Profiles not initialized. Run 'ocx
|
|
9948
|
+
super("Profiles not initialized. Run 'ocx init --global' first.", "NOT_FOUND", EXIT_CODES.NOT_FOUND);
|
|
9927
9949
|
this.name = "ProfilesNotInitializedError";
|
|
9928
9950
|
}
|
|
9929
9951
|
}
|
|
@@ -10399,7 +10421,7 @@ class GlobalConfigProvider {
|
|
|
10399
10421
|
static async requireInitialized() {
|
|
10400
10422
|
const basePath = getGlobalConfigPath();
|
|
10401
10423
|
if (!await globalDirectoryExists()) {
|
|
10402
|
-
throw new ConfigError("Global config not found. Run '
|
|
10424
|
+
throw new ConfigError("Global config not found. Run 'ocx init --global' first.");
|
|
10403
10425
|
}
|
|
10404
10426
|
const config = await readOcxConfig(basePath);
|
|
10405
10427
|
return new GlobalConfigProvider(basePath, config);
|
|
@@ -10626,7 +10648,25 @@ class ProfileManager {
|
|
|
10626
10648
|
const dir = getProfileDir(name);
|
|
10627
10649
|
await mkdir2(dir, { recursive: true, mode: 448 });
|
|
10628
10650
|
const ocxPath = getProfileOcxConfig(name);
|
|
10629
|
-
|
|
10651
|
+
const ocxFile = Bun.file(ocxPath);
|
|
10652
|
+
if (!await ocxFile.exists()) {
|
|
10653
|
+
await atomicWrite(ocxPath, DEFAULT_OCX_CONFIG);
|
|
10654
|
+
}
|
|
10655
|
+
const opencodePath = getProfileOpencodeConfig(name);
|
|
10656
|
+
const opencodeFile = Bun.file(opencodePath);
|
|
10657
|
+
if (!await opencodeFile.exists()) {
|
|
10658
|
+
await atomicWrite(opencodePath, {});
|
|
10659
|
+
}
|
|
10660
|
+
const agentsPath = getProfileAgents(name);
|
|
10661
|
+
const agentsFile = Bun.file(agentsPath);
|
|
10662
|
+
if (!await agentsFile.exists()) {
|
|
10663
|
+
const agentsContent = `# Profile Instructions
|
|
10664
|
+
|
|
10665
|
+
<!-- Add your custom instructions for this profile here -->
|
|
10666
|
+
<!-- These will be included when running \`ocx opencode -p ${name}\` -->
|
|
10667
|
+
`;
|
|
10668
|
+
await Bun.write(agentsPath, agentsContent, { mode: 384 });
|
|
10669
|
+
}
|
|
10630
10670
|
}
|
|
10631
10671
|
async remove(name) {
|
|
10632
10672
|
if (!await this.exists(name)) {
|
|
@@ -10765,11 +10805,13 @@ class ConfigResolver {
|
|
|
10765
10805
|
}
|
|
10766
10806
|
}
|
|
10767
10807
|
const shouldLoadLocal = this.shouldLoadLocalConfig();
|
|
10768
|
-
if (shouldLoadLocal && this.localConfigDir) {
|
|
10808
|
+
if (!this.profile && shouldLoadLocal && this.localConfigDir) {
|
|
10769
10809
|
const localOcxConfig = this.loadLocalOcxConfig();
|
|
10770
10810
|
if (localOcxConfig) {
|
|
10771
|
-
registries =
|
|
10811
|
+
registries = localOcxConfig.registries;
|
|
10772
10812
|
}
|
|
10813
|
+
}
|
|
10814
|
+
if (shouldLoadLocal && this.localConfigDir) {
|
|
10773
10815
|
const localOpencodeConfig = this.loadLocalOpencodeConfig();
|
|
10774
10816
|
if (localOpencodeConfig) {
|
|
10775
10817
|
opencode = this.deepMerge(opencode, localOpencodeConfig);
|
|
@@ -10810,7 +10852,7 @@ class ConfigResolver {
|
|
|
10810
10852
|
}
|
|
10811
10853
|
}
|
|
10812
10854
|
const shouldLoadLocal = this.shouldLoadLocalConfig();
|
|
10813
|
-
if (shouldLoadLocal && this.localConfigDir) {
|
|
10855
|
+
if (!this.profile && shouldLoadLocal && this.localConfigDir) {
|
|
10814
10856
|
const localOcxConfig = this.loadLocalOcxConfig();
|
|
10815
10857
|
if (localOcxConfig) {
|
|
10816
10858
|
const localOcxPath = join2(this.localConfigDir, OCX_CONFIG_FILE);
|
|
@@ -10819,6 +10861,8 @@ class ConfigResolver {
|
|
|
10819
10861
|
origins.set(`registries.${key}`, { path: localOcxPath, source: "local-config" });
|
|
10820
10862
|
}
|
|
10821
10863
|
}
|
|
10864
|
+
}
|
|
10865
|
+
if (shouldLoadLocal && this.localConfigDir) {
|
|
10822
10866
|
const localOpencodeConfig = this.loadLocalOpencodeConfig();
|
|
10823
10867
|
if (localOpencodeConfig) {
|
|
10824
10868
|
opencode = this.deepMerge(opencode, localOpencodeConfig);
|
|
@@ -10938,7 +10982,7 @@ class ConfigResolver {
|
|
|
10938
10982
|
// package.json
|
|
10939
10983
|
var package_default = {
|
|
10940
10984
|
name: "ocx",
|
|
10941
|
-
version: "1.4.
|
|
10985
|
+
version: "1.4.2",
|
|
10942
10986
|
description: "OCX CLI - ShadCN-style registry for OpenCode extensions. Install agents, plugins, skills, and MCP servers.",
|
|
10943
10987
|
author: "kdcokenny",
|
|
10944
10988
|
license: "MIT",
|
|
@@ -11632,6 +11676,25 @@ function wrapAction(action) {
|
|
|
11632
11676
|
};
|
|
11633
11677
|
}
|
|
11634
11678
|
function formatErrorAsJson(error) {
|
|
11679
|
+
if (error instanceof RegistryExistsError) {
|
|
11680
|
+
return {
|
|
11681
|
+
success: false,
|
|
11682
|
+
error: {
|
|
11683
|
+
code: error.code,
|
|
11684
|
+
message: error.message,
|
|
11685
|
+
details: {
|
|
11686
|
+
registryName: error.registryName,
|
|
11687
|
+
existingUrl: error.existingUrl,
|
|
11688
|
+
newUrl: error.newUrl,
|
|
11689
|
+
...error.targetLabel && { targetLabel: error.targetLabel }
|
|
11690
|
+
}
|
|
11691
|
+
},
|
|
11692
|
+
exitCode: error.exitCode,
|
|
11693
|
+
meta: {
|
|
11694
|
+
timestamp: new Date().toISOString()
|
|
11695
|
+
}
|
|
11696
|
+
};
|
|
11697
|
+
}
|
|
11635
11698
|
if (error instanceof OCXError) {
|
|
11636
11699
|
return {
|
|
11637
11700
|
success: false,
|
|
@@ -11695,6 +11758,7 @@ var sharedOptions = {
|
|
|
11695
11758
|
cwd: () => new Option("--cwd <path>", "Working directory").default(process.cwd()),
|
|
11696
11759
|
quiet: () => new Option("-q, --quiet", "Suppress output"),
|
|
11697
11760
|
json: () => new Option("--json", "Output as JSON"),
|
|
11761
|
+
profile: () => new Option("-p, --profile <name>", "Target a specific profile's config"),
|
|
11698
11762
|
force: () => new Option("-f, --force", "Skip confirmation prompts"),
|
|
11699
11763
|
verbose: () => new Option("-v, --verbose", "Verbose output"),
|
|
11700
11764
|
global: new Option("-g, --global", "Install to global OpenCode config (~/.config/opencode)")
|
|
@@ -11711,6 +11775,20 @@ function addVerboseOption(cmd) {
|
|
|
11711
11775
|
function addGlobalOption(cmd) {
|
|
11712
11776
|
return cmd.addOption(sharedOptions.global);
|
|
11713
11777
|
}
|
|
11778
|
+
function addProfileOption(cmd) {
|
|
11779
|
+
return cmd.addOption(sharedOptions.profile());
|
|
11780
|
+
}
|
|
11781
|
+
function validateProfileName(name) {
|
|
11782
|
+
if (!name || name.length === 0) {
|
|
11783
|
+
throw new InvalidProfileNameError(name, "cannot be empty");
|
|
11784
|
+
}
|
|
11785
|
+
if (name.length > 32) {
|
|
11786
|
+
throw new InvalidProfileNameError(name, "must be 32 characters or less");
|
|
11787
|
+
}
|
|
11788
|
+
if (!/^[a-zA-Z][a-zA-Z0-9._-]*$/.test(name)) {
|
|
11789
|
+
throw new InvalidProfileNameError(name, "must start with a letter and contain only alphanumeric characters, dots, underscores, or hyphens");
|
|
11790
|
+
}
|
|
11791
|
+
}
|
|
11714
11792
|
// ../../node_modules/.bun/ora@8.2.0/node_modules/ora/index.js
|
|
11715
11793
|
import process9 from "process";
|
|
11716
11794
|
|
|
@@ -13861,7 +13939,7 @@ import { existsSync as existsSync6 } from "fs";
|
|
|
13861
13939
|
import { mkdir as mkdir6 } from "fs/promises";
|
|
13862
13940
|
import { join as join6 } from "path";
|
|
13863
13941
|
function registerConfigEditCommand(parent) {
|
|
13864
|
-
parent.command("edit").description("Open configuration file in editor").option("-g, --global", "Edit global ocx.jsonc").action(async (options2) => {
|
|
13942
|
+
parent.command("edit").description("Open configuration file in editor").option("-g, --global", "Edit global ocx.jsonc").option("-p, --profile <name>", "Edit specific profile's config").action(async (options2) => {
|
|
13865
13943
|
try {
|
|
13866
13944
|
await runConfigEdit(options2);
|
|
13867
13945
|
} catch (error) {
|
|
@@ -13870,12 +13948,26 @@ function registerConfigEditCommand(parent) {
|
|
|
13870
13948
|
});
|
|
13871
13949
|
}
|
|
13872
13950
|
async function runConfigEdit(options2) {
|
|
13951
|
+
if (options2.global && options2.profile) {
|
|
13952
|
+
throw new ValidationError("Cannot use both --global and --profile flags");
|
|
13953
|
+
}
|
|
13873
13954
|
let configPath;
|
|
13874
|
-
if (options2.
|
|
13955
|
+
if (options2.profile) {
|
|
13956
|
+
const parseResult = profileNameSchema.safeParse(options2.profile);
|
|
13957
|
+
if (!parseResult.success) {
|
|
13958
|
+
throw new ValidationError(`Invalid profile name "${options2.profile}": ${parseResult.error.errors[0]?.message ?? "Invalid name"}`);
|
|
13959
|
+
}
|
|
13960
|
+
await ProfileManager.requireInitialized();
|
|
13961
|
+
const manager = ProfileManager.create();
|
|
13962
|
+
if (!await manager.exists(options2.profile)) {
|
|
13963
|
+
throw new ProfileNotFoundError(options2.profile);
|
|
13964
|
+
}
|
|
13965
|
+
configPath = getProfileOcxConfig(options2.profile);
|
|
13966
|
+
} else if (options2.global) {
|
|
13875
13967
|
configPath = getGlobalConfig();
|
|
13876
13968
|
if (!existsSync6(configPath)) {
|
|
13877
13969
|
throw new ConfigError(`Global config not found at ${configPath}.
|
|
13878
|
-
|
|
13970
|
+
Run 'ocx init --global' first.`);
|
|
13879
13971
|
}
|
|
13880
13972
|
} else {
|
|
13881
13973
|
const localConfigDir = findLocalConfigDir(process.cwd());
|
|
@@ -15291,34 +15383,90 @@ async function runInit(options2) {
|
|
|
15291
15383
|
}
|
|
15292
15384
|
}
|
|
15293
15385
|
async function runInitGlobal(options2) {
|
|
15294
|
-
const manager = ProfileManager.create();
|
|
15295
|
-
if (await manager.isInitialized()) {
|
|
15296
|
-
const profilesDir = getProfilesDir();
|
|
15297
|
-
throw new ProfileExistsError(`Global profiles already initialized at ${profilesDir}`);
|
|
15298
|
-
}
|
|
15299
15386
|
const spin = options2.quiet ? null : createSpinner({ text: "Initializing global profiles..." });
|
|
15300
15387
|
spin?.start();
|
|
15301
15388
|
try {
|
|
15302
|
-
|
|
15389
|
+
const created = [];
|
|
15390
|
+
const existed = [];
|
|
15391
|
+
const globalConfigPath = getGlobalConfig();
|
|
15392
|
+
if (existsSync8(globalConfigPath)) {
|
|
15393
|
+
existed.push("globalConfig");
|
|
15394
|
+
} else {
|
|
15395
|
+
await mkdir7(dirname3(globalConfigPath), { recursive: true, mode: 448 });
|
|
15396
|
+
await atomicWrite(globalConfigPath, {
|
|
15397
|
+
$schema: OCX_SCHEMA_URL,
|
|
15398
|
+
registries: {}
|
|
15399
|
+
});
|
|
15400
|
+
created.push("globalConfig");
|
|
15401
|
+
}
|
|
15303
15402
|
const profilesDir = getProfilesDir();
|
|
15304
|
-
|
|
15403
|
+
if (!existsSync8(profilesDir)) {
|
|
15404
|
+
await mkdir7(profilesDir, { recursive: true, mode: 448 });
|
|
15405
|
+
}
|
|
15406
|
+
const profileDir = getProfileDir("default");
|
|
15407
|
+
if (!existsSync8(profileDir)) {
|
|
15408
|
+
await mkdir7(profileDir, { recursive: true, mode: 448 });
|
|
15409
|
+
}
|
|
15410
|
+
const ocxPath = getProfileOcxConfig("default");
|
|
15411
|
+
if (existsSync8(ocxPath)) {
|
|
15412
|
+
existed.push("profileOcx");
|
|
15413
|
+
} else {
|
|
15414
|
+
await atomicWrite(ocxPath, DEFAULT_OCX_CONFIG);
|
|
15415
|
+
created.push("profileOcx");
|
|
15416
|
+
}
|
|
15417
|
+
const opencodePath = getProfileOpencodeConfig("default");
|
|
15418
|
+
if (existsSync8(opencodePath)) {
|
|
15419
|
+
existed.push("profileOpencode");
|
|
15420
|
+
} else {
|
|
15421
|
+
await atomicWrite(opencodePath, {});
|
|
15422
|
+
created.push("profileOpencode");
|
|
15423
|
+
}
|
|
15424
|
+
const agentsPath = getProfileAgents("default");
|
|
15425
|
+
if (existsSync8(agentsPath)) {
|
|
15426
|
+
existed.push("profileAgents");
|
|
15427
|
+
} else {
|
|
15428
|
+
const agentsContent = `# Profile Instructions
|
|
15429
|
+
|
|
15430
|
+
<!-- Add your custom instructions for this profile here -->
|
|
15431
|
+
<!-- These will be included when running \`ocx opencode -p default\` -->
|
|
15432
|
+
`;
|
|
15433
|
+
await Bun.write(agentsPath, agentsContent, { mode: 384 });
|
|
15434
|
+
created.push("profileAgents");
|
|
15435
|
+
}
|
|
15305
15436
|
spin?.succeed("Initialized global profiles");
|
|
15306
15437
|
if (options2.json) {
|
|
15307
15438
|
console.log(JSON.stringify({
|
|
15308
15439
|
success: true,
|
|
15309
|
-
|
|
15310
|
-
|
|
15311
|
-
|
|
15440
|
+
files: {
|
|
15441
|
+
globalConfig: globalConfigPath,
|
|
15442
|
+
profileOcx: ocxPath,
|
|
15443
|
+
profileOpencode: opencodePath,
|
|
15444
|
+
profileAgents: agentsPath
|
|
15445
|
+
},
|
|
15446
|
+
created,
|
|
15447
|
+
existed
|
|
15312
15448
|
}));
|
|
15313
15449
|
} else if (!options2.quiet) {
|
|
15314
|
-
|
|
15315
|
-
|
|
15316
|
-
|
|
15317
|
-
|
|
15318
|
-
|
|
15319
|
-
|
|
15320
|
-
|
|
15321
|
-
|
|
15450
|
+
if (created.length > 0) {
|
|
15451
|
+
for (const key of created) {
|
|
15452
|
+
if (key === "globalConfig")
|
|
15453
|
+
logger.info(`Created global config: ${globalConfigPath}`);
|
|
15454
|
+
if (key === "profileOcx")
|
|
15455
|
+
logger.info(`Created profile config: ${ocxPath}`);
|
|
15456
|
+
if (key === "profileOpencode")
|
|
15457
|
+
logger.info(`Created profile opencode config: ${opencodePath}`);
|
|
15458
|
+
if (key === "profileAgents")
|
|
15459
|
+
logger.info(`Created profile instructions: ${agentsPath}`);
|
|
15460
|
+
}
|
|
15461
|
+
logger.info("");
|
|
15462
|
+
logger.info("Next steps:");
|
|
15463
|
+
logger.info(" 1. Edit your profile config: ocx config edit -p default");
|
|
15464
|
+
logger.info(" 2. Add registries: ocx registry add <url> --name <name> --global");
|
|
15465
|
+
logger.info(" 3. Launch OpenCode: ocx opencode");
|
|
15466
|
+
logger.info(" 4. Create more profiles: ocx profile add <name>");
|
|
15467
|
+
} else {
|
|
15468
|
+
logger.info("Global profiles already initialized (all files exist)");
|
|
15469
|
+
}
|
|
15322
15470
|
}
|
|
15323
15471
|
} catch (error) {
|
|
15324
15472
|
spin?.fail("Failed to initialize");
|
|
@@ -15346,7 +15494,7 @@ async function runInitRegistry(directory, options2) {
|
|
|
15346
15494
|
await mkdir7(cwd, { recursive: true });
|
|
15347
15495
|
await copyDir(options2.local, cwd);
|
|
15348
15496
|
} else {
|
|
15349
|
-
const version = options2.canary ? "main" :
|
|
15497
|
+
const version = options2.canary ? "main" : getReleaseTag();
|
|
15350
15498
|
await fetchAndExtractTemplate(cwd, version, options2.verbose);
|
|
15351
15499
|
}
|
|
15352
15500
|
if (spin)
|
|
@@ -15375,15 +15523,16 @@ async function runInitRegistry(directory, options2) {
|
|
|
15375
15523
|
async function copyDir(src, dest) {
|
|
15376
15524
|
await cp(src, dest, { recursive: true });
|
|
15377
15525
|
}
|
|
15378
|
-
|
|
15379
|
-
|
|
15380
|
-
|
|
15381
|
-
const pkg = JSON.parse(pkgContent.toString());
|
|
15382
|
-
return `v${pkg.version}`;
|
|
15526
|
+
function getReleaseTag() {
|
|
15527
|
+
if (false) {}
|
|
15528
|
+
return `v${"1.4.2"}`;
|
|
15383
15529
|
}
|
|
15384
|
-
|
|
15530
|
+
function getTemplateUrl(version) {
|
|
15385
15531
|
const ref = version === "main" ? "heads/main" : `tags/${version}`;
|
|
15386
|
-
|
|
15532
|
+
return `https://github.com/${TEMPLATE_REPO}/archive/refs/${ref}.tar.gz`;
|
|
15533
|
+
}
|
|
15534
|
+
async function fetchAndExtractTemplate(destDir, version, verbose) {
|
|
15535
|
+
const tarballUrl = getTemplateUrl(version);
|
|
15387
15536
|
if (verbose) {
|
|
15388
15537
|
logger.info(`Fetching ${tarballUrl}`);
|
|
15389
15538
|
}
|
|
@@ -15492,6 +15641,18 @@ function formatTerminalName(cwd, profileName, gitInfo) {
|
|
|
15492
15641
|
}
|
|
15493
15642
|
|
|
15494
15643
|
// src/commands/opencode.ts
|
|
15644
|
+
function resolveOpenCodeBinary(opts) {
|
|
15645
|
+
return opts.configBin ?? opts.envBin ?? "opencode";
|
|
15646
|
+
}
|
|
15647
|
+
function buildOpenCodeEnv(opts) {
|
|
15648
|
+
return {
|
|
15649
|
+
...opts.baseEnv,
|
|
15650
|
+
...opts.disableProjectConfig && { OPENCODE_DISABLE_PROJECT_CONFIG: "true" },
|
|
15651
|
+
...opts.profileDir && { OPENCODE_CONFIG_DIR: opts.profileDir },
|
|
15652
|
+
...opts.mergedConfig && { OPENCODE_CONFIG_CONTENT: JSON.stringify(opts.mergedConfig) },
|
|
15653
|
+
...opts.profileName && { OCX_PROFILE: opts.profileName }
|
|
15654
|
+
};
|
|
15655
|
+
}
|
|
15495
15656
|
function registerOpencodeCommand(program2) {
|
|
15496
15657
|
program2.command("opencode [path]").alias("oc").description("Launch OpenCode with resolved configuration").option("-p, --profile <name>", "Use specific profile").option("--no-rename", "Disable terminal/tmux window renaming").addOption(sharedOptions.quiet()).addOption(sharedOptions.json()).allowUnknownOption().allowExcessArguments(true).action(async (path8, options2, command) => {
|
|
15497
15658
|
try {
|
|
@@ -15546,17 +15707,20 @@ async function runOpencode(pathArg, args, options2) {
|
|
|
15546
15707
|
const gitInfo = await getGitInfo(projectDir);
|
|
15547
15708
|
setTerminalName(formatTerminalName(projectDir, config.profileName ?? "default", gitInfo));
|
|
15548
15709
|
}
|
|
15549
|
-
const bin =
|
|
15710
|
+
const bin = resolveOpenCodeBinary({
|
|
15711
|
+
configBin: ocxConfig?.bin,
|
|
15712
|
+
envBin: process.env.OPENCODE_BIN
|
|
15713
|
+
});
|
|
15550
15714
|
proc = Bun.spawn({
|
|
15551
15715
|
cmd: [bin, ...args],
|
|
15552
15716
|
cwd: projectDir,
|
|
15553
|
-
env: {
|
|
15554
|
-
|
|
15555
|
-
|
|
15556
|
-
|
|
15557
|
-
|
|
15558
|
-
|
|
15559
|
-
},
|
|
15717
|
+
env: buildOpenCodeEnv({
|
|
15718
|
+
baseEnv: process.env,
|
|
15719
|
+
profileDir,
|
|
15720
|
+
profileName: config.profileName ?? undefined,
|
|
15721
|
+
mergedConfig: configToPass,
|
|
15722
|
+
disableProjectConfig: true
|
|
15723
|
+
}),
|
|
15560
15724
|
stdin: "inherit",
|
|
15561
15725
|
stdout: "inherit",
|
|
15562
15726
|
stderr: "inherit"
|
|
@@ -15846,14 +16010,14 @@ async function requireGlobalRegistry(namespace) {
|
|
|
15846
16010
|
throw new ConfigError(`Registry "${namespace}" is not configured globally.
|
|
15847
16011
|
|
|
15848
16012
|
` + `Profile installation requires global registry configuration.
|
|
15849
|
-
` + `Run: ocx registry add ${namespace}
|
|
16013
|
+
` + `Run: ocx registry add <url> --name ${namespace} --global`);
|
|
15850
16014
|
}
|
|
15851
16015
|
const registry = globalConfig.registries[namespace];
|
|
15852
16016
|
if (!registry) {
|
|
15853
16017
|
throw new ConfigError(`Registry "${namespace}" is not configured globally.
|
|
15854
16018
|
|
|
15855
16019
|
` + `Profile installation requires global registry configuration.
|
|
15856
|
-
` + `Run: ocx registry add ${namespace}
|
|
16020
|
+
` + `Run: ocx registry add <url> --name ${namespace} --global`);
|
|
15857
16021
|
}
|
|
15858
16022
|
return { config: globalConfig, registryUrl: registry.url };
|
|
15859
16023
|
}
|
|
@@ -15931,33 +16095,6 @@ async function cloneFromLocalProfile(manager, name, sourceName, exists) {
|
|
|
15931
16095
|
logger.success(`Created profile "${name}" (cloned from "${sourceName}")`);
|
|
15932
16096
|
}
|
|
15933
16097
|
|
|
15934
|
-
// src/commands/profile/config.ts
|
|
15935
|
-
function registerProfileConfigCommand(parent) {
|
|
15936
|
-
parent.command("config [name]").description("Open profile ocx.jsonc in editor").action(async (name) => {
|
|
15937
|
-
try {
|
|
15938
|
-
await runProfileConfig(name);
|
|
15939
|
-
} catch (error) {
|
|
15940
|
-
handleError(error);
|
|
15941
|
-
}
|
|
15942
|
-
});
|
|
15943
|
-
}
|
|
15944
|
-
async function runProfileConfig(name) {
|
|
15945
|
-
const manager = await ProfileManager.requireInitialized();
|
|
15946
|
-
const profileName = name ?? await manager.resolveProfile();
|
|
15947
|
-
await manager.get(profileName);
|
|
15948
|
-
const configPath = getProfileOcxConfig(profileName);
|
|
15949
|
-
const editor = process.env.EDITOR || process.env.VISUAL || "vi";
|
|
15950
|
-
const proc = Bun.spawn([editor, configPath], {
|
|
15951
|
-
stdin: "inherit",
|
|
15952
|
-
stdout: "inherit",
|
|
15953
|
-
stderr: "inherit"
|
|
15954
|
-
});
|
|
15955
|
-
const exitCode = await proc.exited;
|
|
15956
|
-
if (exitCode !== 0) {
|
|
15957
|
-
throw new Error(`Editor exited with code ${exitCode}`);
|
|
15958
|
-
}
|
|
15959
|
-
}
|
|
15960
|
-
|
|
15961
16098
|
// src/commands/profile/list.ts
|
|
15962
16099
|
function registerProfileListCommand(parent) {
|
|
15963
16100
|
parent.command("list").alias("ls").description("List all global profiles").addOption(sharedOptions.json()).action(async (options2) => {
|
|
@@ -16044,22 +16181,43 @@ function registerProfileCommand(program2) {
|
|
|
16044
16181
|
registerProfileAddCommand(profile);
|
|
16045
16182
|
registerProfileRemoveCommand(profile);
|
|
16046
16183
|
registerProfileShowCommand(profile);
|
|
16047
|
-
registerProfileConfigCommand(profile);
|
|
16048
16184
|
}
|
|
16049
16185
|
|
|
16050
16186
|
// src/commands/registry.ts
|
|
16187
|
+
import { existsSync as existsSync10 } from "fs";
|
|
16188
|
+
import { dirname as dirname5, join as join9 } from "path";
|
|
16051
16189
|
async function runRegistryAddCore2(url, options2, callbacks) {
|
|
16052
16190
|
if (callbacks.isLocked?.()) {
|
|
16053
16191
|
throw new Error("Registries are locked. Cannot add.");
|
|
16054
16192
|
}
|
|
16055
|
-
const
|
|
16193
|
+
const trimmedUrl = url.trim();
|
|
16194
|
+
if (!trimmedUrl) {
|
|
16195
|
+
throw new ValidationError("Registry URL is required");
|
|
16196
|
+
}
|
|
16197
|
+
let derivedName;
|
|
16198
|
+
try {
|
|
16199
|
+
const parsed = new URL(trimmedUrl);
|
|
16200
|
+
if (!["http:", "https:"].includes(parsed.protocol)) {
|
|
16201
|
+
throw new ValidationError(`Invalid registry URL: ${trimmedUrl} (must use http or https)`);
|
|
16202
|
+
}
|
|
16203
|
+
derivedName = options2.name || parsed.hostname.replace(/\./g, "-");
|
|
16204
|
+
} catch (error) {
|
|
16205
|
+
if (error instanceof ValidationError)
|
|
16206
|
+
throw error;
|
|
16207
|
+
throw new ValidationError(`Invalid registry URL: ${trimmedUrl}`);
|
|
16208
|
+
}
|
|
16209
|
+
const name = derivedName;
|
|
16056
16210
|
const registries = callbacks.getRegistries();
|
|
16211
|
+
const existingRegistry = registries[name];
|
|
16212
|
+
if (existingRegistry && !options2.force) {
|
|
16213
|
+
throw new RegistryExistsError(name, existingRegistry.url, trimmedUrl);
|
|
16214
|
+
}
|
|
16057
16215
|
const isUpdate = name in registries;
|
|
16058
16216
|
await callbacks.setRegistry(name, {
|
|
16059
|
-
url,
|
|
16217
|
+
url: trimmedUrl,
|
|
16060
16218
|
version: options2.version
|
|
16061
16219
|
});
|
|
16062
|
-
return { name, url, updated: isUpdate };
|
|
16220
|
+
return { name, url: trimmedUrl, updated: isUpdate };
|
|
16063
16221
|
}
|
|
16064
16222
|
async function runRegistryRemoveCore(name, callbacks) {
|
|
16065
16223
|
if (callbacks.isLocked?.()) {
|
|
@@ -16082,43 +16240,69 @@ function runRegistryListCore(callbacks) {
|
|
|
16082
16240
|
}));
|
|
16083
16241
|
return { registries: list, locked };
|
|
16084
16242
|
}
|
|
16243
|
+
async function resolveRegistryTarget(options2, command, cwd) {
|
|
16244
|
+
const cwdExplicitlyProvided = command.getOptionValueSource("cwd") === "cli";
|
|
16245
|
+
if (options2.global && options2.profile) {
|
|
16246
|
+
throw new ValidationError("Cannot use both --global and --profile flags");
|
|
16247
|
+
}
|
|
16248
|
+
if (cwdExplicitlyProvided && options2.profile) {
|
|
16249
|
+
throw new ValidationError("Cannot use both --cwd and --profile flags");
|
|
16250
|
+
}
|
|
16251
|
+
if (options2.global && cwdExplicitlyProvided) {
|
|
16252
|
+
throw new ValidationError("Cannot use both --global and --cwd flags");
|
|
16253
|
+
}
|
|
16254
|
+
if (options2.profile) {
|
|
16255
|
+
validateProfileName(options2.profile);
|
|
16256
|
+
const manager = await ProfileManager.requireInitialized();
|
|
16257
|
+
if (!await manager.exists(options2.profile)) {
|
|
16258
|
+
throw new ProfileNotFoundError(options2.profile);
|
|
16259
|
+
}
|
|
16260
|
+
const configPath = getProfileOcxConfig(options2.profile);
|
|
16261
|
+
if (!existsSync10(configPath)) {
|
|
16262
|
+
throw new OcxConfigError(`Profile '${options2.profile}' has no ocx.jsonc. Run 'ocx profile config ${options2.profile}' to create it.`);
|
|
16263
|
+
}
|
|
16264
|
+
return {
|
|
16265
|
+
scope: "profile",
|
|
16266
|
+
configPath,
|
|
16267
|
+
configDir: dirname5(configPath),
|
|
16268
|
+
targetLabel: `profile '${options2.profile}' config`
|
|
16269
|
+
};
|
|
16270
|
+
}
|
|
16271
|
+
if (options2.global) {
|
|
16272
|
+
const configDir = getGlobalConfigPath();
|
|
16273
|
+
return {
|
|
16274
|
+
scope: "global",
|
|
16275
|
+
configPath: join9(configDir, "ocx.jsonc"),
|
|
16276
|
+
configDir,
|
|
16277
|
+
targetLabel: "global config"
|
|
16278
|
+
};
|
|
16279
|
+
}
|
|
16280
|
+
const found = findOcxConfig(cwd);
|
|
16281
|
+
return {
|
|
16282
|
+
scope: "local",
|
|
16283
|
+
configPath: found.path,
|
|
16284
|
+
configDir: found.exists ? dirname5(found.path) : join9(cwd, ".opencode"),
|
|
16285
|
+
targetLabel: "local config"
|
|
16286
|
+
};
|
|
16287
|
+
}
|
|
16085
16288
|
function registerRegistryCommand(program2) {
|
|
16086
16289
|
const registry = program2.command("registry").description("Manage registries");
|
|
16087
|
-
const addCmd = registry.command("add").description("Add a registry").argument("<url>", "Registry URL").option("--name <name>", "Registry alias (defaults to hostname)").option("--version <version>", "Pin to specific version");
|
|
16290
|
+
const addCmd = registry.command("add").description("Add a registry").argument("<url>", "Registry URL").option("--name <name>", "Registry alias (defaults to hostname)").option("--version <version>", "Pin to specific version").option("-f, --force", "Overwrite existing registry");
|
|
16088
16291
|
addGlobalOption(addCmd);
|
|
16292
|
+
addProfileOption(addCmd);
|
|
16089
16293
|
addCommonOptions(addCmd);
|
|
16090
16294
|
addCmd.action(async (url, options2, command) => {
|
|
16295
|
+
let target;
|
|
16091
16296
|
try {
|
|
16092
|
-
const
|
|
16093
|
-
|
|
16094
|
-
|
|
16297
|
+
const cwd = options2.cwd ?? process.cwd();
|
|
16298
|
+
target = await resolveRegistryTarget(options2, command, cwd);
|
|
16299
|
+
const { configDir, configPath } = target;
|
|
16300
|
+
const config = await readOcxConfig(configDir);
|
|
16301
|
+
if (!config) {
|
|
16302
|
+
const initHint = target.scope === "global" ? "Run 'ocx init --global' first." : target.scope === "profile" ? `Run 'ocx profile config ${options2.profile}' to create it.` : "Run 'ocx init' first.";
|
|
16303
|
+
logger.error(`${target.targetLabel} not found. ${initHint}`);
|
|
16095
16304
|
process.exit(1);
|
|
16096
16305
|
}
|
|
16097
|
-
let configDir;
|
|
16098
|
-
let configPath;
|
|
16099
|
-
const config = await (async () => {
|
|
16100
|
-
if (options2.global) {
|
|
16101
|
-
configDir = getGlobalConfigPath();
|
|
16102
|
-
const found = findOcxConfig(configDir);
|
|
16103
|
-
configPath = found.path;
|
|
16104
|
-
const cfg = await readOcxConfig(configDir);
|
|
16105
|
-
if (!cfg) {
|
|
16106
|
-
logger.error("Global config not found. Run 'opencode' once to initialize.");
|
|
16107
|
-
process.exit(1);
|
|
16108
|
-
}
|
|
16109
|
-
return cfg;
|
|
16110
|
-
} else {
|
|
16111
|
-
configDir = options2.cwd ?? process.cwd();
|
|
16112
|
-
const found = findOcxConfig(configDir);
|
|
16113
|
-
configPath = found.path;
|
|
16114
|
-
const cfg = await readOcxConfig(configDir);
|
|
16115
|
-
if (!cfg) {
|
|
16116
|
-
logger.error("No ocx.jsonc found. Run 'ocx init' first.");
|
|
16117
|
-
process.exit(1);
|
|
16118
|
-
}
|
|
16119
|
-
return cfg;
|
|
16120
|
-
}
|
|
16121
|
-
})();
|
|
16122
16306
|
const result = await runRegistryAddCore2(url, options2, {
|
|
16123
16307
|
getRegistries: () => config.registries,
|
|
16124
16308
|
isLocked: () => config.lockRegistries ?? false,
|
|
@@ -16130,65 +16314,46 @@ function registerRegistryCommand(program2) {
|
|
|
16130
16314
|
if (options2.json) {
|
|
16131
16315
|
outputJson({ success: true, data: result });
|
|
16132
16316
|
} else if (!options2.quiet) {
|
|
16133
|
-
const location = options2.global ? "global config" : "local config";
|
|
16134
16317
|
if (result.updated) {
|
|
16135
|
-
logger.success(`Updated registry in ${
|
|
16318
|
+
logger.success(`Updated registry in ${target.targetLabel}: ${result.name} -> ${result.url}`);
|
|
16136
16319
|
} else {
|
|
16137
|
-
logger.success(`Added registry to ${
|
|
16320
|
+
logger.success(`Added registry to ${target.targetLabel}: ${result.name} -> ${result.url}`);
|
|
16138
16321
|
}
|
|
16139
16322
|
}
|
|
16140
16323
|
} catch (error) {
|
|
16324
|
+
if (error instanceof RegistryExistsError && !error.targetLabel) {
|
|
16325
|
+
const enrichedError = new RegistryExistsError(error.registryName, error.existingUrl, error.newUrl, target?.targetLabel ?? "config");
|
|
16326
|
+
handleError(enrichedError, { json: options2.json });
|
|
16327
|
+
}
|
|
16141
16328
|
handleError(error, { json: options2.json });
|
|
16142
16329
|
}
|
|
16143
16330
|
});
|
|
16144
16331
|
const removeCmd = registry.command("remove").description("Remove a registry").argument("<name>", "Registry name");
|
|
16145
16332
|
addGlobalOption(removeCmd);
|
|
16333
|
+
addProfileOption(removeCmd);
|
|
16146
16334
|
addCommonOptions(removeCmd);
|
|
16147
16335
|
removeCmd.action(async (name, options2, command) => {
|
|
16148
16336
|
try {
|
|
16149
|
-
const
|
|
16150
|
-
|
|
16151
|
-
|
|
16337
|
+
const cwd = options2.cwd ?? process.cwd();
|
|
16338
|
+
const target = await resolveRegistryTarget(options2, command, cwd);
|
|
16339
|
+
const config = await readOcxConfig(target.configDir);
|
|
16340
|
+
if (!config) {
|
|
16341
|
+
const initHint = target.scope === "global" ? "Run 'ocx init --global' first." : target.scope === "profile" ? `Run 'ocx profile config ${options2.profile}' to create it.` : "Run 'ocx init' first.";
|
|
16342
|
+
logger.error(`${target.targetLabel} not found. ${initHint}`);
|
|
16152
16343
|
process.exit(1);
|
|
16153
16344
|
}
|
|
16154
|
-
let configDir;
|
|
16155
|
-
let configPath;
|
|
16156
|
-
const config = await (async () => {
|
|
16157
|
-
if (options2.global) {
|
|
16158
|
-
configDir = getGlobalConfigPath();
|
|
16159
|
-
const found = findOcxConfig(configDir);
|
|
16160
|
-
configPath = found.path;
|
|
16161
|
-
const cfg = await readOcxConfig(configDir);
|
|
16162
|
-
if (!cfg) {
|
|
16163
|
-
logger.error("Global config not found. Run 'opencode' once to initialize.");
|
|
16164
|
-
process.exit(1);
|
|
16165
|
-
}
|
|
16166
|
-
return cfg;
|
|
16167
|
-
} else {
|
|
16168
|
-
configDir = options2.cwd ?? process.cwd();
|
|
16169
|
-
const found = findOcxConfig(configDir);
|
|
16170
|
-
configPath = found.path;
|
|
16171
|
-
const cfg = await readOcxConfig(configDir);
|
|
16172
|
-
if (!cfg) {
|
|
16173
|
-
logger.error("No ocx.jsonc found. Run 'ocx init' first.");
|
|
16174
|
-
process.exit(1);
|
|
16175
|
-
}
|
|
16176
|
-
return cfg;
|
|
16177
|
-
}
|
|
16178
|
-
})();
|
|
16179
16345
|
const result = await runRegistryRemoveCore(name, {
|
|
16180
16346
|
getRegistries: () => config.registries,
|
|
16181
16347
|
isLocked: () => config.lockRegistries ?? false,
|
|
16182
16348
|
removeRegistry: async (regName) => {
|
|
16183
16349
|
delete config.registries[regName];
|
|
16184
|
-
await writeOcxConfig(configDir, config, configPath);
|
|
16350
|
+
await writeOcxConfig(target.configDir, config, target.configPath);
|
|
16185
16351
|
}
|
|
16186
16352
|
});
|
|
16187
16353
|
if (options2.json) {
|
|
16188
16354
|
outputJson({ success: true, data: result });
|
|
16189
16355
|
} else if (!options2.quiet) {
|
|
16190
|
-
|
|
16191
|
-
logger.success(`Removed registry from ${location}: ${result.removed}`);
|
|
16356
|
+
logger.success(`Removed registry from ${target.targetLabel}: ${result.removed}`);
|
|
16192
16357
|
}
|
|
16193
16358
|
} catch (error) {
|
|
16194
16359
|
handleError(error, { json: options2.json });
|
|
@@ -16196,36 +16361,18 @@ function registerRegistryCommand(program2) {
|
|
|
16196
16361
|
});
|
|
16197
16362
|
const listCmd = registry.command("list").description("List configured registries");
|
|
16198
16363
|
addGlobalOption(listCmd);
|
|
16364
|
+
addProfileOption(listCmd);
|
|
16199
16365
|
addCommonOptions(listCmd);
|
|
16200
16366
|
listCmd.action(async (options2, command) => {
|
|
16201
16367
|
try {
|
|
16202
|
-
const
|
|
16203
|
-
|
|
16204
|
-
|
|
16205
|
-
|
|
16206
|
-
|
|
16207
|
-
|
|
16208
|
-
const config = await (async () => {
|
|
16209
|
-
if (options2.global) {
|
|
16210
|
-
configDir = getGlobalConfigPath();
|
|
16211
|
-
const cfg = await readOcxConfig(configDir);
|
|
16212
|
-
if (!cfg) {
|
|
16213
|
-
logger.warn("Global config not found. Run 'opencode' once to initialize.");
|
|
16214
|
-
return null;
|
|
16215
|
-
}
|
|
16216
|
-
return cfg;
|
|
16217
|
-
} else {
|
|
16218
|
-
configDir = options2.cwd ?? process.cwd();
|
|
16219
|
-
const cfg = await readOcxConfig(configDir);
|
|
16220
|
-
if (!cfg) {
|
|
16221
|
-
logger.warn("No ocx.jsonc found. Run 'ocx init' first.");
|
|
16222
|
-
return null;
|
|
16223
|
-
}
|
|
16224
|
-
return cfg;
|
|
16225
|
-
}
|
|
16226
|
-
})();
|
|
16227
|
-
if (!config)
|
|
16368
|
+
const cwd = options2.cwd ?? process.cwd();
|
|
16369
|
+
const target = await resolveRegistryTarget(options2, command, cwd);
|
|
16370
|
+
const config = await readOcxConfig(target.configDir);
|
|
16371
|
+
if (!config) {
|
|
16372
|
+
const initHint = target.scope === "global" ? "Run 'ocx init --global' first." : target.scope === "profile" ? `Run 'ocx profile config ${options2.profile}' to create it.` : "Run 'ocx init' first.";
|
|
16373
|
+
logger.warn(`${target.targetLabel} not found. ${initHint}`);
|
|
16228
16374
|
return;
|
|
16375
|
+
}
|
|
16229
16376
|
const result = runRegistryListCore({
|
|
16230
16377
|
getRegistries: () => config.registries,
|
|
16231
16378
|
isLocked: () => config.lockRegistries ?? false
|
|
@@ -16236,7 +16383,8 @@ function registerRegistryCommand(program2) {
|
|
|
16236
16383
|
if (result.registries.length === 0) {
|
|
16237
16384
|
logger.info("No registries configured.");
|
|
16238
16385
|
} else {
|
|
16239
|
-
|
|
16386
|
+
const scopeLabel = target.scope === "global" ? " (global)" : target.scope === "profile" ? ` (profile '${options2.profile}')` : "";
|
|
16387
|
+
logger.info(`Configured registries${scopeLabel}${result.locked ? kleur_default.yellow(" (locked)") : ""}:`);
|
|
16240
16388
|
for (const reg of result.registries) {
|
|
16241
16389
|
console.log(` ${kleur_default.cyan(reg.name)}: ${reg.url} ${kleur_default.dim(`(${reg.version})`)}`);
|
|
16242
16390
|
}
|
|
@@ -16371,7 +16519,7 @@ async function runSearchCore(query, options2, provider) {
|
|
|
16371
16519
|
|
|
16372
16520
|
// src/self-update/version-provider.ts
|
|
16373
16521
|
class BuildTimeVersionProvider {
|
|
16374
|
-
version = "1.4.
|
|
16522
|
+
version = "1.4.2";
|
|
16375
16523
|
}
|
|
16376
16524
|
var defaultVersionProvider = new BuildTimeVersionProvider;
|
|
16377
16525
|
|
|
@@ -16484,7 +16632,7 @@ function getExecutablePath() {
|
|
|
16484
16632
|
}
|
|
16485
16633
|
|
|
16486
16634
|
// src/self-update/download.ts
|
|
16487
|
-
import { chmodSync, existsSync as
|
|
16635
|
+
import { chmodSync, existsSync as existsSync11, renameSync as renameSync2, unlinkSync as unlinkSync2 } from "fs";
|
|
16488
16636
|
var GITHUB_REPO2 = "kdcokenny/ocx";
|
|
16489
16637
|
var DEFAULT_DOWNLOAD_BASE_URL = `https://github.com/${GITHUB_REPO2}/releases/download`;
|
|
16490
16638
|
var PLATFORM_MAP = {
|
|
@@ -16562,7 +16710,7 @@ async function downloadToTemp(version) {
|
|
|
16562
16710
|
try {
|
|
16563
16711
|
chmodSync(tempPath, 493);
|
|
16564
16712
|
} catch (error) {
|
|
16565
|
-
if (
|
|
16713
|
+
if (existsSync11(tempPath)) {
|
|
16566
16714
|
unlinkSync2(tempPath);
|
|
16567
16715
|
}
|
|
16568
16716
|
throw new SelfUpdateError(`Failed to set permissions: ${error instanceof Error ? error.message : String(error)}`);
|
|
@@ -16572,20 +16720,20 @@ async function downloadToTemp(version) {
|
|
|
16572
16720
|
function atomicReplace(tempPath, execPath) {
|
|
16573
16721
|
const backupPath = `${execPath}.backup`;
|
|
16574
16722
|
try {
|
|
16575
|
-
if (
|
|
16723
|
+
if (existsSync11(execPath)) {
|
|
16576
16724
|
renameSync2(execPath, backupPath);
|
|
16577
16725
|
}
|
|
16578
16726
|
renameSync2(tempPath, execPath);
|
|
16579
|
-
if (
|
|
16727
|
+
if (existsSync11(backupPath)) {
|
|
16580
16728
|
unlinkSync2(backupPath);
|
|
16581
16729
|
}
|
|
16582
16730
|
} catch (error) {
|
|
16583
|
-
if (
|
|
16731
|
+
if (existsSync11(backupPath) && !existsSync11(execPath)) {
|
|
16584
16732
|
try {
|
|
16585
16733
|
renameSync2(backupPath, execPath);
|
|
16586
16734
|
} catch {}
|
|
16587
16735
|
}
|
|
16588
|
-
if (
|
|
16736
|
+
if (existsSync11(tempPath)) {
|
|
16589
16737
|
try {
|
|
16590
16738
|
unlinkSync2(tempPath);
|
|
16591
16739
|
} catch {}
|
|
@@ -16594,7 +16742,7 @@ function atomicReplace(tempPath, execPath) {
|
|
|
16594
16742
|
}
|
|
16595
16743
|
}
|
|
16596
16744
|
function cleanupTempFile(tempPath) {
|
|
16597
|
-
if (
|
|
16745
|
+
if (existsSync11(tempPath)) {
|
|
16598
16746
|
try {
|
|
16599
16747
|
unlinkSync2(tempPath);
|
|
16600
16748
|
} catch {}
|
|
@@ -16770,9 +16918,9 @@ function registerSelfCommand(program2) {
|
|
|
16770
16918
|
|
|
16771
16919
|
// src/commands/update.ts
|
|
16772
16920
|
import { createHash as createHash4 } from "crypto";
|
|
16773
|
-
import { existsSync as
|
|
16921
|
+
import { existsSync as existsSync12 } from "fs";
|
|
16774
16922
|
import { mkdir as mkdir9, writeFile as writeFile4 } from "fs/promises";
|
|
16775
|
-
import { dirname as
|
|
16923
|
+
import { dirname as dirname6, join as join10 } from "path";
|
|
16776
16924
|
function registerUpdateCommand(program2) {
|
|
16777
16925
|
program2.command("update [components...]").description("Update installed components (use @version suffix to pin, e.g., kdco/agents@1.2.0)").option("--all", "Update all installed components").option("--registry <name>", "Update all components from a specific registry").option("--dry-run", "Preview changes without applying").option("--cwd <path>", "Working directory", process.cwd()).option("-q, --quiet", "Suppress output").option("-v, --verbose", "Verbose output").option("--json", "Output as JSON").action(async (components, options2) => {
|
|
16778
16926
|
try {
|
|
@@ -16910,9 +17058,9 @@ Version cannot be empty. Use 'kdco/agents@1.2.0' or omit the version for latest.
|
|
|
16910
17058
|
const fileObj = update.component.files.find((f) => f.path === file.path);
|
|
16911
17059
|
if (!fileObj)
|
|
16912
17060
|
continue;
|
|
16913
|
-
const targetPath =
|
|
16914
|
-
const targetDir =
|
|
16915
|
-
if (!
|
|
17061
|
+
const targetPath = join10(provider.cwd, fileObj.target);
|
|
17062
|
+
const targetDir = dirname6(targetPath);
|
|
17063
|
+
if (!existsSync12(targetDir)) {
|
|
16916
17064
|
await mkdir9(targetDir, { recursive: true });
|
|
16917
17065
|
}
|
|
16918
17066
|
await writeFile4(targetPath, file.content);
|
|
@@ -17076,7 +17224,7 @@ function registerUpdateCheckHook(program2) {
|
|
|
17076
17224
|
});
|
|
17077
17225
|
}
|
|
17078
17226
|
// src/index.ts
|
|
17079
|
-
var version = "1.4.
|
|
17227
|
+
var version = "1.4.2";
|
|
17080
17228
|
async function main2() {
|
|
17081
17229
|
const program2 = new Command().name("ocx").description("OpenCode Extensions - Install agents, skills, plugins, and commands").version(version);
|
|
17082
17230
|
registerInitCommand(program2);
|
|
@@ -17108,4 +17256,4 @@ export {
|
|
|
17108
17256
|
buildRegistry
|
|
17109
17257
|
};
|
|
17110
17258
|
|
|
17111
|
-
//# debugId=
|
|
17259
|
+
//# debugId=52AD8D268EBA9E8864756E2164756E21
|