@haus-tech/haus-workflow 0.23.1 → 0.24.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,11 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.24.0](https://github.com/WeAreHausTech/haus-workflow/compare/v0.23.1...v0.24.0) (2026-06-12)
4
+
5
+ ### Features
6
+
7
+ - **cloneandsetup:** local-dev orchestration via localdev.yml ([#97](https://github.com/WeAreHausTech/haus-workflow/issues/97)) ([8a2b5d3](https://github.com/WeAreHausTech/haus-workflow/commit/8a2b5d3e9a767bfe92152189b37921d58878818b))
8
+
3
9
  ## [0.23.1](https://github.com/WeAreHausTech/haus-workflow/compare/v0.23.0...v0.23.1) (2026-06-12)
4
10
 
5
11
  ## [0.23.0](https://github.com/WeAreHausTech/haus-workflow/compare/v0.22.1...v0.23.0) (2026-06-12)
@@ -1,51 +1,100 @@
1
- Clone a project's repos **and** set each one up locally — node version, dependencies, env scaffold. This is `project:clone` followed by a per-repo setup pass.
1
+ Clone a project's repos **and** set each one up for local development — node version, dependencies, databases, cross-repo links, and env. This is `project:clone` followed by a per-repo setup pass and a localdev orchestration pass.
2
2
 
3
- **Always ask before doing work — never assume.** Cloning and setup both run things that take time, hit the network, and need auth; confirm with the user before each phase, and respect repos they already have.
3
+ **Always ask before doing work — never assume.** Cloning and setup hit the network, need auth, and can touch databases; confirm before each phase, and respect repos the user already has.
4
4
 
5
5
  ## Step 1 — Clone
6
6
 
7
- Run the full `project:clone` flow first by following `~/.claude/commands/haus-clone.md` end to end whichever mode applies:
7
+ Run the full `project:clone` flow by following `~/.claude/commands/haus-clone.md` end to end (name one repo; no name → workspace repos from `repos.manifest.json`). Carry the resulting repo list into Step 2.
8
8
 
9
- - A **name** was given it finds and clones that one repo from GitHub.
10
- - **No name** → it clones the workspace's repos from `repos.manifest.json` (asking clean-clone vs reuse-local first).
9
+ ## Step 2 Confirm the setup pass
11
10
 
12
- When that finishes you have a set of repos on disk (freshly cloned and/or reused-local). Carry that list into Step 2.
11
+ 1. List the repos and what each will run (node, deps, localdev steps). Get a go-ahead. For **reused** local clones, ask whether to re-run setup.
12
+ 2. Check `NODE_AUTH_TOKEN` is exported if any repo needs private `@`-scoped packages; if missing, tell the user — those installs fail without it.
13
13
 
14
- ## Step 2Confirm the setup pass
14
+ ## Step 3Per-repo dependency pass
15
15
 
16
- Before running any setup:
16
+ For each repo, in its own directory, detect and install from the repo's own files (read its `docs/setup.md` / `CLAUDE.md` / `README.md` first — they win). Select node from `.nvmrc`/`engines.node` (`nvm install`), enable the pinned package manager (`corepack enable`), install JS deps (`yarn`/`pnpm`/`npm` by lockfile), composer deps if `composer.json` + `composer` present. Run each repo's steps in one login shell so the node version stays active. Per-repo failure is reported and skipped, not fatal.
17
17
 
18
- 1. List the repos you're about to set up and what each will run (node version select, dependency install, etc.). Get a go-ahead. For repos that were **reused** from an existing local clone, ask whether to (re)run setup there too they may already be set up.
19
- 2. Check `NODE_AUTH_TOKEN` is exported if any repo depends on private `@`-scoped packages (e.g. `@haus-storefront-*`, `@haus-tech/*`). If it's missing, tell the user to set it first — those installs will fail without it. Let them decide whether to continue or stop.
18
+ **Scaffold `.env`** so the env-wiring in Step 4 has a file to write to: if `.env.example` exists and `.env` does not, copy it; otherwise create an empty `.env`. Per decision D5, write `.env`; if the write is blocked, print the values for the user to add. Tell the user real secrets still need filling.
20
19
 
21
- ## Step 3Set up each repo
20
+ ## Step 4Local-dev orchestration
22
21
 
23
- For each repo directory, run its setup **in that directory**, detecting what's needed from the repo's own files don't assume a stack. Run a repo's steps in a single login shell so the selected node version stays active for the install. A robust pattern:
22
+ This is the phase that takes the workspace from "installed" to "ready to run." It is driven by `localdev.yml` files; a repo with none is set up by Step 3 only.
24
23
 
25
- ```
26
- bash -lc 'export NVM_DIR="$HOME/.nvm"; [ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh"; cd "<repo>" && nvm install && corepack enable && yarn install'
24
+ ### House conventions (the "how", so repos specify only the "what")
25
+
26
+ Specify the least. Infer the rest from the repo's stack + these conventions, and work out the concrete commands at run time:
27
+
28
+ - **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.
29
+ - **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`.
30
+ - **Databases and other services (a repo's `needs:`) run in Docker.** **If Docker isn't installed**, it's a prerequisite for these — tell the user and **ask before installing it** (it's a global install). Once Docker is available, provision services the simplest way (a one-off `docker run`, or the repo's own compose if it ships one), then wire the matching env vars to point at them. Confirm before creating/overwriting data.
31
+ - **Dependencies** install from the lockfile (Step 3).
32
+ - 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.
33
+
34
+ ### The `localdev.yml` format
35
+
36
+ **Per-repo — `<repo>/.haus-workflow/localdev.yml`** (how to set up THAT repo alone; sibling-agnostic):
37
+
38
+ All fields optional. **Prefer intent (`needs`/`build`/`seed`/`serve`) over explicit `steps`** —
39
+ the conventions above turn intent into commands.
40
+
41
+ ```yaml
42
+ needs: [mysql] # services this repo requires; provisioned in Docker, env wired to them
43
+ needsEnv: [WP_HOME, DB_NAME] # env keys that must be present to run/serve
44
+ build: 'yarn build' # optional: the build command (run after deps)
45
+ seed: 'dep db:pull staging-oderland' # optional: how to load data; remote/destructive → confirm first
46
+ serve: # optional: how it runs (printed as a next-step, never auto-started)
47
+ via: herd # herd | valet | docker | command — for PHP envs, bring-your-own (don't install)
48
+ url: 'https://example.test'
49
+ start: 'yarn dev'
50
+ steps: # optional escape hatch: explicit ordered shell steps when intent isn't enough
51
+ - run: 'composer install'
52
+ node: 10 # nvm version for THIS step
53
+ remote: true # SSH → confirm first
54
+ destructive: true # overwrites data → confirm first
55
+ optional: true # failure is non-fatal, continue
27
56
  ```
28
57
 
29
- **Read the repo's own setup docs first they win.** Before applying the file-heuristics below, look for the repo's canonical setup instructions: `docs/setup.md`, `CLAUDE.md`, `README.md` (or follow `docs/SUMMARY.md` to the setup page). If present, **follow them as authoritative** — they capture nested or non-standard builds a root file-scan can't see. Use the heuristics below only to fill gaps, or when the repo ships no setup doc. Example: a WordPress/Bedrock repo has **no root `package.json`** — its JS/theme build lives under `web/app/themes/<theme>` and is only described in the docs, so a root-only scan wrongly reports "no JS". When the docs point at a nested build, scan subdirectories for the relevant `package.json` / build script and run it.
58
+ **Workspace`<workspace>/.haus-workflow/localdev.yml`** (the glue BETWEEN repos):
59
+
60
+ ```yaml
61
+ order: [repo-a, repo-b] # setup/startup order, by manifest id
62
+ links:
63
+ - { type: symlink, from: <repo-folder>, to: <repo-folder>/path/to/link }
64
+ - { type: composer-path, in: <repo>, dep: <sibling-repo> }
65
+ - { type: yarn-link, in: [<repo>, ...], dep: <sibling-package-repo> }
66
+ env:
67
+ - source: { repo: <repo>, provides: '<value>' }
68
+ sinks:
69
+ - { repo: <repo>, key: ENV_KEY }
70
+ ```
30
71
 
31
- Adjust per repo (gap-fill, or when no setup doc exists):
72
+ ### Run order
32
73
 
33
- 1. **Node version.** If `.nvmrc` (or `engines.node` in `package.json`) is present, select it with `nvm install` (reads `.nvmrc`, installs the version if missing, then switches to it). If the user uses `fnm` instead, `fnm use --install-if-missing`. If neither is available, tell the user the required version and continue on the current node.
34
- 2. **JS dependencies.** Enable the pinned package manager with `corepack enable`, then install based on what's present:
35
- - `yarn.lock` or `packageManager: "yarn@…"` `yarn install`
36
- - `pnpm-lock.yaml``pnpm install`
37
- - `package-lock.json``npm install`
38
- - no JS manifest skip
39
- 3. **PHP dependencies.** If `composer.json` is present and `composer` is installed `composer install`. If composer is missing, note it and skip.
40
- 4. **Env scaffold.** If `.env.example` exists and `.env` does not copy `.env.example` to `.env` (never overwrite an existing `.env`). Tell the user the real values still need filling.
74
+ 1. **Discover** `.haus-workflow/localdev.yml` in the workspace root and each repo.
75
+ 2. **Resolve order** from the workspace `order` (repos not listed run last, in manifest order). No workspace file → manifest order.
76
+ 3. **Per repo, in order**, apply intent via the conventions:
77
+ - **`needs`**provision each service in Docker if not already running, and wire its env vars. Confirm before creating/overwriting data.
78
+ - **`build`**run it (honor any node version the repo's docs note).
79
+ - **`serve`** for `via: herd` / PHP envs, install nothing — verify the dev's environment serves `web/`, and report the URL.
80
+ - **`seed`** run it; **confirm first** if it's remote (SSH) or destructive (overwrites data).
81
+ - **`steps`** (escape hatch) run in order, selecting `node:` per step, `optional:` failures continue, **confirming before any `remote:`/`destructive:` step** every run, even on re-run.
82
+ 4. **Links** (workspace-owned, performed generically — do NOT call a repo's own `setup-dev-mode.sh`, which is deprecated):
83
+ - `symlink` → `ln -s <from> <to>`; replace an existing symlink, but never clobber a real directory without confirmation.
84
+ - `composer-path` → in `in`'s `composer.json`, set the `dep`'s require to `{ "type": "path", "url": "../<dep-folder>", "options": { "symlink": true } }`, then `composer update <vendor/dep>`.
85
+ - `yarn-link` → `yarn link` in the `dep` repo, then `yarn link <pkg-name>` in each `in` repo (read `<pkg-name>` from the dep's `package.json`).
86
+ 5. **Env:** for each workspace `env` entry, confirm the `source` is satisfiable, then upsert the value into each sink repo's `.env` under its `key` — **creating `.env` if it does not exist** (Step 3 scaffolds it, but don't assume). **If the write is blocked or fails, print the exact `KEY=value` lines for the user to paste** (decision D5). Real secrets (DB passwords, tokens) remain the user's to fill.
87
+ 6. **Report, then offer to start.** Give the per-repo summary, then **ask the user whether to start everything now.**
88
+ - **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`).
89
+ - **No** → just print the ordered start commands + follow-ups as next steps; start nothing.
41
90
 
42
- If a repo's setup fails, report the error and **continue to the next repo** don't abort the whole run.
91
+ **Default is "ready to run" (D2):** the preparation — datastores up (`docker compose up -d`), DBs pulled, links, builds, env wired — always happens. Starting the **foreground** dev servers and the initial product sync happens **only if the user says yes** to the start prompt above; otherwise they're printed, not run.
43
92
 
44
- ## Step 4 — Report
93
+ ## Step 5 — Report
45
94
 
46
- Summarise per repo: node version used, dependency install result, composer (if any), env seeded. Then list what's still manual:
95
+ Summarise per repo (node, deps, localdev steps, links, env). Then **ask whether to start everything now**:
47
96
 
48
- - Fill in each `.env` with real values (cross-repo values must match see the workspace's environment docs).
49
- - Start Docker services and dev servers in dependency order see the workspace's local-development docs.
97
+ - **Yes** → start the dev servers in workspace `order`, run any follow-ups, and **print the live URLs** so the user can open the running app.
98
+ - **No** print the ordered start commands + follow-ups instead, and start nothing.
50
99
 
51
- **Do not** start servers or run `docker compose up` / `yarn dev` — this command only prepares the repos.
100
+ Never start the app without that explicit yes.
@@ -21,17 +21,17 @@ The unprefixed verbs (`update`, `catalog`, `install`, `uninstall`) act on **this
21
21
  haus install** (`~/.claude`, npm) — they manage the haus tool itself, like `npm install -g`.
22
22
  The short legacy aliases still work but the names below are canonical.
23
23
 
24
- | Task name (legacy aliases) | Command | Scope | What it does |
25
- | ----------------------------------------------------------------- | ------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------- |
26
- | `project:init` (`setup`, `init`) | _Setup procedure below_ | project | First-time setup of an **existing** repo: adds AI skills, commands, workflow + project docs |
27
- | `project:clone [name]` (`clone`) | _Clone procedure below_ | project | No name: clone a **workspace**'s repos from `repos.manifest.json`. With a `name`: find & clone one repo by name from GitHub |
28
- | `project:cloneandsetup [name]` (`cloneandsetup`) | _Clone & setup procedure below_ | project | Run `project:clone`, then set up each repo locally (node version, deps, `.env`) |
29
- | `project:refresh` (`apply`, `refresh`, `claude-md`, `regenerate`) | `haus apply --write` | project | Re-run setup / refresh `.claude/` context + regenerate root `CLAUDE.md` import block |
30
- | `project:doctor` (`doctor`, `check`) | `haus doctor` | project | Check for install drift |
31
- | `update` (`upgrade`) | `haus update` | global | Update npm package + catalog + `~/.claude/` (also refreshes this project) |
32
- | `catalog` | `haus update` | global | Fetch latest catalog (same command as update) |
33
- | `install` (`global`) | `haus install` | global | Seed `~/.claude/` with haus-owned files |
34
- | `uninstall` | `haus uninstall` | global | Remove all haus global files from `~/.claude/` |
24
+ | Task name (legacy aliases) | Command | Scope | What it does |
25
+ | ----------------------------------------------------------------- | ------------------------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
26
+ | `project:init` (`setup`, `init`) | _Setup procedure below_ | project | First-time setup of an **existing** repo: adds AI skills, commands, workflow + project docs |
27
+ | `project:clone [name]` (`clone`) | _Clone procedure below_ | project | No name: clone a **workspace**'s repos from `repos.manifest.json`. With a `name`: find & clone one repo by name from GitHub |
28
+ | `project:cloneandsetup [name]` (`cloneandsetup`) | _Clone & setup procedure below_ | project | Run `project:clone`, then set up each repo for local dev deps, databases, cross-repo links, and env — via each repo's `.haus-workflow/localdev.yml` (+ the workspace's order/links/env) |
29
+ | `project:refresh` (`apply`, `refresh`, `claude-md`, `regenerate`) | `haus apply --write` | project | Re-run setup / refresh `.claude/` context + regenerate root `CLAUDE.md` import block |
30
+ | `project:doctor` (`doctor`, `check`) | `haus doctor` | project | Check for install drift |
31
+ | `update` (`upgrade`) | `haus update` | global | Update npm package + catalog + `~/.claude/` (also refreshes this project) |
32
+ | `catalog` | `haus update` | global | Fetch latest catalog (same command as update) |
33
+ | `install` (`global`) | `haus install` | global | Seed `~/.claude/` with haus-owned files |
34
+ | `uninstall` | `haus uninstall` | global | Remove all haus global files from `~/.claude/` |
35
35
 
36
36
  ## Step 1 — Determine the task
37
37
 
@@ -52,8 +52,8 @@ Options:
52
52
  (haus update — same command; pulls latest workflow templates and lockfile)
53
53
  5. [project] project:clone [name] — clone repos
54
54
  (no name: clone a workspace from repos.manifest.json; with a name: find & clone one repo by name from GitHub)
55
- 6. [project] project:cloneandsetup [name] — clone repos, then set them up
56
- (project:clone, then per-repo node version + dependency install + .env scaffold)
55
+ 6. [project] project:cloneandsetup [name] — clone repos, then set them up for local dev
56
+ (project:clone, then per-repo deps + databases + cross-repo links + env from localdev.yml)
57
57
  ```
58
58
 
59
59
  Map the user's selection to the command from the alias table, then continue to Step 2.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@haus-tech/haus-workflow",
3
- "version": "0.23.1",
3
+ "version": "0.24.0",
4
4
  "description": "Haus AI workflow CLI for Claude Code.",
5
5
  "type": "module",
6
6
  "bin": {