@x-all-in-one/coding-helper 0.0.4 → 0.0.6

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.
@@ -1,3 +1,11 @@
1
+ export interface OhMyOpenCodeConfig {
2
+ $schema?: string;
3
+ agents?: Record<string, {
4
+ model?: string;
5
+ [key: string]: any;
6
+ }>;
7
+ [key: string]: any;
8
+ }
1
9
  export declare const OPENCODE_DEFAULT_CONFIG: {
2
10
  BASE_URL: string;
3
11
  PROVIDER_NAME: string;
@@ -50,6 +58,7 @@ export interface OpenCodeModelConfig {
50
58
  export declare class OpenCodeManager {
51
59
  private static instance;
52
60
  private configPath;
61
+ private ohMyOpenCodeConfigPath;
53
62
  private cachedModels;
54
63
  private constructor();
55
64
  static getInstance(): OpenCodeManager;
@@ -89,5 +98,22 @@ export declare class OpenCodeManager {
89
98
  * Clear model config (only remove xaio provider)
90
99
  */
91
100
  clearModelConfig(): void;
101
+ /**
102
+ * Check if oh-my-opencode plugin is installed in opencode.json
103
+ */
104
+ hasOhMyOpenCodePlugin(): boolean;
105
+ /**
106
+ * Get oh-my-opencode config
107
+ */
108
+ getOhMyOpenCodeConfig(): OhMyOpenCodeConfig;
109
+ /**
110
+ * Save oh-my-opencode config
111
+ */
112
+ saveOhMyOpenCodeConfig(config: OhMyOpenCodeConfig): void;
113
+ /**
114
+ * Update oh-my-opencode agent models
115
+ * Only updates the model field, preserves other agent configurations
116
+ */
117
+ updateOhMyOpenCodeModels(model: string): void;
92
118
  }
93
119
  export declare const openCodeManager: OpenCodeManager;
@@ -3,11 +3,21 @@ import { homedir } from 'node:os';
3
3
  import { dirname, join } from 'node:path';
4
4
  // X-AIO Provider ID
5
5
  const XAIO_PROVIDER_ID = 'xaio';
6
+ // oh-my-opencode agent names
7
+ const OH_MY_OPENCODE_AGENTS = [
8
+ 'Sisyphus',
9
+ 'librarian',
10
+ 'explore',
11
+ 'oracle',
12
+ 'frontend-ui-ux-engineer',
13
+ 'document-writer',
14
+ 'multimodal-looker',
15
+ ];
6
16
  // Default configuration
7
17
  export const OPENCODE_DEFAULT_CONFIG = {
8
18
  BASE_URL: 'https://code-api.x-aio.com/v1',
9
19
  PROVIDER_NAME: 'Coding Plan By X-AIO',
10
- DEFAULT_MODEL: 'MiniMax-M2',
20
+ DEFAULT_MODEL: 'MiniMax-M2.1',
11
21
  DEFAULT_SMALL_MODEL: 'Qwen3-Coder-30B-A3B-Instruct',
12
22
  // Default limits (hardcoded for v1, will be fetched from API in future)
13
23
  DEFAULT_CONTEXT: 128000,
@@ -19,12 +29,15 @@ export const OPENCODE_DEFAULT_CONFIG = {
19
29
  export class OpenCodeManager {
20
30
  static instance;
21
31
  configPath;
32
+ ohMyOpenCodeConfigPath;
22
33
  cachedModels = [];
23
34
  constructor() {
24
35
  // OpenCode config file paths (cross-platform support)
25
36
  // - macOS/Linux: ~/.config/opencode/opencode.json
26
37
  // - Windows: %USERPROFILE%\.config\opencode\opencode.json
27
38
  this.configPath = join(homedir(), '.config', 'opencode', 'opencode.json');
39
+ // oh-my-opencode config path
40
+ this.ohMyOpenCodeConfigPath = join(homedir(), '.config', 'opencode', 'oh-my-opencode.json');
28
41
  }
29
42
  static getInstance() {
30
43
  if (!OpenCodeManager.instance) {
@@ -234,5 +247,76 @@ export class OpenCodeManager {
234
247
  }
235
248
  this.saveConfig(currentConfig);
236
249
  }
250
+ /**
251
+ * Check if oh-my-opencode plugin is installed in opencode.json
252
+ */
253
+ hasOhMyOpenCodePlugin() {
254
+ try {
255
+ const config = this.getConfig();
256
+ if (config.plugin && Array.isArray(config.plugin)) {
257
+ return config.plugin.some((p) => typeof p === 'string' && p.startsWith('oh-my-opencode'));
258
+ }
259
+ return false;
260
+ }
261
+ catch {
262
+ return false;
263
+ }
264
+ }
265
+ /**
266
+ * Get oh-my-opencode config
267
+ */
268
+ getOhMyOpenCodeConfig() {
269
+ try {
270
+ if (existsSync(this.ohMyOpenCodeConfigPath)) {
271
+ const content = readFileSync(this.ohMyOpenCodeConfigPath, 'utf-8');
272
+ return JSON.parse(content);
273
+ }
274
+ }
275
+ catch (error) {
276
+ console.warn('Failed to read oh-my-opencode config:', error);
277
+ }
278
+ return {};
279
+ }
280
+ /**
281
+ * Save oh-my-opencode config
282
+ */
283
+ saveOhMyOpenCodeConfig(config) {
284
+ try {
285
+ this.ensureDir(this.ohMyOpenCodeConfigPath);
286
+ writeFileSync(this.ohMyOpenCodeConfigPath, JSON.stringify(config, null, 2), 'utf-8');
287
+ }
288
+ catch (error) {
289
+ throw new Error(`Failed to save oh-my-opencode config: ${error}`);
290
+ }
291
+ }
292
+ /**
293
+ * Update oh-my-opencode agent models
294
+ * Only updates the model field, preserves other agent configurations
295
+ */
296
+ updateOhMyOpenCodeModels(model) {
297
+ const prefixedModel = `${XAIO_PROVIDER_ID}/${model}`;
298
+ // Read existing config or create new one
299
+ const currentConfig = this.getOhMyOpenCodeConfig();
300
+ // Initialize agents if not exists
301
+ if (!currentConfig.agents) {
302
+ currentConfig.agents = {};
303
+ }
304
+ // Update each agent's model, preserving other settings
305
+ for (const agentName of OH_MY_OPENCODE_AGENTS) {
306
+ if (currentConfig.agents[agentName]) {
307
+ // Agent exists, only update model
308
+ currentConfig.agents[agentName].model = prefixedModel;
309
+ }
310
+ else {
311
+ // Agent doesn't exist, create with only model
312
+ currentConfig.agents[agentName] = { model: prefixedModel };
313
+ }
314
+ }
315
+ // Ensure schema is set
316
+ if (!currentConfig.$schema) {
317
+ currentConfig.$schema = 'https://raw.githubusercontent.com/code-yeongyu/oh-my-opencode/master/assets/oh-my-opencode.schema.json';
318
+ }
319
+ this.saveOhMyOpenCodeConfig(currentConfig);
320
+ }
237
321
  }
238
322
  export const openCodeManager = OpenCodeManager.getInstance();
@@ -20,7 +20,7 @@ export const SUPPORTED_TOOLS = {
20
20
  'opencode': {
21
21
  name: 'opencode',
22
22
  command: 'opencode',
23
- installCommand: 'npm install -g opencode',
23
+ installCommand: 'npm install -g opencode-ai',
24
24
  configPath: join(homedir(), '.config', 'opencode', 'opencode.json'),
25
25
  displayName: 'OpenCode',
26
26
  },
@@ -42,6 +42,8 @@ export declare class Wizard {
42
42
  showMainMenu(): Promise<void>;
43
43
  openOfficialWebsite(): Promise<void>;
44
44
  showToolMenu(toolName: any): Promise<void>;
45
+ installOhMyOpenCode(): Promise<void>;
46
+ installBun(): Promise<boolean>;
45
47
  startTool(toolName: any): Promise<void>;
46
48
  loadModelConfig(toolName: any): Promise<void>;
47
49
  unloadModelConfig(toolName: any): Promise<void>;
@@ -718,6 +718,10 @@ export class Wizard {
718
718
  if (detectedConfig) {
719
719
  choices.push({ name: `> ${i18n.t('wizard.start_tool', { tool: SUPPORTED_TOOLS[toolName].displayName, shell: SUPPORTED_TOOLS[toolName].command })}`, value: 'start_tool' });
720
720
  }
721
+ // Add oh-my-opencode install option for OpenCode only
722
+ if (toolName === 'opencode' && detectedConfig) {
723
+ choices.push({ name: `> ${i18n.t('wizard.action_install_oh_my_opencode')}`, value: 'install_oh_my_opencode' });
724
+ }
721
725
  choices.push(new inquirer.Separator(), { name: `<- ${i18n.t('wizard.nav_return')}`, value: 'back' }, { name: `x ${i18n.t('wizard.nav_exit')}`, value: 'exit' });
722
726
  const { action } = await this.promptWithHints([
723
727
  {
@@ -725,6 +729,7 @@ export class Wizard {
725
729
  name: 'action',
726
730
  message: i18n.t('wizard.select_action'),
727
731
  choices,
732
+ pageSize: 15,
728
733
  },
729
734
  ]);
730
735
  if (action === 'exit') {
@@ -746,7 +751,132 @@ export class Wizard {
746
751
  else if (action === 'start_tool') {
747
752
  await this.startTool(toolName);
748
753
  }
754
+ else if (action === 'install_oh_my_opencode') {
755
+ await this.installOhMyOpenCode();
756
+ }
757
+ }
758
+ }
759
+ async installOhMyOpenCode() {
760
+ const { spawn, execSync } = await import('node:child_process');
761
+ // Check if bun is available (oh-my-opencode requires bun)
762
+ const isWindows = process.platform === 'win32';
763
+ let hasBun = false;
764
+ try {
765
+ execSync(isWindows ? 'where bun' : 'which bun', { stdio: 'ignore' });
766
+ hasBun = true;
767
+ }
768
+ catch {
769
+ hasBun = false;
770
+ }
771
+ if (!hasBun) {
772
+ console.log(chalk.yellow(`\n⚠️ ${i18n.t('wizard.oh_my_opencode_requires_bun')}`));
773
+ // Ask user if they want to install bun
774
+ const { installBun } = await this.promptWithHints([
775
+ {
776
+ type: 'confirm',
777
+ name: 'installBun',
778
+ message: i18n.t('wizard.bun_install_confirm'),
779
+ default: true,
780
+ },
781
+ ]);
782
+ if (!installBun) {
783
+ console.log(chalk.gray(`\n${i18n.t('wizard.bun_install_skipped')}`));
784
+ console.log(chalk.cyan(` ${i18n.t('wizard.bun_install_hint')}`));
785
+ console.log(chalk.blue(' https://bun.sh/docs/installation\n'));
786
+ await this.promptWithHints([
787
+ {
788
+ type: 'input',
789
+ name: 'continue',
790
+ message: i18n.t('wizard.press_enter'),
791
+ },
792
+ ]);
793
+ return;
794
+ }
795
+ // Install bun
796
+ const bunInstalled = await this.installBun();
797
+ if (!bunInstalled) {
798
+ return;
799
+ }
749
800
  }
801
+ console.log(chalk.cyan(`\n${i18n.t('wizard.oh_my_opencode_installing')}\n`));
802
+ return new Promise((resolve) => {
803
+ // Use bunx since oh-my-opencode requires bun
804
+ const command = isWindows ? 'bunx.cmd' : 'bunx';
805
+ const args = ['oh-my-opencode', 'install'];
806
+ const child = spawn(command, args, {
807
+ stdio: 'inherit',
808
+ shell: true,
809
+ });
810
+ child.on('close', (code) => {
811
+ if (code === 0) {
812
+ console.log(chalk.green(`\n✅ ${i18n.t('wizard.oh_my_opencode_installed')}`));
813
+ }
814
+ else {
815
+ console.log(chalk.red(`\n❌ ${i18n.t('wizard.oh_my_opencode_install_failed')}`));
816
+ }
817
+ resolve();
818
+ });
819
+ child.on('error', (error) => {
820
+ console.error(chalk.red(`\n❌ ${i18n.t('wizard.oh_my_opencode_install_failed')}`));
821
+ console.error(error);
822
+ resolve();
823
+ });
824
+ });
825
+ }
826
+ async installBun() {
827
+ const { spawn } = await import('node:child_process');
828
+ const isWindows = process.platform === 'win32';
829
+ console.log(chalk.cyan(`\n${i18n.t('wizard.bun_installing')}\n`));
830
+ return new Promise((resolve) => {
831
+ let command;
832
+ let args;
833
+ if (isWindows) {
834
+ // Windows: use npm to install bun globally
835
+ command = 'npm.cmd';
836
+ args = ['install', '-g', 'bun'];
837
+ }
838
+ else {
839
+ // macOS/Linux: use curl installer
840
+ command = 'bash';
841
+ args = ['-c', 'curl -fsSL https://bun.sh/install | bash'];
842
+ }
843
+ const child = spawn(command, args, {
844
+ stdio: 'inherit',
845
+ shell: true,
846
+ });
847
+ child.on('close', async (code) => {
848
+ if (code === 0) {
849
+ console.log(chalk.green(`\n✅ ${i18n.t('wizard.bun_installed')}`));
850
+ await new Promise(r => setTimeout(r, 1000));
851
+ resolve(true);
852
+ }
853
+ else {
854
+ console.log(chalk.red(`\n❌ ${i18n.t('wizard.bun_install_failed')}`));
855
+ console.log(chalk.cyan(` ${i18n.t('wizard.bun_install_hint')}`));
856
+ console.log(chalk.blue(' https://bun.sh/docs/installation\n'));
857
+ await this.promptWithHints([
858
+ {
859
+ type: 'input',
860
+ name: 'continue',
861
+ message: i18n.t('wizard.press_enter'),
862
+ },
863
+ ]);
864
+ resolve(false);
865
+ }
866
+ });
867
+ child.on('error', async (error) => {
868
+ console.error(chalk.red(`\n❌ ${i18n.t('wizard.bun_install_failed')}`));
869
+ console.error(error);
870
+ await this.promptWithHints([
871
+ {
872
+ type: 'input',
873
+ name: 'continue',
874
+ message: i18n.t('wizard.press_enter'),
875
+ },
876
+ ]);
877
+ resolve(false);
878
+ });
879
+ });
750
880
  }
751
881
  async startTool(toolName) {
752
882
  const tool = SUPPORTED_TOOLS[toolName];
@@ -832,6 +962,13 @@ export class Wizard {
832
962
  openCodeModel,
833
963
  openCodeSmallModel,
834
964
  });
965
+ // Update oh-my-opencode agent models if plugin is installed
966
+ if (toolName === 'opencode' && openCodeManager.hasOhMyOpenCodePlugin()) {
967
+ spinner.text = i18n.t('wizard.oh_my_opencode_detected');
968
+ openCodeManager.updateOhMyOpenCodeModels(openCodeModel);
969
+ await new Promise(resolve => setTimeout(resolve, 500));
970
+ console.log(chalk.gray(` ${i18n.t('wizard.oh_my_opencode_models_updated')}`));
971
+ }
835
972
  await new Promise(resolve => setTimeout(resolve, 800));
836
973
  spinner.succeed(chalk.green(i18n.t('wizard.config_loaded', { tool: SUPPORTED_TOOLS[toolName].displayName })));
837
974
  await new Promise(resolve => setTimeout(resolve, 2000));
@@ -156,7 +156,20 @@
156
156
  "directory_required": "Directory path cannot be empty",
157
157
  "directory_not_exist": "Directory does not exist",
158
158
  "press_ctrl_c_to_exit": "Press Ctrl+C to go back",
159
- "nav_go_back": "Go back"
159
+ "nav_go_back": "Go back",
160
+ "action_install_oh_my_opencode": "Install oh-my-opencode Plugin",
161
+ "oh_my_opencode_installing": "Installing oh-my-opencode...",
162
+ "oh_my_opencode_installed": "oh-my-opencode installed successfully!",
163
+ "oh_my_opencode_install_failed": "Failed to install oh-my-opencode",
164
+ "oh_my_opencode_detected": "oh-my-opencode plugin detected, updating agent models...",
165
+ "oh_my_opencode_models_updated": "oh-my-opencode agent models updated",
166
+ "oh_my_opencode_requires_bun": "oh-my-opencode requires Bun to be installed",
167
+ "bun_install_hint": "Please install Bun first:",
168
+ "bun_install_confirm": "Would you like to install Bun now?",
169
+ "bun_installing": "Installing Bun...",
170
+ "bun_installed": "Bun installed successfully!",
171
+ "bun_install_failed": "Failed to install Bun",
172
+ "bun_install_skipped": "Bun installation skipped"
160
173
  },
161
174
  "doctor": {
162
175
  "checking": "Running health check...",
@@ -156,7 +156,20 @@
156
156
  "directory_required": "目录路径不能为空",
157
157
  "directory_not_exist": "目录不存在",
158
158
  "press_ctrl_c_to_exit": "按 Ctrl+C 可退出返回",
159
- "nav_go_back": "返回上一步"
159
+ "nav_go_back": "返回上一步",
160
+ "action_install_oh_my_opencode": "安装 oh-my-opencode 插件",
161
+ "oh_my_opencode_installing": "正在安装 oh-my-opencode...",
162
+ "oh_my_opencode_installed": "oh-my-opencode 安装成功!",
163
+ "oh_my_opencode_install_failed": "oh-my-opencode 安装失败",
164
+ "oh_my_opencode_detected": "检测到 oh-my-opencode 插件,正在更新 Agent 模型...",
165
+ "oh_my_opencode_models_updated": "oh-my-opencode Agent 模型已更新",
166
+ "oh_my_opencode_requires_bun": "oh-my-opencode 需要先安装 Bun",
167
+ "bun_install_hint": "请先安装 Bun:",
168
+ "bun_install_confirm": "是否需要帮您安装 Bun?",
169
+ "bun_installing": "正在安装 Bun...",
170
+ "bun_installed": "Bun 安装成功!",
171
+ "bun_install_failed": "Bun 安装失败",
172
+ "bun_install_skipped": "已跳过 Bun 安装"
160
173
  },
161
174
  "doctor": {
162
175
  "checking": "正在进行健康检查...",
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@x-all-in-one/coding-helper",
3
3
  "type": "module",
4
- "version": "0.0.4",
4
+ "version": "0.0.6",
5
5
  "description": "X All In One Coding Helper",
6
6
  "author": "X.AIO",
7
7
  "homepage": "https://docs.x-aio.com/zh/docs",