claudecode-omc 5.3.0 → 5.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/.local/guidelines/CLAUDE.md +31 -0
- package/README.md +57 -1
- package/bundled/manifest.json +2 -2
- package/bundled/upstream/oh-my-claudecode/agents/analyst.md +1 -1
- package/bundled/upstream/oh-my-claudecode/agents/architect.md +1 -1
- package/bundled/upstream/oh-my-claudecode/agents/code-reviewer.md +1 -1
- package/bundled/upstream/oh-my-claudecode/agents/code-simplifier.md +1 -1
- package/bundled/upstream/oh-my-claudecode/agents/critic.md +1 -1
- package/bundled/upstream/oh-my-claudecode/agents/debugger.md +1 -1
- package/bundled/upstream/oh-my-claudecode/agents/designer.md +1 -1
- package/bundled/upstream/oh-my-claudecode/agents/document-specialist.md +1 -1
- package/bundled/upstream/oh-my-claudecode/agents/executor.md +1 -1
- package/bundled/upstream/oh-my-claudecode/agents/explore.md +1 -1
- package/bundled/upstream/oh-my-claudecode/agents/git-master.md +3 -3
- package/bundled/upstream/oh-my-claudecode/agents/planner.md +1 -1
- package/bundled/upstream/oh-my-claudecode/agents/qa-tester.md +1 -1
- package/bundled/upstream/oh-my-claudecode/agents/scientist.md +1 -1
- package/bundled/upstream/oh-my-claudecode/agents/security-reviewer.md +1 -1
- package/bundled/upstream/oh-my-claudecode/agents/test-engineer.md +1 -75
- package/bundled/upstream/oh-my-claudecode/agents/tracer.md +1 -1
- package/bundled/upstream/oh-my-claudecode/agents/verifier.md +1 -1
- package/bundled/upstream/oh-my-claudecode/agents/writer.md +1 -1
- package/bundled/upstream/oh-my-claudecode/hooks/hooks.json +21 -1
- package/bundled/upstream/oh-my-claudecode/skills/AGENTS.md +200 -0
- package/bundled/upstream/oh-my-claudecode/skills/autopilot/SKILL.md +17 -10
- package/bundled/upstream/oh-my-claudecode/skills/autoresearch/SKILL.md +90 -0
- package/bundled/upstream/oh-my-claudecode/skills/cancel/SKILL.md +15 -6
- package/bundled/upstream/oh-my-claudecode/skills/configure-notifications/SKILL.md +12 -12
- package/bundled/upstream/oh-my-claudecode/skills/debug/SKILL.md +35 -0
- package/bundled/upstream/oh-my-claudecode/skills/deep-dive/SKILL.md +4 -0
- package/bundled/upstream/oh-my-claudecode/skills/deep-interview/SKILL.md +23 -18
- package/bundled/upstream/oh-my-claudecode/skills/hud/SKILL.md +23 -101
- package/bundled/upstream/oh-my-claudecode/skills/learner/SKILL.md +27 -2
- package/bundled/upstream/oh-my-claudecode/skills/mcp-setup/SKILL.md +67 -8
- package/bundled/upstream/oh-my-claudecode/skills/omc-doctor/SKILL.md +32 -47
- package/bundled/upstream/oh-my-claudecode/skills/omc-setup/SKILL.md +4 -2
- package/bundled/upstream/oh-my-claudecode/skills/omc-setup/phases/01-install-claude-md.md +15 -4
- package/bundled/upstream/oh-my-claudecode/skills/omc-setup/phases/02-configure.md +9 -9
- package/bundled/upstream/oh-my-claudecode/skills/omc-setup/phases/03-integrations.md +13 -13
- package/bundled/upstream/oh-my-claudecode/skills/omc-setup/phases/04-welcome.md +3 -3
- package/bundled/upstream/oh-my-claudecode/skills/omc-teams/SKILL.md +28 -0
- package/bundled/upstream/oh-my-claudecode/skills/plan/SKILL.md +1 -0
- package/bundled/upstream/oh-my-claudecode/skills/project-session-manager/SKILL.md +25 -5
- package/bundled/upstream/oh-my-claudecode/skills/project-session-manager/lib/config.sh +2 -15
- package/bundled/upstream/oh-my-claudecode/skills/project-session-manager/lib/providers/github.sh +1 -1
- package/bundled/upstream/oh-my-claudecode/skills/project-session-manager/lib/session.sh +2 -2
- package/bundled/upstream/oh-my-claudecode/skills/project-session-manager/lib/tmux.sh +109 -4
- package/bundled/upstream/oh-my-claudecode/skills/project-session-manager/lib/worktree.sh +26 -0
- package/bundled/upstream/oh-my-claudecode/skills/project-session-manager/psm.sh +46 -5
- package/bundled/upstream/oh-my-claudecode/skills/project-session-manager/templates/pr-review.md +5 -2
- package/bundled/upstream/oh-my-claudecode/skills/project-session-manager/templates/projects.json +1 -1
- package/bundled/upstream/oh-my-claudecode/skills/project-session-manager/tests/test-psm-prompt-injection.sh +336 -0
- package/bundled/upstream/oh-my-claudecode/skills/ralph/SKILL.md +18 -9
- package/bundled/upstream/oh-my-claudecode/skills/ralplan/SKILL.md +2 -0
- package/bundled/upstream/oh-my-claudecode/skills/release/SKILL.md +167 -57
- package/bundled/upstream/oh-my-claudecode/skills/remember/SKILL.md +41 -0
- package/bundled/upstream/oh-my-claudecode/skills/self-improve/SKILL.md +391 -0
- package/bundled/upstream/oh-my-claudecode/skills/self-improve/data_contracts.md +274 -0
- package/bundled/upstream/oh-my-claudecode/skills/self-improve/scripts/plot_progress.py +128 -0
- package/bundled/upstream/oh-my-claudecode/skills/self-improve/scripts/resolve-paths.mjs +192 -0
- package/bundled/upstream/oh-my-claudecode/skills/self-improve/scripts/validate.sh +404 -0
- package/bundled/upstream/oh-my-claudecode/skills/self-improve/si-benchmark-builder.md +79 -0
- package/bundled/upstream/oh-my-claudecode/skills/self-improve/si-goal-clarifier.md +94 -0
- package/bundled/upstream/oh-my-claudecode/skills/self-improve/si-researcher.md +73 -0
- package/bundled/upstream/oh-my-claudecode/skills/self-improve/templates/agent-settings.json +14 -0
- package/bundled/upstream/oh-my-claudecode/skills/self-improve/templates/goal.md +22 -0
- package/bundled/upstream/oh-my-claudecode/skills/self-improve/templates/harness.md +18 -0
- package/bundled/upstream/oh-my-claudecode/skills/self-improve/templates/idea.md +5 -0
- package/bundled/upstream/oh-my-claudecode/skills/self-improve/templates/settings.json +23 -0
- package/bundled/upstream/oh-my-claudecode/skills/skill/SKILL.md +46 -77
- package/bundled/upstream/oh-my-claudecode/skills/skillify/SKILL.md +53 -0
- package/bundled/upstream/oh-my-claudecode/skills/team/SKILL.md +83 -11
- package/bundled/upstream/oh-my-claudecode/skills/trace/SKILL.md +1 -0
- package/bundled/upstream/oh-my-claudecode/skills/ultraqa/SKILL.md +1 -0
- package/bundled/upstream/oh-my-claudecode/skills/ultrawork/SKILL.md +1 -0
- package/bundled/upstream/oh-my-claudecode/skills/verify/SKILL.md +37 -0
- package/bundled/upstream/oh-my-claudecode/skills/wiki/SKILL.md +67 -0
- package/package.json +3 -1
- package/src/cli/artifact.js +63 -2
- package/src/cli/guidelines.js +83 -0
- package/src/cli/index.js +13 -1
- package/src/cli/setup.js +48 -18
- package/src/cli/source.js +35 -1
- package/src/config/artifact-types.js +12 -2
- package/src/config/paths.js +95 -4
- package/src/config/sources.js +29 -5
- package/src/guidelines/apply.js +152 -0
- package/src/guidelines/optimizer.js +325 -0
- package/src/merge/claude-md-merger.js +35 -12
- package/templates/merge-config.json +12 -1
- package/bundled/upstream/oh-my-claudecode/skills/omc-doctor/skill-debugger.md +0 -101
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const fsp = require('fs/promises');
|
|
3
|
+
const path = require('path');
|
|
4
|
+
const { getProjectRoot } = require('../config/paths');
|
|
5
|
+
const { sha256 } = require('./optimizer');
|
|
6
|
+
|
|
7
|
+
function assert(condition, message) {
|
|
8
|
+
if (!condition) {
|
|
9
|
+
throw new Error(message);
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function readJson(filePath) {
|
|
14
|
+
return JSON.parse(fs.readFileSync(filePath, 'utf8'));
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
async function ensureDir(dirPath) {
|
|
18
|
+
await fsp.mkdir(dirPath, { recursive: true });
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
async function writeJson(filePath, value) {
|
|
22
|
+
await ensureDir(path.dirname(filePath));
|
|
23
|
+
await fsp.writeFile(filePath, JSON.stringify(value, null, 2) + '\n', 'utf8');
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
async function writeText(filePath, value) {
|
|
27
|
+
await ensureDir(path.dirname(filePath));
|
|
28
|
+
await fsp.writeFile(filePath, value, 'utf8');
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function validateResult(result) {
|
|
32
|
+
assert(result && typeof result === 'object', 'Result file must contain a JSON object.');
|
|
33
|
+
assert(result.version === 1, 'Result file must set "version": 1.');
|
|
34
|
+
assert(typeof result.generatedBy === 'string' && result.generatedBy.trim(), 'Result file must include generatedBy.');
|
|
35
|
+
assert(typeof result.summary === 'string' && result.summary.trim(), 'Result file must include summary.');
|
|
36
|
+
assert(
|
|
37
|
+
typeof result.runtimeGuidelinesMarkdown === 'string' &&
|
|
38
|
+
result.runtimeGuidelinesMarkdown.trim().startsWith('# '),
|
|
39
|
+
'runtimeGuidelinesMarkdown must be markdown starting with a top-level heading.'
|
|
40
|
+
);
|
|
41
|
+
assert(Array.isArray(result.decisions), 'Result file must include a decisions array.');
|
|
42
|
+
assert(Array.isArray(result.conflicts), 'Result file must include a conflicts array.');
|
|
43
|
+
|
|
44
|
+
for (const [index, decision] of result.decisions.entries()) {
|
|
45
|
+
assert(typeof decision === 'object' && decision, `decisions[${index}] must be an object.`);
|
|
46
|
+
assert(typeof decision.action === 'string' && decision.action.trim(), `decisions[${index}].action is required.`);
|
|
47
|
+
assert(Array.isArray(decision.sourceSectionIds), `decisions[${index}].sourceSectionIds must be an array.`);
|
|
48
|
+
assert(typeof decision.title === 'string' && decision.title.trim(), `decisions[${index}].title is required.`);
|
|
49
|
+
assert(typeof decision.rationale === 'string' && decision.rationale.trim(), `decisions[${index}].rationale is required.`);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
for (const [index, conflict] of result.conflicts.entries()) {
|
|
53
|
+
assert(typeof conflict === 'object' && conflict, `conflicts[${index}] must be an object.`);
|
|
54
|
+
assert(Array.isArray(conflict.sourceSectionIds), `conflicts[${index}].sourceSectionIds must be an array.`);
|
|
55
|
+
assert(typeof conflict.resolution === 'string' && conflict.resolution.trim(), `conflicts[${index}].resolution is required.`);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function buildDecisionLog(result) {
|
|
60
|
+
const lines = [
|
|
61
|
+
'# Guideline Optimization Decision Log',
|
|
62
|
+
'',
|
|
63
|
+
`Generated by: ${result.generatedBy}`,
|
|
64
|
+
'',
|
|
65
|
+
`Summary: ${result.summary}`,
|
|
66
|
+
'',
|
|
67
|
+
'## Decisions',
|
|
68
|
+
'',
|
|
69
|
+
];
|
|
70
|
+
|
|
71
|
+
for (const decision of result.decisions) {
|
|
72
|
+
lines.push(`### ${decision.title}`);
|
|
73
|
+
lines.push(`- Action: ${decision.action}`);
|
|
74
|
+
lines.push(`- Source sections: ${decision.sourceSectionIds.join(', ') || 'none'}`);
|
|
75
|
+
lines.push(`- Rationale: ${decision.rationale}`);
|
|
76
|
+
lines.push('');
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
lines.push('## Conflicts');
|
|
80
|
+
lines.push('');
|
|
81
|
+
|
|
82
|
+
if (result.conflicts.length === 0) {
|
|
83
|
+
lines.push('- None');
|
|
84
|
+
lines.push('');
|
|
85
|
+
return lines.join('\n');
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
for (const conflict of result.conflicts) {
|
|
89
|
+
lines.push(`- Sections: ${conflict.sourceSectionIds.join(', ') || 'none'}`);
|
|
90
|
+
lines.push(` Resolution: ${conflict.resolution}`);
|
|
91
|
+
}
|
|
92
|
+
lines.push('');
|
|
93
|
+
|
|
94
|
+
return lines.join('\n');
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
async function applyGuidelineResult(options = {}) {
|
|
98
|
+
const root = getProjectRoot();
|
|
99
|
+
assert(options.resultFile, 'apply requires --result-file <path>.');
|
|
100
|
+
|
|
101
|
+
const resultFile = path.resolve(root, options.resultFile);
|
|
102
|
+
assert(fs.existsSync(resultFile), `Result file not found: ${resultFile}`);
|
|
103
|
+
|
|
104
|
+
const result = readJson(resultFile);
|
|
105
|
+
validateResult(result);
|
|
106
|
+
|
|
107
|
+
const runtimePath = path.join(root, '.local', 'guidelines', 'CLAUDE.md');
|
|
108
|
+
const outputDir = options.outputDir
|
|
109
|
+
? path.resolve(root, options.outputDir)
|
|
110
|
+
: path.join(root, '.omc', 'guidelines');
|
|
111
|
+
const latestDir = path.join(outputDir, 'latest');
|
|
112
|
+
const appliedDir = path.join(outputDir, 'applied');
|
|
113
|
+
const appliedRunDir = path.join(appliedDir, new Date().toISOString().replace(/[:.]/g, '-'));
|
|
114
|
+
const runtimeMarkdown = result.runtimeGuidelinesMarkdown.trimEnd() + '\n';
|
|
115
|
+
const appliedSummary = {
|
|
116
|
+
appliedAt: new Date().toISOString(),
|
|
117
|
+
generatedBy: result.generatedBy,
|
|
118
|
+
summary: result.summary,
|
|
119
|
+
resultFile,
|
|
120
|
+
runtimePath,
|
|
121
|
+
runtimeGuidelinesHash: sha256(runtimeMarkdown),
|
|
122
|
+
decisions: result.decisions.length,
|
|
123
|
+
conflicts: result.conflicts.length,
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
if (!options.dryRun) {
|
|
127
|
+
await writeText(runtimePath, runtimeMarkdown);
|
|
128
|
+
await writeText(path.join(latestDir, 'current-local-guidelines.md'), runtimeMarkdown);
|
|
129
|
+
await writeJson(path.join(latestDir, 'result.json'), result);
|
|
130
|
+
await writeText(path.join(latestDir, 'decision-log.md'), buildDecisionLog(result));
|
|
131
|
+
await writeJson(path.join(latestDir, 'applied-summary.json'), appliedSummary);
|
|
132
|
+
|
|
133
|
+
await writeText(path.join(appliedRunDir, 'current-local-guidelines.md'), runtimeMarkdown);
|
|
134
|
+
await writeJson(path.join(appliedRunDir, 'result.json'), result);
|
|
135
|
+
await writeText(path.join(appliedRunDir, 'decision-log.md'), buildDecisionLog(result));
|
|
136
|
+
await writeJson(path.join(appliedRunDir, 'applied-summary.json'), appliedSummary);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
return {
|
|
140
|
+
resultFile,
|
|
141
|
+
runtimePath,
|
|
142
|
+
latestDir,
|
|
143
|
+
appliedRunDir,
|
|
144
|
+
appliedSummary,
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
module.exports = {
|
|
149
|
+
applyGuidelineResult,
|
|
150
|
+
buildDecisionLog,
|
|
151
|
+
validateResult,
|
|
152
|
+
};
|
|
@@ -0,0 +1,325 @@
|
|
|
1
|
+
/* eslint-disable no-console */
|
|
2
|
+
const fs = require('fs');
|
|
3
|
+
const fsp = require('fs/promises');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const crypto = require('crypto');
|
|
6
|
+
const { getProjectRoot, getSourceArtifactDir } = require('../config/paths');
|
|
7
|
+
const { readConfig } = require('../config/sources');
|
|
8
|
+
const { loadClaudeMd } = require('../merge/claude-md-merger');
|
|
9
|
+
|
|
10
|
+
function sanitizeSlug(value) {
|
|
11
|
+
return value
|
|
12
|
+
.toLowerCase()
|
|
13
|
+
.replace(/[^a-z0-9]+/g, '-')
|
|
14
|
+
.replace(/^-+|-+$/g, '')
|
|
15
|
+
.slice(0, 64) || 'untitled';
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function sha256(value) {
|
|
19
|
+
return crypto.createHash('sha256').update(value).digest('hex');
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function getGuidelineSources(root, requestedSources = []) {
|
|
23
|
+
const config = readConfig();
|
|
24
|
+
const requested = new Set(requestedSources);
|
|
25
|
+
|
|
26
|
+
return Object.entries(config.sources)
|
|
27
|
+
.sort(([, a], [, b]) => a.priority - b.priority)
|
|
28
|
+
.filter(([name, source]) => {
|
|
29
|
+
if (source.role === 'reference') return false;
|
|
30
|
+
if (requested.size > 0 && !requested.has(name)) return false;
|
|
31
|
+
const artifacts = source.artifacts || [];
|
|
32
|
+
return artifacts.includes('guidelines') || artifacts.includes('claude-md');
|
|
33
|
+
})
|
|
34
|
+
.map(([name, source]) => {
|
|
35
|
+
const dir = getSourceArtifactDir(name, 'guidelines', root);
|
|
36
|
+
return { name, source, dir };
|
|
37
|
+
})
|
|
38
|
+
.filter(({ dir }) => fs.existsSync(dir))
|
|
39
|
+
.map(({ name, source, dir }) => {
|
|
40
|
+
const content = loadClaudeMd(dir);
|
|
41
|
+
if (!content) return null;
|
|
42
|
+
return {
|
|
43
|
+
sourceName: name,
|
|
44
|
+
priority: source.priority,
|
|
45
|
+
role: source.role || null,
|
|
46
|
+
dir,
|
|
47
|
+
content,
|
|
48
|
+
};
|
|
49
|
+
})
|
|
50
|
+
.filter(Boolean);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function extractDocumentTitle(content) {
|
|
54
|
+
const firstHeader = content.match(/^#\s+(.+)$/m);
|
|
55
|
+
return firstHeader ? firstHeader[1].trim() : 'Guidelines';
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function splitGuidelineSections(content, sourceName) {
|
|
59
|
+
const normalized = content.replace(/\r\n/g, '\n').trim();
|
|
60
|
+
const docTitle = extractDocumentTitle(normalized);
|
|
61
|
+
const lines = normalized.split('\n');
|
|
62
|
+
const sections = [];
|
|
63
|
+
let current = null;
|
|
64
|
+
let sectionIndex = 0;
|
|
65
|
+
|
|
66
|
+
for (const line of lines) {
|
|
67
|
+
if (/^##\s+/.test(line)) {
|
|
68
|
+
if (current && current.body.trim()) {
|
|
69
|
+
sections.push(current);
|
|
70
|
+
}
|
|
71
|
+
sectionIndex += 1;
|
|
72
|
+
current = {
|
|
73
|
+
id: `${sourceName}:${sectionIndex}`,
|
|
74
|
+
sourceName,
|
|
75
|
+
title: line.replace(/^##\s+/, '').trim(),
|
|
76
|
+
body: '',
|
|
77
|
+
};
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (!current) {
|
|
82
|
+
current = {
|
|
83
|
+
id: `${sourceName}:0`,
|
|
84
|
+
sourceName,
|
|
85
|
+
title: docTitle,
|
|
86
|
+
body: '',
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
current.body += (current.body ? '\n' : '') + line;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (current && current.body.trim()) {
|
|
94
|
+
sections.push(current);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return sections
|
|
98
|
+
.map((section, index) => ({
|
|
99
|
+
...section,
|
|
100
|
+
id: `${sourceName}:${index + 1}`,
|
|
101
|
+
body: section.body.trim(),
|
|
102
|
+
slug: sanitizeSlug(section.title),
|
|
103
|
+
}))
|
|
104
|
+
.filter(section => section.body.length > 0);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function buildOptimizerPrompt({ sources, sections, currentLocalGuidelines, outputPath }) {
|
|
108
|
+
const sourceSummary = sources
|
|
109
|
+
.map(source => `- ${source.sourceName} (priority ${source.priority}${source.role ? `, role ${source.role}` : ''})`)
|
|
110
|
+
.join('\n');
|
|
111
|
+
|
|
112
|
+
const sectionText = sections.map((section) => (
|
|
113
|
+
`### ${section.id} — ${section.title}\n` +
|
|
114
|
+
`Source: ${section.sourceName}\n\n` +
|
|
115
|
+
`${section.body}\n`
|
|
116
|
+
)).join('\n');
|
|
117
|
+
|
|
118
|
+
const currentLocalText = currentLocalGuidelines
|
|
119
|
+
? currentLocalGuidelines.trim()
|
|
120
|
+
: '_No current local guidelines file found._';
|
|
121
|
+
|
|
122
|
+
return `# Guideline Optimizer Input
|
|
123
|
+
|
|
124
|
+
You are maintaining OMC's canonical runtime guidelines.
|
|
125
|
+
|
|
126
|
+
## Goal
|
|
127
|
+
|
|
128
|
+
Produce an improved \`CLAUDE.md\` section for OMC by semantically deduplicating,
|
|
129
|
+
merging, rewriting, and prioritizing the guideline material collected below.
|
|
130
|
+
|
|
131
|
+
## Constraints
|
|
132
|
+
|
|
133
|
+
- This is a maintainer workflow. The optimizer logic itself does not ship to end users.
|
|
134
|
+
- The runtime output must stay concise, high-signal, and suitable for always-on use.
|
|
135
|
+
- Prefer rewriting combined rules over stacking near-duplicates.
|
|
136
|
+
- Preserve behaviorally important constraints even if wording changes.
|
|
137
|
+
- Surface genuine conflicts explicitly instead of silently averaging them away.
|
|
138
|
+
- The final markdown should be written to \`${outputPath}\`.
|
|
139
|
+
- Output markdown body only. Do not include surrounding commentary.
|
|
140
|
+
|
|
141
|
+
## Source Summary
|
|
142
|
+
|
|
143
|
+
${sourceSummary}
|
|
144
|
+
|
|
145
|
+
## Current Local Guidelines
|
|
146
|
+
|
|
147
|
+
${currentLocalText}
|
|
148
|
+
|
|
149
|
+
## Extracted Source Sections
|
|
150
|
+
|
|
151
|
+
${sectionText}
|
|
152
|
+
|
|
153
|
+
## Required Output Shape
|
|
154
|
+
|
|
155
|
+
1. A canonical markdown document body suitable for \`${outputPath}\`
|
|
156
|
+
2. Short internal rationale notes for:
|
|
157
|
+
- merged rules
|
|
158
|
+
- dropped rules
|
|
159
|
+
- unresolved conflicts
|
|
160
|
+
|
|
161
|
+
When two sections are semantically overlapping, prefer a single clearer rule.
|
|
162
|
+
When one section is a stronger, more specific operationalization of another,
|
|
163
|
+
keep the stronger wording and note the collapse in rationale.`;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
async function ensureDir(dirPath) {
|
|
167
|
+
await fsp.mkdir(dirPath, { recursive: true });
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
async function writeJson(filePath, value) {
|
|
171
|
+
await ensureDir(path.dirname(filePath));
|
|
172
|
+
await fsp.writeFile(filePath, JSON.stringify(value, null, 2) + '\n', 'utf8');
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
async function writeText(filePath, value) {
|
|
176
|
+
await ensureDir(path.dirname(filePath));
|
|
177
|
+
await fsp.writeFile(filePath, value, 'utf8');
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
function buildNextSteps({ summary, latestDir }) {
|
|
181
|
+
const lines = [
|
|
182
|
+
'# Guideline Optimizer Next Steps',
|
|
183
|
+
'',
|
|
184
|
+
'This workflow is for Claude Code CLI or Codex operating inside the OMC repository.',
|
|
185
|
+
'',
|
|
186
|
+
'## Read First',
|
|
187
|
+
'',
|
|
188
|
+
`- ${path.join(latestDir, 'optimizer-input.md')}`,
|
|
189
|
+
`- ${path.join(latestDir, 'sections.json')}`,
|
|
190
|
+
`- ${path.join(latestDir, 'sources.json')}`,
|
|
191
|
+
`- ${path.join(summary.root, '.maintainer', 'skills', 'guideline-optimizer', 'SKILL.md')}`,
|
|
192
|
+
'',
|
|
193
|
+
'## Edit Target',
|
|
194
|
+
'',
|
|
195
|
+
`- ${summary.outputPath}`,
|
|
196
|
+
'',
|
|
197
|
+
'## Required Verification',
|
|
198
|
+
'',
|
|
199
|
+
'```bash',
|
|
200
|
+
'node bin/omc-manage.js setup --dry-run --type guidelines',
|
|
201
|
+
'node bin/omc-manage.js artifact list --type guidelines',
|
|
202
|
+
'```',
|
|
203
|
+
'',
|
|
204
|
+
'## Rules',
|
|
205
|
+
'',
|
|
206
|
+
'- Apply semantic merging, not text-level dedupe.',
|
|
207
|
+
'- Keep maintainer reasoning out of the runtime guideline file.',
|
|
208
|
+
'- Do not move maintainer-only workflow prompts into `.local/skills/`.',
|
|
209
|
+
'',
|
|
210
|
+
'## Structured Result Contract',
|
|
211
|
+
'',
|
|
212
|
+
'Create a JSON file with this shape, then apply it with the CLI:',
|
|
213
|
+
'',
|
|
214
|
+
'```json',
|
|
215
|
+
'{',
|
|
216
|
+
' "version": 1,',
|
|
217
|
+
' "generatedBy": "claude-code | codex | other",',
|
|
218
|
+
' "summary": "short description of what changed",',
|
|
219
|
+
' "runtimeGuidelinesMarkdown": "# Coding Discipline\\n...",',
|
|
220
|
+
' "decisions": [',
|
|
221
|
+
' {',
|
|
222
|
+
' "action": "keep | merge | rewrite | drop",',
|
|
223
|
+
' "sourceSectionIds": ["local:2"],',
|
|
224
|
+
' "title": "Think Before Coding",',
|
|
225
|
+
' "rationale": "why this rule stayed or changed"',
|
|
226
|
+
' }',
|
|
227
|
+
' ],',
|
|
228
|
+
' "conflicts": [',
|
|
229
|
+
' {',
|
|
230
|
+
' "sourceSectionIds": ["a:2", "b:4"],',
|
|
231
|
+
' "resolution": "how the conflict was resolved"',
|
|
232
|
+
' }',
|
|
233
|
+
' ]',
|
|
234
|
+
'}',
|
|
235
|
+
'```',
|
|
236
|
+
'',
|
|
237
|
+
'Apply it with:',
|
|
238
|
+
'',
|
|
239
|
+
'```bash',
|
|
240
|
+
'node bin/omc-manage.js guidelines apply --result-file /absolute/path/to/result.json',
|
|
241
|
+
'node bin/omc-manage.js setup --dry-run --type guidelines',
|
|
242
|
+
'```',
|
|
243
|
+
];
|
|
244
|
+
|
|
245
|
+
return lines.join('\n') + '\n';
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
async function optimizeGuidelines(options = {}) {
|
|
249
|
+
const root = getProjectRoot();
|
|
250
|
+
const selectedSources = options.sources || [];
|
|
251
|
+
const sources = getGuidelineSources(root, selectedSources);
|
|
252
|
+
|
|
253
|
+
if (sources.length === 0) {
|
|
254
|
+
throw new Error('No guideline sources found. Add a guidelines source or create .local/guidelines/CLAUDE.md.');
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
const sections = sources.flatMap(source => splitGuidelineSections(source.content, source.sourceName));
|
|
258
|
+
const localGuidelinesPath = path.join(root, '.local', 'guidelines', 'CLAUDE.md');
|
|
259
|
+
const currentLocalGuidelines = fs.existsSync(localGuidelinesPath)
|
|
260
|
+
? fs.readFileSync(localGuidelinesPath, 'utf8')
|
|
261
|
+
: '';
|
|
262
|
+
|
|
263
|
+
const runId = new Date().toISOString().replace(/[:.]/g, '-');
|
|
264
|
+
const baseOutputDir = options.outputDir
|
|
265
|
+
? path.resolve(root, options.outputDir)
|
|
266
|
+
: path.join(root, '.omc', 'guidelines');
|
|
267
|
+
const latestDir = path.join(baseOutputDir, 'latest');
|
|
268
|
+
const runDir = path.join(baseOutputDir, 'runs', runId);
|
|
269
|
+
|
|
270
|
+
const summary = {
|
|
271
|
+
runId,
|
|
272
|
+
root,
|
|
273
|
+
sourceCount: sources.length,
|
|
274
|
+
sectionCount: sections.length,
|
|
275
|
+
outputPath: localGuidelinesPath,
|
|
276
|
+
currentLocalGuidelinesHash: sha256(currentLocalGuidelines || ''),
|
|
277
|
+
latestDir,
|
|
278
|
+
runDir,
|
|
279
|
+
sources: sources.map(source => ({
|
|
280
|
+
sourceName: source.sourceName,
|
|
281
|
+
priority: source.priority,
|
|
282
|
+
role: source.role,
|
|
283
|
+
dir: source.dir,
|
|
284
|
+
title: extractDocumentTitle(source.content),
|
|
285
|
+
contentHash: sha256(source.content),
|
|
286
|
+
})),
|
|
287
|
+
};
|
|
288
|
+
|
|
289
|
+
const prompt = buildOptimizerPrompt({
|
|
290
|
+
sources: summary.sources,
|
|
291
|
+
sections,
|
|
292
|
+
currentLocalGuidelines,
|
|
293
|
+
outputPath: localGuidelinesPath,
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
if (!options.dryRun) {
|
|
297
|
+
await ensureDir(latestDir);
|
|
298
|
+
await ensureDir(runDir);
|
|
299
|
+
const nextSteps = buildNextSteps({ summary, latestDir });
|
|
300
|
+
|
|
301
|
+
await writeJson(path.join(latestDir, 'summary.json'), summary);
|
|
302
|
+
await writeJson(path.join(latestDir, 'sections.json'), sections);
|
|
303
|
+
await writeJson(path.join(latestDir, 'sources.json'), summary.sources);
|
|
304
|
+
await writeText(path.join(latestDir, 'optimizer-input.md'), prompt);
|
|
305
|
+
await writeText(path.join(latestDir, 'current-local-guidelines.md'), currentLocalGuidelines || '');
|
|
306
|
+
await writeText(path.join(latestDir, 'next-steps.md'), nextSteps);
|
|
307
|
+
|
|
308
|
+
await writeJson(path.join(runDir, 'summary.json'), summary);
|
|
309
|
+
await writeJson(path.join(runDir, 'sections.json'), sections);
|
|
310
|
+
await writeJson(path.join(runDir, 'sources.json'), summary.sources);
|
|
311
|
+
await writeText(path.join(runDir, 'optimizer-input.md'), prompt);
|
|
312
|
+
await writeText(path.join(runDir, 'current-local-guidelines.md'), currentLocalGuidelines || '');
|
|
313
|
+
await writeText(path.join(runDir, 'next-steps.md'), nextSteps);
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
return { summary, prompt };
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
module.exports = {
|
|
320
|
+
optimizeGuidelines,
|
|
321
|
+
getGuidelineSources,
|
|
322
|
+
splitGuidelineSections,
|
|
323
|
+
buildOptimizerPrompt,
|
|
324
|
+
sha256,
|
|
325
|
+
};
|
|
@@ -25,28 +25,51 @@ function assembleSections(sections) {
|
|
|
25
25
|
return sections.map(s => s.content).join('\n\n').trimEnd() + '\n';
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
+
function getMarkers(markerKey) {
|
|
29
|
+
return {
|
|
30
|
+
start: `<!-- OMC:${markerKey}:START -->`,
|
|
31
|
+
end: `<!-- OMC:${markerKey}:END -->`,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function replaceFirstMatchingBlock(result, markerKeys, block) {
|
|
36
|
+
for (const markerKey of markerKeys) {
|
|
37
|
+
const { start, end } = getMarkers(markerKey);
|
|
38
|
+
const startIdx = result.indexOf(start);
|
|
39
|
+
const endIdx = result.indexOf(end);
|
|
40
|
+
|
|
41
|
+
if (startIdx !== -1 && endIdx !== -1) {
|
|
42
|
+
return result.slice(0, startIdx) + block + result.slice(endIdx + end.length);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
|
|
28
49
|
/**
|
|
29
50
|
* Merge new sections into an existing CLAUDE.md
|
|
30
51
|
* Wraps each source block in OMC markers to allow idempotent updates
|
|
31
52
|
*/
|
|
32
|
-
function mergeIntoExisting(existing, sections) {
|
|
53
|
+
function mergeIntoExisting(existing, sections, options = {}) {
|
|
54
|
+
const markerNamespace = options.markerNamespace || 'claude-md';
|
|
33
55
|
let result = existing;
|
|
34
56
|
|
|
35
57
|
for (const { sourceName, content } of sections) {
|
|
36
|
-
const
|
|
37
|
-
const
|
|
58
|
+
const markerKey = `${markerNamespace}:${sourceName}`;
|
|
59
|
+
const { start: startMarker, end: endMarker } = getMarkers(markerKey);
|
|
38
60
|
const block = `${startMarker}\n${content.trimEnd()}\n${endMarker}`;
|
|
61
|
+
const legacyMarkerKeys = options.legacyMarkerKeys
|
|
62
|
+
? options.legacyMarkerKeys(sourceName)
|
|
63
|
+
: [sourceName];
|
|
64
|
+
const replaced = replaceFirstMatchingBlock(result, [markerKey, ...legacyMarkerKeys], block);
|
|
39
65
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
if (startIdx !== -1 && endIdx !== -1) {
|
|
44
|
-
// Replace existing block
|
|
45
|
-
result = result.slice(0, startIdx) + block + result.slice(endIdx + endMarker.length);
|
|
46
|
-
} else {
|
|
47
|
-
// Append new block
|
|
48
|
-
result = result.trimEnd() + '\n\n' + block + '\n';
|
|
66
|
+
if (replaced !== null) {
|
|
67
|
+
result = replaced;
|
|
68
|
+
continue;
|
|
49
69
|
}
|
|
70
|
+
|
|
71
|
+
// Append new block
|
|
72
|
+
result = result.trimEnd() + '\n\n' + block + '\n';
|
|
50
73
|
}
|
|
51
74
|
|
|
52
75
|
return result;
|
|
@@ -7,5 +7,16 @@
|
|
|
7
7
|
{ "name": "oh-my-claudecode", "priority": 2 },
|
|
8
8
|
{ "name": "superpowers", "priority": 3 }
|
|
9
9
|
],
|
|
10
|
-
"preferences": {}
|
|
10
|
+
"preferences": {},
|
|
11
|
+
"exclude": {
|
|
12
|
+
"skills": [
|
|
13
|
+
"ask",
|
|
14
|
+
"ccg",
|
|
15
|
+
"multi-model-research",
|
|
16
|
+
"test-gen",
|
|
17
|
+
"release",
|
|
18
|
+
"omc-teams",
|
|
19
|
+
"using-superpowers"
|
|
20
|
+
]
|
|
21
|
+
}
|
|
11
22
|
}
|
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: Debug why a Claude Code skill isn't triggering when expected
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
# Skill Debugger
|
|
6
|
-
|
|
7
|
-
[SKILL DEBUG MODE ACTIVATED]
|
|
8
|
-
|
|
9
|
-
## Objective
|
|
10
|
-
|
|
11
|
-
Systematically diagnose why a skill isn't triggering as expected. Identify root causes and provide actionable fixes.
|
|
12
|
-
|
|
13
|
-
## Debugging Workflow
|
|
14
|
-
|
|
15
|
-
### Step 1: Identify Target Skill
|
|
16
|
-
|
|
17
|
-
Ask the user which skill isn't working, or infer from context. Then verify it exists:
|
|
18
|
-
|
|
19
|
-
```bash
|
|
20
|
-
# Check plugin skills
|
|
21
|
-
ls ~/.claude/plugins/cache/omc/oh-my-claudecode/*/skills/<skill-name>/ 2>/dev/null
|
|
22
|
-
|
|
23
|
-
# Check global skills
|
|
24
|
-
ls ~/.claude/skills/<skill-name>/ 2>/dev/null
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
### Step 2: Validate SKILL.md
|
|
28
|
-
|
|
29
|
-
Use the `Read` tool to read the target skill's `SKILL.md` and check:
|
|
30
|
-
|
|
31
|
-
- [ ] File exists and is readable
|
|
32
|
-
- [ ] YAML frontmatter has `---` delimiters
|
|
33
|
-
- [ ] `name:` field matches folder name
|
|
34
|
-
- [ ] `description:` is 50-150 characters, specific, not vague
|
|
35
|
-
- [ ] No vague words ("helps", "assists", "various")
|
|
36
|
-
|
|
37
|
-
### Step 3: Analyze Description Quality
|
|
38
|
-
|
|
39
|
-
Compare the skill description against what the user asked. Check:
|
|
40
|
-
|
|
41
|
-
- Does the description contain keywords the user would naturally say?
|
|
42
|
-
- Is there a `<Use_When>` or "When to Use" section?
|
|
43
|
-
- Are there at least 3 usage examples?
|
|
44
|
-
|
|
45
|
-
### Step 4: Check for Conflicts
|
|
46
|
-
|
|
47
|
-
Scan all installed skills for overlapping descriptions:
|
|
48
|
-
|
|
49
|
-
```bash
|
|
50
|
-
# List all skill descriptions
|
|
51
|
-
for dir in ~/.claude/plugins/cache/omc/oh-my-claudecode/*/skills/*/; do
|
|
52
|
-
if [ -f "$dir/SKILL.md" ]; then
|
|
53
|
-
echo "=== $(basename $dir) ==="
|
|
54
|
-
head -5 "$dir/SKILL.md"
|
|
55
|
-
echo
|
|
56
|
-
fi
|
|
57
|
-
done
|
|
58
|
-
```
|
|
59
|
-
|
|
60
|
-
Look for skills with similar keywords or overlapping use cases.
|
|
61
|
-
|
|
62
|
-
### Step 5: Check Command Registration
|
|
63
|
-
|
|
64
|
-
Verify if the skill has a corresponding slash command:
|
|
65
|
-
|
|
66
|
-
```bash
|
|
67
|
-
ls ~/.claude/plugins/cache/omc/oh-my-claudecode/*/commands/<skill-name>.md 2>/dev/null
|
|
68
|
-
```
|
|
69
|
-
|
|
70
|
-
If no command exists, the skill relies purely on semantic matching.
|
|
71
|
-
|
|
72
|
-
## Diagnosis Report Format
|
|
73
|
-
|
|
74
|
-
```
|
|
75
|
-
## Skill Debug Report
|
|
76
|
-
|
|
77
|
-
Skill: <name>
|
|
78
|
-
Path: <location>
|
|
79
|
-
Status: OK / NOT TRIGGERING / CONFLICT
|
|
80
|
-
|
|
81
|
-
### Issues Found
|
|
82
|
-
| Priority | Issue | Fix |
|
|
83
|
-
|----------|-------|-----|
|
|
84
|
-
| CRITICAL | ... | ... |
|
|
85
|
-
| HIGH | ... | ... |
|
|
86
|
-
| MEDIUM | ... | ... |
|
|
87
|
-
|
|
88
|
-
### Recommendations
|
|
89
|
-
1. [Specific fix with before/after examples]
|
|
90
|
-
2. [...]
|
|
91
|
-
```
|
|
92
|
-
|
|
93
|
-
## Common Fixes
|
|
94
|
-
|
|
95
|
-
| Problem | Fix |
|
|
96
|
-
|---------|-----|
|
|
97
|
-
| Description too vague | Add specific keywords and use cases |
|
|
98
|
-
| No trigger keywords | Add words users would naturally say |
|
|
99
|
-
| Wrong skill triggers | Differentiate descriptions between conflicting skills |
|
|
100
|
-
| Skill not found | Check installation path and folder name |
|
|
101
|
-
| No slash command | Create `commands/<name>.md` for explicit triggering |
|