@haus-tech/haus-workflow 0.11.1 → 0.12.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.
@@ -1,63 +1,103 @@
1
- ## <!-- HAUS-MANAGED id=skill.haus-workflow v=1 source=@haus-tech/haus-workflow@0.1.0 -->
1
+ ## <!-- HAUS-MANAGED id=skill.haus-workflow v=2 source=@haus-tech/haus-workflow@0.1.0 -->
2
2
 
3
3
  name: haus-workflow
4
- description: Haus all-in-one workflow skill. Handles project setup, update, catalog refresh, and CLAUDE.md regeneration.
4
+ 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
5
 
6
6
  ---
7
7
 
8
8
  # haus-workflow
9
9
 
10
- All-in-one entry point for the Haus AI workflow. Covers setup, update, sync, catalog refresh, and root `CLAUDE.md` regeneration.
10
+ All-in-one entry point for the Haus AI workflow.
11
11
 
12
- ## Use when
12
+ ## Invocation
13
13
 
14
- - Setting up a project for the first time (`haus init`).
15
- - Updating an existing project setup (`.claude/` + `.haus-workflow/`).
16
- - Checking for a newer `@haus-tech/haus-workflow` package and refreshing `~/.claude/` accordingly.
17
- - Fetching catalog updates (`haus update`).
18
- - Regenerating the root `CLAUDE.md` import block.
14
+ `/haus-workflow [task]`
19
15
 
20
- ## Do not use when
16
+ `task` is optional. If omitted, present a task menu (see below). If provided, map it to a command and run immediately.
21
17
 
22
- - User needs a security, code, or test review — use the dedicated reviewer agents instead.
18
+ ## Task aliases commands
19
+
20
+ | Alias(es) | Command | What it does |
21
+ | ------------------------------------ | -------------------- | ---------------------------------------------- |
22
+ | `init`, `setup` | `haus init` | First-time project setup |
23
+ | `apply`, `refresh`, `update-project` | `haus apply --write` | Re-run setup / refresh `.claude/` context |
24
+ | `update`, `upgrade` | `haus update` | Update npm package + catalog + `~/.claude/` |
25
+ | `catalog` | `haus update` | Fetch latest catalog (same command as update) |
26
+ | `doctor`, `check` | `haus doctor` | Check for install drift |
27
+ | `install`, `global` | `haus install` | Seed `~/.claude/` with haus-owned files |
28
+ | `uninstall` | `haus uninstall` | Remove all haus global files from `~/.claude/` |
29
+ | `claude-md`, `regenerate` | `haus apply --write` | Regenerate root `CLAUDE.md` import block |
30
+
31
+ ## Step 1 — Determine the task
32
+
33
+ **If a task argument was passed:** look it up in the alias table above. If no match, tell the user and list valid options. If matched, skip to Step 2.
34
+
35
+ **If no task was passed:** use `AskUserQuestion` to present this menu:
36
+
37
+ ```
38
+ Question: "What would you like to do?"
39
+ Options:
40
+ 1. Set up this project for the first time
41
+ (haus init — scans repo, writes .haus-workflow/, updates CLAUDE.md)
42
+ 2. Refresh project setup
43
+ (haus apply --write — re-runs setup, regenerates CLAUDE.md imports)
44
+ 3. Update haus package + catalog + global files
45
+ (haus update — checks npm for new version, fetches catalog, refreshes ~/.claude/)
46
+ 4. Fetch catalog updates only
47
+ (haus update — same command; pulls latest workflow templates and lockfile)
48
+ 5. Regenerate CLAUDE.md import block
49
+ (haus apply --write — rewrites the @-import block at the root CLAUDE.md)
50
+ ```
51
+
52
+ Map the user's selection to the command from the alias table, then continue to Step 2.
53
+
54
+ ## Step 2 — Run the command
23
55
 
24
- ## How to invoke
56
+ Run the mapped command via Bash. Quote the exact command you are running before executing it.
25
57
 
