@piagent/platform 1.43.9 → 1.44.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.
Files changed (78) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/docs/command-reference-vietnamese.md +8 -2
  3. package/docs/company-dev-commands.md +2 -0
  4. package/docs/distribution-standard.md +6 -6
  5. package/docs/operator-manual-vietnamese.md +7 -7
  6. package/docs/publishing-for-teams.md +2 -0
  7. package/docs/release-install-policy.md +4 -2
  8. package/docs/team-onboarding.md +2 -2
  9. package/docs-site/architecture.html +1 -1
  10. package/docs-site/assets/search-en.json +1 -1
  11. package/docs-site/assets/search-vi.json +1 -1
  12. package/docs-site/benchmark.html +1 -1
  13. package/docs-site/commands.html +1 -1
  14. package/docs-site/context-engine.html +1 -1
  15. package/docs-site/ecosystem.html +1 -1
  16. package/docs-site/en/architecture.html +1 -1
  17. package/docs-site/en/benchmark.html +1 -1
  18. package/docs-site/en/commands.html +1 -1
  19. package/docs-site/en/context-engine.html +1 -1
  20. package/docs-site/en/ecosystem.html +1 -1
  21. package/docs-site/en/index.html +9 -9
  22. package/docs-site/en/mcp-approval.html +1 -1
  23. package/docs-site/en/mcp-auth.html +1 -1
  24. package/docs-site/en/mcp-servers.html +1 -1
  25. package/docs-site/en/mcp.html +1 -1
  26. package/docs-site/en/permissions.html +1 -1
  27. package/docs-site/en/profiles.html +1 -1
  28. package/docs-site/en/quickstart.html +1 -1
  29. package/docs-site/en/runtime.html +1 -1
  30. package/docs-site/en/scope.html +1 -1
  31. package/docs-site/en/security.html +1 -1
  32. package/docs-site/en/team.html +1 -1
  33. package/docs-site/en/update.html +3 -3
  34. package/docs-site/en/whats-new.html +55 -31
  35. package/docs-site/en/windows.html +1 -1
  36. package/docs-site/en/workflows.html +1 -1
  37. package/docs-site/index.html +9 -9
  38. package/docs-site/mcp-approval.html +1 -1
  39. package/docs-site/mcp-auth.html +1 -1
  40. package/docs-site/mcp-servers.html +1 -1
  41. package/docs-site/mcp.html +1 -1
  42. package/docs-site/permissions.html +1 -1
  43. package/docs-site/profiles.html +1 -1
  44. package/docs-site/quickstart.html +1 -1
  45. package/docs-site/releases.json +77 -0
  46. package/docs-site/runtime.html +1 -1
  47. package/docs-site/scope.html +1 -1
  48. package/docs-site/security.html +1 -1
  49. package/docs-site/team.html +1 -1
  50. package/docs-site/update.html +3 -3
  51. package/docs-site/whats-new.html +55 -31
  52. package/docs-site/windows.html +1 -1
  53. package/docs-site/workflows.html +1 -1
  54. package/evals/private-holdout-v1/public-exposure.v2.json +2 -2
  55. package/package.json +4 -1
  56. package/packages/piagent-core/extensions/piagent-guard.ts +3 -0
  57. package/packages/piagent-core/managed/pi-host.mjs +60 -1
  58. package/packages/piagent-core/managed/resource-loader.mjs +3 -2
  59. package/packages/piagent-core/managed/session.mjs +2 -1
  60. package/packages/piagent-core/package.json +1 -1
  61. package/packages/piagent-core/runtime/resources/plugin-skills.mjs +33 -4
  62. package/packages/piagent-core/runtime/terminal/terminal-style.d.mts +7 -0
  63. package/packages/piagent-core/runtime/terminal/terminal-style.mjs +99 -0
  64. package/packages/piagent-core/themes/piagent-contrast.json +78 -0
  65. package/packages/piagent-core/themes/piagent-focus.json +78 -0
  66. package/packages/piagent-core/themes/piagent-ocean.json +78 -0
  67. package/packages/piagent-core/themes/piagent-paper.json +78 -0
  68. package/packages/piagent-webui/gateway/pi-host.ts +13 -1
  69. package/scripts/company-terminal.mjs +6 -2
  70. package/scripts/install-global.sh +13 -1
  71. package/scripts/pi-host.mjs +109 -0
  72. package/scripts/piagent-cli.mjs +17 -6
  73. package/scripts/piagent-dashboard.mjs +2 -2
  74. package/scripts/runtime-advisory-exceptions.json +40 -0
  75. package/scripts/setup.sh +19 -1
  76. package/scripts/skill-sources.mjs +188 -0
  77. package/scripts/uninstall-global.sh +18 -1
  78. package/scripts/update-global.mjs +13 -5
@@ -37,7 +37,7 @@
37
37
  <span class="brand-mark"><img src="/assets/piagent-logo.svg" alt="" width="28" height="28" /></span>
38
38
  <span class="brand-name"><b>Piagent</b> <span>Platform</span></span>
39
39
  </a>
40
- <a class="version-badge" href="/whats-new" data-docs-version="v1.43.9" title="v1.43.9 docs · VI"><span class="dot"></span>v1.43.9</a>
40
+ <a class="version-badge" href="/whats-new" data-docs-version="v1.44.1" title="v1.44.1 docs · VI"><span class="dot"></span>v1.44.1</a>
41
41
  <nav class="top-nav" aria-label="Tài liệu">
42
42
  <a href="/quickstart">Tài liệu</a>
43
43
  <a href="/whats-new">Changelog</a>
@@ -37,7 +37,7 @@
37
37
  <span class="brand-mark"><img src="/assets/piagent-logo.svg" alt="" width="28" height="28" /></span>
38
38
  <span class="brand-name"><b>Piagent</b> <span>Platform</span></span>
39
39
  </a>
40
- <a class="version-badge" href="/whats-new" data-docs-version="v1.43.9" title="v1.43.9 docs · VI"><span class="dot"></span>v1.43.9</a>
40
+ <a class="version-badge" href="/whats-new" data-docs-version="v1.44.1" title="v1.44.1 docs · VI"><span class="dot"></span>v1.44.1</a>
41
41
  <nav class="top-nav" aria-label="Tài liệu">
42
42
  <a href="/quickstart">Tài liệu</a>
43
43
  <a href="/whats-new">Changelog</a>
