oh-my-customcode 0.45.2 → 0.46.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.
package/README.md CHANGED
@@ -21,17 +21,17 @@ npm install -g oh-my-customcode && cd your-project && omcustom init
21
21
 
22
22
  ---
23
23
 
24
- ## What's New in v0.38.0
24
+ ## What's New in v0.46.0
25
25
 
26
26
  | Feature | Description |
27
27
  |---------|-------------|
28
- | **Interactive Init Wizard** | `omcustom init` now uses `@clack/prompts` for guided setup language, framework, team mode |
29
- | **PostCompact Hook** | Automatic rule reinforcement after context compaction (CC v2.1.76+) prevents rule amnesia |
30
- | **@omcustom/eval-core MVP** | LLM evaluation engine: session/turn/outcome collection, SQLite via Drizzle ORM, CLI interface |
31
- | **Codex-exec Auto-delegation** | Routing skills automatically delegate to Codex when available |
32
- | **CC v2.1.72~v2.1.76 Compatibility** | SessionEnd timeout config, HTML comment optimization, `autoMemoryDirectory`, full model ID support |
33
- | **Template Full Sync** | All 200+ template files are byte-identical to source |
34
- | **Hook System Hardening** | Duplicate recorder removal, context-budget field fix, orphan cleanup |
28
+ | **Rate Limit Monitoring** | Statusline now displays 5-hour rate limit usage with color-coded warnings (CC v2.1.80+) |
29
+ | **Skill Effort Override** | Skills can set `effort` frontmatter to override model effort level at invocation time |
30
+ | **Multi-project Web UI** | `omcustom serve` supports multi-project management with sidebar project selector |
31
+ | **Batch Update UI** | Web dashboard supports visual project update status and batch updates |
32
+ | **CC v2.1.72~v2.1.80 Compatibility** | Rate limits statusline, skill effort frontmatter, settings-based plugin source |
33
+ | **SDD Workflow** | Spec-Driven Development with `sdd/` folder hierarchy and planning-first gates |
34
+ | **Ambiguity Gate** | Pre-routing clarity scoring and clarification questions |
35
35
 
36
36
  ---
37
37
 
@@ -170,6 +170,9 @@ All commands are invoked inside the Claude Code conversation.
170
170
  | `/structured-dev-cycle` | 6-stage development: plan → verify → implement → verify → compound → done |
171
171
  | `/deep-plan` | Research-validated planning |
172
172
  | `/research` | 10-team parallel analysis with cross-verification |
173
+ | `/sdd-dev` | Spec-Driven Development workflow |
174
+ | `/ambiguity-gate` | Pre-routing ambiguity analysis |
175
+ | `/adversarial-review` | Attacker-mindset security code review |
173
176
 
174
177
  ### Agent Management
175
178
 
@@ -181,6 +184,13 @@ All commands are invoked inside the Claude Code conversation.
181
184
  | `/omcustom:audit-agents` | Audit agent dependencies |
182
185
  | `/omcustom:update-docs` | Sync project structure and documentation |
183
186
  | `/omcustom:sauron-watch` | Full structural verification (5+3 rounds) |
187
+ | `/omcustom:feedback` | Submit feedback as GitHub issue |
188
+
189
+ ### Web UI
190
+
191
+ | Command | What it does |
192
+ |---------|-------------|
193
+ | `/omcustom:web` | Control built-in Web UI (start, stop, status, open) |
184
194
 
185
195
  ### Package & Release
186
196
 
@@ -230,7 +240,7 @@ oh-my-customcode includes security and lifecycle hooks:
230
240
  | secret-filter | Bash, Read output | Detects AWS keys, API tokens, private keys, bearer tokens |
231
241
  | audit-log | Edit, Write, Bash, Agent | Append-only JSONL at `~/.claude/audit.jsonl` |
232
242
  | schema-validator | Write, Edit, Bash input | Validates tool inputs, flags dangerous patterns |
233
- | PostCompact | Context compaction | Reinjects enforced rules (R007–R018) — prevents rule amnesia |
243
+ | PostCompact | Context compaction | Reinjects enforced rules (R007–R018, R021) — prevents rule amnesia |
234
244
 
235
245
  Security hooks are advisory (exit 0). They warn but never block.
236
246
 
@@ -246,6 +256,10 @@ omcustom list # List components
246
256
  omcustom doctor # Verify installation
247
257
  omcustom doctor --fix # Auto-fix issues
248
258
  omcustom security # Scan for security issues
