@piagent/platform 1.2.3 → 1.2.4

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
@@ -2,6 +2,16 @@
2
2
 
3
3
  This file records release-facing changes for Pi Agent Platform. Copy the relevant version block into GitHub Releases when publishing a tag.
4
4
 
5
+ ## v1.2.4 - 2026-07-30
6
+
7
+ ### Changed
8
+
9
+ - `piagent-update` remains a global machine update first; optional `--project <path>` now runs a post-update legacy project migration and strict-share doctor when a maintainer wants that extra check.
10
+
11
+ - Documented the global `npm exec --package @piagent/platform@X.Y.Z -- piagent-update ...` bootstrap command for machines that do not have the global `piagent-update` helper yet.
12
+
13
+ - `piagent-update` now falls back to a user-writable npm global prefix when the default prefix is locked by the OS, avoiding `/usr/local/lib/node_modules` permission failures during team rollout.
14
+
5
15
  ## v1.2.3 - 2026-07-30
6
16
 
7
17
  ### Added
package/README.md CHANGED
@@ -290,7 +290,7 @@ This repository intentionally excludes:
290
290
 
291
291
  ## Maturity
292
292
 
293
- The current package version is read from package metadata and release tags. Personal machines may follow the unpinned package source when accepting ongoing updates; production/team quickstarts and committed project settings should pin an explicit tag such as `v1.2.3` or a reviewed commit.
293
+ The current package version is read from package metadata and release tags. Personal machines may follow the unpinned package source when accepting ongoing updates; production/team quickstarts and committed project settings should pin an explicit tag such as `v1.2.4` or a reviewed commit.
294
294
 
295
295
  Ready for:
296
296
 
@@ -464,12 +464,15 @@ Các lệnh này chạy ngoài Pi.
464
464
  | Command | Dùng khi nào |
465
465
  |---|---|
466
466
  | `npm install -g --ignore-scripts @earendil-works/pi-coding-agent@0.82.0` | Cài Pi CLI tương thích với release hiện tại. |
467
- | `npm install -g --ignore-scripts @piagent/platform@1.2.3` | Cài terminal helper `piagent-*` từ release tag hiện tại. |
468
- | `pi install git:github.com/Vt-mmm/piagent@v1.2.3` | Cài pinned release khi cần reproducible team setup. |
467
+ | `npm install -g --ignore-scripts @piagent/platform@1.2.4` | Cài terminal helper `piagent-*` từ release tag hiện tại. |
468
+ | `pi install git:github.com/Vt-mmm/piagent@v1.2.4` | Cài pinned release khi cần reproducible team setup. |
469
469
  | `pi install git:github.com/Vt-mmm/piagent` | Cài latest package platform cho máy cá nhân/sandbox. |
470
470
  | `piagent-update --check` | Báo version hiện tại vs version sẽ lên cho cả ba thành phần; không cài gì. |
471
- | `piagent-update` | Full update một lệnh: Pi host → npm-global helper → Pi package, đúng thứ tự release yêu cầu. Thêm `--project <path>` để chạy doctor sau. |
471
+ | `piagent-update` | Full update global một lệnh cho cả máy: Pi host → npm-global helper → Pi package, đúng thứ tự release yêu cầu. |
472
472
  | `piagent-update --version X.Y.Z` | Update tới đúng một release thay vì latest; dùng cho rollout theo lô hoặc rollback. |
473
+ | `piagent-update --project <path>` | Bước phụ sau global update: migrate project cũ nếu có rồi chạy doctor strict-share cho project đó. |
474
+ | `piagent-update --npm-prefix ~/.pi/npm-global` | Ép updater cài host/helper vào npm global prefix của user; hữu ích khi `/usr/local/lib/node_modules` không ghi được. |
475
+ | `npm exec -y --package @piagent/platform@X.Y.Z -- piagent-update --version X.Y.Z --force` | Bootstrap/update global cho máy chưa có `piagent-update`; chạy từ Terminal, không cần mở Pi. |
473
476
  | `PIAGENT_NO_UPDATE_CHECK=1` | Tắt notice "có bản mới" ở đầu session Pi. Mặc định bật, hỏi registry nhiều nhất một lần mỗi 24 giờ ở tiến trình nền. |
474
477
  | Cài exact Pi host của release, rồi `npm install -g --ignore-scripts @piagent/platform@X.Y.Z` và `piagent-install --stable` | Sequence thủ công tương đương. Thứ tự bắt buộc: `piagent-install` fail nếu Pi host lệch bản pin và không tự cài host. Version pin của từng release nằm trong [release/install policy](release-install-policy.md). |
475
478
  | Cài exact Pi host ghi trong release cũ, rồi helper `vPREVIOUS` và `piagent-install --stable` | Full rollback; đánh giá dependency risk của host cũ trước khi hạ version. |
@@ -14,9 +14,9 @@ Repo này phải chạy được cho nhiều project/domain khác nhau. Vì vậ
14
14
 
15
15
  | Use case | Package source |
16
16
  |---|---|
17
- | Team pinned release | `git:github.com/Vt-mmm/piagent@v1.2.3` |
17
+ | Team pinned release | `git:github.com/Vt-mmm/piagent@v1.2.4` |
18
18
  | Personal/sandbox dev | `git:github.com/Vt-mmm/piagent` |
19
- | Registry distribution | `npm:@piagent/platform@1.2.3` |
19
+ | Registry distribution | `npm:@piagent/platform@1.2.4` |
20
20
  | Enterprise npm (fork under another scope) | `npm:@your-scope/platform@x.y.z` |
21
21
  | Local platform dev | `/path/to/piagent` |
22
22
 
@@ -26,7 +26,7 @@ Latest tiện cho máy cá nhân muốn nhận cập nhật nhanh. Pin tag/commi
26
26
 
27
27
  | Channel | Command | Target | Policy |
28
28
  |---|---|---|---|
29
- | `stable` | `bash scripts/install-global.sh --stable` | Helper release tag resolved to commit SHA, currently `v1.2.3` | Install the Pi package matching the helper. |
29
+ | `stable` | `bash scripts/install-global.sh --stable` | Helper release tag resolved to commit SHA, currently `v1.2.4` | Install the Pi package matching the helper. |
30
30
  | `exact` | `bash scripts/install-global.sh --version vX.Y.Z --resolve-tag` | Requested tag resolved to commit SHA | Pi-package-only rollout, rollback, and incident recovery. |