@@ -37,7 +37,7 @@
37
37
  <span class="brand-mark"><img src="/assets/piagent-logo.svg" alt="" width="28" height="28" /></span>
38
38
  <span class="brand-name"><b>Piagent</b> <span>Platform</span></span>
39
39
  </a>
40
- <a class="version-badge" href="/whats-new" data-docs-version="v1.43.9" title="v1.43.9 docs · VI"><span class="dot"></span>v1.43.9</a>
40
+ <a class="version-badge" href="/whats-new" data-docs-version="v1.44.1" title="v1.44.1 docs · VI"><span class="dot"></span>v1.44.1</a>
41
41
  <nav class="top-nav" aria-label="Tài liệu">
42
42
  <a href="/quickstart">Tài liệu</a>
43
43
  <a href="/whats-new">Changelog</a>
@@ -145,9 +145,9 @@
145
145
  <h2 id="pin-cho-team">Pin một bản cho cả team</h2>
146
146
  <p>Khi rollout cho team, cài đúng bản Pi host và đúng bản platform, rồi chạy installer ở chế độ stable. Bước <code>--dry-run</code> in ra những gì sẽ đổi.</p>
147
147
  <div class="command-card">
148
- <header><span>Cài pin theo bản</span><button class="clip-btn" data-clip="npm install -g --ignore-scripts @earendil-works/pi-coding-agent@1.3.0&#10;npm install -g --ignore-scripts @piagent/platform@1.43.9&#10;piagent-install --stable --dry-run&#10;piagent-install --stable">Lấy lệnh</button></header>
148
+ <header><span>Cài pin theo bản</span><button class="clip-btn" data-clip="npm install -g --ignore-scripts @earendil-works/pi-coding-agent@1.3.0&#10;npm install -g --ignore-scripts @piagent/platform@1.44.1&#10;piagent-install --stable --dry-run&#10;piagent-install --stable">Lấy lệnh</button></header>
149
149
  <pre><code>npm install -g --ignore-scripts @earendil-works/pi-coding-agent@1.3.0
150
- npm install -g --ignore-scripts @piagent/platform@1.43.9
150
+ npm install -g --ignore-scripts @piagent/platform@1.44.1
151
151
  piagent-install --stable --dry-run
152
152
  piagent-install --stable</code></pre>
153
153
  </div>
@@ -37,7 +37,7 @@
37
37
  <span class="brand-mark"><img src="/assets/piagent-logo.svg" alt="" width="28" height="28" /></span>
38
38
  <span class="brand-name"><b>Piagent</b> <span>Platform</span></span>
39
39
  </a>
40
- <a class="version-badge" href="/whats-new" data-docs-version="v1.43.9" title="v1.43.9 docs · VI"><span class="dot"></span>v1.43.9</a>
40
+ <a class="version-badge" href="/whats-new" data-docs-version="v1.44.1" title="v1.44.1 docs · VI"><span class="dot"></span>v1.44.1</a>
41
41
  <nav class="top-nav" aria-label="Tài liệu">
42
42
  <a href="/quickstart">Tài liệu</a>
43
43
  <a href="/whats-new" aria-current="page">Changelog</a>
@@ -108,7 +108,34 @@
108
108
  <div class="release-filter" role="toolbar" aria-label="Lọc theo loại thay đổi"><button type="button" data-filter-kind="all" aria-pressed="true">Tất cả</button><button type="button" data-filter-kind="new" aria-pressed="false">Mới</button><button type="button" data-filter-kind="improved" aria-pressed="false">Cải thiện</button><button type="button" data-filter-kind="fixed" aria-pressed="false">Sửa lỗi</button><button type="button" data-filter-kind="security" aria-pressed="false">Bảo mật</button></div>
109
109
  <section class="section releases" data-releases>
110
110
  <h2 id="latest" class="sr-only">Mới nhất</h2>
111
- <article class="release latest" id="v1-43-9" data-release>
111
+ <article class="release latest" id="v1-44-1" data-release>
112
+ <div class="release-meta"><a class="release-version" href="#v1-44-1">v1.44.1</a><time class="release-date" datetime="2026-10-28">28/10/2026</time></div>
113
+ <div class="release-body">
114
+ <h3 data-toc-skip id="v1-44-1-title">Giữ Pi của bạn, chọn giao diện Terminal, thêm repo skill</h3>
115
+ <p>Dev đang dùng Pi mới hơn giữ nguyên Pi của mình, Piagent chạy bản Pi riêng đúng bản pin; /style chọn giao diện Terminal; piagent skills add thêm repo skill như mattpocock/skills.</p>
116
+ <ul class="release-items">
117
+ <li data-kind="new"><span class="kind kind-new">Mới</span><span>/style chọn giao diện Terminal: system, dark, light của Pi hoặc ocean, paper, contrast, focus của Piagent. Terminal công ty nhớ lựa chọn.</span></li>
118
+ <li data-kind="new"><span class="kind kind-new">Mới</span><span>piagent skills add mattpocock/skills thêm repo skill GitHub ghim một commit; skill dùng được dạng /skill:tên trong Pi, Terminal công ty và dashboard.</span></li>
119
+ <li data-kind="fixed"><span class="kind kind-fixed">Sửa lỗi</span><span>Setup, install, update không còn hạ pi mới hơn của dev (vd 1.4.0) về bản pin 1.3.0: Piagent giữ bản riêng trong ~/.piagent/pi-host cho phiên công ty, dashboard và lệnh piagent pi.</span></li>
120
+ <li data-kind="fixed"><span class="kind kind-fixed">Sửa lỗi</span><span>piagent-uninstall --with-host gỡ bản Pi riêng của Piagent và giữ nguyên pi mới hơn của dev.</span></li>
121
+ <li data-kind="security"><span class="kind kind-security">Bảo mật</span><span>Năm advisory undici công bố ngày 2026-10-27 được chấp nhận tạm tới 2026-11-07: undici 8.10.2 do mọi Pi host ghim cứng, bản vá ở 8.12.2.</span></li>
122
+ </ul>
123
+ </div>
124
+ </article>
125
+ <article class="release" id="v1-44-0" data-release>
126
+ <div class="release-meta"><a class="release-version" href="#v1-44-0">v1.44.0</a><time class="release-date" datetime="2026-10-28">28/10/2026</time></div>
127
+ <div class="release-body">
128
+ <h3 data-toc-skip id="v1-44-0-title">Giữ Pi của bạn, chọn giao diện Terminal, thêm repo skill <span class="tag">không phát hành</span></h3>
129
+ <p>Đã tag nhưng chưa publish: advisory undici mới trong Pi host làm kiểm tra runtime fail. Thay bằng 1.44.1.</p>
130
+ <ul class="release-items">
131
+ <li data-kind="new"><span class="kind kind-new">Mới</span><span>/style chọn giao diện Terminal: system, dark, light của Pi hoặc ocean, paper, contrast, focus của Piagent. Terminal công ty nhớ lựa chọn.</span></li>
132
+ <li data-kind="new"><span class="kind kind-new">Mới</span><span>piagent skills add mattpocock/skills thêm repo skill GitHub ghim một commit; skill dùng được dạng /skill:tên trong Pi, Terminal công ty và dashboard.</span></li>
133
+ <li data-kind="fixed"><span class="kind kind-fixed">Sửa lỗi</span><span>Setup, install, update không còn hạ pi mới hơn của dev (vd 1.4.0) về bản pin 1.3.0: Piagent giữ bản riêng trong ~/.piagent/pi-host cho phiên công ty, dashboard và lệnh piagent pi.</span></li>
134
+ <li data-kind="fixed"><span class="kind kind-fixed">Sửa lỗi</span><span>piagent-uninstall --with-host gỡ bản Pi riêng của Piagent và giữ nguyên pi mới hơn của dev.</span></li>
135
+ </ul>
136
+ </div>
137
+ </article>
138
+ <article class="release" id="v1-43-9" data-release>
112
139
  <div class="release-meta"><a class="release-version" href="#v1-43-9">v1.43.9</a><time class="release-date" datetime="2026-10-27">27/10/2026</time></div>
