claudecode-omc 5.4.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 (90) 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 +47 -0
  80. package/src/cli/guidelines.js +83 -0
  81. package/src/cli/index.js +13 -1
  82. package/src/cli/setup.js +35 -17
  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/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)) {
@@ -109,6 +146,9 @@ async function artifact(args, flags = {}) {
109
146
  }
110
147
 
111
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
+ }
112
152
  const name = args[1];
113
153
  const source = args[2];
114
154
  if (!name || !source) {
@@ -126,6 +166,13 @@ async function artifact(args, flags = {}) {
126
166
  }
127
167
 
128
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
+
129
176
  const sources = loadSourcesForType(artifactType, root);
130
177
  if (sources.length < 2) {
131
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 };
@@ -137,7 +160,7 @@ async function installHooks(sources, installTarget, flags) {
137
160
  return result;
138
161
  }
139
162
 
140
- async function installClaudeMd(sources, installTarget, flags) {
163
+ async function installSectionDocument(artifactType, sources, installTarget, flags) {
141
164
  const sections = [];
142
165
  // Collect in reverse priority order (lowest priority first)
143
166
  const sorted = [...sources].reverse();
@@ -159,7 +182,15 @@ async function installClaudeMd(sources, installTarget, flags) {
159
182
  let finalContent;
160
183
  if (fs.existsSync(installTarget)) {
161
184
  const existing = fs.readFileSync(installTarget, 'utf8');
162
- 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
+ });
163
194
  } else {
164
195
  finalContent = assembleSections(sections);
165
196
  }
@@ -238,20 +269,7 @@ async function setup(args, flags = {}) {
238
269
  continue;
239
270
  }
240
271
 
241
- // Collect sources that have this artifact type
242
- const sourcesForType = [];
243
- for (const [name, src] of orderedSources) {
244
- // Skip reference-only sources (e.g. anthropic-skills) — they provide
245
- // evaluation standards, not installable artifacts.
246
- if (src.role === 'reference') continue;
247
- const declaredArtifacts = src.artifacts || [];
248
- if (!declaredArtifacts.includes(artifactType)) continue;
249
-
250
- const dir = getSourceArtifactDir(name, artifactType, root);
251
- if (fs.existsSync(dir)) {
252
- sourcesForType.push({ name, dir, priority: src.priority });
253
- }
254
- }
272
+ const sourcesForType = collectSourcesForType(artifactType, orderedSources, root);
255
273
 
256
274
  const installTarget = (artifactType === 'skills' && scope === 'project')
257
275
  ? path.join(process.cwd(), '.claude', 'skills')
@@ -273,7 +291,7 @@ async function setup(args, flags = {}) {
273
291
  result = await installHooks(sourcesForType, installTarget, flags);
274
292
  break;
275
293
  case 'section-concat':
276
- result = await installClaudeMd(sourcesForType, installTarget, flags);
294
+ result = await installSectionDocument(artifactType, sourcesForType, installTarget, flags);
277
295
  break;
278
296
  case 'deep-merge':
279
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
  };