diff --git a/.gitignore b/.gitignore index 7a9e0d5..afc45ba 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,9 @@ /ai_plan/ +/.pi/ /.worktrees/ /skills/atlassian/shared/scripts/.env /skills/atlassian/shared/scripts/node_modules/ /skills/atlassian/*/scripts/.env /skills/atlassian/*/scripts/node_modules/ /skills/web-automation/*/scripts/node_modules/ +/pi-package/skills/*/scripts/node_modules/ diff --git a/README.md b/README.md index a537ae2..738e246 100644 --- a/README.md +++ b/README.md @@ -122,13 +122,26 @@ The repo root now includes a pi package manifest that ships only the pi-specific - `scripts/sync-pi-package-skills.sh` - `scripts/verify-pi-resources.sh` -Install it into project-local pi settings from this checkout with: +Install it from a cloned checkout with the repo-owned one-liner: ```bash -pi install -l "$(pwd)" -pi list +./scripts/install-pi-package.sh --global ``` +For a project-local install instead: + +```bash +./scripts/install-pi-package.sh --local +``` + +Prerequisites: + +- Node.js 20+ +- `pi` +- either `pnpm` on `PATH`, or `corepack` support from the Node install + +The repo pins its pnpm version in `package.json` so Corepack-backed installs resolve consistently. + Before publishing or sharing a tarball, run: ```bash diff --git a/docs/PI.md b/docs/PI.md index 8572e45..4481a53 100644 --- a/docs/PI.md +++ b/docs/PI.md @@ -52,13 +52,39 @@ Workflow-heavy Pi skills split their shared setup across two docs: ## Package Install -The repo-level package manifest lives at root so Pi can install directly from this checkout: +The user-facing install flow is the repo-owned installer script, not a raw `pi install` command. + +Global install from a cloned checkout: ```bash -pi install -l "$(pwd)" -pi list +./scripts/install-pi-package.sh --global ``` +Project-local install from a cloned checkout: + +```bash +./scripts/install-pi-package.sh --local +``` + +Prerequisites for that one-liner: + +- Node.js 20+ +- `pi` +- either `pnpm` on `PATH`, or Node's bundled `corepack` support + +The installer uses `pnpm` directly when available and falls back to `corepack pnpm` otherwise. +The root `package.json` pins the pnpm version so Corepack-backed installs resolve consistently. + +That script: + +- runs `pi install` in the chosen scope +- installs the nested runtime dependencies for `atlassian` +- installs the nested runtime dependencies for `web-automation` +- fetches the CloakBrowser binary for `web-automation` +- prints `pi list` at the end so the active install is visible immediately + +For this cloned-checkout flow, local checkout package install keeps the runtime in `pi-package/skills//scripts`. Pi loads the skills from the package mirror in this repo; it does not copy them into `~/.pi/agent/skills//` or `.pi/skills//` unless you do a manual copy install. + The package surface intentionally ships: - `pi-package/skills/**` @@ -89,12 +115,15 @@ When a source Pi variant changes: npm pack --dry-run --json ``` +The installer intentionally does not run sync. It assumes the checked-in `pi-package/skills/*` mirror is already current. + The verifier is responsible for catching: - missing mirror directories - source/mirror drift - package metadata pointing at the wrong skill roots - missing shared Pi docs +- missing user-facing installer wiring ## Extension Decision diff --git a/package.json b/package.json index 6df90db..fa5eb84 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,7 @@ "docs/WEB-AUTOMATION.md", "pi-package/skills", "skills/reviewer-runtime/pi", + "scripts/install-pi-package.sh", "scripts/sync-pi-package-skills.sh", "scripts/verify-pi-resources.sh" ], @@ -35,5 +36,6 @@ "./pi-package/skills/implement-plan", "./pi-package/skills/web-automation" ] - } + }, + "packageManager": "pnpm@10.18.1+sha512.77a884a165cbba2d8d1c19e3b4880eee6d2fcabd0d879121e282196b80042351d5eb3ca0935fa599da1dc51265cc68816ad2bddd2a2de5ea9fdf92adbec7cd34" } diff --git a/pi-package/skills/atlassian/SKILL.md b/pi-package/skills/atlassian/SKILL.md index 3097e27..10d3507 100644 --- a/pi-package/skills/atlassian/SKILL.md +++ b/pi-package/skills/atlassian/SKILL.md @@ -40,12 +40,18 @@ pnpm install Pi can also load this repo through settings or package installs as documented in [docs/PI.md](../../../docs/PI.md). +If you installed this repo from a local checkout with `./scripts/install-pi-package.sh`, the runtime stays in the checkout mirror at `pi-package/skills/atlassian/scripts`. + ## Prerequisite Check (MANDATORY) -Run inside the installed skill directory. The command block below uses the global install path; for a project-local install, replace `~/.pi/agent/skills/atlassian/` with `.pi/skills/atlassian/`. +Run inside the skill runtime directory that matches your install style: + +- local checkout package install: `pi-package/skills/atlassian/scripts` +- project-local copied install: `.pi/skills/atlassian/scripts` +- global copied install: `~/.pi/agent/skills/atlassian/scripts` ```bash -cd ~/.pi/agent/skills/atlassian/scripts +cd pi-package/skills/atlassian/scripts node -e "require.resolve('commander');require.resolve('dotenv');console.log('OK: runtime dependencies installed')" node -e 'require("dotenv").config({ path: ".env" }); const required = ["ATLASSIAN_BASE_URL", "ATLASSIAN_EMAIL", "ATLASSIAN_API_TOKEN"]; const missing = required.filter((key) => !(process.env[key] || "").trim()); if (missing.length) { console.error("Missing required Atlassian config: " + missing.join(", ")); process.exit(1); } console.log("OK: Atlassian config present")' pnpm atlassian health diff --git a/pi-package/skills/web-automation/SKILL.md b/pi-package/skills/web-automation/SKILL.md index 706604e..5a021e7 100644 --- a/pi-package/skills/web-automation/SKILL.md +++ b/pi-package/skills/web-automation/SKILL.md @@ -41,6 +41,8 @@ pnpm rebuild better-sqlite3 esbuild Pi can also load this repo through settings or package installs as documented in [docs/PI.md](../../../docs/PI.md). +If you installed this repo from a local checkout with `./scripts/install-pi-package.sh`, the runtime stays in the checkout mirror at `pi-package/skills/web-automation/scripts`. + ## Updating CloakBrowser Run inside the installed `scripts/` directory for the pi skill. The commands below work for both global and project-local installs as long as you run them from the installed `scripts/` directory. @@ -54,10 +56,14 @@ pnpm rebuild better-sqlite3 esbuild ## Prerequisite Check (MANDATORY) -Before running automation, verify CloakBrowser and Playwright Core are installed and wired correctly. The command block below uses the global install path; for a project-local install, replace `~/.pi/agent/skills/web-automation/` with `.pi/skills/web-automation/`. +Before running automation, verify the runtime from the location that matches your install style: + +- local checkout package install: `pi-package/skills/web-automation/scripts` +- project-local copied install: `.pi/skills/web-automation/scripts` +- global copied install: `~/.pi/agent/skills/web-automation/scripts` ```bash -cd ~/.pi/agent/skills/web-automation/scripts +cd pi-package/skills/web-automation/scripts node check-install.js ``` @@ -68,7 +74,7 @@ If the check fails, stop and return: If runtime fails with missing native bindings for `better-sqlite3` or `esbuild`, run the same commands from your installed `scripts/` directory: ```bash -cd ~/.pi/agent/skills/web-automation/scripts +cd pi-package/skills/web-automation/scripts pnpm approve-builds pnpm rebuild better-sqlite3 esbuild ``` diff --git a/pi-package/skills/web-automation/scripts/check-install.js b/pi-package/skills/web-automation/scripts/check-install.js index 50e4884..2a60c8a 100644 --- a/pi-package/skills/web-automation/scripts/check-install.js +++ b/pi-package/skills/web-automation/scripts/check-install.js @@ -18,9 +18,11 @@ async function main() { try { await import("cloakbrowser"); await import("playwright-core"); + await import("better-sqlite3"); + await import("esbuild"); } catch (error) { fail( - "Missing dependency/config: web-automation requires cloakbrowser and playwright-core.", + "Missing dependency/config: web-automation requires cloakbrowser, playwright-core, better-sqlite3, and esbuild.", error instanceof Error ? error.message : String(error) ); } @@ -32,6 +34,7 @@ async function main() { } process.stdout.write("OK: cloakbrowser + playwright-core installed\n"); + process.stdout.write("OK: better-sqlite3 + esbuild installed\n"); process.stdout.write("OK: CloakBrowser integration detected in browse.ts\n"); } diff --git a/scripts/install-pi-package.sh b/scripts/install-pi-package.sh new file mode 100755 index 0000000..64de899 --- /dev/null +++ b/scripts/install-pi-package.sh @@ -0,0 +1,105 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd) + +usage() { + cat <<'EOF' +Usage: + ./scripts/install-pi-package.sh --global + ./scripts/install-pi-package.sh --local + +Options: + --global Install the repo path into ~/.pi/agent/settings.json + --local Install the repo path into .pi/settings.json for the current project +EOF +} + +require_command() { + local command_name=$1 + if ! command -v "$command_name" >/dev/null 2>&1; then + echo "Missing required command: $command_name" >&2 + exit 1 + fi +} + +pnpm_cmd=() + +resolve_pnpm() { + if command -v pnpm >/dev/null 2>&1; then + pnpm_cmd=(pnpm) + return + fi + + if command -v corepack >/dev/null 2>&1; then + pnpm_cmd=(corepack pnpm) + return + fi + + echo "Missing required command: pnpm (or corepack)" >&2 + exit 1 +} + +run_pnpm() { + "${pnpm_cmd[@]}" "$@" +} + +require_node_20() { + local node_major + node_major=$(node -p "process.versions.node.split('.')[0]") + if (( node_major < 20 )); then + echo "Node.js 20+ is required. Found Node.js $(node -v)." >&2 + exit 1 + fi +} + +install_scope= +if [[ $# -ne 1 ]]; then + usage >&2 + exit 1 +fi + +case "$1" in + --global) + install_scope="global" + ;; + --local) + install_scope="local" + ;; + -h|--help) + usage + exit 0 + ;; + *) + usage >&2 + exit 1 + ;; +esac + +require_command pi +require_command node +require_node_20 +resolve_pnpm + +case "$install_scope" in + global) + pi install "$ROOT_DIR" + ;; + local) + pi install -l "$ROOT_DIR" + ;; +esac + +echo "Bootstrapping Atlassian runtime dependencies..." +run_pnpm install --frozen-lockfile --dir "${ROOT_DIR}/pi-package/skills/atlassian/scripts" + +echo "Bootstrapping web-automation runtime dependencies..." +run_pnpm install --frozen-lockfile --dir "${ROOT_DIR}/pi-package/skills/web-automation/scripts" +run_pnpm --dir "${ROOT_DIR}/pi-package/skills/web-automation/scripts" exec cloakbrowser install +echo "Rebuilding native web-automation dependencies..." +run_pnpm rebuild --dir "${ROOT_DIR}/pi-package/skills/web-automation/scripts" better-sqlite3 esbuild + +echo "Installed Pi packages now visible to this scope:" +pi list + +echo "Pi package installed (${install_scope}) and runtime dependencies bootstrapped." diff --git a/scripts/verify-pi-resources.sh b/scripts/verify-pi-resources.sh index 49b3709..804442d 100755 --- a/scripts/verify-pi-resources.sh +++ b/scripts/verify-pi-resources.sh @@ -17,6 +17,7 @@ REQUIRED_FILES=( "skills/web-automation/pi/SKILL.md" "skills/reviewer-runtime/pi/run-review.sh" "skills/reviewer-runtime/pi/notify-telegram.sh" + "scripts/install-pi-package.sh" "scripts/sync-pi-package-skills.sh" "pi-package/skills/atlassian/SKILL.md" "pi-package/skills/create-plan/SKILL.md" @@ -34,6 +35,7 @@ done test -x skills/reviewer-runtime/pi/run-review.sh test -x skills/reviewer-runtime/pi/notify-telegram.sh +test -x scripts/install-pi-package.sh test -x scripts/sync-pi-package-skills.sh find skills/web-automation/pi/scripts -type f -print -quit | grep -q . find skills/atlassian/pi/scripts -type f -print -quit | grep -q . @@ -43,6 +45,15 @@ for file in skills/create-plan/pi/SKILL.md skills/do-task/pi/SKILL.md skills/imp grep -q 'docs/PI-COMMON-REVIEWER.md' "$file" done +grep -q 'pi-package/skills/atlassian/scripts' skills/atlassian/pi/SKILL.md +grep -q 'pi-package/skills/web-automation/scripts' skills/web-automation/pi/SKILL.md +grep -q 'local checkout package install keeps the runtime in `pi-package/skills//scripts`' docs/PI.md + +grep -q 'install-pi-package.sh --global' docs/PI.md +grep -q 'install-pi-package.sh --local' docs/PI.md +grep -q 'install-pi-package.sh --global' README.md +grep -q 'install-pi-package.sh --local' README.md + for family in atlassian create-plan do-task implement-plan web-automation; do source_dir="skills/${family}/pi" source_skill_md="${source_dir}/SKILL.md" @@ -55,14 +66,19 @@ for family in atlassian create-plan do-task implement-plan web-automation; do test "$skill_name" = "$(basename "$mirror_dir")" test "$skill_name" = "$(awk '/^name:/ { print $2; exit }' "$mirror_skill_md")" - diff -qr --exclude '.DS_Store' "$source_dir" "$mirror_dir" >/dev/null + diff -qr \ + --exclude '.DS_Store' \ + --exclude 'node_modules' \ + "$source_dir" "$mirror_dir" >/dev/null while IFS= read -r -d '' source_path; do rel_path=${source_path#"$source_dir"/} mirror_path="${mirror_dir}/${rel_path}" test -e "$mirror_path" test "$(stat -f '%Lp' "$source_path")" = "$(stat -f '%Lp' "$mirror_path")" - done < <(find "$source_dir" -mindepth 1 -print0) + done < <(find "$source_dir" \ + \( -name '.DS_Store' -o -name 'node_modules' \) -prune -o \ + -mindepth 1 -print0) done ! grep -nE 'update_plan|plan mode|sub-agent|subagents' \ @@ -100,6 +116,7 @@ if (!Array.isArray(pkg.files) || pkg.files.length === 0) { for (const requiredFile of [ "pi-package/skills", "docs/PI-COMMON-REVIEWER.md", + "scripts/install-pi-package.sh", "scripts/sync-pi-package-skills.sh", ]) { if (!pkg.files.includes(requiredFile)) { diff --git a/skills/atlassian/pi/SKILL.md b/skills/atlassian/pi/SKILL.md index 3097e27..10d3507 100644 --- a/skills/atlassian/pi/SKILL.md +++ b/skills/atlassian/pi/SKILL.md @@ -40,12 +40,18 @@ pnpm install Pi can also load this repo through settings or package installs as documented in [docs/PI.md](../../../docs/PI.md). +If you installed this repo from a local checkout with `./scripts/install-pi-package.sh`, the runtime stays in the checkout mirror at `pi-package/skills/atlassian/scripts`. + ## Prerequisite Check (MANDATORY) -Run inside the installed skill directory. The command block below uses the global install path; for a project-local install, replace `~/.pi/agent/skills/atlassian/` with `.pi/skills/atlassian/`. +Run inside the skill runtime directory that matches your install style: + +- local checkout package install: `pi-package/skills/atlassian/scripts` +- project-local copied install: `.pi/skills/atlassian/scripts` +- global copied install: `~/.pi/agent/skills/atlassian/scripts` ```bash -cd ~/.pi/agent/skills/atlassian/scripts +cd pi-package/skills/atlassian/scripts node -e "require.resolve('commander');require.resolve('dotenv');console.log('OK: runtime dependencies installed')" node -e 'require("dotenv").config({ path: ".env" }); const required = ["ATLASSIAN_BASE_URL", "ATLASSIAN_EMAIL", "ATLASSIAN_API_TOKEN"]; const missing = required.filter((key) => !(process.env[key] || "").trim()); if (missing.length) { console.error("Missing required Atlassian config: " + missing.join(", ")); process.exit(1); } console.log("OK: Atlassian config present")' pnpm atlassian health diff --git a/skills/web-automation/pi/SKILL.md b/skills/web-automation/pi/SKILL.md index 706604e..5a021e7 100644 --- a/skills/web-automation/pi/SKILL.md +++ b/skills/web-automation/pi/SKILL.md @@ -41,6 +41,8 @@ pnpm rebuild better-sqlite3 esbuild Pi can also load this repo through settings or package installs as documented in [docs/PI.md](../../../docs/PI.md). +If you installed this repo from a local checkout with `./scripts/install-pi-package.sh`, the runtime stays in the checkout mirror at `pi-package/skills/web-automation/scripts`. + ## Updating CloakBrowser Run inside the installed `scripts/` directory for the pi skill. The commands below work for both global and project-local installs as long as you run them from the installed `scripts/` directory. @@ -54,10 +56,14 @@ pnpm rebuild better-sqlite3 esbuild ## Prerequisite Check (MANDATORY) -Before running automation, verify CloakBrowser and Playwright Core are installed and wired correctly. The command block below uses the global install path; for a project-local install, replace `~/.pi/agent/skills/web-automation/` with `.pi/skills/web-automation/`. +Before running automation, verify the runtime from the location that matches your install style: + +- local checkout package install: `pi-package/skills/web-automation/scripts` +- project-local copied install: `.pi/skills/web-automation/scripts` +- global copied install: `~/.pi/agent/skills/web-automation/scripts` ```bash -cd ~/.pi/agent/skills/web-automation/scripts +cd pi-package/skills/web-automation/scripts node check-install.js ``` @@ -68,7 +74,7 @@ If the check fails, stop and return: If runtime fails with missing native bindings for `better-sqlite3` or `esbuild`, run the same commands from your installed `scripts/` directory: ```bash -cd ~/.pi/agent/skills/web-automation/scripts +cd pi-package/skills/web-automation/scripts pnpm approve-builds pnpm rebuild better-sqlite3 esbuild ``` diff --git a/skills/web-automation/pi/scripts/check-install.js b/skills/web-automation/pi/scripts/check-install.js index 50e4884..2a60c8a 100644 --- a/skills/web-automation/pi/scripts/check-install.js +++ b/skills/web-automation/pi/scripts/check-install.js @@ -18,9 +18,11 @@ async function main() { try { await import("cloakbrowser"); await import("playwright-core"); + await import("better-sqlite3"); + await import("esbuild"); } catch (error) { fail( - "Missing dependency/config: web-automation requires cloakbrowser and playwright-core.", + "Missing dependency/config: web-automation requires cloakbrowser, playwright-core, better-sqlite3, and esbuild.", error instanceof Error ? error.message : String(error) ); } @@ -32,6 +34,7 @@ async function main() { } process.stdout.write("OK: cloakbrowser + playwright-core installed\n"); + process.stdout.write("OK: better-sqlite3 + esbuild installed\n"); process.stdout.write("OK: CloakBrowser integration detected in browse.ts\n"); }