wordpress-agent-kit 0.5.1 → 0.6.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.
Files changed (132) hide show
  1. package/.agents/skills/wp-bootstrap/SKILL.md +314 -0
  2. package/.agents/skills/wp-bootstrap/references/composer-setup.md +275 -0
  3. package/.agents/skills/wp-bootstrap/references/monorepo-patterns.md +184 -0
  4. package/.agents/skills/wp-bootstrap/scripts/bootstrap.sh +151 -0
  5. package/.agents/skills/wp-bootstrap/scripts/detect-structure.mjs +466 -0
  6. package/.agents/skills/wp-bootstrap/scripts/package-wp.sh +173 -0
  7. package/.agents/skills/wp-bootstrap/scripts/playground-start.sh +148 -0
  8. package/.agents/skills/wp-bootstrap/scripts/playground-verify.sh +165 -0
  9. package/.agents/skills/wp-bootstrap/scripts/setup-github.sh +417 -0
  10. package/.agents/skills/wp-wpengine/SKILL.md +76 -12
  11. package/.agents/skills/wp-wpengine/references/github-actions-deploy.md +16 -9
  12. package/README.md +1 -1
  13. package/dist/cli.js +2 -0
  14. package/dist/commands/bootstrap.js +105 -0
  15. package/dist/lib/api.js +1 -0
  16. package/dist/lib/bootstrap.js +352 -0
  17. package/extensions/wp-agent-kit/index.ts +143 -3
  18. package/package.json +1 -1
  19. package/skills-custom/wp-bootstrap/SKILL.md +314 -0
  20. package/skills-custom/wp-bootstrap/references/composer-setup.md +275 -0
  21. package/skills-custom/wp-bootstrap/references/monorepo-patterns.md +184 -0
  22. package/skills-custom/wp-bootstrap/scripts/bootstrap.sh +151 -0
  23. package/skills-custom/wp-bootstrap/scripts/detect-structure.mjs +466 -0
  24. package/skills-custom/wp-bootstrap/scripts/package-wp.sh +173 -0
  25. package/skills-custom/wp-bootstrap/scripts/playground-start.sh +148 -0
  26. package/skills-custom/wp-bootstrap/scripts/playground-verify.sh +165 -0
  27. package/skills-custom/wp-bootstrap/scripts/setup-github.sh +417 -0
  28. package/skills-custom/wp-wpengine/SKILL.md +76 -12
  29. package/skills-custom/wp-wpengine/references/github-actions-deploy.md +16 -9
  30. package/.github/skills/blueprint/SKILL.md +0 -418
  31. package/.github/skills/wordpress-router/SKILL.md +0 -52
  32. package/.github/skills/wordpress-router/references/decision-tree.md +0 -55
  33. package/.github/skills/wp-abilities-api/SKILL.md +0 -108
  34. package/.github/skills/wp-abilities-api/references/delegate-helper-pattern.md +0 -241
  35. package/.github/skills/wp-abilities-api/references/domain-vs-projection.md +0 -113
  36. package/.github/skills/wp-abilities-api/references/error-code-vocabulary.md +0 -123
  37. package/.github/skills/wp-abilities-api/references/grouping-heuristic.md +0 -89
  38. package/.github/skills/wp-abilities-api/references/input-schema-gotchas.md +0 -265
  39. package/.github/skills/wp-abilities-api/references/php-registration.md +0 -94
  40. package/.github/skills/wp-abilities-api/references/plugin-family-patterns.md +0 -233
  41. package/.github/skills/wp-abilities-api/references/rest-api.md +0 -13
  42. package/.github/skills/wp-abilities-api/references/shared-core-service.md +0 -184
  43. package/.github/skills/wp-abilities-audit/SKILL.md +0 -199
  44. package/.github/skills/wp-abilities-audit/references/audit-schema.md +0 -300
  45. package/.github/skills/wp-abilities-audit/references/capability-gate-tracing.md +0 -197
  46. package/.github/skills/wp-abilities-audit/references/controller-enumeration.md +0 -116
  47. package/.github/skills/wp-abilities-verify/SKILL.md +0 -215
  48. package/.github/skills/wp-abilities-verify/references/annotation-correctness.md +0 -154
  49. package/.github/skills/wp-abilities-verify/references/audit-schema-validation.md +0 -131
  50. package/.github/skills/wp-abilities-verify/references/permission-roundtrip.md +0 -190
  51. package/.github/skills/wp-abilities-verify/references/runtime-harness.md +0 -462
  52. package/.github/skills/wp-abilities-verify/references/schema-lints.md +0 -118
  53. package/.github/skills/wp-abilities-verify/references/static-enumeration.md +0 -126
  54. package/.github/skills/wp-block-development/SKILL.md +0 -175
  55. package/.github/skills/wp-block-development/references/attributes-and-serialization.md +0 -22
  56. package/.github/skills/wp-block-development/references/block-json.md +0 -49
  57. package/.github/skills/wp-block-development/references/creating-new-blocks.md +0 -46
  58. package/.github/skills/wp-block-development/references/debugging.md +0 -36
  59. package/.github/skills/wp-block-development/references/deprecations.md +0 -24
  60. package/.github/skills/wp-block-development/references/dynamic-rendering.md +0 -23
  61. package/.github/skills/wp-block-development/references/inner-blocks.md +0 -25
  62. package/.github/skills/wp-block-development/references/registration.md +0 -30
  63. package/.github/skills/wp-block-development/references/supports-and-wrappers.md +0 -18
  64. package/.github/skills/wp-block-development/references/tooling-and-testing.md +0 -21
  65. package/.github/skills/wp-block-development/scripts/list_blocks.mjs +0 -121
  66. package/.github/skills/wp-block-themes/SKILL.md +0 -117
  67. package/.github/skills/wp-block-themes/references/creating-new-block-theme.md +0 -37
  68. package/.github/skills/wp-block-themes/references/debugging.md +0 -24
  69. package/.github/skills/wp-block-themes/references/patterns.md +0 -18
  70. package/.github/skills/wp-block-themes/references/style-variations.md +0 -14
  71. package/.github/skills/wp-block-themes/references/templates-and-parts.md +0 -16
  72. package/.github/skills/wp-block-themes/references/theme-json.md +0 -59
  73. package/.github/skills/wp-block-themes/scripts/detect_block_themes.mjs +0 -117
  74. package/.github/skills/wp-interactivity-api/SKILL.md +0 -180
  75. package/.github/skills/wp-interactivity-api/references/debugging.md +0 -29
  76. package/.github/skills/wp-interactivity-api/references/directives-quickref.md +0 -30
  77. package/.github/skills/wp-interactivity-api/references/server-side-rendering.md +0 -310
  78. package/.github/skills/wp-performance/SKILL.md +0 -147
  79. package/.github/skills/wp-performance/references/autoload-options.md +0 -24
  80. package/.github/skills/wp-performance/references/cron.md +0 -20
  81. package/.github/skills/wp-performance/references/database.md +0 -20
  82. package/.github/skills/wp-performance/references/http-api.md +0 -15
  83. package/.github/skills/wp-performance/references/measurement.md +0 -21
  84. package/.github/skills/wp-performance/references/object-cache.md +0 -24
  85. package/.github/skills/wp-performance/references/query-monitor-headless.md +0 -38
  86. package/.github/skills/wp-performance/references/server-timing.md +0 -22
  87. package/.github/skills/wp-performance/references/wp-cli-doctor.md +0 -24
  88. package/.github/skills/wp-performance/references/wp-cli-profile.md +0 -32
  89. package/.github/skills/wp-performance/scripts/perf_inspect.mjs +0 -128
  90. package/.github/skills/wp-phpstan/SKILL.md +0 -98
  91. package/.github/skills/wp-phpstan/references/configuration.md +0 -52
  92. package/.github/skills/wp-phpstan/references/third-party-classes.md +0 -76
  93. package/.github/skills/wp-phpstan/references/wordpress-annotations.md +0 -124
  94. package/.github/skills/wp-phpstan/scripts/phpstan_inspect.mjs +0 -263
  95. package/.github/skills/wp-playground/SKILL.md +0 -233
  96. package/.github/skills/wp-playground/references/blueprints.md +0 -36
  97. package/.github/skills/wp-playground/references/cli-commands.md +0 -39
  98. package/.github/skills/wp-playground/references/debugging.md +0 -16
  99. package/.github/skills/wp-playground/references/e2e-playwright.md +0 -115
  100. package/.github/skills/wp-plugin-development/SKILL.md +0 -113
  101. package/.github/skills/wp-plugin-development/references/data-and-cron.md +0 -19
  102. package/.github/skills/wp-plugin-development/references/debugging.md +0 -19
  103. package/.github/skills/wp-plugin-development/references/lifecycle.md +0 -33
  104. package/.github/skills/wp-plugin-development/references/security.md +0 -29
  105. package/.github/skills/wp-plugin-development/references/settings-api.md +0 -22
  106. package/.github/skills/wp-plugin-development/references/structure.md +0 -16
  107. package/.github/skills/wp-plugin-development/scripts/detect_plugins.mjs +0 -122
  108. package/.github/skills/wp-plugin-directory-guidelines/SKILL.md +0 -133
  109. package/.github/skills/wp-plugin-directory-guidelines/references/gpl-compliance.md +0 -217
  110. package/.github/skills/wp-plugin-directory-guidelines/references/guideline-review-checklist.md +0 -592
  111. package/.github/skills/wp-plugin-directory-guidelines/references/naming-rules.md +0 -121
  112. package/.github/skills/wp-project-triage/SKILL.md +0 -39
  113. package/.github/skills/wp-project-triage/references/triage.schema.json +0 -143
  114. package/.github/skills/wp-project-triage/scripts/detect_wp_project.mjs +0 -610
  115. package/.github/skills/wp-rest-api/SKILL.md +0 -115
  116. package/.github/skills/wp-rest-api/references/authentication.md +0 -18
  117. package/.github/skills/wp-rest-api/references/custom-content-types.md +0 -20
  118. package/.github/skills/wp-rest-api/references/discovery-and-params.md +0 -20
  119. package/.github/skills/wp-rest-api/references/responses-and-fields.md +0 -30
  120. package/.github/skills/wp-rest-api/references/routes-and-endpoints.md +0 -36
  121. package/.github/skills/wp-rest-api/references/schema.md +0 -22
  122. package/.github/skills/wp-wpcli-and-ops/SKILL.md +0 -124
  123. package/.github/skills/wp-wpcli-and-ops/references/automation.md +0 -30
  124. package/.github/skills/wp-wpcli-and-ops/references/cron-and-cache.md +0 -23
  125. package/.github/skills/wp-wpcli-and-ops/references/debugging.md +0 -17
  126. package/.github/skills/wp-wpcli-and-ops/references/multisite.md +0 -22
  127. package/.github/skills/wp-wpcli-and-ops/references/packages-and-updates.md +0 -22
  128. package/.github/skills/wp-wpcli-and-ops/references/safety.md +0 -30
  129. package/.github/skills/wp-wpcli-and-ops/references/search-replace.md +0 -40
  130. package/.github/skills/wp-wpcli-and-ops/scripts/wpcli_inspect.mjs +0 -90
  131. package/.github/skills/wp-wpengine/SKILL.md +0 -127
  132. package/.github/skills/wpds/SKILL.md +0 -59