31
31
  | `dev` | `bash scripts/install-global.sh --dev` | Moving Git source | Personal/sandbox only; do not commit into project settings. |
32
32
  | `local` | `bash scripts/install-global.sh --local` | Current checkout path | Platform development only. |
@@ -53,7 +53,7 @@ Root `package.json` có `pi` manifest trỏ tới:
53
53
  Do đó team có thể:
54
54
 
55
55
  ```bash
56
- pi install git:github.com/Vt-mmm/piagent@v1.2.3
56
+ pi install git:github.com/Vt-mmm/piagent@v1.2.4
57
57
  ```
58
58
 
59
59
  Không cần biết internal folder `packages/piagent-core`. Source không pin chỉ dành cho personal/sandbox như bảng channel ở trên.
@@ -65,12 +65,12 @@ Team nên install global package một lần:
65
65
  ```bash
66
66
  node --version # >= 22.19.0
67
67
  npm install -g --ignore-scripts @earendil-works/pi-coding-agent@0.82.0
68
- npm install -g --ignore-scripts @piagent/platform@1.2.3
68
+ npm install -g --ignore-scripts @piagent/platform@1.2.4
69
69
  piagent-install --stable --dry-run
70
70
  piagent-install --stable
71
71
  ```
72
72
 
73
- `pi install git:github.com/Vt-mmm/piagent@v1.2.3` vẫn hợp lệ nếu chỉ cần cài Pi package. Lệnh đó không tự tạo các binary terminal `piagent-*`; muốn có helper global thì dùng `npm install -g --ignore-scripts @piagent/platform@1.2.3`.
73
+ `pi install git:github.com/Vt-mmm/piagent@v1.2.4` vẫn hợp lệ nếu chỉ cần cài Pi package. Lệnh đó không tự tạo các binary terminal `piagent-*`; muốn có helper global thì dùng `npm install -g --ignore-scripts @piagent/platform@1.2.4`.
74
74
 
75
75
  Support matrix hiện tại: macOS Apple Silicon + Bash và Linux x64 + Bash đã được verify; macOS Intel + Bash và Linux ARM64 + Bash là supported target cần chạy smoke trước rollout; native Windows chưa phải target rollout team; WSL2 experimental. Chi tiết và version runtime nằm trong [release/install policy](release-install-policy.md).
76
76
 
@@ -120,7 +120,7 @@ Nếu muốn commit sẵn `.pi/piagent-profile.json` vào repo hoặc bootstrap
120
120
  ```bash
121
121
  bash scripts/setup.sh /path/to/project \
122
122
  --profile be-readonly-fe \
123
- --package-source git:github.com/Vt-mmm/piagent@v1.2.3 \
123
+ --package-source git:github.com/Vt-mmm/piagent@v1.2.4 \
124
124
  --mcp-preset core \
125
125
  --subagents-preset safe
126
126
  ```
@@ -189,13 +189,34 @@ Files không commit:
189
189
 
190
190
  [Release/install policy](release-install-policy.md) là checklist canonical duy nhất. Production docs chỉ được promote sau khi tag đã tồn tại và stable dry-run resolve đúng commit SHA.
191
191
 
192
- Full platform update phải đồng bộ Pi host, npm-global helper và Pi package:
192
+ Full platform update phải đồng bộ Pi host, npm-global helper và Pi package cho cả máy:
193
+
194
+ ```bash
195
+ piagent-update --version X.Y.Z
196
+ ```
197
+
198
+ Máy chưa có helper dùng bootstrap all-in-one:
199
+
200
+ ```bash
201
+ npm exec -y --package @piagent/platform@X.Y.Z -- piagent-update --version X.Y.Z --force
202
+ ```
203
+
204
+ Máy bị khóa npm global ở `/usr/local` không cần `sudo`: updater sẽ dùng prefix user-local `~/.pi/npm-global` hoặc maintainer có thể truyền `--npm-prefix <path>`.
205
+
206
+ Project migration/doctor là bước kiểm tra sau global update, chỉ chạy cho repo cần xác minh:
207
+
208
+ ```bash
209
+ piagent-update --version X.Y.Z --project /path/to/project
210
+ ```
211
+
212
+ Sequence thủ công tương đương:
193
213
 
194
214
  ```bash
195
215
  npm install -g --ignore-scripts @earendil-works/pi-coding-agent@0.82.0
196
216
  npm install -g --ignore-scripts @piagent/platform@X.Y.Z
197
217
  piagent-install --stable --dry-run
198
218
  piagent-install --stable
219
+ piagent-migrate /path/to/project --apply --remove-old
199
220
  piagent-doctor /path/to/project --strict-share
200
221
  ```
201
222
 
@@ -18,12 +18,12 @@ Support matrix release hiện tại: macOS Apple Silicon + Bash và Linux x64 +
18
18
  ```bash
19
19
  node --version # >= 22.19.0
20
20
  npm install -g --ignore-scripts @earendil-works/pi-coding-agent@0.82.0
21
- npm install -g --ignore-scripts @piagent/platform@1.2.3
21
+ npm install -g --ignore-scripts @piagent/platform@1.2.4
22
22
  piagent-install --stable --dry-run
23
23
  piagent-install --stable
24
24
  ```
25
25
 
26
- Khi seed `.pi/settings.json` cho team/repo cần audit lặp lại, giữ package source dạng pinned tag như `git:github.com/Vt-mmm/piagent@v1.2.3`. Máy cá nhân có thể dùng `git:github.com/Vt-mmm/piagent` để theo latest.
26
+ Khi seed `.pi/settings.json` cho team/repo cần audit lặp lại, giữ package source dạng pinned tag như `git:github.com/Vt-mmm/piagent@v1.2.4`. Máy cá nhân có thể dùng `git:github.com/Vt-mmm/piagent` để theo latest.
27
27
 
28
28
  Nếu đang ở source checkout của platform, dùng helper theo channel để preview trước khi đổi:
29
29
 
@@ -99,7 +99,7 @@ install package once
99
99
 
100
100
  ```bash
101
101
  npm install -g --ignore-scripts @earendil-works/pi-coding-agent@0.82.0
102
- npm install -g --ignore-scripts @piagent/platform@1.2.3
102
+ npm install -g --ignore-scripts @piagent/platform@1.2.4
103
103
  piagent-install --stable --dry-run
104
104
  piagent-install --stable
105
105
  ```
