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
package/src/cli/artifact.js
CHANGED
|
@@ -11,6 +11,19 @@ const { loadAgentsFromSource } = require('../merge/agent-merger');
|
|
|
11
11
|
const { loadCommandsFromSource } = require('../merge/command-merger');
|
|
12
12
|
const { loadHookFilesFromSource } = require('../merge/hook-merger');
|
|
13
13
|
const { loadFilesFromSource } = require('../merge/file-merger');
|
|
14
|
+
const { loadClaudeMd } = require('../merge/claude-md-merger');
|
|
15
|
+
|
|
16
|
+
function loadSectionDocumentFromSource(sourceDir) {
|
|
17
|
+
const content = loadClaudeMd(sourceDir);
|
|
18
|
+
if (!content) return [];
|
|
19
|
+
return [{
|
|
20
|
+
name: 'CLAUDE.md',
|
|
21
|
+
path: sourceDir,
|
|
22
|
+
metadata: {
|
|
23
|
+
description: `${content.length} chars of prompt guidelines`,
|
|
24
|
+
},
|
|
25
|
+
}];
|
|
26
|
+
}
|
|
14
27
|
|
|
15
28
|
function getLoader(artifactType) {
|
|
16
29
|
switch (artifactType) {
|
|
@@ -18,6 +31,8 @@ function getLoader(artifactType) {
|
|
|
18
31
|
case 'agents': return loadAgentsFromSource;
|
|
19
32
|
case 'commands': return loadCommandsFromSource;
|
|
20
33
|
case 'hooks': return loadHookFilesFromSource;
|
|
34
|
+
case 'guidelines': return loadSectionDocumentFromSource;
|
|
35
|
+
case 'claude-md': return loadSectionDocumentFromSource;
|
|
21
36
|
case 'hud': return loadFilesFromSource;
|
|
22
37
|
default: return null;
|
|
23
38
|
}
|
|
@@ -42,6 +57,11 @@ function loadSourcesForType(artifactType, root) {
|
|
|
42
57
|
sources.push({ name, items });
|
|
43
58
|
}
|
|
44
59
|
}
|
|
60
|
+
|
|
61
|
+
if (sources.length === 0 && artifactType === 'claude-md') {
|
|
62
|
+
return loadSourcesForType('guidelines', root);
|
|
63
|
+
}
|
|
64
|
+
|
|
45
65
|
return sources;
|
|
46
66
|
}
|
|
47
67
|
|
|
@@ -62,6 +82,23 @@ async function artifact(args, flags = {}) {
|
|
|
62
82
|
return;
|
|
63
83
|
}
|
|
64
84
|
|
|
85
|
+
const artifactConfig = ARTIFACT_TYPES[artifactType];
|
|
86
|
+
if (artifactConfig.mergeStrategy === 'section-concat') {
|
|
87
|
+
const total = sources.reduce((sum, source) => sum + source.items.length, 0);
|
|
88
|
+
console.log(`${artifactConfig.label} (${total} installable, additive merge, from ${sources.length} sources):`);
|
|
89
|
+
console.log('');
|
|
90
|
+
|
|
91
|
+
for (const source of sources) {
|
|
92
|
+
console.log(`[${source.name}] (${source.items.length})`);
|
|
93
|
+
for (const item of source.items) {
|
|
94
|
+
const desc = item.metadata?.description || '';
|
|
95
|
+
console.log(` ${item.name}${desc ? ' — ' + desc : ''}`);
|
|
96
|
+
}
|
|
97
|
+
console.log('');
|
|
98
|
+
}
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
|
|
65
102
|
const mergeConfigPath = getMergeConfigPath(root);
|
|
66
103
|
let mergeConfig = { preferences: {} };
|
|
67
104
|
if (fs.existsSync(mergeConfigPath)) {
|
|
@@ -70,9 +107,15 @@ async function artifact(args, flags = {}) {
|
|
|
70
107
|
|
|
71
108
|
const conflicts = detectConflicts(sources);
|
|
72
109
|
const resolutions = resolveConflicts(conflicts, mergeConfig);
|
|
73
|
-
|
|
110
|
+
let merged = applyResolutions(sources, resolutions);
|
|
74
111
|
|
|
75
|
-
|
|
112
|
+
// Apply exclude list
|
|
113
|
+
const excludeList = (mergeConfig.exclude && mergeConfig.exclude[artifactType]) || [];
|
|
114
|
+
const excludeSet = new Set(excludeList);
|
|
115
|
+
const excluded = merged.filter(item => excludeSet.has(item.name));
|
|
116
|
+
merged = merged.filter(item => !excludeSet.has(item.name));
|
|
117
|
+
|
|
118
|
+
console.log(`${ARTIFACT_TYPES[artifactType].label} (${merged.length} installable, ${excluded.length} excluded, from ${sources.length} sources):`);
|
|
76
119
|
console.log('');
|
|
77
120
|
|
|
78
121
|
const bySource = {};
|
|
@@ -91,10 +134,21 @@ async function artifact(args, flags = {}) {
|
|
|
91
134
|
}
|
|
92
135
|
console.log('');
|
|
93
136
|
}
|
|
137
|
+
|
|
138
|
+
if (excluded.length > 0) {
|
|
139
|
+
console.log(`[excluded] (${excluded.length})`);
|
|
140
|
+
for (const item of excluded.sort((a, b) => a.name.localeCompare(b.name))) {
|
|
141
|
+
console.log(` ${item.name} (${item.sourceName})`);
|
|
142
|
+
}
|
|
143
|
+
console.log('');
|
|
144
|
+
}
|
|
94
145
|
break;
|
|
95
146
|
}
|
|
96
147
|
|
|
97
148
|
case 'prefer': {
|
|
149
|
+
if (ARTIFACT_TYPES[artifactType].mergeStrategy === 'section-concat') {
|
|
150
|
+
throw new Error(`${artifactType} is merged additively and does not support source preferences.`);
|
|
151
|
+
}
|
|
98
152
|
const name = args[1];
|
|
99
153
|
const source = args[2];
|
|
100
154
|
if (!name || !source) {
|
|
@@ -112,6 +166,13 @@ async function artifact(args, flags = {}) {
|
|
|
112
166
|
}
|
|
113
167
|
|
|
114
168
|
case 'conflicts': {
|
|
169
|
+
if (ARTIFACT_TYPES[artifactType].mergeStrategy === 'section-concat') {
|
|
170
|
+
console.log(`${ARTIFACT_TYPES[artifactType].label} Conflict Report`);
|
|
171
|
+
console.log('='.repeat(40));
|
|
172
|
+
console.log('Section-concat artifacts are merged additively; no conflicts to resolve.');
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
|
|
115
176
|
const sources = loadSourcesForType(artifactType, root);
|
|
116
177
|
if (sources.length < 2) {
|
|
117
178
|
console.log(`Need at least 2 sources for ${artifactType}. Run: omc-manage source sync`);
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/* eslint-disable no-console */
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const { optimizeGuidelines } = require('../guidelines/optimizer');
|
|
4
|
+
const { applyGuidelineResult } = require('../guidelines/apply');
|
|
5
|
+
|
|
6
|
+
async function guidelines(args, flags = {}) {
|
|
7
|
+
const cmd = args[0] || 'help';
|
|
8
|
+
|
|
9
|
+
switch (cmd) {
|
|
10
|
+
case 'optimize': {
|
|
11
|
+
const selectedSources = args.slice(1);
|
|
12
|
+
const result = await optimizeGuidelines({
|
|
13
|
+
sources: selectedSources,
|
|
14
|
+
outputDir: flags.outputDir,
|
|
15
|
+
dryRun: flags.dryRun,
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
const { summary } = result;
|
|
19
|
+
console.log('Guidelines Optimization');
|
|
20
|
+
console.log('=======================');
|
|
21
|
+
console.log(`Sources: ${summary.sourceCount}`);
|
|
22
|
+
console.log(`Sections: ${summary.sectionCount}`);
|
|
23
|
+
console.log(`Target runtime file: ${summary.outputPath}`);
|
|
24
|
+
|
|
25
|
+
if (flags.dryRun) {
|
|
26
|
+
console.log('');
|
|
27
|
+
console.log('[dry-run] Would write maintainer artifacts to:');
|
|
28
|
+
console.log(` latest: ${summary.latestDir}`);
|
|
29
|
+
console.log(` run: ${summary.runDir}`);
|
|
30
|
+
} else {
|
|
31
|
+
console.log('');
|
|
32
|
+
console.log('Wrote maintainer artifacts:');
|
|
33
|
+
console.log(` latest: ${summary.latestDir}`);
|
|
34
|
+
console.log(` run: ${summary.runDir}`);
|
|
35
|
+
console.log('');
|
|
36
|
+
console.log('Next step for Claude Code CLI or Codex:');
|
|
37
|
+
console.log(` read ${path.join(summary.latestDir, 'next-steps.md')}`);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
break;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
case 'apply': {
|
|
44
|
+
const result = await applyGuidelineResult({
|
|
45
|
+
resultFile: flags.resultFile || args[1],
|
|
46
|
+
outputDir: flags.outputDir,
|
|
47
|
+
dryRun: flags.dryRun,
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
console.log('Guidelines Apply');
|
|
51
|
+
console.log('================');
|
|
52
|
+
console.log(`Result file: ${result.resultFile}`);
|
|
53
|
+
console.log(`Runtime file: ${result.runtimePath}`);
|
|
54
|
+
|
|
55
|
+
if (flags.dryRun) {
|
|
56
|
+
console.log('');
|
|
57
|
+
console.log('[dry-run] Would write:');
|
|
58
|
+
console.log(` ${path.join(result.latestDir, 'result.json')}`);
|
|
59
|
+
console.log(` ${path.join(result.latestDir, 'decision-log.md')}`);
|
|
60
|
+
console.log(` ${result.runtimePath}`);
|
|
61
|
+
} else {
|
|
62
|
+
console.log('');
|
|
63
|
+
console.log('Wrote:');
|
|
64
|
+
console.log(` ${path.join(result.latestDir, 'result.json')}`);
|
|
65
|
+
console.log(` ${path.join(result.latestDir, 'decision-log.md')}`);
|
|
66
|
+
console.log(` ${result.runtimePath}`);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
break;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
case 'help':
|
|
73
|
+
default:
|
|
74
|
+
console.log('Usage:');
|
|
75
|
+
console.log(' omc-manage guidelines optimize [source...] [--output-dir <dir>] [--dry-run]');
|
|
76
|
+
console.log(' omc-manage guidelines apply --result-file <path> [--output-dir <dir>] [--dry-run]');
|
|
77
|
+
console.log('');
|
|
78
|
+
console.log('Build or apply maintainer-only guideline optimization artifacts.');
|
|
79
|
+
console.log('The optimizer skill is repository-only and is not installed into user Claude Code configs.');
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
module.exports = { guidelines };
|
package/src/cli/index.js
CHANGED
|
@@ -6,6 +6,7 @@ const COMMANDS = {
|
|
|
6
6
|
source: () => require('./source'),
|
|
7
7
|
skill: () => require('./skill'),
|
|
8
8
|
artifact: () => require('./artifact'),
|
|
9
|
+
guidelines: () => require('./guidelines'),
|
|
9
10
|
};
|
|
10
11
|
|
|
11
12
|
function showHelp() {
|
|
@@ -19,13 +20,16 @@ function showHelp() {
|
|
|
19
20
|
console.log(' doctor Health checks for all artifact types');
|
|
20
21
|
console.log(' source list|add|remove|sync|status — manage sources');
|
|
21
22
|
console.log(' artifact list|prefer|conflicts [--type <type>] — manage artifacts');
|
|
23
|
+
console.log(' guidelines optimize [source...] [--output-dir <dir>] [--dry-run]');
|
|
24
|
+
console.log(' guidelines apply --result-file <path> [--output-dir <dir>] [--dry-run]');
|
|
25
|
+
console.log(' Build or apply maintainer guideline optimization artifacts');
|
|
22
26
|
console.log(' skill list|prefer|conflicts — alias for artifact --type skills');
|
|
23
27
|
console.log(' evaluate [name] — quality score (Anthropic-aligned)');
|
|
24
28
|
console.log(' compare [--threshold N] — cross-source overlap analysis');
|
|
25
29
|
console.log(' recommend [--apply] — preference recommendations');
|
|
26
30
|
console.log(' help Show this help');
|
|
27
31
|
console.log('');
|
|
28
|
-
console.log('Artifact types: skills, agents, hooks, commands, claude-md, settings, hud');
|
|
32
|
+
console.log('Artifact types: skills, agents, hooks, commands, guidelines, claude-md, settings, hud');
|
|
29
33
|
}
|
|
30
34
|
|
|
31
35
|
async function main(argv) {
|
|
@@ -71,6 +75,14 @@ async function main(argv) {
|
|
|
71
75
|
else if (arg === '--ref' && args[i + 1]) flags.ref = args[++i];
|
|
72
76
|
else if (arg === '--priority' && args[i + 1]) flags.priority = parseInt(args[++i], 10);
|
|
73
77
|
else if (arg === '--artifacts' && args[i + 1]) flags.artifacts = args[++i].split(',');
|
|
78
|
+
else if (arg === '--mapping' && args[i + 1]) flags.mapping = args[++i];
|
|
79
|
+
else if (arg.startsWith('--mapping=')) flags.mapping = arg.split('=')[1];
|
|
80
|
+
else if (arg === '--role' && args[i + 1]) flags.role = args[++i];
|
|
81
|
+
else if (arg.startsWith('--role=')) flags.role = arg.split('=')[1];
|
|
82
|
+
else if (arg === '--output-dir' && args[i + 1]) flags.outputDir = args[++i];
|
|
83
|
+
else if (arg.startsWith('--output-dir=')) flags.outputDir = arg.split('=')[1];
|
|
84
|
+
else if (arg === '--result-file' && args[i + 1]) flags.resultFile = args[++i];
|
|
85
|
+
else if (arg.startsWith('--result-file=')) flags.resultFile = arg.split('=')[1];
|
|
74
86
|
else if (arg === '--apply') flags.apply = true;
|
|
75
87
|
else if (arg === '--threshold' && args[i + 1]) flags.threshold = args[++i];
|
|
76
88
|
else if (arg.startsWith('--threshold=')) flags.threshold = arg.split('=')[1];
|
package/src/cli/setup.js
CHANGED
|
@@ -49,6 +49,29 @@ function getLoader(artifactType) {
|
|
|
49
49
|
}
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
+
function collectSourcesForType(artifactType, orderedSources, root) {
|
|
53
|
+
const sourcesForType = [];
|
|
54
|
+
|
|
55
|
+
for (const [name, src] of orderedSources) {
|
|
56
|
+
// Skip reference-only sources (e.g. anthropic-skills) — they provide
|
|
57
|
+
// evaluation standards, not installable artifacts.
|
|
58
|
+
if (src.role === 'reference') continue;
|
|
59
|
+
const declaredArtifacts = src.artifacts || [];
|
|
60
|
+
if (!declaredArtifacts.includes(artifactType)) continue;
|
|
61
|
+
|
|
62
|
+
const dir = getSourceArtifactDir(name, artifactType, root);
|
|
63
|
+
if (fs.existsSync(dir)) {
|
|
64
|
+
sourcesForType.push({ name, dir, priority: src.priority });
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (sourcesForType.length === 0 && artifactType === 'claude-md') {
|
|
69
|
+
return collectSourcesForType('guidelines', orderedSources, root);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return sourcesForType;
|
|
73
|
+
}
|
|
74
|
+
|
|
52
75
|
async function installNameBasedArtifacts(artifactType, sources, mergeConfig, installTarget, flags) {
|
|
53
76
|
const loader = getLoader(artifactType);
|
|
54
77
|
if (!loader) return { count: 0, total: 0 };
|
|
@@ -65,7 +88,19 @@ async function installNameBasedArtifacts(artifactType, sources, mergeConfig, ins
|
|
|
65
88
|
|
|
66
89
|
const conflicts = detectConflicts(loaded);
|
|
67
90
|
const resolutions = resolveConflicts(conflicts, mergeConfig);
|
|
68
|
-
|
|
91
|
+
let merged = applyResolutions(loaded, resolutions);
|
|
92
|
+
|
|
93
|
+
// Apply exclude list
|
|
94
|
+
const excludeList = (mergeConfig.exclude && mergeConfig.exclude[artifactType]) || [];
|
|
95
|
+
if (excludeList.length > 0) {
|
|
96
|
+
const excludeSet = new Set(excludeList);
|
|
97
|
+
const before = merged.length;
|
|
98
|
+
merged = merged.filter(item => !excludeSet.has(item.name));
|
|
99
|
+
const excluded = before - merged.length;
|
|
100
|
+
if (excluded > 0) {
|
|
101
|
+
console.log(` excluded ${excluded} items: ${excludeList.filter(n => merged.every(m => m.name !== n)).join(', ')}`);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
69
104
|
|
|
70
105
|
if (flags.dryRun) {
|
|
71
106
|
for (const item of merged.sort((a, b) => a.name.localeCompare(b.name))) {
|
|
@@ -125,7 +160,7 @@ async function installHooks(sources, installTarget, flags) {
|
|
|
125
160
|
return result;
|
|
126
161
|
}
|
|
127
162
|
|
|
128
|
-
async function
|
|
163
|
+
async function installSectionDocument(artifactType, sources, installTarget, flags) {
|
|
129
164
|
const sections = [];
|
|
130
165
|
// Collect in reverse priority order (lowest priority first)
|
|
131
166
|
const sorted = [...sources].reverse();
|
|
@@ -147,7 +182,15 @@ async function installClaudeMd(sources, installTarget, flags) {
|
|
|
147
182
|
let finalContent;
|
|
148
183
|
if (fs.existsSync(installTarget)) {
|
|
149
184
|
const existing = fs.readFileSync(installTarget, 'utf8');
|
|
150
|
-
finalContent = mergeIntoExisting(existing, sections
|
|
185
|
+
finalContent = mergeIntoExisting(existing, sections, {
|
|
186
|
+
markerNamespace: artifactType,
|
|
187
|
+
legacyMarkerKeys: (sourceName) => {
|
|
188
|
+
if (artifactType === 'guidelines') {
|
|
189
|
+
return [sourceName, `claude-md:${sourceName}`];
|
|
190
|
+
}
|
|
191
|
+
return [sourceName];
|
|
192
|
+
},
|
|
193
|
+
});
|
|
151
194
|
} else {
|
|
152
195
|
finalContent = assembleSections(sections);
|
|
153
196
|
}
|
|
@@ -226,20 +269,7 @@ async function setup(args, flags = {}) {
|
|
|
226
269
|
continue;
|
|
227
270
|
}
|
|
228
271
|
|
|
229
|
-
|
|
230
|
-
const sourcesForType = [];
|
|
231
|
-
for (const [name, src] of orderedSources) {
|
|
232
|
-
// Skip reference-only sources (e.g. anthropic-skills) — they provide
|
|
233
|
-
// evaluation standards, not installable artifacts.
|
|
234
|
-
if (src.role === 'reference') continue;
|
|
235
|
-
const declaredArtifacts = src.artifacts || [];
|
|
236
|
-
if (!declaredArtifacts.includes(artifactType)) continue;
|
|
237
|
-
|
|
238
|
-
const dir = getSourceArtifactDir(name, artifactType, root);
|
|
239
|
-
if (fs.existsSync(dir)) {
|
|
240
|
-
sourcesForType.push({ name, dir, priority: src.priority });
|
|
241
|
-
}
|
|
242
|
-
}
|
|
272
|
+
const sourcesForType = collectSourcesForType(artifactType, orderedSources, root);
|
|
243
273
|
|
|
244
274
|
const installTarget = (artifactType === 'skills' && scope === 'project')
|
|
245
275
|
? path.join(process.cwd(), '.claude', 'skills')
|
|
@@ -261,7 +291,7 @@ async function setup(args, flags = {}) {
|
|
|
261
291
|
result = await installHooks(sourcesForType, installTarget, flags);
|
|
262
292
|
break;
|
|
263
293
|
case 'section-concat':
|
|
264
|
-
result = await
|
|
294
|
+
result = await installSectionDocument(artifactType, sourcesForType, installTarget, flags);
|
|
265
295
|
break;
|
|
266
296
|
case 'deep-merge':
|
|
267
297
|
result = await installSettings(sourcesForType, installTarget, flags);
|
package/src/cli/source.js
CHANGED
|
@@ -20,6 +20,26 @@ async function copyDirRecursive(src, dest) {
|
|
|
20
20
|
}
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
+
function parseMappingFlag(mappingFlag) {
|
|
24
|
+
if (!mappingFlag) return {};
|
|
25
|
+
|
|
26
|
+
const entries = mappingFlag
|
|
27
|
+
.split(',')
|
|
28
|
+
.map(part => part.trim())
|
|
29
|
+
.filter(Boolean);
|
|
30
|
+
|
|
31
|
+
const mapping = {};
|
|
32
|
+
for (const entry of entries) {
|
|
33
|
+
const [artifactType, ...rest] = entry.split('=');
|
|
34
|
+
const target = rest.join('=').trim();
|
|
35
|
+
if (!artifactType || !target) {
|
|
36
|
+
throw new Error(`Invalid mapping entry "${entry}". Use artifact=path.`);
|
|
37
|
+
}
|
|
38
|
+
mapping[artifactType.trim()] = target;
|
|
39
|
+
}
|
|
40
|
+
return mapping;
|
|
41
|
+
}
|
|
42
|
+
|
|
23
43
|
async function syncRemoteSource(sourceName, sourceConfig, root) {
|
|
24
44
|
console.log(` Syncing ${sourceName} from ${sourceConfig.remote} (${sourceConfig.ref})...`);
|
|
25
45
|
|
|
@@ -85,6 +105,15 @@ async function source(args, flags = {}) {
|
|
|
85
105
|
console.log(`${marker} ${name} (priority ${src.priority})`);
|
|
86
106
|
console.log(` ${location}`);
|
|
87
107
|
console.log(` artifacts: ${(src.artifacts || []).join(', ')}`);
|
|
108
|
+
if (src.role) {
|
|
109
|
+
console.log(` role: ${src.role}`);
|
|
110
|
+
}
|
|
111
|
+
if (src.mapping && Object.keys(src.mapping).length > 0) {
|
|
112
|
+
const mapping = Object.entries(src.mapping)
|
|
113
|
+
.map(([artifact, target]) => `${artifact}=${target}`)
|
|
114
|
+
.join(', ');
|
|
115
|
+
console.log(` mapping: ${mapping}`);
|
|
116
|
+
}
|
|
88
117
|
console.log('');
|
|
89
118
|
}
|
|
90
119
|
break;
|
|
@@ -94,12 +123,14 @@ async function source(args, flags = {}) {
|
|
|
94
123
|
const name = args[1];
|
|
95
124
|
const remote = args[2];
|
|
96
125
|
if (!name || !remote) {
|
|
97
|
-
throw new Error('Usage: omc-manage source add <name> <remote-url> [--ref main] [--priority N] [--artifacts skills,agents]');
|
|
126
|
+
throw new Error('Usage: omc-manage source add <name> <remote-url> [--ref main] [--priority N] [--artifacts skills,agents,guidelines] [--mapping guidelines=CLAUDE.md] [--role guidelines]');
|
|
98
127
|
}
|
|
99
128
|
await addSource(name, remote, {
|
|
100
129
|
ref: flags.ref,
|
|
101
130
|
priority: flags.priority,
|
|
102
131
|
artifacts: flags.artifacts,
|
|
132
|
+
mapping: parseMappingFlag(flags.mapping),
|
|
133
|
+
role: flags.role,
|
|
103
134
|
});
|
|
104
135
|
console.log(`Source "${name}" added.`);
|
|
105
136
|
console.log(`Run "omc-manage source sync ${name}" to fetch artifacts.`);
|
|
@@ -167,6 +198,9 @@ async function source(args, flags = {}) {
|
|
|
167
198
|
|
|
168
199
|
for (const [name, src] of Object.entries(config.sources)) {
|
|
169
200
|
console.log(`[${name}] (priority ${src.priority})`);
|
|
201
|
+
if (src.role) {
|
|
202
|
+
console.log(` role: ${src.role}`);
|
|
203
|
+
}
|
|
170
204
|
const artifacts = src.artifacts || [];
|
|
171
205
|
for (const type of artifacts) {
|
|
172
206
|
const dir = getSourceArtifactDir(name, type, root);
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
const path = require('path');
|
|
2
2
|
const os = require('os');
|
|
3
3
|
|
|
4
|
+
const CLAUDE_MD_TARGET = path.join(os.homedir(), '.claude', 'CLAUDE.md');
|
|
5
|
+
|
|
4
6
|
const ARTIFACT_TYPES = {
|
|
5
7
|
skills: {
|
|
6
8
|
label: 'Skills',
|
|
@@ -35,9 +37,17 @@ const ARTIFACT_TYPES = {
|
|
|
35
37
|
metadataFile: null,
|
|
36
38
|
mergeStrategy: 'name-based',
|
|
37
39
|
},
|
|
40
|
+
guidelines: {
|
|
41
|
+
label: 'Guidelines',
|
|
42
|
+
installTarget: CLAUDE_MD_TARGET,
|
|
43
|
+
sourceSubdir: 'guidelines',
|
|
44
|
+
format: 'single-file',
|
|
45
|
+
metadataFile: null,
|
|
46
|
+
mergeStrategy: 'section-concat',
|
|
47
|
+
},
|
|
38
48
|
'claude-md': {
|
|
39
|
-
label: 'CLAUDE.md',
|
|
40
|
-
installTarget:
|
|
49
|
+
label: 'CLAUDE.md (legacy)',
|
|
50
|
+
installTarget: CLAUDE_MD_TARGET,
|
|
41
51
|
sourceSubdir: 'claude-md',
|
|
42
52
|
format: 'single-file',
|
|
43
53
|
metadataFile: null,
|
package/src/config/paths.js
CHANGED
|
@@ -34,6 +34,9 @@ function isDistributionMode() {
|
|
|
34
34
|
function getSourceArtifactDir(sourceName, artifactType, root) {
|
|
35
35
|
root = root || getProjectRoot();
|
|
36
36
|
|
|
37
|
+
const legacyArtifactType = artifactType === 'guidelines' ? 'claude-md' : null;
|
|
38
|
+
const modernArtifactType = artifactType === 'claude-md' ? 'guidelines' : null;
|
|
39
|
+
|
|
37
40
|
if (isDistributionMode()) {
|
|
38
41
|
if (sourceName === 'local') {
|
|
39
42
|
// Check user-customized local first, then fall back to bundled .local/
|
|
@@ -41,21 +44,109 @@ function getSourceArtifactDir(sourceName, artifactType, root) {
|
|
|
41
44
|
if (fs.existsSync(userLocal)) {
|
|
42
45
|
return userLocal;
|
|
43
46
|
}
|
|
44
|
-
|
|
47
|
+
if (legacyArtifactType) {
|
|
48
|
+
const userLegacy = path.join(USER_DATA_DIR, 'local', legacyArtifactType);
|
|
49
|
+
if (fs.existsSync(userLegacy)) {
|
|
50
|
+
return userLegacy;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
if (modernArtifactType) {
|
|
54
|
+
const userModern = path.join(USER_DATA_DIR, 'local', modernArtifactType);
|
|
55
|
+
if (fs.existsSync(userModern)) {
|
|
56
|
+
return userModern;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
const bundledLocal = path.join(root, '.local', artifactType);
|
|
60
|
+
if (fs.existsSync(bundledLocal)) {
|
|
61
|
+
return bundledLocal;
|
|
62
|
+
}
|
|
63
|
+
if (legacyArtifactType) {
|
|
64
|
+
const bundledLegacy = path.join(root, '.local', legacyArtifactType);
|
|
65
|
+
if (fs.existsSync(bundledLegacy)) {
|
|
66
|
+
return bundledLegacy;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
if (modernArtifactType) {
|
|
70
|
+
const bundledModern = path.join(root, '.local', modernArtifactType);
|
|
71
|
+
if (fs.existsSync(bundledModern)) {
|
|
72
|
+
return bundledModern;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return bundledLocal;
|
|
45
76
|
}
|
|
46
77
|
// Check user-synced first, then fall back to bundled
|
|
47
78
|
const synced = path.join(USER_DATA_DIR, 'upstream', sourceName, artifactType);
|
|
48
79
|
if (fs.existsSync(synced)) {
|
|
49
80
|
return synced;
|
|
50
81
|
}
|
|
51
|
-
|
|
82
|
+
if (legacyArtifactType) {
|
|
83
|
+
const syncedLegacy = path.join(USER_DATA_DIR, 'upstream', sourceName, legacyArtifactType);
|
|
84
|
+
if (fs.existsSync(syncedLegacy)) {
|
|
85
|
+
return syncedLegacy;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
if (modernArtifactType) {
|
|
89
|
+
const syncedModern = path.join(USER_DATA_DIR, 'upstream', sourceName, modernArtifactType);
|
|
90
|
+
if (fs.existsSync(syncedModern)) {
|
|
91
|
+
return syncedModern;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
const bundled = path.join(root, 'bundled', 'upstream', sourceName, artifactType);
|
|
95
|
+
if (fs.existsSync(bundled)) {
|
|
96
|
+
return bundled;
|
|
97
|
+
}
|
|
98
|
+
if (legacyArtifactType) {
|
|
99
|
+
const bundledLegacy = path.join(root, 'bundled', 'upstream', sourceName, legacyArtifactType);
|
|
100
|
+
if (fs.existsSync(bundledLegacy)) {
|
|
101
|
+
return bundledLegacy;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
if (modernArtifactType) {
|
|
105
|
+
const bundledModern = path.join(root, 'bundled', 'upstream', sourceName, modernArtifactType);
|
|
106
|
+
if (fs.existsSync(bundledModern)) {
|
|
107
|
+
return bundledModern;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
return bundled;
|
|
52
111
|
}
|
|
53
112
|
|
|
54
113
|
// Dev mode
|
|
55
114
|
if (sourceName === 'local') {
|
|
56
|
-
|
|
115
|
+
const localDir = path.join(root, '.local', artifactType);
|
|
116
|
+
if (fs.existsSync(localDir)) {
|
|
117
|
+
return localDir;
|
|
118
|
+
}
|
|
119
|
+
if (legacyArtifactType) {
|
|
120
|
+
const legacyDir = path.join(root, '.local', legacyArtifactType);
|
|
121
|
+
if (fs.existsSync(legacyDir)) {
|
|
122
|
+
return legacyDir;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
if (modernArtifactType) {
|
|
126
|
+
const modernDir = path.join(root, '.local', modernArtifactType);
|
|
127
|
+
if (fs.existsSync(modernDir)) {
|
|
128
|
+
return modernDir;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
return localDir;
|
|
57
132
|
}
|
|
58
|
-
|
|
133
|
+
const upstreamDir = path.join(root, '.upstream', sourceName, artifactType);
|
|
134
|
+
if (fs.existsSync(upstreamDir)) {
|
|
135
|
+
return upstreamDir;
|
|
136
|
+
}
|
|
137
|
+
if (legacyArtifactType) {
|
|
138
|
+
const legacyDir = path.join(root, '.upstream', sourceName, legacyArtifactType);
|
|
139
|
+
if (fs.existsSync(legacyDir)) {
|
|
140
|
+
return legacyDir;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
if (modernArtifactType) {
|
|
144
|
+
const modernDir = path.join(root, '.upstream', sourceName, modernArtifactType);
|
|
145
|
+
if (fs.existsSync(modernDir)) {
|
|
146
|
+
return modernDir;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
return upstreamDir;
|
|
59
150
|
}
|
|
60
151
|
|
|
61
152
|
/**
|
package/src/config/sources.js
CHANGED
|
@@ -13,7 +13,7 @@ function getDefaultConfig() {
|
|
|
13
13
|
local: {
|
|
14
14
|
path: '.local',
|
|
15
15
|
priority: 1,
|
|
16
|
-
artifacts: ['skills', 'agents', 'hooks', 'commands', '
|
|
16
|
+
artifacts: ['skills', 'agents', 'hooks', 'commands', 'guidelines', 'settings', 'hud'],
|
|
17
17
|
},
|
|
18
18
|
'oh-my-claudecode': {
|
|
19
19
|
remote: 'https://github.com/Yeachan-Heo/oh-my-claudecode.git',
|
|
@@ -56,14 +56,36 @@ function getDefaultConfig() {
|
|
|
56
56
|
};
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
+
function dedupeArtifacts(artifacts) {
|
|
60
|
+
return [...new Set((artifacts || []).filter(Boolean))];
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function normalizeConfig(config) {
|
|
64
|
+
const normalized = config || getDefaultConfig();
|
|
65
|
+
normalized.sources = normalized.sources || {};
|
|
66
|
+
|
|
67
|
+
for (const [name, source] of Object.entries(normalized.sources)) {
|
|
68
|
+
source.artifacts = dedupeArtifacts(source.artifacts);
|
|
69
|
+
|
|
70
|
+
// Migrate local prompt guidance from legacy claude-md to guidelines.
|
|
71
|
+
if (name === 'local' && source.artifacts.includes('claude-md') && !source.artifacts.includes('guidelines')) {
|
|
72
|
+
source.artifacts = source.artifacts.map((artifact) => (
|
|
73
|
+
artifact === 'claude-md' ? 'guidelines' : artifact
|
|
74
|
+
));
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return normalized;
|
|
79
|
+
}
|
|
80
|
+
|
|
59
81
|
function readConfig() {
|
|
60
82
|
if (!fs.existsSync(CONFIG_PATH)) {
|
|
61
|
-
return getDefaultConfig();
|
|
83
|
+
return normalizeConfig(getDefaultConfig());
|
|
62
84
|
}
|
|
63
85
|
try {
|
|
64
|
-
return JSON.parse(fs.readFileSync(CONFIG_PATH, 'utf8'));
|
|
86
|
+
return normalizeConfig(JSON.parse(fs.readFileSync(CONFIG_PATH, 'utf8')));
|
|
65
87
|
} catch {
|
|
66
|
-
return getDefaultConfig();
|
|
88
|
+
return normalizeConfig(getDefaultConfig());
|
|
67
89
|
}
|
|
68
90
|
}
|
|
69
91
|
|
|
@@ -71,7 +93,7 @@ async function writeConfig(config) {
|
|
|
71
93
|
if (!fs.existsSync(CONFIG_DIR)) {
|
|
72
94
|
await fsp.mkdir(CONFIG_DIR, { recursive: true });
|
|
73
95
|
}
|
|
74
|
-
await fsp.writeFile(CONFIG_PATH, JSON.stringify(config, null, 2) + '\n', 'utf8');
|
|
96
|
+
await fsp.writeFile(CONFIG_PATH, JSON.stringify(normalizeConfig(config), null, 2) + '\n', 'utf8');
|
|
75
97
|
}
|
|
76
98
|
|
|
77
99
|
function getActiveSource() {
|
|
@@ -112,6 +134,7 @@ async function addSource(name, remote, options = {}) {
|
|
|
112
134
|
priority: options.priority || Object.keys(config.sources).length + 1,
|
|
113
135
|
artifacts: options.artifacts || ['skills'],
|
|
114
136
|
mapping: options.mapping || {},
|
|
137
|
+
role: options.role,
|
|
115
138
|
};
|
|
116
139
|
await writeConfig(config);
|
|
117
140
|
}
|
|
@@ -136,6 +159,7 @@ module.exports = {
|
|
|
136
159
|
recordSync,
|
|
137
160
|
addSource,
|
|
138
161
|
removeSource,
|
|
162
|
+
normalizeConfig,
|
|
139
163
|
CONFIG_DIR,
|
|
140
164
|
CONFIG_PATH,
|
|
141
165
|
};
|