oh-my-customcode 0.12.2 → 0.12.4

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/README.md CHANGED
@@ -21,7 +21,7 @@ Like oh-my-zsh transformed shell customization, oh-my-customcode makes personali
21
21
 
22
22
  | Feature | Description |
23
23
  |---------|-------------|
24
- | **Batteries Included** | 42 agents, 51 skills, 22 guides, 18 rules, 1 hook, 4 contexts - ready to use out of the box |
24
+ | **Batteries Included** | 42 agents, 52 skills, 22 guides, 18 rules, 1 hook, 4 contexts - ready to use out of the box |
25
25
  | **Sub-Agent Model** | Supports hierarchical agent orchestration with specialized roles |
26
26
  | **Dead Simple Customization** | Create a folder + markdown file = new agent or skill |
27
27
  | **Mix and Match** | Use built-in components, create your own, or combine both |
@@ -171,7 +171,7 @@ tool-npm-expert
171
171
  tool-optimizer
172
172
  ```
173
173
 
174
- ### Skills (51)
174
+ ### Skills (52)
175
175
 
176
176
  Canonical skill IDs (`templates/.claude/skills/*/SKILL.md`):
177
177
 
@@ -180,6 +180,7 @@ airflow-best-practices
180
180
  audit-agents
181
181
  aws-best-practices
182
182
  claude-code-bible
183
+ codex-exec
183
184
  create-agent
184
185
  dbt-best-practices
185
186
  de-lead-routing
@@ -301,7 +302,7 @@ your-project/
301
302
  │ ├── be-fastapi-expert.md
302
303
  │ ├── mgr-creator.md
303
304
  │ └── ...
304
- ├── skills/ # Skill modules (51 directories, each with SKILL.md)
305
+ ├── skills/ # Skill modules (52 directories, each with SKILL.md)
305
306
  │ ├── go-best-practices/
306
307
  │ ├── react-best-practices/
307
308
  │ ├── secretary-routing/
package/dist/cli/index.js CHANGED
@@ -14074,11 +14074,18 @@ async function generateMCPConfig(targetDir) {
14074
14074
  if (!ontologyExists) {
14075
14075
  return;
14076
14076
  }
14077
+ try {
14078
+ execSync3("uv venv .venv", { cwd: targetDir, stdio: "pipe" });
14079
+ execSync3("uv pip install ontology-rag", { cwd: targetDir, stdio: "pipe" });
14080
+ } catch (error2) {
14081
+ const msg = error2 instanceof Error ? error2.message : String(error2);
14082
+ throw new Error(`Failed to setup Python environment: ${msg}`);
14083
+ }
14077
14084
  const config = {
14078
14085
  mcpServers: {
14079
14086
  "ontology-rag": {
14080
14087
  type: "stdio",
14081
- command: "python",
14088
+ command: ".venv/bin/python",
14082
14089
  args: ["-m", "ontology_rag.mcp_server"],
14083
14090
  env: {
14084
14091
  ONTOLOGY_DIR: ontologyDir
@@ -14107,9 +14114,9 @@ async function generateMCPConfig(targetDir) {
14107
14114
  `);
14108
14115
  }
14109
14116
  }
14110
- async function checkPythonAvailable() {
14117
+ async function checkUvAvailable() {
14111
14118
  try {
14112
- execSync3("python --version", { stdio: "pipe" });
14119
+ execSync3("uv --version", { stdio: "pipe" });
14113
14120
  return true;
14114
14121
  } catch {
14115
14122
  return false;
@@ -14187,16 +14194,17 @@ async function initCommand(options) {
14187
14194
  const installedPaths = buildInstalledPaths(targetDir, installResult.installedComponents);
14188
14195
  logInstallResultInfo(installResult);
14189
14196
  logSuccessDetails(installedPaths, installResult.skippedComponents);
14190
- const pythonAvailable = await checkPythonAvailable();
14191
- if (pythonAvailable) {
14197
+ const uvAvailable = await checkUvAvailable();
14198
+ if (uvAvailable) {
14192
14199
  try {
14193
14200
  await generateMCPConfig(targetDir);
14194
- } catch {
14195
- console.warn("Warning: Failed to generate MCP config. You can configure it manually.");
14201
+ } catch (error2) {
14202
+ const msg = error2 instanceof Error ? error2.message : String(error2);
14203
+ console.warn(`Warning: Failed to setup MCP environment: ${msg}`);
14196
14204
  }
14197
14205
  } else {
14198
- console.warn("Warning: Python not found. Skipping MCP server configuration.");
14199
- console.warn("Install Python 3.10+ and ontology-rag to enable MCP integration.");
14206
+ console.warn("Warning: uv not found. Skipping MCP server configuration.");
14207
+ console.warn("Install uv (https://docs.astral.sh/uv/) to enable MCP integration.");
14200
14208
  }
14201
14209
  return {
14202
14210
  success: true,
package/dist/index.js CHANGED
@@ -1,4 +1,20 @@
1
1
  import { createRequire } from "node:module";
2
+ var __create = Object.create;
3
+ var __getProtoOf = Object.getPrototypeOf;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __toESM = (mod, isNodeMode, target) => {
8
+ target = mod != null ? __create(__getProtoOf(mod)) : {};
9
+ const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
10
+ for (let key of __getOwnPropNames(mod))
11
+ if (!__hasOwnProp.call(to, key))
12
+ __defProp(to, key, {
13
+ get: () => mod[key],
14
+ enumerable: true
15
+ });
16
+ return to;
17
+ };
2
18
  var __require = /* @__PURE__ */ createRequire(import.meta.url);
