@cuewright/skills 0.2.3 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -27,8 +27,8 @@ npx @cuewright/skills init [options]
27
27
  **What it does:**
28
28
  1. Clones the framework as a git submodule at `.claude/skills/_framework/`
29
29
  2. Creates skill symlinks at `.claude/skills/<name>/` for each skill in the manifest
30
- 3. Scaffolds `arch/project-config.md` from the framework template
31
- 4. Creates `arch/fragments/project/`
30
+ 3. Scaffolds `cw-project/project-config.md` from the framework template
31
+ 4. Creates `cw-project/fragments/project/`
32
32
 
33
33
  **Flags:**
34
34
 
@@ -81,7 +81,7 @@ npx @cuewright/skills doctor
81
81
  ```
82
82
  ✓ Framework installed at v0.14.33
83
83
  ✓ 25/25 skills wired
84
- arch/project-config.md found
84
+ cw-project/project-config.md found
85
85
  ✓ Target lit-browser found
86
86
  ```
87
87
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cuewright/skills",
3
- "version": "0.2.3",
3
+ "version": "0.3.0",
4
4
  "description": "CLI installer for the Cuewright skills framework",
5
5
  "type": "module",
6
6
  "engines": {
@@ -110,22 +110,22 @@ export async function doctor() {
110
110
  }
111
111
  }
112
112
 
113
- // 5. arch/project-config.md exists
114
- const configPath = join(projectRoot, '.claude', 'skills', 'arch', 'project-config.md');
113
+ // 5. cw-project/project-config.md exists
114
+ const configPath = join(projectRoot, '.claude', 'skills', 'cw-project', 'project-config.md');
115
115
  if (!await exists(configPath)) {
116
116
  allPassed = false;
117
117
  checks.push(fail(
118
- 'arch/project-config.md not found',
118
+ 'cw-project/project-config.md not found',
119
119
  'Run `cuewright init` to scaffold it, or create it manually from _framework/targets/_template/project-config-template.md.'
120
120
  ));
121
121
  } else {
122
- checks.push(pass('arch/project-config.md found'));
122
+ checks.push(pass('cw-project/project-config.md found'));
123
123
 
124
124
  // 6. Target named in project-config exists
125
125
  const targetName = await extractTargetName(configPath);
126
126
  if (targetName) {
127
127
  const targetDir = join(frameworkDir, 'targets', targetName);
128
- const projectTargetDir = join(projectRoot, '.claude', 'skills', 'arch', 'targets', targetName);
128
+ const projectTargetDir = join(projectRoot, '.claude', 'skills', 'cw-project', 'targets', targetName);
129
129
 
130
130
  if (await exists(targetDir) || await exists(projectTargetDir)) {
131
131
  checks.push(pass(`Target ${targetName} found`));
@@ -134,20 +134,20 @@ export async function doctor() {
134
134
  const availableTargets = await listAvailableTargets(frameworkDir);
135
135
  checks.push(fail(
136
136
  `Target '${targetName}' not found`,
137
- `Update arch/project-config.md with a valid target. Available: ${availableTargets.join(', ')}`
137
+ `Update cw-project/project-config.md with a valid target. Available: ${availableTargets.join(', ')}`
138
138
  ));
139
139
  }
140
140
  } else {
141
- checks.push(warn('Could not read target name from arch/project-config.md'));
141
+ checks.push(warn('Could not read target name from cw-project/project-config.md'));
142
142
  }
143
143
  }
144
144
 
145
- // 6b. arch/references/ exists
146
- const referencesDir = join(projectRoot, '.claude', 'skills', 'arch', 'references');
145
+ // 6b. cw-project/references/ exists
146
+ const referencesDir = join(projectRoot, '.claude', 'skills', 'cw-project', 'references');
147
147
  if (!await exists(referencesDir)) {
148
- checks.push(warn('arch/references/ not found — skill reference files have no home. Run `cuewright update` to scaffold it.'));
148
+ checks.push(warn('cw-project/references/ not found — skill reference files have no home. Run `cuewright update` to scaffold it.'));
149
149
  } else {
150
- checks.push(pass('arch/references/ found'));
150
+ checks.push(pass('cw-project/references/ found'));
151
151
  }
152
152
 
153
153
  // 7. Baseline compatibility check (if baseline present)
@@ -97,21 +97,21 @@ async function freshInstall(projectRoot, frameworkDir, skillsDir, options) {
97
97
  }
98
98
 
99
99
  await scaffoldConfigIfMissing(projectRoot, frameworkDir);
100
- await scaffoldArchDirectories(projectRoot);
100
+ await scaffoldProjectDirectories(projectRoot);
101
101
 
102
102
  console.log(chalk.green(`\nDone.`));
103
103
  console.log(` Framework: v${version}`);
104
104
  console.log(` Skills wired: ${wired.length}`);
105
- console.log(` Config: .claude/skills/arch/project-config.md`);
105
+ console.log(` Config: .claude/skills/cw-project/project-config.md`);
106
106
  console.log('');
107
107
  console.log('Next: edit project-config.md to set your target, then run /align-project-skills');
108
108
  }
