@piagent/platform 1.1.0 → 1.1.1
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 +16 -0
- package/README.md +1 -1
- package/docs/command-reference-vietnamese.md +2 -2
- package/docs/distribution-standard.md +7 -7
- package/docs/operator-manual-vietnamese.md +7 -7
- package/docs/release-install-policy.md +12 -7
- package/docs/security-threat-model.md +1 -1
- package/docs/team-onboarding.md +2 -2
- package/docs-site/index.html +2 -2
- package/package.json +1 -1
- package/packages/piagent-core/extensions/document-intake.ts +32 -4
- package/packages/piagent-core/package.json +1 -1
- package/scripts/check-published-site.mjs +70 -17
- package/scripts/install-global.sh +3 -3
- package/scripts/setup.sh +5 -0
- package/scripts/team-doctor.sh +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,22 @@
|
|
|
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.1 - 2026-07-26
|
|
6
|
+
|
|
7
|
+
Fixes for defects found reviewing v1.1.0 after it shipped.
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
|
|
11
|
+
- `piagent-setup --no-mcp` installs no MCP again. Setup only ever appended `--with-mcp` and relied on the installer defaulting MCP off; v1.1.0 changed that default to on, so the opt-out reached the installer as silence and the installer's default overrode the operator's explicit choice. It now passes `--no-mcp` through. The other install flags stay one-sided because the installer still defaults them off, which is the condition that made the pattern safe in the first place.
|
|
12
|
+
- `npm run site:check` no longer hangs when a response exceeds the 4 MB body cap. Hitting the cap destroys the response, and a destroyed response emits neither `end` nor `error` — it goes to `aborted` and `close` — so the promise stayed pending forever, and the request timeout could not rescue it because the socket was already gone. A release gate that hangs is worse than one that fails, because nothing reports it. A body cut short is also now reported as cut short rather than as a page that does not mention the version, which is a different claim.
|
|
13
|
+
- `npm run site:check` no longer exits `0` when it could not check an address. Unreachable addresses were printed as `UNVERIFIED` and then the run still ended in `PASS`, so a gate that verified fewer addresses than it resolved reported that it had verified them all. An unchecked address now ends the run; `--allow-unverified` accepts the gap deliberately and names it in the summary.
|
|
14
|
+
- `piagent_document_read` refuses bytes that are not valid UTF-8 or UTF-16 instead of decoding them into replacement characters. The binary check was a scan for a NUL byte, which plenty of binary formats do not carry in their first bytes, and everything past it was decoded leniently — so a binary file renamed to `.txt` came back as content-shaped garbage and was handed to the model. Decoding is now strict in both encodings, which is what the surrounding code already claimed to do.
|
|
15
|
+
- Two CodeQL high alerts came from building a regular expression out of a version string and escaping only `.`. Those assertions were comparing literal text, so they are substring checks now and need no escaping at all. Two further alerts were reviewed and dismissed with written reasons: extracting `<script>` from a document as `<script>` is the required result and the sink is a terminal tool result, not HTML; and the SHA-256 over a normalised shell command is a content identifier, not a password hash.
|
|
16
|
+
|
|
17
|
+
### Changed
|
|
18
|
+
|
|
19
|
+
- The release checklist now requires the **Code scanning results** check on the `main` ruleset, separately from the `analyze (...)` jobs. Requiring those jobs proves only that the analysis ran and uploaded its results — they succeed just as well when the analysis found new high-severity alerts, which is how v1.1.0 merged green with open ones.
|
|
20
|
+
|
|
5
21
|
## v1.1.0 - 2026-07-26
|
|
6
22
|
|
|
7
23
|
A document downloaded outside the repository can now be read by the agent, and the two documented install commands stop disagreeing about MCP.
|
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.1` or a reviewed commit.
|
|
287
287
|
|
|
288
288
|
Ready for:
|
|
289
289
|
|
|
@@ -419,8 +419,8 @@ 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.1` | Cài terminal helper `piagent-*` từ release tag hiện tại. |
|
|
423
|
+
| `pi install git:github.com/Vt-mmm/piagent@v1.1.1` | 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
|
| 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, npm-global 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). |
|
|
426
426
|
| 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.1.
|
|
17
|
+
| Team pinned release | `git:github.com/Vt-mmm/piagent@v1.1.1` |
|
|
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.1` |
|
|
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.1` | 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.1
|
|
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.1
|
|
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.1` 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.1`.
|
|
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.1 \
|
|
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.1
|
|
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.1`. 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.1
|
|
103
103
|
piagent-install --stable --dry-run
|
|
104
104
|
piagent-install --stable
|
|
105
105
|
```
|
|
@@ -269,7 +269,7 @@ Không phải daily default. Dùng khi muốn tạo sẵn `.pi` files cho projec
|
|
|
269
269
|
bash /path/to/piagent/scripts/setup.sh /path/to/project \
|
|
270
270
|
--project-only \
|
|
271
271
|
--profile auto \
|
|
272
|
-
--package-source git:github.com/Vt-mmm/piagent@v1.1.
|
|
272
|
+
--package-source git:github.com/Vt-mmm/piagent@v1.1.1 \
|
|
273
273
|
--mcp-preset core \
|
|
274
274
|
--subagents-preset safe
|
|
275
275
|
```
|
|
@@ -842,8 +842,8 @@ Watchdog là optional adversarial reviewer ở cuối turn, không bật mặc
|
|
|
842
842
|
|
|
843
843
|
| Command | Dùng để |
|
|
844
844
|
|---|---|
|
|
845
|
-
| `npm install -g --ignore-scripts @piagent/platform@1.1.
|
|
846
|
-
| `pi install git:github.com/Vt-mmm/piagent@v1.1.
|
|
845
|
+
| `npm install -g --ignore-scripts @piagent/platform@1.1.1` | Cài terminal helper `piagent-*` từ release tag hiện tại. |
|
|
846
|
+
| `pi install git:github.com/Vt-mmm/piagent@v1.1.1` | Install pinned release cho reproducible team setup. |
|
|
847
847
|
| `pi install git:github.com/Vt-mmm/piagent` | Install latest platform package cho máy cá nhân/sandbox. |
|
|
848
848
|
| 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
849
|
| 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 +940,7 @@ Mở lại Pi session sau khi install.
|
|
|
940
940
|
Cài lại terminal helper đúng release rồi kiểm tra `PATH`:
|
|
941
941
|
|
|
942
942
|
```bash
|
|
943
|
-
npm install -g --ignore-scripts @piagent/platform@1.1.
|
|
943
|
+
npm install -g --ignore-scripts @piagent/platform@1.1.1
|
|
944
944
|
command -v piagent-install
|
|
945
945
|
```
|
|
946
946
|
|
|
@@ -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.1 | 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.1` | 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.1
|
|
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.1 (helper package version)
|
|
65
|
+
tag: v1.1.1
|
|
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.1.
|
|
82
|
+
pi install git:github.com/Vt-mmm/piagent@v1.1.1
|
|
83
83
|
```
|
|
84
84
|
|
|
85
85
|
Direct `pi install` does not create `piagent-*` commands on `PATH`.
|
|
@@ -192,9 +192,12 @@ Before broad team access, a repository administrator must enable these external
|
|
|
192
192
|
3. Enable Dependency graph, Dependabot alerts, and Dependabot security updates. Keep `.github/dependabot.yml` enabled for scheduled npm and GitHub Actions update pull requests.
|
|
193
193
|
4. Enable GitHub private vulnerability reporting so the form linked by `SECURITY.md` works before public rollout.
|
|
194
194
|
5. Keep secret scanning and push protection enabled. Review CodeQL results after the workflow's first successful run.
|
|
195
|
+
6. Add the **Code scanning results** check to the `main` branch ruleset and set its alert threshold so that a new high-severity CodeQL alert blocks the merge. The `analyze (...)` jobs required above only prove the analysis ran and uploaded its SARIF; they succeed just as well when the analysis found new high-severity alerts. Without this separate check, a pull request merges green with open high alerts, which is what happened on `v1.1.1`. Requiring the `analyze` jobs is still necessary — it catches an analysis that failed to run — but it is not the results gate and must not be mistaken for one.
|
|
195
196
|
|
|
196
197
|
Verify these settings in GitHub **Settings → Rules** and **Settings → Code security and analysis**. Treat any missing control as an explicit rollout blocker, not as a passing source-code gate. Repository rules also close the remaining mutability risk of bootstrap-by-tag; tag-to-SHA resolution inside `piagent-install` alone cannot protect the helper package before it starts.
|
|
197
198
|
|
|
199
|
+
Alerts dismissed as false positives carry their reason in the dismissal comment, and the reason belongs in the source as well when the flagged shape is deliberate. An alert dismissed without a written reason is indistinguishable from an alert nobody read.
|
|
200
|
+
|
|
198
201
|
### Required npm publishing controls
|
|
199
202
|
|
|
200
203
|
The publish workflow authenticates with the `NPM_TOKEN` repository secret. That token needs three things, and read-and-write access alone is not enough:
|
|
@@ -270,7 +273,9 @@ Re-running the workflow from a branch instead skips publishing, because the publ
|
|
|
270
273
|
npm run site:check
|
|
271
274
|
```
|
|
272
275
|
|
|
273
|
-
Opening the site in a browser does not answer this. The domain has several address records, so one can be dead or looping while every manual look lands on a healthy one. This resolves both hosts, asks each address directly with the right `Host` header and SNI, and requires each to return the released version. A redirect from an address back to its own host is reported as a loop rather than followed.
|
|
276
|
+
Opening the site in a browser does not answer this. The domain has several address records, so one can be dead or looping while every manual look lands on a healthy one. This resolves both hosts, asks each address directly with the right `Host` header and SNI, and requires each to return the released version. A redirect from an address back to its own host is reported as a loop rather than followed.
|
|
277
|
+
|
|
278
|
+
An address the machine has no route to ends the run. It is reported separately from a site failure, because the machine is what is missing rather than the site, but it is not a pass either — the release gate must not report that it verified every address in a run where it verified fewer. Run the check from a machine with routes to every address family the domain publishes. `--allow-unverified` accepts the gap deliberately and names it in the summary; use it only when the missing route is understood and the remaining addresses were verified.
|
|
274
279
|
9. Publish the already-reviewed draft only after production verification passes:
|
|
275
280
|
|
|
276
281
|
```bash
|
|
@@ -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.1, 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.1
|
|
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.1
|
|
46
46
|
piagent-install --stable --dry-run
|
|
47
47
|
piagent-install --stable
|
|
48
48
|
```
|
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.1 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.1</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
|
@@ -288,6 +288,17 @@ function decodeXmlEntities(value: string): string {
|
|
|
288
288
|
.replace(/&/g, "&");
|
|
289
289
|
}
|
|
290
290
|
|
|
291
|
+
// Stripping markup and then decoding entities is the shape of an incomplete
|
|
292
|
+
// sanitizer, and static analysis flags it as one: a document containing the
|
|
293
|
+
// literal text `<script>` comes out as `<script>`. That is not a defect
|
|
294
|
+
// here, it is the required result — the document shows those characters to a
|
|
295
|
+
// reader, so extraction has to reproduce them. What makes it safe is the sink.
|
|
296
|
+
// This text becomes a Pi tool result, `{ type: "text" }`, rendered in a
|
|
297
|
+
// terminal; the shipped package contains no HTML sink at all. Untrusted
|
|
298
|
+
// document content is separately redacted and wrapped in a region delimited by
|
|
299
|
+
// a marker the document cannot predict. If any renderer that interprets markup
|
|
300
|
+
// is ever added downstream, escaping belongs at that boundary, not here, where
|
|
301
|
+
// it would corrupt the extracted text for every existing caller.
|
|
291
302
|
export function extractDocxText(buffer: Buffer): DocumentExtraction {
|
|
292
303
|
const document = readZipEntry(buffer, "word/document.xml");
|
|
293
304
|
if (document.status === "error") return document;
|
|
@@ -337,6 +348,20 @@ function finish(text: string, kind: "text" | "docx" | "pdf"): DocumentExtraction
|
|
|
337
348
|
// UTF-16 is half NUL bytes by design, so the binary check has to know about it
|
|
338
349
|
// before it runs, and a byte-order mark is the only signal available without
|
|
339
350
|
// guessing. Everything without a mark is treated as UTF-8.
|
|
351
|
+
//
|
|
352
|
+
// Decoding is strict in both encodings. Buffer.toString substitutes U+FFFD for
|
|
353
|
+
// anything it cannot decode, which turns a binary file renamed to .txt into
|
|
354
|
+
// "text" made of replacement characters — the exact outcome the extension gate
|
|
355
|
+
// exists to prevent. A NUL scan does not catch it either: plenty of binary
|
|
356
|
+
// formats carry no NUL in their first bytes.
|
|
357
|
+
function decodeStrict(bytes: Buffer, encoding: "utf-8" | "utf-16le"): string | undefined {
|
|
358
|
+
try {
|
|
359
|
+
return new TextDecoder(encoding, { fatal: true }).decode(bytes);
|
|
360
|
+
} catch {
|
|
361
|
+
return undefined;
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
|
|
340
365
|
function decodeTextBuffer(buffer: Buffer): string | undefined {
|
|
341
366
|
if (buffer.length >= 4 && buffer[0] === 0xff && buffer[1] === 0xfe && buffer[2] === 0x00 && buffer[3] === 0x00) {
|
|
342
367
|
return undefined;
|
|
@@ -346,13 +371,13 @@ function decodeTextBuffer(buffer: Buffer): string | undefined {
|
|
|
346
371
|
if (utf16Little || utf16Big) {
|
|
347
372
|
const body = buffer.subarray(2);
|
|
348
373
|
if (body.length % 2 !== 0) return undefined;
|
|
349
|
-
return utf16Big ? Buffer.from(body).swap16()
|
|
374
|
+
return decodeStrict(utf16Big ? Buffer.from(body).swap16() : body, "utf-16le");
|
|
350
375
|
}
|
|
351
376
|
if (buffer.includes(0)) return undefined;
|
|
352
377
|
if (buffer.length >= 3 && buffer[0] === 0xef && buffer[1] === 0xbb && buffer[2] === 0xbf) {
|
|
353
|
-
return buffer.subarray(3)
|
|
378
|
+
return decodeStrict(buffer.subarray(3), "utf-8");
|
|
354
379
|
}
|
|
355
|
-
return buffer
|
|
380
|
+
return decodeStrict(buffer, "utf-8");
|
|
356
381
|
}
|
|
357
382
|
|
|
358
383
|
export function extractTextDocument(buffer: Buffer): DocumentExtraction {
|
|
@@ -360,7 +385,10 @@ export function extractTextDocument(buffer: Buffer): DocumentExtraction {
|
|
|
360
385
|
// otherwise rather than emit replacement characters that read like content.
|
|
361
386
|
const decoded = decodeTextBuffer(buffer);
|
|
362
387
|
if (decoded === undefined) {
|
|
363
|
-
return {
|
|
388
|
+
return {
|
|
389
|
+
status: "error",
|
|
390
|
+
reason: "file has a text extension but its bytes are not valid UTF-8 or UTF-16 text; it is binary or in some other encoding"
|
|
391
|
+
};
|
|
364
392
|
}
|
|
365
393
|
return finish(decoded.replace(/\r\n?/g, "\n"), "text");
|
|
366
394
|
}
|
|
@@ -30,15 +30,20 @@ function fail(message) {
|
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
function parseArguments(values) {
|
|
33
|
-
const options = { hosts: [], expect: null };
|
|
33
|
+
const options = { hosts: [], expect: null, allowUnverified: false };
|
|
34
34
|
for (let index = 0; index < values.length; index += 1) {
|
|
35
35
|
const option = values[index];
|
|
36
36
|
if (option === "-h" || option === "--help") {
|
|
37
|
-
process.stdout.write("Usage: node scripts/check-published-site.mjs [--host <name>]... [--expect <text>]\n");
|
|
37
|
+
process.stdout.write("Usage: node scripts/check-published-site.mjs [--host <name>]... [--expect <text>] [--allow-unverified]\n");
|
|
38
38
|
process.stdout.write("Verify every resolved address of the docs site serves the released version.\n");
|
|
39
39
|
process.stdout.write("Defaults to piagent.io.vn and www.piagent.io.vn, expecting the root package version.\n");
|
|
40
|
+
process.stdout.write("--allow-unverified downgrades addresses this machine cannot route to from a failure to a note.\n");
|
|
40
41
|
process.exit(0);
|
|
41
42
|
}
|
|
43
|
+
if (option === "--allow-unverified") {
|
|
44
|
+
options.allowUnverified = true;
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
42
47
|
const value = values[index + 1];
|
|
43
48
|
if (option === "--host") {
|
|
44
49
|
if (!value || value.startsWith("--")) fail("--host requires a value");
|
|
@@ -76,14 +81,30 @@ async function resolveAddresses(host) {
|
|
|
76
81
|
return addresses;
|
|
77
82
|
}
|
|
78
83
|
|
|
79
|
-
|
|
84
|
+
// `port` and `tlsOptions` exist so the body-cap path can be driven against a
|
|
85
|
+
// local server in a test. Nothing on the command line reaches them, and the
|
|
86
|
+
// defaults are what every real run uses: port 443 and Node's own trust store.
|
|
87
|
+
export function request(host, { address, family, port = 443 }, tlsOptions = {}) {
|
|
80
88
|
return new Promise((resolve) => {
|
|
89
|
+
// Every path out of here has to settle exactly once. Capping the body
|
|
90
|
+
// destroys the response, and a destroyed response emits neither `end` nor
|
|
91
|
+
// `error` — it goes straight to `aborted` and `close`. Without a `close`
|
|
92
|
+
// handler the promise stays pending forever, and the request timeout cannot
|
|
93
|
+
// rescue it because the socket is already gone. That is a hung release gate,
|
|
94
|
+
// not a failed one.
|
|
95
|
+
let settled = false;
|
|
96
|
+
const settle = (value) => {
|
|
97
|
+
if (settled) return;
|
|
98
|
+
settled = true;
|
|
99
|
+
resolve(value);
|
|
100
|
+
};
|
|
81
101
|
const call = https.request(
|
|
82
102
|
{
|
|
103
|
+
...tlsOptions,
|
|
83
104
|
host: address,
|
|
84
105
|
family,
|
|
85
106
|
servername: host,
|
|
86
|
-
port
|
|
107
|
+
port,
|
|
87
108
|
path: "/",
|
|
88
109
|
method: "GET",
|
|
89
110
|
headers: { Host: host, "User-Agent": "piagent-site-check" },
|
|
@@ -92,24 +113,31 @@ function request(host, { address, family }) {
|
|
|
92
113
|
(response) => {
|
|
93
114
|
let body = "";
|
|
94
115
|
let bytes = 0;
|
|
116
|
+
let truncated = false;
|
|
95
117
|
response.setEncoding("utf8");
|
|
96
118
|
response.on("data", (chunk) => {
|
|
97
119
|
bytes += Buffer.byteLength(chunk, "utf8");
|
|
98
120
|
if (bytes > MAX_BODY_BYTES) {
|
|
121
|
+
truncated = true;
|
|
99
122
|
response.destroy();
|
|
100
123
|
return;
|
|
101
124
|
}
|
|
102
125
|
body += chunk;
|
|
103
126
|
});
|
|
104
|
-
response.on("end", () =>
|
|
105
|
-
|
|
127
|
+
response.on("end", () =>
|
|
128
|
+
settle({ status: response.statusCode, location: response.headers.location, body, truncated })
|
|
129
|
+
);
|
|
130
|
+
response.on("error", (error) => settle({ error: error.message, code: error.code }));
|
|
131
|
+
response.on("close", () =>
|
|
132
|
+
settle({ status: response.statusCode, location: response.headers.location, body, truncated })
|
|
133
|
+
);
|
|
106
134
|
}
|
|
107
135
|
);
|
|
108
136
|
call.on("timeout", () => {
|
|
109
137
|
call.destroy();
|
|
110
|
-
|
|
138
|
+
settle({ error: `no response within ${REQUEST_TIMEOUT_MS}ms` });
|
|
111
139
|
});
|
|
112
|
-
call.on("error", (error) =>
|
|
140
|
+
call.on("error", (error) => settle({ error: error.message, code: error.code }));
|
|
113
141
|
call.end();
|
|
114
142
|
});
|
|
115
143
|
}
|
|
@@ -137,8 +165,13 @@ export function judge(host, hosts, expect, result, family) {
|
|
|
137
165
|
return null;
|
|
138
166
|
}
|
|
139
167
|
if (result.status !== 200) return `HTTP ${result.status}`;
|
|
140
|
-
if (
|
|
141
|
-
|
|
168
|
+
if (result.body.includes(expect)) return null;
|
|
169
|
+
// Not finding the version in a body that was cut short is not the same claim
|
|
170
|
+
// as not finding it in the page.
|
|
171
|
+
if (result.truncated) {
|
|
172
|
+
return `HTTP 200 but the response exceeded ${MAX_BODY_BYTES} bytes and the part read does not mention ${expect}`;
|
|
173
|
+
}
|
|
174
|
+
return `HTTP 200 but the page does not mention ${expect}`;
|
|
142
175
|
}
|
|
143
176
|
|
|
144
177
|
async function main() {
|
|
@@ -170,18 +203,38 @@ async function main() {
|
|
|
170
203
|
}
|
|
171
204
|
}
|
|
172
205
|
|
|
173
|
-
|
|
206
|
+
const summary = summarize({ checked, failures, unverified, expect: options.expect, allowUnverified: options.allowUnverified });
|
|
207
|
+
process.stdout.write(summary.out);
|
|
208
|
+
process.stderr.write(summary.err);
|
|
209
|
+
process.exit(summary.code);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// An address nobody checked is not an address that passed. Reporting it as
|
|
213
|
+
// unverified and then exiting 0 makes the gate say "verified every address"
|
|
214
|
+
// about a run that did not, so an unchecked address ends the run unless the
|
|
215
|
+
// operator accepts the gap deliberately.
|
|
216
|
+
export function summarize({ checked, failures, unverified, expect, allowUnverified }) {
|
|
217
|
+
let out = "";
|
|
218
|
+
for (const entry of unverified) out += `UNVERIFIED: ${entry}\n`;
|
|
174
219
|
|
|
175
220
|
if (failures.length > 0) {
|
|
176
|
-
|
|
177
|
-
for (const failure of failures)
|
|
178
|
-
|
|
179
|
-
|
|
221
|
+
let err = `FAIL: ${failures.length} of ${checked} addresses do not serve ${expect}\n`;
|
|
222
|
+
for (const failure of failures) err += ` ${failure}\n`;
|
|
223
|
+
err += "Each address is a real path users take. Fix the DNS records or the deployment behind them.\n";
|
|
224
|
+
return { code: 1, out, err };
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
if (unverified.length > 0 && !allowUnverified) {
|
|
228
|
+
let err = `FAIL: ${unverified.length} of ${checked} addresses could not be checked from this machine\n`;
|
|
229
|
+
for (const entry of unverified) err += ` ${entry}\n`;
|
|
230
|
+
err += "Run the check from a machine with a route to them, or pass --allow-unverified to accept the gap.\n";
|
|
231
|
+
return { code: 1, out, err };
|
|
180
232
|
}
|
|
181
233
|
|
|
182
234
|
const verified = checked - unverified.length;
|
|
183
|
-
const note = unverified.length > 0 ? ` (${unverified.length} not reachable from this machine)` : "";
|
|
184
|
-
|
|
235
|
+
const note = unverified.length > 0 ? ` (${unverified.length} accepted as not reachable from this machine)` : "";
|
|
236
|
+
out += `PASS: ${verified} of ${checked} addresses serve ${expect}${note}\n`;
|
|
237
|
+
return { code: 0, out, err: "" };
|
|
185
238
|
}
|
|
186
239
|
|
|
187
240
|
if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
|
|
@@ -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.1 --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.1 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.1 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/setup.sh
CHANGED
|
@@ -378,8 +378,13 @@ echo
|
|
|
378
378
|
if [[ "$DO_GLOBAL" == true ]]; then
|
|
379
379
|
ensure_pi_cli
|
|
380
380
|
install_args=("$PLATFORM_ROOT/scripts/install-global.sh" "--package-source" "$PACKAGE_SOURCE")
|
|
381
|
+
# The opt-out has to be passed explicitly. The installer defaults MCP on, so
|
|
382
|
+
# saying nothing here would install it against the operator's choice; the
|
|
383
|
+
# flags below can stay one-sided only because the installer defaults them off.
|
|
381
384
|
if [[ "$WITH_MCP" == true ]]; then
|
|
382
385
|
install_args+=("--with-mcp" "--mcp-preset" "$MCP_PRESET")
|
|
386
|
+
else
|
|
387
|
+
install_args+=("--no-mcp")
|
|
383
388
|
fi
|
|
384
389
|
if [[ "$WITH_SUBAGENTS" == true ]]; then
|
|
385
390
|
install_args+=("--with-subagents" "--subagents-preset" "$SUBAGENTS_PRESET" "--subagents-model-scope" "$SUBAGENTS_MODEL_SCOPE")
|
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.1 support matrix."
|
|
141
141
|
};
|
|
142
142
|
}
|
|
143
143
|
|