@@ -282,7 +282,7 @@ Không phải daily default. Dùng khi muốn tạo sẵn `.pi` files cho projec
282
282
  bash /path/to/piagent/scripts/setup.sh /path/to/project \
283
283
  --project-only \
284
284
  --profile auto \
285
- --package-source git:github.com/Vt-mmm/piagent@v1.2.3 \
285
+ --package-source git:github.com/Vt-mmm/piagent@v1.2.4 \
286
286
  --mcp-preset core \
287
287
  --subagents-preset safe
288
288
  ```
@@ -894,8 +894,8 @@ Watchdog là optional adversarial reviewer ở cuối turn, không bật mặc
894
894
 
895
895
  | Command | Dùng để |
896
896
  |---|---|
897
- | `npm install -g --ignore-scripts @piagent/platform@1.2.3` | Cài terminal helper `piagent-*` từ release tag hiện tại. |
898
- | `pi install git:github.com/Vt-mmm/piagent@v1.2.3` | Install pinned release cho reproducible team setup. |
897
+ | `npm install -g --ignore-scripts @piagent/platform@1.2.4` | Cài terminal helper `piagent-*` từ release tag hiện tại. |
898
+ | `pi install git:github.com/Vt-mmm/piagent@v1.2.4` | Install pinned release cho reproducible team setup. |
899
899
  | `pi install git:github.com/Vt-mmm/piagent` | Install latest platform package cho máy cá nhân/sandbox. |
900
900
  | Cài exact Pi host của release, rồi `npm install -g --ignore-scripts @piagent/platform@X.Y.Z` và `piagent-install --stable` | Full update: đồng bộ host, terminal helper và Pi package. Mỗi release pin một Pi host chính xác; lấy đúng version của release đang cài trong [release/install policy](release-install-policy.md). |
901
901
  | Cài exact Pi host ghi trong release cũ, rồi helper `vPREVIOUS` và `piagent-install --stable` | Full rollback; đánh giá lại dependency findings của host cũ trước khi hạ version. |
@@ -1002,7 +1002,7 @@ Mở lại Pi session sau khi install.
1002
1002
  Cài lại terminal helper đúng release rồi kiểm tra `PATH`:
1003
1003
 
1004
1004
  ```bash
1005
- npm install -g --ignore-scripts @piagent/platform@1.2.3
1005
+ npm install -g --ignore-scripts @piagent/platform@1.2.4
1006
1006
  command -v piagent-install
1007
1007
  ```
1008
1008
 
@@ -10,7 +10,7 @@ This file is the canonical install, update, rollback, and release checklist. Oth
10
10
 
11
11
  All supported environments require Node.js `>=22.19.0` and Pi Coding Agent `0.82.0`. The Pi host is installed as a Node CLI; Pi Agent Platform still defines its own release matrix because the terminal helpers and shell policy rely on Bash/POSIX behavior.
12
12
 
13
- | Surface | Status for v1.2.3 | Rollout guidance |
13
+ | Surface | Status for v1.2.4 | Rollout guidance |
14
14
  |---|---|---|
15
15
  | macOS Apple Silicon (`darwin/arm64`) + Bash | Verified for this release. | Safe default for team rollout after normal project smoke tests. |
16
16
  | Linux x64 + Bash | Verified in GitHub Actions. | Safe default for CI/server usage after normal project smoke tests. |
@@ -33,7 +33,7 @@ These three components are versioned independently. A full install, update, or r
33
33
 
34
34
  | Channel | Source shape | Mutability | Use when |
35
35
  |---|---|---:|---|
36
- | `stable` | `git:github.com/Vt-mmm/piagent@<resolved-commit-sha>` from `v1.2.3` | Fixed after resolution | Default for team rollout. |
36
+ | `stable` | `git:github.com/Vt-mmm/piagent@<resolved-commit-sha>` from `v1.2.4` | Fixed after resolution | Default for team rollout. |
37
37
  | `exact` | Tag, reviewed commit, or a tag resolved with `--resolve-tag` | Fixed when using a commit SHA | Pi-package-only roll forward, rollback, or reproduction. |
38
38
  | `dev` | `git:github.com/Vt-mmm/piagent` | Moving | Personal machine or sandbox only. |
39
39
  | `local` | `/path/to/piagent` | Local workspace | Platform development and dry-run validation. |
@@ -53,7 +53,7 @@ Use this flow when the team needs both terminal commands and the Pi package:
53
53
  ```bash
54
54
  node --version # >= 22.19.0
55
55
  npm install -g --ignore-scripts @earendil-works/pi-coding-agent@0.82.0
56
- npm install -g --ignore-scripts @piagent/platform@1.2.3
56
+ npm install -g --ignore-scripts @piagent/platform@1.2.4
57
57
  piagent-install --stable --dry-run
58
58
  piagent-install --stable
59
59
  ```
@@ -61,8 +61,8 @@ piagent-install --stable
61
61
  The stable preview and apply output includes:
62
62
 
63
63
  ```text
64
- currentRelease: v1.2.3 (helper package version)
65
- tag: v1.2.3
64
+ currentRelease: v1.2.4 (helper package version)
65
+ tag: v1.2.4
66
66
  resolvedCommit: <40-char-sha>
67
67
  source: git:github.com/Vt-mmm/piagent@<40-char-sha>
68
68
  ```
@@ -79,7 +79,7 @@ bash scripts/install-global.sh --stable
79
79
  Use this only when terminal commands are not needed:
80
80
 
81
81
  ```bash
82
- pi install git:github.com/Vt-mmm/piagent@v1.2.3
82
+ pi install git:github.com/Vt-mmm/piagent@v1.2.4
83
83
  ```
84
84
 
85
85
  Direct `pi install` does not create `piagent-*` commands on `PATH`.
@@ -91,11 +91,27 @@ Direct `pi install` does not create `piagent-*` commands on `PATH`.
91
91
  ```bash
92
92
  piagent-update --check
93
93
  piagent-update --dry-run
