@piagent/platform 1.1.3 → 1.1.5
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 +21 -0
- package/README.md +1 -1
- package/docs/command-reference-vietnamese.md +6 -3
- package/docs/distribution-standard.md +7 -7
- package/docs/operator-manual-vietnamese.md +19 -7
- package/docs/publishing-for-teams.md +2 -0
- package/docs/release-install-policy.md +19 -7
- package/docs/security-threat-model.md +1 -1
- package/docs/team-onboarding.md +14 -3
- package/docs-site/index.html +2 -2
- package/package.json +2 -1
- package/packages/piagent-core/package.json +1 -1
- package/packages/piagent-core/security/sensitive-data.js +34 -2
- package/scripts/install-global.sh +3 -3
- package/scripts/piagent-cli.mjs +1 -0
- package/scripts/team-doctor.sh +1 -1
- package/scripts/update-global.mjs +265 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,27 @@
|
|
|
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.1.5 - 2026-07-27
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- `piagent-update` moves a machine from one release to the next in one command. A release is three independently versioned things — the Pi host, the npm-global terminal helper, and the Pi package — and they have to move in that order, because `piagent-install` refuses to run against a host that does not match the version its own package.json pins and does not install one itself. Doing it by hand is three commands and one ordering rule that fails late when it is got wrong.
|
|
10
|
+
|
|
11
|
+
Every version the run needs is resolved from the registry before anything is installed, including the host version taken from the *target* helper's published metadata rather than the running one, so `--check` and `--dry-run` describe exactly what a real run would do. After the helper replaces itself the run confirms that the version on disk is the one it asked for, and stops before touching the Pi package if it is not. Running it from a git checkout is refused rather than replacing that checkout's commands with a published build.
|
|
12
|
+
|
|
13
|
+
`--check`, `--dry-run`, `--version X.Y.Z`, `--force`, `--project <path>`, `--no-host`, `--no-package`, and pass-through to `piagent-install` after `--`.
|
|
14
|
+
|
|
15
|
+
### Fixed
|
|
16
|
+
|
|
17
|
+
- `docs/release-install-policy.md`, `docs/team-onboarding.md` and `docs/command-reference-vietnamese.md` described the manual update sequence without saying why its order is mandatory. `piagent-install` fails on a host mismatch; the auto-install of a matching host lives in `setup.sh` and does not apply to that flow.
|
|
18
|
+
|
|
19
|
+
## v1.1.4 - 2026-07-27
|
|
20
|
+
|
|
21
|
+
### Fixed
|
|
22
|
+
|
|
23
|
+
- A credential passed as a command-line option is recognised as one. `--token=abc123`, `--token abc123`, `--password`, `--api-key`, `--client-secret` and the rest went unrecognised because the assignment patterns require a key that starts with a letter, and `-` is not one. v1.1.3 made the redactor's verdict the gate that decides whether a command may serve as verify evidence, so anything it missed was stored in the clear *and* accepted as proof — the same invariant v1.1.3 was written to enforce, defeated by the syntax most command-line tools actually use. Env-style assignments were the only shape covered.
|
|
24
|
+
- An `Authorization` header is redacted wherever it sits among the arguments. The value ran to the end of the line, so the same credential survived or not depending on how much text happened to follow it: `curl URL -H "Authorization: Token abc123"` left the header value one character under the length bar, while moving the header ahead of the URL swept the URL into the value and pushed it over. The value is now the single whitespace-free token that follows the scheme, and under a known authentication scheme its length is not consulted at all. Prose such as `Authorization: not required for local runs` is still left alone.
|
|
25
|
+
|
|
5
26
|
## v1.1.3 - 2026-07-27
|
|
6
27
|
|
|
7
28
|
Fixes for defects found reviewing v1.1.2 after it shipped, including two introduced by v1.1.2 itself. Every fix was reproduced first.
|
package/README.md
CHANGED
|
@@ -283,7 +283,7 @@ This repository intentionally excludes:
|
|
|
283
283
|
|
|
284
284
|
## Maturity
|
|
285
285
|
|
|
286
|
-
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.1.
|
|
286
|
+
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.1.5` or a reviewed commit.
|
|
287
287
|
|
|
288
288
|
Ready for:
|
|
289
289
|
|
|
@@ -419,10 +419,13 @@ Các lệnh này chạy ngoài Pi.
|
|
|
419
419
|
| Command | Dùng khi nào |
|
|
420
420
|
|---|---|
|
|
421
421
|
| `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. |
|
|
422
|
-
| `npm install -g --ignore-scripts @piagent/platform@1.1.
|
|
423
|
-
| `pi install git:github.com/Vt-mmm/piagent@v1.1.
|
|
422
|
+
| `npm install -g --ignore-scripts @piagent/platform@1.1.5` | Cài terminal helper `piagent-*` từ release tag hiện tại. |
|
|
423
|
+
| `pi install git:github.com/Vt-mmm/piagent@v1.1.5` | Cài pinned release khi cần reproducible team setup. |
|
|
424
424
|
| `pi install git:github.com/Vt-mmm/piagent` | Cài latest package platform cho máy cá nhân/sandbox. |
|
|
425
|
-
|
|
|
425
|
+
| `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ì. |
|
|
426
|
+
| `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. |
|
|
427
|
+
| `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. |
|
|
428
|
+
| 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). |
|
|
426
429
|
| 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. |
|
|
427
430
|
| `piagent-install --stable --dry-run` | Preview Pi package matching với helper hiện tại; stable resolve tag → commit SHA. |
|
|
428
431
|
| `piagent-install --stable` | Cài Pi package matching với helper hiện tại bằng resolved commit SHA. |
|
|
@@ -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.1.
|
|
17
|
+
| Team pinned release | `git:github.com/Vt-mmm/piagent@v1.1.5` |
|
|
18
18
|
| Personal/sandbox dev | `git:github.com/Vt-mmm/piagent` |
|
|
19
|
-
| Registry distribution | `npm:@piagent/platform@1.1.
|
|
19
|
+
| Registry distribution | `npm:@piagent/platform@1.1.5` |
|
|
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.1.
|
|
29
|
+
| `stable` | `bash scripts/install-global.sh --stable` | Helper release tag resolved to commit SHA, currently `v1.1.5` | 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.1.
|
|
56
|
+
pi install git:github.com/Vt-mmm/piagent@v1.1.5
|
|
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.1.
|
|
68
|
+
npm install -g --ignore-scripts @piagent/platform@1.1.5
|
|
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.1.
|
|
73
|
+
`pi install git:github.com/Vt-mmm/piagent@v1.1.5` 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.1.5`.
|
|
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
|
|
|
@@ -103,7 +103,7 @@ Nếu muốn commit sẵn `.pi/piagent-profile.json` vào repo hoặc bootstrap
|
|
|
103
103
|
```bash
|
|
104
104
|
bash scripts/setup.sh /path/to/project \
|
|
105
105
|
--profile be-readonly-fe \
|
|
106
|
-
--package-source git:github.com/Vt-mmm/piagent@v1.1.
|
|
106
|
+
--package-source git:github.com/Vt-mmm/piagent@v1.1.5 \
|
|
107
107
|
--mcp-preset core \
|
|
108
108
|
--subagents-preset safe
|
|
109
109
|
```
|
|
@@ -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.1.
|
|
21
|
+
npm install -g --ignore-scripts @piagent/platform@1.1.5
|
|
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.1.
|
|
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.1.5`. 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.1.
|
|
102
|
+
npm install -g --ignore-scripts @piagent/platform@1.1.5
|
|
103
103
|
piagent-install --stable --dry-run
|
|
104
104
|
piagent-install --stable
|
|
105
105
|
```
|
|
@@ -156,6 +156,18 @@ Trong Pi:
|
|
|
156
156
|
|
|
157
157
|
Chọn provider/account như OpenAI/Codex hoặc Anthropic/Claude. Credential nằm trong Pi user dir, không nằm trong repo và không được commit.
|
|
158
158
|
|
|
159
|
+
Browser login của OpenAI có hai chỗ trông như treo. Cả hai là lỗi Pi host, không phải platform, và còn nguyên ở `0.82.0` lẫn `0.82.1`.
|
|
160
|
+
|
|
161
|
+
Paste xong callback URL mà màn hình đứng im: **bấm Enter**. Ô nhập callback chỉ hiện hint `to cancel`, không hiện `to submit`, nên nó đang chờ submit chứ không đơ.
|
|
162
|
+
|
|
163
|
+
Đã Enter rồi mà terminal khoá luôn, Esc không thoát được: Pi lưu credential xong mới refresh model catalog từ `pi.dev`, và request đó không có timeout. Firewall hoặc proxy giữ connection im lặng thì `/login` chờ mãi. Credential thực tế đã lưu rồi, nên mở tab mới vẫn dùng được. Login bằng đường này để tránh hẳn:
|
|
164
|
+
|
|
165
|
+
```bash
|
|
166
|
+
pi --offline
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
Rồi `/login` → browser → paste → Enter. `--offline` chỉ chặn bước refresh catalog gây treo, OAuth vẫn chạy. Xong thì thoát và mở `pi` bình thường.
|
|
170
|
+
|
|
159
171
|
### Chọn model và thinking
|
|
160
172
|
|
|
161
173
|
Trong Pi:
|
|
@@ -269,7 +281,7 @@ Không phải daily default. Dùng khi muốn tạo sẵn `.pi` files cho projec
|
|
|
269
281
|
bash /path/to/piagent/scripts/setup.sh /path/to/project \
|
|
270
282
|
--project-only \
|
|
271
283
|
--profile auto \
|
|
272
|
-
--package-source git:github.com/Vt-mmm/piagent@v1.1.
|
|
284
|
+
--package-source git:github.com/Vt-mmm/piagent@v1.1.5 \
|
|
273
285
|
--mcp-preset core \
|
|
274
286
|
--subagents-preset safe
|
|
275
287
|
```
|
|
@@ -842,8 +854,8 @@ Watchdog là optional adversarial reviewer ở cuối turn, không bật mặc
|
|
|
842
854
|
|
|
843
855
|
| Command | Dùng để |
|
|
844
856
|
|---|---|
|
|
845
|
-
| `npm install -g --ignore-scripts @piagent/platform@1.1.
|
|
846
|
-
| `pi install git:github.com/Vt-mmm/piagent@v1.1.
|
|
857
|
+
| `npm install -g --ignore-scripts @piagent/platform@1.1.5` | Cài terminal helper `piagent-*` từ release tag hiện tại. |
|
|
858
|
+
| `pi install git:github.com/Vt-mmm/piagent@v1.1.5` | Install pinned release cho reproducible team setup. |
|
|
847
859
|
| `pi install git:github.com/Vt-mmm/piagent` | Install latest platform package cho máy cá nhân/sandbox. |
|
|
848
860
|
| 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). |
|
|
849
861
|
| 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. |
|
|
@@ -940,7 +952,7 @@ Mở lại Pi session sau khi install.
|
|
|
940
952
|
Cài lại terminal helper đúng release rồi kiểm tra `PATH`:
|
|
941
953
|
|
|
942
954
|
```bash
|
|
943
|
-
npm install -g --ignore-scripts @piagent/platform@1.1.
|
|
955
|
+
npm install -g --ignore-scripts @piagent/platform@1.1.5
|
|
944
956
|
command -v piagent-install
|
|
945
957
|
```
|
|
946
958
|
|
|
@@ -46,6 +46,8 @@ pi install /path/to/piagent
|
|
|
46
46
|
- `1.1.0`: đọc document ngoài project qua `additionalReadRoots`, MCP baseline bật mặc định ở cả hai lệnh install, pin Pi host `0.82.0`.
|
|
47
47
|
- `1.1.2`: đóng TOCTOU của document reader, hash evidence tính trên text đã redact, publish chờ đủ verify matrix.
|
|
48
48
|
- `1.1.3`: command mang secret không còn được dùng làm verify evidence, document reader từ chối FIFO thay vì treo, redact secret ngắn, redirect phải về đúng trang được kiểm.
|
|
49
|
+
- `1.1.4`: nhận diện secret dạng CLI option (`--token`, `--password`, `--api-key`) và Authorization header ở mọi vị trí argument.
|
|
50
|
+
- `1.1.5`: thêm `piagent-update` — một lệnh update cả Pi host, terminal helper và Pi package đúng thứ tự.
|
|
49
51
|
|
|
50
52
|
## Không publish
|
|
51
53
|
|
|
@@ -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.1.
|
|
13
|
+
| Surface | Status for v1.1.5 | 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.1.
|
|
36
|
+
| `stable` | `git:github.com/Vt-mmm/piagent@<resolved-commit-sha>` from `v1.1.5` | 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.1.
|
|
56
|
+
npm install -g --ignore-scripts @piagent/platform@1.1.5
|
|
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.1.
|
|
65
|
-
tag: v1.1.
|
|
64
|
+
currentRelease: v1.1.5 (helper package version)
|
|
65
|
+
tag: v1.1.5
|
|
66
66
|
resolvedCommit: <40-char-sha>
|
|
67
67
|
source: git:github.com/Vt-mmm/piagent@<40-char-sha>
|
|
68
68
|
```
|
|
@@ -79,14 +79,26 @@ 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.1.
|
|
82
|
+
pi install git:github.com/Vt-mmm/piagent@v1.1.5
|
|
83
83
|
```
|
|
84
84
|
|
|
85
85
|
Direct `pi install` does not create `piagent-*` commands on `PATH`.
|
|
86
86
|
|
|
87
87
|
## Full platform update
|
|
88
88
|
|
|
89
|
-
|
|
89
|
+
`piagent-update` does the whole sequence in one command:
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
piagent-update --check
|
|
93
|
+
piagent-update --dry-run
|
|
94
|
+
piagent-update --project /path/to/project
|
|
95
|
+
```
|
|
96
|
+
|
|
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
|
+
|
|
99
|
+
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
|
+
|
|
101
|
+
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:
|
|
90
102
|
|
|
91
103
|
```bash
|
|
92
104
|
npm install -g --ignore-scripts @earendil-works/pi-coding-agent@0.82.0
|
|
@@ -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.1.
|
|
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.1.5, 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
|
package/docs/team-onboarding.md
CHANGED
|
@@ -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.1.
|
|
12
|
+
npm install -g --ignore-scripts @piagent/platform@1.1.5
|
|
13
13
|
piagent-install --stable
|
|
14
14
|
cd /path/to/project
|
|
15
15
|
pi
|
|
@@ -42,7 +42,7 @@ Mặc định team dùng stable helper:
|
|
|
42
42
|
```bash
|
|
43
43
|
node --version # >= 22.19.0
|
|
44
44
|
npm install -g --ignore-scripts @earendil-works/pi-coding-agent@0.82.0
|
|
45
|
-
npm install -g --ignore-scripts @piagent/platform@1.1.
|
|
45
|
+
npm install -g --ignore-scripts @piagent/platform@1.1.5
|
|
46
46
|
piagent-install --stable --dry-run
|
|
47
47
|
piagent-install --stable
|
|
48
48
|
```
|
|
@@ -63,7 +63,16 @@ pi install git:github.com/Vt-mmm/piagent
|
|
|
63
63
|
|
|
64
64
|
## Update và rollback cho team
|
|
65
65
|
|
|
66
|
-
|
|
66
|
+
Một lệnh, đúng thứ tự, cho cả ba thành phần:
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
piagent-update --check
|
|
70
|
+
piagent-update --project /path/to/project
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
`--check` chỉ báo version, không đụng gì. Lên đúng một bản cụ thể thì `piagent-update --version 1.1.5`.
|
|
74
|
+
|
|
75
|
+
Sequence thủ công vẫn dùng được, và bắt buộc theo thứ tự này — `piagent-install` **fail** nếu Pi host lệch bản pin, nó không tự nâng host:
|
|
67
76
|
|
|
68
77
|
```bash
|
|
69
78
|
npm install -g --ignore-scripts @earendil-works/pi-coding-agent@0.82.0
|
|
@@ -108,6 +117,8 @@ pi
|
|
|
108
117
|
|
|
109
118
|
Credential nằm trong user Pi dir, không commit.
|
|
110
119
|
|
|
120
|
+
Nếu browser login của OpenAI trông như treo, xem [login provider](operator-manual-vietnamese.md#login-provider). Tóm tắt: paste callback URL xong phải bấm **Enter** (màn hình không nhắc), và nếu sau Enter terminal khoá luôn thì login bằng `pi --offline` một lần. Cả hai là lỗi Pi host `0.82.0`/`0.82.1`, không phải platform.
|
|
121
|
+
|
|
111
122
|
## Bước 3 — chọn model và onboard project
|
|
112
123
|
|
|
113
124
|
Sau login, chọn provider/model intended cho project understanding bằng native Pi selector. OpenAI Codex và Claude/Anthropic đều là supported option.
|
package/docs-site/index.html
CHANGED
|
@@ -798,7 +798,7 @@
|
|
|
798
798
|
<span>Pi Agent Platform</span>
|
|
799
799
|
</a>
|
|
800
800
|
<div class="top-actions">
|
|
801
|
-
<span class="pill"><span class="pill-dot"></span>v1.1.
|
|
801
|
+
<span class="pill"><span class="pill-dot"></span>v1.1.5 docs</span>
|
|
802
802
|
<a class="button social" href="https://github.com/Vt-mmm/piagent" target="_blank" rel="noopener noreferrer" aria-label="Mở GitHub repository">
|
|
803
803
|
<svg viewBox="0 0 24 24" fill="none" aria-hidden="true">
|
|
804
804
|
<path d="M7 17 17 7M9 7h8v8" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
|
|
@@ -934,7 +934,7 @@
|
|
|
934
934
|
<article class="step">
|
|
935
935
|
<div>
|
|
936
936
|
<h3>Cài — hai lệnh</h3>
|
|
937
|
-
<p>Cần Node.js 22.19.0 trở lên. Không cần cài Pi Coding Agent trước: <span class="inline-code">piagent-setup</span> tự cài đúng bản <span class="inline-code">0.82.0</span> mà release <span class="inline-code">v1.1.
|
|
937
|
+
<p>Cần Node.js 22.19.0 trở lên. Không cần cài Pi Coding Agent trước: <span class="inline-code">piagent-setup</span> tự cài đúng bản <span class="inline-code">0.82.0</span> mà release <span class="inline-code">v1.1.5</span> đang pin. Chạy nó ngay trong thư mục project — nó cài Pi package, khởi tạo <span class="inline-code">.pi/</span>, cài MCP baseline cùng subagents, rồi chạy doctor. Thêm <span class="inline-code">--no-mcp</span>, <span class="inline-code">--no-subagents</span>, <span class="inline-code">--no-herdr</span> hoặc <span class="inline-code">--global-only</span> để bỏ bớt.</p>
|
|
938
938
|
<div class="table-wrap compact-table">
|
|
939
939
|
<table>
|
|
940
940
|
<thead>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@piagent/platform",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.5",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public",
|
|
@@ -47,6 +47,7 @@
|
|
|
47
47
|
"bin": {
|
|
48
48
|
"piagent-setup": "scripts/piagent-cli.mjs",
|
|
49
49
|
"piagent-install": "scripts/piagent-cli.mjs",
|
|
50
|
+
"piagent-update": "scripts/piagent-cli.mjs",
|
|
50
51
|
"piagent-uninstall": "scripts/piagent-cli.mjs",
|
|
51
52
|
"piagent-init": "scripts/piagent-cli.mjs",
|
|
52
53
|
"piagent-doctor": "scripts/piagent-cli.mjs",
|
|
@@ -15,7 +15,27 @@ const TOKEN_PATTERNS = [
|
|
|
15
15
|
const CONNECTION_URL_PATTERN = /\b((?:https?|ftp|postgres(?:ql)?|mysql|mariadb|mongodb(?:\+srv)?|redis):\/\/[^:\s/"']+:)([^@\s/"']+)(@[^\s"'<>]+)/gi;
|
|
16
16
|
const BEARER_PATTERN = /\b(Bearer\s+)([A-Za-z0-9._~+/=-]{20,})\b/gi;
|
|
17
17
|
const BASIC_AUTH_PATTERN = /\b(Basic\s+)([A-Za-z0-9+/]{12,}={0,2})(?=$|[\s,;}])/gi;
|
|
18
|
-
|
|
18
|
+
// The value is one whitespace-free token, not the rest of the line. Taking the
|
|
19
|
+
// rest of the line made the result depend on where the header sat among the
|
|
20
|
+
// arguments: `curl URL -H "Authorization: Token abc123"` yielded `abc123"`, short
|
|
21
|
+
// enough to keep, while moving the header before the URL swept the URL into the
|
|
22
|
+
// value and pushed it past the length bar. Same header, same credential, opposite
|
|
23
|
+
// outcome. Credentials carry no spaces, so stopping at the first one also keeps
|
|
24
|
+
// prose like "Authorization: not required for local runs" intact.
|
|
25
|
+
const AUTHORIZATION_HEADER_PATTERN = /\b(Authorization\s*:\s*)([A-Za-z][A-Za-z0-9_-]{0,31})(\s+)([^\s\r\n"'`]+)/gi;
|
|
26
|
+
|
|
27
|
+
// A credential passed as a command-line option, which is how most CLIs take one.
|
|
28
|
+
// The assignment patterns below require a key starting with a letter, so every
|
|
29
|
+
// `--token=...` and `--token ...` walked straight past them.
|
|
30
|
+
const CLI_OPTION_SECRET_PATTERN = /(^|[\s({[])(--[A-Za-z][A-Za-z0-9_.-]{0,80})(=|\s+)("[^"\r\n]*"|'[^'\r\n]*'|[^\s"'`;,)}]+)/g;
|
|
31
|
+
|
|
32
|
+
// Under one of these schemes the header carries an opaque credential, so its
|
|
33
|
+
// length says nothing. Anything else after `Authorization:` is more likely prose
|
|
34
|
+
// — "Authorization: not required" — and keeps the ambiguous-syntax length bar.
|
|
35
|
+
const AUTHORIZATION_SCHEMES = new Set([
|
|
36
|
+
"bearer", "basic", "token", "digest", "negotiate", "ntlm",
|
|
37
|
+
"oauth", "hawk", "signature", "apikey", "jwt", "aws4-hmac-sha256"
|
|
38
|
+
]);
|
|
19
39
|
const QUERY_SECRET_PATTERN = /([?&])([A-Za-z][A-Za-z0-9_.-]{0,80})(=)([^&#\s]+)/gi;
|
|
20
40
|
const DOUBLE_QUOTED_SECRET_ASSIGNMENT_PATTERN = /(^|[\s{[,(;])((?:"|')?[A-Za-z][A-Za-z0-9_.-]{0,80}(?:"|')?\s*)(:|=(?!=))\s*"((?:\\.|[^"\\\r\n])*)"/gim;
|
|
21
41
|
const SINGLE_QUOTED_SECRET_ASSIGNMENT_PATTERN = /(^|[\s{[,(;])((?:"|')?[A-Za-z][A-Za-z0-9_.-]{0,80}(?:"|')?\s*)(:|=(?!=))\s*'((?:\\.|[^'\\\r\n])*)'/gim;
|
|
@@ -144,10 +164,22 @@ export function redactSensitiveText(input) {
|
|
|
144
164
|
text = text.replace(BEARER_PATTERN, (_match, prefix) => `${prefix}${REDACTION}`);
|
|
145
165
|
text = text.replace(BASIC_AUTH_PATTERN, (_match, prefix) => `${prefix}${REDACTION}`);
|
|
146
166
|
text = text.replace(AUTHORIZATION_HEADER_PATTERN, (match, prefix, scheme, spacing, value) => {
|
|
147
|
-
|
|
167
|
+
const syntax = AUTHORIZATION_SCHEMES.has(scheme.toLowerCase()) ? "assignment" : "unquoted-colon";
|
|
168
|
+
if (!valueLooksSensitive("authorization", value, syntax)) return match;
|
|
148
169
|
return `${prefix}${scheme}${spacing}${REDACTION}`;
|
|
149
170
|
});
|
|
150
171
|
|
|
172
|
+
// Over-redaction is the safe direction here: a flag whose name says "secret"
|
|
173
|
+
// and whose argument is a plain name — `docker service create --secret build` —
|
|
174
|
+
// loses that name from the record and cannot serve as verify evidence. Reading
|
|
175
|
+
// the name as the credential it is called is the cheaper mistake.
|
|
176
|
+
text = text.replace(CLI_OPTION_SECRET_PATTERN, (match, prefix, flag, separator, value) => {
|
|
177
|
+
// A following option is the next flag, not this flag's argument.
|
|
178
|
+
if (separator !== "=" && value.startsWith("-")) return match;
|
|
179
|
+
if (!keyLooksSensitive(flag) || !valueLooksSensitive(flag, value, "assignment")) return match;
|
|
180
|
+
return `${prefix}${flag}${separator === "=" ? "= " : " "}${REDACTION}`;
|
|
181
|
+
});
|
|
182
|
+
|
|
151
183
|
for (const pattern of TOKEN_PATTERNS) text = text.replace(pattern, REDACTION);
|
|
152
184
|
|
|
153
185
|
text = text.replace(QUERY_SECRET_PATTERN, (match, prefix, key, separator, value) => {
|
|
@@ -15,7 +15,7 @@ Package source examples:
|
|
|
15
15
|
# Installs the stable tag after resolving it to a commit SHA.
|
|
16
16
|
|
|
17
17
|
# Pin a specific release:
|
|
18
|
-
scripts/install-global.sh --version v1.1.
|
|
18
|
+
scripts/install-global.sh --version v1.1.5 --resolve-tag
|
|
19
19
|
|
|
20
20
|
# Preview the planned install/update without changing user config:
|
|
21
21
|
scripts/install-global.sh --stable --dry-run
|
|
@@ -127,7 +127,7 @@ detect_runtime_surface() {
|
|
|
127
127
|
printf 'native-windows/%s (not release-gated; terminal helpers require Bash semantics)' "$arch_name"
|
|
128
128
|
;;
|
|
129
129
|
*)
|
|
130
|
-
printf '%s/%s (outside v1.1.
|
|
130
|
+
printf '%s/%s (outside v1.1.5 release matrix)' "$os_name" "$arch_name"
|
|
131
131
|
;;
|
|
132
132
|
esac
|
|
133
133
|
}
|
|
@@ -135,7 +135,7 @@ detect_runtime_surface() {
|
|
|
135
135
|
warn_runtime_surface_if_needed() {
|
|
136
136
|
local surface="$1"
|
|
137
137
|
case "$surface" in
|
|
138
|
-
*"supported target"*|*"experimental"*|*"not release-gated"*|*"outside v1.1.
|
|
138
|
+
*"supported target"*|*"experimental"*|*"not release-gated"*|*"outside v1.1.5 release matrix"*)
|
|
139
139
|
echo "WARN: runtime surface is $surface." >&2
|
|
140
140
|
echo "WARN: For team rollout, run piagent-doctor plus the project smoke/verify suite on this machine before relying on it." >&2
|
|
141
141
|
;;
|
package/scripts/piagent-cli.mjs
CHANGED
|
@@ -6,6 +6,7 @@ import { fileURLToPath } from "node:url";
|
|
|
6
6
|
const scriptByCommand = {
|
|
7
7
|
"piagent-setup": "scripts/setup.sh",
|
|
8
8
|
"piagent-install": "scripts/install-global.sh",
|
|
9
|
+
"piagent-update": "scripts/update-global.mjs",
|
|
9
10
|
"piagent-uninstall": "scripts/uninstall-global.sh",
|
|
10
11
|
"piagent-init": "scripts/init-project.sh",
|
|
11
12
|
"piagent-doctor": "scripts/team-doctor.sh",
|
package/scripts/team-doctor.sh
CHANGED
|
@@ -137,7 +137,7 @@ function runtimeMatrixStatus() {
|
|
|
137
137
|
surface: `${platform}/${arch}`,
|
|
138
138
|
status: "outside-release-matrix",
|
|
139
139
|
teamRolloutReady: false,
|
|
140
|
-
note: "This runtime is outside the documented v1.1.
|
|
140
|
+
note: "This runtime is outside the documented v1.1.5 support matrix."
|
|
141
141
|
};
|
|
142
142
|
}
|
|
143
143
|
|
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// One command that moves a machine from one release to the next.
|
|
3
|
+
//
|
|
4
|
+
// A release is three independently versioned things: the Pi host, this npm-global
|
|
5
|
+
// terminal helper, and the Pi package the helper installs. They have to move in
|
|
6
|
+
// that order, because `piagent-install` refuses to run against a host that does
|
|
7
|
+
// not match the version its own package.json pins. Doing it by hand means three
|
|
8
|
+
// commands and one ordering rule, and getting the order wrong fails late.
|
|
9
|
+
//
|
|
10
|
+
// The awkward part is that the helper is the program running this file, so it has
|
|
11
|
+
// to replace itself. Rather than re-exec a half-replaced process, every version
|
|
12
|
+
// this run needs is resolved from the registry *before* anything is installed:
|
|
13
|
+
// the target helper version and, from that version's metadata, the host version it
|
|
14
|
+
// will demand. The plan is therefore complete and printable before the first
|
|
15
|
+
// mutation, `--dry-run` shows exactly what a real run would do, and after the
|
|
16
|
+
// helper is replaced the run only has to confirm that what landed on disk is what
|
|
17
|
+
// it asked for.
|
|
18
|
+
|
|
19
|
+
import fs from "node:fs";
|
|
20
|
+
import path from "node:path";
|
|
21
|
+
import { spawnSync } from "node:child_process";
|
|
22
|
+
import { fileURLToPath } from "node:url";
|
|
23
|
+
|
|
24
|
+
const HELPER_PACKAGE = "@piagent/platform";
|
|
25
|
+
const HOST_PACKAGE = "@earendil-works/pi-coding-agent";
|
|
26
|
+
const EXIT_USAGE = 2;
|
|
27
|
+
|
|
28
|
+
const platformRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
|
|
29
|
+
|
|
30
|
+
function usage() {
|
|
31
|
+
return `Usage:
|
|
32
|
+
piagent-update [options]
|
|
33
|
+
|
|
34
|
+
Updates the Pi host, this terminal helper, and the Pi package together, in the
|
|
35
|
+
order a release requires.
|
|
36
|
+
|
|
37
|
+
Options:
|
|
38
|
+
--check Report current and available versions, change nothing
|
|
39
|
+
--dry-run Print every command that would run, change nothing
|
|
40
|
+
--version <x.y.z> Update to an exact helper version instead of latest
|
|
41
|
+
--force Reinstall even when already on the target version
|
|
42
|
+
--project <path> Run the team doctor against this project afterwards
|
|
43
|
+
--no-host Do not touch the Pi host
|
|
44
|
+
--no-package Do not reinstall the Pi package
|
|
45
|
+
-h, --help Show this help
|
|
46
|
+
|
|
47
|
+
Anything after -- is passed through to piagent-install, for example:
|
|
48
|
+
piagent-update -- --no-mcp
|
|
49
|
+
`;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function fail(message, code = 1) {
|
|
53
|
+
console.error(`FAIL: ${message}`);
|
|
54
|
+
process.exit(code);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function readJson(file) {
|
|
58
|
+
try {
|
|
59
|
+
return JSON.parse(fs.readFileSync(file, "utf8"));
|
|
60
|
+
} catch {
|
|
61
|
+
return undefined;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function isReleaseVersion(value) {
|
|
66
|
+
return typeof value === "string" && /^[0-9]+\.[0-9]+\.[0-9]+([+-][0-9A-Za-z.-]+)?$/.test(value);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// "v1.2.3" and "1.2.3" both name the same release everywhere else in this
|
|
70
|
+
// repository, so accept either and normalise once.
|
|
71
|
+
function normalizeVersion(value) {
|
|
72
|
+
return typeof value === "string" && value.startsWith("v") ? value.slice(1) : value;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function parseArguments(argv) {
|
|
76
|
+
const options = {
|
|
77
|
+
check: false,
|
|
78
|
+
dryRun: false,
|
|
79
|
+
force: false,
|
|
80
|
+
version: undefined,
|
|
81
|
+
project: undefined,
|
|
82
|
+
host: true,
|
|
83
|
+
package: true,
|
|
84
|
+
passthrough: []
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
88
|
+
const argument = argv[index];
|
|
89
|
+
if (argument === "--") {
|
|
90
|
+
options.passthrough = argv.slice(index + 1);
|
|
91
|
+
break;
|
|
92
|
+
}
|
|
93
|
+
switch (argument) {
|
|
94
|
+
case "-h":
|
|
95
|
+
case "--help":
|
|
96
|
+
process.stdout.write(usage());
|
|
97
|
+
process.exit(0);
|
|
98
|
+
break;
|
|
99
|
+
case "--check":
|
|
100
|
+
options.check = true;
|
|
101
|
+
break;
|
|
102
|
+
case "--dry-run":
|
|
103
|
+
options.dryRun = true;
|
|
104
|
+
break;
|
|
105
|
+
case "--force":
|
|
106
|
+
options.force = true;
|
|
107
|
+
break;
|
|
108
|
+
case "--no-host":
|
|
109
|
+
options.host = false;
|
|
110
|
+
break;
|
|
111
|
+
case "--no-package":
|
|
112
|
+
options.package = false;
|
|
113
|
+
break;
|
|
114
|
+
case "--version": {
|
|
115
|
+
const value = normalizeVersion(argv[index += 1]);
|
|
116
|
+
if (!isReleaseVersion(value)) fail(`--version needs an exact release such as 1.1.4, got ${argv[index] ?? "nothing"}`, EXIT_USAGE);
|
|
117
|
+
options.version = value;
|
|
118
|
+
break;
|
|
119
|
+
}
|
|
120
|
+
case "--project": {
|
|
121
|
+
const value = argv[index += 1];
|
|
122
|
+
if (!value) fail("--project needs a path", EXIT_USAGE);
|
|
123
|
+
options.project = value;
|
|
124
|
+
break;
|
|
125
|
+
}
|
|
126
|
+
default:
|
|
127
|
+
fail(`unknown option: ${argument}\n\n${usage()}`, EXIT_USAGE);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
return options;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function run(command, args, { capture = false } = {}) {
|
|
135
|
+
const result = spawnSync(command, args, {
|
|
136
|
+
encoding: "utf8",
|
|
137
|
+
stdio: capture ? ["ignore", "pipe", "pipe"] : "inherit"
|
|
138
|
+
});
|
|
139
|
+
if (result.error) return { ok: false, stdout: "", stderr: String(result.error.message ?? result.error) };
|
|
140
|
+
return { ok: result.status === 0, stdout: result.stdout ?? "", stderr: result.stderr ?? "" };
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function npmView(specifier, field) {
|
|
144
|
+
const result = run("npm", ["view", specifier, field, "--json"], { capture: true });
|
|
145
|
+
if (!result.ok) return undefined;
|
|
146
|
+
try {
|
|
147
|
+
return JSON.parse(result.stdout.trim());
|
|
148
|
+
} catch {
|
|
149
|
+
return undefined;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function installedHostVersion() {
|
|
154
|
+
const result = run("pi", ["--version"], { capture: true });
|
|
155
|
+
if (!result.ok) return undefined;
|
|
156
|
+
const match = /([0-9]+\.[0-9]+\.[0-9]+([+-][0-9A-Za-z.-]+)?)/.exec(result.stdout);
|
|
157
|
+
return match ? match[1] : undefined;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// The helper installs itself from the registry, so a run started from a git
|
|
161
|
+
// checkout would replace the checkout's own commands with a published build and
|
|
162
|
+
// leave the operator somewhere they did not ask to be.
|
|
163
|
+
function runningFromGlobalInstall() {
|
|
164
|
+
return platformRoot.split(path.sep).includes("node_modules");
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
function describeStep(dryRun, command, args) {
|
|
168
|
+
console.log(`${dryRun ? "DRY RUN:" : "run:"} ${command} ${args.join(" ")}`);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function main() {
|
|
172
|
+
const options = parseArguments(process.argv.slice(2));
|
|
173
|
+
|
|
174
|
+
const manifest = readJson(path.join(platformRoot, "package.json"));
|
|
175
|
+
if (!manifest?.version) fail(`cannot read the helper package at ${platformRoot}`);
|
|
176
|
+
const currentHelper = manifest.version;
|
|
177
|
+
const currentHost = installedHostVersion();
|
|
178
|
+
|
|
179
|
+
const targetHelper = options.version ?? npmView(HELPER_PACKAGE, "version");
|
|
180
|
+
if (!isReleaseVersion(targetHelper)) {
|
|
181
|
+
fail(`cannot resolve a release for ${HELPER_PACKAGE}. Check network access to the npm registry, or pass --version.`);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// The host requirement belongs to the version being installed, not the one
|
|
185
|
+
// running, so it is read from the target's published metadata.
|
|
186
|
+
const targetPeers = npmView(`${HELPER_PACKAGE}@${targetHelper}`, "peerDependencies");
|
|
187
|
+
const targetHost = targetPeers?.[HOST_PACKAGE];
|
|
188
|
+
if (!isReleaseVersion(targetHost)) {
|
|
189
|
+
fail(`${HELPER_PACKAGE}@${targetHelper} does not pin an exact ${HOST_PACKAGE} version, so the host cannot be updated safely.`);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
const helperNeedsChange = options.force || currentHelper !== targetHelper;
|
|
193
|
+
const hostNeedsChange = options.host && (options.force || currentHost !== targetHost);
|
|
194
|
+
|
|
195
|
+
console.log("Pi Agent Platform update");
|
|
196
|
+
console.log(` helper: ${currentHelper} -> ${targetHelper}${helperNeedsChange ? "" : " (already current)"}`);
|
|
197
|
+
console.log(` host: ${currentHost ?? "not installed"} -> ${targetHost}${hostNeedsChange ? "" : " (already current)"}`);
|
|
198
|
+
console.log(` package: reinstalled from v${targetHelper} as a resolved commit${options.package ? "" : " (skipped)"}`);
|
|
199
|
+
|
|
200
|
+
if (options.check) {
|
|
201
|
+
const pending = [helperNeedsChange && "helper", hostNeedsChange && "host"].filter(Boolean);
|
|
202
|
+
console.log(pending.length ? `\nUpdate available: ${pending.join(", ")}.` : "\nEverything is on the target release.");
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
if (!helperNeedsChange && !hostNeedsChange && !options.package) {
|
|
207
|
+
console.log("\nNothing to do.");
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
if (!options.dryRun && !runningFromGlobalInstall()) {
|
|
212
|
+
fail(`this command updates the npm-global helper, but it is running from ${platformRoot}.\n`
|
|
213
|
+
+ "From a checkout, update with git and install from it:\n"
|
|
214
|
+
+ ` git -C ${platformRoot} pull\n`
|
|
215
|
+
+ ` bash ${path.join(platformRoot, "scripts/install-global.sh")} --local`);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// Host first: piagent-install refuses to run against a host that does not match
|
|
219
|
+
// the version its package.json pins, so a helper installed ahead of the host
|
|
220
|
+
// would fail on its very next step.
|
|
221
|
+
if (hostNeedsChange) {
|
|
222
|
+
const args = ["install", "-g", "--ignore-scripts", `${HOST_PACKAGE}@${targetHost}`];
|
|
223
|
+
describeStep(options.dryRun, "npm", args);
|
|
224
|
+
if (!options.dryRun && !run("npm", args).ok) fail(`could not install ${HOST_PACKAGE}@${targetHost}`);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
if (helperNeedsChange) {
|
|
228
|
+
const args = ["install", "-g", "--ignore-scripts", `${HELPER_PACKAGE}@${targetHelper}`];
|
|
229
|
+
describeStep(options.dryRun, "npm", args);
|
|
230
|
+
if (!options.dryRun) {
|
|
231
|
+
if (!run("npm", args).ok) fail(`could not install ${HELPER_PACKAGE}@${targetHelper}`);
|
|
232
|
+
// The helper has just replaced itself on disk. Everything after this point
|
|
233
|
+
// runs the newly installed scripts, so confirm they are the ones asked for
|
|
234
|
+
// 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
|
+
}
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
if (options.package) {
|
|
244
|
+
const installer = path.join(platformRoot, "scripts/install-global.sh");
|
|
245
|
+
if (!options.dryRun && !fs.existsSync(installer)) {
|
|
246
|
+
fail(`the updated helper has no installer at ${installer}`);
|
|
247
|
+
}
|
|
248
|
+
const args = [installer, "--stable", ...options.passthrough];
|
|
249
|
+
describeStep(options.dryRun, "bash", args);
|
|
250
|
+
if (!options.dryRun && !run("bash", args).ok) fail("the Pi package install did not complete");
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
if (options.project) {
|
|
254
|
+
const doctor = path.join(platformRoot, "scripts/team-doctor.sh");
|
|
255
|
+
const args = [doctor, options.project, "--strict-share"];
|
|
256
|
+
describeStep(options.dryRun, "bash", args);
|
|
257
|
+
if (!options.dryRun && !run("bash", args).ok) fail("the team doctor reported a problem");
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
console.log(options.dryRun
|
|
261
|
+
? `\nDRY RUN: nothing was installed. Rerun without --dry-run to apply v${targetHelper}.`
|
|
262
|
+
: `\nPASS: updated to v${targetHelper}.`);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
main();
|