@haus-tech/haus-workflow 0.16.3 → 0.17.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 +6 -0
- package/dist/cli.js +22 -7
- package/library/catalog/validation-rules.json +2 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.17.0](https://github.com/WeAreHausTech/haus-workflow/compare/v0.16.3...v0.17.0) (2026-06-09)
|
|
4
|
+
|
|
5
|
+
### Features
|
|
6
|
+
|
|
7
|
+
- **catalog:** support curated superpowers skills and commands ([#80](https://github.com/WeAreHausTech/haus-workflow/issues/80)) ([2e49c80](https://github.com/WeAreHausTech/haus-workflow/commit/2e49c80d6780e8ff753536f2d4042b4ce7fa2ae8))
|
|
8
|
+
|
|
3
9
|
## [0.16.3](https://github.com/WeAreHausTech/haus-workflow/compare/v0.16.2...v0.16.3) (2026-06-09)
|
|
4
10
|
|
|
5
11
|
### Bug Fixes
|
package/dist/cli.js
CHANGED
|
@@ -137,7 +137,7 @@ async function syncRemoteCatalog() {
|
|
|
137
137
|
let unchanged = 0;
|
|
138
138
|
const failed = [];
|
|
139
139
|
for (const item of items) {
|
|
140
|
-
if (item.type !== "skill" && item.type !== "agent" && item.type !== "template" || !item.path)
|
|
140
|
+
if (item.type !== "skill" && item.type !== "agent" && item.type !== "template" && item.type !== "command" || !item.path)
|
|
141
141
|
continue;
|
|
142
142
|
if (!isSafeCatalogPath(item.path)) {
|
|
143
143
|
warn(`Skipping ${item.id}: invalid path "${item.path}"`);
|
|
@@ -1240,7 +1240,7 @@ async function writeClaudeFiles(root, dryRun, selectedIds, opts = {}) {
|
|
|
1240
1240
|
}
|
|
1241
1241
|
}
|
|
1242
1242
|
const sourcePath = catalogItemContentPath(contentRoot, manifestItem);
|
|
1243
|
-
const target = item.type === "agent" ? "agents" : item.type === "template" ? "templates" : "skills";
|
|
1243
|
+
const target = item.type === "agent" ? "agents" : item.type === "template" ? "templates" : item.type === "command" ? "commands" : "skills";
|
|
1244
1244
|
const destination = claudePath(root, target, path12.basename(sourcePath));
|
|
1245
1245
|
if (await fs10.pathExists(sourcePath)) {
|
|
1246
1246
|
if (dryRun) {
|
|
@@ -1549,7 +1549,8 @@ var validation_rules_default = {
|
|
|
1549
1549
|
"baseline",
|
|
1550
1550
|
"project-instructions"
|
|
1551
1551
|
],
|
|
1552
|
-
patternTagSuffixes: ["-patterns"]
|
|
1552
|
+
patternTagSuffixes: ["-patterns"],
|
|
1553
|
+
skillSectionExemptSources: ["curated"]
|
|
1553
1554
|
};
|
|
1554
1555
|
|
|
1555
1556
|
// src/catalog/validation-rules.ts
|
|
@@ -1557,6 +1558,10 @@ var toRegExp = (r) => new RegExp(r.source, r.flags);
|
|
|
1557
1558
|
var FORBIDDEN_TAGS = validation_rules_default.forbiddenTags;
|
|
1558
1559
|
var BANNED_AGENT_PHRASES = validation_rules_default.bannedAgentPhrases;
|
|
1559
1560
|
var REQUIRED_SKILL_SECTIONS = validation_rules_default.requiredSkillSections;
|
|
1561
|
+
var SKILL_SECTION_EXEMPT_SOURCES = validation_rules_default.skillSectionExemptSources;
|
|
1562
|
+
function isVerbatimSuperpowersMarkdownPath(rel) {
|
|
1563
|
+
return rel.replace(/\\/g, "/").includes("/superpowers/");
|
|
1564
|
+
}
|
|
1560
1565
|
var REQUIRED_AGENT_SECTIONS = validation_rules_default.requiredAgentSections;
|
|
1561
1566
|
var RISKY_INSTALL_PATTERNS = validation_rules_default.riskyInstallPatterns.map(toRegExp);
|
|
1562
1567
|
var ALLOWED_NPX_PATTERN = toRegExp(validation_rules_default.allowedNpxPattern);
|
|
@@ -4130,7 +4135,7 @@ function auditManifestStructure(items) {
|
|
|
4130
4135
|
} else {
|
|
4131
4136
|
seenIds.set(item.id, i);
|
|
4132
4137
|
}
|
|
4133
|
-
if (item.type === "skill" || item.type === "agent" || item.type === "template") {
|
|
4138
|
+
if (item.type === "skill" || item.type === "agent" || item.type === "template" || item.type === "command") {
|
|
4134
4139
|
if (!item.path) {
|
|
4135
4140
|
failures.push(`${item.id}: missing path`);
|
|
4136
4141
|
} else {
|
|
@@ -4168,8 +4173,11 @@ function auditShippedFiles(manifestDir, items) {
|
|
|
4168
4173
|
continue;
|
|
4169
4174
|
}
|
|
4170
4175
|
const text = fs18.readFileSync(skillMd, "utf8");
|
|
4171
|
-
|
|
4172
|
-
|
|
4176
|
+
const skillSectionExempt = SKILL_SECTION_EXEMPT_SOURCES.includes(item.source) && item.whenToUse && item.whenNotToUse;
|
|
4177
|
+
if (!skillSectionExempt) {
|
|
4178
|
+
for (const section of REQUIRED_SKILL_SECTIONS) {
|
|
4179
|
+
if (!text.includes(section)) failures.push(`${item.id}: SKILL.md missing ${section}`);
|
|
4180
|
+
}
|
|
4173
4181
|
}
|
|
4174
4182
|
failures.push(
|
|
4175
4183
|
...auditForbiddenTagsInText(text, `${item.id}: ${path26.relative(manifestDir, skillMd)}`)
|
|
@@ -4198,6 +4206,12 @@ function auditShippedFiles(manifestDir, items) {
|
|
|
4198
4206
|
continue;
|
|
4199
4207
|
}
|
|
4200
4208
|
failures.push(...auditTemplateContent(manifestDir, absPath, item.id));
|
|
4209
|
+
} else if (item.type === "command") {
|
|
4210
|
+
if (!fs18.existsSync(absPath)) {
|
|
4211
|
+
failures.push(`${item.id}: missing command file ${item.path}`);
|
|
4212
|
+
continue;
|
|
4213
|
+
}
|
|
4214
|
+
failures.push(...auditTemplateContent(manifestDir, absPath, item.id));
|
|
4201
4215
|
}
|
|
4202
4216
|
}
|
|
4203
4217
|
return failures;
|
|
@@ -4224,13 +4238,14 @@ function auditTemplateContent(manifestDir, absPath, itemId) {
|
|
|
4224
4238
|
}
|
|
4225
4239
|
function auditMarkdownContent(manifestDir) {
|
|
4226
4240
|
const failures = [];
|
|
4227
|
-
const dirs = ["skills", "agents", "templates"];
|
|
4241
|
+
const dirs = ["skills", "agents", "templates", "commands"];
|
|
4228
4242
|
for (const dir of dirs) {
|
|
4229
4243
|
const abs = path26.join(manifestDir, dir);
|
|
4230
4244
|
if (!fs18.existsSync(abs)) continue;
|
|
4231
4245
|
walkMd(abs, (file) => {
|
|
4232
4246
|
const text = fs18.readFileSync(file, "utf8");
|
|
4233
4247
|
const rel = path26.relative(manifestDir, file);
|
|
4248
|
+
if (isVerbatimSuperpowersMarkdownPath(rel)) return;
|
|
4234
4249
|
const lines = text.split(/\r?\n/);
|
|
4235
4250
|
for (let i = 0; i < lines.length; i++) {
|
|
4236
4251
|
const line2 = lines[i] ?? "";
|