@happycastle/oh-my-openclaw 0.5.0 โ†’ 0.6.0

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.
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Defines the Oh-My-OpenClaw plugin's local agent configuration contracts
3
+ * and the canonical list of built-in OMOC agent definitions.
4
+ */
5
+ export type OmocAgentConfig = {
6
+ id: string;
7
+ name?: string;
8
+ model?: string | {
9
+ primary: string;
10
+ fallbacks?: string[];
11
+ };
12
+ skills?: string[];
13
+ identity?: {
14
+ name?: string;
15
+ theme?: string;
16
+ emoji?: string;
17
+ };
18
+ subagents?: {
19
+ allowAgents?: string[];
20
+ model?: string | {
21
+ primary: string;
22
+ fallbacks?: string[];
23
+ };
24
+ };
25
+ tools?: {
26
+ profile?: 'minimal' | 'coding' | 'messaging' | 'full';
27
+ allow?: string[];
28
+ deny?: string[];
29
+ };
30
+ };
31
+ export declare const OMOC_AGENT_CONFIGS: OmocAgentConfig[];
@@ -0,0 +1,188 @@
1
+ export const OMOC_AGENT_CONFIGS = [
2
+ // Strategic planning agent.
3
+ {
4
+ id: 'omoc_prometheus',
5
+ name: 'Prometheus',
6
+ model: {
7
+ primary: 'openai/o3',
8
+ fallbacks: ['anthropic/claude-opus-4-6'],
9
+ },
10
+ identity: {
11
+ name: 'Prometheus',
12
+ emoji: '๐Ÿ”ฅ',
13
+ theme: 'Strategic Planner',
14
+ },
15
+ tools: { profile: 'full' },
16
+ subagents: { allowAgents: ['*'] },
17
+ },
18
+ // Task orchestration coordinator (cheap/fast tier โ€” lightweight orchestrator).
19
+ {
20
+ id: 'omoc_atlas',
21
+ name: 'Atlas',
22
+ model: {
23
+ primary: 'anthropic/claude-sonnet-4-6',
24
+ fallbacks: ['openai/gpt-4.1'],
25
+ },
26
+ identity: {
27
+ name: 'Atlas',
28
+ emoji: '๐Ÿ—บ๏ธ',
29
+ theme: 'Task Orchestrator',
30
+ },
31
+ tools: { profile: 'full' },
32
+ subagents: { allowAgents: ['*'] },
33
+ },
34
+ // Primary implementation worker (opus-tier โ€” high-quality output).
35
+ {
36
+ id: 'omoc_sisyphus',
37
+ name: 'Sisyphus-Junior',
38
+ model: {
39
+ primary: 'anthropic/claude-opus-4-6',
40
+ fallbacks: ['openai/o3'],
41
+ },
42
+ identity: {
43
+ name: 'Sisyphus-Junior',
44
+ emoji: '๐Ÿชจ',
45
+ theme: 'Implementation Worker',
46
+ },
47
+ tools: { profile: 'full' },
48
+ subagents: {
49
+ allowAgents: ['omoc_explore', 'omoc_librarian', 'omoc_oracle'],
50
+ },
51
+ },
52
+ // Deep implementation specialist.
53
+ {
54
+ id: 'omoc_hephaestus',
55
+ name: 'Hephaestus',
56
+ model: {
57
+ primary: 'anthropic/claude-opus-4-6',
58
+ fallbacks: ['openai/o3'],
59
+ },
60
+ identity: {
61
+ name: 'Hephaestus',
62
+ emoji: '๐Ÿ”จ',
63
+ theme: 'Deep Implementation',
64
+ },
65
+ tools: { profile: 'full' },
66
+ subagents: {
67
+ allowAgents: ['omoc_explore', 'omoc_librarian', 'omoc_oracle'],
68
+ },
69
+ },
70
+ // Read-only architecture consultant.
71
+ {
72
+ id: 'omoc_oracle',
73
+ name: 'Oracle',
74
+ model: {
75
+ primary: 'openai/o3',
76
+ fallbacks: ['anthropic/claude-opus-4-6'],
77
+ },
78
+ identity: {
79
+ name: 'Oracle',
80
+ emoji: '๐Ÿ›๏ธ',
81
+ theme: 'Architecture Consultant',
82
+ },
83
+ tools: {
84
+ profile: 'coding',
85
+ deny: ['write', 'edit', 'apply_patch', 'sessions_spawn'],
86
+ },
87
+ },
88
+ // Read-only codebase search specialist.
89
+ {
90
+ id: 'omoc_explore',
91
+ name: 'Explore',
92
+ model: 'anthropic/claude-sonnet-4-6',
93
+ identity: {
94
+ name: 'Explore',
95
+ emoji: '๐Ÿ”',
96
+ theme: 'Codebase Search',
97
+ },
98
+ tools: {
99
+ profile: 'coding',
100
+ deny: ['write', 'edit', 'apply_patch', 'sessions_spawn'],
101
+ },
102
+ },
103
+ // Read-only documentation research specialist.
104
+ {
105
+ id: 'omoc_librarian',
106
+ name: 'Librarian',
107
+ model: 'anthropic/claude-sonnet-4-6',
108
+ identity: {
109
+ name: 'Librarian',
110
+ emoji: '๐Ÿ“š',
111
+ theme: 'Documentation Research',
112
+ },
113
+ tools: {
114
+ profile: 'coding',
115
+ deny: ['write', 'edit', 'apply_patch', 'sessions_spawn'],
116
+ },
117
+ },
118
+ // Read-only pre-planning analyst.
119
+ {
120
+ id: 'omoc_metis',
121
+ name: 'Metis',
122
+ model: {
123
+ primary: 'anthropic/claude-opus-4-6',
124
+ fallbacks: ['openai/o3'],
125
+ },
126
+ identity: {
127
+ name: 'Metis',
128
+ emoji: '๐Ÿง ',
129
+ theme: 'Pre-Planning Analyst',
130
+ },
131
+ tools: {
132
+ profile: 'coding',
133
+ deny: ['write', 'edit', 'apply_patch', 'sessions_spawn'],
134
+ },
135
+ },
136
+ // Read-only plan review specialist.
137
+ {
138
+ id: 'omoc_momus',
139
+ name: 'Momus',
140
+ model: {
141
+ primary: 'anthropic/claude-opus-4-6',
142
+ fallbacks: ['openai/o3'],
143
+ },
144
+ identity: {
145
+ name: 'Momus',
146
+ emoji: '๐ŸŽญ',
147
+ theme: 'Plan Reviewer',
148
+ },
149
+ tools: {
150
+ profile: 'coding',
151
+ deny: ['write', 'edit', 'apply_patch', 'sessions_spawn'],
152
+ },
153
+ },
154
+ // Multimodal visual analysis specialist (read-only โ€” allowlist approach).
155
+ {
156
+ id: 'omoc_looker',
157
+ name: 'Multimodal Looker',
158
+ model: {
159
+ primary: 'google/gemini-2.5-flash',
160
+ fallbacks: ['anthropic/claude-sonnet-4-6'],
161
+ },
162
+ identity: {
163
+ name: 'Multimodal Looker',
164
+ emoji: '๐Ÿ‘๏ธ',
165
+ theme: 'Visual Analysis',
166
+ },
167
+ tools: {
168
+ allow: ['read'],
169
+ deny: ['write', 'edit', 'apply_patch', 'sessions_spawn'],
170
+ },
171
+ },
172
+ // Frontend-focused visual engineering specialist.
173
+ {
174
+ id: 'omoc_frontend',
175
+ name: 'Frontend',
176
+ model: {
177
+ primary: 'google/gemini-2.5-pro',
178
+ fallbacks: ['anthropic/claude-sonnet-4-6'],
179
+ },
180
+ identity: {
181
+ name: 'Frontend',
182
+ emoji: '๐ŸŽจ',
183
+ theme: 'Visual Engineering',
184
+ },
185
+ tools: { profile: 'coding' },
186
+ subagents: { allowAgents: ['omoc_explore', 'omoc_librarian'] },
187
+ },
188
+ ];
@@ -0,0 +1,60 @@
1
+ import { type OmocAgentConfig } from '../agents/agent-configs.js';
2
+ type AgentsSection = {
3
+ defaults?: Record<string, unknown>;
4
+ list?: Array<{
5
+ id: string;
6
+ [key: string]: unknown;
7
+ }>;
8
+ };
9
+ type ConfigShape = {
10
+ agents?: AgentsSection;
11
+ [key: string]: unknown;
12
+ };
13
+ type Logger = {
14
+ info: (msg: string) => void;
15
+ warn: (msg: string) => void;
16
+ error: (msg: string) => void;
17
+ };
18
+ export declare function findConfigPath(workspaceDir?: string): string | undefined;
19
+ /**
20
+ * Lenient JSON5 parser: strips // and /* comments, removes trailing commas,
21
+ * then delegates to JSON.parse.
22
+ */
23
+ export declare function parseConfig(raw: string): ConfigShape;
24
+ export declare function serializeConfig(config: ConfigShape): string;
25
+ export interface MergeResult {
26
+ added: string[];
27
+ skipped: string[];
28
+ updated: string[];
29
+ }
30
+ export declare function mergeAgentConfigs(existing: Array<{
31
+ id: string;
32
+ [key: string]: unknown;
33
+ }>, incoming: OmocAgentConfig[], force: boolean): {
34
+ merged: Array<{
35
+ id: string;
36
+ [key: string]: unknown;
37
+ }>;
38
+ result: MergeResult;
39
+ };
40
+ export interface SetupOptions {
41
+ configPath?: string;
42
+ workspaceDir?: string;
43
+ force?: boolean;
44
+ dryRun?: boolean;
45
+ logger: Logger;
46
+ }
47
+ export declare function runSetup(options: SetupOptions): MergeResult;
48
+ export declare function registerSetupCli(ctx: {
49
+ program: {
50
+ command: (name: string) => CommandBuilder;
51
+ };
52
+ workspaceDir?: string;
53
+ logger: Logger;
54
+ }): void;
55
+ type CommandBuilder = {
56
+ description: (desc: string) => CommandBuilder;
57
+ option: (flags: string, desc: string, defaultValue?: unknown) => CommandBuilder;
58
+ action: (fn: (...args: unknown[]) => void) => CommandBuilder;
59
+ };
60
+ export {};
@@ -0,0 +1,145 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { OMOC_AGENT_CONFIGS } from '../agents/agent-configs.js';
4
+ const CONFIG_FILENAMES = [
5
+ 'openclaw.json5',
6
+ 'openclaw.json',
7
+ 'openclaw.yaml',
8
+ 'openclaw.yml',
9
+ ];
10
+ export function findConfigPath(workspaceDir) {
11
+ const searchDirs = [];
12
+ if (workspaceDir) {
13
+ searchDirs.push(workspaceDir);
14
+ const parent = path.dirname(workspaceDir);
15
+ if (parent !== workspaceDir) {
16
+ searchDirs.push(parent);
17
+ }
18
+ }
19
+ searchDirs.push(process.cwd());
20
+ const homeDir = process.env['HOME'] ?? process.env['USERPROFILE'];
21
+ if (homeDir) {
22
+ searchDirs.push(path.join(homeDir, '.openclaw'));
23
+ }
24
+ for (const dir of searchDirs) {
25
+ for (const filename of CONFIG_FILENAMES) {
26
+ const candidate = path.join(dir, filename);
27
+ if (fs.existsSync(candidate)) {
28
+ return candidate;
29
+ }
30
+ }
31
+ }
32
+ return undefined;
33
+ }
34
+ /**
35
+ * Lenient JSON5 parser: strips // and /* comments, removes trailing commas,
36
+ * then delegates to JSON.parse.
37
+ */
38
+ export function parseConfig(raw) {
39
+ const stripped = raw
40
+ .replace(/\/\/.*$/gm, '')
41
+ .replace(/\/\*[\s\S]*?\*\//g, '')
42
+ .replace(/,\s*([\]}])/g, '$1');
43
+ return JSON.parse(stripped);
44
+ }
45
+ export function serializeConfig(config) {
46
+ return JSON.stringify(config, null, 2) + '\n';
47
+ }
48
+ export function mergeAgentConfigs(existing, incoming, force) {
49
+ const result = { added: [], skipped: [], updated: [] };
50
+ const merged = [...existing];
51
+ const existingIds = new Set(existing.map((a) => a.id));
52
+ for (const agent of incoming) {
53
+ if (existingIds.has(agent.id)) {
54
+ if (force) {
55
+ const idx = merged.findIndex((a) => a.id === agent.id);
56
+ if (idx !== -1) {
57
+ merged[idx] = agent;
58
+ result.updated.push(agent.id);
59
+ }
60
+ }
61
+ else {
62
+ result.skipped.push(agent.id);
63
+ }
64
+ }
65
+ else {
66
+ merged.push(agent);
67
+ result.added.push(agent.id);
68
+ }
69
+ }
70
+ return { merged, result };
71
+ }
72
+ export function runSetup(options) {
73
+ const { logger, force = false, dryRun = false } = options;
74
+ const configPath = options.configPath ?? findConfigPath(options.workspaceDir);
75
+ if (!configPath) {
76
+ throw new Error('Could not find OpenClaw config file. Searched for: ' +
77
+ CONFIG_FILENAMES.join(', ') +
78
+ '\nSpecify the path with --config <path>');
79
+ }
80
+ if (!fs.existsSync(configPath)) {
81
+ throw new Error(`Config file not found: ${configPath}`);
82
+ }
83
+ logger.info(`Found config: ${configPath}`);
84
+ const raw = fs.readFileSync(configPath, 'utf-8');
85
+ if (configPath.endsWith('.yaml') || configPath.endsWith('.yml')) {
86
+ throw new Error('YAML config files are not supported by omoc-setup. ' +
87
+ 'Please convert to JSON or JSON5, or manually add agent configs.');
88
+ }
89
+ const config = parseConfig(raw);
90
+ if (!config.agents) {
91
+ config.agents = {};
92
+ }
93
+ if (!config.agents.list) {
94
+ config.agents.list = [];
95
+ }
96
+ const { merged, result } = mergeAgentConfigs(config.agents.list, OMOC_AGENT_CONFIGS, force);
97
+ config.agents.list = merged;
98
+ if (dryRun) {
99
+ logger.info('[dry-run] Would write config to: ' + configPath);
100
+ }
101
+ else {
102
+ const backupPath = configPath + '.bak';
103
+ fs.copyFileSync(configPath, backupPath);
104
+ logger.info(`Backup created: ${backupPath}`);
105
+ fs.writeFileSync(configPath, serializeConfig(config), 'utf-8');
106
+ logger.info(`Config updated: ${configPath}`);
107
+ }
108
+ if (result.added.length > 0) {
109
+ logger.info(`Added ${result.added.length} agent(s): ${result.added.join(', ')}`);
110
+ }
111
+ if (result.updated.length > 0) {
112
+ logger.info(`Updated ${result.updated.length} agent(s): ${result.updated.join(', ')}`);
113
+ }
114
+ if (result.skipped.length > 0) {
115
+ logger.info(`Skipped ${result.skipped.length} existing agent(s): ${result.skipped.join(', ')}`);
116
+ }
117
+ if (result.added.length === 0 && result.updated.length === 0) {
118
+ logger.info('No changes needed โ€” all OmOC agents already present.');
119
+ }
120
+ return result;
121
+ }
122
+ export function registerSetupCli(ctx) {
123
+ ctx.program
124
+ .command('setup')
125
+ .description('Inject OmOC agent definitions into your OpenClaw config')
126
+ .option('--force', 'Overwrite existing OmOC agent configs', false)
127
+ .option('--dry-run', 'Preview changes without writing', false)
128
+ .option('--config <path>', 'Path to OpenClaw config file')
129
+ .action((...args) => {
130
+ const opts = (args[0] ?? {});
131
+ try {
132
+ runSetup({
133
+ configPath: opts.config,
134
+ workspaceDir: ctx.workspaceDir,
135
+ force: opts.force,
136
+ dryRun: opts.dryRun,
137
+ logger: ctx.logger,
138
+ });
139
+ }
140
+ catch (err) {
141
+ ctx.logger.error(`Setup failed: ${err instanceof Error ? err.message : String(err)}`);
142
+ process.exitCode = 1;
143
+ }
144
+ });
145
+ }
@@ -2,10 +2,11 @@ import { startLoop, stopLoop, getStatus } from '../services/ralph-loop.js';
2
2
  import { getMessageCount } from '../hooks/message-monitor.js';