@@ -0,0 +1,184 @@
1
+ # WordPress Monorepo Patterns
2
+
3
+ Common structures agents will encounter. `detect-structure.mjs` identifies them automatically.
4
+
5
+ ---
6
+
7
+ ## Pattern 1 — Single plugin/theme repo (most common)
8
+
9
+ The repo IS the plugin or theme. `repoRoot === wpPackageDir`.
10
+
11
+ ```
12
+ my-plugin/
13
+ ├── my-plugin.php ← Plugin header here
14
+ ├── includes/
15
+ ├── assets/src/ ← JS/CSS source (gitignored dist/)
16
+ ├── tests/
17
+ ├── composer.json ← plugin-level (Pest tests)
18
+ ├── package.json ← @wordpress/scripts or Biome
19
+ └── .agents/skills/ ← installed by wp-agent-kit
20
+ ```
21
+
22
+ **detect-structure.mjs output:**
23
+ ```json
24
+ {
25
+ "isMonorepo": false,
26
+ "wpPackages": [{ "type": "plugin", "path": ".", "name": "My Plugin" }],
27
+ "wpRoot": "." // or null if Playground-only
28
+ }
29
+ ```
30
+
31
+ **WP Engine deploy:** push the entire repo.
32
+ **Playground:** `--mount=.:/wordpress/wp-content/plugins/my-plugin`
33
+
34
+ ---
35
+
36
+ ## Pattern 2 — wp-agent-os style (WP packages + non-WP packages at root)
37
+
38
+ Multiple WP packages and JS packages at the top level. No WP core in repo.
39
+
40
+ ```
41
+ project/
42
+ ├── wpaos/ ← companion plugin (Plugin Name: in wpaos.php)
43
+ ├── wpaos-blocks/ ← generated plugin (Plugin Name: in wpaos-blocks.php)
44
+ ├── wpaos-theme/ ← block theme (Theme Name: in style.css)
45
+ ├── design-system/ ← TypeScript/Node (not a WP package)
46
+ ├── backend/ ← Firebase/Genkit (not a WP package)
47
+ ├── web/ ← Next.js (not a WP package)
48
+ ├── composer.json ← ROOT: dev tooling only (PHPCS/PHPStan) — NOT shipped
49
+ ├── pnpm-workspace.yaml ← workspace includes design-system, backend, web, tools/e2e
50
+ ├── biome.json ← root JS/TS lint+format
51
+ └── tools/
52
+ ├── setup.sh ← one-command bootstrap
53
+ ├── package-plugins.sh ← build + zip WP packages
54
+ └── playground/ ← Playground launch + verify scripts
55
+ ```
56
+
57
+ **detect-structure.mjs output:**
58
+ ```json
59
+ {
60
+ "isMonorepo": true,
61
+ "packageManager": "pnpm",
62
+ "wpPackages": [
63
+ { "type": "plugin", "path": "wpaos", "name": "WP Agent OS" },
64
+ { "type": "plugin", "path": "wpaos-blocks", "name": "WP Agent OS Blocks" },
65
+ { "type": "theme", "path": "wpaos-theme", "name": "WP Agent OS Theme" }
66
+ ],
67
+ "wpRoot": null,
68
+ "playgroundOnly": true
69
+ }
70
+ ```
71
+
72
+ **WP Engine deploy:** `bash tools/package-plugins.sh` → upload zips. No git push from monorepo.
73
+ **Playground:** mount each WP package separately. See Playground patterns reference.
74
+
75
+ ---
76
+
77
+ ## Pattern 3 — Bedrock / full-stack (WP core in repo)
78
+
79
+ Roots Bedrock or similar — WP core managed by Composer, web root is a subdirectory.
80
+
81
+ ```
82
+ project/
83
+ ├── web/
84
+ │ ├── wp/ ← WP core (managed by Composer)
85
+ │ ├── app/
86
+ │ │ ├── plugins/ ← custom plugins here
87
+ │ │ └── themes/ ← custom themes here
88
+ │ └── wp-config.php
89
+ ├── config/
90
+ │ └── environments/
91
+ ├── composer.json ← Bedrock manages WP core + plugins via Composer
92
+ └── .env
93
+ ```
94
+
95
+ **detect-structure.mjs output:**
96
+ ```json
97
+ {
98
+ "wpRoot": "web",
99
+ "wpPackages": [], // plugins detected under web/app/plugins/
100
+ "wpackagist": true // Bedrock always uses WPackagist
101
+ }
102
+ ```
103
+
104
+ **WP Engine deploy:** push the whole repo OR just the `web/` subtree:
105
+ ```bash
106
+ git subtree push --prefix=web wpe-prod main
107
+ ```
108
+ **wp-cli.yml:**
109
+ ```yaml
110
+ path: ./web
111
+ @production:
112
+ ssh: <install>@<install>.ssh.wpengine.net
113
+ path: /home/wpe-user/sites/<install>
114
+ ```
115
+
116
+ ---
117
+
118
+ ## Pattern 4 — Agency monorepo (multiple client sites)
119
+
120
+ ```
121
+ agency-repo/
122
+ ├── client-a/
123
+ │ ├── plugins/my-plugin/
124
+ │ └── themes/my-theme/
125
+ ├── client-b/
126
+ │ └── plugins/client-b-plugin/
127
+ └── shared/
128
+ └── components/ ← shared JS library
129
+ ```
130
+
131
+ Not well-suited for a single wp-agent-kit install. Better to:
132
+ - Install wp-agent-kit per client: `wp-agent-kit install ./client-a`
133
+ - Or: one install at root with per-client `wp-cli.yml` aliases
134
+
135
+ ---
136
+
137
+ ## Key questions for each structure
138
+
139
+ 1. **Is WP core in this repo?** (`wpRoot` not null)
140
+ - Yes → use `--path` in WP-CLI, `wp-cli.yml` `path:` at that location
141
+ - No → Playground-only local dev, deploy via zip or separate deploy repo
142
+
143
+ 2. **Are plugins/themes installed into a WP install, or are they standalone packages?**
144
+ - Standalone → Playground mounts, zip deploy, WPackagist for dependencies
145
+ - In a WP install → `wp plugin install`, WP-CLI, Bedrock patterns
146
+
147
+ 3. **How many WP packages?**
148
+ - 1 → push the whole repo to WP Engine
149
+ - 2+ → package individually, upload each as a zip; OR subtree push
150
+
151
+ 4. **Is there a build step?**
152
+ - Yes (JS assets, generated plugins) → CI must build before deploying
153
+ - No → push source files directly
154
+
155
+ ---
156
+
157
+ ## wp-bootstrap.config.json — optional config file
158
+
159
+ Place at repo root to override detection:
160
+
161
+ ```json
162
+ {
163
+ "packageManager": "pnpm",
164
+ "jsWorkspaces": ["design-system", "backend", "web", "tools/e2e"],
165
+ "phpDirs": [".", "wpaos"],
166
+ "hooksDir": ".githooks",
167
+ "buildCommand": "cd design-system && pnpm run build && pnpm run build:blocks",
168
+ "wpPackages": [
169
+ { "path": "wpaos", "type": "plugin", "slug": "wpaos", "mainFile": "wpaos.php" },
170
+ { "path": "wpaos-blocks", "type": "plugin", "slug": "wpaos-blocks", "mainFile": "wpaos-blocks.php" },
171
+ { "path": "wpaos-theme", "type": "theme", "slug": "wpaos-theme" }
172
+ ],
173
+ "playgroundMounts": [
174
+ "./wpaos:/wordpress/wp-content/plugins/wpaos",
175
+ "./wpaos-blocks:/wordpress/wp-content/plugins/wpaos-blocks",
176
+ "./wpaos-theme:/wordpress/wp-content/themes/wpaos-theme"
177
+ ],
178
+ "wpeEnvironments": {
179
+ "production": { "install": "mysite", "gitUrl": "git@git.wpengine.com:mysite.git" },
180
+ "staging": { "install": "mysitestg", "gitUrl": "git@git.wpengine.com:mysitestg.git" },
181
+ "development":{ "install": "mysitedev", "gitUrl": "git@git.wpengine.com:mysitedev.git" }
182
+ }
183
+ }
184
+ ```
@@ -0,0 +1,151 @@
1
+ #!/usr/bin/env bash
2
+ # bootstrap.sh — one-command dev setup for a WordPress project or monorepo.
3
+ #
4
+ # Generalized from the wp-agent-os tools/setup.sh pattern. Idempotent: safe
5
+ # to re-run on an existing clone. Activates git hooks, installs PHP and JS
6
+ # dependencies, and verifies the environment.
7
+ #
8
+ # Usage:
9
+ # bash .agents/skills/wp-bootstrap/scripts/bootstrap.sh [OPTIONS]
10
+ #
11
+ # Options:
12
+ # --php-only Skip JS workspace installs
13
+ # --js-only Skip PHP/Composer installs
14
+ # --no-hooks Skip git hook activation
15
+ # --quiet Minimal output
16
+ #
17
+ # Reads wp-bootstrap.config.json from repo root if present:
18
+ # {
19
+ # "packageManager": "pnpm",
20
+ # "jsWorkspaces": ["design-system", "backend", "web", "tools/e2e"],
21
+ # "phpDirs": [".", "wpaos"],
22
+ # "hooksDir": ".githooks"
23
+ # }
24
+
25
+ set -uo pipefail
26
+ root="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
27
+ cd "$root"
28
+
29
+ PHP_ONLY=false; JS_ONLY=false; NO_HOOKS=false; QUIET=false
30
+ for arg in "$@"; do
31
+ case "$arg" in
32
+ --php-only) PHP_ONLY=true ;;
33
+ --js-only) JS_ONLY=true ;;
34
+ --no-hooks) NO_HOOKS=true ;;
35
+ --quiet) QUIET=true ;;
36
+ esac
37
+ done
38
+
39
+ OK=0; WARN=0
40
+ say() { $QUIET || printf '\n\033[1m→ %s\033[0m\n' "$*"; }
41
+ good() { $QUIET || printf ' \033[32m✓\033[0m %s\n' "$*"; ((OK++)); }
42
+ nope() { printf ' \033[33m⚠\033[0m %s\n' "$*" >&2; ((WARN++)); }
43
+
44
+ # ── Read optional config ──────────────────────────────────────────────────────
45
+ CONFIG_FILE="$root/wp-bootstrap.config.json"
46
+ if [ -f "$CONFIG_FILE" ] && command -v node >/dev/null 2>&1; then
47
+ PKG_MGR=$(node -e "process.stdout.write(require('$CONFIG_FILE').packageManager ?? '')")
48
+ HOOKS_DIR=$(node -e "process.stdout.write(require('$CONFIG_FILE').hooksDir ?? '.githooks')")
49
+ JS_WS=$(node -e "console.log((require('$CONFIG_FILE').jsWorkspaces ?? []).join('\n'))")
50
+ PHP_DIRS=$(node -e "console.log((require('$CONFIG_FILE').phpDirs ?? ['.']).join('\n'))")
51
+ else
52
+ # Auto-detect
53
+ if [ -f "pnpm-lock.yaml" ] || [ -f "pnpm-workspace.yaml" ]; then PKG_MGR="pnpm"
54
+ elif [ -f "yarn.lock" ]; then PKG_MGR="yarn"
55
+ else PKG_MGR="npm"; fi
56
+
57
+ HOOKS_DIR=".githooks"
58
+ [ -d ".husky" ] && HOOKS_DIR=".husky"
59
+
60
+ # Discover JS workspaces from pnpm-workspace.yaml
61
+ if [ -f "pnpm-workspace.yaml" ] && command -v node >/dev/null 2>&1; then
62
+ JS_WS=$(node -e "
63
+ const fs = require('fs');
64
+ const yaml = fs.readFileSync('pnpm-workspace.yaml','utf-8');
65
+ const pkgs = [...yaml.matchAll(/[-]\\s+['\"]?([^'\"#\\n]+)['\"]?/g)].map(m=>m[1].trim().replace(/\/\*\$/,''));
66
+ pkgs.filter(p=>fs.existsSync(p)).forEach(p=>console.log(p));
67
+ " 2>/dev/null || echo "")
68
+ else
69
+ JS_WS=""
70
+ fi
71
+
72
+ # Discover PHP dirs (any dir with its own composer.json)
73
+ PHP_DIRS="."
74
+ while IFS= read -r -d '' composer_file; do
75
+ dir="$(dirname "${composer_file#./}")"
76
+ [ "$dir" != "." ] && PHP_DIRS="$PHP_DIRS
77
+ $dir"
78
+ done < <(find . -maxdepth 3 -name "composer.json" \
79
+ -not -path "*/vendor/*" -not -path "*/node_modules/*" -print0)
80
+ fi
81
+
82
+ # ── 1. Git hooks ──────────────────────────────────────────────────────────────
83
+ if ! $NO_HOOKS; then
84
+ say "Activating git hooks (${HOOKS_DIR}/)"
85
+ if git rev-parse --git-dir >/dev/null 2>&1; then
86
+ if [ -d "$HOOKS_DIR" ]; then
87
+ git config core.hooksPath "$HOOKS_DIR"
88
+ chmod +x "$HOOKS_DIR"/* 2>/dev/null || true
89
+ good "core.hooksPath = $HOOKS_DIR ($(ls "$HOOKS_DIR" | grep -v README | tr '\n' ' '))"
90
+ else
91
+ nope "$HOOKS_DIR not found — create it and add a pre-push script"
92
+ fi
93
+ else
94
+ nope "Not a git repo — skipping hook activation"
95
+ fi
96
+ fi
97
+
98
+ # ── 2. PHP dependencies ───────────────────────────────────────────────────────
99
+ if ! $JS_ONLY && command -v composer >/dev/null 2>&1; then
100
+ while IFS= read -r php_dir; do
101
+ [ -z "$php_dir" ] && continue
102
+ [ ! -f "$root/$php_dir/composer.json" ] && continue
103
+ say "Composer install ($php_dir)"
104
+ if ( cd "$root/$php_dir" && composer install --no-interaction --quiet ); then
105
+ good "$php_dir: composer deps installed"
106
+ else
107
+ nope "$php_dir: composer install failed"
108
+ fi
109
+ done <<< "$PHP_DIRS"
110
+ elif ! $JS_ONLY; then
111
+ nope "composer not found — install Composer (https://getcomposer.org), then re-run"
112
+ fi
113
+
114
+ # ── 3. JS dependencies ────────────────────────────────────────────────────────
115
+ if ! $PHP_ONLY; then
116
+ if ! command -v "$PKG_MGR" >/dev/null 2>&1; then
117
+ nope "$PKG_MGR not found — install it, then re-run"
118
+ else
119
+ # Root package.json first
120
+ if [ -f "$root/package.json" ]; then
121
+ say "JS install root ($PKG_MGR)"
122
+ if ( cd "$root" && "$PKG_MGR" install --silent 2>/dev/null || "$PKG_MGR" install ); then
123
+ good "root: JS deps installed"
124
+ else
125
+ nope "root: $PKG_MGR install failed"
126
+ fi
127
+ fi
128
+
129
+ # Workspaces (if not handled by root install)
130
+ if [ -n "$JS_WS" ] && [ "$PKG_MGR" = "npm" ]; then
131
+ while IFS= read -r ws; do
132
+ [ -z "$ws" ] && continue
133
+ [ ! -f "$root/$ws/package.json" ] && continue
134
+ say "JS install $ws"
135
+ if ( cd "$root/$ws" && npm install --silent ); then
136
+ good "$ws: npm deps installed"
137
+ else
138
+ nope "$ws: npm install failed"
139
+ fi
140
+ done <<< "$JS_WS"
141
+ fi
142
+ fi
143
+ fi
144
+
145
+ # ── 4. Summary ────────────────────────────────────────────────────────────────
146
+ say "Bootstrap complete"
147
+ echo " PHP gate: composer fix && composer phpcs && composer phpstan"
148
+ echo " JS gate: ${PKG_MGR} run lint && ${PKG_MGR} test"
149
+ echo " Full gate: ${PKG_MGR} run gate (if configured)"
150
+ [ "$WARN" -gt 0 ] && echo " ⚠ $WARN warning(s) above — fix them, then re-run."
151
+ exit 0