94
- piagent-update --project /path/to/project
94
+ piagent-update --version X.Y.Z
95
95
  ```
96
96
 
97
97
  It resolves the target helper version and, from that version's published metadata, the exact Pi host that version pins — both before installing anything, so `--check` and `--dry-run` describe a real run. It then installs the host, replaces the helper, verifies that the version now on disk is the one it asked for, and only then runs the new helper's installer for the Pi package. `--version X.Y.Z` targets an exact release instead of latest, `--no-host` and `--no-package` narrow the run, and anything after `--` is passed to `piagent-install`.
98
98
 
99
+ Project migration and doctor are post-update checks, not the update scope. Run them only for the project being verified:
100
+
101
+ ```bash
102
+ piagent-update --version X.Y.Z --project /path/to/project
103
+ ```
104
+
105
+ With `--project`, the updater migrates legacy project state if needed and runs `piagent-doctor --strict-share`; use `--no-migrate` only when debugging a migration.
106
+
107
+ If the machine's default npm global prefix is locked by the OS, for example `/usr/local/lib/node_modules`, the updater uses `~/.pi/npm-global` for this rollout and prints the `PATH` line to add later. Do not run project update/doctor as root, because that can leave project files owned by root. Maintainers can force a specific prefix with `--npm-prefix <path>`.
108
+
109
+ For a fresh machine that does not have `piagent-update` yet, bootstrap the same all-in-one flow without opening Pi:
110
+
111
+ ```bash
112
+ npm exec -y --package @piagent/platform@X.Y.Z -- piagent-update --version X.Y.Z --force
113
+ ```
114
+
99
115
  Running it from a git checkout is refused rather than replacing that checkout's commands with a published build; update a checkout with `git pull` and `install-global.sh --local`.
100
116
 
101
117
  The same sequence by hand, which must keep this order because `piagent-install` fails against a host that does not match the version it pins and does not install one itself:
@@ -21,7 +21,7 @@ This document covers the packaged guard, project profiles, capability locks, ins
21
21
  - The operator, operating-system account, Pi host, and explicitly trusted project repository are trusted to execute code.
22
22
  - Project-local Pi resources are loaded only after Pi project trust or an explicit operator override.
23
23
  - A human remains available to approve destructive and external-provider actions.
24
- - Supported release verification covers macOS Apple Silicon + Bash, Linux x64 + Bash, Node.js `>=22.19.0`, and the exact Pi host version declared by the release. macOS Intel + Bash and Linux ARM64 + Bash are supported targets that need local smoke verification before broad rollout. Native Windows is not a team-rollout target for v1.2.3, and WSL2 is experimental/unverified.
24
+ - Supported release verification covers macOS Apple Silicon + Bash, Linux x64 + Bash, Node.js `>=22.19.0`, and the exact Pi host version declared by the release. macOS Intel + Bash and Linux ARM64 + Bash are supported targets that need local smoke verification before broad rollout. Native Windows is not a team-rollout target for v1.2.4, and WSL2 is experimental/unverified.
25
25
  - Registry, GitHub, model-provider, MCP-provider, and Vercel controls are external dependencies. Their account security and platform guarantees are not replaced by this repository.
26
26
 
27
27
  ## Threat actors and failure modes
@@ -9,7 +9,7 @@ Một thành viên mới không cần biết local path của maintainer. Luồn
9
9
  ```bash
10
10
  node --version # >= 22.19.0
11
11
  npm install -g --ignore-scripts @earendil-works/pi-coding-agent@0.82.0
12
- npm install -g --ignore-scripts @piagent/platform@1.2.3
12
+ npm install -g --ignore-scripts @piagent/platform@1.2.4
13
13
  piagent-install --stable
14
14
  cd /path/to/project
15
15
  pi
@@ -43,7 +43,7 @@ Mặc định team dùng stable helper:
43
43
  ```bash
44
44
  node --version # >= 22.19.0
45
45
  npm install -g --ignore-scripts @earendil-works/pi-coding-agent@0.82.0
46
- npm install -g --ignore-scripts @piagent/platform@1.2.3
46
+ npm install -g --ignore-scripts @piagent/platform@1.2.4
47
47
  piagent-install --stable --dry-run
48
48
  piagent-install --stable
49
49
  ```
@@ -68,10 +68,26 @@ Một lệnh, đúng thứ tự, cho cả ba thành phần:
68
68
 
69
69
  ```bash
70
70
  piagent-update --check
71
- piagent-update --project /path/to/project
71
+ piagent-update --version X.Y.Z
72
72
  ```
73
73
 
74
- `--check` chỉ báo version, không đụng gì. Lên đúng một bản cụ thể thì `piagent-update --version 1.2.3`.
74
+ Chạy từ Terminal, không cần mở Pi và không cần đứng trong project. Đây là update global cho cả máy: Pi host, npm-global helper, và Pi package.
75
+
76
+ Khi cần kiểm tra một project sau rollout, chạy riêng:
77
+
78
+ ```bash
79
+ piagent-update --version X.Y.Z --project /path/to/project
80
+ ```
81
+
82
+ `--project` là bước phụ: tự migrate layout cũ nếu có rồi chạy doctor strict-share. `--check` chỉ báo version, không đụng gì.
83
+
84
+ Nếu npm global mặc định của máy bị khóa quyền ở `/usr/local`, updater tự chuyển sang `~/.pi/npm-global` cho user hiện tại và in dòng `PATH` cần thêm. Không chạy doctor bằng `sudo`.
85
+
86
+ Máy mới chưa có `piagent-update` dùng một dòng bootstrap này:
87
+
88
+ ```bash
89
+ npm exec -y --package @piagent/platform@X.Y.Z -- piagent-update --version X.Y.Z --force
90
+ ```
75
91
 
76
92
  Không cần ai nhớ đi kiểm tra: khi có release mới, Pi tự báo ngay ở dòng notice lúc mở session, kèm luôn lệnh chạy.
77
93
 
@@ -27,7 +27,7 @@
27
27
  <span>Pi Agent Platform</span>
28
28
  </a>
29
29
  <div class="top-actions">
30
- <span class="pill"><span class="pill-dot"></span>v1.2.3 docs</span>
30
+ <span class="pill"><span class="pill-dot"></span>v1.2.4 docs</span>
31
31
  <a class="button social" href="https://github.com/Vt-mmm/piagent" target="_blank" rel="noopener noreferrer" aria-label="Mở GitHub repository">
32
32
  <svg viewBox="0 0 24 24" fill="none" aria-hidden="true">
33
33
  <path d="M7 17 17 7M9 7h8v8" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
@@ -27,7 +27,7 @@
27
27
  <span>Pi Agent Platform</span>
