@happycastle/oh-my-openclaw 0.8.0 β†’ 0.8.1

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.
@@ -7,6 +7,9 @@ export type ProviderPreset = Record<ModelTier, ModelConfig>;
7
7
  export declare const PROVIDER_PRESETS: Record<string, ProviderPreset>;
8
8
  export declare const AGENT_TIER_MAP: Record<string, ModelTier>;
9
9
  export declare const PROVIDER_LABELS: Record<string, string>;
10
+ export declare const MODEL_TIERS: ModelTier[];
11
+ export declare function buildCustomPreset(tierModels: Record<ModelTier, string>): ProviderPreset;
12
+ export declare function registerCustomPreset(name: string, preset: ProviderPreset): void;
10
13
  export declare function getProviderNames(): string[];
11
14
  export declare function applyProviderPreset(agentId: string, provider: string): {
12
15
  primary: string;
@@ -38,7 +38,22 @@ export const PROVIDER_LABELS = {
38
38
  anthropic: 'Anthropic (Claude)',
39
39
  openai: 'OpenAI (GPT)',
40
40
  google: 'Google (Gemini)',
41
+ custom: 'Custom (enter model IDs manually)',
41
42
  };
43
+ export const MODEL_TIERS = ['planning', 'worker', 'orchestrator', 'lightweight', 'visual'];
44
+ export function buildCustomPreset(tierModels) {
45
+ const preset = {};
46
+ for (const tier of MODEL_TIERS) {
47
+ preset[tier] = { primary: tierModels[tier], fallbacks: [] };
48
+ }
49
+ return preset;
50
+ }
51
+ export function registerCustomPreset(name, preset) {
52
+ PROVIDER_PRESETS[name] = preset;
53
+ if (!PROVIDER_LABELS[name]) {
54
+ PROVIDER_LABELS[name] = name;
55
+ }
56
+ }
42
57
  export function getProviderNames() {
43
58
  return Object.keys(PROVIDER_PRESETS);
44
59
  }
package/dist/cli/setup.js CHANGED
@@ -3,7 +3,7 @@ import path from 'node:path';
3
3
  import * as readline from 'node:readline';
4
4
  import JSON5 from 'json5';
5
5
  import { OMOC_AGENT_CONFIGS } from '../agents/agent-configs.js';
6
- import { PROVIDER_PRESETS, PROVIDER_LABELS, AGENT_TIER_MAP, applyProviderPreset, getProviderNames, } from './model-presets.js';
6
+ import { PROVIDER_PRESETS, PROVIDER_LABELS, AGENT_TIER_MAP, MODEL_TIERS, applyProviderPreset, getProviderNames, buildCustomPreset, registerCustomPreset, } from './model-presets.js';
7
7
  const CONFIG_FILENAMES = [
8
8
  'openclaw.json5',
9
9
  'openclaw.json',
@@ -93,6 +93,47 @@ const TIER_LABELS = {
93
93
  lightweight: 'Search/Research',
94
94
  visual: 'Visual/Frontend',
95
95
  };
96
+ function printPreview(logger, provider) {
97
+ const preset = PROVIDER_PRESETS[provider];
98
+ for (const [tier, label] of Object.entries(TIER_LABELS)) {
99
+ const config = preset[tier];
100
+ const agents = Object.entries(AGENT_TIER_MAP)
101
+ .filter(([, t]) => t === tier)
102
+ .map(([id]) => id.replace('omoc_', ''))
103
+ .join(', ');
104
+ logger.info(` ${label} (${agents}):`);
105
+ logger.info(` β†’ ${config.primary}`);
106
+ if (config.fallbacks.length > 0) {
107
+ logger.info(` fallback: ${config.fallbacks.join(', ')}`);
108
+ }
109
+ }
110
+ }
111
+ async function runCustomProviderFlow(rl, logger) {
112
+ logger.info('');
113
+ logger.info(' Enter model IDs for each tier.');
114
+ logger.info(' Format: provider/model (e.g., cliproxy/claude-opus-4-6, z.ai/gpt-5.3-codex)');
115
+ logger.info('');
116
+ const tierModels = {};
117
+ for (const tier of MODEL_TIERS) {
118
+ const label = TIER_LABELS[tier];
119
+ const agents = Object.entries(AGENT_TIER_MAP)
120
+ .filter(([, t]) => t === tier)
121
+ .map(([id]) => id.replace('omoc_', ''))
122
+ .join(', ');
123
+ let model = '';
124
+ while (!model) {
125
+ model = await askQuestion(rl, ` ${label} (${agents}): `);
126
+ if (!model) {
127
+ logger.info(' Model ID required.');
128
+ }
129
+ }
130
+ tierModels[tier] = model;
131
+ }
132
+ const customPreset = buildCustomPreset(tierModels);
133
+ const customName = '_custom_' + Date.now();
134
+ registerCustomPreset(customName, customPreset);
135
+ return customName;
136
+ }
96
137
  export async function runInteractiveSetup(logger) {
97
138
  const rl = readline.createInterface({
98
139
  input: process.stdin,
@@ -103,45 +144,38 @@ export async function runInteractiveSetup(logger) {
103
144
  logger.info('πŸ—ΊοΈ Oh-My-OpenClaw Agent Setup');
104
145
  logger.info('─'.repeat(40));
105
146
  logger.info('');
106
- const providers = getProviderNames();
107
- logger.info('Step 1/2: Select your primary AI provider');
147
+ const presetProviders = getProviderNames();
148
+ const choices = [...presetProviders, 'custom'];
149
+ const choiceCount = choices.length;
150
+ logger.info('Step 1/2: Select your AI provider');
108
151
  logger.info('');
109
- providers.forEach((p, i) => {
152
+ choices.forEach((p, i) => {
110
153
  logger.info(` ${i + 1}. ${PROVIDER_LABELS[p] ?? p}`);
111
154
  });
112
155
  logger.info('');
113
156
  let provider = '';
114
157
  while (!provider) {
115
- const answer = await askQuestion(rl, ' Select (1-3): ');
158
+ const answer = await askQuestion(rl, ` Select (1-${choiceCount}): `);
116
159
  const idx = parseInt(answer, 10) - 1;
117
- if (idx >= 0 && idx < providers.length) {
118
- provider = providers[idx];
160
+ if (idx >= 0 && idx < choiceCount) {
161
+ provider = choices[idx];
119
162
  }
120
- else if (providers.includes(answer.toLowerCase())) {
163
+ else if (choices.includes(answer.toLowerCase())) {
121
164
  provider = answer.toLowerCase();
122
165
  }
123
166
  else {
124
- logger.info(' Invalid choice. Enter 1, 2, or 3.');
167
+ logger.info(` Invalid choice. Enter 1-${choiceCount}.`);
125
168
  }
126
169
  }
170
+ if (provider === 'custom') {
171
+ provider = await runCustomProviderFlow(rl, logger);
172
+ }
127
173
  logger.info('');
128
- logger.info(` βœ“ Selected: ${PROVIDER_LABELS[provider]}`);
174
+ logger.info(` βœ“ Selected: ${PROVIDER_LABELS[provider] ?? 'Custom'}`);
129
175
  logger.info('');
130
176
  logger.info('Step 2/2: Model configuration preview');
131
177
  logger.info('');
132
- const preset = PROVIDER_PRESETS[provider];
133
- for (const [tier, label] of Object.entries(TIER_LABELS)) {
134
- const config = preset[tier];
135
- const agents = Object.entries(AGENT_TIER_MAP)
136
- .filter(([, t]) => t === tier)
137
- .map(([id]) => id.replace('omoc_', ''))
138
- .join(', ');
139
- logger.info(` ${label} (${agents}):`);
140
- logger.info(` β†’ ${config.primary}`);
141
- if (config.fallbacks.length > 0) {
142
- logger.info(` fallback: ${config.fallbacks.join(', ')}`);
143
- }
144
- }
178
+ printPreview(logger, provider);
145
179
  logger.info('');
146
180
  const confirm = await askQuestion(rl, ' Apply this configuration? (Y/n): ');
147
181
  if (confirm.toLowerCase() === 'n' || confirm.toLowerCase() === 'no') {
@@ -2,7 +2,7 @@
2
2
  "id": "oh-my-openclaw",
3
3
  "name": "Oh-My-OpenClaw",
4
4
  "description": "Multi-agent orchestration plugin \u2014 11 agents, category-based model routing, todo enforcer, ralph loop, agent setup CLI, and custom tools",
5
- "version": "0.8.0",
5
+ "version": "0.8.1",
6
6
  "skills": ["skills"],
7
7
  "configSchema": {
8
8
  "type": "object",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@happycastle/oh-my-openclaw",
3
- "version": "0.8.0",
3
+ "version": "0.8.1",
4
4
  "description": "Oh-My-OpenClaw plugin β€” multi-agent orchestration, todo enforcer, ralph loop, and custom tools for OpenClaw",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",