baldart 5.6.0 → 5.8.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/CHANGELOG.md +98 -0
- package/VERSION +1 -1
- package/framework/.claude/agents/prd-card-writer.md +23 -0
- package/framework/.claude/skills/capture/CHANGELOG.md +4 -0
- package/framework/.claude/skills/capture/SKILL.md +2 -1
- package/framework/.claude/skills/design-sync/CHANGELOG.md +4 -0
- package/framework/.claude/skills/design-sync/SKILL.md +2 -1
- package/framework/.claude/skills/ds-edit/CHANGELOG.md +5 -0
- package/framework/.claude/skills/ds-edit/SKILL.md +9 -10
- package/framework/.claude/skills/ds-handoff/CHANGELOG.md +5 -0
- package/framework/.claude/skills/ds-handoff/SKILL.md +3 -2
- package/framework/.claude/skills/ds-new/CHANGELOG.md +4 -0
- package/framework/.claude/skills/ds-new/SKILL.md +2 -1
- package/framework/.claude/skills/ds-render/CHANGELOG.md +4 -0
- package/framework/.claude/skills/ds-render/SKILL.md +2 -1
- package/framework/.claude/skills/e2e-review/CHANGELOG.md +4 -0
- package/framework/.claude/skills/e2e-review/SKILL.md +2 -1
- package/framework/.claude/skills/gamification-design/CHANGELOG.md +4 -0
- package/framework/.claude/skills/gamification-design/SKILL.md +2 -1
- package/framework/.claude/skills/graph-align/CHANGELOG.md +4 -0
- package/framework/.claude/skills/graph-align/SKILL.md +2 -1
- package/framework/.claude/skills/i18n/CHANGELOG.md +4 -0
- package/framework/.claude/skills/i18n/SKILL.md +2 -1
- package/framework/.claude/skills/motion-design/CHANGELOG.md +4 -0
- package/framework/.claude/skills/motion-design/SKILL.md +2 -1
- package/framework/.claude/skills/new/CHANGELOG.md +19 -0
- package/framework/.claude/skills/new/SKILL.md +2 -1
- package/framework/.claude/skills/new/references/final-review.md +36 -1
- package/framework/.claude/skills/new2/CHANGELOG.md +15 -0
- package/framework/.claude/skills/new2/SKILL.md +2 -1
- package/framework/.claude/skills/prd/CHANGELOG.md +32 -0
- package/framework/.claude/skills/prd/SKILL.md +2 -1
- package/framework/.claude/skills/prd/assets/epic-template.yml +6 -0
- package/framework/.claude/skills/prd/references/backlog-phase.md +36 -0
- package/framework/.claude/skills/prd/references/validation-phase.md +30 -0
- package/framework/.claude/skills/prd-add/CHANGELOG.md +4 -0
- package/framework/.claude/skills/prd-add/SKILL.md +2 -1
- package/framework/.claude/skills/skill-creator/references/skill-structure.md +31 -2
- package/framework/.claude/skills/skill-creator/scripts/quick_validate.py +25 -3
- package/framework/.claude/skills/ui-design/CHANGELOG.md +4 -0
- package/framework/.claude/skills/ui-design/SKILL.md +2 -1
- package/framework/.claude/skills/ui-implement/CHANGELOG.md +4 -0
- package/framework/.claude/skills/ui-implement/SKILL.md +2 -1
- package/framework/.claude/workflows/new2.js +24 -3
- package/framework/agents/card-schema.md +50 -0
- package/package.json +1 -1
- package/src/commands/configure.js +9 -2
- package/src/commands/doctor.js +65 -0
- package/src/utils/skill-gate.js +139 -0
- package/src/utils/symlinks.js +72 -7
package/src/utils/symlinks.js
CHANGED
|
@@ -210,7 +210,7 @@ class SymlinkUtils {
|
|
|
210
210
|
*/
|
|
211
211
|
mergeSkills(opts = {}) {
|
|
212
212
|
const tools = (opts.tools && opts.tools.length) ? opts.tools : ['claude'];
|
|
213
|
-
const aggregate = { linked: [], skipped: [], conflicts: [] };
|
|
213
|
+
const aggregate = { linked: [], skipped: [], conflicts: [], pruned: [], gatedOff: [] };
|
|
214
214
|
|
|
215
215
|
const frameworkSkillsDir = path.join(this.cwd, FRAMEWORK_PAYLOAD, '.claude', 'skills');
|
|
216
216
|
if (!fs.existsSync(frameworkSkillsDir)) {
|
|
@@ -218,17 +218,31 @@ class SymlinkUtils {
|
|
|
218
218
|
return aggregate;
|
|
219
219
|
}
|
|
220
220
|
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
221
|
+
// Feature-gate: link only the skills whose `requires_feature` frontmatter is
|
|
222
|
+
// satisfied by this consumer's `features.*` (fail-open when config is
|
|
223
|
+
// unavailable → link everything). Resolved ONCE and applied to EVERY tool
|
|
224
|
+
// from this single code path — the gate is shared semantics, so Claude and
|
|
225
|
+
// Codex stay identical by construction. See src/utils/skill-gate.js.
|
|
226
|
+
const gate = require('./skill-gate').resolveSkillGate(frameworkSkillsDir, this.cwd);
|
|
227
|
+
const frameworkSkills = gate.toLink;
|
|
228
|
+
aggregate.gatedOff = gate.gatedOff.slice();
|
|
229
|
+
if (gate.gatedOff.length) {
|
|
230
|
+
UI.info(`Feature-gate: ${gate.gatedOff.length} skill(s) skipped (gating feature off): ${gate.gatedOff.join(', ')}`);
|
|
231
|
+
}
|
|
226
232
|
|
|
227
233
|
for (const tool of tools) {
|
|
228
234
|
const result = this._mergeSkillsForTool(tool, frameworkSkills, frameworkSkillsDir);
|
|
229
235
|
aggregate.linked.push(...result.linked);
|
|
230
236
|
aggregate.skipped.push(...result.skipped);
|
|
231
237
|
aggregate.conflicts.push(...result.conflicts);
|
|
238
|
+
|
|
239
|
+
// Prune direction: remove any pre-existing framework symlink for a skill
|
|
240
|
+
// that is now gated-off (e.g. a feature flipped false after a prior
|
|
241
|
+
// install, or a fail-open install that linked everything before config
|
|
242
|
+
// existed). Only OUR framework symlinks are removed — never a real user
|
|
243
|
+
// skill dir, never a user-override symlink pointing elsewhere.
|
|
244
|
+
const pruneResult = this._pruneGatedSkillsForTool(tool, gate.gatedOff, frameworkSkillsDir);
|
|
245
|
+
aggregate.pruned.push(...pruneResult.pruned);
|
|
232
246
|
}
|
|
233
247
|
|
|
234
248
|
if (aggregate.conflicts.length > 0) {
|
|
@@ -329,6 +343,54 @@ class SymlinkUtils {
|
|
|
329
343
|
return result;
|
|
330
344
|
}
|
|
331
345
|
|
|
346
|
+
/**
|
|
347
|
+
* Prune framework skill symlinks that are now gated-off — internal.
|
|
348
|
+
*
|
|
349
|
+
* This is the reconcile (removal) direction of the feature-gate: turning a
|
|
350
|
+
* `features.*` flag off (or a fail-open first install that linked everything
|
|
351
|
+
* before config existed) must actually REMOVE the stale symlinks, or the
|
|
352
|
+
* skill-description budget never shrinks. Each `name` in `gatedOff` is a
|
|
353
|
+
* framework skill name by construction (it came from the framework catalog),
|
|
354
|
+
* so basename∈catalog is guaranteed; we still verify the link RESOLVES to our
|
|
355
|
+
* framework source for that exact skill before unlinking. Safety invariants:
|
|
356
|
+
* - never touch a real directory (a user-authored skill of the same name);
|
|
357
|
+
* - never touch a symlink pointing ANYWHERE ELSE (a user override, cf. the
|
|
358
|
+
* `user-symlink-override` branch in _mergeSkillsForTool).
|
|
359
|
+
*/
|
|
360
|
+
_pruneGatedSkillsForTool(toolName, gatedOff, frameworkSkillsDir) {
|
|
361
|
+
const { getAdapter } = require('./tool-adapters');
|
|
362
|
+
const adapter = getAdapter(toolName, this.cwd);
|
|
363
|
+
const result = { pruned: [] };
|
|
364
|
+
if (!gatedOff || !gatedOff.length) return result;
|
|
365
|
+
|
|
366
|
+
const skillsRel = adapter.skillsDir();
|
|
367
|
+
const userSkillsDir = path.join(this.cwd, skillsRel);
|
|
368
|
+
if (!fs.existsSync(userSkillsDir)) return result;
|
|
369
|
+
|
|
370
|
+
for (const name of gatedOff) {
|
|
371
|
+
const linkPath = path.join(userSkillsDir, name);
|
|
372
|
+
let lstat = null;
|
|
373
|
+
try { lstat = fs.lstatSync(linkPath); } catch (_) { continue; /* absent */ }
|
|
374
|
+
|
|
375
|
+
// Only ever remove a symlink — a real dir here is a user-authored skill.
|
|
376
|
+
if (!lstat.isSymbolicLink()) continue;
|
|
377
|
+
|
|
378
|
+
const current = fs.readlinkSync(linkPath);
|
|
379
|
+
const resolved = path.resolve(path.dirname(linkPath), current);
|
|
380
|
+
const frameworkTarget = path.join(frameworkSkillsDir, name);
|
|
381
|
+
|
|
382
|
+
// Unlink ONLY when it resolves to OUR framework source for this skill.
|
|
383
|
+
// A symlink pointing elsewhere is a deliberate user override → leave it.
|
|
384
|
+
if (resolved === frameworkTarget) {
|
|
385
|
+
fs.unlinkSync(linkPath);
|
|
386
|
+
UI.info(`[${adapter.label}] Skill unlinked (feature gated off): ${path.join(skillsRel, name)}`);
|
|
387
|
+
result.pruned.push({ tool: toolName, name });
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
return result;
|
|
392
|
+
}
|
|
393
|
+
|
|
332
394
|
// -----------------------------------------------------------------------
|
|
333
395
|
// Public composite operations
|
|
334
396
|
// -----------------------------------------------------------------------
|
|
@@ -827,7 +889,10 @@ class SymlinkUtils {
|
|
|
827
889
|
UI.warning(`[${adapter.label}] Legacy bulk skills symlink at ${skillsRel}. Run \`npx baldart update\` to convert to per-item.`);
|
|
828
890
|
allValid = false;
|
|
829
891
|
} else {
|
|
830
|
-
|
|
892
|
+
// Sample ONLY always-linked skills — never feature-gated ones (e.g.
|
|
893
|
+
// prd/capture), which are legitimately absent when their feature is
|
|
894
|
+
// off and would make this probe brittle / falsely alarming.
|
|
895
|
+
const sample = ['skill-creator', 'bug', 'simplify', 'overlay', 'find-skills'];
|
|
831
896
|
let frameworkLinks = 0;
|
|
832
897
|
sample.forEach(name => {
|
|
833
898
|
const p = path.join(skillsDir, name);
|