26
- Run the relevant CLI command for the task:
58
+ ## Step 3 Post-run steps
27
59
 
28
- | Goal | Command |
29
- | ------------------------------------------- | -------------------- |
30
- | First-time project setup | `haus init` |
31
- | Re-run setup / refresh context | `haus apply --write` |
32
- | Update package + catalog + `~/.claude/` | `haus update` |
33
- | Check install drift | `haus doctor` |
34
- | Install global haus files into `~/.claude/` | `haus install` |
35
- | Remove all haus global files | `haus uninstall` |
60
+ After the command completes, follow the relevant post-run steps below.
36
61
 
37
- ## Setup flow (init)
62
+ ### After `haus init`
38
63
 
39
- 1. Run `haus init` in the project root.
40
- 2. Haus scans the repo, generates `.haus-workflow/context-map.json` and `.haus-workflow/recommendation.json`.
41
- 3. Writes `.haus-workflow/WORKFLOW.md` (managed, from catalog template) and `.haus-workflow/project.md`.
42
- 4. Writes `.haus-workflow/workflow-config.md` if it does not exist (project-owned). The CLI seeds what the scan knows (package manager → inferred test/audit commands). After the CLI step, open `workflow-config.md` and complete it using project context:
43
- - `package.json` scripts exact test, lint, typecheck, build commands
44
- - `docs/` directory presence of SPEC.md, DESIGN.md, UX.md
45
- - Dependencies validation library (zod, yup, joi…), pre-commit tool
46
- - Project domain highest-stakes logic (payment, auth, medical…)
47
- 5. Ensures root `CLAUDE.md` imports `@.haus-workflow/WORKFLOW.md`, `@.haus-workflow/workflow-config.md`, and `@.haus-workflow/project.md`.
48
- 6. Prints a summary; user confirms before writes.
64
+ 1. Open `.haus-workflow/workflow-config.md`.
65
+ 2. Check for unfilled placeholders (`TODO`, `n/a`, empty values) in:
66
+ - Test, lint, typecheck, build commands confirm against `package.json` scripts.
67
+ - Docs paths check whether `docs/SPEC.md`, `docs/DESIGN.md`, `docs/UX.md` exist.
68
+ - Validation library — check `package.json` dependencies for `zod`, `yup`, `joi`, `valibot`.
69
+ - Pre-commit tool check for `.husky/`, `lefthook.yml`, `.pre-commit-config.yaml`.
70
+ - Highest-stakes logic ask the user if unclear.
71
+ 3. Fill in every unfilled field. Do not leave placeholders.
72
+ 4. Confirm with the user that `workflow-config.md` is complete before proceeding.
49
73
 
50
- ## Update flow
74
+ ### After `haus apply --write`
51
75
 
52
- `haus update` runs in order:
76
+ Verify that the root `CLAUDE.md` imports all three haus files:
53
77
 
54
- 1. Checks installed npm package version vs. latest on registry. If newer: prints `npm i -g @haus-tech/haus-workflow` instruction.
55
- 2. After any version change, re-runs `haus install` to refresh `~/.claude/` haus files.
56
- 3. Fetches latest catalog from `haus-workflow-catalog`, writes cache, updates lockfile.
57
- 4. Re-renders `.haus-workflow/project.md`. Re-applies `.haus-workflow/WORKFLOW.md` if catalog template version changed (hash-based; skips if user-modified). If `.haus-workflow/workflow-config.md` does not exist, writes and completes it (same as init step 4). If WORKFLOW.md was updated, prompt the user: "WORKFLOW.md has been updated. Review workflow-config.md to check if any new configuration sections need project-specific values."
78
+ ```
79
+ @.haus-workflow/WORKFLOW.md
80
+ @.haus-workflow/workflow-config.md
81
+ @.haus-workflow/project.md
82
+ ```
58
83
 