113
140
  <div class="release-body">
114
141
  <h3 data-toc-skip id="v1-43-9-title">Đủ skill đã cài, và mở file agent gửi lại</h3>
@@ -402,40 +429,37 @@
402
429
  <p class="release-requires"><strong>Cần:</strong> Agent Studio 0.37.0</p>
403
430
  </div>
404
431
  </article>
405
- <article class="release" id="v1-35-1" data-release>
406
- <div class="release-meta"><a class="release-version" href="#v1-35-1">v1.35.1</a><time class="release-date" datetime="2026-10-21">21/10/2026</time></div>
407
- <div class="release-body">
408
- <h3 data-toc-skip id="v1-35-1-title">Lỗi tạm thời của nhà cung cấp model không còn làm dừng task dài</h3>
409
- <p>Lỗi của nhà cung cấp model giữa câu trả lời được hỏi lại, và vòng bị cắt bởi lỗi như vậy tự chạy tiếp sau một lúc chờ.</p>
410
- <ul class="release-items">
411
- <li data-kind="improved"><span class="kind kind-improved">Cải thiện</span><span>Khi không hỏi lại được, vòng sau tự bắt đầu sau một lúc chờ và báo agent lý do, tối đa 8 lần mỗi tin nhắn của member (khoảng 23 phút).</span></li>
412
- <li data-kind="improved"><span class="kind kind-improved">Cải thiện</span><span>Vòng kết thúc tốt sẽ đặt lại bộ đếm, Stop dừng lúc chờ, và sau lần cuối lượt báo lỗi kèm lý do.</span></li>
413
- <li data-kind="improved"><span class="kind kind-improved">Cải thiện</span><span>Mỗi lần hỏi lại được ghi vào log trên máy của member, để đọc lại vì sao task dừng hay chạy tiếp.</span></li>
414
- <li data-kind="fixed"><span class="kind kind-fixed">Sửa lỗi</span><span>Lỗi của nhà cung cấp sau một bước tool từng dừng task dài cho tới khi member nhắn lại; giờ Piagent hỏi lại sau 2 và 4 giây.</span></li>
415
- </ul>
416
- </div>
417
- </article>
418
- <article class="release" id="v1-35-0" data-release>
419
- <div class="release-meta"><a class="release-version" href="#v1-35-0">v1.35.0</a><time class="release-date" datetime="2026-10-21">21/10/2026</time></div>
420
- <div class="release-body">
421
- <h3 data-toc-skip id="v1-35-0-title">Task dài của công ty chạy qua được lúc Studio cập nhật</h3>
422
- <p>Khi Studio dừng, khởi động lại hay cập nhật giữa task, Piagent chờ rồi làm tiếp thay vì báo lỗi, và một lượt trên dashboard chạy được 24 giờ.</p>
423
- <ul class="release-items">
424
- <li data-kind="new"><span class="kind kind-new">Mới</span><span>Khi Studio không phản hồi, Piagent đọc heartbeat và hỏi lại khi Studio trở lại, không giới hạn thời gian; Stop vẫn dừng được.</span></li>
425
- <li data-kind="new"><span class="kind kind-new">Mới</span><span>Mỗi lần chờ được ghi vào log trên máy và báo về Studio, nơi hiện nó kèm nguyên nhân trong Logs → &quot;Mất kết nối&quot;.</span></li>
426
- <li data-kind="improved"><span class="kind kind-improved">Cải thiện</span><span>Vòng mà dashboard không phát lại được sẽ tự bắt đầu lại và báo agent Studio vừa cập nhật, để agent làm tiếp từ chỗ dở.</span></li>
427
- <li data-kind="improved"><span class="kind kind-improved">Cải thiện</span><span>Một tin nhắn của member chạy được tới 24 giờ trên dashboard (trước là 6); giới hạn 15 phút im lặng vẫn giữ.</span></li>
428
- <li data-kind="improved"><span class="kind kind-improved">Cải thiện</span><span>Lỗi key, quota hay policy vẫn báo lỗi ngay như trước.</span></li>
429
- </ul>
430
- <p class="release-requires"><strong>Cần:</strong> Agent Studio 0.36.0</p>
431
- </div>
432
- </article>
433
432
  </section>
434
433
  <section class="section archive">
435
434
  <h2 id="archive">Các bản trước</h2>
436
435
  <p class="section-lead">Bản cũ hơn, gom theo tháng. Mở một tháng để xem từng thay đổi.</p>
437
436
  <details class="release-archive">
