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.
Files changed (91) hide show
  1. package/.local/guidelines/CLAUDE.md +31 -0
  2. package/README.md +57 -1
  3. package/bundled/manifest.json +2 -2
  4. package/bundled/upstream/oh-my-claudecode/agents/analyst.md +1 -1
  5. package/bundled/upstream/oh-my-claudecode/agents/architect.md +1 -1
  6. package/bundled/upstream/oh-my-claudecode/agents/code-reviewer.md +1 -1
  7. package/bundled/upstream/oh-my-claudecode/agents/code-simplifier.md +1 -1
  8. package/bundled/upstream/oh-my-claudecode/agents/critic.md +1 -1
  9. package/bundled/upstream/oh-my-claudecode/agents/debugger.md +1 -1
  10. package/bundled/upstream/oh-my-claudecode/agents/designer.md +1 -1
  11. package/bundled/upstream/oh-my-claudecode/agents/document-specialist.md +1 -1
  12. package/bundled/upstream/oh-my-claudecode/agents/executor.md +1 -1
  13. package/bundled/upstream/oh-my-claudecode/agents/explore.md +1 -1
  14. package/bundled/upstream/oh-my-claudecode/agents/git-master.md +3 -3
  15. package/bundled/upstream/oh-my-claudecode/agents/planner.md +1 -1
  16. package/bundled/upstream/oh-my-claudecode/agents/qa-tester.md +1 -1
  17. package/bundled/upstream/oh-my-claudecode/agents/scientist.md +1 -1
  18. package/bundled/upstream/oh-my-claudecode/agents/security-reviewer.md +1 -1
  19. package/bundled/upstream/oh-my-claudecode/agents/test-engineer.md +1 -75
  20. package/bundled/upstream/oh-my-claudecode/agents/tracer.md +1 -1
  21. package/bundled/upstream/oh-my-claudecode/agents/verifier.md +1 -1
  22. package/bundled/upstream/oh-my-claudecode/agents/writer.md +1 -1
  23. package/bundled/upstream/oh-my-claudecode/hooks/hooks.json +21 -1
  24. package/bundled/upstream/oh-my-claudecode/skills/AGENTS.md +200 -0
  25. package/bundled/upstream/oh-my-claudecode/skills/autopilot/SKILL.md +17 -10
  26. package/bundled/upstream/oh-my-claudecode/skills/autoresearch/SKILL.md +90 -0
  27. package/bundled/upstream/oh-my-claudecode/skills/cancel/SKILL.md +15 -6
  28. package/bundled/upstream/oh-my-claudecode/skills/configure-notifications/SKILL.md +12 -12
  29. package/bundled/upstream/oh-my-claudecode/skills/debug/SKILL.md +35 -0
  30. package/bundled/upstream/oh-my-claudecode/skills/deep-dive/SKILL.md +4 -0
  31. package/bundled/upstream/oh-my-claudecode/skills/deep-interview/SKILL.md +23 -18
  32. package/bundled/upstream/oh-my-claudecode/skills/hud/SKILL.md +23 -101
  33. package/bundled/upstream/oh-my-claudecode/skills/learner/SKILL.md +27 -2
  34. package/bundled/upstream/oh-my-claudecode/skills/mcp-setup/SKILL.md +67 -8
  35. package/bundled/upstream/oh-my-claudecode/skills/omc-doctor/SKILL.md +32 -47
  36. package/bundled/upstream/oh-my-claudecode/skills/omc-setup/SKILL.md +4 -2
  37. package/bundled/upstream/oh-my-claudecode/skills/omc-setup/phases/01-install-claude-md.md +15 -4
  38. package/bundled/upstream/oh-my-claudecode/skills/omc-setup/phases/02-configure.md +9 -9
  39. package/bundled/upstream/oh-my-claudecode/skills/omc-setup/phases/03-integrations.md +13 -13
  40. package/bundled/upstream/oh-my-claudecode/skills/omc-setup/phases/04-welcome.md +3 -3
  41. package/bundled/upstream/oh-my-claudecode/skills/omc-teams/SKILL.md +28 -0
  42. package/bundled/upstream/oh-my-claudecode/skills/plan/SKILL.md +1 -0
  43. package/bundled/upstream/oh-my-claudecode/skills/project-session-manager/SKILL.md +25 -5
  44. package/bundled/upstream/oh-my-claudecode/skills/project-session-manager/lib/config.sh +2 -15
  45. package/bundled/upstream/oh-my-claudecode/skills/project-session-manager/lib/providers/github.sh +1 -1
  46. package/bundled/upstream/oh-my-claudecode/skills/project-session-manager/lib/session.sh +2 -2
  47. package/bundled/upstream/oh-my-claudecode/skills/project-session-manager/lib/tmux.sh +109 -4
  48. package/bundled/upstream/oh-my-claudecode/skills/project-session-manager/lib/worktree.sh +26 -0
  49. package/bundled/upstream/oh-my-claudecode/skills/project-session-manager/psm.sh +46 -5
  50. package/bundled/upstream/oh-my-claudecode/skills/project-session-manager/templates/pr-review.md +5 -2
  51. package/bundled/upstream/oh-my-claudecode/skills/project-session-manager/templates/projects.json +1 -1
  52. package/bundled/upstream/oh-my-claudecode/skills/project-session-manager/tests/test-psm-prompt-injection.sh +336 -0
  53. package/bundled/upstream/oh-my-claudecode/skills/ralph/SKILL.md +18 -9
  54. package/bundled/upstream/oh-my-claudecode/skills/ralplan/SKILL.md +2 -0
  55. package/bundled/upstream/oh-my-claudecode/skills/release/SKILL.md +167 -57
  56. package/bundled/upstream/oh-my-claudecode/skills/remember/SKILL.md +41 -0
  57. package/bundled/upstream/oh-my-claudecode/skills/self-improve/SKILL.md +391 -0
  58. package/bundled/upstream/oh-my-claudecode/skills/self-improve/data_contracts.md +274 -0
  59. package/bundled/upstream/oh-my-claudecode/skills/self-improve/scripts/plot_progress.py +128 -0
  60. package/bundled/upstream/oh-my-claudecode/skills/self-improve/scripts/resolve-paths.mjs +192 -0
  61. package/bundled/upstream/oh-my-claudecode/skills/self-improve/scripts/validate.sh +404 -0
  62. package/bundled/upstream/oh-my-claudecode/skills/self-improve/si-benchmark-builder.md +79 -0
  63. package/bundled/upstream/oh-my-claudecode/skills/self-improve/si-goal-clarifier.md +94 -0
  64. package/bundled/upstream/oh-my-claudecode/skills/self-improve/si-researcher.md +73 -0
  65. package/bundled/upstream/oh-my-claudecode/skills/self-improve/templates/agent-settings.json +14 -0
  66. package/bundled/upstream/oh-my-claudecode/skills/self-improve/templates/goal.md +22 -0
  67. package/bundled/upstream/oh-my-claudecode/skills/self-improve/templates/harness.md +18 -0
  68. package/bundled/upstream/oh-my-claudecode/skills/self-improve/templates/idea.md +5 -0
  69. package/bundled/upstream/oh-my-claudecode/skills/self-improve/templates/settings.json +23 -0
  70. package/bundled/upstream/oh-my-claudecode/skills/skill/SKILL.md +46 -77
  71. package/bundled/upstream/oh-my-claudecode/skills/skillify/SKILL.md +53 -0
  72. package/bundled/upstream/oh-my-claudecode/skills/team/SKILL.md +83 -11
  73. package/bundled/upstream/oh-my-claudecode/skills/trace/SKILL.md +1 -0
  74. package/bundled/upstream/oh-my-claudecode/skills/ultraqa/SKILL.md +1 -0
  75. package/bundled/upstream/oh-my-claudecode/skills/ultrawork/SKILL.md +1 -0
  76. package/bundled/upstream/oh-my-claudecode/skills/verify/SKILL.md +37 -0
  77. package/bundled/upstream/oh-my-claudecode/skills/wiki/SKILL.md +67 -0
  78. package/package.json +3 -1
  79. package/src/cli/artifact.js +63 -2
  80. package/src/cli/guidelines.js +83 -0
  81. package/src/cli/index.js +13 -1
  82. package/src/cli/setup.js +48 -18
  83. package/src/cli/source.js +35 -1
  84. package/src/config/artifact-types.js +12 -2
  85. package/src/config/paths.js +95 -4
  86. package/src/config/sources.js +29 -5
  87. package/src/guidelines/apply.js +152 -0
  88. package/src/guidelines/optimizer.js +325 -0
  89. package/src/merge/claude-md-merger.js +35 -12
  90. package/templates/merge-config.json +12 -1
  91. package/bundled/upstream/oh-my-claudecode/skills/omc-doctor/skill-debugger.md +0 -101