59
- ## Global install
84
+ If any import is missing, add it.
60
85
 
61
- `haus install` seeds `~/.claude/` with haus-owned files. Each file carries a `<!-- HAUS-MANAGED ... -->` header so the CLI can update or remove it safely without touching user content.
86
+ ### After `haus update`
62
87
 
63
- `haus uninstall` reverses this: removes every HAUS-MANAGED file and strips haus hook entries from `~/.claude/settings.json`. User-owned files are never deleted.
88
+ 1. If CLI output says a new version is available, run `npm i -g @haus-tech/haus-workflow` and confirm the version bump.
89
+ 2. If `WORKFLOW.md` was updated, remind the user: "WORKFLOW.md updated — review `workflow-config.md` for any new sections that need project-specific values."
90
+ 3. If CLI output shows catalog changes, summarise which templates changed.
91
+
92
+ ### After `haus doctor`
93
+
94
+ Report findings clearly. For each drift item, suggest the exact fix command.
95
+
96
+ ### After `haus install` / `haus uninstall`
97
+
98
+ Confirm which files were written to or removed from `~/.claude/`. No further steps.
99
+
100
+ ## Do not use when
101
+
102
+ - User needs a security, code, or test review — use the dedicated reviewer agents instead.
103
+ - User asks about workflow concepts or wants to understand the WORKFLOW.md standard — answer directly from the loaded context.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@haus-tech/haus-workflow",
3
- "version": "0.11.1",
3
+ "version": "0.12.0",
4
4
  "description": "Haus AI workflow CLI for Claude Code.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -13,6 +13,7 @@
13
13
  "homepage": "https://github.com/WeAreHausTech/haus-workflow",
