@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 +3 -3
- package/package.json +1 -1
- package/src/commands/doctor.js +11 -11
- package/src/commands/init.js +14 -14
- package/src/commands/status.js +1 -1
- package/src/commands/update.js +24 -8
- package/src/utils/project-config.js +1 -1
- package/src/utils/symlink.js +3 -3
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 `
|
|
31
|
-
4. Creates `
|
|
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
|
-
✓
|
|
84
|
+
✓ cw-project/project-config.md found
|
|
85
85
|
✓ Target lit-browser found
|
|
86
86
|
```
|
|
87
87
|
|
package/package.json
CHANGED
package/src/commands/doctor.js
CHANGED
|
@@ -110,22 +110,22 @@ export async function doctor() {
|
|
|
110
110
|
}
|
|
111
111
|
}
|
|
112
112
|
|
|
113
|
-
// 5.
|
|
114
|
-
const configPath = join(projectRoot, '.claude', 'skills', '
|
|
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
|
-
'
|
|
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('
|
|
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', '
|
|
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
|
|
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
|
|
141
|
+
checks.push(warn('Could not read target name from cw-project/project-config.md'));
|
|
142
142
|
}
|
|
143
143
|
}
|
|
144
144
|
|
|
145
|
-
// 6b.
|
|
146
|
-
const referencesDir = join(projectRoot, '.claude', 'skills', '
|
|
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('
|
|
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('
|
|
150
|
+
checks.push(pass('cw-project/references/ found'));
|
|
151
151
|
}
|
|
152
152
|
|
|
153
153
|
// 7. Baseline compatibility check (if baseline present)
|
package/src/commands/init.js
CHANGED
|
@@ -97,21 +97,21 @@ async function freshInstall(projectRoot, frameworkDir, skillsDir, options) {
|
|
|
97
97
|
}
|
|
98
98
|
|
|
99
99
|
await scaffoldConfigIfMissing(projectRoot, frameworkDir);
|
|
100
|
-
await
|
|
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/
|
|
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
|
|
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', '
|
|
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', '
|
|
123
|
+
const fragmentsDir = join(projectRoot, '.claude', 'skills', 'cw-project', 'fragments', 'project');
|
|
124
124
|
|
|
125
|
-
await mkdir(join(projectRoot, '.claude', 'skills', '
|
|
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
|
|
129
|
+
console.log(' Scaffolded cw-project/project-config.md');
|
|
130
130
|
}
|
|
131
131
|
|
|
132
132
|
/**
|
|
133
|
-
* Scaffold
|
|
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
|
|
137
|
-
const
|
|
138
|
-
await mkdir(join(
|
|
139
|
-
await mkdir(join(
|
|
140
|
-
await mkdir(join(
|
|
141
|
-
await mkdir(join(
|
|
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) {
|
package/src/commands/status.js
CHANGED
|
@@ -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', '
|
|
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 = [];
|
package/src/commands/update.js
CHANGED
|
@@ -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
|
|
108
|
+
// Scaffold cw-project/references/ and cw-project/templates/ if missing
|
|
107
109
|
if (!dryRun) {
|
|
108
|
-
const
|
|
109
|
-
await mkdir(join(
|
|
110
|
-
await mkdir(join(
|
|
111
|
-
await mkdir(join(
|
|
112
|
-
await mkdir(join(
|
|
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', '
|
|
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
|
|
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.
|
package/src/utils/symlink.js
CHANGED
|
@@ -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', '
|
|
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
|
);
|