28
28
  </a>
29
29
  <div class="top-actions">
30
- <span class="pill"><span class="pill-dot"></span>v1.2.3 docs</span>
30
+ <span class="pill"><span class="pill-dot"></span>v1.2.4 docs</span>
31
31
  <a class="button social" href="https://github.com/Vt-mmm/piagent" target="_blank" rel="noopener noreferrer" aria-label="Mở GitHub repository">
32
32
  <svg viewBox="0 0 24 24" fill="none" aria-hidden="true">
33
33
  <path d="M7 17 17 7M9 7h8v8" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
@@ -27,7 +27,7 @@
27
27
  <span>Pi Agent Platform</span>
28
28
  </a>
29
29
  <div class="top-actions">
30
- <span class="pill"><span class="pill-dot"></span>v1.2.3 docs</span>
30
+ <span class="pill"><span class="pill-dot"></span>v1.2.4 docs</span>
31
31
  <a class="button social" href="https://github.com/Vt-mmm/piagent" target="_blank" rel="noopener noreferrer" aria-label="Mở GitHub repository">
32
32
  <svg viewBox="0 0 24 24" fill="none" aria-hidden="true">
33
33
  <path d="M7 17 17 7M9 7h8v8" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
@@ -27,7 +27,7 @@
27
27
  <span>Pi Agent Platform</span>
28
28
  </a>
29
29
  <div class="top-actions">
30
- <span class="pill"><span class="pill-dot"></span>v1.2.3 docs</span>
30
+ <span class="pill"><span class="pill-dot"></span>v1.2.4 docs</span>
31
31
  <a class="button social" href="https://github.com/Vt-mmm/piagent" target="_blank" rel="noopener noreferrer" aria-label="Mở GitHub repository">
32
32
  <svg viewBox="0 0 24 24" fill="none" aria-hidden="true">
33
33
  <path d="M7 17 17 7M9 7h8v8" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
@@ -27,7 +27,7 @@
27
27
  <span>Pi Agent Platform</span>
28
28
  </a>
29
29
  <div class="top-actions">
30
- <span class="pill"><span class="pill-dot"></span>v1.2.3 docs</span>
30
+ <span class="pill"><span class="pill-dot"></span>v1.2.4 docs</span>
31
31
  <a class="button social" href="https://github.com/Vt-mmm/piagent" target="_blank" rel="noopener noreferrer" aria-label="Mở GitHub repository">
32
32
  <svg viewBox="0 0 24 24" fill="none" aria-hidden="true">
33
33
  <path d="M7 17 17 7M9 7h8v8" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
@@ -27,7 +27,7 @@
27
27
  <span>Pi Agent Platform</span>
28
28
  </a>
29
29
  <div class="top-actions">
30
- <span class="pill"><span class="pill-dot"></span>v1.2.3 docs</span>
30
+ <span class="pill"><span class="pill-dot"></span>v1.2.4 docs</span>
31
31
  <a class="button social" href="https://github.com/Vt-mmm/piagent" target="_blank" rel="noopener noreferrer" aria-label="Mở GitHub repository">
32
32
  <svg viewBox="0 0 24 24" fill="none" aria-hidden="true">
33
33
  <path d="M7 17 17 7M9 7h8v8" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
@@ -27,7 +27,7 @@
27
27
  <span>Pi Agent Platform</span>
28
28
  </a>
29
29
  <div class="top-actions">
30
- <span class="pill"><span class="pill-dot"></span>v1.2.3 docs</span>
30
+ <span class="pill"><span class="pill-dot"></span>v1.2.4 docs</span>
31
31
  <a class="button social" href="https://github.com/Vt-mmm/piagent" target="_blank" rel="noopener noreferrer" aria-label="Mở GitHub repository">
32
32
  <svg viewBox="0 0 24 24" fill="none" aria-hidden="true">
33
33
  <path d="M7 17 17 7M9 7h8v8" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
@@ -27,7 +27,7 @@
27
27
  <span>Pi Agent Platform</span>
28
28
  </a>
29
29
  <div class="top-actions">
30
- <span class="pill"><span class="pill-dot"></span>v1.2.3 docs</span>
30
+ <span class="pill"><span class="pill-dot"></span>v1.2.4 docs</span>
31
31
  <a class="button social" href="https://github.com/Vt-mmm/piagent" target="_blank" rel="noopener noreferrer" aria-label="Mở GitHub repository">
32
32
  <svg viewBox="0 0 24 24" fill="none" aria-hidden="true">
33
33
  <path d="M7 17 17 7M9 7h8v8" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
@@ -27,7 +27,7 @@
27
27
  <span>Pi Agent Platform</span>
28
28
  </a>
29
29
  <div class="top-actions">
30
- <span class="pill"><span class="pill-dot"></span>v1.2.3 docs</span>
30
+ <span class="pill"><span class="pill-dot"></span>v1.2.4 docs</span>
31
31
  <a class="button social" href="https://github.com/Vt-mmm/piagent" target="_blank" rel="noopener noreferrer" aria-label="Mở GitHub repository">
32
32
  <svg viewBox="0 0 24 24" fill="none" aria-hidden="true">
33
33
  <path d="M7 17 17 7M9 7h8v8" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
@@ -27,7 +27,7 @@
27
27
  <span>Pi Agent Platform</span>
28
28
  </a>
29
29
  <div class="top-actions">
30
- <span class="pill"><span class="pill-dot"></span>v1.2.3 docs</span>
30
+ <span class="pill"><span class="pill-dot"></span>v1.2.4 docs</span>
31
31
  <a class="button social" href="https://github.com/Vt-mmm/piagent" target="_blank" rel="noopener noreferrer" aria-label="Mở GitHub repository">
32
32
  <svg viewBox="0 0 24 24" fill="none" aria-hidden="true">
33
33
  <path d="M7 17 17 7M9 7h8v8" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
@@ -27,7 +27,7 @@
27
27
  <span>Pi Agent Platform</span>
28
28
  </a>
29
29
  <div class="top-actions">
30
- <span class="pill"><span class="pill-dot"></span>v1.2.3 docs</span>
30
+ <span class="pill"><span class="pill-dot"></span>v1.2.4 docs</span>
31
31
  <a class="button social" href="https://github.com/Vt-mmm/piagent" target="_blank" rel="noopener noreferrer" aria-label="Mở GitHub repository">