259
+ omcustom projects # List managed projects with version status
260
+ omcustom update --all # Batch update all outdated projects
261
+ omcustom serve # Start built-in Web UI
262
+ omcustom serve-stop # Stop Web UI
249
263
  ```
250
264
 
251
265
  ---
@@ -257,7 +271,7 @@ your-project/
257
271
  ├── CLAUDE.md # Entry point
258
272
  ├── .claude/
259
273
  │ ├── agents/ # 45 agent definitions
260
- │ ├── skills/ # 78 skill modules
274
+ │ ├── skills/ # 82 skill modules
261
275
  │ ├── rules/ # 21 governance rules (R000-R021)
262
276
  │ ├── hooks/ # 15 lifecycle hook scripts
263
277
  │ ├── schemas/ # Tool input validation schemas
package/dist/cli/index.js CHANGED
@@ -9323,7 +9323,7 @@ var init_package = __esm(() => {
9323
9323
  package_default = {
9324
9324
  name: "oh-my-customcode",
9325
9325
  workspaces: ["packages/*"],
9326
- version: "0.45.2",
9326
+ version: "0.46.1",
9327
9327
  description: "Batteries-included agent harness for Claude Code",
9328
9328
  type: "module",
9329
9329
  bin: {
@@ -9347,7 +9347,7 @@ var init_package = __esm(() => {
9347
9347
  },
9348
9348
  scripts: {
9349
9349
  dev: "bun run src/cli/index.ts",
9350
- build: "bun build src/cli/index.ts --outdir dist/cli --target node && bun build src/index.ts --outdir dist --target node",
9350
+ build: "bun build src/cli/index.ts --outdir dist/cli --target node && bun build src/index.ts --outdir dist --target node && bun run scripts/sync-source-lockfile.ts",
9351
9351
  test: "bun test",
9352
9352
  "test:unit": "bun test tests/unit",
9353
9353
  "test:integration": "bun test tests/integration",
@@ -9501,8 +9501,16 @@ async function searchDirectory(dir2, depth, results, currentVersion, seen) {
9501
9501
  await Promise.all(subdirs.map((subdir) => searchDirectory(join9(dir2, subdir.name), depth + 1, results, currentVersion, seen)));
9502
9502
  }
9503
9503
  }
9504
+ async function getTemplateVersion() {
9505
+ const manifestPath = resolveTemplatePath("manifest.json");
9506
+ if (await fileExists(manifestPath)) {
9507
+ const manifest = await readJsonFile(manifestPath);
9508
+ return manifest.version;
9509
+ }
9510
+ return package_default.version;
9511
+ }
9504
9512
  async function findProjects(options = {}) {
9505
- const currentVersion = package_default.version;
9513
+ const currentVersion = await getTemplateVersion();
9506
9514
  const home = homedir2();
9507
9515
  const seen = new Set;
9508
9516
  const results = [];
@@ -9589,7 +9597,7 @@ oh-my-customcode 적용 프로젝트 (${projects.length}개):`);
9589
9597
  현재 설치 버전: v${currentVersion}`);
9590
9598
  }
9591
9599
  async function projectsCommand(options = {}) {
9592
- const currentVersion = package_default.version;
9600
+ const currentVersion = await getTemplateVersion();
9593
9601
  const format = options.format || "table";
9594
9602
  console.log(" oh-my-customcode 적용 프로젝트를 검색 중...");
9595
9603
  try {
@@ -9611,6 +9619,7 @@ async function projectsCommand(options = {}) {
9611
9619
  var DEFAULT_SEARCH_DIRS, MAX_SEARCH_DEPTH = 3, projects_default;
9612
9620
  var init_projects = __esm(() => {
9613
9621
  init_package();
9622
+ init_fs();
9614
9623
  DEFAULT_SEARCH_DIRS = ["workspace", "projects", "dev", "src", "code", "repos", "work"];
9615
9624
  projects_default = projectsCommand;
9616
9625
  });
@@ -27767,7 +27776,7 @@ async function startServeBackground(projectRoot, port = DEFAULT_PORT) {
27767
27776
  OMCUSTOM_PORT: String(port),
27768
27777
  OMCUSTOM_HOST: "localhost",
27769
27778
  OMCUSTOM_ORIGIN: `http://localhost:${port}`,
27770
- OMCUSTOM_PROJECT_ROOT: projectRoot
27779
+ OMX_PROJECT_ROOT: projectRoot
27771
27780
  },
27772
27781
  stdio: "ignore",
27773
27782
  detached: true