3
3
  import { getConfig } from '../utils/config.js';
4
4
  export function registerRalphCommands(api) {
5
- // /ralph-loop command
5
+ // /ralph_loop command
6
6
  api.registerCommand({
7
- name: 'ralph-loop',
7
+ name: 'ralph_loop',
8
8
  description: 'Start the Ralph Loop self-completion mechanism',
9
+ acceptsArgs: true,
9
10
  handler: async (ctx) => {
10
11
  const args = (ctx.args || '').trim().split(/\s+/).filter(Boolean);
11
12
  const config = getConfig(api);
@@ -22,9 +23,9 @@ export function registerRalphCommands(api) {
22
23
  };
23
24
  },
24
25
  });
25
- // /ralph-stop command
26
+ // /ralph_stop command
26
27
  api.registerCommand({
27
- name: 'ralph-stop',
28
+ name: 'ralph_stop',
28
29
  description: 'Stop the active Ralph Loop',
29
30
  handler: async () => {
30
31
  const result = await stopLoop();
@@ -33,9 +34,9 @@ export function registerRalphCommands(api) {
33
34
  };
34
35
  },
35
36
  });
36
- // /omoc-status command
37
+ // /omoc_status command
37
38
  api.registerCommand({
38
- name: 'omoc-status',
39
+ name: 'omoc_status',
39
40
  description: 'Show Oh-My-OpenClaw plugin status',
40
41
  handler: async () => {
41
42
  const config = getConfig(api);
@@ -5,7 +5,7 @@ import { getStatus as getRalphStatus } from '../services/ralph-loop.js';
5
5
  import { getMessageCount } from '../hooks/message-monitor.js';
6
6
  export function registerStatusCommands(api) {
7
7
  api.registerCommand({
8
- name: 'omoc-health',
8
+ name: 'omoc_health',
9
9
  description: 'Plugin health check (auto-reply, no AI invocation)',
10
10
  handler: async () => {
11
11
  const config = getConfig(api);
@@ -24,7 +24,7 @@ export function registerStatusCommands(api) {
24
24
  },
25
25
  });
26
26
  api.registerCommand({
27
- name: 'omoc-config',
27
+ name: 'omoc_config',
28
28
  description: 'Show current plugin configuration (auto-reply)',
29
29
  handler: () => {
30
30
  const config = getConfig(api);
@@ -17,7 +17,8 @@ async function readWorkflow(workflowName) {
17
17
  export function registerWorkflowCommands(api) {
18
18
  api.registerCommand({
19
19
  name: 'ultrawork',
20
- description: 'Full planning \u2192 execution \u2192 verification workflow',
20
+ description: 'Full planning โ†’ execution โ†’ verification workflow',
21
+ acceptsArgs: true,
21
22
  handler: async (ctx) => {
22
23
  const taskDescription = ctx.args || 'No task specified';
23
24
  const workflow = await readWorkflow('ultrawork');
@@ -29,6 +30,7 @@ export function registerWorkflowCommands(api) {
29
30
  api.registerCommand({
30
31
  name: 'plan',
31
32
  description: 'Create a structured execution plan',
33
+ acceptsArgs: true,
32
34
  handler: async (ctx) => {
33
35
  const topic = ctx.args || 'No topic specified';
34
36
  const workflow = await readWorkflow('plan');
@@ -38,8 +40,9 @@ export function registerWorkflowCommands(api) {
38
40
  },
39
41
  });
40
42
  api.registerCommand({
41
- name: 'start-work',
43
+ name: 'start_work',
42
44
  description: 'Execute an approved plan',
45
+ acceptsArgs: true,
43
46
  handler: async (ctx) => {
44
47
  const planPath = ctx.args || 'most recent plan';
45
48
  const workflow = await readWorkflow('start-work');
package/dist/index.js CHANGED
@@ -12,12 +12,13 @@ import { registerCheckpointTool } from './tools/checkpoint.js';
12
12
  import { registerWorkflowCommands } from './commands/workflow-commands.js';
13
13
  import { registerRalphCommands } from './commands/ralph-commands.js';
14
14
  import { registerStatusCommands } from './commands/status-commands.js';
15
- /** Registry of successfully registered components */
15
+ import { registerSetupCli } from './cli/setup.js';
16
16
  const registry = {
17
17
  hooks: [],
18
18
  services: [],
19
19
  tools: [],
20
20
  commands: [],
21
+ cli: [],
21
22
  };
22
23
  export default function register(api) {
23
24
  const config = getConfig(api);
@@ -88,28 +89,42 @@ export default function register(api) {
88
89
  }
89
90
  try {
90
91
  registerWorkflowCommands(api);
91
- registry.commands.push('ultrawork', 'plan', 'start-work');
92
- api.logger.info(`[${PLUGIN_ID}] Workflow commands registered (ultrawork, plan, start-work)`);
92
+ registry.commands.push('ultrawork', 'plan', 'start_work');
93
+ api.logger.info(`[${PLUGIN_ID}] Workflow commands registered (ultrawork, plan, start_work)`);
93
94
  }
94
95
  catch (err) {
95
96
  api.logger.error(`[${PLUGIN_ID}] Failed to register Workflow commands:`, err);
96
97
  }
97
98
  try {
98
99
  registerRalphCommands(api);
99
- registry.commands.push('ralph-loop', 'ralph-stop', 'omoc-status');
100
- api.logger.info(`[${PLUGIN_ID}] Ralph commands registered (ralph-loop, ralph-stop, omoc-status)`);
100
+ registry.commands.push('ralph_loop', 'ralph_stop', 'omoc_status');
101
+ api.logger.info(`[${PLUGIN_ID}] Ralph commands registered (ralph_loop, ralph_stop, omoc_status)`);
101
102
  }
102
103
  catch (err) {
103
104
  api.logger.error(`[${PLUGIN_ID}] Failed to register Ralph commands:`, err);
104
105
  }
105
106
  try {
106
107
  registerStatusCommands(api);
107
- registry.commands.push('omoc-health', 'omoc-config');
108
- api.logger.info(`[${PLUGIN_ID}] Status commands registered (omoc-health, omoc-config)`);
108
+ registry.commands.push('omoc_health', 'omoc_config');
109
+ api.logger.info(`[${PLUGIN_ID}] Status commands registered (omoc_health, omoc_config)`);
109
110
  }
110
111
  catch (err) {
111
112
  api.logger.error(`[${PLUGIN_ID}] Failed to register Status commands:`, err);
112
113
  }
114
+ try {
115
+ api.registerCli((ctx) => {
116
+ registerSetupCli({
117
+ program: ctx.program,
118
+ workspaceDir: ctx.workspaceDir,
119
+ logger: ctx.logger,
120
+ });
121
+ }, { commands: ['setup'] });
122
+ registry.cli.push('setup');
123
+ api.logger.info(`[${PLUGIN_ID}] CLI command registered (setup)`);
124
+ }
125
+ catch (err) {
126
+ api.logger.error(`[${PLUGIN_ID}] Failed to register CLI:`, err);
127
+ }
113
128
  api.registerGatewayMethod('oh-my-openclaw.status', () => {
114
129
  return {
115
130
  ok: true,
@@ -119,6 +134,7 @@ export default function register(api) {
119
134
  services: [...registry.services],
120
135
  tools: [...registry.tools],
121
136
  commands: [...registry.commands],
137
+ cli: [...registry.cli],
122
138
  config: {
123
139
  todo_enforcer_enabled: config.todo_enforcer_enabled,
124
140
  comment_checker_enabled: config.comment_checker_enabled,
@@ -3,12 +3,14 @@ import { promises as fs } from 'fs';
3
3
  import { join } from 'path';
4
4
  import { readState, writeState, ensureDir } from '../utils/state.js';
5
5
  import { getConfig } from '../utils/config.js';
6
+ // Use Type.Unsafe with enum instead of Type.Union([Type.Literal(...)]) to avoid
7
+ // generating JSON Schema "const" keyword, which Gemini API does not support.
6
8
  const CheckpointParamsSchema = Type.Object({
7
- action: Type.Union([
8
- Type.Literal('save'),
9
- Type.Literal('load'),
10
- Type.Literal('list'),
11
- ], { description: 'Checkpoint operation' }),
9
+ action: Type.Unsafe({
10
+ type: 'string',
11
+ enum: ['save', 'load', 'list'],
12
+ description: 'Checkpoint operation',
13
+ }),
12
14
  task: Type.Optional(Type.String({ description: 'Current task name (for save)' })),
13
15
  step: Type.Optional(Type.String({ description: 'Current step name (for save)' })),
14
16
  changed_files: Type.Optional(Type.Array(Type.String(), { description: 'Files modified since last checkpoint' })),
package/dist/types.d.ts CHANGED
@@ -85,6 +85,7 @@ export interface CommandRegistration<TCtx = {
85
85
  }> {
86
86
  name: string;
87
87
  description: string;
88
+ acceptsArgs?: boolean;
88
89
  handler: (ctx: TCtx) => {
89
90
  text: string;
90
91
  } | Promise<{
@@ -99,6 +100,7 @@ export interface ServiceRegistration {
99
100
  stop?: () => Promise<void>;
100
101
  }
101
102
  export interface OmocPluginApi {
103
+ pluginConfig?: PluginConfig;
102
104
  config: PluginConfig;
103
105
  logger: {
104
106
  info: (...args: unknown[]) => void;
@@ -112,4 +114,12 @@ export interface OmocPluginApi {
112
114
  }>(config: CommandRegistration<TCtx>) => void;
113
115
  registerService: (config: ServiceRegistration) => void;
114
116
  registerGatewayMethod: (name: string, handler: () => unknown) => void;
117
+ registerCli: (registrar: (ctx: {
118
+ program: unknown;
119
+ config: unknown;
120
+ workspaceDir?: string;
121
+ logger: OmocPluginApi['logger'];
122
+ }) => void | Promise<void>, opts?: {
123
+ commands?: string[];
124
+ }) => void;
115
125
  }
@@ -12,7 +12,7 @@ export function getConfig(api) {
12
12
  tmux_socket: '/tmp/openclaw-tmux-sockets/openclaw.sock',
13
13
  model_routing: undefined,
14
14
  };
15
- const config = { ...defaults, ...api.config };
15
+ const config = { ...defaults, ...(api.pluginConfig ?? api.config) };
16
16
  const validation = validateConfig(config);
17
17
  if (!validation.valid) {
18
18
  api.logger.warn(`Config validation failed: ${validation.errors.join(', ')}`);
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "id": "oh-my-openclaw",
3
3
  "name": "Oh-My-OpenClaw",
4
- "description": "Multi-agent orchestration plugin \u2014 10 agents, category-based model routing, todo enforcer, ralph loop, and custom tools",
5
- "version": "0.5.0",
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.6.0",
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.5.0",
3
+ "version": "0.6.0",
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",
@@ -23,7 +23,7 @@ OmO์˜ `src/tools/` ๊ตฌ์กฐ๋ฅผ ๊ธฐ์ค€์œผ๋กœ, OpenClaw์—์„œ ์‹ค์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ
23
23
  | `lsp/*` (goto/references) | ์ฝ”๋“œ ํƒ์ƒ‰/๊ฒ€์ฆ | `exec` ๋„๊ตฌ๋กœ ๋ฆฐํ„ฐ/ํƒ€์ž…์ฒด์ปค ์‹คํ–‰ โ†’ ๊ฒฐ๊ณผ๋กœ ๊ฒ€์ฆ |
24
24
  | `interactive-bash` | ์žฅ์‹œ๊ฐ„/์ƒํ˜ธ์ž‘์šฉ ์…ธ | `exec`(`pty: true`) ๋˜๋Š” tmux ์—ฐ๋™ |
25
25
  | `bash` | ์›์ƒท ๋ช…๋ น | `exec`(๋™๊ธฐ), `exec`(`background: true`) โ†’ `process`(`poll`) |
26
- | `slashcommand` | ๋ช…๋ น ์›Œํฌํ”Œ๋กœ์šฐ ๊ตฌ๋™ | OpenClaw ์Šคํ‚ฌ `/ultrawork`, `/plan`, `/start-work` (์Šฌ๋ž˜์‹œ ์ปค๋งจ๋“œ) |
26
+ | `slashcommand` | ๋ช…๋ น ์›Œํฌํ”Œ๋กœ์šฐ ๊ตฌ๋™ | OpenClaw ์Šคํ‚ฌ `/ultrawork`, `/plan`, `/start_work` (์Šฌ๋ž˜์‹œ ์ปค๋งจ๋“œ) |
27
27
  | `session-manager` | ์„ธ์…˜ ํƒ์ƒ‰/์žฌ๊ฐœ | `sessions_list`, `sessions_history`, `session_status` |
28
28
  | `skill-mcp` | ์Šคํ‚ฌ ๊ธฐ๋ฐ˜ ๋„๊ตฌ ํ˜ธ์ถœ | OpenClaw ์Šคํ‚ฌ ์‹œ์Šคํ…œ (`read` โ†’ SKILL.md ์ฐธ์กฐ) |
29
29
  | `look-at` | ๋ฉ€ํ‹ฐ๋ชจ๋‹ฌ ๋ถ„์„ | `image` ๋„๊ตฌ + Gemini CLI tmux ์—ฐ๋™ |
package/workflows/plan.md CHANGED
@@ -11,7 +11,7 @@ Strategic planning workflow that analyzes requirements and creates a structured
11
11
  - Starting a new feature or project
12
12
  - Complex multi-step tasks
13
13
  - When requirements are ambiguous and need clarification
14
- - Before any `/ultrawork` or `/start-work` invocation
14
+ - Before any `/ultrawork` or `/start_work` invocation
15
15
 
16
16
  ## Workflow Steps
17
17
 
@@ -103,7 +103,7 @@ Strategic planning workflow that analyzes requirements and creates a structured
103
103
 
104
104
  ## Integration with Other Workflows
105
105
 
106
- - After plan approval, use `/start-work` to begin execution
106
+ - After plan approval, use `/start_work` to begin execution
107
107
  - Or use `/ultrawork` for fully automated execution without stops
108
108
  - Plan files persist in `workspace/plans/` for future reference
109
109
 
@@ -17,7 +17,7 @@ Execute an approved plan by delegating tasks to appropriate worker agents, track
17
17
 
18
18
  1. **Load the plan**
19
19
  - Read the most recent plan from `workspace/plans/`
20
- - Or specify a plan: `/start-work <plan-file>`
20
+ - Or specify a plan: `/start_work <plan-file>`
21
21
  - Verify plan status is "approved"
22
22
  - Update plan status to "in-progress"
23
23
 
@@ -106,5 +106,5 @@ After each task completion, output:
106
106
  ## Integration
107
107
 
108
108
  - Plans come from `/plan` workflow
109
- - `/ultrawork` combines `/plan` + `/start-work` automatically
109
+ - `/ultrawork` combines `/plan` + `/start_work` automatically
110
110
  - Wisdom notepads persist across sessions for future reference