@bleedingdev/modern-js-create 3.2.0-ultramodern.21 → 3.2.0-ultramodern.23
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 +20 -14
- package/dist/index.js +1460 -321
- package/dist/types/locale/en.d.ts +2 -0
- package/dist/types/locale/zh.d.ts +2 -0
- package/dist/types/ultramodern-workspace.d.ts +13 -0
- package/package.json +6 -6
- package/template/.mise.toml +2 -0
- package/template/README.md +7 -6
- package/template/package.json.handlebars +16 -16
- package/template/pnpm-workspace.yaml +2 -0
- package/template/scripts/validate-ultramodern.mjs.handlebars +138 -26
- package/template/tests/{ultramodern.contract.test.ts → ultramodern.contract.test.ts.handlebars} +28 -0
- package/template-workspace/.agents/skills-lock.json +19 -0
- package/template-workspace/.github/workflows/ultramodern-workspace-gates.yml.handlebars +1 -1
- package/template-workspace/.mise.toml +2 -0
- package/template-workspace/AGENTS.md +7 -7
- package/template-workspace/README.md.handlebars +12 -3
- package/template-workspace/pnpm-workspace.yaml +15 -0
- package/template-workspace/scripts/assert-mf-types.mjs +44 -0
- package/template-workspace/scripts/bootstrap-agent-skills.mjs +73 -13
- package/template-workspace/scripts/validate-ultramodern-workspace.mjs.handlebars +449 -121
- package/template-workspace/scripts/check-i18n-strings.mjs +0 -83
|
@@ -8,7 +8,7 @@ const lockPath = path.join(root, '.agents/skills-lock.json');
|
|
|
8
8
|
const checkOnly = process.argv.includes('--check');
|
|
9
9
|
const force = process.argv.includes('--force');
|
|
10
10
|
|
|
11
|
-
const readJson =
|
|
11
|
+
const readJson = filePath => JSON.parse(fs.readFileSync(filePath, 'utf-8'));
|
|
12
12
|
|
|
13
13
|
const run = (command, args, options = {}) =>
|
|
14
14
|
execFileSync(command, args, {
|
|
@@ -28,6 +28,23 @@ const cloneSource = (source, targetDir) => {
|
|
|
28
28
|
stdio: 'inherit',
|
|
29
29
|
});
|
|
30
30
|
}
|
|
31
|
+
if (source.commit) {
|
|
32
|
+
try {
|
|
33
|
+
run('git', ['checkout', source.commit], {
|
|
34
|
+
cwd: targetDir,
|
|
35
|
+
stdio: 'inherit',
|
|
36
|
+
});
|
|
37
|
+
} catch {
|
|
38
|
+
run('git', ['fetch', '--depth', '1', 'origin', source.commit], {
|
|
39
|
+
cwd: targetDir,
|
|
40
|
+
stdio: 'inherit',
|
|
41
|
+
});
|
|
42
|
+
run('git', ['checkout', source.commit], {
|
|
43
|
+
cwd: targetDir,
|
|
44
|
+
stdio: 'inherit',
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
}
|
|
31
48
|
};
|
|
32
49
|
|
|
33
50
|
const resolveSkillDir = (sourceRoot, skillName) => {
|
|
@@ -37,7 +54,9 @@ const resolveSkillDir = (sourceRoot, skillName) => {
|
|
|
37
54
|
path.join(sourceRoot, 'skills', 'engineering', skillName),
|
|
38
55
|
path.join(sourceRoot, 'skills', 'productivity', skillName),
|
|
39
56
|
];
|
|
40
|
-
return candidates.find(
|
|
57
|
+
return candidates.find(candidate =>
|
|
58
|
+
fs.existsSync(path.join(candidate, 'SKILL.md')),
|
|
59
|
+
);
|
|
41
60
|
};
|
|
42
61
|
|
|
43
62
|
if (!fs.existsSync(lockPath)) {
|
|
@@ -47,36 +66,77 @@ if (!fs.existsSync(lockPath)) {
|
|
|
47
66
|
|
|
48
67
|
const lock = readJson(lockPath);
|
|
49
68
|
const installDir = path.join(root, lock.installDir ?? '.agents/skills');
|
|
50
|
-
const
|
|
51
|
-
|
|
69
|
+
const sources = lock.sources ?? [];
|
|
70
|
+
const requiredCloneSources = sources.filter(
|
|
71
|
+
source => source.install === 'clone',
|
|
72
|
+
);
|
|
73
|
+
const optionalCloneSources = sources.filter(
|
|
74
|
+
source => source.install === 'clone-if-authorized',
|
|
75
|
+
);
|
|
76
|
+
const requiredSkills = [
|
|
77
|
+
...(lock.baseline ?? []),
|
|
78
|
+
...requiredCloneSources.flatMap(source => source.baseline ?? []),
|
|
79
|
+
].filter(
|
|
80
|
+
(skill, index, skills) =>
|
|
81
|
+
skills.findIndex(candidate => candidate.name === skill.name) === index,
|
|
52
82
|
);
|
|
53
83
|
|
|
54
84
|
if (checkOnly) {
|
|
55
|
-
const
|
|
85
|
+
const missingRequired = requiredSkills
|
|
86
|
+
.map(skill => skill.name)
|
|
87
|
+
.filter(
|
|
88
|
+
skillName => !fs.existsSync(path.join(installDir, skillName, 'SKILL.md')),
|
|
89
|
+
);
|
|
90
|
+
const missingOptional = optionalCloneSources.flatMap(source =>
|
|
56
91
|
(source.baseline ?? [])
|
|
57
|
-
.map(
|
|
58
|
-
.filter(
|
|
92
|
+
.map(skill => skill.name)
|
|
93
|
+
.filter(
|
|
94
|
+
skillName =>
|
|
95
|
+
!fs.existsSync(path.join(installDir, skillName, 'SKILL.md')),
|
|
96
|
+
),
|
|
59
97
|
);
|
|
60
|
-
|
|
98
|
+
|
|
99
|
+
if (missingRequired.length > 0) {
|
|
100
|
+
console.error(
|
|
101
|
+
`Required agent skills not installed: ${missingRequired.join(', ')}. Run pnpm skills:install.`,
|
|
102
|
+
);
|
|
103
|
+
process.exit(1);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (missingOptional.length > 0) {
|
|
61
107
|
console.warn(
|
|
62
|
-
`Private skills not installed: ${
|
|
108
|
+
`Private skills not installed: ${missingOptional.join(', ')}. Run pnpm skills:install if you have access.`,
|
|
63
109
|
);
|
|
64
110
|
} else {
|
|
65
|
-
console.log('
|
|
111
|
+
console.log('Required and private agent skills are installed.');
|
|
112
|
+
process.exit(0);
|
|
66
113
|
}
|
|
114
|
+
console.log('Required agent skills are installed.');
|
|
67
115
|
process.exit(0);
|
|
68
116
|
}
|
|
69
117
|
|
|
70
118
|
fs.mkdirSync(installDir, { recursive: true });
|
|
71
119
|
|
|
72
|
-
for (const source of
|
|
120
|
+
for (const source of [...requiredCloneSources, ...optionalCloneSources]) {
|
|
73
121
|
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'ultramodern-skills-'));
|
|
74
122
|
try {
|
|
75
|
-
|
|
123
|
+
try {
|
|
124
|
+
cloneSource(source, tempDir);
|
|
125
|
+
} catch (error) {
|
|
126
|
+
if (source.install === 'clone-if-authorized') {
|
|
127
|
+
console.warn(
|
|
128
|
+
`Skipping ${source.repository}; current developer may not have access.`,
|
|
129
|
+
);
|
|
130
|
+
continue;
|
|
131
|
+
}
|
|
132
|
+
throw error;
|
|
133
|
+
}
|
|
76
134
|
for (const skill of source.baseline ?? []) {
|
|
77
135
|
const sourceSkillDir = resolveSkillDir(tempDir, skill.name);
|
|
78
136
|
if (!sourceSkillDir) {
|
|
79
|
-
throw new Error(
|
|
137
|
+
throw new Error(
|
|
138
|
+
`Skill ${skill.name} not found in ${source.repository}`,
|
|
139
|
+
);
|
|
80
140
|
}
|
|
81
141
|
const targetSkillDir = path.join(installDir, skill.name);
|
|
82
142
|
if (fs.existsSync(targetSkillDir)) {
|