oh-my-customcode 0.46.1 → 0.47.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.
- package/README.md +7 -6
- package/dist/cli/index.js +158 -28
- package/package.json +4 -4
- package/templates/.claude/hooks/hooks.json +9 -1
- package/templates/.claude/skills/dev-refactor/SKILL.md +3 -3
- package/templates/.claude/skills/omcustom-feedback/SKILL.md +135 -26
- package/templates/.claude/skills/omcustom-loop/SKILL.md +45 -0
- package/templates/.claude/skills/omcustom-release-notes/SKILL.md +3 -3
- package/templates/.claude/skills/omcustom-takeover/SKILL.md +3 -3
- package/templates/.claude/statusline.sh +8 -2
- package/templates/CLAUDE.md +9 -8
- package/templates/CLAUDE.md.en +2 -2
- package/templates/CLAUDE.md.ko +2 -2
- package/templates/manifest.json +2 -2
package/README.md
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
|
|
14
14
|
**[한국어 문서 (Korean)](./README_ko.md)**
|
|
15
15
|
|
|
16
|
-
45 agents.
|
|
16
|
+
45 agents. 83 skills. 21 rules. One command.
|
|
17
17
|
|
|
18
18
|
```bash
|
|
19
19
|
npm install -g oh-my-customcode && cd your-project && omcustom init
|
|
@@ -138,7 +138,7 @@ Each agent declares its tools, model, memory scope, and limitations in YAML fron
|
|
|
138
138
|
|
|
139
139
|
---
|
|
140
140
|
|
|
141
|
-
### Skills (
|
|
141
|
+
### Skills (83)
|
|
142
142
|
|
|
143
143
|
| Category | Count | Includes |
|
|
144
144
|
|----------|-------|----------|
|
|
@@ -180,11 +180,11 @@ All commands are invoked inside the Claude Code conversation.
|
|
|
180
180
|
|---------|-------------|
|
|
181
181
|
| `/omcustom:analysis` | Analyze project, auto-configure agents and skills |
|
|
182
182
|
| `/omcustom:create-agent` | Create a new agent |
|
|
183
|
-
| `/omcustom
|
|
183
|
+
| `/omcustom-takeover` | Extract canonical spec from existing agent or skill |
|
|
184
184
|
| `/omcustom:audit-agents` | Audit agent dependencies |
|
|
185
185
|
| `/omcustom:update-docs` | Sync project structure and documentation |
|
|
186
186
|
| `/omcustom:sauron-watch` | Full structural verification (5+3 rounds) |
|
|
187
|
-
| `/omcustom
|
|
187
|
+
| `/omcustom-feedback` | Submit feedback as GitHub issue |
|
|
188
188
|
|
|
189
189
|
### Web UI
|
|
190
190
|
|
|
@@ -199,7 +199,7 @@ All commands are invoked inside the Claude Code conversation.
|
|
|
199
199
|
| `/omcustom:npm-publish` | Publish to npm |
|
|
200
200
|
| `/omcustom:npm-version` | Semantic versioning |
|
|
201
201
|
| `/omcustom:npm-audit` | Dependency security audit |
|
|
202
|
-
| `/omcustom
|
|
202
|
+
| `/omcustom-release-notes` | Generate release notes from git history |
|
|
203
203
|
|
|
204
204
|
### Memory & System
|
|
205
205
|
|
|
@@ -208,6 +208,7 @@ All commands are invoked inside the Claude Code conversation.
|
|
|
208
208
|
| `/memory-save` | Save session context |
|
|
209
209
|
| `/memory-recall` | Search and recall memories |
|
|
210
210
|
| `/omcustom:monitoring-setup` | OTel monitoring toggle |
|
|
211
|
+
| `/omcustom:loop` | Auto-continue background agent workflows (3-continue safety limit) |
|
|
211
212
|
| `/omcustom:lists` | Show all commands |
|
|
212
213
|
| `/omcustom:status` | System health check |
|
|
213
214
|
|
|
@@ -271,7 +272,7 @@ your-project/
|
|
|
271
272
|
├── CLAUDE.md # Entry point
|
|
272
273
|
├── .claude/
|
|
273
274
|
│ ├── agents/ # 45 agent definitions
|
|
274
|
-
│ ├── skills/ #
|
|
275
|
+
│ ├── skills/ # 83 skill modules
|
|
275
276
|
│ ├── rules/ # 21 governance rules (R000-R021)
|
|
276
277
|
│ ├── hooks/ # 15 lifecycle hook scripts
|
|
277
278
|
│ ├── 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.
|
|
9326
|
+
version: "0.47.0",
|
|
9327
9327
|
description: "Batteries-included agent harness for Claude Code",
|
|
9328
9328
|
type: "module",
|
|
9329
9329
|
bin: {
|
|
@@ -9353,9 +9353,9 @@ var init_package = __esm(() => {
|
|
|
9353
9353
|
"test:integration": "bun test tests/integration",
|
|
9354
9354
|
"test:e2e": "bun test tests/e2e",
|
|
9355
9355
|
"test:coverage": "bun test --coverage",
|
|
9356
|
-
lint: "biome check
|
|
9357
|
-
"lint:fix": "biome check --write
|
|
9358
|
-
format: "biome format --write
|
|
9356
|
+
lint: "biome check src/ tests/ scripts/",
|
|
9357
|
+
"lint:fix": "biome check --write src/ tests/ scripts/",
|
|
9358
|
+
format: "biome format --write src/ tests/ scripts/",
|
|
9359
9359
|
typecheck: "tsc --noEmit",
|
|
9360
9360
|
"docs:dev": "vitepress dev docs",
|
|
9361
9361
|
"docs:build": "vitepress build docs",
|
|
@@ -9419,7 +9419,7 @@ __export(exports_projects, {
|
|
|
9419
9419
|
default: () => projects_default
|
|
9420
9420
|
});
|
|
9421
9421
|
import { homedir as homedir2 } from "node:os";
|
|
9422
|
-
import { basename as basename3, join as join9 } from "node:path";
|
|
9422
|
+
import { basename as basename3, dirname as dirname3, join as join9 } from "node:path";
|
|
9423
9423
|
async function readLockFile(projectDir) {
|
|
9424
9424
|
const lockFilePath = join9(projectDir, ".omcustom.lock.json");
|
|
9425
9425
|
try {
|
|
@@ -9518,6 +9518,14 @@ async function findProjects(options = {}) {
|
|
|
9518
9518
|
for (const dir2 of DEFAULT_SEARCH_DIRS) {
|
|
9519
9519
|
searchPaths.push(join9(home, dir2));
|
|
9520
9520
|
}
|
|
9521
|
+
if (!options.paths) {
|
|
9522
|
+
const cwd = process.cwd();
|
|
9523
|
+
if (!searchPaths.includes(cwd))
|
|
9524
|
+
searchPaths.push(cwd);
|
|
9525
|
+
const parent = dirname3(cwd);
|
|
9526
|
+
if (parent !== cwd && !searchPaths.includes(parent))
|
|
9527
|
+
searchPaths.push(parent);
|
|
9528
|
+
}
|
|
9521
9529
|
if (options.paths) {
|
|
9522
9530
|
searchPaths.push(...options.paths);
|
|
9523
9531
|
}
|
|
@@ -9546,7 +9554,7 @@ function formatProjectsTable(projects, currentVersion) {
|
|
|
9546
9554
|
if (projects.length === 0) {
|
|
9547
9555
|
console.log(`
|
|
9548
9556
|
oh-my-customcode가 적용된 프로젝트를 찾을 수 없습니다.`);
|
|
9549
|
-
console.log(` 검색 경로: ~/workspace, ~/projects, ~/dev, ~/src, ~/code
|
|
9557
|
+
console.log(` 검색 경로: ~/workspace, ~/projects, ~/dev, ~/src, ~/code, ~/repos, ~/work, (현재 디렉토리 및 부모)
|
|
9550
9558
|
`);
|
|
9551
9559
|
return;
|
|
9552
9560
|
}
|
|
@@ -24896,6 +24904,37 @@ var en_default = {
|
|
|
24896
24904
|
}
|
|
24897
24905
|
}
|
|
24898
24906
|
},
|
|
24907
|
+
web: {
|
|
24908
|
+
description: "Manage the Web UI server (start, stop, status, open)",
|
|
24909
|
+
start: {
|
|
24910
|
+
description: "Start the Web UI server",
|
|
24911
|
+
portOption: "Port number",
|
|
24912
|
+
openOption: "Open browser automatically after start",
|
|
24913
|
+
foregroundOption: "Run in foreground (not detached)",
|
|
24914
|
+
started: "Web UI started: http://localhost:{{port}}",
|
|
24915
|
+
failed: "Failed to start Web UI server"
|
|
24916
|
+
},
|
|
24917
|
+
stop: {
|
|
24918
|
+
description: "Stop the Web UI server",
|
|
24919
|
+
stopped: "Web UI server stopped",
|
|
24920
|
+
notRunning: "Web UI server is not running"
|
|
24921
|
+
},
|
|
24922
|
+
status: {
|
|
24923
|
+
description: "Show Web UI server status",
|
|
24924
|
+
running: "Web UI is running: http://localhost:{{port}}",
|
|
24925
|
+
notRunning: "Web UI is not running",
|
|
24926
|
+
startHint: " Start with: omcustom web start"
|
|
24927
|
+
},
|
|
24928
|
+
open: {
|
|
24929
|
+
description: "Open the Web UI in the default browser",
|
|
24930
|
+
portOption: "Port number",
|
|
24931
|
+
notRunningWarn: "Web UI does not appear to be running. Start it with: omcustom web start"
|
|
24932
|
+
},
|
|
24933
|
+
deprecated: {
|
|
24934
|
+
serve: "[Deprecated] `omcustom serve` is deprecated. Use `omcustom web start` instead.",
|
|
24935
|
+
serveStop: "[Deprecated] `omcustom serve-stop` is deprecated. Use `omcustom web stop` instead."
|
|
24936
|
+
}
|
|
24937
|
+
},
|
|
24899
24938
|
security: {
|
|
24900
24939
|
description: "Scan for security issues in hooks, configs, and templates",
|
|
24901
24940
|
verboseOption: "Show detailed scan results",
|
|
@@ -25247,6 +25286,37 @@ var ko_default = {
|
|
|
25247
25286
|
}
|
|
25248
25287
|
}
|
|
25249
25288
|
},
|
|
25289
|
+
web: {
|
|
25290
|
+
description: "Web UI 서버 관리 (시작, 중지, 상태, 열기)",
|
|
25291
|
+
start: {
|
|
25292
|
+
description: "Web UI 서버 시작",
|
|
25293
|
+
portOption: "포트 번호",
|
|
25294
|
+
openOption: "시작 후 브라우저 자동 열기",
|
|
25295
|
+
foregroundOption: "포그라운드 실행 (백그라운드 분리 안 함)",
|
|
25296
|
+
started: "Web UI 시작됨: http://localhost:{{port}}",
|
|
25297
|
+
failed: "Web UI 서버 시작 실패"
|
|
25298
|
+
},
|
|
25299
|
+
stop: {
|
|
25300
|
+
description: "Web UI 서버 중지",
|
|
25301
|
+
stopped: "Web UI 서버가 중지되었습니다",
|
|
25302
|
+
notRunning: "Web UI 서버가 실행 중이 아닙니다"
|
|
25303
|
+
},
|
|
25304
|
+
status: {
|
|
25305
|
+
description: "Web UI 서버 상태 표시",
|
|
25306
|
+
running: "Web UI 실행 중: http://localhost:{{port}}",
|
|
25307
|
+
notRunning: "Web UI가 실행 중이 아닙니다",
|
|
25308
|
+
startHint: " 시작하려면: omcustom web start"
|
|
25309
|
+
},
|
|
25310
|
+
open: {
|
|
25311
|
+
description: "기본 브라우저에서 Web UI 열기",
|
|
25312
|
+
portOption: "포트 번호",
|
|
25313
|
+
notRunningWarn: "Web UI가 실행 중이지 않은 것 같습니다. 먼저 시작하세요: omcustom web start"
|
|
25314
|
+
},
|
|
25315
|
+
deprecated: {
|
|
25316
|
+
serve: "[Deprecated] `omcustom serve` is deprecated. Use `omcustom web start` instead.",
|
|
25317
|
+
serveStop: "[Deprecated] `omcustom serve-stop` is deprecated. Use `omcustom web stop` instead."
|
|
25318
|
+
}
|
|
25319
|
+
},
|
|
25250
25320
|
security: {
|
|
25251
25321
|
description: "훅, 설정, 템플릿의 보안 문제 검사",
|
|
25252
25322
|
verboseOption: "상세 검사 결과 표시",
|
|
@@ -27738,13 +27808,15 @@ import { readFile as readFile2, unlink, writeFile as writeFile2 } from "node:fs/
|
|
|
27738
27808
|
import { join as join10 } from "node:path";
|
|
27739
27809
|
var DEFAULT_PORT = 4321;
|
|
27740
27810
|
var PID_FILE = join10(process.env.HOME ?? "~", ".omcustom-serve.pid");
|
|
27741
|
-
function findServeBuildDir(projectRoot) {
|
|
27811
|
+
function findServeBuildDir(projectRoot, options) {
|
|
27742
27812
|
const localBuild = join10(projectRoot, "packages", "serve", "build");
|
|
27743
27813
|
if (existsSync2(join10(localBuild, "index.js")))
|
|
27744
27814
|
return localBuild;
|
|
27745
|
-
|
|
27746
|
-
|
|
27747
|
-
|
|
27815
|
+
if (options?.skipNpmFallback !== true) {
|
|
27816
|
+
const npmBuild = join10(import.meta.dirname, "..", "..", "packages", "serve", "build");
|
|
27817
|
+
if (existsSync2(join10(npmBuild, "index.js")))
|
|
27818
|
+
return npmBuild;
|
|
27819
|
+
}
|
|
27748
27820
|
return null;
|
|
27749
27821
|
}
|
|
27750
27822
|
async function isServeRunning() {
|
|
@@ -27762,11 +27834,11 @@ async function isServeRunning() {
|
|
|
27762
27834
|
return false;
|
|
27763
27835
|
}
|
|
27764
27836
|
}
|
|
27765
|
-
async function startServeBackground(projectRoot, port = DEFAULT_PORT) {
|
|
27837
|
+
async function startServeBackground(projectRoot, port = DEFAULT_PORT, buildDirOpts) {
|
|
27766
27838
|
if (await isServeRunning()) {
|
|
27767
27839
|
return;
|
|
27768
27840
|
}
|
|
27769
|
-
const buildDir = findServeBuildDir(projectRoot);
|
|
27841
|
+
const buildDir = findServeBuildDir(projectRoot, buildDirOpts);
|
|
27770
27842
|
if (buildDir === null) {
|
|
27771
27843
|
return;
|
|
27772
27844
|
}
|
|
@@ -28926,7 +28998,7 @@ async function initCommand(options) {
|
|
|
28926
28998
|
}
|
|
28927
28999
|
|
|
28928
29000
|
// src/cli/list.ts
|
|
28929
|
-
import { basename as basename4, dirname as
|
|
29001
|
+
import { basename as basename4, dirname as dirname4, join as join12, relative as relative3 } from "node:path";
|
|
28930
29002
|
init_fs();
|
|
28931
29003
|
var ALLOWED_TOP_LEVEL_KEYS = new Set(["name", "type", "description", "version", "category"]);
|
|
28932
29004
|
function parseKeyValue(line) {
|
|
@@ -29127,7 +29199,7 @@ async function getSkills(targetDir, rootDir = ".claude", config) {
|
|
|
29127
29199
|
const customSkillPaths = new Set(customComponents.filter((c) => c.type === "skill").map((c) => c.path));
|
|
29128
29200
|
const skillMdFiles = await listFiles(skillsDir, { recursive: true, pattern: "SKILL.md" });
|
|
29129
29201
|
const skills = await Promise.all(skillMdFiles.map(async (skillMdPath) => {
|
|
29130
|
-
const skillDir =
|
|
29202
|
+
const skillDir = dirname4(skillMdPath);
|
|
29131
29203
|
const indexYamlPath = join12(skillDir, "index.yaml");
|
|
29132
29204
|
const { description, version } = await tryReadIndexYamlMetadata(indexYamlPath);
|
|
29133
29205
|
const relativePath = relative3(targetDir, skillDir);
|
|
@@ -29664,38 +29736,41 @@ async function serveCommand(options) {
|
|
|
29664
29736
|
console.error(`Invalid port: ${options.port}`);
|
|
29665
29737
|
process.exit(1);
|
|
29666
29738
|
}
|
|
29667
|
-
const cwd = process.cwd();
|
|
29739
|
+
const cwd = options._projectRoot ?? process.cwd();
|
|
29740
|
+
const buildDirOpts = {
|
|
29741
|
+
skipNpmFallback: options._projectRoot !== undefined
|
|
29742
|
+
};
|
|
29668
29743
|
if (options.foreground === true) {
|
|
29669
|
-
runForeground(cwd, port);
|
|
29744
|
+
runForeground(cwd, port, buildDirOpts);
|
|
29670
29745
|
return;
|
|
29671
29746
|
}
|
|
29672
|
-
await startServeBackground(cwd, port);
|
|
29747
|
+
await startServeBackground(cwd, port, buildDirOpts);
|
|
29673
29748
|
const running = await isServeRunning();
|
|
29674
29749
|
if (running) {
|
|
29675
|
-
console.log(
|
|
29750
|
+
console.log(i18n.t("cli.web.start.started", { port }));
|
|
29676
29751
|
if (options.open === true) {
|
|
29677
29752
|
openBrowser(port);
|
|
29678
29753
|
}
|
|
29679
29754
|
} else {
|
|
29680
|
-
console.error("
|
|
29755
|
+
console.error(i18n.t("cli.web.start.failed"));
|
|
29681
29756
|
process.exit(1);
|
|
29682
29757
|
}
|
|
29683
29758
|
}
|
|
29684
29759
|
async function serveStopCommand() {
|
|
29685
29760
|
const stopped = await stopServe();
|
|
29686
29761
|
if (stopped) {
|
|
29687
|
-
console.log("
|
|
29762
|
+
console.log(i18n.t("cli.web.stop.stopped"));
|
|
29688
29763
|
} else {
|
|
29689
|
-
console.log("
|
|
29764
|
+
console.log(i18n.t("cli.web.stop.notRunning"));
|
|
29690
29765
|
}
|
|
29691
29766
|
}
|
|
29692
|
-
function runForeground(projectRoot, port) {
|
|
29693
|
-
const buildDir = findServeBuildDir(projectRoot);
|
|
29767
|
+
function runForeground(projectRoot, port, buildDirOpts) {
|
|
29768
|
+
const buildDir = findServeBuildDir(projectRoot, buildDirOpts);
|
|
29694
29769
|
if (buildDir === null) {
|
|
29695
29770
|
console.error("Web UI build not found. Run: cd packages/serve && bun run build");
|
|
29696
29771
|
process.exit(1);
|
|
29697
29772
|
}
|
|
29698
|
-
console.log(`Web UI: http://
|
|
29773
|
+
console.log(`Web UI: http://localhost:${port}`);
|
|
29699
29774
|
spawnSync2("node", [join13(buildDir, "index.js")], {
|
|
29700
29775
|
env: {
|
|
29701
29776
|
...process.env,
|
|
@@ -29708,7 +29783,7 @@ function runForeground(projectRoot, port) {
|
|
|
29708
29783
|
});
|
|
29709
29784
|
}
|
|
29710
29785
|
function openBrowser(port) {
|
|
29711
|
-
const url = `http://
|
|
29786
|
+
const url = `http://localhost:${port}`;
|
|
29712
29787
|
const platform = process.platform;
|
|
29713
29788
|
if (platform === "darwin") {
|
|
29714
29789
|
execFile("open", [url], () => {});
|
|
@@ -30493,6 +30568,36 @@ function printUpdateResults(result) {
|
|
|
30493
30568
|
}
|
|
30494
30569
|
}
|
|
30495
30570
|
|
|
30571
|
+
// src/cli/web-commands.ts
|
|
30572
|
+
async function webStartCommand(options) {
|
|
30573
|
+
await serveCommand(options);
|
|
30574
|
+
}
|
|
30575
|
+
async function webStopCommand() {
|
|
30576
|
+
await serveStopCommand();
|
|
30577
|
+
}
|
|
30578
|
+
async function webStatusCommand() {
|
|
30579
|
+
const running = await isServeRunning();
|
|
30580
|
+
if (running) {
|
|
30581
|
+
const port = process.env.OMCUSTOM_PORT ?? String(DEFAULT_PORT);
|
|
30582
|
+
console.log(i18n.t("cli.web.status.running", { port }));
|
|
30583
|
+
} else {
|
|
30584
|
+
console.log(i18n.t("cli.web.status.notRunning"));
|
|
30585
|
+
console.log(i18n.t("cli.web.status.startHint"));
|
|
30586
|
+
}
|
|
30587
|
+
}
|
|
30588
|
+
async function webOpenCommand(options) {
|
|
30589
|
+
const port = options.port !== undefined ? Number(options.port) : DEFAULT_PORT;
|
|
30590
|
+
if (!Number.isFinite(port) || port < 1 || port > 65535) {
|
|
30591
|
+
console.error(`Invalid port: ${options.port}`);
|
|
30592
|
+
process.exit(1);
|
|
30593
|
+
}
|
|
30594
|
+
const running = await isServeRunning();
|
|
30595
|
+
if (!running) {
|
|
30596
|
+
console.warn(i18n.t("cli.web.open.notRunningWarn"));
|
|
30597
|
+
}
|
|
30598
|
+
openBrowser(port);
|
|
30599
|
+
}
|
|
30600
|
+
|
|
30496
30601
|
// src/cli/index.ts
|
|
30497
30602
|
var require2 = createRequire2(import.meta.url);
|
|
30498
30603
|
var packageJson = require2("../../package.json");
|
|
@@ -30518,10 +30623,28 @@ function createProgram() {
|
|
|
30518
30623
|
const result = await securityCommand(options);
|
|
30519
30624
|
process.exitCode = result.success ? 0 : 1;
|
|
30520
30625
|
});
|
|
30521
|
-
program2.command("
|
|
30626
|
+
const web = program2.command("web").description(i18n.t("cli.web.description"));
|
|
30627
|
+
web.command("start").description(i18n.t("cli.web.start.description")).option("-p, --port <port>", i18n.t("cli.web.start.portOption"), "4321").option("--open", i18n.t("cli.web.start.openOption")).option("--foreground", i18n.t("cli.web.start.foregroundOption")).action(async (options) => {
|
|
30628
|
+
await webStartCommand(options);
|
|
30629
|
+
});
|
|
30630
|
+
web.command("stop").description(i18n.t("cli.web.stop.description")).action(async () => {
|
|
30631
|
+
await webStopCommand();
|
|
30632
|
+
});
|
|
30633
|
+
web.command("status").description(i18n.t("cli.web.status.description")).action(async () => {
|
|
30634
|
+
await webStatusCommand();
|
|
30635
|
+
});
|
|
30636
|
+
web.command("open").description(i18n.t("cli.web.open.description")).option("-p, --port <port>", i18n.t("cli.web.open.portOption"), "4321").action(async (options) => {
|
|
30637
|
+
await webOpenCommand(options);
|
|
30638
|
+
});
|
|
30639
|
+
web.action(async () => {
|
|
30640
|
+
await webStatusCommand();
|
|
30641
|
+
});
|
|
30642
|
+
program2.command("serve").description("(Deprecated) Start the Web UI server — use `omcustom web start` instead").option("-p, --port <port>", i18n.t("cli.web.start.portOption"), "4321").option("--open", i18n.t("cli.web.start.openOption")).option("--foreground", i18n.t("cli.web.start.foregroundOption")).action(async (options) => {
|
|
30643
|
+
console.warn(i18n.t("cli.web.deprecated.serve"));
|
|
30522
30644
|
await serveCommand(options);
|
|
30523
30645
|
});
|
|
30524
|
-
program2.command("serve-stop").description("Stop the
|
|
30646
|
+
program2.command("serve-stop").description("(Deprecated) Stop the Web UI server — use `omcustom web stop` instead").action(async () => {
|
|
30647
|
+
console.warn(i18n.t("cli.web.deprecated.serveStop"));
|
|
30525
30648
|
await serveStopCommand();
|
|
30526
30649
|
});
|
|
30527
30650
|
program2.command("projects").description("List all projects on this machine where oh-my-customcode is installed").option("-f, --format <format>", "Output format: table, json, or simple", "table").option("--path <dir>", "Additional search directory (can be specified multiple times)", (val, prev) => [...prev, val], []).action(async (options) => {
|
|
@@ -30530,7 +30653,14 @@ function createProgram() {
|
|
|
30530
30653
|
program2.hook("preAction", async (thisCommand, actionCommand) => {
|
|
30531
30654
|
const opts = thisCommand.optsWithGlobals();
|
|
30532
30655
|
const skipCheck = opts.skipVersionCheck || false;
|
|
30533
|
-
|
|
30656
|
+
const cmdName = actionCommand.name();
|
|
30657
|
+
const parentName = actionCommand.parent?.name();
|
|
30658
|
+
const isServeCmd = cmdName === "serve" || cmdName === "serve-stop";
|
|
30659
|
+
const isWebCmd = cmdName === "web" || parentName === "web";
|
|
30660
|
+
if (isServeCmd || isWebCmd) {
|
|
30661
|
+
return;
|
|
30662
|
+
}
|
|
30663
|
+
if (cmdName === "init") {
|
|
30534
30664
|
await maybeHandleSelfUpdateForInit({
|
|
30535
30665
|
currentVersion: packageJson.version,
|
|
30536
30666
|
skip: skipCheck
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "oh-my-customcode",
|
|
3
3
|
"workspaces": ["packages/*"],
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.47.0",
|
|
5
5
|
"description": "Batteries-included agent harness for Claude Code",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"bin": {
|
|
@@ -31,9 +31,9 @@
|
|
|
31
31
|
"test:integration": "bun test tests/integration",
|
|
32
32
|
"test:e2e": "bun test tests/e2e",
|
|
33
33
|
"test:coverage": "bun test --coverage",
|
|
34
|
-
"lint": "biome check
|
|
35
|
-
"lint:fix": "biome check --write
|
|
36
|
-
"format": "biome format --write
|
|
34
|
+
"lint": "biome check src/ tests/ scripts/",
|
|
35
|
+
"lint:fix": "biome check --write src/ tests/ scripts/",
|
|
36
|
+
"format": "biome format --write src/ tests/ scripts/",
|
|
37
37
|
"typecheck": "tsc --noEmit",
|
|
38
38
|
"docs:dev": "vitepress dev docs",
|
|
39
39
|
"docs:build": "vitepress build docs",
|
|
@@ -136,9 +136,17 @@
|
|
|
136
136
|
{
|
|
137
137
|
"type": "command",
|
|
138
138
|
"command": "bash .claude/hooks/scripts/task-outcome-recorder.sh"
|
|
139
|
+
},
|
|
140
|
+
{
|
|
141
|
+
"type": "command",
|
|
142
|
+
"command": "count_file=\"/tmp/.claude-loop-count-$PPID\"; if [ -f \"$count_file\" ]; then last_mod=$(stat -f%m \"$count_file\" 2>/dev/null || echo 0); now=$(date +%s); if [ $((now - last_mod)) -gt 60 ]; then echo 0 > \"$count_file\"; fi; fi; count=$(cat \"$count_file\" 2>/dev/null || echo 0); count=$((count + 1)); echo \"$count\" > \"$count_file\"; if [ \"$count\" -ge 4 ]; then echo '[AutoContinue] SAFETY: auto-continue limit (3) reached. Pausing.' >&2; fi; cat"
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
"type": "prompt",
|
|
146
|
+
"prompt": "A background subagent just completed. Check if there are pending workflow steps that depend on this result. If the previous subagent FAILED, do NOT auto-continue — report the failure and wait for user input. If the previous step succeeded and there are pending steps, proceed automatically. If no pending steps, report results and wait. Safety: The file /tmp/.claude-loop-count-$PPID tracks auto-continue count. After 3 consecutive auto-continues without user interaction, pause and ask the user before proceeding."
|
|
139
147
|
}
|
|
140
148
|
],
|
|
141
|
-
"description": "Record agent outcomes on subagent completion
|
|
149
|
+
"description": "Record agent outcomes + auto-continue workflow on subagent completion"
|
|
142
150
|
}
|
|
143
151
|
],
|
|
144
152
|
"PostCompact": [
|
|
@@ -205,8 +205,8 @@ When the `--spec` flag is present, refactoring is guided by the target's canonic
|
|
|
205
205
|
|
|
206
206
|
### Workflow
|
|
207
207
|
|
|
208
|
-
1. **Load spec**: Read `.claude/specs/<agent-name>.spec.md` (generated by `/omcustom
|
|
209
|
-
- If spec doesn't exist, run takeover first: `/omcustom
|
|
208
|
+
1. **Load spec**: Read `.claude/specs/<agent-name>.spec.md` (generated by `/omcustom-takeover`)
|
|
209
|
+
- If spec doesn't exist, run takeover first: `/omcustom-takeover <name>`
|
|
210
210
|
2. **Extract invariants**: Parse the spec's `## Invariants` section as pre-flight guard constraints
|
|
211
211
|
3. **Refactor**: Perform normal refactoring (per existing workflow)
|
|
212
212
|
4. **Verify invariants**: After refactoring, check each invariant still holds:
|
|
@@ -216,7 +216,7 @@ When the `--spec` flag is present, refactoring is guided by the target's canonic
|
|
|
216
216
|
├── ✓ Invariant 2: {description} — PASS
|
|
217
217
|
└── ✗ Invariant 3: {description} — FAIL (reason)
|
|
218
218
|
```
|
|
219
|
-
5. **Regenerate spec**: If refactoring changed the contract, run `/omcustom
|
|
219
|
+
5. **Regenerate spec**: If refactoring changed the contract, run `/omcustom-takeover <name>` to update
|
|
220
220
|
|
|
221
221
|
### When to Use
|
|
222
222
|
|
|
@@ -1,53 +1,82 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: omcustom-feedback
|
|
3
|
-
description: Submit feedback about oh-my-customcode
|
|
3
|
+
description: Submit feedback about oh-my-customcode (supports anonymous submission)
|
|
4
4
|
scope: harness
|
|
5
5
|
user-invocable: true
|
|
6
6
|
disable-model-invocation: true
|
|
7
|
-
argument-hint: "[description or leave empty for interactive]"
|
|
7
|
+
argument-hint: "[description or leave empty for interactive] [--anonymous]"
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# Feedback Submitter
|
|
11
11
|
|
|
12
|
-
Submit feedback about oh-my-customcode (bugs, features, improvements, questions) directly
|
|
12
|
+
Submit feedback about oh-my-customcode (bugs, features, improvements, questions) directly from the CLI session. Supports anonymous submission via Airflow DAG when gh CLI is unavailable or when anonymity is requested.
|
|
13
13
|
|
|
14
14
|
## Purpose
|
|
15
15
|
|
|
16
|
-
Lowers the barrier for submitting feedback by allowing users to create GitHub issues without leaving their terminal session. All feedback is filed to the `baekenough/oh-my-customcode` repository.
|
|
16
|
+
Lowers the barrier for submitting feedback by allowing users to create GitHub issues or submit anonymously — without leaving their terminal session. All feedback is filed to the `baekenough/oh-my-customcode` repository.
|
|
17
17
|
|
|
18
18
|
## Usage
|
|
19
19
|
|
|
20
20
|
```
|
|
21
21
|
# Inline feedback
|
|
22
|
-
/omcustom
|
|
22
|
+
/omcustom-feedback HUD display is missing during parallel agent spawn
|
|
23
|
+
|
|
24
|
+
# Anonymous submission
|
|
25
|
+
/omcustom:feedback --anonymous Something feels off with the routing
|
|
23
26
|
|
|
24
27
|
# Interactive (no arguments)
|
|
25
|
-
/omcustom
|
|
28
|
+
/omcustom-feedback
|
|
26
29
|
```
|
|
27
30
|
|
|
28
31
|
## Workflow
|
|
29
32
|
|
|
30
33
|
### Phase 1: Input Parsing
|
|
31
34
|
|
|
32
|
-
|
|
35
|
+
Check for `--anonymous` flag in the arguments:
|
|
36
|
+
- If `--anonymous` is present, set `ANONYMOUS=true` and strip the flag from the content
|
|
37
|
+
- Otherwise, set `ANONYMOUS=false`
|
|
38
|
+
|
|
39
|
+
If remaining arguments are provided:
|
|
33
40
|
1. Analyze the content to auto-detect category (`bug`, `feature`, `improvement`, `question`)
|
|
34
41
|
2. Use the content as the issue title (truncate to 80 chars if needed)
|
|
35
42
|
3. Use the full content as the description body
|
|
36
43
|
|
|
37
|
-
If no arguments:
|
|
44
|
+
If no arguments (or only `--anonymous`):
|
|
38
45
|
1. Ask the user for category using AskUserQuestion: `[bug / feature / improvement / question]`
|
|
39
46
|
2. Ask for title and optional detailed description (combine into a single prompt when possible)
|
|
40
47
|
|
|
41
|
-
### Phase 2:
|
|
48
|
+
### Phase 2: Route Decision
|
|
42
49
|
|
|
43
|
-
|
|
44
|
-
# Verify gh CLI is installed
|
|
45
|
-
command -v gh >/dev/null 2>&1 || { echo "Error: gh CLI not installed. Install from https://cli.github.com/"; exit 1; }
|
|
50
|
+
Check environment and user intent:
|
|
46
51
|
|
|
47
|
-
|
|
48
|
-
|
|
52
|
+
```bash
|
|
53
|
+
# Check gh CLI availability
|
|
54
|
+
command -v gh >/dev/null 2>&1 && GH_AVAILABLE=true || GH_AVAILABLE=false
|
|
55
|
+
|
|
56
|
+
# Check gh authentication (only if gh is available)
|
|
57
|
+
if [ "$GH_AVAILABLE" = "true" ]; then
|
|
58
|
+
gh auth status >/dev/null 2>&1 && GH_AUTHED=true || GH_AUTHED=false
|
|
59
|
+
else
|
|
60
|
+
GH_AUTHED=false
|
|
61
|
+
fi
|
|
62
|
+
|
|
63
|
+
# Check curl availability
|
|
64
|
+
command -v curl >/dev/null 2>&1 && CURL_AVAILABLE=true || CURL_AVAILABLE=false
|
|
49
65
|
```
|
|
50
66
|
|
|
67
|
+
**Route A**: `gh` available + authenticated + NOT anonymous
|
|
68
|
+
- Use GitHub Issue creation (see Phase 4A)
|
|
69
|
+
|
|
70
|
+
**Route B**: anonymous OR not authenticated (gh available)
|
|
71
|
+
- Use `curl` to Airflow REST API (see Phase 4C)
|
|
72
|
+
- Phase 4B (workflow_dispatch) reserved for future use
|
|
73
|
+
|
|
74
|
+
**Route C**: `gh` NOT available (or Route B curl fallback)
|
|
75
|
+
- Use `curl` to Airflow REST API (see Phase 4C)
|
|
76
|
+
|
|
77
|
+
**Fallback**: Neither `gh` nor `curl` available
|
|
78
|
+
- Save feedback locally and inform the user (see Phase 4D)
|
|
79
|
+
|
|
51
80
|
### Phase 3: Environment Collection
|
|
52
81
|
|
|
53
82
|
Collect environment info via Bash:
|
|
@@ -64,9 +93,16 @@ OS_INFO=$(uname -s 2>/dev/null || echo "unknown")
|
|
|
64
93
|
|
|
65
94
|
# Project name
|
|
66
95
|
PROJECT_NAME=$(basename "$(pwd)")
|
|
96
|
+
|
|
97
|
+
# Build project context string
|
|
98
|
+
PROJECT_CONTEXT="omcustom v${OMCUSTOM_VERSION}, Claude Code ${CLAUDE_VERSION}, ${OS_INFO}"
|
|
67
99
|
```
|
|
68
100
|
|
|
69
|
-
|
|
101
|
+
For anonymous submissions, do NOT include the project name. Offer to include project context as opt-in:
|
|
102
|
+
- Ask: "Include environment info (version, OS) in the anonymous report? [Y/n]"
|
|
103
|
+
- If declined, set `PROJECT_CONTEXT=""`
|
|
104
|
+
|
|
105
|
+
### Phase 4A: GitHub Issue Creation (Route A — gh + authenticated + not anonymous)
|
|
70
106
|
|
|
71
107
|
1. Show the user a preview of the issue to be created:
|
|
72
108
|
```
|
|
@@ -80,7 +116,7 @@ PROJECT_NAME=$(basename "$(pwd)")
|
|
|
80
116
|
|
|
81
117
|
3. Ensure labels exist (defensive):
|
|
82
118
|
```bash
|
|
83
|
-
gh label create feedback --description "User feedback via /omcustom
|
|
119
|
+
gh label create feedback --description "User feedback via /omcustom-feedback" --color 0E8A16 --repo baekenough/oh-my-customcode 2>/dev/null || true
|
|
84
120
|
```
|
|
85
121
|
|
|
86
122
|
4. Create the issue using `--body-file` for safe markdown handling:
|
|
@@ -102,7 +138,7 @@ PROJECT_NAME=$(basename "$(pwd)")
|
|
|
102
138
|
- Project: {project_name}
|
|
103
139
|
|
|
104
140
|
---
|
|
105
|
-
*Submitted via `/omcustom
|
|
141
|
+
*Submitted via `/omcustom-feedback`*
|
|
106
142
|
FEEDBACK_EOF
|
|
107
143
|
|
|
108
144
|
# Create issue
|
|
@@ -120,18 +156,91 @@ PROJECT_NAME=$(basename "$(pwd)")
|
|
|
120
156
|
|
|
121
157
|
6. Return the issue URL to the user
|
|
122
158
|
|
|
159
|
+
### Phase 4B: Anonymous via GitHub Actions (Route B — FUTURE)
|
|
160
|
+
|
|
161
|
+
> **Note**: This route is reserved for future implementation. The `feedback-submission.yml` workflow does not yet exist. All anonymous/unauthenticated submissions currently fall through to Route C (Airflow REST API).
|
|
162
|
+
|
|
163
|
+
```bash
|
|
164
|
+
gh workflow run feedback-submission.yml \
|
|
165
|
+
--repo baekenough/oh-my-customcode \
|
|
166
|
+
-f title="$TITLE" \
|
|
167
|
+
-f body="$BODY" \
|
|
168
|
+
-f feedback_type="$TYPE" \
|
|
169
|
+
-f anonymous=true \
|
|
170
|
+
-f project_context="$PROJECT_CONTEXT"
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
On success, inform the user:
|
|
174
|
+
```
|
|
175
|
+
[Done] Anonymous feedback submitted via GitHub Actions workflow.
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
If `gh workflow run` fails (e.g., permissions), fall through to Route C.
|
|
179
|
+
|
|
180
|
+
### Phase 4C: Anonymous via Airflow REST API (Route C — no gh)
|
|
181
|
+
|
|
182
|
+
```bash
|
|
183
|
+
# Build JSON payload safely with jq
|
|
184
|
+
PAYLOAD=$(jq -n --arg title "$TITLE" --arg body "$BODY" --arg type "$TYPE" --arg ctx "$PROJECT_CONTEXT" \
|
|
185
|
+
'{"conf":{"title":$title,"body":$body,"feedback_type":$type,"anonymous":true,"submitter":"","project_context":$ctx}}')
|
|
186
|
+
|
|
187
|
+
curl -X POST "https://airflow.baekenough.com/api/v2/dags/omc_feedback_collector/dagRuns" \
|
|
188
|
+
-H "Content-Type: application/json" \
|
|
189
|
+
-d "$PAYLOAD" \
|
|
190
|
+
--silent --show-error \
|
|
191
|
+
--max-time 15
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
On HTTP 200/201, inform the user:
|
|
195
|
+
```
|
|
196
|
+
[Done] Anonymous feedback submitted via Airflow.
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
On failure (non-2xx or network error), fall through to Fallback.
|
|
200
|
+
|
|
201
|
+
### Phase 4D: Local Fallback (no gh, no curl, or all routes failed)
|
|
202
|
+
|
|
203
|
+
```bash
|
|
204
|
+
mkdir -p ~/.omcustom/feedback
|
|
205
|
+
TIMESTAMP=$(date +%Y%m%dT%H%M%S)
|
|
206
|
+
FEEDBACK_FILE=~/.omcustom/feedback/${TIMESTAMP}.json
|
|
207
|
+
|
|
208
|
+
cat > "$FEEDBACK_FILE" << EOF
|
|
209
|
+
{
|
|
210
|
+
"title": "$TITLE",
|
|
211
|
+
"body": "$BODY",
|
|
212
|
+
"feedback_type": "$TYPE",
|
|
213
|
+
"anonymous": $ANONYMOUS,
|
|
214
|
+
"project_context": "$PROJECT_CONTEXT",
|
|
215
|
+
"saved_at": "$TIMESTAMP"
|
|
216
|
+
}
|
|
217
|
+
EOF
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
Inform the user:
|
|
221
|
+
```
|
|
222
|
+
[Saved] Feedback saved locally to ~/.omcustom/feedback/{timestamp}.json
|
|
223
|
+
Submit manually when connectivity is available:
|
|
224
|
+
- GitHub Issues: https://github.com/baekenough/oh-my-customcode/issues/new
|
|
225
|
+
- Or run /omcustom:feedback again when gh or curl is available
|
|
226
|
+
```
|
|
227
|
+
|
|
123
228
|
### Category-to-Label Mapping
|
|
124
229
|
|
|
125
|
-
| Category | GitHub Label |
|
|
126
|
-
|
|
127
|
-
| bug | bug |
|
|
128
|
-
| feature | enhancement |
|
|
129
|
-
| improvement | enhancement |
|
|
130
|
-
| question | question |
|
|
230
|
+
| Category | GitHub Label | Airflow feedback_type |
|
|
231
|
+
|----------|--------------|-----------------------|
|
|
232
|
+
| bug | bug | bug |
|
|
233
|
+
| feature | enhancement | feature |
|
|
234
|
+
| improvement | enhancement | improvement |
|
|
235
|
+
| question | question | question |
|
|
236
|
+
| (auto-detect fails) | (none) | general |
|
|
131
237
|
|
|
132
238
|
## Notes
|
|
133
239
|
|
|
134
|
-
-
|
|
135
|
-
-
|
|
136
|
-
-
|
|
240
|
+
- Route A creates a visible GitHub issue attributed to the user's gh account
|
|
241
|
+
- Routes B and C submit anonymously — submitter identity is not recorded
|
|
242
|
+
- Route B requires `gh` but NOT authentication to the repo (public workflow)
|
|
243
|
+
- Route C requires `curl` (available on macOS/Linux by default)
|
|
244
|
+
- Fallback ensures no feedback is silently lost even in offline environments
|
|
137
245
|
- `disable-model-invocation: true` ensures this skill only runs when explicitly invoked by the user
|
|
246
|
+
- Target repo is hardcoded to `baekenough/oh-my-customcode` — feedback is always about omcustom itself
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: omcustom-loop
|
|
3
|
+
description: Prevent session idle during background agent work via SubagentStop prompt hook auto-continuation
|
|
4
|
+
scope: core
|
|
5
|
+
version: 1.0.0
|
|
6
|
+
user-invocable: true
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# /omcustom:loop — Session Auto-Continuation
|
|
10
|
+
|
|
11
|
+
## Overview
|
|
12
|
+
|
|
13
|
+
Prevents session idle when background subagents complete by using a `SubagentStop` prompt hook that nudges the orchestrator to check for pending workflow steps.
|
|
14
|
+
|
|
15
|
+
## How It Works
|
|
16
|
+
|
|
17
|
+
1. When a background subagent completes, Claude Code fires the `SubagentStop` event
|
|
18
|
+
2. The prompt hook injects a message asking the orchestrator to check for pending steps
|
|
19
|
+
3. If pending steps exist, the orchestrator proceeds automatically
|
|
20
|
+
4. If no pending steps, it reports results and waits for user input
|
|
21
|
+
|
|
22
|
+
## Safety Limits
|
|
23
|
+
|
|
24
|
+
- **3 consecutive auto-continues max**: After 3 automatic progressions without user interaction, the system pauses and asks the user before proceeding
|
|
25
|
+
- **stuck-detector integration**: If the same action repeats 3+ times, stuck-detector intervenes
|
|
26
|
+
- **cost-cap-advisor**: Cost monitoring continues during auto-continuation
|
|
27
|
+
|
|
28
|
+
## Configuration
|
|
29
|
+
|
|
30
|
+
The hook is configured in `.claude/hooks/hooks.json` under `SubagentStop`. It works alongside the existing `task-outcome-recorder.sh` command hook.
|
|
31
|
+
|
|
32
|
+
## Limitations
|
|
33
|
+
|
|
34
|
+
- **Platform constraint**: Claude Code's turn-based model means the prompt hook only fires when a subagent completes — it cannot wake the model from true idle state
|
|
35
|
+
- **Foreground agents preferred**: For guaranteed continuation, use foreground parallel agents (R009) instead of background agents
|
|
36
|
+
- **PoC status**: This is an experimental feature. If the prompt hook doesn't reliably trigger in all scenarios, fall back to foreground agent patterns
|
|
37
|
+
|
|
38
|
+
## Usage
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
/omcustom:loop # Show current auto-continuation status
|
|
42
|
+
/omcustom:loop status # Same as above
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
The feature is active by default via hooks.json. No explicit activation needed.
|
|
@@ -17,8 +17,8 @@ Replaces the CI-based `release-notes.yml` workflow that previously used Claude A
|
|
|
17
17
|
## Usage
|
|
18
18
|
|
|
19
19
|
```
|
|
20
|
-
/omcustom
|
|
21
|
-
/omcustom
|
|
20
|
+
/omcustom-release-notes 0.36.0
|
|
21
|
+
/omcustom-release-notes 0.36.0 --previous-tag v0.35.3
|
|
22
22
|
```
|
|
23
23
|
|
|
24
24
|
## Workflow
|
|
@@ -105,7 +105,7 @@ This skill is designed to be used during the release process:
|
|
|
105
105
|
|
|
106
106
|
```
|
|
107
107
|
/omcustom:npm-version patch|minor|major -> version bump
|
|
108
|
-
/omcustom
|
|
108
|
+
/omcustom-release-notes {version} -> generate notes
|
|
109
109
|
mgr-gitnerd: gh release create -> create release with notes
|
|
110
110
|
```
|
|
111
111
|
|
|
@@ -17,8 +17,8 @@ When an agent or skill has evolved organically without a formal spec, `takeover`
|
|
|
17
17
|
## Usage
|
|
18
18
|
|
|
19
19
|
```
|
|
20
|
-
/omcustom
|
|
21
|
-
/omcustom
|
|
20
|
+
/omcustom-takeover <agent-name>
|
|
21
|
+
/omcustom-takeover <skill-name>
|
|
22
22
|
```
|
|
23
23
|
|
|
24
24
|
## Workflow
|
|
@@ -110,6 +110,6 @@ generated: <ISO-8601 timestamp>
|
|
|
110
110
|
## Notes
|
|
111
111
|
|
|
112
112
|
- Specs are git-untracked (under `.claude/`)
|
|
113
|
-
- Regenerate anytime with `/omcustom
|
|
113
|
+
- Regenerate anytime with `/omcustom-takeover <name>`
|
|
114
114
|
- Used by `/dev-refactor --spec` for invariant-preserving refactoring
|
|
115
115
|
- Advisory output — human review recommended before using as contract
|
|
@@ -59,6 +59,11 @@ if [[ -z "$json" ]]; then
|
|
|
59
59
|
exit 0
|
|
60
60
|
fi
|
|
61
61
|
|
|
62
|
+
# Debug logging for CTX investigation
|
|
63
|
+
if [[ -n "${STATUSLINE_DEBUG}" ]]; then
|
|
64
|
+
printf '%s\n' "$json" >> "/tmp/.claude-statusline-debug-${PPID}.jsonl"
|
|
65
|
+
fi
|
|
66
|
+
|
|
62
67
|
# ---------------------------------------------------------------------------
|
|
63
68
|
# 4. Single jq call — extract all fields as TSV
|
|
64
69
|
# Fields: model_name, project_dir, ctx_pct, ctx_size, cost_usd, rl_5h_pct
|
|
@@ -67,7 +72,7 @@ IFS=$'\t' read -r model_name project_dir ctx_pct ctx_size cost_usd rl_5h_pct <<<
|
|
|
67
72
|
printf '%s' "$json" | jq -r '[
|
|
68
73
|
(.model.display_name // "unknown"),
|
|
69
74
|
(.workspace.current_dir // ""),
|
|
70
|
-
(.context_window.used_percentage
|
|
75
|
+
(if .context_window.used != null and .context_window.total != null and .context_window.total > 0 then (.context_window.used / .context_window.total * 100) elif .context_window.used_percentage != null then .context_window.used_percentage else 0 end),
|
|
71
76
|
(.context_window.context_window_size // 0),
|
|
72
77
|
(.cost.total_cost_usd // 0),
|
|
73
78
|
(.rate_limits.five_hour.used_percentage // -1)
|
|
@@ -78,7 +83,8 @@ IFS=$'\t' read -r model_name project_dir ctx_pct ctx_size cost_usd rl_5h_pct <<<
|
|
|
78
83
|
# 4b. Cost & context data bridge — write to temp file for hooks
|
|
79
84
|
# ---------------------------------------------------------------------------
|
|
80
85
|
COST_BRIDGE_FILE="/tmp/.claude-cost-${PPID}"
|
|
81
|
-
|
|
86
|
+
_tmp="${COST_BRIDGE_FILE}.tmp.$$"
|
|
87
|
+
printf '%s\t%s\t%s\t%s\n' "$cost_usd" "$ctx_pct" "$(date +%s)" "$rl_5h_pct" > "$_tmp" 2>/dev/null && mv -f "$_tmp" "$COST_BRIDGE_FILE" 2>/dev/null || true
|
|
82
88
|
|
|
83
89
|
# ---------------------------------------------------------------------------
|
|
84
90
|
# 5. Model display name + color (bash 3.2 compatible case pattern matching)
|
package/templates/CLAUDE.md
CHANGED
|
@@ -101,7 +101,7 @@ oh-my-customcode로 구동됩니다.
|
|
|
101
101
|
| `/omcustom:update-external` | 외부 소스에서 에이전트 업데이트 |
|
|
102
102
|
| `/omcustom:audit-agents` | 에이전트 의존성 감사 |
|
|
103
103
|
| `/omcustom:fix-refs` | 깨진 참조 수정 |
|
|
104
|
-
| `/omcustom
|
|
104
|
+
| `/omcustom-takeover` | 기존 에이전트/스킬에서 canonical spec 추출 |
|
|
105
105
|
| `/adversarial-review` | 공격자 관점 보안 코드 리뷰 |
|
|
106
106
|
| `/ambiguity-gate` | 요청 모호성 분석 및 명확화 질문 (ouroboros 패턴) |
|
|
107
107
|
| `/dev-review` | 코드 베스트 프랙티스 리뷰 |
|
|
@@ -112,8 +112,8 @@ oh-my-customcode로 구동됩니다.
|
|
|
112
112
|
| `/omcustom:npm-publish` | npm 레지스트리에 패키지 배포 |
|
|
113
113
|
| `/omcustom:npm-version` | 시맨틱 버전 관리 |
|
|
114
114
|
| `/omcustom:npm-audit` | 의존성 감사 |
|
|
115
|
-
| `/omcustom
|
|
116
|
-
| `/omcustom
|
|
115
|
+
| `/omcustom-release-notes` | 릴리즈 노트 생성 (git 히스토리 기반) |
|
|
116
|
+
| `/omcustom-feedback` | 사용자 피드백을 GitHub Issue로 등록 |
|
|
117
117
|
| `/codex-exec` | Codex CLI 프롬프트 실행 |
|
|
118
118
|
| `/optimize-analyze` | 번들 및 성능 분석 |
|
|
119
119
|
| `/optimize-bundle` | 번들 크기 최적화 |
|
|
@@ -122,6 +122,7 @@ oh-my-customcode로 구동됩니다.
|
|
|
122
122
|
| `/deep-plan` | 연구 검증 기반 계획 수립 (research → plan → verify) |
|
|
123
123
|
| `/omcustom:sauron-watch` | 전체 R017 검증 |
|
|
124
124
|
| `/structured-dev-cycle` | 6단계 구조적 개발 사이클 (Plan → Verify → Implement → Verify → Compound → Done) |
|
|
125
|
+
| `/omcustom:loop` | 백그라운드 에이전트 자동 계속 실행 |
|
|
125
126
|
| `/omcustom:lists` | 모든 사용 가능한 커맨드 표시 |
|
|
126
127
|
| `/omcustom:status` | 시스템 상태 표시 |
|
|
127
128
|
| `/omcustom:help` | 도움말 표시 |
|
|
@@ -132,12 +133,12 @@ oh-my-customcode로 구동됩니다.
|
|
|
132
133
|
project/
|
|
133
134
|
+-- CLAUDE.md # 진입점
|
|
134
135
|
+-- .claude/
|
|
135
|
-
| +-- agents/ # 서브에이전트 정의 (
|
|
136
|
-
| +-- skills/ # 스킬 (
|
|
136
|
+
| +-- agents/ # 서브에이전트 정의 (45 파일)
|
|
137
|
+
| +-- skills/ # 스킬 (83 디렉토리)
|
|
137
138
|
| +-- rules/ # 전역 규칙 (R000-R021)
|
|
138
139
|
| +-- hooks/ # 훅 스크립트 (보안, 검증, HUD)
|
|
139
140
|
| +-- contexts/ # 컨텍스트 파일 (ecomode)
|
|
140
|
-
+-- guides/ # 레퍼런스 문서 (
|
|
141
|
+
+-- guides/ # 레퍼런스 문서 (28 토픽)
|
|
141
142
|
```
|
|
142
143
|
|
|
143
144
|
## 오케스트레이션
|
|
@@ -185,14 +186,14 @@ oh-my-customcode는 소프트웨어 컴파일과 동일한 구조를 따릅니
|
|
|
185
186
|
| SW Engineer/Frontend | 4 | fe-vercel-agent, fe-vuejs-agent, fe-svelte-agent, fe-flutter-agent |
|
|
186
187
|
| SW Engineer/Tooling | 3 | tool-npm-expert, tool-optimizer, tool-bun-expert |
|
|
187
188
|
| DE Engineer | 6 | de-airflow-expert, de-dbt-expert, de-spark-expert, de-kafka-expert, de-snowflake-expert, de-pipeline-expert |
|
|
188
|
-
| SW Engineer/Database |
|
|
189
|
+
| SW Engineer/Database | 4 | db-supabase-expert, db-postgres-expert, db-redis-expert, db-alembic-expert |
|
|
189
190
|
| Security | 1 | sec-codeql-expert |
|
|
190
191
|
| SW Architect | 2 | arch-documenter, arch-speckit-agent |
|
|
191
192
|
| Infra Engineer | 2 | infra-docker-expert, infra-aws-expert |
|
|
192
193
|
| QA Team | 3 | qa-planner, qa-writer, qa-engineer |
|
|
193
194
|
| Manager | 6 | mgr-creator, mgr-updater, mgr-supplier, mgr-gitnerd, mgr-sauron, mgr-claude-code-bible |
|
|
194
195
|
| System | 2 | sys-memory-keeper, sys-naggy |
|
|
195
|
-
| **총계** | **
|
|
196
|
+
| **총계** | **45** | |
|
|
196
197
|
|
|
197
198
|
## Agent Teams (MUST when enabled)
|
|
198
199
|
|
package/templates/CLAUDE.md.en
CHANGED
|
@@ -100,7 +100,7 @@ NO EXCEPTIONS. NO EXCUSES.
|
|
|
100
100
|
| `/omcustom:update-external` | Update agents from external sources |
|
|
101
101
|
| `/omcustom:audit-agents` | Audit agent dependencies |
|
|
102
102
|
| `/omcustom:fix-refs` | Fix broken references |
|
|
103
|
-
| `/omcustom
|
|
103
|
+
| `/omcustom-takeover` | Extract canonical spec from existing agent/skill |
|
|
104
104
|
| `/dev-review` | Review code for best practices |
|
|
105
105
|
| `/dev-refactor` | Refactor code |
|
|
106
106
|
| `/memory-save` | Save session context to claude-mem |
|
|
@@ -109,7 +109,7 @@ NO EXCEPTIONS. NO EXCUSES.
|
|
|
109
109
|
| `/omcustom:npm-publish` | Publish package to npm registry |
|
|
110
110
|
| `/omcustom:npm-version` | Manage semantic versions |
|
|
111
111
|
| `/omcustom:npm-audit` | Audit dependencies |
|
|
112
|
-
| `/omcustom
|
|
112
|
+
| `/omcustom-release-notes` | Generate release notes from git history |
|
|
113
113
|
| `/codex-exec` | Execute Codex CLI prompts |
|
|
114
114
|
| `/optimize-analyze` | Analyze bundle and performance |
|
|
115
115
|
| `/optimize-bundle` | Optimize bundle size |
|
package/templates/CLAUDE.md.ko
CHANGED
|
@@ -100,7 +100,7 @@ oh-my-customcode로 구동됩니다.
|
|
|
100
100
|
| `/omcustom:update-external` | 외부 소스에서 에이전트 업데이트 |
|
|
101
101
|
| `/omcustom:audit-agents` | 에이전트 의존성 감사 |
|
|
102
102
|
| `/omcustom:fix-refs` | 깨진 참조 수정 |
|
|
103
|
-
| `/omcustom
|
|
103
|
+
| `/omcustom-takeover` | 기존 에이전트/스킬에서 canonical spec 추출 |
|
|
104
104
|
| `/dev-review` | 코드 베스트 프랙티스 리뷰 |
|
|
105
105
|
| `/dev-refactor` | 코드 리팩토링 |
|
|
106
106
|
| `/memory-save` | 세션 컨텍스트를 claude-mem에 저장 |
|
|
@@ -109,7 +109,7 @@ oh-my-customcode로 구동됩니다.
|
|
|
109
109
|
| `/omcustom:npm-publish` | npm 레지스트리에 패키지 배포 |
|
|
110
110
|
| `/omcustom:npm-version` | 시맨틱 버전 관리 |
|
|
111
111
|
| `/omcustom:npm-audit` | 의존성 감사 |
|
|
112
|
-
| `/omcustom
|
|
112
|
+
| `/omcustom-release-notes` | 릴리즈 노트 생성 (git 히스토리 기반) |
|
|
113
113
|
| `/codex-exec` | Codex CLI 프롬프트 실행 |
|
|
114
114
|
| `/optimize-analyze` | 번들 및 성능 분석 |
|
|
115
115
|
| `/optimize-bundle` | 번들 크기 최적화 |
|
package/templates/manifest.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "0.
|
|
2
|
+
"version": "0.47.0",
|
|
3
3
|
"lastUpdated": "2026-03-16T00:00:00.000Z",
|
|
4
4
|
"components": [
|
|
5
5
|
{
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"name": "skills",
|
|
19
19
|
"path": ".claude/skills",
|
|
20
20
|
"description": "Reusable skill modules (includes slash commands)",
|
|
21
|
-
"files":
|
|
21
|
+
"files": 83
|
|
22
22
|
},
|
|
23
23
|
{
|
|
24
24
|
"name": "guides",
|