14
14
  "files": [
15
15
  "dist",
16
+ "scripts/postinstall.mjs",
16
17
  "library/global",
17
18
  "library/catalog",
18
19
  "tests/fixtures/catalog",
@@ -24,7 +25,7 @@
24
25
  "scripts": {
25
26
  "build": "tsup src/cli.ts --format esm --dts --clean --out-dir dist --external @inquirer/checkbox",
26
27
  "dev": "tsx src/cli.ts",
27
- "test": "node --test tests/**/*.test.js",
28
+ "test": "node --import tsx --test tests/**/*.test.js",
28
29
  "lint": "eslint src scripts",
29
30
  "format:check": "prettier --check .",
30
31
  "format": "prettier --write .",
@@ -37,7 +38,8 @@
37
38
  "release:dry": "GITHUB_TOKEN=$(gh auth token) release-it --dry-run",
38
39
  "prepack": "yarn build",
39
40
  "verify": "yarn typecheck && yarn typecheck:scripts && yarn lint && yarn build && yarn test",
40
- "prepare": "husky",
41
+ "postinstall": "node ./scripts/postinstall.mjs || true",
42
+ "prepare": "lefthook install || true",
41
43
  "security:audit": "yarn npm audit -A -R --severity high --environment production"
42
44
  },
43
45
  "dependencies": {
@@ -62,8 +64,7 @@
62
64
  "@typescript-eslint/parser": "8.59.3",
63
65
  "eslint": "9.39.4",
64
66
  "eslint-plugin-import": "2.32.0",
65
- "husky": "9.1.7",
66
- "lint-staged": "17.0.4",
67
+ "lefthook": "1.13.6",
67
68
  "prettier": "3.8.3",
68
69
  "release-it": "20.0.1",
69
70
  "tsup": "8.5.1",
@@ -77,10 +78,9 @@
77
78
  "access": "public"
78
79
  },
79
80
  "packageManager": "yarn@4.15.0",
80
- "lint-staged": {
81
- "**/*.ts": [
82
- "eslint",
83
- "prettier --write"
84
- ]
81
+ "dependenciesMeta": {
82
+ "lefthook": {
83
+ "built": true
84
+ }
85
85
  }
86
86
  }
@@ -0,0 +1,62 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * npm postinstall hook. On a GLOBAL install of @haus-tech/haus-workflow, runs
4
+ * `haus install --postinstall` automatically so a non-developer gets a working
5
+ * Claude Code setup with zero manual steps — then the CLI prints exactly what it
6
+ * changed in ~/.claude and how to undo it.
7
+ *
8
+ * Fail-open by design: this must NEVER break `npm install`. Every gate that isn't
9
+ * satisfied is a silent no-op, and the whole body is wrapped so any error still
10
+ * exits 0. Plain Node ESM (no tsx) because consumers don't have the dev toolchain.
11
+ */
12
+ import { spawnSync } from 'node:child_process'
13
+ import fs from 'node:fs'
14
+ import path from 'node:path'
15
+ import { fileURLToPath } from 'node:url'
16
+
17
+ /**
18
+ * Pure gate: decides whether the postinstall should run. Kept side-effect-free and
19
+ * exported so it can be unit-tested across the full env/fs matrix without spawning npm.
20
+ *
21
+ * @param {{ env: Record<string, string | undefined>, distExists: boolean, srcExists: boolean }} input
22
+ * @returns {{ run: boolean, reason: string }}
23
+ */
24
+ export function shouldRunPostinstall({ env, distExists, srcExists }) {
25
+ if (env.npm_config_global !== 'true') return { run: false, reason: 'not a global install' }
26
+ if (env.CI) return { run: false, reason: 'CI environment' }
27
+ if (env.HAUS_NO_POSTINSTALL === '1') return { run: false, reason: 'HAUS_NO_POSTINSTALL=1' }
28
+ if (!distExists) return { run: false, reason: 'dist/cli.js missing' }
29
+ // Published tarballs omit src/; its presence means we're in the package's own
30
+ // dev checkout, where a local `yarn install` must not self-trigger.
31
+ if (srcExists) return { run: false, reason: 'running inside the package dev checkout' }
32
+ return { run: true, reason: 'global install' }
33
+ }
34
+
35
+ /** Entry point: runs only when this file is invoked directly (not when imported by a test). */
36
+ function main() {
37
+ try {
38
+ const pkgRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..')
39
+ const cliPath = path.join(pkgRoot, 'dist', 'cli.js')
40
+ const decision = shouldRunPostinstall({
41
+ env: process.env,
42
+ distExists: fs.existsSync(cliPath),
43
+ srcExists: fs.existsSync(path.join(pkgRoot, 'src')),
44
+ })
45
+
46
+ if (!decision.run) {
47
+ if (process.env.HAUS_DEBUG) console.error(`[haus postinstall] skipped: ${decision.reason}`)
48
+ process.exit(0)
49
+ }
50
+
51
+ // Non-fatal: a nonzero CLI exit must not fail `npm install`.
52
+ spawnSync(process.execPath, [cliPath, 'install', '--postinstall'], { stdio: 'inherit' })
53
+ } catch (err) {
54
+ if (process.env.HAUS_DEBUG) console.error(`[haus postinstall] error (ignored): ${err}`)
55
+ }
56
+ process.exit(0)
57
+ }
58
+
59
+ // Run only as a script, never when imported.
60
+ if (process.argv[1] && fileURLToPath(import.meta.url) === path.resolve(process.argv[1])) {
61
+ main()
62
+ }
package/tests/README.md CHANGED
@@ -8,12 +8,11 @@ yarn test
8
8
 
9
9
  ## Structure
10
10
 
11
- | Path | Contents |
12
- | ----------------- | -------------------------------------------------- |
13
- | `tests/*.test.js` | Unit and integration tests |
14
- | `tests/helpers/` | Shared test utilities |
15
- | `tests/fixtures/` | Static fixture repos used by tests |
16
- | `tests/golden/` | Golden output snapshots for scan/recommend/context |
11
+ | Path | Contents |
12
+ | ----------------- | ----------------------------------- |
13
+ | `tests/*.test.js` | Unit and integration tests |
14
+ | `tests/helpers/` | Shared test utilities |
15
+ | `tests/fixtures/` | Static fixture repos used by tests |
17
16
 
18
17
  ## helpers/fixture-runner.js
19
18
 
@@ -22,8 +21,6 @@ Utilities for running the compiled CLI against fixture repos in a temp directory
22
21
  - `cloneFixtureToTemp(fixtureName)` — copies `tests/fixtures/repos/<name>` to a temp dir, returns the path
23
22
  - `runHaus(cwd, command)` — runs `node dist/cli.js <command>` in `cwd`, returns stdout
24
23
  - `readHausJson(cwd, fileName)` — reads `.haus-workflow/<fileName>` as parsed JSON
25
- - `normalizeRecommendationForGolden(rec)` — stable sort for golden snapshot comparison
26
- - `normalizeContextForGolden(ctx)` — stable sort for golden snapshot comparison
27
24
 
28
25
  Tests that use `fixture-runner.js` require a built `dist/` — run `yarn build && yarn test`, or use `yarn verify` which builds before running tests.
29
26
 
@@ -47,10 +44,6 @@ Full fixture repos scanned by integration tests and golden tests. Each subdirect
47
44
  | `wordpress-bedrock-site` | WordPress Bedrock (Composer) |
48
45
  | `wordpress-with-node-tooling` | WordPress + Node tooling (pnpm) |
49
46
 
50
- ### fixtures/findings/
51
-
52
- QA findings records (see `fixtures/findings/README.md`). Observational only — not gated by any test.
53
-
54
47
  ### Other fixture dirs
55
48
 
56
49
  - `fixtures/dotnet-service/` — unsupported stack (C#/.NET), used to verify unsupported-stack handling
@@ -59,12 +52,3 @@ QA findings records (see `fixtures/findings/README.md`). Observational only —
59
52
  - `fixtures/vendure-plugin/` — minimal Vendure plugin package
60
53
  - `fixtures/laravel-app/`, `fixtures/next-react-app/`, `fixtures/wordpress-bedrock/` — legacy shallow fixtures; prefer `fixtures/repos/` equivalents for new tests
61
54
 
62
- ## golden/
63
-
64
- Snapshot files for `context-goldens.test.js` and `recommender.test.js`. Keyed by fixture name.
65
-
66
- - `golden/scans/` — `scanProject` output
67
- - `golden/recommendations/` — `runRecommend` output (normalized)
68
- - `golden/context/` — `runContext` output (normalized)
69
-
70
- To regenerate goldens after intentional recommender changes, delete the relevant `.json` file and re-run `yarn test` — the test will write the new snapshot and pass on the next run.
@@ -2,25 +2,6 @@
2
2
  "version": "0.1.0",
3
3
  "_note": "Stable fixture for CLI tests. Decoupled from production catalog repo. Update manually when catalog schema changes.",
4
4
  "items": [
5
- {
6
- "id": "haus.global-engineering-rules",
7
- "source": "haus",
8
- "type": "skill",
9
- "path": "skills/global-engineering-rules",
10
- "title": "Haus global engineering rules",
11
- "purpose": "Provide baseline deterministic engineering, validation, and security guardrails.",
12
- "whenToUse": "Use as default baseline in supported Haus workflows.",
13
- "whenNotToUse": "Do not use for unsupported stacks or non-development workflows.",
14
- "references": [],
15
- "safetyNotes": ["Never read secrets or customer exports."],
16
- "tokenBudget": 1800,
17
- "tags": ["haus", "quality", "security"],
18
- "repoRoles": [],
19
- "requiresAny": [],
20
- "tokenEstimate": 1800,
21
- "installMode": "copy-selected",
22
- "default": true
23
- },
24
5
  {
25
6
  "id": "haus.nextjs-patterns",
26
7
  "source": "haus",