@haus-tech/haus-workflow 0.16.2 → 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 CHANGED
@@ -1,5 +1,17 @@
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
+
9
+ ## [0.16.3](https://github.com/WeAreHausTech/haus-workflow/compare/v0.16.2...v0.16.3) (2026-06-09)
10
+
11
+ ### Bug Fixes
12
+
13
+ - **install:** keep skill frontmatter valid by stamping marker as a field ([#79](https://github.com/WeAreHausTech/haus-workflow/issues/79)) ([76ddbf1](https://github.com/WeAreHausTech/haus-workflow/commit/76ddbf1248b8844538363dcfd3744cd975d96f52))
14
+
3
15
  ## [0.16.2](https://github.com/WeAreHausTech/haus-workflow/compare/v0.16.1...v0.16.2) (2026-06-09)
4
16
 
5
17
  ## [0.16.1](https://github.com/WeAreHausTech/haus-workflow/compare/v0.16.0...v0.16.1) (2026-06-09)
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);
@@ -3323,6 +3328,8 @@ import fs15 from "fs-extra";
3323
3328
  // src/install/header.ts
3324
3329
  var MD_PREFIX = "<!-- HAUS-MANAGED";
3325
3330
  var MD_SUFFIX = " -->";
3331
+ var FM_FENCE = "---";
3332
+ var FM_KEY = "haus_managed";
3326
3333
  function parseAttrs(raw) {
3327
3334
  const idMatch = /\bid=(\S+)/.exec(raw);
3328
3335
  const vMatch = /\bv=(\S+)/.exec(raw);
@@ -3330,20 +3337,67 @@ function parseAttrs(raw) {
3330
3337
  if (!idMatch || !vMatch || !srcMatch) return void 0;
3331
3338
  return { stableId: idMatch[1], schemaVersion: vMatch[1], source: srcMatch[1] };
3332
3339
  }
3340
+ function isFence(line2) {
3341
+ return (line2 ?? "").replace(/\r$/, "") === FM_FENCE;
3342
+ }
3343
+ function hasFrontmatter(content2) {
3344
+ return isFence(content2.split("\n", 1)[0]);
3345
+ }
3346
+ function frontmatterMarkerValue(content2) {
3347
+ const lines = content2.split("\n");
3348
+ if (!isFence(lines[0])) return void 0;
3349
+ for (let i = 1; i < lines.length; i++) {
3350
+ if (isFence(lines[i])) return void 0;
3351
+ const m = /^haus_managed:\s*"?(.*?)"?\s*$/.exec(lines[i]);
3352
+ if (m) return m[1];
3353
+ }
3354
+ return void 0;
3355
+ }
3333
3356
  function parseMarkdownHeader(content2) {
3334
3357
  const firstLine = content2.split("\n")[0] ?? "";
3335
- if (!firstLine.startsWith(MD_PREFIX)) return void 0;
3336
- return parseAttrs(firstLine);
3358
+ if (firstLine.startsWith(MD_PREFIX)) return parseAttrs(firstLine);
3359
+ const fmValue = frontmatterMarkerValue(content2);
3360
+ if (fmValue !== void 0) return parseAttrs(fmValue);
3361
+ return void 0;
3337
3362
  }
3338
3363
  function buildMarkdownHeader(h) {
3339
3364
  return `${MD_PREFIX} id=${h.stableId} v=${h.schemaVersion} source=${h.source}${MD_SUFFIX}`;
3340
3365
  }
3366
+ function buildMarkerValue(h) {
3367
+ return `id=${h.stableId} v=${h.schemaVersion} source=${h.source}`;
3368
+ }
3369
+ function stampFrontmatter(content2, h) {
3370
+ const lines = content2.split("\n");
3371
+ let close = -1;
3372
+ for (let i = 1; i < lines.length; i++) {
3373
+ if (isFence(lines[i])) {
3374
+ close = i;
3375
+ break;
3376
+ }
3377
+ }
3378
+ if (close === -1) return content2;
3379
+ const fields2 = [];
3380
+ for (let i = 1; i < close; i++) {
3381
+ if (/^haus_managed:/.test(lines[i])) continue;
3382
+ fields2.push(lines[i]);
3383
+ }
3384
+ const rebuilt = [
3385
+ FM_FENCE,
3386
+ ...fields2,
3387
+ `${FM_KEY}: "${buildMarkerValue(h)}"`,
3388
+ ...lines.slice(close)
3389
+ // closing fence + body
3390
+ ];
3391
+ return rebuilt.join("\n");
3392
+ }
3341
3393
  function stampMarkdown(content2, h) {
3394
+ if (hasFrontmatter(content2)) return stampFrontmatter(content2, h);
3342
3395
  const header = buildMarkdownHeader(h);
3343
- const existing = parseMarkdownHeader(content2);
3344
- if (existing) {
3345
- const rest = content2.slice(content2.indexOf("\n") + 1);
3346
- return `${header}
3396
+ const firstLine = content2.split("\n")[0] ?? "";
3397
+ if (firstLine.startsWith(MD_PREFIX)) {
3398
+ const nl = content2.indexOf("\n");
3399
+ const rest = nl === -1 ? "" : content2.slice(nl + 1);
3400
+ return rest === "" ? header : `${header}
3347
3401
  ${rest}`;
3348
3402
  }
3349
3403
  return `${header}
@@ -4081,7 +4135,7 @@ function auditManifestStructure(items) {
4081
4135
  } else {
4082
4136
  seenIds.set(item.id, i);
4083
4137
  }
4084
- if (item.type === "skill" || item.type === "agent" || item.type === "template") {
4138
+ if (item.type === "skill" || item.type === "agent" || item.type === "template" || item.type === "command") {
4085
4139
  if (!item.path) {
4086
4140
  failures.push(`${item.id}: missing path`);
4087
4141
  } else {
@@ -4119,8 +4173,11 @@ function auditShippedFiles(manifestDir, items) {
4119
4173
  continue;
4120
4174
  }
4121
4175
  const text = fs18.readFileSync(skillMd, "utf8");
4122
- for (const section of REQUIRED_SKILL_SECTIONS) {
4123
- if (!text.includes(section)) failures.push(`${item.id}: SKILL.md missing ${section}`);
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
+ }
4124
4181
  }
4125
4182
  failures.push(
4126
4183
  ...auditForbiddenTagsInText(text, `${item.id}: ${path26.relative(manifestDir, skillMd)}`)
@@ -4149,6 +4206,12 @@ function auditShippedFiles(manifestDir, items) {
4149
4206
  continue;
4150
4207
  }
4151
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));
4152
4215
  }
4153
4216
  }
4154
4217
  return failures;
@@ -4175,13 +4238,14 @@ function auditTemplateContent(manifestDir, absPath, itemId) {
4175
4238
  }
4176
4239
  function auditMarkdownContent(manifestDir) {
4177
4240
  const failures = [];
4178
- const dirs = ["skills", "agents", "templates"];
4241
+ const dirs = ["skills", "agents", "templates", "commands"];
4179
4242
  for (const dir of dirs) {
4180
4243
  const abs = path26.join(manifestDir, dir);
4181
4244
  if (!fs18.existsSync(abs)) continue;
4182
4245
  walkMd(abs, (file) => {
4183
4246
  const text = fs18.readFileSync(file, "utf8");
4184
4247
  const rel = path26.relative(manifestDir, file);
4248
+ if (isVerbatimSuperpowersMarkdownPath(rel)) return;
4185
4249
  const lines = text.split(/\r?\n/);
4186
4250
  for (let i = 0; i < lines.length; i++) {
4187
4251
  const line2 = lines[i] ?? "";
@@ -142,5 +142,6 @@
142
142
  "baseline",
143
143
  "project-instructions"
144
144
  ],
145
- "patternTagSuffixes": ["-patterns"]
145
+ "patternTagSuffixes": ["-patterns"],
146
+ "skillSectionExemptSources": ["curated"]
146
147
  }
@@ -1,8 +1,6 @@
1
- ## <!-- HAUS-MANAGED id=skill.haus-workflow v=2 source=@haus-tech/haus-workflow@0.1.0 -->
2
-
1
+ ---
3
2
  name: haus-workflow
4
3
  description: Haus all-in-one workflow skill. Handles project setup, update, catalog refresh, and CLAUDE.md regeneration. Invoke with a task name or without to get a menu.
5
-
6
4
  ---
7
5
 
8
6
  # haus-workflow
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@haus-tech/haus-workflow",
3
- "version": "0.16.2",
3
+ "version": "0.17.0",
4
4
  "description": "Haus AI workflow CLI for Claude Code.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -18,9 +18,7 @@
18
18
  "library/catalog",
19
19
  "tests/fixtures/catalog",
20
20
  "README.md",
21
- "CHANGELOG.md",
22
- "LICENSE",
23
- "NOTICE"
21
+ "CHANGELOG.md"
24
22
  ],
25
23
  "scripts": {
26
24
  "build": "tsup src/cli.ts --format esm --dts --clean --out-dir dist --external @inquirer/checkbox",
@@ -34,8 +32,6 @@
34
32
  "typecheck": "tsc --noEmit",
35
33
  "typecheck:scripts": "tsc --noEmit --project tsconfig.scripts.json",
36
34
  "pack:local": "yarn pack",
37
- "publish:dry": "npm pack --dry-run",
38
- "publish:public": "yarn npm publish --access public",
39
35
  "release": "GITHUB_TOKEN=$(gh auth token) release-it",
40
36
  "release:dry": "GITHUB_TOKEN=$(gh auth token) release-it --dry-run",
41
37
  "prepack": "yarn build",