3
19
 
4
20
  // src/core/config.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "oh-my-customcode",
3
- "version": "0.12.2",
3
+ "version": "0.12.4",
4
4
  "description": "Batteries-included agent harness for Claude Code",
5
5
  "type": "module",
6
6
  "bin": {
@@ -0,0 +1,123 @@
1
+ ---
2
+ name: codex-exec
3
+ description: Execute OpenAI Codex CLI prompts and return results
4
+ argument-hint: "<prompt> [--json] [--output <path>] [--model <name>] [--timeout <ms>]"
5
+ disable-model-invocation: true
6
+ ---
7
+
8
+ # Codex Exec Skill
9
+
10
+ Execute OpenAI Codex CLI prompts in non-interactive mode and return structured results. Enables Claude + Codex hybrid workflows.
11
+
12
+ ## Options
13
+
14
+ ```
15
+ <prompt> Required. The prompt to send to Codex CLI
16
+ --json Return structured JSON Lines output
17
+ --output <path> Save final message to file
18
+ --model <name> Model override (o3, o4-mini, etc.)
19
+ --timeout <ms> Execution timeout (default: 120000, max: 600000)
20
+ --full-auto Enable auto-approval mode (codex -a full-auto)
21
+ --working-dir Working directory for Codex execution
22
+ ```
23
+
24
+ ## Workflow
25
+
26
+ ```
27
+ 1. Pre-checks
28
+ - Verify `codex` binary is installed (which codex || npx codex --version)
29
+ - Verify authentication (OPENAI_API_KEY or logged in)
30
+ 2. Build command
31
+ - Base: codex exec --ephemeral "<prompt>"
32
+ - Apply options: --json, --model, --full-auto, -C <dir>
33
+ - Set --working-dir if specified
34
+ 3. Execute
35
+ - Run via Bash tool with timeout (default 2min, max 10min)
36
+ - Or use helper script: node .claude/skills/codex-exec/scripts/codex-wrapper.cjs
37
+ 4. Parse output
38
+ - Text mode: return raw stdout
39
+ - JSON mode: parse JSON Lines, extract final assistant message
40
+ 5. Report results
41
+ - Format output with execution metadata
42
+ ```
43
+
44
+ ## Safety Defaults
45
+
46
+ - `--ephemeral`: No session persistence (conversations not saved)
47
+ - Default mode: Normal approval (Codex prompts for confirmation)
48
+ - Override with `--full-auto` only when explicitly requested
49
+
50
+ ## Output Format
51
+
52
+ ### Success (Text Mode)
53
+ ```
54
+ [Codex Exec] Completed
55
+
56
+ Model: o3
57
+ Duration: 23.4s
58
+ Working Dir: /path/to/project
59
+
60
+ --- Output ---
61
+ {codex response text}
62
+ ```
63
+
64
+ ### Success (JSON Mode)
65
+ ```
66
+ [Codex Exec] Completed (JSON)
67
+
68
+ Model: o3
69
+ Duration: 23.4s
70
+ Events: 12
71
+
72
+ --- Final Message ---
73
+ {extracted final assistant message}
74
+ ```
75
+
76
+ ### Failure
77
+ ```
78
+ [Codex Exec] Failed
79
+
80
+ Error: {error_message}
81
+ Exit Code: {code}
82
+ Suggested Fix: {suggestion}
83
+ ```
84
+
85
+ ## Helper Script
86
+
87
+ For complex executions, use the wrapper script:
88
+ ```bash
89
+ node .claude/skills/codex-exec/scripts/codex-wrapper.cjs --prompt "your prompt" [options]
90
+ ```
91
+
92
+ The wrapper provides:
93
+ - Environment validation (binary + auth checks)
94
+ - Safe command construction
95
+ - JSON Lines parsing with event extraction
96
+ - Structured JSON output
97
+ - Timeout handling with graceful termination
98
+
99
+ ## Examples
100
+
101
+ ```bash
102
+ # Simple text prompt
103
+ codex-exec "explain what this project does"
104
+
105
+ # JSON output with model override
106
+ codex-exec "list all TODO items" --json --model o4-mini
107
+
108
+ # Save output to file
109
+ codex-exec "generate a README" --output ./README.md
110
+
111
+ # Full auto mode with custom timeout
112
+ codex-exec "fix the failing tests" --full-auto --timeout 300000
113
+
114
+ # Specify working directory
115
+ codex-exec "analyze the codebase" --working-dir /path/to/project
116
+ ```
117
+
118
+ ## Integration
119
+
120
+ Works with the orchestrator pattern:
121
+ - Main conversation delegates Codex execution via this skill
122
+ - Results are returned to the main conversation for further processing
123
+ - Can be chained with other skills (e.g., dev-review after Codex generates code)
@@ -0,0 +1,413 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * codex-wrapper.js
5
+ *
6
+ * Node.js wrapper for OpenAI Codex CLI (non-interactive execution).
7
+ * Executes codex in ephemeral mode with structured JSON output.
8
+ *
9
+ * Usage:
10
+ * node codex-wrapper.js --prompt "your prompt" [options]
11
+ *
12
+ * Options:
13
+ * --prompt <text> Required: prompt to execute
14
+ * --json Enable JSON Lines output from codex
15
+ * --output <path> Save final message to file
16
+ * --model <name> Specify model (default: o3)
17
+ * --timeout <ms> Execution timeout in milliseconds (default: 120000, max: 600000)
18
+ * --full-auto Use full-auto approval mode (default: -a never)
19
+ * --working-dir <dir> Set working directory for execution
20
+ *
21
+ * Output (JSON to stdout):
22
+ * Success: { "success": true, "output": "...", "duration_ms": 1234, ... }
23
+ * Failure: { "success": false, "error": "...", "stderr": "...", ... }
24
+ *
25
+ * Exit codes:
26
+ * 0 = success
27
+ * 1 = execution error
28
+ * 2 = validation error (missing binary/auth)
29
+ */
30
+
31
+ const { spawn, execFileSync } = require('child_process');
32
+ const fs = require('fs');
33
+ const path = require('path');
34
+ const os = require('os');
35
+
36
+ // Configuration
37
+ const DEFAULT_TIMEOUT_MS = 120000; // 2 minutes
38
+ const MAX_TIMEOUT_MS = 600000; // 10 minutes
39
+ const KILL_GRACE_PERIOD_MS = 5000; // 5 seconds for graceful shutdown
40
+
41
+ /**
42
+ * Parse command line arguments
43
+ * @returns {Object} Parsed arguments
44
+ */
45
+ function parseArgs() {
46
+ const args = {
47
+ prompt: null,
48
+ json: false,
49
+ output: null,
50
+ model: null,
51
+ timeout: DEFAULT_TIMEOUT_MS,
52
+ fullAuto: false,
53
+ workingDir: null,
54
+ };
55
+
56
+ for (let i = 2; i < process.argv.length; i++) {
57
+ const arg = process.argv[i];
58
+
59
+ switch (arg) {
60
+ case '--prompt':
61
+ if (i + 1 < process.argv.length) {
62
+ args.prompt = process.argv[++i];
63
+ }
64
+ break;
65
+ case '--json':
66
+ args.json = true;
67
+ break;
68
+ case '--output':
69
+ if (i + 1 < process.argv.length) {
70
+ args.output = process.argv[++i];
71
+ }
72
+ break;
73
+ case '--model':
74
+ if (i + 1 < process.argv.length) {
75
+ args.model = process.argv[++i];
76
+ }
77
+ break;
78
+ case '--timeout':
79
+ if (i + 1 < process.argv.length) {
80
+ const timeoutValue = parseInt(process.argv[++i], 10);
81
+ if (!isNaN(timeoutValue)) {
82
+ args.timeout = Math.min(timeoutValue, MAX_TIMEOUT_MS);
83
+ }
84
+ }
85
+ break;
86
+ case '--full-auto':
87
+ args.fullAuto = true;
88
+ break;
89
+ case '--working-dir':
90
+ if (i + 1 < process.argv.length) {
91
+ args.workingDir = process.argv[++i];
92
+ }
93
+ break;
94
+ }
95
+ }
96
+
97
+ return args;
98
+ }
99
+
100
+ /**
101
+ * Validate environment for codex execution
102
+ * @returns {Object} Validation result { valid: boolean, errors: string[] }
103
+ */
104
+ function validateEnvironment() {
105
+ const errors = [];
106
+
107
+ // Check for codex binary
108
+ try {
109
+ execFileSync('which', ['codex'], { stdio: 'pipe' });
110
+ } catch (error) {
111
+ // Try common installation paths
112
+ const commonPaths = [
113
+ '/usr/local/bin/codex',
114
+ path.join(os.homedir(), '.local', 'bin', 'codex'),
115
+ path.join(os.homedir(), 'bin', 'codex'),
116
+ ];
117
+
118
+ const codexExists = commonPaths.some(p => fs.existsSync(p));
119
+ if (!codexExists) {
120
+ errors.push('codex binary not found in PATH or common locations');
121
+ }
122
+ }
123
+
124
+ // Note: OPENAI_API_KEY is optional if codex has its own stored auth (via `codex auth`)
125
+ if (!process.env.OPENAI_API_KEY) {
126
+ console.error('[codex-wrapper] Note: OPENAI_API_KEY not set, relying on codex built-in auth');
127
+ }
128
+
129
+ return {
130
+ valid: errors.length === 0,
131
+ errors,
132
+ };
133
+ }
134
+
135
+ /**
136
+ * Build codex command array
137
+ * @param {Object} options - Command options
138
+ * @returns {Object} Command structure { binary: string, args: string[] }
139
+ */
140
+ function buildCommand(options) {
141
+ const args = ['exec', '--ephemeral'];
142
+
143
+ // Approval mode (default: normal, --full-auto: automatic execution)
144
+ if (options.fullAuto) {
145
+ args.push('--full-auto');
146
+ }
147
+
148
+ // JSON output
149
+ if (options.json) {
150
+ args.push('--json');
151
+ }
152
+
153
+ // Model selection
154
+ if (options.model) {
155
+ args.push('--model', options.model);
156
+ }
157
+
158
+ // Working directory
159
+ if (options.workingDir) {
160
+ args.push('-C', options.workingDir);
161
+ }
162
+
163
+ // Add prompt as last argument
164
+ args.push(options.prompt);
165
+
166
+ return {
167
+ binary: 'codex',
168
+ args,
169
+ };
170
+ }
171
+
172
+ /**
173
+ * Execute codex command
174
+ * @param {string} binary - Binary to execute
175
+ * @param {string[]} args - Command arguments
176
+ * @param {number} timeout - Timeout in milliseconds
177
+ * @param {string|null} workingDir - Working directory
178
+ * @returns {Promise<Object>} Execution result
179
+ */
180
+ function executeCodex(binary, args, timeout, workingDir = null) {
181
+ return new Promise((resolve) => {
182
+ const startTime = Date.now();
183
+ let stdout = '';
184
+ let stderr = '';
185
+ let timedOut = false;
186
+
187
+ const spawnOptions = {
188
+ cwd: workingDir || process.cwd(),
189
+ env: process.env,
190
+ };
191
+
192
+ const child = spawn(binary, args, spawnOptions);
193
+
194
+ // Collect output
195
+ child.stdout.on('data', (data) => {
196
+ stdout += data.toString();
197
+ });
198
+
199
+ child.stderr.on('data', (data) => {
200
+ stderr += data.toString();
201
+ });
202
+
203
+ // Set timeout
204
+ const timeoutHandle = setTimeout(() => {
205
+ timedOut = true;
206
+ console.error('[codex-wrapper] Timeout reached, terminating process...', { file: 'stderr' });
207
+
208
+ // Graceful termination attempt
209
+ child.kill('SIGTERM');
210
+
211
+ // Force kill after grace period
212
+ setTimeout(() => {
213
+ if (!child.killed) {
214
+ console.error('[codex-wrapper] Force killing process...', { file: 'stderr' });
215
+ child.kill('SIGKILL');
216
+ }
217
+ }, KILL_GRACE_PERIOD_MS);
218
+ }, timeout);
219
+
220
+ // Handle process exit
221
+ child.on('close', (exitCode) => {
222
+ clearTimeout(timeoutHandle);
223
+ const durationMs = Date.now() - startTime;
224
+
225
+ resolve({
226
+ exitCode: exitCode !== null ? exitCode : 1,
227
+ stdout,
228
+ stderr,
229
+ timedOut,
230
+ durationMs,
231
+ });
232
+ });
233
+
234
+ // Handle spawn errors
235
+ child.on('error', (error) => {
236
+ clearTimeout(timeoutHandle);
237
+ const durationMs = Date.now() - startTime;
238
+
239
+ resolve({
240
+ exitCode: 1,
241
+ stdout,
242
+ stderr: stderr + '\nSpawn error: ' + error.message,
243
+ timedOut: false,
244
+ durationMs,
245
+ });
246
+ });
247
+ });
248
+ }
249
+
250
+ /**
251
+ * Parse JSON Lines output from codex
252
+ * @param {string} output - Raw output string
253
+ * @returns {Object} Parsed result { events: object[], finalMessage: string|null, parseErrors: string[] }
254
+ */
255
+ function parseJsonLines(output) {
256
+ const lines = output.split('\n').filter(line => line.trim().length > 0);
257
+ const events = [];
258
+ const parseErrors = [];
259
+ let finalMessage = null;
260
+
261
+ for (const line of lines) {
262
+ try {
263
+ const event = JSON.parse(line);
264
+ events.push(event);
265
+
266
+ // Codex CLI v0.99.0 format: item.completed events with agent_message type
267
+ if (event.type === 'item.completed' && event.item) {
268
+ if (event.item.type === 'agent_message' && event.item.text) {
269
+ finalMessage = event.item.text;
270
+ }
271
+ }
272
+ // Look for assistant message in various event structures (fallback for future API changes)
273
+ else if (event.type === 'assistant_message' && event.content) {
274
+ finalMessage = event.content;
275
+ } else if (event.message && event.message.role === 'assistant') {
276
+ finalMessage = event.message.content || event.message.text;
277
+ } else if (event.role === 'assistant' && event.content) {
278
+ finalMessage = event.content;
279
+ }
280
+ } catch (error) {
281
+ parseErrors.push(`Failed to parse line: ${error.message}`);
282
+ }
283
+ }
284
+
285
+ return {
286
+ events,
287
+ finalMessage,
288
+ parseErrors,
289
+ };
290
+ }
291
+
292
+ /**
293
+ * Main execution function
294
+ */
295
+ async function main() {
296
+ const args = parseArgs();
297
+
298
+ // Validate required arguments
299
+ if (!args.prompt) {
300
+ const result = {
301
+ success: false,
302
+ error: 'Missing required argument: --prompt',
303
+ exit_code: 2,
304
+ };
305
+ console.log(JSON.stringify(result, null, 2));
306
+ process.exit(2);
307
+ }
308
+
309
+ // Validate environment
310
+ const validation = validateEnvironment();
311
+ if (!validation.valid) {
312
+ const result = {
313
+ success: false,
314
+ error: 'Environment validation failed',
315
+ validation_errors: validation.errors,
316
+ exit_code: 2,
317
+ };
318
+ console.log(JSON.stringify(result, null, 2));
319
+ process.exit(2);
320
+ }
321
+
322
+ console.error(`[codex-wrapper] Executing codex with timeout: ${args.timeout}ms`);
323
+ if (args.workingDir) {
324
+ console.error(`[codex-wrapper] Working directory: ${args.workingDir}`);
325
+ }
326
+
327
+ // Build command
328
+ const command = buildCommand(args);
329
+ console.error(`[codex-wrapper] Command: ${command.binary} ${command.args.join(' ')}`);
330
+
331
+ // Execute
332
+ const execResult = await executeCodex(
333
+ command.binary,
334
+ command.args,
335
+ args.timeout,
336
+ args.workingDir
337
+ );
338
+
339
+ // Process result
340
+ let output = null;
341
+ let eventsCount = 0;
342
+
343
+ if (args.json && execResult.stdout) {
344
+ const parsed = parseJsonLines(execResult.stdout);
345
+ eventsCount = parsed.events.length;
346
+ output = parsed.finalMessage;
347
+
348
+ if (parsed.parseErrors.length > 0) {
349
+ console.error('[codex-wrapper] JSON parse errors:', parsed.parseErrors.join('; '));
350
+ }
351
+ } else {
352
+ output = execResult.stdout.trim();
353
+ }
354
+
355
+ // Determine success
356
+ const success = execResult.exitCode === 0 && !execResult.timedOut;
357
+
358
+ // Build result object
359
+ const result = {
360
+ success,
361
+ duration_ms: execResult.durationMs,
362
+ exit_code: execResult.exitCode,
363
+ };
364
+
365
+ if (success) {
366
+ result.output = output || execResult.stdout;
367
+ result.model = args.model || 'o3';
368
+ if (args.json) {
369
+ result.events_count = eventsCount;
370
+ }
371
+ } else {
372
+ if (execResult.timedOut) {
373
+ result.error = `Execution timed out after ${args.timeout}ms`;
374
+ } else {
375
+ result.error = 'Execution failed';
376
+ }
377
+ if (execResult.stderr) {
378
+ result.stderr = execResult.stderr.trim();
379
+ }
380
+ }
381
+
382
+ // Write output file if requested
383
+ if (args.output && output) {
384
+ try {
385
+ const outputDir = path.dirname(args.output);
386
+ if (!fs.existsSync(outputDir)) {
387
+ fs.mkdirSync(outputDir, { recursive: true });
388
+ }
389
+ fs.writeFileSync(args.output, output, 'utf-8');
390
+ console.error(`[codex-wrapper] Output written to: ${args.output}`);
391
+ } catch (error) {
392
+ console.error(`[codex-wrapper] Failed to write output file: ${error.message}`);
393
+ result.output_file_error = error.message;
394
+ }
395
+ }
396
+
397
+ // Output JSON result to stdout
398
+ console.log(JSON.stringify(result, null, 2));
399
+
400
+ process.exit(result.exit_code);
401
+ }
402
+
403
+ // Run
404
+ main().catch(error => {
405
+ const result = {
406
+ success: false,
407
+ error: 'Unexpected error: ' + error.message,
408
+ stack: error.stack,
409
+ exit_code: 1,
410
+ };
411
+ console.log(JSON.stringify(result, null, 2));
412
+ process.exit(1);
413
+ });
@@ -155,6 +155,7 @@ Flow:
155
155
  | `/npm-publish` | Publish package to npm registry |
156
156
  | `/npm-version` | Manage semantic versions |
157
157
  | `/npm-audit` | Audit dependencies |
158
+ | `/codex-exec` | Execute Codex CLI prompts |
158
159
  | `/optimize-analyze` | Analyze bundle and performance |
159
160
  | `/optimize-bundle` | Optimize bundle size |
160
161
  | `/optimize-report` | Generate optimization report |
@@ -155,6 +155,7 @@ oh-my-customcode로 구동됩니다.
155
155
  | `/npm-publish` | npm 레지스트리에 패키지 배포 |
156
156
  | `/npm-version` | 시맨틱 버전 관리 |
157
157
  | `/npm-audit` | 의존성 감사 |
158
+ | `/codex-exec` | Codex CLI 프롬프트 실행 |
158
159
  | `/optimize-analyze` | 번들 및 성능 분석 |
159
160
  | `/optimize-bundle` | 번들 크기 최적화 |
160
161
  | `/optimize-report` | 최적화 리포트 생성 |