@haus-tech/haus-workflow 0.26.0 → 0.27.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,13 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.27.0](https://github.com/WeAreHausTech/haus-workflow/compare/v0.26.1...v0.27.0) (2026-06-15)
4
+
5
+ ### Features
6
+
7
+ - **install:** suggest Caveman and RTK after global install ([#111](https://github.com/WeAreHausTech/haus-workflow/issues/111)) ([ab39845](https://github.com/WeAreHausTech/haus-workflow/commit/ab3984550f931f10083aa8e9e5b736c9a7765e94))
8
+
9
+ ## [0.26.1](https://github.com/WeAreHausTech/haus-workflow/compare/v0.26.0...v0.26.1) (2026-06-15)
10
+
3
11
  ## [0.26.0](https://github.com/WeAreHausTech/haus-workflow/compare/v0.25.1...v0.26.0) (2026-06-15)
4
12
 
5
13
  ### Features
package/README.md CHANGED
@@ -87,8 +87,11 @@ project when their on-disk copy still matches the lock hash; user-edited copies
87
87
 
88
88
  ## Internal docs
89
89
 
90
+ [docs/SUMMARY.md](docs/SUMMARY.md) — full documentation index
91
+
90
92
  - [Architecture](docs/architecture.md)
93
+ - [Codebase](docs/codebase.md)
91
94
  - [CLI reference](docs/cli.md)
95
+ - [Developer scripts & release](docs/dev.md)
92
96
  - [Security](docs/security.md)
93
- - [Developer scripts](docs/dev.md)
94
97
  - [Runbook](docs/runbook.md)
package/dist/cli.js CHANGED
@@ -3794,6 +3794,59 @@ function printApplyResult(result, dryRun) {
3794
3794
  }
3795
3795
  }
3796
3796
 
3797
+ // src/install/companion-tools.ts
3798
+ import { execaSync } from "execa";
3799
+ var COMPANION_TOOLS = [
3800
+ {
3801
+ bin: "caveman",
3802
+ label: "Caveman",
3803
+ blurb: "Ultra-compressed Claude Code responses \u2014 cuts output tokens ~75%.",
3804
+ installCmds: [
3805
+ "curl -fsSL https://raw.githubusercontent.com/JuliusBrussee/caveman/main/install.sh | bash"
3806
+ ],
3807
+ url: "https://github.com/JuliusBrussee/caveman"
3808
+ },
3809
+ {
3810
+ bin: "rtk",
3811
+ label: "RTK (Rust Token Killer)",
3812
+ blurb: "Token-optimized CLI proxy \u2014 60-90% savings on dev operations.",
3813
+ installCmds: [
3814
+ "brew install rtk",
3815
+ "cargo install --git https://github.com/rtk-ai/rtk # if Homebrew is unavailable"
3816
+ ],
3817
+ url: "https://github.com/rtk-ai/rtk",
3818
+ note: 'Another crate named "rtk" (Rust Type Kit) exists on crates.io \u2014 use the commands above, not a bare `cargo install rtk`.'
3819
+ }
3820
+ ];
3821
+ function buildCompanionSuggestions(tools, isInstalled) {
3822
+ const missing = tools.filter((t) => !isInstalled(t.bin));
3823
+ if (missing.length === 0) return [];
3824
+ const lines = ["", "Optional token-saving tools you can add:"];
3825
+ for (const tool of missing) {
3826
+ lines.push("", ` ${tool.label} \u2014 ${tool.blurb}`);
3827
+ for (const cmd of tool.installCmds) {
3828
+ lines.push(` ${cmd}`);
3829
+ }
3830
+ if (tool.note) lines.push(` note: ${tool.note}`);
3831
+ lines.push(` ${tool.url}`);
3832
+ }
3833
+ return lines;
3834
+ }
3835
+ function commandExists(bin) {
3836
+ try {
3837
+ const r = execaSync("sh", ["-c", 'command -v -- "$1"', "probe", bin], { reject: false });
3838
+ return r.exitCode === 0;
3839
+ } catch {
3840
+ return false;
3841
+ }
3842
+ }
3843
+ function printCompanionToolSuggestions(deps = {}) {
3844
+ const isInstalled = deps.isInstalled ?? commandExists;
3845
+ const emit2 = deps.log ?? log;
3846
+ const lines = buildCompanionSuggestions(COMPANION_TOOLS, isInstalled);
3847
+ for (const line2 of lines) emit2(line2);
3848
+ }
3849
+
3797
3850
  // src/commands/install.ts
3798
3851
  async function runInstall(options) {
3799
3852
  try {
@@ -3806,6 +3859,7 @@ async function runInstall(options) {
3806
3859
  if (options.check && result.drift) {
3807
3860
  process.exitCode = 1;
3808
3861
  } else if (!options.check && !options.dryRun) {
3862
+ printCompanionToolSuggestions();
3809
3863
  const total = result.created.length + result.updated.length;
3810
3864
  if (options.postinstall) {
3811
3865
  log("haus configured Claude Code for you:");
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "2.7.0",
2
+ "version": "2.7.2",
3
3
  "items": [
4
4
  {
5
5
  "id": "haus.nextjs-patterns",
@@ -1648,7 +1648,7 @@
1648
1648
  },
1649
1649
  {
1650
1650
  "id": "haus.superpowers-using-git-worktrees",
1651
- "version": "1.0.0",
1651
+ "version": "1.0.1",
1652
1652
  "source": "curated",
1653
1653
  "type": "skill",
1654
1654
  "path": "skills/superpowers/using-git-worktrees",
@@ -1658,7 +1658,7 @@
1658
1658
  "whenNotToUse": "Do not use when current workspace isolation is already sufficient.",
1659
1659
  "tags": ["workflow", "workflow-skill"],
1660
1660
  "repoRoles": [],
1661
- "tokenEstimate": 1996,
1661
+ "tokenEstimate": 2140,
1662
1662
  "installMode": "copy-selected",
1663
1663
  "default": true,
1664
1664
  "reviewStatus": "approved",
@@ -1667,8 +1667,9 @@
1667
1667
  "license": "MIT",
1668
1668
  "licenseConfidence": "high",
1669
1669
  "originSourceId": "superpowers-pcvelz",
1670
- "originUrl": "https://github.com/pcvelz/superpowers/tree/bd000c6ec1df53449a74397f55305b22802b9a2b/skills/using-git-worktrees",
1671
- "ecosystem": "superpowers"
1670
+ "originUrl": "https://github.com/pcvelz/superpowers/tree/20c0b1ed71cb073c847432fe01379f48c5278a5f/skills/using-git-worktrees",
1671
+ "ecosystem": "superpowers",
1672
+ "pinnedRef": "20c0b1ed71cb073c847432fe01379f48c5278a5f"
1672
1673
  },
1673
1674
  {
1674
1675
  "id": "haus.superpowers-using-superpowers",
@@ -1889,7 +1890,7 @@
1889
1890
  },
1890
1891
  {
1891
1892
  "id": "haus.superpowers-onboard",
1892
- "version": "1.0.0",
1893
+ "version": "1.0.1",
1893
1894
  "source": "curated",
1894
1895
  "type": "command",
1895
1896
  "path": "commands/superpowers/onboard.md",
@@ -1899,7 +1900,7 @@
1899
1900
  "whenNotToUse": "Do not use when a more specific skill or command applies.",
1900
1901
  "tags": ["workflow"],
1901
1902
  "repoRoles": [],
1902
- "tokenEstimate": 2871,
1903
+ "tokenEstimate": 3567,
1903
1904
  "installMode": "copy-selected",
1904
1905
  "default": true,
1905
1906
  "reviewStatus": "approved",
@@ -1908,8 +1909,8 @@
1908
1909
  "license": "MIT",
1909
1910
  "licenseConfidence": "high",
1910
1911
  "originSourceId": "superpowers-pcvelz",
1911
- "originUrl": "https://github.com/pcvelz/superpowers/blob/48f5123e18a1a92dfba962da8dc2509391c821ee/commands/onboard.md",
1912
- "pinnedRef": "48f5123e18a1a92dfba962da8dc2509391c821ee",
1912
+ "originUrl": "https://github.com/pcvelz/superpowers/blob/20c0b1ed71cb073c847432fe01379f48c5278a5f/commands/onboard.md",
1913
+ "pinnedRef": "20c0b1ed71cb073c847432fe01379f48c5278a5f",
1913
1914
  "ecosystem": "superpowers"
1914
1915
  },
1915
1916
  {
@@ -34,7 +34,7 @@ Specify the least. Infer the rest from the repo's stack + these conventions, and
34
34
 
35
35
  - **IMPORTANT — never install anything without asking first; global/system tools especially** (Homebrew, Docker, Laravel Herd, global `npm`/`composer` packages). Detect what's already present; if something required is missing, name it, say why it's needed, and get an explicit **yes** before installing. Prefer the least-invasive option, and don't switch or override tools the dev already has.
36
36
  - **PHP / WordPress sites are served by the developer's own PHP environment.** If they already have one — detect `valet`, `herd`, `ddev`, or `php` on PATH — **use it**: just satisfy the env contract (docroot → the repo's `web/`, HTTPS) and report the URL; never override what they already run. **Only when no local PHP environment exists** (a completely fresh machine) suggest installing **[Laravel Herd](https://herd.laravel.com)** as the default (asking first) and point its docroot at `web/` + `herd secure`.
37
- - **Databases and other services (a repo's `needs:`) run in Docker as standalone containers.** Bring each up with a **clean `docker run`** — image, host port, and env from the house convention for that service (e.g. `mysql` → `mysql:8` on `127.0.0.1:3306`, root password from generated secrets; `postgres` → `postgres:16` on `5432`). **Do not provision a `needs:` service from the repo's own `docker-compose.yml` when that compose bind-mounts repo-relative init files** (e.g. `./seed.sql`, `./docker-entrypoint-initdb.d/`): those mounts need files the guard won't let us create, and they conflate bring-up with seeding (which is the separate `seed:` step). **If Docker isn't installed** it's a prerequisite (surfaced in the Step 2 gate) — **ask before installing it** (global install). **Port-conflict caveat:** if the conventional host port is already taken, pick the next free port, use it, and **record the chosen port in the workspace `localdev.yml` `env` map** so sink repos point at the right place. A `needs:` service comes up **empty** — populating it is always the separate `seed:` step.
37
+ - **Databases and other services (a repo's `needs:`) run in Docker as a shared, workspace-owned `docker-compose` project** — grouped and self-contained (`up`/`down` together, named volumes), namespaced per workspace instance via `COMPOSE_PROJECT_NAME` + its own host ports so the workspace can run multiple times side by side. Image/port/env per the house convention (`mysql:8`, `postgres:16`, …). Don't reuse a repo's own compose that bind-mounts repo-relative init files (`seed.sql`) — author the service in the workspace compose. Services come up **empty** (seeding is the separate `seed:` step); record chosen host ports in the workspace `localdev.yml` `env` map.
38
38
  - **Dependencies** install from the lockfile (Step 3).
39
39
  - A repo's `localdev.yml` carries **only what can't be inferred** — its `needs`, repo-specific `build`/`seed` commands, env keys, and URL. Detect the stack (e.g. Bedrock = `composer.json` + `web/` docroot + `wp-cli.yml`; Vendure/Node = `docker-compose.yml` + `@vendure/*`) and apply the matching convention.
40
40
 
@@ -84,7 +84,7 @@ env:
84
84
  1. **Discover** `.haus-workflow/localdev.yml` in the workspace root and each repo.
85
85
  2. **Resolve order** from the workspace `order` (repos not listed run last, in manifest order). No workspace file → manifest order.
86
86
  3. **Per repo, in order**, apply intent via the conventions:
87
- - **`needs`** → bring up each service as a **standalone `docker run`** (image/port/env from conventions; **not** the repo's compose when it bind-mounts repo-relative init files) if not already running. The service comes up **empty**; record its values in the workspace `localdev.yml` `env` map. No data is created here, so no overwrite prompt at this step — data lands in `seed:`.
87
+ - **`needs`** → add the service to the **workspace compose project** and `docker compose up -d` if not already running (namespaced by `COMPOSE_PROJECT_NAME`, free host ports per instance; not the repo's own bind-mounting compose). Comes up **empty**; record host ports in the workspace `localdev.yml` `env` map — data lands in `seed:`.
88
88
  - **`build`** → run it (honor any node version the repo's docs note).
89
89
  - **`serve`** → for `via: herd` / PHP envs, install nothing — verify the dev's environment serves `web/`, and report the URL.
90
90
  - **`seed`** → populate the empty datastore. **Always a distinct, confirm-gated step, separate from `needs:` bring-up** (don't conflate "DB up" with "DB has data"). Before running, **check its prerequisites and report any gap instead of running blind** — e.g. WP-CLI present (for `wp` / `db:pull` seeds), the target repo's **`.env` written** (the seed reads connection values from it — done in the Env step above), the **SSH alias resolves** (for remote pulls like `dep db:pull staging-oderland`). **Confirm first** for every remote (SSH) or destructive (overwrites data) seed — every run, even on re-run. Missing prerequisite → skip with a clear message, don't guess.
@@ -112,13 +112,13 @@ env:
112
112
  - **Yes** → start each repo in the workspace `order` (its `serve.start`, e.g. `yarn dev`; bring up any remaining foreground services), run any follow-ups (e.g. `wp sync-products sync`), then **print the live URLs** (each repo's `serve.url`).
113
113
  - **No** → just print the ordered start commands + follow-ups as next steps; start nothing.
114
114
 
115
- **Default is "ready to run" (D2):** the preparation — datastores up (standalone `docker run`), seeds applied (confirm-gated), links, builds, each repo's `.env` written — always happens. Starting the **foreground** dev servers and the initial product sync happen **only if the user says yes** to the start prompt above; otherwise they're printed, not run.
115
+ **Default is "ready to run" (D2):** the preparation — datastores up (workspace `docker compose` project), seeds applied (confirm-gated), links, builds, each repo's `.env` written — always happens. Starting the **foreground** dev servers and the initial product sync happen **only if the user says yes** to the start prompt above; otherwise they're printed, not run.
116
116
 
117
117
  ## Step 5 — Report and define "done"
118
118
 
119
119
  **"Done" is an explicit terminal state**, not "looks set up". The preparation reaches:
120
120
 
121
- - datastores up (standalone containers),
121
+ - datastores up (workspace `docker compose` project),
122
122
  - dependencies installed and builds green,
123
123
  - links wired,
124
124
  - each repo's `.env` written from known values.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@haus-tech/haus-workflow",
3
- "version": "0.26.0",
3
+ "version": "0.27.0",
4
4
  "description": "Haus AI workflow CLI for Claude Code.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -22,7 +22,8 @@
22
22
  "scripts": {
23
23
  "build": "tsup src/cli.ts --format esm --dts --clean --out-dir dist --external @inquirer/checkbox",
24
24
  "dev": "tsx src/cli.ts",
25
- "test": "node --import tsx --test tests/**/*.test.js",
25
+ "test": "node scripts/run-tests.mjs tests/**/*.test.js",
26
+ "test:fast": "node scripts/test-fast.mjs",
26
27
  "test:coverage": "c8 yarn test",
27
28
  "coverage:check": "c8 --check-coverage yarn test",
28
29
  "lint": "eslint src",