32
32
  <svg viewBox="0 0 24 24" fill="none" aria-hidden="true">
33
33
  <path d="M7 17 17 7M9 7h8v8" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
@@ -27,7 +27,7 @@
27
27
  <span>Pi Agent Platform</span>
28
28
  </a>
29
29
  <div class="top-actions">
30
- <span class="pill"><span class="pill-dot"></span>v1.2.3 docs</span>
30
+ <span class="pill"><span class="pill-dot"></span>v1.2.4 docs</span>
31
31
  <a class="button social" href="https://github.com/Vt-mmm/piagent" target="_blank" rel="noopener noreferrer" aria-label="Mở GitHub repository">
32
32
  <svg viewBox="0 0 24 24" fill="none" aria-hidden="true">
33
33
  <path d="M7 17 17 7M9 7h8v8" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
@@ -27,7 +27,7 @@
27
27
  <span>Pi Agent Platform</span>
28
28
  </a>
29
29
  <div class="top-actions">
30
- <span class="pill"><span class="pill-dot"></span>v1.2.3 docs</span>
30
+ <span class="pill"><span class="pill-dot"></span>v1.2.4 docs</span>
31
31
  <a class="button social" href="https://github.com/Vt-mmm/piagent" target="_blank" rel="noopener noreferrer" aria-label="Mở GitHub repository">
32
32
  <svg viewBox="0 0 24 24" fill="none" aria-hidden="true">
33
33
  <path d="M7 17 17 7M9 7h8v8" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
@@ -27,7 +27,7 @@
27
27
  <span>Pi Agent Platform</span>
28
28
  </a>
29
29
  <div class="top-actions">
30
- <span class="pill"><span class="pill-dot"></span>v1.2.3 docs</span>
30
+ <span class="pill"><span class="pill-dot"></span>v1.2.4 docs</span>
31
31
  <a class="button social" href="https://github.com/Vt-mmm/piagent" target="_blank" rel="noopener noreferrer" aria-label="Mở GitHub repository">
32
32
  <svg viewBox="0 0 24 24" fill="none" aria-hidden="true">
33
33
  <path d="M7 17 17 7M9 7h8v8" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
@@ -27,7 +27,7 @@
27
27
  <span>Pi Agent Platform</span>
28
28
  </a>
29
29
  <div class="top-actions">
30
- <span class="pill"><span class="pill-dot"></span>v1.2.3 docs</span>
30
+ <span class="pill"><span class="pill-dot"></span>v1.2.4 docs</span>
31
31
  <a class="button social" href="https://github.com/Vt-mmm/piagent" target="_blank" rel="noopener noreferrer" aria-label="Mở GitHub repository">
32
32
  <svg viewBox="0 0 24 24" fill="none" aria-hidden="true">
33
33
  <path d="M7 17 17 7M9 7h8v8" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@piagent/platform",
3
- "version": "1.2.3",
3
+ "version": "1.2.4",
4
4
  "license": "MIT",