438
- <summary><span>Tháng 10/2026</span><span class="archive-count">50</span></summary>
437
+ <summary><span>Tháng 10/2026</span><span class="archive-count">52</span></summary>
438
+ <div class="archive-row" id="v1-35-1">
439
+ <div class="archive-head"><a class="release-version" href="#v1-35-1">v1.35.1</a> <span class="release-date">21/10/2026</span></div>
440
+ <div class="archive-body">
441
+ <p><strong>Lỗi tạm thời của nhà cung cấp model không còn làm dừng task dài</strong> — Lỗi của nhà cung cấp model giữa câu trả lời được hỏi lại, và vòng bị cắt bởi lỗi như vậy tự chạy tiếp sau một lúc chờ.</p>
442
+ <ul class="release-items">
443
+ <li data-kind="improved"><span class="kind kind-improved">Cải thiện</span><span>Khi không hỏi lại được, vòng sau tự bắt đầu sau một lúc chờ và báo agent lý do, tối đa 8 lần mỗi tin nhắn của member (khoảng 23 phút).</span></li>
444
+ <li data-kind="improved"><span class="kind kind-improved">Cải thiện</span><span>Vòng kết thúc tốt sẽ đặt lại bộ đếm, Stop dừng lúc chờ, và sau lần cuối lượt báo lỗi kèm lý do.</span></li>
445
+ <li data-kind="improved"><span class="kind kind-improved">Cải thiện</span><span>Mỗi lần hỏi lại được ghi vào log trên máy của member, để đọc lại vì sao task dừng hay chạy tiếp.</span></li>
446
+ <li data-kind="fixed"><span class="kind kind-fixed">Sửa lỗi</span><span>Lỗi của nhà cung cấp sau một bước tool từng dừng task dài cho tới khi member nhắn lại; giờ Piagent hỏi lại sau 2 và 4 giây.</span></li>
447
+ </ul>
448
+ </div>
449
+ </div>
450
+ <div class="archive-row" id="v1-35-0">
451
+ <div class="archive-head"><a class="release-version" href="#v1-35-0">v1.35.0</a> <span class="release-date">21/10/2026</span></div>
452
+ <div class="archive-body">
453
+ <p><strong>Task dài của công ty chạy qua được lúc Studio cập nhật</strong> — Khi Studio dừng, khởi động lại hay cập nhật giữa task, Piagent chờ rồi làm tiếp thay vì báo lỗi, và một lượt trên dashboard chạy được 24 giờ.</p>
454
+ <ul class="release-items">
455
+ <li data-kind="new"><span class="kind kind-new">Mới</span><span>Khi Studio không phản hồi, Piagent đọc heartbeat và hỏi lại khi Studio trở lại, không giới hạn thời gian; Stop vẫn dừng được.</span></li>
456
+ <li data-kind="new"><span class="kind kind-new">Mới</span><span>Mỗi lần chờ được ghi vào log trên máy và báo về Studio, nơi hiện nó kèm nguyên nhân trong Logs → &quot;Mất kết nối&quot;.</span></li>
457
+ <li data-kind="improved"><span class="kind kind-improved">Cải thiện</span><span>Vòng mà dashboard không phát lại được sẽ tự bắt đầu lại và báo agent Studio vừa cập nhật, để agent làm tiếp từ chỗ dở.</span></li>
458
+ <li data-kind="improved"><span class="kind kind-improved">Cải thiện</span><span>Một tin nhắn của member chạy được tới 24 giờ trên dashboard (trước là 6); giới hạn 15 phút im lặng vẫn giữ.</span></li>
459
+ <li data-kind="improved"><span class="kind kind-improved">Cải thiện</span><span>Lỗi key, quota hay policy vẫn báo lỗi ngay như trước.</span></li>
460
+ </ul>
461
+ </div>
462
+ </div>
439
463
  <div class="archive-row" id="v1-34-3">
440
464
  <div class="archive-head"><a class="release-version" href="#v1-34-3">v1.34.3</a> <span class="release-date">20/10/2026</span></div>
441
465
  <div class="archive-body">
@@ -37,7 +37,7 @@
37
37
  <span class="brand-mark"><img src="/assets/piagent-logo.svg" alt="" width="28" height="28" /></span>
38
38
  <span class="brand-name"><b>Piagent</b> <span>Platform</span></span>
39
39
  </a>
40
- <a class="version-badge" href="/whats-new" data-docs-version="v1.43.9" title="v1.43.9 docs · VI"><span class="dot"></span>v1.43.9</a>
40
+ <a class="version-badge" href="/whats-new" data-docs-version="v1.44.1" title="v1.44.1 docs · VI"><span class="dot"></span>v1.44.1</a>
41
41
  <nav class="top-nav" aria-label="Tài liệu">
42
42
  <a href="/quickstart">Tài liệu</a>
43
43
  <a href="/whats-new">Changelog</a>
@@ -37,7 +37,7 @@
37
37
  <span class="brand-mark"><img src="/assets/piagent-logo.svg" alt="" width="28" height="28" /></span>
38
38
  <span class="brand-name"><b>Piagent</b> <span>Platform</span></span>
39
39
  </a>
40
- <a class="version-badge" href="/whats-new" data-docs-version="v1.43.9" title="v1.43.9 docs · VI"><span class="dot"></span>v1.43.9</a>
40
+ <a class="version-badge" href="/whats-new" data-docs-version="v1.44.1" title="v1.44.1 docs · VI"><span class="dot"></span>v1.44.1</a>
41
41
  <nav class="top-nav" aria-label="Tài liệu">
42
42
  <a href="/quickstart">Tài liệu</a>
43
43
  <a href="/whats-new">Changelog</a>
@@ -256,8 +256,8 @@
256
256
  },
257
257
  {
258
258
  "path": "tests",
259
- "fileCount": 627,
260
- "sha256": "b5348255a9be4cc54e203df95af8677a1defd3407017fc45c8a4a0cbcf5d6469"
259
+ "fileCount": 630,
260
+ "sha256": "3cb368eea2af5b678eb083ca68195a165db4a05888045939bc846c91b3fa6350"
261
261
  }
262
262
  ],
263
263
  "custodianComparisonRules": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@piagent/platform",
3
- "version": "1.43.9",
3
+ "version": "1.44.1",
4
4
  "license": "MIT",