@@ -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
- const merged = applyResolutions(sources, resolutions);
110
+ let merged = applyResolutions(sources, resolutions);
74
111
 
75
- console.log(`${ARTIFACT_TYPES[artifactType].label} (${merged.length} total, from ${sources.length} sources):`);
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
- const merged = applyResolutions(loaded, resolutions);
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 installClaudeMd(sources, installTarget, flags) {
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
- // Collect sources that have this artifact type
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 installClaudeMd(sourcesForType, installTarget, flags);
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: path.join(os.homedir(), '.claude', 'CLAUDE.md'),
49
+ label: 'CLAUDE.md (legacy)',
50
+ installTarget: CLAUDE_MD_TARGET,
41
51
  sourceSubdir: 'claude-md',
42
52
  format: 'single-file',
43
53
  metadataFile: null,
@@ -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
- return path.join(root, '.local', artifactType);
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
- return path.join(root, 'bundled', 'upstream', sourceName, artifactType);
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
- return path.join(root, '.local', artifactType);
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
- return path.join(root, '.upstream', sourceName, artifactType);
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
  /**
@@ -13,7 +13,7 @@ function getDefaultConfig() {
13
13
  local: {
14
14
  path: '.local',
15
15
  priority: 1,
16
- artifacts: ['skills', 'agents', 'hooks', 'commands', 'claude-md', 'settings', 'hud'],
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
  };