5
5
  "publishConfig": {
6
6
  "access": "public",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@piagent/core",
3
- "version": "1.2.3",
3
+ "version": "1.2.4",
4
4
  "type": "module",
5
5
  "private": true,
6
6
  "license": "MIT",
@@ -17,6 +17,7 @@
17
17
  // it asked for.
18
18
 
19
19
  import fs from "node:fs";
20
+ import os from "node:os";
20
21
  import path from "node:path";
21
22
  import { spawnSync } from "node:child_process";
22
23
  import { fileURLToPath } from "node:url";
@@ -39,13 +40,18 @@ Options:
39
40
  --dry-run Print every command that would run, change nothing
40
41
  --version <x.y.z> Update to an exact helper version instead of latest
41
42
  --force Reinstall even when already on the target version
42
- --project <path> Run the team doctor against this project afterwards
43
+ --project <path> Optional: after the global update, migrate and doctor this project
43
44
  --no-host Do not touch the Pi host
44
45
  --no-package Do not reinstall the Pi package
46
+ --no-migrate With --project, skip project state migration
47
+ --npm-prefix <path> Use this npm global prefix for host/helper installs
45
48
  -h, --help Show this help
46
49
 
47
50
  Anything after -- is passed through to piagent-install, for example:
48
51
  piagent-update -- --no-mcp
52
+
53
+ Bootstrap a machine that does not have piagent-update yet:
54
+ npm exec -y --package @piagent/platform@X.Y.Z -- piagent-update --version X.Y.Z --force
49
55
  `;
50
56
  }
51
57
 
@@ -81,6 +87,8 @@ function parseArguments(argv) {
81
87
  project: undefined,
82
88
  host: true,
83
89
  package: true,
90
+ migrate: true,
91
+ npmPrefix: undefined,
84
92
  passthrough: []
85
93
  };
86
94
 
@@ -111,6 +119,15 @@ function parseArguments(argv) {
111
119
  case "--no-package":
112
120
  options.package = false;
113
121
  break;
122
+ case "--no-migrate":
123
+ options.migrate = false;
124
+ break;
125
+ case "--npm-prefix": {
126
+ const value = argv[index += 1];
127
+ if (!value) fail("--npm-prefix needs a path", EXIT_USAGE);
128
+ options.npmPrefix = value;
129
+ break;
130
+ }
114
131
  case "--version": {
115
132
  const value = normalizeVersion(argv[index += 1]);
116
133
  if (!isReleaseVersion(value)) fail(`--version needs an exact release such as 1.1.4, got ${argv[index] ?? "nothing"}`, EXIT_USAGE);
@@ -140,6 +157,167 @@ function run(command, args, { capture = false } = {}) {
140
157
  return { ok: result.status === 0, stdout: result.stdout ?? "", stderr: result.stderr ?? "" };
141
158
  }
142
159
 
160
+ function expandHome(value) {
161
+ if (value === "~") return os.homedir();
162
+ if (value?.startsWith("~/")) return path.join(os.homedir(), value.slice(2));
163
+ return value;
164
+ }
165
+
166
+ function configuredNpmPrefix() {
167
+ const result = run("npm", ["config", "get", "prefix"], { capture: true });
168
+ if (!result.ok) return undefined;
169
+ const prefix = result.stdout.trim();
170
+ return prefix && prefix !== "undefined" && prefix !== "null" ? path.resolve(expandHome(prefix)) : undefined;
171
+ }
172
+
173
+ function fallbackNpmRoot(prefix) {
174
+ return process.platform === "win32"
175
+ ? path.join(prefix, "node_modules")
176
+ : path.join(prefix, "lib", "node_modules");
177
+ }
178
+
179
+ function npmRoot(prefix) {
180
+ const args = ["root", "-g"];
181
+ if (prefix) args.push("--prefix", prefix);
182
+ const result = run("npm", args, { capture: true });
183
+ if (result.ok && result.stdout.trim()) return path.resolve(expandHome(result.stdout.trim()));
184
+ return prefix ? fallbackNpmRoot(prefix) : undefined;
185
+ }
186
+
187
+ function nearestExistingPath(target) {
188
+ let current = target;
189
+ while (current && !fs.existsSync(current)) {
190
+ const parent = path.dirname(current);
191
+ if (parent === current) return undefined;
192
+ current = parent;
193
+ }
194
+ return current || undefined;
195
+ }
196
+
197
+ function canWriteOrCreate(target) {
198
+ const nearest = nearestExistingPath(target);
199
+ if (!nearest) return false;
200
+ try {
201
+ fs.accessSync(nearest, fs.constants.W_OK);
202
+ return true;
203
+ } catch {
204
+ return false;
205
+ }
206
+ }
207
+
208
+ function userNpmPrefix() {
209
+ return path.join(os.homedir(), ".pi", "npm-global");
210
+ }
211
+
212
+ function binForPrefix(prefix) {
213
+ return process.platform === "win32" ? prefix : path.join(prefix, "bin");
214
+ }
215
+
216
+ function prependPath(directory) {
217
+ process.env.PATH = `${directory}${path.delimiter}${process.env.PATH ?? ""}`;
218
+ }
219
+
220
+ function resolveNpmInstallTarget(options, needsGlobalInstall) {
221
+ const explicitPrefix = options.npmPrefix ? path.resolve(expandHome(options.npmPrefix)) : undefined;
222
+ if (explicitPrefix) {
223
+ if (!options.dryRun) fs.mkdirSync(explicitPrefix, { recursive: true });
224
+ return {
225
+ prefix: explicitPrefix,
226
+ root: npmRoot(explicitPrefix),
227
+ bin: binForPrefix(explicitPrefix),
228
+ reason: "explicit"
229
+ };
230
+ }
231
+
232
+ const defaultPrefix = configuredNpmPrefix();
233
+ const defaultRoot = npmRoot(defaultPrefix);
234
+ if (!needsGlobalInstall || (defaultRoot && canWriteOrCreate(defaultRoot))) {
235
+ return { prefix: undefined, root: defaultRoot, bin: undefined, reason: "default" };
236
+ }
237
+
238
+ const prefix = userNpmPrefix();
239
+ if (!options.dryRun) fs.mkdirSync(prefix, { recursive: true });
240
+ return {
241
+ prefix,
242
+ root: npmRoot(prefix),
243
+ bin: binForPrefix(prefix),
244
+ reason: "user-prefix",
245
+ blockedRoot: defaultRoot
246
+ };
247
+ }
248
+
249
+ function npmInstallArgs(specifier, npmTarget) {
250
+ const args = ["install", "-g", "--ignore-scripts"];
251
+ if (npmTarget.prefix) args.push("--prefix", npmTarget.prefix);
252
+ args.push(specifier);
253
+ return args;
254
+ }
255
+
256
+ function helperRootFromNpmTarget(npmTarget) {
257
+ return npmTarget.root ? path.join(npmTarget.root, "@piagent", "platform") : undefined;
258
+ }
259
+
260
+ function helperVersionAt(root) {
261
+ return root ? readJson(path.join(root, "package.json"))?.version : undefined;
262
+ }
263
+
264
+ function resolveInstalledHelperRoot(targetHelper, npmTarget) {
265
+ const npmHelperRoot = helperRootFromNpmTarget(npmTarget);
266
+ if (helperVersionAt(npmHelperRoot) === targetHelper) return npmHelperRoot;
267
+ if (helperVersionAt(platformRoot) === targetHelper) return platformRoot;
268
+ const checked = [];
269
+ for (const root of [npmHelperRoot, platformRoot]) {
270
+ if (!root || checked.some((entry) => entry.root === root)) continue;
271
+ checked.push({ root, version: helperVersionAt(root) ?? "nothing" });
272
+ }
273
+ const details = checked.map((entry) => `${entry.root} reports ${entry.version}`).join("; ");
274
+ fail(`installed ${HELPER_PACKAGE}@${targetHelper}, but ${details || "the helper paths did not report that version"}. `
275
+ + "The Pi package was left untouched; rerun once the helper is correct.");
276
+ }
277
+
278
+ function parseJsonOutput(result, label) {
279
+ try {
280
+ return JSON.parse(result.stdout.trim() || "{}");
281
+ } catch {
282
+ fail(`${label} did not return valid JSON:\n${result.stdout.trim()}`);
283
+ }
284
+ }
285
+
286
+ function summarizeMigration(report, dryRun) {
287
+ const renamed = report.renamed?.length ?? 0;
288
+ const removed = report.removedOld?.length ?? 0;
289
+ const rewrote = report.rewrote?.length ?? report.wouldRewrite?.length ?? 0;
290
+ const wouldRename = report.wouldRename?.length ?? 0;
291
+ const alreadyMigrated = report.alreadyMigrated?.length ?? 0;
292
+
293
+ if (dryRun) {
294
+ const planned = wouldRename + rewrote + alreadyMigrated;
295
+ return planned > 0
296
+ ? `project migration: would update legacy layout (${wouldRename} rename, ${rewrote} rewrite, ${alreadyMigrated} already copied)`
297
+ : "project migration: already current";
298
+ }
299
+ if (report.migrated === false) return "project migration: already current";
300
+ return `project migration: applied (${renamed} rename, ${rewrote} rewrite, ${removed} old path removed)`;
301
+ }
302
+
303
+ function runProjectMigration(project, options, activePlatformRoot) {
304
+ const migrator = path.join(activePlatformRoot, "scripts/migrate-project-state.mjs");
305
+ if (!options.dryRun && !fs.existsSync(migrator)) {
306
+ fail(`the updated helper has no project migrator at ${migrator}`);
307
+ }
308
+ const args = options.dryRun
309
+ ? [migrator, project]
310
+ : [migrator, project, "--apply", "--remove-old"];
311
+ describeStep(options.dryRun, process.execPath, args);
312
+ const result = run(process.execPath, args, { capture: true });
313
+ if (!result.ok) fail(`project migration failed:\n${result.stderr.trim() || result.stdout.trim()}`);
314
+ const report = parseJsonOutput(result, "project migration");
315
+ if ((report.skipped?.length ?? 0) > 0) {
316
+ fail(`project migration skipped protected entries: ${report.skipped.map((entry) => `${entry.path} (${entry.reason})`).join(", ")}`);
317
+ }
318
+ console.log(` ${summarizeMigration(report, options.dryRun)}`);
319
+ }
320
+
143
321
  function npmView(specifier, field) {
144
322
  const result = run("npm", ["view", specifier, field, "--json"], { capture: true });
145
323
  if (!result.ok) return undefined;
@@ -196,6 +374,9 @@ function main() {
196
374
  console.log(` helper: ${currentHelper} -> ${targetHelper}${helperNeedsChange ? "" : " (already current)"}`);
197
375
  console.log(` host: ${currentHost ?? "not installed"} -> ${targetHost}${hostNeedsChange ? "" : " (already current)"}`);
198
376
  console.log(` package: reinstalled from v${targetHelper} as a resolved commit${options.package ? "" : " (skipped)"}`);
377
+ if (options.project) {
378
+ console.log(` project: ${path.resolve(options.project)} (${options.migrate ? "migrate + doctor" : "doctor only"})`);
379
+ }
199
380
 
200
381
  if (options.check) {
201
382
  const pending = [helperNeedsChange && "helper", hostNeedsChange && "host"].filter(Boolean);
@@ -203,7 +384,7 @@ function main() {
203
384
  return;
204
385
  }
205
386
 
206
- if (!helperNeedsChange && !hostNeedsChange && !options.package) {
387
+ if (!helperNeedsChange && !hostNeedsChange && !options.package && !options.project) {
207
388
  console.log("\nNothing to do.");
208
389
  return;
209
390
  }
@@ -215,33 +396,38 @@ function main() {
215
396
  + ` bash ${path.join(platformRoot, "scripts/install-global.sh")} --local`);
216
397
  }
217
398
 
399
+ let activePlatformRoot = platformRoot;
400
+ const npmTarget = resolveNpmInstallTarget(options, hostNeedsChange || helperNeedsChange);
401
+ if (npmTarget.bin) prependPath(npmTarget.bin);
402
+ if (npmTarget.reason === "user-prefix") {
403
+ console.log(` npm: default global root is not writable (${npmTarget.blockedRoot ?? "unknown"}); using ${npmTarget.prefix}`);
404
+ } else if (npmTarget.reason === "explicit") {
405
+ console.log(` npm: using explicit global prefix ${npmTarget.prefix}`);
406
+ }
407
+
218
408
  // Host first: piagent-install refuses to run against a host that does not match
219
409
  // the version its package.json pins, so a helper installed ahead of the host
220
410
  // would fail on its very next step.
221
411
  if (hostNeedsChange) {
222
- const args = ["install", "-g", "--ignore-scripts", `${HOST_PACKAGE}@${targetHost}`];
412
+ const args = npmInstallArgs(`${HOST_PACKAGE}@${targetHost}`, npmTarget);
223
413
  describeStep(options.dryRun, "npm", args);
224
414
  if (!options.dryRun && !run("npm", args).ok) fail(`could not install ${HOST_PACKAGE}@${targetHost}`);
225
415
  }
226
416
 
227
417
  if (helperNeedsChange) {
228
- const args = ["install", "-g", "--ignore-scripts", `${HELPER_PACKAGE}@${targetHelper}`];
418
+ const args = npmInstallArgs(`${HELPER_PACKAGE}@${targetHelper}`, npmTarget);
229
419
  describeStep(options.dryRun, "npm", args);
230
420
  if (!options.dryRun) {
231
421
  if (!run("npm", args).ok) fail(`could not install ${HELPER_PACKAGE}@${targetHelper}`);
232
422
  // The helper has just replaced itself on disk. Everything after this point
233
423
  // runs the newly installed scripts, so confirm they are the ones asked for
234
424
  // rather than trusting that npm did what it said.
235
- const landed = readJson(path.join(platformRoot, "package.json"))?.version;
236
- if (landed !== targetHelper) {
237
- fail(`installed ${HELPER_PACKAGE}@${targetHelper} but ${platformRoot} reports ${landed ?? "nothing"}. `
238
- + "The Pi package was left untouched; rerun once the helper is correct.");
239
- }
425
+ activePlatformRoot = resolveInstalledHelperRoot(targetHelper, npmTarget);
240
426
  }
241
427
  }
242
428
 
243
429
  if (options.package) {
244
- const installer = path.join(platformRoot, "scripts/install-global.sh");
430
+ const installer = path.join(activePlatformRoot, "scripts/install-global.sh");
245
431
  if (!options.dryRun && !fs.existsSync(installer)) {
246
432
  fail(`the updated helper has no installer at ${installer}`);
247
433
  }
@@ -251,12 +437,22 @@ function main() {
251
437
  }
252
438
 
253
439
  if (options.project) {
254
- const doctor = path.join(platformRoot, "scripts/team-doctor.sh");
440
+ if (options.migrate) {
441
+ runProjectMigration(options.project, options, activePlatformRoot);
442
+ } else {
443
+ console.log(" project migration: skipped");
444
+ }
445
+ const doctor = path.join(activePlatformRoot, "scripts/team-doctor.sh");
255
446
  const args = [doctor, options.project, "--strict-share"];
256
447
  describeStep(options.dryRun, "bash", args);
257
448
  if (!options.dryRun && !run("bash", args).ok) fail("the team doctor reported a problem");
258
449
  }
259
450
 
451
+ if (npmTarget.reason === "user-prefix") {
452
+ console.log(`\nPATH note: add this once if your shell cannot find piagent-* commands later:`);
453
+ console.log(` export PATH="${npmTarget.bin}:$PATH"`);
454
+ }
455
+
260
456
  console.log(options.dryRun
261
457
  ? `\nDRY RUN: nothing was installed. Rerun without --dry-run to apply v${targetHelper}.`
262
458
  : `\nPASS: updated to v${targetHelper}.`);