claudecode-omc 5.4.0 → 5.5.1

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 +47 -0
  80. package/src/cli/doctor.js +6 -1
  81. package/src/cli/guidelines.js +83 -0
  82. package/src/cli/index.js +13 -1
  83. package/src/cli/setup.js +68 -19
  84. package/src/cli/source.js +35 -1
  85. package/src/config/artifact-types.js +12 -2
  86. package/src/config/paths.js +95 -4
  87. package/src/config/sources.js +29 -5
  88. package/src/guidelines/apply.js +152 -0
  89. package/src/guidelines/optimizer.js +325 -0
  90. package/src/merge/claude-md-merger.js +35 -12
  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)) {
@@ -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`);
package/src/cli/doctor.js CHANGED
@@ -71,7 +71,12 @@ async function doctor() {
71
71
  console.log('');
72
72
 
73
73
  console.log('Installation:');
74
- for (const typeName of getArtifactTypeNames()) {
74
+ const typeNames = getArtifactTypeNames().filter(typeName => {
75
+ if (typeName !== 'claude-md') return true;
76
+ return !fs.existsSync(ARTIFACT_TYPES.guidelines.installTarget);
77
+ });
78
+
79
+ for (const typeName of typeNames) {
75
80
  const type = ARTIFACT_TYPES[typeName];
76
81
  const target = type.installTarget;
77
82
  if (fs.existsSync(target)) {
@@ -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
@@ -2,6 +2,7 @@
2
2
  const fs = require('fs');
3
3
  const fsp = require('fs/promises');
4
4
  const path = require('path');
5
+ const os = require('os');
5
6
  const { getProjectRoot, getSourceArtifactDir, getInstallTarget, getMergeConfigPath, getReportDir } = require('../config/paths');
6
7
  const { readConfig } = require('../config/sources');
7
8
  const { getArtifactTypeNames, ARTIFACT_TYPES } = require('../config/artifact-types');
@@ -16,6 +17,30 @@ const { loadFilesFromSource } = require('../merge/file-merger');
16
17
  const { evaluateSkillQuality } = require('../utils/quality');
17
18
  const { copyDirRecursive } = require('./source');
18
19
 
20
+ const OMC_VERSION_PATH = path.join(os.homedir(), '.claude', '.omc-version.json');
21
+
22
+ function getPackageVersion(root) {
23
+ try {
24
+ const pkg = JSON.parse(fs.readFileSync(path.join(root, 'package.json'), 'utf8'));
25
+ return pkg.version || '0.0.0';
26
+ } catch {
27
+ return '0.0.0';
28
+ }
29
+ }
30
+
31
+ async function writeInstallMetadata(root) {
32
+ const now = new Date().toISOString();
33
+ const metadata = {
34
+ version: getPackageVersion(root),
35
+ installedAt: now,
36
+ installMethod: fs.existsSync(path.join(root, '.git')) ? 'local-dev' : 'npm',
37
+ lastCheckAt: now,
38
+ };
39
+
40
+ await fsp.mkdir(path.dirname(OMC_VERSION_PATH), { recursive: true });
41
+ await fsp.writeFile(OMC_VERSION_PATH, JSON.stringify(metadata, null, 2) + '\n', 'utf8');
42
+ }
43
+
19
44
  async function copyDirectory(src, dest, options = {}) {
20
45
  if (!fs.existsSync(src)) return 0;
21
46
  if (!options.dryRun) await fsp.mkdir(dest, { recursive: true });
@@ -49,6 +74,29 @@ function getLoader(artifactType) {
49
74
  }
50
75
  }
51
76
 
77
+ function collectSourcesForType(artifactType, orderedSources, root) {
78
+ const sourcesForType = [];
79
+
80
+ for (const [name, src] of orderedSources) {
81
+ // Skip reference-only sources (e.g. anthropic-skills) — they provide
82
+ // evaluation standards, not installable artifacts.
83
+ if (src.role === 'reference') continue;
84
+ const declaredArtifacts = src.artifacts || [];
85
+ if (!declaredArtifacts.includes(artifactType)) continue;
86
+
87
+ const dir = getSourceArtifactDir(name, artifactType, root);
88
+ if (fs.existsSync(dir)) {
89
+ sourcesForType.push({ name, dir, priority: src.priority });
90
+ }
91
+ }
92
+
93
+ if (sourcesForType.length === 0 && artifactType === 'claude-md') {
94
+ return collectSourcesForType('guidelines', orderedSources, root);
95
+ }
96
+
97
+ return sourcesForType;
98
+ }
99
+
52
100
  async function installNameBasedArtifacts(artifactType, sources, mergeConfig, installTarget, flags) {
53
101
  const loader = getLoader(artifactType);
54
102
  if (!loader) return { count: 0, total: 0 };
@@ -137,7 +185,7 @@ async function installHooks(sources, installTarget, flags) {
137
185
  return result;
138
186
  }
139
187
 
140
- async function installClaudeMd(sources, installTarget, flags) {
188
+ async function installSectionDocument(artifactType, sources, installTarget, flags) {
141
189
  const sections = [];
142
190
  // Collect in reverse priority order (lowest priority first)
143
191
  const sorted = [...sources].reverse();
@@ -159,7 +207,15 @@ async function installClaudeMd(sources, installTarget, flags) {
159
207
  let finalContent;
160
208
  if (fs.existsSync(installTarget)) {
161
209
  const existing = fs.readFileSync(installTarget, 'utf8');
162
- finalContent = mergeIntoExisting(existing, sections);
210
+ finalContent = mergeIntoExisting(existing, sections, {
211
+ markerNamespace: artifactType,
212
+ legacyMarkerKeys: (sourceName) => {
213
+ if (artifactType === 'guidelines') {
214
+ return [sourceName, `claude-md:${sourceName}`];
215
+ }
216
+ return [sourceName];
217
+ },
218
+ });
163
219
  } else {
164
220
  finalContent = assembleSections(sections);
165
221
  }
@@ -206,7 +262,9 @@ async function setup(args, flags = {}) {
206
262
  const root = getProjectRoot();
207
263
  const config = readConfig();
208
264
  const scope = flags.scope || 'user';
209
- const typeFilter = flags.type ? flags.type.split(',') : null;
265
+ const typeFilter = flags.type
266
+ ? [...new Set(flags.type.split(',').map(type => (type === 'claude-md' ? 'guidelines' : type)))]
267
+ : null;
210
268
 
211
269
  console.log('claudecode-omc setup');
212
270
  console.log('====================');
@@ -225,7 +283,7 @@ async function setup(args, flags = {}) {
225
283
  const orderedSources = Object.entries(config.sources)
226
284
  .sort(([, a], [, b]) => a.priority - b.priority);
227
285
 
228
- const allTypes = getArtifactTypeNames();
286
+ const allTypes = getArtifactTypeNames().filter(type => type !== 'claude-md');
229
287
  const typesToInstall = typeFilter || allTypes;
230
288
  let step = 0;
231
289
  const totalSteps = typesToInstall.length;
@@ -238,20 +296,7 @@ async function setup(args, flags = {}) {
238
296
  continue;
239
297
  }
240
298
 
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
- }
299
+ const sourcesForType = collectSourcesForType(artifactType, orderedSources, root);
255
300
 
256
301
  const installTarget = (artifactType === 'skills' && scope === 'project')
257
302
  ? path.join(process.cwd(), '.claude', 'skills')
@@ -273,7 +318,7 @@ async function setup(args, flags = {}) {
273
318
  result = await installHooks(sourcesForType, installTarget, flags);
274
319
  break;
275
320
  case 'section-concat':
276
- result = await installClaudeMd(sourcesForType, installTarget, flags);
321
+ result = await installSectionDocument(artifactType, sourcesForType, installTarget, flags);
277
322
  break;
278
323
  case 'deep-merge':
279
324
  result = await installSettings(sourcesForType, installTarget, flags);
@@ -293,6 +338,10 @@ async function setup(args, flags = {}) {
293
338
  }
294
339
  }
295
340
 
341
+ if (!flags.dryRun && scope === 'user') {
342
+ await writeInstallMetadata(root);
343
+ }
344
+
296
345
  console.log('\nDone.');
297
346
  }
298
347
 
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
  };