109
109
 
110
110
  /**
111
- * Scaffold arch/project-config.md from the framework template if it does not yet exist.
111
+ * Scaffold cw-project/project-config.md from the framework template if it does not yet exist.
112
112
  */
113
113
  async function scaffoldConfigIfMissing(projectRoot, frameworkDir) {
114
- const configPath = join(projectRoot, '.claude', 'skills', 'arch', 'project-config.md');
114
+ const configPath = join(projectRoot, '.claude', 'skills', 'cw-project', 'project-config.md');
115
115
  const configExists = await exists(configPath);
116
116
 
117
117
  if (configExists) {
@@ -120,25 +120,25 @@ async function scaffoldConfigIfMissing(projectRoot, frameworkDir) {
120
120
  }
121
121
 
122
122
  const templatePath = join(frameworkDir, 'targets', '_template', 'project-config-template.md');
123
- const fragmentsDir = join(projectRoot, '.claude', 'skills', 'arch', 'fragments', 'project');
123
+ const fragmentsDir = join(projectRoot, '.claude', 'skills', 'cw-project', 'fragments', 'project');
124
124
 
125
- await mkdir(join(projectRoot, '.claude', 'skills', 'arch'), { recursive: true });
125
+ await mkdir(join(projectRoot, '.claude', 'skills', 'cw-project'), { recursive: true });
126
126
  await mkdir(fragmentsDir, { recursive: true });
127
127
  await copyFile(templatePath, configPath);
128
128
 
129
- console.log(' Scaffolded arch/project-config.md');
129
+ console.log(' Scaffolded cw-project/project-config.md');
130
130
  }
131
131
 
132
132
  /**
133
- * Scaffold arch/references/ and arch/templates/ subdirectories if they don't exist.
133
+ * Scaffold cw-project/references/ and cw-project/templates/ subdirectories if they don't exist.
134
134
  * These are the project customization roots under the cw- prefix model.
135
135
  */
136
- async function scaffoldArchDirectories(projectRoot) {
137
- const archDir = join(projectRoot, '.claude', 'skills', 'arch');
138
- await mkdir(join(archDir, 'references'), { recursive: true });
139
- await mkdir(join(archDir, 'templates', 'page'), { recursive: true });
140
- await mkdir(join(archDir, 'templates', 'component'), { recursive: true });
141
- await mkdir(join(archDir, 'templates', 'guide'), { recursive: true });
136
+ async function scaffoldProjectDirectories(projectRoot) {
137
+ const projectDir = join(projectRoot, '.claude', 'skills', 'cw-project');
138
+ await mkdir(join(projectDir, 'references'), { recursive: true });
139
+ await mkdir(join(projectDir, 'templates', 'page'), { recursive: true });
140
+ await mkdir(join(projectDir, 'templates', 'component'), { recursive: true });
141
+ await mkdir(join(projectDir, 'templates', 'guide'), { recursive: true });
142
142
  }
143
143
 
144
144
  async function exists(path) {
@@ -46,7 +46,7 @@ export async function status(options = {}) {
46
46
  }
47
47
 
48
48
  // Read project-config for target and governance
49
- const configPath = join(projectRoot, '.claude', 'skills', 'arch', 'project-config.md');
49
+ const configPath = join(projectRoot, '.claude', 'skills', 'cw-project', 'project-config.md');
50
50
  const configExists = await exists(configPath);
51
51
  let targetName = null;
52
52
  let governanceRows = [];
@@ -1,5 +1,5 @@
1
1
  import chalk from 'chalk';
2
- import { access, readFile, unlink, mkdir } from 'fs/promises';
2
+ import { access, readFile, unlink, mkdir, rename } from 'fs/promises';
3
3
  import { join } from 'path';
4
4
  import { cwd } from 'process';
5
5
  import { readManifest, listSkills, getVersion } from '../utils/manifest.js';
@@ -16,6 +16,8 @@ export async function update(options) {
16
16
  const skillsDir = getSkillsDir(projectRoot);
17
17
  const dryRun = options.dryRun || false;
18
18
 
19
+ await migrateArchToCwProject(skillsDir, { dryRun });
20
+
19
21
  // Framework must already be installed
20
22
  const manifestPath = join(frameworkDir, 'manifest.json');
21
23
  if (!await exists(manifestPath)) {
@@ -103,13 +105,13 @@ export async function update(options) {
103
105
  // Always run legacy cleanup — catches dirs that survived the diff-based migration
104
106
  await runCleanup(skillsDir, [...newSkills], projectRoot, dryRun);
105
107
 
106
- // Scaffold arch/references/ and arch/templates/ if missing
108
+ // Scaffold cw-project/references/ and cw-project/templates/ if missing
107
109
  if (!dryRun) {
108
- const archDir = join(projectRoot, '.claude', 'skills', 'arch');
109
- await mkdir(join(archDir, 'references'), { recursive: true });
110
- await mkdir(join(archDir, 'templates', 'page'), { recursive: true });
111
- await mkdir(join(archDir, 'templates', 'component'), { recursive: true });
112
- await mkdir(join(archDir, 'templates', 'guide'), { recursive: true });
110
+ const projectDir = join(projectRoot, '.claude', 'skills', 'cw-project');
111
+ await mkdir(join(projectDir, 'references'), { recursive: true });
112
+ await mkdir(join(projectDir, 'templates', 'page'), { recursive: true });
113
+ await mkdir(join(projectDir, 'templates', 'component'), { recursive: true });
114
+ await mkdir(join(projectDir, 'templates', 'guide'), { recursive: true });
113
115
  }
114
116
 
115
117
  // Print changelog for the updated range
@@ -125,7 +127,7 @@ export async function update(options) {
125
127
 
126
128
  // Update version in project-config.md
127
129
  if (!dryRun) {
128
- const configPath = join(projectRoot, '.claude', 'skills', 'arch', 'project-config.md');
130
+ const configPath = join(projectRoot, '.claude', 'skills', 'cw-project', 'project-config.md');
129
131
  await updateProjectConfigVersion(configPath, targetVersion);
130
132
  }
131
133
 
@@ -227,3 +229,17 @@ async function isRealDirectory(path) {
227
229
  const stat = await lstat(path);
228
230
  return stat.isDirectory() && !stat.isSymbolicLink();
229
231
  }
232
+
233
+ export async function migrateArchToCwProject(skillsDir, { dryRun = false } = {}) {
234
+ const oldDir = join(skillsDir, 'arch');
235
+ const newDir = join(skillsDir, 'cw-project');
236
+ if (await exists(oldDir) && !await exists(newDir)) {
237
+ if (!dryRun) {
238
+ await rename(oldDir, newDir);
239
+ }
240
+ const verb = dryRun ? 'Would migrate' : 'Migrated';
241
+ console.log(` ${verb} .claude/skills/arch/ \u2192 .claude/skills/cw-project/`);
242
+ return true;
243
+ }
244
+ return false;
245
+ }
@@ -1,7 +1,7 @@
1
1
  import { readFile, writeFile, access } from 'fs/promises';
2
2
 
3
3
  /**
4
- * Update the Framework Version line in arch/project-config.md.
4
+ * Update the Framework Version line in cw-project/project-config.md.
5
5
  * Looks for a markdown table row like: | Framework Version | v0.8.0 |
6
6
  * Updates the version value in place. No-ops if the file doesn't exist
7
7
  * or doesn't contain a recognizable version line.
@@ -190,7 +190,7 @@ export async function cleanupLegacyDirectories(skillsDir, manifestSkillNames, pr
190
190
  const referenceFiles = entries.filter(e => e !== 'SKILL.md');
191
191
 
192
192
  if (referenceFiles.length > 0 && !dryRun) {
193
- const refDir = join(projectRoot, '.claude', 'skills', 'arch', 'references', cwName);
193
+ const refDir = join(projectRoot, '.claude', 'skills', 'cw-project', 'references', cwName);
194
194
  try {
195
195
  await mkdir(refDir, { recursive: true });
196
196
  for (const file of referenceFiles) {
@@ -223,7 +223,7 @@ export async function cleanupLegacyDirectories(skillsDir, manifestSkillNames, pr
223
223
  // Second pass: remove broken symlinks pointing into _framework/ with no manifest match.
224
224
  // These are retired framework skills whose target directory no longer exists.
225
225
  const { join: pathJoin } = await import('path');
226
- const RESERVED = new Set(['_framework', '_baseline', 'arch', 'worktrees']);
226
+ const RESERVED = new Set(['_framework', '_baseline', 'arch', 'cw-project', 'worktrees']);
227
227
  const cwNameSet = new Set(manifestSkillNames);
228
228
  const unprefixedSet = new Set(
229
229
  manifestSkillNames.filter(n => n.startsWith('cw-')).map(n => n.slice(3))
@@ -297,7 +297,7 @@ export async function inventorySkillsDir(skillsDir, manifestSkillNames) {
297
297
  const deadFramework = [];
298
298
  const orphaned = [];
299
299
 
300
- const RESERVED = new Set(['_framework', '_baseline', 'arch', 'worktrees']);
300
+ const RESERVED = new Set(['_framework', '_baseline', 'arch', 'cw-project', 'worktrees']);
301
301
  const unprefixedNames = new Set(
302
302
  manifestSkillNames.filter(n => n.startsWith('cw-')).map(n => n.slice(3))
303
303
  );