oh-my-customcodex 0.4.15 → 0.5.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 -7
- package/dist/cli/index.js +65 -20
- package/dist/index.js +40 -4
- package/package.json +1 -1
- package/templates/.claude/agents/mgr-gitnerd.md +4 -0
- package/templates/.claude/agents/mgr-sauron.md +5 -4
- package/templates/.claude/hooks/hooks.json +13 -0
- package/templates/.claude/hooks/scripts/context-budget-advisor.sh +40 -2
- package/templates/.claude/hooks/scripts/cost-cap-advisor.sh +8 -3
- package/templates/.claude/hooks/scripts/destructive-git-guard.sh +53 -0
- package/templates/.claude/hooks/scripts/omcustom-auto-update.sh +5 -5
- package/templates/.claude/hooks/scripts/session-env-check.sh +8 -6
- package/templates/.claude/hooks/scripts/stuck-detector.sh +2 -2
- package/templates/.claude/ontology/skills.yaml +3 -3
- package/templates/.claude/rules/MUST-agent-design.md +1 -0
- package/templates/.claude/rules/MUST-orchestrator-coordination.md +6 -0
- package/templates/.claude/rules/MUST-safety.md +15 -0
- package/templates/.claude/rules/SHOULD-hud-statusline.md +2 -0
- package/templates/.claude/skills/gitlab/SKILL.md +346 -0
- package/templates/.claude/skills/goal/SKILL.md +5 -3
- package/templates/.claude/skills/harness-synthesizer/SKILL.md +32 -0
- package/templates/.claude/skills/help/SKILL.md +2 -2
- package/templates/.claude/skills/lists/SKILL.md +2 -2
- package/templates/.claude/skills/npm-version/SKILL.md +6 -0
- package/templates/.claude/skills/omcodex-release-notes/SKILL.md +5 -4
- package/templates/.claude/skills/post-release-followup/SKILL.md +1 -1
- package/templates/.claude/skills/status/SKILL.md +1 -1
- package/templates/.claude/statusline.sh +24 -3
- package/templates/AGENTS.md.en +5 -3
- package/templates/AGENTS.md.ko +5 -3
- package/templates/CLAUDE.md +12 -3
- package/templates/CLAUDE.md.en +12 -3
- package/templates/CLAUDE.md.ko +12 -3
- package/templates/guides/claude-code/04-agent-skills.md +16 -0
- package/templates/guides/claude-code/06-mcp.md +6 -0
- package/templates/guides/claude-code/13-cli-flags.md +13 -1
- package/templates/guides/claude-code/15-version-compatibility.md +59 -0
- package/templates/guides/claude-code/index.yaml +5 -0
- package/templates/guides/git-safety/README.md +44 -0
- package/templates/guides/hook-data-flow/README.md +16 -16
- package/templates/guides/index.yaml +6 -0
- package/templates/guides/professor-triage/phases.md +324 -0
- package/templates/manifest.json +3 -3
- package/templates/workflows/auto-dev.yaml +13 -1
package/README.md
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
|
|
14
14
|
**[한국어 문서 (Korean)](./README_ko.md)**
|
|
15
15
|
|
|
16
|
-
49 agents.
|
|
16
|
+
49 agents. 119 skills. 22 rules. One command.
|
|
17
17
|
|
|
18
18
|
```bash
|
|
19
19
|
npm install -g oh-my-customcodex && cd your-project && omcustomcodex init
|
|
@@ -134,7 +134,7 @@ Each agent declares its tools, model, memory scope, and limitations in YAML fron
|
|
|
134
134
|
|
|
135
135
|
---
|
|
136
136
|
|
|
137
|
-
### Skills (
|
|
137
|
+
### Skills (119)
|
|
138
138
|
|
|
139
139
|
| Category | Count | Includes |
|
|
140
140
|
|----------|-------|----------|
|
|
@@ -147,7 +147,7 @@ Each agent declares its tools, model, memory scope, and limitations in YAML fron
|
|
|
147
147
|
| Package | 3 | npm-publish, npm-version, npm-audit |
|
|
148
148
|
| Optimization | 3 | optimize-analyze, optimize-bundle, optimize-report |
|
|
149
149
|
| Security | 3 | adversarial-review, cve-triage, jinja2-prompts |
|
|
150
|
-
| Other |
|
|
150
|
+
| Other | 13 | codex-exec, claude-native, gitlab, visual-ralph, visual-verdict, vercel-deploy, skills-sh-search, result-aggregation, writing-clearly-and-concisely, and more |
|
|
151
151
|
|
|
152
152
|
Skills use a 3-tier scope system: `core` (universal), `harness` (agent/skill maintenance), `package` (project-specific).
|
|
153
153
|
|
|
@@ -170,7 +170,7 @@ All commands are invoked inside the oh-my-customcodex GPT Codex + OMX session.
|
|
|
170
170
|
| `/ambiguity-gate` | Pre-routing ambiguity analysis |
|
|
171
171
|
| `/pre-generation-arch-check` | Check architecture risks before implementation |
|
|
172
172
|
| `/adversarial-review` | Attacker-mindset security code review |
|
|
173
|
-
| `/goal` | Keep a concrete objective in view through planning, execution, and verification |
|
|
173
|
+
| `/omcustomcodex:goal` | Keep a concrete objective in view through planning, execution, and verification |
|
|
174
174
|
| `/pipeline` | Execute YAML-defined pipelines |
|
|
175
175
|
| `/pipeline resume` | Resume a halted pipeline from last failure point |
|
|
176
176
|
|
|
@@ -228,7 +228,7 @@ Key rules: R010 (orchestrator never writes files), R009 (parallel execution mand
|
|
|
228
228
|
|
|
229
229
|
---
|
|
230
230
|
|
|
231
|
-
### Guides (
|
|
231
|
+
### Guides (48)
|
|
232
232
|
|
|
233
233
|
Reference documentation covering best practices, architecture decisions, and integration patterns. Located in `guides/` at project root, covering topics from agent design to CI/CD to observability.
|
|
234
234
|
|
|
@@ -287,8 +287,8 @@ your-project/
|
|
|
287
287
|
│ ├── contexts/ # 4 shared context files
|
|
288
288
|
│ └── ontology/ # Knowledge graph for RAG
|
|
289
289
|
├── .agents/
|
|
290
|
-
│ └── skills/ #
|
|
291
|
-
└── guides/ #
|
|
290
|
+
│ └── skills/ # 119 installed skill modules
|
|
291
|
+
└── guides/ # 48 reference documents
|
|
292
292
|
```
|
|
293
293
|
|
|
294
294
|
### Source Repository And Compatibility Surfaces
|
package/dist/cli/index.js
CHANGED
|
@@ -1019,7 +1019,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1019
1019
|
this._exitCallback = (err) => {
|
|
1020
1020
|
if (err.code !== "commander.executeSubCommandAsync") {
|
|
1021
1021
|
throw err;
|
|
1022
|
-
}
|
|
1022
|
+
}
|
|
1023
1023
|
};
|
|
1024
1024
|
}
|
|
1025
1025
|
return this;
|
|
@@ -3091,7 +3091,7 @@ var init_package = __esm(() => {
|
|
|
3091
3091
|
workspaces: [
|
|
3092
3092
|
"packages/*"
|
|
3093
3093
|
],
|
|
3094
|
-
version: "0.
|
|
3094
|
+
version: "0.5.0",
|
|
3095
3095
|
requiresCC: ">=2.1.121",
|
|
3096
3096
|
claudeCode: {
|
|
3097
3097
|
minimumVersion: "2.1.121",
|
|
@@ -10179,6 +10179,23 @@ function sortProjects(projects) {
|
|
|
10179
10179
|
return a.name.localeCompare(b.name);
|
|
10180
10180
|
});
|
|
10181
10181
|
}
|
|
10182
|
+
async function buildRegistryProjectInfo(projectPath, entry, options, home, currentVersion) {
|
|
10183
|
+
if (!matchesSearchPaths(projectPath, options.paths))
|
|
10184
|
+
return null;
|
|
10185
|
+
if (!isUnderHome(projectPath, home))
|
|
10186
|
+
return null;
|
|
10187
|
+
if (!await fileExists(projectPath))
|
|
10188
|
+
return null;
|
|
10189
|
+
return {
|
|
10190
|
+
name: basename5(projectPath),
|
|
10191
|
+
path: projectPath,
|
|
10192
|
+
version: entry.version || null,
|
|
10193
|
+
installedAt: entry.installedAt || null,
|
|
10194
|
+
updatedAt: entry.updatedAt || null,
|
|
10195
|
+
status: computeStatus(entry.version || null, currentVersion),
|
|
10196
|
+
detectionMethod: "registry"
|
|
10197
|
+
};
|
|
10198
|
+
}
|
|
10182
10199
|
async function findProjects(options = {}) {
|
|
10183
10200
|
const currentVersion = await getTemplateVersion();
|
|
10184
10201
|
const registry = await readRegistry();
|
|
@@ -10192,19 +10209,9 @@ async function findProjects(options = {}) {
|
|
|
10192
10209
|
const results = [];
|
|
10193
10210
|
const home = process.env.HOME ?? homedir3();
|
|
10194
10211
|
for (const [projectPath, entry] of Object.entries(registry.projects)) {
|
|
10195
|
-
|
|
10196
|
-
|
|
10197
|
-
|
|
10198
|
-
continue;
|
|
10199
|
-
results.push({
|
|
10200
|
-
name: basename5(projectPath),
|
|
10201
|
-
path: projectPath,
|
|
10202
|
-
version: entry.version || null,
|
|
10203
|
-
installedAt: entry.installedAt || null,
|
|
10204
|
-
updatedAt: entry.updatedAt || null,
|
|
10205
|
-
status: computeStatus(entry.version || null, currentVersion),
|
|
10206
|
-
detectionMethod: "registry"
|
|
10207
|
-
});
|
|
10212
|
+
const project = await buildRegistryProjectInfo(projectPath, entry, options, home, currentVersion);
|
|
10213
|
+
if (project)
|
|
10214
|
+
results.push(project);
|
|
10208
10215
|
}
|
|
10209
10216
|
return sortProjects(results);
|
|
10210
10217
|
}
|
|
@@ -19772,7 +19779,7 @@ var require_dbcs_codec = __commonJS((exports) => {
|
|
|
19772
19779
|
if (resCode !== undefined) {
|
|
19773
19780
|
dbcsCode = resCode;
|
|
19774
19781
|
nextChar = uCode;
|
|
19775
|
-
}
|
|
19782
|
+
}
|
|
19776
19783
|
}
|
|
19777
19784
|
seqObj = undefined;
|
|
19778
19785
|
} else if (uCode >= 0) {
|
|
@@ -19837,7 +19844,7 @@ var require_dbcs_codec = __commonJS((exports) => {
|
|
|
19837
19844
|
newBuf[j2++] = dbcsCode >> 8;
|
|
19838
19845
|
newBuf[j2++] = dbcsCode & 255;
|
|
19839
19846
|
}
|
|
19840
|
-
}
|
|
19847
|
+
}
|
|
19841
19848
|
this.seqObj = undefined;
|
|
19842
19849
|
}
|
|
19843
19850
|
if (this.leadSurrogate !== -1) {
|
|
@@ -31413,6 +31420,7 @@ async function runFullUpdatePostProcessing(options, result, config) {
|
|
|
31413
31420
|
const removed = await removeDeprecatedFiles(options.targetDir, options);
|
|
31414
31421
|
result.removedDeprecatedFiles = removed;
|
|
31415
31422
|
if (!options.dryRun) {
|
|
31423
|
+
await ensureStatusLineConfig(options.targetDir);
|
|
31416
31424
|
await updateEntryDoc(options.targetDir, config, options);
|
|
31417
31425
|
}
|
|
31418
31426
|
}
|
|
@@ -31431,6 +31439,34 @@ async function runFullUpdatePostProcessing(options, result, config) {
|
|
|
31431
31439
|
});
|
|
31432
31440
|
}
|
|
31433
31441
|
}
|
|
31442
|
+
async function ensureStatusLineConfig(targetDir) {
|
|
31443
|
+
const layout = getProviderLayout();
|
|
31444
|
+
const settingsPath = join17(targetDir, layout.rootDir, "settings.local.json");
|
|
31445
|
+
const statusLineConfig = {
|
|
31446
|
+
type: "command",
|
|
31447
|
+
command: `${layout.rootDir}/statusline.sh`,
|
|
31448
|
+
padding: 0,
|
|
31449
|
+
refreshInterval: 10
|
|
31450
|
+
};
|
|
31451
|
+
if (!await fileExists(settingsPath)) {
|
|
31452
|
+
await ensureDirectory(join17(settingsPath, ".."));
|
|
31453
|
+
await writeJsonFile(settingsPath, { statusLine: statusLineConfig });
|
|
31454
|
+
return;
|
|
31455
|
+
}
|
|
31456
|
+
const settings = await readJsonFile(settingsPath);
|
|
31457
|
+
const statusLine = settings.statusLine;
|
|
31458
|
+
if (!statusLine || typeof statusLine !== "object" || Array.isArray(statusLine)) {
|
|
31459
|
+
settings.statusLine = statusLineConfig;
|
|
31460
|
+
await writeJsonFile(settingsPath, settings);
|
|
31461
|
+
return;
|
|
31462
|
+
}
|
|
31463
|
+
const mergedStatusLine = statusLine;
|
|
31464
|
+
if (mergedStatusLine.refreshInterval === undefined) {
|
|
31465
|
+
mergedStatusLine.refreshInterval = statusLineConfig.refreshInterval;
|
|
31466
|
+
settings.statusLine = mergedStatusLine;
|
|
31467
|
+
await writeJsonFile(settingsPath, settings);
|
|
31468
|
+
}
|
|
31469
|
+
}
|
|
31434
31470
|
function compareSemver2(a, b) {
|
|
31435
31471
|
const pa = a.split(".").map(Number);
|
|
31436
31472
|
const pb = b.split(".").map(Number);
|
|
@@ -31502,6 +31538,15 @@ function checkAndInstallOmxAfterUpdate() {
|
|
|
31502
31538
|
}
|
|
31503
31539
|
}
|
|
31504
31540
|
}
|
|
31541
|
+
async function handleNoUpdateResult(options, result) {
|
|
31542
|
+
const isFullUpdate = !options.components || options.components.length === 0;
|
|
31543
|
+
if (isFullUpdate && !options.dryRun) {
|
|
31544
|
+
await ensureStatusLineConfig(options.targetDir);
|
|
31545
|
+
}
|
|
31546
|
+
info("update.no_updates");
|
|
31547
|
+
result.success = true;
|
|
31548
|
+
result.skippedComponents = options.components || getAllUpdateComponents();
|
|
31549
|
+
}
|
|
31505
31550
|
async function update(options) {
|
|
31506
31551
|
const result = createUpdateResult();
|
|
31507
31552
|
try {
|
|
@@ -31520,9 +31565,7 @@ async function update(options) {
|
|
|
31520
31565
|
const updateCheck = await checkForUpdates(options.targetDir);
|
|
31521
31566
|
result.newVersion = updateCheck.latestVersion;
|
|
31522
31567
|
if (!updateCheck.hasUpdates && !options.force) {
|
|
31523
|
-
|
|
31524
|
-
result.success = true;
|
|
31525
|
-
result.skippedComponents = options.components || getAllUpdateComponents();
|
|
31568
|
+
await handleNoUpdateResult(options, result);
|
|
31526
31569
|
return result;
|
|
31527
31570
|
}
|
|
31528
31571
|
await handleBackupIfRequested(options.targetDir, !!options.backup, result);
|
|
@@ -32022,8 +32065,10 @@ function reportProjectUpdateResult(project, result, currentVersion) {
|
|
|
32022
32065
|
}
|
|
32023
32066
|
async function updateAllProjects(options) {
|
|
32024
32067
|
const { findProjects: findProjects2 } = await Promise.resolve().then(() => (init_projects(), exports_projects));
|
|
32068
|
+
const { cleanRegistry: cleanRegistry2 } = await Promise.resolve().then(() => (init_registry(), exports_registry));
|
|
32025
32069
|
const currentVersion = package_default.version;
|
|
32026
32070
|
console.log(i18n.t("cli.update.allScanning"));
|
|
32071
|
+
await cleanRegistry2();
|
|
32027
32072
|
const projects = await findProjects2();
|
|
32028
32073
|
if (projects.length === 0) {
|
|
32029
32074
|
console.log(i18n.t("cli.update.allNoneFound"));
|
package/dist/index.js
CHANGED
|
@@ -2180,7 +2180,7 @@ var package_default = {
|
|
|
2180
2180
|
workspaces: [
|
|
2181
2181
|
"packages/*"
|
|
2182
2182
|
],
|
|
2183
|
-
version: "0.
|
|
2183
|
+
version: "0.5.0",
|
|
2184
2184
|
requiresCC: ">=2.1.121",
|
|
2185
2185
|
claudeCode: {
|
|
2186
2186
|
minimumVersion: "2.1.121",
|
|
@@ -5015,6 +5015,7 @@ async function runFullUpdatePostProcessing(options, result, config) {
|
|
|
5015
5015
|
const removed = await removeDeprecatedFiles(options.targetDir, options);
|
|
5016
5016
|
result.removedDeprecatedFiles = removed;
|
|
5017
5017
|
if (!options.dryRun) {
|
|
5018
|
+
await ensureStatusLineConfig(options.targetDir);
|
|
5018
5019
|
await updateEntryDoc(options.targetDir, config, options);
|
|
5019
5020
|
}
|
|
5020
5021
|
}
|
|
@@ -5033,6 +5034,34 @@ async function runFullUpdatePostProcessing(options, result, config) {
|
|
|
5033
5034
|
});
|
|
5034
5035
|
}
|
|
5035
5036
|
}
|
|
5037
|
+
async function ensureStatusLineConfig(targetDir) {
|
|
5038
|
+
const layout = getProviderLayout();
|
|
5039
|
+
const settingsPath = join8(targetDir, layout.rootDir, "settings.local.json");
|
|
5040
|
+
const statusLineConfig = {
|
|
5041
|
+
type: "command",
|
|
5042
|
+
command: `${layout.rootDir}/statusline.sh`,
|
|
5043
|
+
padding: 0,
|
|
5044
|
+
refreshInterval: 10
|
|
5045
|
+
};
|
|
5046
|
+
if (!await fileExists(settingsPath)) {
|
|
5047
|
+
await ensureDirectory(join8(settingsPath, ".."));
|
|
5048
|
+
await writeJsonFile(settingsPath, { statusLine: statusLineConfig });
|
|
5049
|
+
return;
|
|
5050
|
+
}
|
|
5051
|
+
const settings = await readJsonFile(settingsPath);
|
|
5052
|
+
const statusLine = settings.statusLine;
|
|
5053
|
+
if (!statusLine || typeof statusLine !== "object" || Array.isArray(statusLine)) {
|
|
5054
|
+
settings.statusLine = statusLineConfig;
|
|
5055
|
+
await writeJsonFile(settingsPath, settings);
|
|
5056
|
+
return;
|
|
5057
|
+
}
|
|
5058
|
+
const mergedStatusLine = statusLine;
|
|
5059
|
+
if (mergedStatusLine.refreshInterval === undefined) {
|
|
5060
|
+
mergedStatusLine.refreshInterval = statusLineConfig.refreshInterval;
|
|
5061
|
+
settings.statusLine = mergedStatusLine;
|
|
5062
|
+
await writeJsonFile(settingsPath, settings);
|
|
5063
|
+
}
|
|
5064
|
+
}
|
|
5036
5065
|
function compareSemver(a, b) {
|
|
5037
5066
|
const pa = a.split(".").map(Number);
|
|
5038
5067
|
const pb = b.split(".").map(Number);
|
|
@@ -5104,6 +5133,15 @@ function checkAndInstallOmxAfterUpdate() {
|
|
|
5104
5133
|
}
|
|
5105
5134
|
}
|
|
5106
5135
|
}
|
|
5136
|
+
async function handleNoUpdateResult(options, result) {
|
|
5137
|
+
const isFullUpdate = !options.components || options.components.length === 0;
|
|
5138
|
+
if (isFullUpdate && !options.dryRun) {
|
|
5139
|
+
await ensureStatusLineConfig(options.targetDir);
|
|
5140
|
+
}
|
|
5141
|
+
info("update.no_updates");
|
|
5142
|
+
result.success = true;
|
|
5143
|
+
result.skippedComponents = options.components || getAllUpdateComponents();
|
|
5144
|
+
}
|
|
5107
5145
|
async function update(options) {
|
|
5108
5146
|
const result = createUpdateResult();
|
|
5109
5147
|
try {
|
|
@@ -5122,9 +5160,7 @@ async function update(options) {
|
|
|
5122
5160
|
const updateCheck = await checkForUpdates(options.targetDir);
|
|
5123
5161
|
result.newVersion = updateCheck.latestVersion;
|
|
5124
5162
|
if (!updateCheck.hasUpdates && !options.force) {
|
|
5125
|
-
|
|
5126
|
-
result.success = true;
|
|
5127
|
-
result.skippedComponents = options.components || getAllUpdateComponents();
|
|
5163
|
+
await handleNoUpdateResult(options, result);
|
|
5128
5164
|
return result;
|
|
5129
5165
|
}
|
|
5130
5166
|
await handleBackupIfRequested(options.targetDir, !!options.backup, result);
|
package/package.json
CHANGED
|
@@ -46,8 +46,12 @@ Types: feat, fix, docs, style, refactor, test, chore
|
|
|
46
46
|
|
|
47
47
|
- NEVER force push to main/master
|
|
48
48
|
- NEVER reset --hard without confirmation
|
|
49
|
+
- NEVER run `git clean -fd`, broad `git restore`, or `git checkout -- .` without preserving diffs and confirming the exact scope
|
|
50
|
+
- NEVER delete branches with `git branch -D` until merge state and remote backup are checked
|
|
49
51
|
- NEVER skip pre-commit hooks without reason
|
|
50
52
|
- ALWAYS create new commits (avoid --amend unless requested)
|
|
53
|
+
- BEFORE release branch creation, check for a local `release` branch that blocks the `release/v*` namespace; rename or remove it only after proving it is merged/backed up
|
|
54
|
+
- AFTER unexpected destructive git output, inspect `git reflog`, `git status`, and `git diff` before any repair attempt
|
|
51
55
|
|
|
52
56
|
## Push Rules (R016)
|
|
53
57
|
|
|
@@ -29,10 +29,11 @@ You are an automated verification specialist that executes the mandatory R017 ve
|
|
|
29
29
|
5. Verify reference integrity (frontmatter, memory fields, skill refs)
|
|
30
30
|
6. Verify philosophy compliance (R006-R011)
|
|
31
31
|
7. Verify Claude-native compatibility
|
|
32
|
-
8.
|
|
33
|
-
9.
|
|
34
|
-
10.
|
|
35
|
-
11.
|
|
32
|
+
8. Verify working-tree preservation: no verification step may reset, clean, restore, or delete branch state without explicit approval and recovery evidence
|
|
33
|
+
9. Spec density analysis: detects agents with excessive inline implementation detail (R006 compliance)
|
|
34
|
+
10. Structural linting: routing coverage (unreachable agents), orphan skill detection, circular dependency check, context:fork cap verification, R006 fork-list/frontmatter cross-validation
|
|
35
|
+
11. Auto-fix simple issues (count mismatches, missing fields)
|
|
36
|
+
12. Generate verification report
|
|
36
37
|
|
|
37
38
|
## Commands
|
|
38
39
|
|
|
@@ -42,6 +42,16 @@
|
|
|
42
42
|
],
|
|
43
43
|
"description": "Pause before git push to review changes"
|
|
44
44
|
},
|
|
45
|
+
{
|
|
46
|
+
"matcher": "tool == \"Bash\" && tool_input.command matches \"git (reset --hard|clean -f|clean -d|restore|checkout --|branch -D|push --force|push -f)\"",
|
|
47
|
+
"hooks": [
|
|
48
|
+
{
|
|
49
|
+
"type": "command",
|
|
50
|
+
"command": "bash .codex/hooks/scripts/destructive-git-guard.sh"
|
|
51
|
+
}
|
|
52
|
+
],
|
|
53
|
+
"description": "Warn on destructive git commands and print recovery guidance without blocking"
|
|
54
|
+
},
|
|
45
55
|
{
|
|
46
56
|
"matcher": "tool == \"Write\" && tool_input.file_path matches \"\\\\.(md|txt)$\" && !(tool_input.file_path matches \"README\\\\.md|CLAUDE\\\\.md|AGENT\\\\.md|SKILL\\\\.md\")",
|
|
47
57
|
"hooks": [
|
|
@@ -438,6 +448,7 @@
|
|
|
438
448
|
"command": "bash .codex/hooks/scripts/context-budget-advisor.sh"
|
|
439
449
|
}
|
|
440
450
|
],
|
|
451
|
+
"continueOnBlock": true,
|
|
441
452
|
"description": "Context budget advisor — track tool usage patterns and advise ecomode activation"
|
|
442
453
|
},
|
|
443
454
|
{
|
|
@@ -448,6 +459,7 @@
|
|
|
448
459
|
"command": "bash .codex/hooks/scripts/stuck-detector.sh"
|
|
449
460
|
}
|
|
450
461
|
],
|
|
462
|
+
"continueOnBlock": true,
|
|
451
463
|
"description": "Detect repetitive failure loops and advise recovery strategies"
|
|
452
464
|
},
|
|
453
465
|
{
|
|
@@ -458,6 +470,7 @@
|
|
|
458
470
|
"command": "bash .codex/hooks/scripts/cost-cap-advisor.sh"
|
|
459
471
|
}
|
|
460
472
|
],
|
|
473
|
+
"continueOnBlock": true,
|
|
461
474
|
"description": "Advisory cost cap monitoring — warn when session cost approaches configurable limit"
|
|
462
475
|
},
|
|
463
476
|
{
|
|
@@ -8,13 +8,14 @@ command -v jq >/dev/null 2>&1 || exit 0
|
|
|
8
8
|
# Context Budget Advisor Hook
|
|
9
9
|
# Trigger: PostToolUse (Edit/Write/Agent/Task/Read/Glob/Grep/Bash)
|
|
10
10
|
# Purpose: Monitor context usage and advise ecomode activation based on task type
|
|
11
|
-
# Protocol: stdin JSON -> stdout pass-through
|
|
11
|
+
# Protocol: stdin JSON -> stdout pass-through; exit 2 only for continueOnBlock signals
|
|
12
12
|
|
|
13
13
|
input=$(cat)
|
|
14
14
|
|
|
15
15
|
# Read context info from status file if available
|
|
16
|
-
|
|
16
|
+
COST_FILE="/tmp/.codex-cost-${PPID}"
|
|
17
17
|
BUDGET_FILE="/tmp/.codex-context-budget-${PPID}"
|
|
18
|
+
SIGNAL_FILE="/tmp/.codex-context-budget-signal-${PPID}"
|
|
18
19
|
|
|
19
20
|
# Initialize budget tracking file
|
|
20
21
|
if [ ! -f "$BUDGET_FILE" ]; then
|
|
@@ -77,6 +78,43 @@ case "$task_type" in
|
|
|
77
78
|
*) THRESHOLD=80 ;;
|
|
78
79
|
esac
|
|
79
80
|
|
|
81
|
+
# Use statusline bridge data when available. Exiting 2 with continueOnBlock=true
|
|
82
|
+
# turns a high-context advisory into model-visible feedback without halting.
|
|
83
|
+
ctx_pct="0"
|
|
84
|
+
ctx_timestamp="0"
|
|
85
|
+
if [ -f "$COST_FILE" ]; then
|
|
86
|
+
IFS=$'\t' read -r _cost_usd ctx_pct ctx_timestamp _rl_5h _rl_7d _rl_5h_resets _rl_7d_resets < "$COST_FILE" 2>/dev/null || true
|
|
87
|
+
fi
|
|
88
|
+
|
|
89
|
+
ctx_int="${ctx_pct%%.*}"
|
|
90
|
+
case "$ctx_int" in
|
|
91
|
+
''|*[!0-9]*) ctx_int=0 ;;
|
|
92
|
+
esac
|
|
93
|
+
case "$ctx_timestamp" in
|
|
94
|
+
''|*[!0-9]*) ctx_timestamp=0 ;;
|
|
95
|
+
esac
|
|
96
|
+
|
|
97
|
+
now=$(date +%s)
|
|
98
|
+
age=$((now - ${ctx_timestamp:-0}))
|
|
99
|
+
signal_key="${task_type}:${THRESHOLD}"
|
|
100
|
+
last_signal=""
|
|
101
|
+
if [ -f "$SIGNAL_FILE" ]; then
|
|
102
|
+
last_signal=$(cat "$SIGNAL_FILE" 2>/dev/null || echo "")
|
|
103
|
+
fi
|
|
104
|
+
|
|
105
|
+
if [ "$age" -le 60 ] && [ "$ctx_int" -ge "$THRESHOLD" ] && [ "$last_signal" != "$signal_key" ]; then
|
|
106
|
+
echo "[Context Budget] ${ctx_int}% context used meets ${task_type} threshold ${THRESHOLD}%" >&2
|
|
107
|
+
echo "[Context Budget] Switch to ecomode, compact, or narrow the remaining task before continuing." >&2
|
|
108
|
+
echo "$signal_key" > "$SIGNAL_FILE"
|
|
109
|
+
echo "$input"
|
|
110
|
+
HOOK_END=$(date +%s%N 2>/dev/null || echo 0)
|
|
111
|
+
if [ "$HOOK_START" != "0" ] && [ "$HOOK_END" != "0" ]; then
|
|
112
|
+
HOOK_MS=$(( (HOOK_END - HOOK_START) / 1000000 ))
|
|
113
|
+
echo "[Hook Perf] $(basename "$0"): ${HOOK_MS}ms" >> "/tmp/.codex-hook-perf-${PPID}.log"
|
|
114
|
+
fi
|
|
115
|
+
exit 2
|
|
116
|
+
fi
|
|
117
|
+
|
|
80
118
|
# Emit advisory at milestones (every 25 tool calls)
|
|
81
119
|
if [ "$tool_count" -gt 0 ] && [ $((tool_count % 25)) -eq 0 ]; then
|
|
82
120
|
echo "[Context Budget] Task: ${task_type} | Threshold: ${THRESHOLD}% | Tools used: ${tool_count}" >&2
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
# cost-cap-advisor.sh — Advisory hook for session cost monitoring
|
|
3
3
|
# Trigger: PostToolUse (Agent/Task)
|
|
4
4
|
# Purpose: Warn when session cost approaches configurable cap
|
|
5
|
-
# Protocol: stdin JSON -> stdout pass-through
|
|
5
|
+
# Protocol: stdin JSON -> stdout pass-through; exit 2 only for continueOnBlock wrap-up signals
|
|
6
6
|
|
|
7
7
|
input=$(cat)
|
|
8
8
|
|
|
@@ -30,10 +30,13 @@ if ! printf '%f' "$cost_usd" >/dev/null 2>&1; then
|
|
|
30
30
|
echo "$input"
|
|
31
31
|
exit 0
|
|
32
32
|
fi
|
|
33
|
+
if ! printf '%f' "$COST_CAP" >/dev/null 2>&1; then
|
|
34
|
+
echo "$input"
|
|
35
|
+
exit 0
|
|
36
|
+
fi
|
|
33
37
|
|
|
34
38
|
# Calculate percentage of cap used
|
|
35
|
-
|
|
36
|
-
cost_pct=$(echo "scale=0; $cost_usd * 100 / $COST_CAP" | bc 2>/dev/null || echo "0")
|
|
39
|
+
cost_pct=$(awk -v cost="$cost_usd" -v cap="$COST_CAP" 'BEGIN { if (cap <= 0) print 0; else printf "%d", (cost * 100 / cap) }' 2>/dev/null || echo "0")
|
|
37
40
|
|
|
38
41
|
# Staleness check — skip if data is older than 60 seconds
|
|
39
42
|
now=$(date +%s)
|
|
@@ -54,6 +57,8 @@ if [ "$cost_pct" -ge 100 ] && [ "$last_level" != "100" ]; then
|
|
|
54
57
|
echo "[Cost Cap] Session cost \$${cost_usd} has reached cap \$${COST_CAP} (${cost_pct}%)" >&2
|
|
55
58
|
echo "[Cost Cap] Consider wrapping up or increasing CLAUDE_COST_CAP" >&2
|
|
56
59
|
echo "100" > "$ADVISORY_FILE"
|
|
60
|
+
echo "$input"
|
|
61
|
+
exit 2
|
|
57
62
|
elif [ "$cost_pct" -ge 90 ] && [ "$last_level" != "90" ] && [ "$last_level" != "100" ]; then
|
|
58
63
|
echo "[Cost Cap] Session cost \$${cost_usd} at 90% of cap \$${COST_CAP}" >&2
|
|
59
64
|
echo "[Cost Cap] Ecomode recommended — consider /compact" >&2
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Advisory guard for destructive git commands.
|
|
3
|
+
# Warns before commands that can discard worktree or branch state.
|
|
4
|
+
# This hook is advisory only: it prints warnings to stderr, records a
|
|
5
|
+
# PPID-scoped event, echoes the original hook input, and exits 0.
|
|
6
|
+
|
|
7
|
+
input=$(cat)
|
|
8
|
+
cmd=""
|
|
9
|
+
|
|
10
|
+
if command -v jq >/dev/null 2>&1; then
|
|
11
|
+
cmd=$(echo "$input" | jq -r '.tool_input.command // ""' 2>/dev/null)
|
|
12
|
+
elif command -v node >/dev/null 2>&1; then
|
|
13
|
+
cmd=$(
|
|
14
|
+
printf '%s' "$input" | node -e 'let s = ""; process.stdin.on("data", d => s += d); process.stdin.on("end", () => { try { const j = JSON.parse(s); process.stdout.write(j?.tool_input?.command || ""); } catch { process.exit(0); } });' 2>/dev/null
|
|
15
|
+
)
|
|
16
|
+
fi
|
|
17
|
+
|
|
18
|
+
warn() {
|
|
19
|
+
local pattern="$1"
|
|
20
|
+
local command="$2"
|
|
21
|
+
local violation_file="/tmp/.codex-destructive-git-violations-${PPID}"
|
|
22
|
+
|
|
23
|
+
echo "[Hook] WARNING: destructive git command detected: ${pattern}" >&2
|
|
24
|
+
echo "[Hook] Command: ${command}" >&2
|
|
25
|
+
echo "[Hook] Verify target, preserve important work, and get explicit approval before continuing." >&2
|
|
26
|
+
echo "[Hook] Recovery: inspect 'git status', 'git diff', and 'git reflog' before attempting repair." >&2
|
|
27
|
+
|
|
28
|
+
printf '%s\t%s\t%s\n' "$(date -u +%Y-%m-%dT%H:%M:%SZ)" "$pattern" "$command" >> "$violation_file"
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if [ -n "$cmd" ]; then
|
|
32
|
+
case "$cmd" in
|
|
33
|
+
*"git reset --hard"*)
|
|
34
|
+
warn "git reset --hard" "$cmd"
|
|
35
|
+
;;
|
|
36
|
+
*"git clean -fd"*|*"git clean -df"*|*"git clean -fxd"*|*"git clean -xdf"*)
|
|
37
|
+
warn "git clean -fd/-fdx" "$cmd"
|
|
38
|
+
;;
|
|
39
|
+
*"git restore"*|*"git checkout -- ."*|*"git checkout -- *"*)
|
|
40
|
+
warn "git restore / git checkout --" "$cmd"
|
|
41
|
+
;;
|
|
42
|
+
*"git branch -D"*)
|
|
43
|
+
warn "git branch -D" "$cmd"
|
|
44
|
+
echo "[Hook] Check whether the branch is merged before deleting it." >&2
|
|
45
|
+
;;
|
|
46
|
+
*"git push --force"*|*"git push -f"*)
|
|
47
|
+
warn "git push --force" "$cmd"
|
|
48
|
+
;;
|
|
49
|
+
esac
|
|
50
|
+
fi
|
|
51
|
+
|
|
52
|
+
echo "$input"
|
|
53
|
+
exit 0
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
|
-
# SessionStart auto-update hook — interactive
|
|
2
|
+
# SessionStart auto-update hook — interactive omcustomcodex update check
|
|
3
3
|
# Trigger: SessionStart (runs BEFORE session-env-check.sh)
|
|
4
4
|
# Purpose: Check for oh-my-customcodex updates, prompt user, optionally update
|
|
5
5
|
# Protocol: stdin JSON -> stdout pass-through, exit 0 ALWAYS
|
|
@@ -135,17 +135,17 @@ if read -r -t "$INPUT_TIMEOUT" answer </dev/tty 2>/dev/null; then
|
|
|
135
135
|
echo " ✓ Updated to v${LATEST_VERSION}" >&2
|
|
136
136
|
|
|
137
137
|
# Check if project harness should be updated too
|
|
138
|
-
if [ -f ".omcustomrc.json" ]; then
|
|
138
|
+
if [ -f ".omcodexrc.json" ] || [ -f ".omcustomrc.json" ]; then
|
|
139
139
|
printf " Update project harness too? [y/N] " >/dev/tty 2>/dev/null
|
|
140
140
|
if read -r -t "$INPUT_TIMEOUT" harness_answer </dev/tty 2>/dev/null; then
|
|
141
141
|
case "$harness_answer" in
|
|
142
142
|
[yY]|[yY][eE][sS])
|
|
143
143
|
echo " Updating project harness..." >&2
|
|
144
|
-
if command -v
|
|
145
|
-
|
|
144
|
+
if command -v omcustomcodex >/dev/null 2>&1; then
|
|
145
|
+
omcustomcodex update --force >&2 2>&1 || echo " ⚠ Harness update failed (non-blocking)" >&2
|
|
146
146
|
echo " ✓ Project harness updated" >&2
|
|
147
147
|
else
|
|
148
|
-
echo " ⚠
|
|
148
|
+
echo " ⚠ omcustomcodex command not found after install" >&2
|
|
149
149
|
fi
|
|
150
150
|
;;
|
|
151
151
|
*)
|
|
@@ -126,8 +126,10 @@ OMCUSTOM_UPDATE_STATUS="unknown"
|
|
|
126
126
|
INSTALLED_VERSION=""
|
|
127
127
|
CACHED_LATEST=""
|
|
128
128
|
|
|
129
|
-
# Read installed version from .
|
|
130
|
-
if [ -f ".
|
|
129
|
+
# Read installed version from the Codex config, falling back to the legacy parent config.
|
|
130
|
+
if [ -f ".omcodexrc.json" ]; then
|
|
131
|
+
INSTALLED_VERSION=$(grep -o '"version"[[:space:]]*:[[:space:]]*"[^"]*"' .omcodexrc.json 2>/dev/null | head -1 | grep -o '"[^"]*"$' | tr -d '"')
|
|
132
|
+
elif [ -f ".omcustomrc.json" ]; then
|
|
131
133
|
INSTALLED_VERSION=$(grep -o '"version"[[:space:]]*:[[:space:]]*"[^"]*"' .omcustomrc.json 2>/dev/null | head -1 | grep -o '"[^"]*"$' | tr -d '"')
|
|
132
134
|
fi
|
|
133
135
|
|
|
@@ -222,8 +224,8 @@ case "$DRIFT_STATUS" in
|
|
|
222
224
|
esac
|
|
223
225
|
echo "" >&2
|
|
224
226
|
echo " [Lockfile Drift]" >&2
|
|
225
|
-
echo " Note: file-level lockfile drift (template hash changes) is checked via '
|
|
226
|
-
echo " Run '
|
|
227
|
+
echo " Note: file-level lockfile drift (template hash changes) is checked via 'omcustomcodex doctor'" >&2
|
|
228
|
+
echo " Run 'omcustomcodex doctor' to detect modified/removed template files since install." >&2
|
|
227
229
|
echo "------------------------------------" >&2
|
|
228
230
|
|
|
229
231
|
# SessionEnd hooks timeout (v2.1.74+)
|
|
@@ -238,12 +240,12 @@ echo " [Update Check]" >&2
|
|
|
238
240
|
if [ -n "$INSTALLED_VERSION" ] && [ -n "$CACHED_LATEST" ]; then
|
|
239
241
|
if [ "$OMCUSTOM_UPDATE_STATUS" = "available" ]; then
|
|
240
242
|
echo " ⚡ oh-my-customcodex v${CACHED_LATEST} available (current: v${INSTALLED_VERSION})" >&2
|
|
241
|
-
echo " Run '
|
|
243
|
+
echo " Run 'omcustomcodex update' to apply" >&2
|
|
242
244
|
else
|
|
243
245
|
echo " ✓ oh-my-customcodex is up to date (v${INSTALLED_VERSION})" >&2
|
|
244
246
|
fi
|
|
245
247
|
elif [ -n "$INSTALLED_VERSION" ]; then
|
|
246
|
-
echo " ℹ oh-my-customcodex v${INSTALLED_VERSION} (run '
|
|
248
|
+
echo " ℹ oh-my-customcodex v${INSTALLED_VERSION} (run 'omcustomcodex doctor --updates' to check for updates)" >&2
|
|
247
249
|
else
|
|
248
250
|
echo " ℹ oh-my-customcodex not detected in this project" >&2
|
|
249
251
|
fi
|
|
@@ -10,7 +10,7 @@ command -v jq >/dev/null 2>&1 || exit 0
|
|
|
10
10
|
# Purpose: Detect repetitive failure loops and advise recovery
|
|
11
11
|
# Protocol: stdin JSON -> process -> stdout pass-through
|
|
12
12
|
# - exit 0: advisory (normal cases, < HARD_BLOCK_THRESHOLD repetitions)
|
|
13
|
-
# - exit
|
|
13
|
+
# - exit 2: conversation block (extreme stuck loops, >= HARD_BLOCK_THRESHOLD repetitions)
|
|
14
14
|
|
|
15
15
|
# Hard block threshold: consecutive identical operations before blocking
|
|
16
16
|
HARD_BLOCK_THRESHOLD=${CLAUDE_STUCK_THRESHOLD:-3}
|
|
@@ -186,7 +186,7 @@ if [ "$hard_block" = true ]; then
|
|
|
186
186
|
HOOK_MS=$(( (HOOK_END - HOOK_START) / 1000000 ))
|
|
187
187
|
echo "[Hook Perf] $(basename "$0"): ${HOOK_MS}ms" >> "/tmp/.codex-hook-perf-${PPID}.log"
|
|
188
188
|
fi
|
|
189
|
-
exit
|
|
189
|
+
exit 2
|
|
190
190
|
fi
|
|
191
191
|
|
|
192
192
|
# Pass through
|
|
@@ -46,7 +46,7 @@ classes:
|
|
|
46
46
|
description: "System information and utilities"
|
|
47
47
|
|
|
48
48
|
GoalWorkflowSkill:
|
|
49
|
-
skills: [goal]
|
|
49
|
+
skills: ["omcustomcodex:goal"]
|
|
50
50
|
description: "Goal-to-execution workflow coordination"
|
|
51
51
|
|
|
52
52
|
VerificationSkill:
|
|
@@ -178,14 +178,14 @@ skills:
|
|
|
178
178
|
keywords: [review, code-review, best-practices, quality]
|
|
179
179
|
rule_references: []
|
|
180
180
|
|
|
181
|
-
goal:
|
|
181
|
+
"omcustomcodex:goal":
|
|
182
182
|
class: GoalWorkflowSkill
|
|
183
183
|
description: "Goal-to-execution workflow for disciplined Codex + OMX task completion"
|
|
184
184
|
user_invocable: true
|
|
185
185
|
model_invocable: true
|
|
186
186
|
scope: core
|
|
187
187
|
summary: "Keep a concrete objective visible through clarification, planning, execution, verification, and completion reporting"
|
|
188
|
-
keywords: [goal, objective, planning, execution, verification, completion]
|
|
188
|
+
keywords: [goal, omcustomcodex-goal, objective, planning, execution, verification, completion]
|
|
189
189
|
rule_references: [R020]
|
|
190
190
|
|
|
191
191
|
docker-best-practices:
|
|
@@ -72,6 +72,7 @@ disableSkillShellExecution: true # Disable inline shell execution in skills (v2
|
|
|
72
72
|
<!-- DETAIL: CC Version Compatibility History
|
|
73
73
|
`isolation`, `background`, `maxTurns`, `maxTokens`, `mcpServers`, `hooks`, `permissionMode`, `disallowedTools`, `limitations` are supported in Claude Code v2.1.63+. Hook types `PostCompact`, `Elicitation`, `ElicitationResult` require v2.1.76+. `CwdChanged`, `FileChanged` hook events and `managed-settings.d/` drop-in directory require v2.1.83+. Conditional `if` field for hooks requires v2.1.85+. `PermissionDenied` hook event requires v2.1.88+. `refreshInterval` setting for status line auto-refresh interval added in v2.1.97+. Monitor tool and subprocess sandboxing (`CLAUDE_CODE_SUBPROCESS_ENV_SCRUB`, `CLAUDE_CODE_SCRIPT_CAPS`) added in v2.1.98+. Settings resilience (unrecognized hook event names no longer cause settings.json to be ignored) improved in v2.1.101+. PreCompact hook block support (exit 2 / `{"decision":"block"}`) added in v2.1.105+. Skill description listing cap raised from 250 to 1,536 characters in v2.1.105+. Plugin `monitors` manifest key for background monitors added in v2.1.105+. `ENABLE_PROMPT_CACHING_1H` and `FORCE_PROMPT_CACHING_5M` env vars for prompt cache TTL control added in v2.1.108+. Skill tool can now discover and invoke built-in slash commands (`/init`, `/review`, `/security-review`) in v2.1.108+. `/recap` session context feature and `/undo` alias for `/rewind` added in v2.1.108+. `/tui` command and `tui` setting for fullscreen rendering added in v2.1.110+. PushNotification tool for mobile push notifications (Remote Control + config required) added in v2.1.110+. `autoScrollEnabled` config for fullscreen mode added in v2.1.110+. SDK/headless `TRACEPARENT`/`TRACESTATE` distributed trace linking added in v2.1.110+. Bash tool maximum timeout enforcement added in v2.1.110+. Write tool IDE diff feedback (informs model when user edits proposed content) added in v2.1.110+. `--resume`/`--continue` now resurrects unexpired scheduled tasks in v2.1.110+. `/focus` command (separated from Ctrl+O) added in v2.1.110+. `xhigh` effort level for Opus 4.7 (between `high` and `max`; other models fall back to `high`) added in v2.1.111+. `/effort` interactive slider with arrow-key navigation (when called without arguments) added in v2.1.111+. Auto mode no longer requires `--enable-auto-mode` in v2.1.111+. PowerShell tool progressive rollout (`CLAUDE_CODE_USE_POWERSHELL_TOOL` env var) added in v2.1.111+. Read-only bash commands with glob patterns (`ls *.ts`) and `cd <project-dir> &&` prefix no longer trigger permission prompt in v2.1.111+. `/less-permission-prompts` built-in skill for permission allowlist scanning added in v2.1.111+. `/ultrareview` parallel multi-agent cloud code review added in v2.1.111+. `/skills` menu sorting by estimated token count (press `t`) added in v2.1.111+. `OTEL_LOG_RAW_API_BODIES` env var for full API request/response body logging added in v2.1.111+. Plan files named after prompt content (not random words) in v2.1.111+. Plugin error handling improvements (dependency conflict errors, stale version recovery, install recovery) in v2.1.111+.
|
|
74
74
|
`sandbox.network.deniedDomains` setting for domain blocking within `allowedDomains` wildcards added in v2.1.113+. Subagent mid-stream stall detection with auto-fail after 10 minutes added in v2.1.113+. Bash `find -exec`/`-delete` no longer auto-approved under `Bash(find:*)` allow rules in v2.1.113+. Bash deny rules now match exec wrappers (`env`/`sudo`/`watch`/`ionice`/`setsid`) in v2.1.113+. Native binary spawning (per-platform optional dependency) replaces bundled JavaScript in v2.1.113+. `/loop` Esc now cancels pending wakeups in v2.1.113+.
|
|
75
|
+
Agent frontmatter `hooks:` fire when the agent runs as a main-thread agent via `--agent` flag in v2.1.116+. Hook JSON output `terminalSequence` field for desktop notifications, window title changes, and terminal bells without controlling terminal added in v2.1.141+. `claude agents --cwd <path>` for directory-scoped session lists added in v2.1.141+. Background agents launched via `/bg` preserve current permission mode in v2.1.141+. `CLAUDE_CODE_PLUGIN_PREFER_HTTPS` and `ANTHROPIC_WORKSPACE_ID` environment variables added in v2.1.141+ for HTTPS plugin clones and workspace-scoped federation.
|
|
75
76
|
-->
|
|
76
77
|
|
|
77
78
|
## Hook Event Types
|