5
5
  "publishConfig": {
6
6
  "access": "public",
@@ -101,6 +101,9 @@
101
101
  "skills": [
102
102
  "packages/piagent-core/skills"
103
103
  ],
104
+ "themes": [
105
+ "packages/piagent-core/themes"
106
+ ],
104
107
  "subagents": {
105
108
  "agents": [
106
109
  "packages/piagent-core/subagents"
@@ -171,6 +171,7 @@ import { prefixCompletions, registerPiagentTool as registerToolDefinition, regis
171
171
  import { registerTaskEvidenceTools } from "../runtime/registration/task-evidence-tools.ts";
172
172
  import { registerAgentResources } from "../runtime/registration/agent-resources.ts";
173
173
  import { registerTerminalUpdateOffer } from "../runtime/update/terminal-update-offer.mjs";
174
+ import { registerStyleCommand } from "../runtime/terminal/terminal-style.mjs";
174
175
  import { userSkillFolders } from "../runtime/resources/agent-resources.mjs";
175
176
  import { FRESH_COMMAND_ACTIONS, FRESH_COMMAND_HELP, ONBOARDING_COMMAND_ACTIONS, WORKFLOW_COMMAND_EXCLUSIONS } from "../runtime/registration/operator-catalogs.ts";
176
177
  import { registerPiagentStatusCommand } from "../runtime/registration/runtime-model-status.ts";
@@ -4242,5 +4243,7 @@ export default function piagentGuard(pi: ExtensionAPI) {
4242
4243
  registerAgentResources(pi);
4243
4244
  // A new release is asked about in the Terminal, as the dashboard does.
4244
4245
  registerTerminalUpdateOffer(pi, { installed: installedPlatformVersion(), packageRoot: PLATFORM_ROOT, restart: "pi" });
4246
+ // The Terminal's look (/style): Pi keeps the pick in its own settings.
4247
+ registerStyleCommand(pi);
4245
4248
  registerSessionCommands(pi, { ...registrationDeps, ...contextCommandApi });
4246
4249
  }
@@ -1,11 +1,15 @@
1
+ import { spawnSync } from 'node:child_process';
1
2
  import fs from 'node:fs';
3
+ import os from 'node:os';
2
4
  import path from 'node:path';
3
5
 
4
6
  // The Pi host company sessions are qualified on: the package's peer
5
7
  // dependency, which piagent-setup installs and CI tests. One place, so moving
6
8
  // to a new host is one change (scripts/verify-release-identity.mjs keeps its
7
9
  // own copy on purpose, to catch a pin moved by accident).
8
- export const PI_HOST_VERSION = JSON.parse(fs.readFileSync(new URL('../../../package.json', import.meta.url), 'utf8')).peerDependencies['@earendil-works/pi-coding-agent'];
10
+ export const PI_HOST_VERSION = JSON.parse(fs.readFileSync(new URL('../../../package.json', import.meta.url), 'utf8')).peerDependencies?.['@earendil-works/pi-coding-agent'];
11
+
12
+ const HOST_NAME = '@earendil-works/pi-coding-agent';
9
13
 
10
14
  // A package the host depends on (@earendil-works/pi-ai), found the way Node
11
15
  // finds it from the host: in its own node_modules (0.87.1 shipped a
@@ -17,3 +21,58 @@ export function hostPackage(sdk, name) {
17
21
  if (path.dirname(dir) === dir) throw new Error(`managed-sdk-dependency-missing: ${name}`);
18
22
  }
19
23
  }
24
+
25
+ // A member may run their own Pi, newer than the pinned host (they keep up
26
+ // with Pi themselves). Piagent never replaces it: the pinned host is installed
27
+ // beside it, privately, under ~/.piagent/pi-host/<version>, and company
28
+ // sessions, the dashboard and `piagent pi` run that one.
29
+ export function privateHostPrefix(version = PI_HOST_VERSION, home = os.homedir()) {
30
+ return path.join(home, '.piagent', 'pi-host', version);
31
+ }
32
+
33
+ // The private host's package root when it holds exactly `version`, else null.
34
+ export function privateHostRoot(version = PI_HOST_VERSION, home = os.homedir()) {
35
+ const root = path.join(privateHostPrefix(version, home), 'node_modules', ...HOST_NAME.split('/'));
36
+ try {
37
+ const manifest = JSON.parse(fs.readFileSync(path.join(root, 'package.json'), 'utf8'));
38
+ return manifest.name === HOST_NAME && manifest.version === version ? fs.realpathSync(root) : null;
39
+ } catch { return null; }
40
+ }
41
+
42
+ // The host's command line entry (`pi`), as its manifest names it.
43
+ export function hostCli(root) {
44
+ const bin = JSON.parse(fs.readFileSync(path.join(root, 'package.json'), 'utf8')).bin;
45
+ return path.join(root, typeof bin === 'string' ? bin : bin.pi);
46
+ }
47
+
48
+ const parts = (version) => String(version).split(/[+-]/)[0].split('.').map(Number);
49
+ export function compareVersions(a, b) {
50
+ const x = parts(a), y = parts(b);
51
+ for (let index = 0; index < 3; index += 1) if ((x[index] ?? 0) !== (y[index] ?? 0)) return (x[index] ?? 0) - (y[index] ?? 0);
52
+ return 0;
53
+ }
54
+
55
+ // What setup does with the `pi` on PATH: nothing when it is the pinned host;
56
+ // keep a newer one (the member's own) and install the pinned host privately;
57
+ // replace a missing or older one, as Piagent itself put it there.
58
+ export function hostPlan(current, pinned = PI_HOST_VERSION) {
59
+ if (current === pinned) return 'current';
60
+ if (current && compareVersions(current, pinned) > 0) return 'private';
61
+ return 'global';
62
+ }
63
+
64
+ // Installs the pinned host into its private prefix (no install scripts, as
65
+ // the global install). Returns the package root.
66
+ export function installPrivateHost({ version = PI_HOST_VERSION, home = os.homedir(), npm = 'npm', dryRun = false, log = () => {} } = {}) {
67
+ const existing = privateHostRoot(version, home);
68
+ if (existing) return existing;
69
+ const prefix = privateHostPrefix(version, home);
70
+ const args = ['install', '--prefix', prefix, '--ignore-scripts', '--no-audit', '--no-fund', '--no-save', `${HOST_NAME}@${version}`];
71
+ log(`${dryRun ? 'DRY RUN: ' : ''}${npm} ${args.join(' ')}`);
72
+ if (dryRun) return path.join(prefix, 'node_modules', ...HOST_NAME.split('/'));
73
+ fs.mkdirSync(prefix, { recursive: true, mode: 0o700 });
74
+ const result = spawnSync(npm, args, { stdio: ['ignore', 'inherit', 'inherit'], shell: process.platform === 'win32' });
75
+ const root = privateHostRoot(version, home);
76
+ if (result.status !== 0 || !root) throw new Error(`pi-host-private-install-failed: ${HOST_NAME}@${version}`);
77
+ return root;
78
+ }
@@ -25,13 +25,14 @@ export function projectInstructions(cwd, top = cwd) {
25
25
  // Managed sessions never consult the personal trust store or execute resources
26
26
  // discovered in a project. Skills and commands are text (agent-skills.mjs):
27
27
  // what they ask for runs with the session's own tools.
28
- export function managedResourceLoader(api, { systemPrompt, extensions = [], runtime = api.createExtensionRuntime(), agentsFiles = [], skills = [], prompts = [] } = {}) {
28
+ // themes: Piagent's own (the company Terminal's /style), loaded by the host.
29
+ export function managedResourceLoader(api, { systemPrompt, extensions = [], runtime = api.createExtensionRuntime(), agentsFiles = [], skills = [], prompts = [], themes = [] } = {}) {
29
30
  const empty = Object.freeze([]);
30
31
  return Object.freeze({
31
32
  getExtensions: () => ({ extensions, errors: empty, runtime }),
32
33
  getSkills: () => ({ skills: [...skills], diagnostics: empty }),
33
34
  getPrompts: () => ({ prompts: [...prompts], diagnostics: empty }),
34
- getThemes: () => ({ themes: empty, diagnostics: empty }),
35
+ getThemes: () => ({ themes: [...themes], diagnostics: empty }),
35
36
  getAgentsFiles: () => ({ agentsFiles: agentsFiles.map((file) => ({ ...file })) }),
36
37
  getSystemPrompt: () => typeof systemPrompt === 'function' ? systemPrompt() : systemPrompt,
37
38
  getSystemPromptSource: () => undefined,
@@ -27,6 +27,7 @@ import { workflowContextTool, workflowContextExtension } from './workflow-contex
27
27
  import { beforeDelegate } from './objections.mjs';
28
28
  import { HELPER_CALLS, HELPER_ROLES, helperRoles, helperPrompt, webPrompt, delegateDescription } from './helper-roles.mjs'; import { delegateParameters, delegateArgs, SPEC_PROMPT } from './helper-settlement.mjs';
29
29
  import { loadAgentResources } from './agent-skills.mjs';
30
+ import { loadPiagentThemes } from '../runtime/terminal/terminal-style.mjs';
30
31
  import { restorePermission, recordBypass, permissionSetter } from './permission.mjs';
31
32
  import { commandTools, servicesPrompt } from './command-tools.mjs'; import { attachMemory, memoryToolsFor, openRound, closeRound, prepareMemoryContext, trackMemoryLessons } from './memory.mjs';
32
33
 
@@ -135,7 +136,7 @@ export class ManagedSession {
135
136
  self.checks = repositoryChecks(agentsFiles, self.cwd, self.boundary.repositoryTop);
136
137
  // The Harness workflow (possibly changed on a later enrollment) adds its process to the prompt.
137
138
  const loader = managedResourceLoader(api, { systemPrompt: () => BASE_PROMPT + referencePrompt(self.boundary.userHome) + TEST_PROMPT + servicesPrompt(self.boundary) + webPrompt(helperRoles(manifest)) + helperPrompt(helperRoles(self.manifest)) + workflowPrompt(workflowPolicy(self.manifest), self.checks), agentsFiles,
138
- skills: self.resources.skills, prompts: self.resources.prompts, ...await inlineExtensions(api, sdk, self.cwd,
139
+ skills: self.resources.skills, prompts: self.resources.prompts, themes: terminalExtensions.length ? await loadPiagentThemes(sdk) : [], ...await inlineExtensions(api, sdk, self.cwd,
139
140
  [...terminalExtensions, workflowContextExtension(self.cwd, () => self.session.sessionManager)]) });
140
141
  const settings = api.SettingsManager.inMemory({ retry: { enabled: false, provider: { maxRetries: 0 } }, cacheWarming: 'off', enableInstallTelemetry: false, enableAnalytics: false, enableSkillCommands: true });
141
142
  const manager = sessionManager ?? api.SessionManager.inMemory(self.cwd); attachMemory(self, manager, agentDir, g => verifyGrant(g, self.manifest, 'main')); self.studioLink = new StudioLink({ origin: self.origin, agentDir, notify: event => self.notify(event), ui: () => self.session?.extensionRunner?.getUIContext?.() });
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@piagent/core",
3
- "version": "1.43.9",
3
+ "version": "1.44.1",
4
4
  "type": "module",
5
5
  "private": true,
6
6
  "license": "MIT",
@@ -2,7 +2,8 @@ import fs from 'node:fs';
2
2
  import os from 'node:os';
3
3
  import path from 'node:path';
4
4
 
5
- // Skills and commands a member installed as Claude or Codex plugins
5
+ // Skills and commands a member installed as Claude or Codex plugins, or added
6
+ // to Piagent as a skill source
6
7
  // (superpowers, a team's own marketplace…). Each agent keeps them in its plugin
7
8
  // cache, not in ~/.claude/skills or ~/.codex/skills, so they are found here:
8
9
  // the plugins the agent records as installed, the newest version of each, and
@@ -119,9 +120,37 @@ function codexPlugins(home) {
119
120
  return found.filter(Boolean);
120
121
  }
121
122
 
122
- // The member's plugins, Claude's first, at most MAX_PLUGINS. A plugin
123
- // that cannot be read is left out; it never keeps a conversation from opening.
123
+ // Skill repositories the member added with `piagent skills add` (for example
124
+ // mattpocock/skills), each kept at the commit it was added at under
125
+ // ~/.piagent/skill-sources and listed in ~/.piagent/skill-sources.json
126
+ // (scripts/skill-sources.mjs). A repository that ships a Claude or Codex
127
+ // plugin manifest is read through it, so only the skills it publishes load.
128
+ export function skillSourcesRoot(home = os.homedir()) {
129
+ return path.join(home, '.piagent', 'skill-sources');
130
+ }
131
+ export function skillSourcesIndex(home = os.homedir()) {
132
+ return path.join(home, '.piagent', 'skill-sources.json');
133
+ }
134
+ function piagentSources(home) {
135
+ const sources = readJson(skillSourcesIndex(home))?.sources;
136
+ if (!Array.isArray(sources)) return [];
137
+ const root = folder(skillSourcesRoot(home));
138
+ if (!root) return [];
139
+ return sources.filter((entry) => entry && typeof entry.path === 'string' && entry.enabled !== false).map((entry) => {
140
+ const dir = folder(path.resolve(root, entry.path));
141
+ return dir && inside(dir, root) ? skillSourcePlugin(dir, entry.name || entry.repo) : null;
142
+ }).filter(Boolean);
143
+ }
144
+ // One source's copy read as a plugin: through its Claude or Codex manifest when it has one.
145
+ export function skillSourcePlugin(dir, name) {
146
+ const manifestDir = fs.existsSync(path.join(dir, '.claude-plugin', 'plugin.json')) ? '.claude-plugin' : '.codex-plugin';
147
+ return plugin(dir, 'piagent', name, manifestDir);
148
+ }
149
+
150
+ // The member's plugins, Claude's first, then Codex's and the skill sources
151
+ // added to Piagent, at most MAX_PLUGINS. A plugin that cannot be read is left
152
+ // out; it never keeps a conversation from opening.
124
153
  export function memberPlugins({ home = os.homedir(), projects = [] } = {}) {
125
154
  const read = (load) => { try { return load(); } catch { return []; } };
126
- return [...read(() => claudePlugins(home, projects)), ...read(() => codexPlugins(home))].slice(0, MAX_PLUGINS);
155
+ return [...read(() => claudePlugins(home, projects)), ...read(() => codexPlugins(home)), ...read(() => piagentSources(home))].slice(0, MAX_PLUGINS);
127
156
  }
@@ -0,0 +1,7 @@
1
+ export const THEMES_DIR: string;
2
+ export function piagentThemeFiles(dir?: string): string[];
3
+ export function loadPiagentThemes(sdkRoot: string, dir?: string): Promise<unknown[]>;
4
+ export function readStyle(home?: string): string | null;
5
+ export function writeStyle(name: string, home?: string): void;
6
+ export function styleChoices(ui: unknown): { name: string; label: string }[];
7
+ export function registerStyleCommand(pi: unknown, options?: { remember?: boolean; home?: string }): void;
@@ -0,0 +1,99 @@
1
+ // The Terminal's look, chosen by the member: /style lists Pi's own themes
2
+ // (system, dark, light) and Piagent's (packages/piagent-core/themes), shows
3
+ // the one picked at once and keeps it. Personal Pi keeps it in its own
4
+ // settings (`theme`), as /settings → Theme does. The company Terminal runs
5
+ // with settings in memory, so its choice is kept in ~/.pi beside the other
6
+ // Terminal state and put back when a conversation opens.
7
+ import fs from "node:fs";
8
+ import os from "node:os";
9
+ import path from "node:path";
10
+ import { fileURLToPath, pathToFileURL } from "node:url";
11
+
12
+ export const THEMES_DIR = fileURLToPath(new URL("../../themes", import.meta.url));
13
+ const STYLE_FILE = "piagent-terminal-style.json";
14
+ // The dashboard's own runtime UI draws its own page: no Terminal theme there.
15
+ const GATEWAY_UI = Symbol.for("piagent.webui.gateway-runtime-ui.v1");
16
+
17
+ // What each style is for, in the member's words; Pi's own are listed first.
18
+ const DESCRIPTIONS = {
19
+ system: "theo màu của terminal (mặc định của Pi)",
20
+ dark: "nền tối của Pi",
21
+ light: "nền sáng của Pi",
22
+ "piagent-ocean": "nền tối, xanh biển dịu mắt cho phiên dài",
23
+ "piagent-paper": "nền sáng, tông giấy ấm",
24
+ "piagent-contrast": "tương phản cao, cho phòng sáng hoặc máy chiếu",
25
+ "piagent-focus": "gần như đơn sắc, một màu nhấn hổ phách",
26
+ };
27
+
28
+ export function piagentThemeFiles(dir = THEMES_DIR) {
29
+ try { return fs.readdirSync(dir).filter((name) => name.endsWith(".json")).sort().map((name) => path.join(dir, name)); }
30
+ catch { return []; }
31
+ }
32
+
33
+ // Piagent's themes loaded with the host's own loader, for a runtime that
34
+ // supplies its own resources (the company Terminal). One that does not load
35
+ // on this host is left out.
36
+ export async function loadPiagentThemes(sdkRoot, dir = THEMES_DIR) {
37
+ let loader;
38
+ try { loader = await import(pathToFileURL(path.join(sdkRoot, "dist", "modes", "interactive", "theme", "theme.js")).href); }
39
+ catch { return []; }
40
+ const themes = [];
41
+ for (const file of piagentThemeFiles(dir)) {
42
+ try { themes.push(loader.loadThemeFromPath(file)); } catch { /* another host's schema */ }
43
+ }
44
+ return themes;
45
+ }
46
+
47
+ const styleFile = (home) => path.join(home ?? os.homedir(), ".pi", STYLE_FILE);
48
+ export function readStyle(home) {
49
+ try { const name = JSON.parse(fs.readFileSync(styleFile(home), "utf8"))?.theme; return typeof name === "string" && name ? name : null; }
50
+ catch { return null; }
51
+ }
52
+ export function writeStyle(name, home) {
53
+ const file = styleFile(home);
54
+ fs.mkdirSync(path.dirname(file), { recursive: true });
55
+ fs.writeFileSync(file, `${JSON.stringify({ theme: name })}\n`, { mode: 0o600 });
56
+ }
57
+
58
+ // The styles to offer: Pi's built-ins and every loaded theme, each once.
59
+ export function styleChoices(ui) {
60
+ const names = [...new Set(["system", "dark", "light", ...(ui?.getAllThemes?.() ?? []).map((item) => item?.name).filter(Boolean)])];
61
+ return names.map((name) => ({ name, label: DESCRIPTIONS[name] ? `${name} — ${DESCRIPTIONS[name]}` : name }));
62
+ }
63
+
64
+ // remember: true where Pi does not keep the setting itself (company Terminal).
65
+ export function registerStyleCommand(pi, { remember = false, home } = {}) {
66
+ const apply = (ctx, name) => {
67
+ const result = ctx.ui.setTheme(name);
68
+ if (!result?.success) return result?.error ?? "unknown";
69
+ if (remember) writeStyle(name, home);
70
+ return null;
71
+ };
72
+ if (remember) {
73
+ pi.on("session_start", async (_event, ctx) => {
74
+ if (!ctx.hasUI || ctx.ui?.[GATEWAY_UI]) return;
75
+ const saved = readStyle(home);
76
+ if (saved && ctx.ui.theme?.name !== saved) ctx.ui.setTheme?.(saved);
77
+ });
78
+ }
79
+ pi.registerCommand("style", {
80
+ description: "Chọn giao diện (theme) của Terminal: /style để chọn trong danh sách, /style <tên> để đổi ngay",
81
+ getArgumentCompletions: (prefix) => {
82
+ const typed = String(prefix ?? "").trim();
83
+ return Object.keys(DESCRIPTIONS).filter((name) => name !== typed && name.startsWith(typed)).map((value) => ({ value, label: value }));
84
+ },
85
+ handler: async (args, ctx) => {
86
+ if (!ctx.hasUI || ctx.ui?.[GATEWAY_UI] || typeof ctx.ui?.setTheme !== "function") { ctx.ui?.notify?.("/style chỉ dùng trong Terminal.", "info"); return; }
87
+ const choices = styleChoices(ctx.ui), current = ctx.ui.theme?.name;
88
+ let name = String(args ?? "").trim();
89
+ if (!name) {
90
+ const picked = await ctx.ui.select(`Giao diện Terminal (đang: ${current ?? "system"})`, choices.map((item) => item.label));
91
+ if (!picked) return;
92
+ name = choices.find((item) => item.label === picked)?.name ?? picked;
93
+ }
94
+ if (!choices.some((item) => item.name === name)) { ctx.ui.notify(`Không có giao diện "${name}". Có: ${choices.map((item) => item.name).join(", ")}.`, "warning"); return; }
95
+ const error = apply(ctx, name);
96
+ ctx.ui.notify(error ? `Không đổi được giao diện: ${error}` : `Đã đổi giao diện sang ${name}.`, error ? "error" : "info");
97
+ },
98
+ });
99
+ }
@@ -0,0 +1,78 @@
1
+ {
2
+ "$schema": "https://pi.dev/schemas/theme.schema.json",
3
+ "name": "piagent-contrast",
4
+ "appearance": "dark",
5
+ "vars": {
6
+ "text": "okhsl(0 0% 98%)",
7
+ "muted": "okhsl(230 8% 80%)",
8
+ "violet": "okhsl(295 80% 75%)",
9
+ "blue": "okhsl(220 85% 75%)",
10
+ "green": "okhsl(150 85% 72%)",
11
+ "red": "okhsl(20 95% 70%)",
12
+ "yellow": "okhsl(85 100% 75%)",
13
+ "blueBg": "okhsl(230 60% 20%)"
14
+ },
15
+ "colors": {
16
+ "accent": "violet",
17
+ "border": "okhsl(231 66% 71%)",
18
+ "borderAccent": "okhsl(295 61% 70%)",
19
+ "borderMuted": "okhsl(229 9% 59%)",
20
+ "success": "green",
21
+ "error": "red",
22
+ "warning": "yellow",
23
+ "muted": "muted",
24
+ "dim": "okhsl(229 9% 62%)",
25
+ "text": "text",
26
+ "thinkingText": "okhsl(226 8% 71%)",
27
+ "selectedBg": "blueBg",
28
+ "scrollbarTrack": "okhsl(237 8% 39%)",
29
+ "scrollbarThumb": "okhsl(232 8% 71%)",
30
+ "searchMatchBg": "okhsl(53 59% 30%)",
31
+ "searchMatchText": "muted",
32
+ "userMessageBg": "blueBg",
33
+ "userMessageText": "text",
34
+ "customMessageBg": "okhsl(295 48% 30%)",
35
+ "customMessageText": "muted",
36
+ "customMessageLabel": "violet",
37
+ "toolPendingBg": "okhsl(229 6% 30%)",
38
+ "toolSuccessBg": "okhsl(158 53% 31%)",
39
+ "toolErrorBg": "okhsl(19 62% 31%)",
40
+ "toolTitle": "text",
41
+ "toolOutput": "muted",
42
+ "mdHeading": "yellow",
43
+ "mdLink": "blue",
44
+ "mdLinkUrl": "muted",
45
+ "mdCode": "violet",
46
+ "mdCodeBlock": "green",
47
+ "mdCodeBlockBorder": "muted",
48
+ "mdQuote": "muted",
49
+ "mdQuoteBorder": "muted",
50
+ "mdHr": "muted",
51
+ "mdListBullet": "violet",
52
+ "toolDiffAdded": "green",
53
+ "toolDiffRemoved": "red",
54
+ "toolDiffContext": "muted",
55
+ "syntaxComment": "muted",
56
+ "syntaxKeyword": "blue",
57
+ "syntaxFunction": "yellow",
58
+ "syntaxVariable": "okhsl(202 67% 73%)",
59
+ "syntaxString": "okhsl(52 77% 73%)",
60
+ "syntaxNumber": "green",
61
+ "syntaxType": "violet",
62
+ "syntaxOperator": "muted",
63
+ "syntaxPunctuation": "muted",
64
+ "thinkingOff": "okhsl(229 9% 55%)",
65
+ "thinkingMinimal": "okhsl(232 23% 58%)",
66
+ "thinkingLow": "okhsl(232 52% 60%)",
67
+ "thinkingMedium": "okhsl(263 68% 62%)",
68
+ "thinkingHigh": "okhsl(295 84% 65%)",
69
+ "thinkingXhigh": "okhsl(337 93% 67%)",
70
+ "thinkingMax": "okhsl(20 100% 69%)",
71
+ "bashMode": "okhsl(159 74% 71%)"
72
+ },
73
+ "export": {
74
+ "pageBg": "okhsl(262 16% 22%)",
75
+ "cardBg": "okhsl(264 15% 25%)",
76
+ "infoBg": "okhsl(53 59% 30%)"
77
+ }
78
+ }