@@ -29693,7 +29702,7 @@ function runForeground(projectRoot, port) {
29693
29702
  OMCUSTOM_PORT: String(port),
29694
29703
  OMCUSTOM_HOST: "localhost",
29695
29704
  OMCUSTOM_ORIGIN: `http://localhost:${port}`,
29696
- OMCUSTOM_PROJECT_ROOT: projectRoot
29705
+ OMX_PROJECT_ROOT: projectRoot
29697
29706
  },
29698
29707
  stdio: "inherit"
29699
29708
  });
@@ -30029,6 +30038,16 @@ async function update(options) {
30029
30038
  info("update.start", { targetDir: options.targetDir });
30030
30039
  const config = await loadConfig(options.targetDir);
30031
30040
  result.previousVersion = config.version;
30041
+ const targetPkgPath = join14(options.targetDir, "package.json");
30042
+ if (await fileExists(targetPkgPath)) {
30043
+ const targetPkg = await readJsonFile(targetPkgPath);
30044
+ if (targetPkg.name === "oh-my-customcode") {
30045
+ warn("update.self_update_skipped");
30046
+ result.success = true;
30047
+ result.warnings.push("Skipped: source project cannot update itself");
30048
+ return result;
30049
+ }
30050
+ }
30032
30051
  const updateCheck = await checkForUpdates(options.targetDir);
30033
30052
  result.newVersion = updateCheck.latestVersion;
30034
30053
  if (!updateCheck.hasUpdates && !options.force) {
package/dist/index.js CHANGED
@@ -1952,6 +1952,16 @@ async function update(options) {
1952
1952
  info("update.start", { targetDir: options.targetDir });
1953
1953
  const config = await loadConfig(options.targetDir);
1954
1954
  result.previousVersion = config.version;
1955
+ const targetPkgPath = join6(options.targetDir, "package.json");
1956
+ if (await fileExists(targetPkgPath)) {
1957
+ const targetPkg = await readJsonFile(targetPkgPath);
1958
+ if (targetPkg.name === "oh-my-customcode") {
1959
+ warn("update.self_update_skipped");
1960
+ result.success = true;
1961
+ result.warnings.push("Skipped: source project cannot update itself");
1962
+ return result;
1963
+ }
1964
+ }
1955
1965
  const updateCheck = await checkForUpdates(options.targetDir);
1956
1966
  result.newVersion = updateCheck.latestVersion;
1957
1967
  if (!updateCheck.hasUpdates && !options.force) {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "oh-my-customcode",
3
3
  "workspaces": ["packages/*"],
4
- "version": "0.45.2",
4
+ "version": "0.46.1",
5
5
  "description": "Batteries-included agent harness for Claude Code",
6
6
  "type": "module",
7
7
  "bin": {
@@ -25,7 +25,7 @@
25
25
  },
26
26
  "scripts": {
27
27
  "dev": "bun run src/cli/index.ts",
28
- "build": "bun build src/cli/index.ts --outdir dist/cli --target node && bun build src/index.ts --outdir dist --target node",
28
+ "build": "bun build src/cli/index.ts --outdir dist/cli --target node && bun build src/index.ts --outdir dist --target node && bun run scripts/sync-source-lockfile.ts",
29
29
  "test": "bun test",
30
30
  "test:unit": "bun test tests/unit",
31
31
  "test:integration": "bun test tests/integration",
@@ -167,8 +167,11 @@ context: fork # Forked context for isolated execution
167
167
  version: 1.0.0 # Semantic version
168
168
  user-invocable: false # Whether user can invoke directly
169
169
  disable-model-invocation: true # Prevent model from auto-invoking
170
+ effort: medium # low | medium | high — overrides model effort level when invoked
170
171
  ```
171
172
 
173
+ When both an agent and its invoked skill specify `effort`, the skill's value takes precedence (more specific invocation-time setting).
174
+
172
175
  ### Skill Effectiveness Tracking
173
176
 
174
177
  Skills can optionally track effectiveness metrics via auto-populated fields:
@@ -41,10 +41,10 @@ Implemented in `.claude/hooks/hooks.json` (PreToolUse → Agent/Task matcher).
41
41
  ### Format
42
42
 
43
43
  ```
44
- {Cost} | {project} | {branch} | CTX:{usage}%
44
+ {Cost} | {project} | {branch} | RL:{rate_limit}% | CTX:{usage}%
45
45
  ```
46
46
 
47
- Example: `$0.05 | my-project | develop | CTX:42%`
47
+ Example: `$0.05 | my-project | develop | RL:45% | CTX:42%`
48
48
 
49
49
  ### Configuration
50
50
 
@@ -58,7 +58,7 @@ Example: `$0.05 | my-project | develop | CTX:42%`
58
58
  }
59
59
  ```
60
60
 
61
- Set in `.claude/settings.local.json`. The command receives JSON via stdin with model, workspace, context window, and cost data.
61
+ Set in `.claude/settings.local.json`. The command receives JSON via stdin with model, workspace, context window, cost, and rate limit data.
62
62
 
63
63
  ### Color Coding
64
64
 
@@ -67,10 +67,15 @@ Set in `.claude/settings.local.json`. The command receives JSON via stdin with m
67
67
  | Cost | < $1.00 | Green |
68
68
  | Cost | $1.00 - $4.99 | Yellow |
69
69
  | Cost | >= $5.00 | Red |
70
+ | Rate Limit | < 50% | Green |
71
+ | Rate Limit | 50-79% | Yellow |
72
+ | Rate Limit | >= 80% | Red |
70
73
  | Context | < 60% | Green |
71
74
  | Context | 60-79% | Yellow |
72
75
  | Context | >= 80% | Red |
73
76
 
77
+ The `RL:{rate_limit}%` segment only appears when Claude Code v2.1.80+ provides `rate_limits` data. On older versions, this segment is omitted.
78
+
74
79
  ## Integration
75
80
 
76
81
  Integrates with R007 (Agent ID), R008 (Tool ID), R009 (Parallel).
@@ -11,7 +11,11 @@
11
11
  # "model": { "display_name": "claude-opus-4-6" },
12
12
  # "workspace": { "current_dir": "/path/to/project" },
13
13
  # "context_window": { "used_percentage": 42, "context_window_size": 200000 },
14
- # "cost": { "total_cost_usd": 0.05 }
14
+ # "cost": { "total_cost_usd": 0.05 },
15
+ # "rate_limits": { (v2.1.80+, optional)
16
+ # "five_hour": { "used_percentage": 10, "resets_at": 1773979200 },
17
+ # "seven_day": { "used_percentage": 90, "resets_at": 1773979200 }
18
+ # }
15
19
  # }
16
20
 
17
21
  # ---------------------------------------------------------------------------
@@ -27,13 +31,13 @@ if [[ -n "${NO_COLOR}" || "${TERM}" == "dumb" ]]; then
27
31
  COLOR_CTX_WARN=""
28
32
  COLOR_CTX_CRIT=""
29
33
  else
30
- COLOR_RESET="\033[0m"
31
- COLOR_OPUS="\033[1;35m" # Magenta bold
32
- COLOR_SONNET="\033[0;36m" # Cyan
33
- COLOR_HAIKU="\033[0;32m" # Green
34
- COLOR_CTX_OK="\033[0;32m" # Green (< 60%)
35
- COLOR_CTX_WARN="\033[0;33m" # Yellow (60-79%)
36
- COLOR_CTX_CRIT="\033[0;31m" # Red (>= 80%)
34
+ COLOR_RESET=$'\033[0m'
35
+ COLOR_OPUS=$'\033[1;35m' # Magenta bold
36
+ COLOR_SONNET=$'\033[0;36m' # Cyan
37
+ COLOR_HAIKU=$'\033[0;32m' # Green
38
+ COLOR_CTX_OK=$'\033[0;32m' # Green (< 60%)
39
+ COLOR_CTX_WARN=$'\033[0;33m' # Yellow (60-79%)
40
+ COLOR_CTX_CRIT=$'\033[0;31m' # Red (>= 80%)
37
41
  fi
38
42
 
39
43
  # ---------------------------------------------------------------------------
@@ -57,15 +61,16 @@ fi
57
61
 
58
62
  # ---------------------------------------------------------------------------
59
63
  # 4. Single jq call — extract all fields as TSV
60
- # Fields: model_name, project_dir, ctx_pct, ctx_size, cost_usd
64
+ # Fields: model_name, project_dir, ctx_pct, ctx_size, cost_usd, rl_5h_pct
61
65
  # ---------------------------------------------------------------------------
62
- IFS=$'\t' read -r model_name project_dir ctx_pct ctx_size cost_usd <<< "$(
66
+ IFS=$'\t' read -r model_name project_dir ctx_pct ctx_size cost_usd rl_5h_pct <<< "$(
63
67
  printf '%s' "$json" | jq -r '[
64
68
  (.model.display_name // "unknown"),
65
69
  (.workspace.current_dir // ""),
66
70
  (.context_window.used_percentage // 0),
67
71
  (.context_window.context_window_size // 0),
68
- (.cost.total_cost_usd // 0)
72
+ (.cost.total_cost_usd // 0),
73
+ (.rate_limits.five_hour.used_percentage // -1)
69
74
  ] | @tsv'
70
75
  )"
71
76
 
@@ -73,7 +78,7 @@ IFS=$'\t' read -r model_name project_dir ctx_pct ctx_size cost_usd <<< "$(
73
78
  # 4b. Cost & context data bridge — write to temp file for hooks
74
79
  # ---------------------------------------------------------------------------
75
80
  COST_BRIDGE_FILE="/tmp/.claude-cost-${PPID}"
76
- printf '%s\t%s\t%s\n' "$cost_usd" "$ctx_pct" "$(date +%s)" > "$COST_BRIDGE_FILE" 2>/dev/null || true
81
+ printf '%s\t%s\t%s\t%s\n' "$cost_usd" "$ctx_pct" "$(date +%s)" "$rl_5h_pct" > "$COST_BRIDGE_FILE" 2>/dev/null || true
77
82
 
78
83
  # ---------------------------------------------------------------------------
79
84
  # 5. Model display name + color (bash 3.2 compatible case pattern matching)
@@ -236,6 +241,29 @@ fi
236
241
 
237
242
  ctx_display="CTX:${ctx_int}%"
238
243
 
244
+ # ---------------------------------------------------------------------------
245
+ # 9b. Rate limit percentage with color (v2.1.80+, optional)
246
+ # ---------------------------------------------------------------------------
247
+ rl_display=""
248
+ rl_color=""
249
+ # rl_5h_pct is -1 when rate_limits field is absent (pre-v2.1.80 compatibility)
250
+ rl_5h_int="${rl_5h_pct%%.*}"
251
+ # Ensure it's a valid integer (fallback to -1)
252
+ if ! [[ "$rl_5h_int" =~ ^-?[0-9]+$ ]]; then
253
+ rl_5h_int=-1
254
+ fi
255
+
256
+ if [[ "$rl_5h_int" -ge 0 ]]; then
257
+ rl_display="RL:${rl_5h_int}%"
258
+ if [[ "$rl_5h_int" -ge 80 ]]; then
259
+ rl_color="${COLOR_CTX_CRIT}" # Red (>= 80%)
260
+ elif [[ "$rl_5h_int" -ge 50 ]]; then
261
+ rl_color="${COLOR_CTX_WARN}" # Yellow (50-79%)
262
+ else
263
+ rl_color="${COLOR_CTX_OK}" # Green (< 50%)
264
+ fi
265
+ fi
266
+
239
267
  # ---------------------------------------------------------------------------
240
268
  # 10. Assemble and output the status line
241
269
  # ---------------------------------------------------------------------------
@@ -253,17 +281,25 @@ if [[ -n "$pr_display" ]]; then
253
281
  pr_segment=" | ${pr_display}"
254
282
  fi
255
283
 
284
+ # Build the RL segment (with separator) if present
285
+ rl_segment=""
286
+ if [[ -n "$rl_display" ]]; then
287
+ rl_segment=" | ${rl_color}${rl_display}${COLOR_RESET}"
288
+ fi
289
+
256
290
  if [[ -n "$git_branch" ]]; then
257
- printf "${cost_color}%s${COLOR_RESET} | %s | %s%s | ${ctx_color}%s${COLOR_RESET}\n" \
291
+ printf "${cost_color}%s${COLOR_RESET} | %s | %s%s%s | ${ctx_color}%s${COLOR_RESET}\n" \
258
292
  "$cost_display" \
259
293
  "$project_name" \
260
294
  "$branch_display" \
261
295
  "$pr_segment" \
296
+ "$rl_segment" \
262
297
  "$ctx_display"
263
298
  else
264
- printf "${cost_color}%s${COLOR_RESET} | %s%s | ${ctx_color}%s${COLOR_RESET}\n" \
299
+ printf "${cost_color}%s${COLOR_RESET} | %s%s%s | ${ctx_color}%s${COLOR_RESET}\n" \
265
300
  "$cost_display" \
266
301
  "$project_name" \
267
302
  "$pr_segment" \
303
+ "$rl_segment" \
268
304
  "$ctx_display"
269
305
  fi
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "0.45.2",
2
+ "version": "0.46.1",
3
3
  "lastUpdated": "2026-03-16T00:00:00.000Z",
4
4
  "components": [
5
5
  {