@piagent/platform 1.43.9 → 1.44.2

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 (82) hide show
  1. package/CHANGELOG.md +45 -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/harness-conformance.md +14 -0
  6. package/docs/operator-manual-vietnamese.md +7 -7
  7. package/docs/publishing-for-teams.md +3 -0
  8. package/docs/release-install-policy.md +4 -2
  9. package/docs/team-onboarding.md +2 -2
  10. package/docs-site/architecture.html +1 -1
  11. package/docs-site/assets/search-en.json +1 -1
  12. package/docs-site/assets/search-vi.json +1 -1
  13. package/docs-site/benchmark.html +1 -1
  14. package/docs-site/commands.html +1 -1
  15. package/docs-site/context-engine.html +1 -1
  16. package/docs-site/ecosystem.html +1 -1
  17. package/docs-site/en/architecture.html +1 -1
  18. package/docs-site/en/benchmark.html +1 -1
  19. package/docs-site/en/commands.html +1 -1
  20. package/docs-site/en/context-engine.html +1 -1
  21. package/docs-site/en/ecosystem.html +1 -1
  22. package/docs-site/en/index.html +15 -15
  23. package/docs-site/en/mcp-approval.html +1 -1
  24. package/docs-site/en/mcp-auth.html +1 -1
  25. package/docs-site/en/mcp-servers.html +1 -1
  26. package/docs-site/en/mcp.html +1 -1
  27. package/docs-site/en/permissions.html +1 -1
  28. package/docs-site/en/profiles.html +1 -1
  29. package/docs-site/en/quickstart.html +1 -1
  30. package/docs-site/en/runtime.html +1 -1
  31. package/docs-site/en/scope.html +1 -1
  32. package/docs-site/en/security.html +1 -1
  33. package/docs-site/en/team.html +1 -1
  34. package/docs-site/en/update.html +3 -3
  35. package/docs-site/en/whats-new.html +79 -45
  36. package/docs-site/en/windows.html +1 -1
  37. package/docs-site/en/workflows.html +1 -1
  38. package/docs-site/index.html +15 -15
  39. package/docs-site/mcp-approval.html +1 -1
  40. package/docs-site/mcp-auth.html +1 -1
  41. package/docs-site/mcp-servers.html +1 -1
  42. package/docs-site/mcp.html +1 -1
  43. package/docs-site/permissions.html +1 -1
  44. package/docs-site/profiles.html +1 -1
  45. package/docs-site/quickstart.html +1 -1
  46. package/docs-site/releases.json +108 -0
  47. package/docs-site/runtime.html +1 -1
  48. package/docs-site/scope.html +1 -1
  49. package/docs-site/security.html +1 -1
  50. package/docs-site/team.html +1 -1
  51. package/docs-site/update.html +3 -3
  52. package/docs-site/whats-new.html +79 -45
  53. package/docs-site/windows.html +1 -1
  54. package/docs-site/workflows.html +1 -1
  55. package/evals/private-holdout-v1/public-exposure.v2.json +2 -2
  56. package/package.json +4 -1
  57. package/packages/piagent-core/extensions/piagent-guard.ts +3 -0
  58. package/packages/piagent-core/managed/helper-roles.mjs +24 -6
  59. package/packages/piagent-core/managed/pi-host.mjs +60 -1
  60. package/packages/piagent-core/managed/resource-loader.mjs +3 -2
  61. package/packages/piagent-core/managed/risk-lanes.mjs +38 -0
  62. package/packages/piagent-core/managed/session.mjs +6 -5
  63. package/packages/piagent-core/managed/workflow.mjs +24 -4
  64. package/packages/piagent-core/package.json +1 -1
  65. package/packages/piagent-core/runtime/resources/plugin-skills.mjs +33 -4
  66. package/packages/piagent-core/runtime/terminal/terminal-style.d.mts +7 -0
  67. package/packages/piagent-core/runtime/terminal/terminal-style.mjs +99 -0
  68. package/packages/piagent-core/themes/piagent-contrast.json +78 -0
  69. package/packages/piagent-core/themes/piagent-focus.json +78 -0
  70. package/packages/piagent-core/themes/piagent-ocean.json +78 -0
  71. package/packages/piagent-core/themes/piagent-paper.json +78 -0
  72. package/packages/piagent-webui/gateway/pi-host.ts +13 -1
  73. package/scripts/company-terminal.mjs +6 -2
  74. package/scripts/install-global.sh +13 -1
  75. package/scripts/pi-host.mjs +109 -0
  76. package/scripts/piagent-cli.mjs +17 -6
  77. package/scripts/piagent-dashboard.mjs +2 -2
  78. package/scripts/runtime-advisory-exceptions.json +40 -0
  79. package/scripts/setup.sh +19 -1
  80. package/scripts/skill-sources.mjs +188 -0
  81. package/scripts/uninstall-global.sh +18 -1
  82. package/scripts/update-global.mjs +13 -5
@@ -1,4 +1,112 @@
1
1
  [
2
+ {
3
+ "version": "1.44.2",
4
+ "date": "2026-10-28",
5
+ "status": "stable",
6
+ "title": {
7
+ "en": "The company harness follows the size of a change",
8
+ "vi": "Harness công ty theo cỡ thay đổi"
9
+ },
10
+ "summary": {
11
+ "en": "A small change ends after its checks without a review; a risky one has its checks and review required. The main agent may keep a few quick web lookups beside the research helper.",
12
+ "vi": "Thay đổi nhỏ xong sau khi check, không cần review; thay đổi rủi ro bắt buộc check và review. Main agent được tra web nhanh vài lần bên cạnh research helper."
13
+ },
14
+ "items": [
15
+ {
16
+ "kind": "improved",
17
+ "en": "Risk lanes, on by default: a change of at most 2 files and 40 lines that touches no sensitive file ends after its checks, without the reviewer. workflow.lanes: false turns them off.",
18
+ "vi": "Risk lanes, bật mặc định: thay đổi tối đa 2 file, 40 dòng, không chạm file nhạy cảm xong sau khi check, không gọi reviewer. workflow.lanes: false để tắt."
19
+ },
20
+ {
21
+ "kind": "improved",
22
+ "en": "A risky change (migration, auth, CI, dependency or AGENTS.md file, a complex request, over 12 files or 400 lines) must pass its checks and review even where they are only suggested.",
23
+ "vi": "Thay đổi rủi ro (migration, auth, CI, dependency, AGENTS.md, yêu cầu phức tạp, hơn 12 file hoặc 400 dòng) bắt buộc qua check và review kể cả khi Harness chỉ đặt suggest."
24
+ },
25
+ {
26
+ "kind": "new",
27
+ "en": "workflow.main_web_lookups (0 to 5) lets the main agent make that many quick web_search or web_fetch calls per message beside the research helper.",
28
+ "vi": "workflow.main_web_lookups (0 đến 5) cho main agent tra web_search hoặc web_fetch nhanh chừng ấy lần mỗi tin nhắn, bên cạnh research helper."
29
+ }
30
+ ],
31
+ "requires": null
32
+ },
33
+ {
34
+ "version": "1.44.1",
35
+ "date": "2026-10-28",
36
+ "status": "stable",
37
+ "title": {
38
+ "en": "Your own Pi stays, pick a Terminal style, add skill repositories",
39
+ "vi": "Giữ Pi của bạn, chọn giao diện Terminal, thêm repo skill"
40
+ },
41
+ "summary": {
42
+ "en": "A member who runs a newer Pi keeps it while Piagent runs its own pinned copy; /style picks the Terminal's look; piagent skills add brings in skill repositories such as mattpocock/skills.",
43
+ "vi": "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."
44
+ },
45
+ "items": [
46
+ {
47
+ "kind": "fixed",
48
+ "en": "Setup, install and update no longer replace a member's newer pi (such as 1.4.0) with the pinned 1.3.0: Piagent keeps its own copy in ~/.piagent/pi-host for company sessions, the dashboard and piagent pi.",
49
+ "vi": "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."
50
+ },
51
+ {
52
+ "kind": "fixed",
53
+ "en": "piagent-uninstall --with-host removes Piagent's private Pi and leaves a member's own newer pi in place.",
54
+ "vi": "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."
55
+ },
56
+ {
57
+ "kind": "new",
58
+ "en": "/style picks the Terminal's look: Pi's system, dark and light, or Piagent's ocean, paper, contrast and focus. The company Terminal remembers the pick.",
59
+ "vi": "/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."
60
+ },
61
+ {
62
+ "kind": "new",
63
+ "en": "piagent skills add mattpocock/skills adds a GitHub skill repository at one commit; its skills work as /skill:name in Pi, the company Terminal and the dashboard.",
64
+ "vi": "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."
65
+ },
66
+ {
67
+ "kind": "security",
68
+ "en": "Five undici advisories published on 2026-10-27 are accepted until 2026-11-07: undici 8.10.2 is pinned by every Pi host and fixed in 8.12.2.",
69
+ "vi": "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."
70
+ }
71
+ ],
72
+ "requires": null
73
+ },
74
+ {
75
+ "version": "1.44.0",
76
+ "date": "2026-10-28",
77
+ "status": "unpublished",
78
+ "title": {
79
+ "en": "Your own Pi stays, pick a Terminal style, add skill repositories",
80
+ "vi": "Giữ Pi của bạn, chọn giao diện Terminal, thêm repo skill"
81
+ },
82
+ "summary": {
83
+ "en": "Tagged but not published: new undici advisories in the Pi host stopped the runtime audit. Superseded by 1.44.1.",
84
+ "vi": "Đã 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."
85
+ },
86
+ "items": [
87
+ {
88
+ "kind": "fixed",
89
+ "en": "Setup, install and update no longer replace a member's newer pi (such as 1.4.0) with the pinned 1.3.0: Piagent keeps its own copy in ~/.piagent/pi-host for company sessions, the dashboard and piagent pi.",
90
+ "vi": "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."
91
+ },
92
+ {
93
+ "kind": "fixed",
94
+ "en": "piagent-uninstall --with-host removes Piagent's private Pi and leaves a member's own newer pi in place.",
95
+ "vi": "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."
96
+ },
97
+ {
98
+ "kind": "new",
99
+ "en": "/style picks the Terminal's look: Pi's system, dark and light, or Piagent's ocean, paper, contrast and focus. The company Terminal remembers the pick.",
100
+ "vi": "/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."
101
+ },
102
+ {
103
+ "kind": "new",
104
+ "en": "piagent skills add mattpocock/skills adds a GitHub skill repository at one commit; its skills work as /skill:name in Pi, the company Terminal and the dashboard.",
105
+ "vi": "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."
106
+ }
107
+ ],
108
+ "requires": null
109
+ },
2
110
  {
3
111
  "version": "1.43.9",
4
112
  "date": "2026-10-27",
@@ -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.2" title="v1.44.2 docs · VI"><span class="dot"></span>v1.44.2</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.2" title="v1.44.2 docs · VI"><span class="dot"></span>v1.44.2</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.2" title="v1.44.2 docs · VI"><span class="dot"></span>v1.44.2</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.2" title="v1.44.2 docs · VI"><span class="dot"></span>v1.44.2</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.2" title="v1.44.2 docs · VI"><span class="dot"></span>v1.44.2</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.2&#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.2
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.2" title="v1.44.2 docs · VI"><span class="dot"></span>v1.44.2</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,46 @@
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-2" data-release>
112
+ <div class="release-meta"><a class="release-version" href="#v1-44-2">v1.44.2</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-2-title">Harness công ty theo cỡ thay đổi</h3>
115
+ <p>Thay đổi nhỏ xong sau khi check, không cần review; thay đổi rủi ro bắt buộc check và review. Main agent được tra web nhanh vài lần bên cạnh research helper.</p>
116
+ <ul class="release-items">
117
+ <li data-kind="new"><span class="kind kind-new">Mới</span><span>workflow.main_web_lookups (0 đến 5) cho main agent tra web_search hoặc web_fetch nhanh chừng ấy lần mỗi tin nhắn, bên cạnh research helper.</span></li>
118
+ <li data-kind="improved"><span class="kind kind-improved">Cải thiện</span><span>Risk lanes, bật mặc định: thay đổi tối đa 2 file, 40 dòng, không chạm file nhạy cảm xong sau khi check, không gọi reviewer. workflow.lanes: false để tắt.</span></li>
119
+ <li data-kind="improved"><span class="kind kind-improved">Cải thiện</span><span>Thay đổi rủi ro (migration, auth, CI, dependency, AGENTS.md, yêu cầu phức tạp, hơn 12 file hoặc 400 dòng) bắt buộc qua check và review kể cả khi Harness chỉ đặt suggest.</span></li>
120
+ </ul>
121
+ </div>
122
+ </article>
123
+ <article class="release" id="v1-44-1" data-release>
124
+ <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>
125
+ <div class="release-body">
126
+ <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>
127
+ <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>
128
+ <ul class="release-items">
129
+ <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>
130
+ <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>
131
+ <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>
132
+ <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>
133
+ <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>
134
+ </ul>
135
+ </div>
136
+ </article>
137
+ <article class="release" id="v1-44-0" data-release>
138
+ <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>
139
+ <div class="release-body">
140
+ <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>
141
+ <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>
142
+ <ul class="release-items">
143
+ <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>
144
+ <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>
145
+ <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>
146
+ <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>
147
+ </ul>
148
+ </div>
149
+ </article>
150
+ <article class="release" id="v1-43-9" data-release>
112
151
  <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
152
  <div class="release-body">
114
153
  <h3 data-toc-skip id="v1-43-9-title">Đủ skill đã cài, và mở file agent gửi lại</h3>
@@ -388,54 +427,49 @@
388
427
  </ul>
389
428
  </div>
390
429
  </article>
391
- <article class="release" id="v1-36-0" data-release>
392
- <div class="release-meta"><a class="release-version" href="#v1-36-0">v1.36.0</a><time class="release-date" datetime="2026-10-21">21/10/2026</time></div>
393
- <div class="release-body">
394
- <h3 data-toc-skip id="v1-36-0-title">Team memory học từ chỗ làm sai</h3>
395
- <p>Memory học từ phản hồi của member và lỗi lặp lại, chỉ giữ task hoàn thành có thêm điều mới, và đề xuất xem lại skill hay lỗi.</p>
396
- <ul class="release-items">
397
- <li data-kind="new"><span class="kind kind-new">Mới</span><span>Những gì memory đưa cho một lượt được gửi lại Studio, để Studio chấm theo câu tiếp theo của member và thôi đưa ghi chú bị nói là sai.</span></li>
398
- <li data-kind="new"><span class="kind kind-new">Mới</span><span>Lệnh lỗi giống nhau hai lần trong một lượt thành bài học, giữ dòng lỗi đầu tiên và không đoán nguyên nhân.</span></li>
399
- <li data-kind="new"><span class="kind kind-new">Mới</span><span>Khi 3 lượt gần nhất của một skill bị lỗi, Piagent ghi đề xuất vào <code>.pi/piagent-state/skill-proposals/</code>, tối đa mỗi tuần; không tự sửa skill.</span></li>
400
- <li data-kind="improved"><span class="kind kind-improved">Cải thiện</span><span>Memory của repo bỏ qua task chỉ đổi build output, cache, log hay trạng thái của Piagent, hoặc lặp lại file đã biết.</span></li>
401
- </ul>
402
- <p class="release-requires"><strong>Cần:</strong> Agent Studio 0.37.0</p>
403
- </div>
404
- </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
430
  </section>
434
431
  <section class="section archive">
435
432
  <h2 id="archive">Các bản trước</h2>
436
433
  <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
434
  <details class="release-archive">
438
- <summary><span>Tháng 10/2026</span><span class="archive-count">50</span></summary>
435
+ <summary><span>Tháng 10/2026</span><span class="archive-count">53</span></summary>
436
+ <div class="archive-row" id="v1-36-0">
437
+ <div class="archive-head"><a class="release-version" href="#v1-36-0">v1.36.0</a> <span class="release-date">21/10/2026</span></div>
438
+ <div class="archive-body">
439
+ <p><strong>Team memory học từ chỗ làm sai</strong> — Memory học từ phản hồi của member và lỗi lặp lại, chỉ giữ task hoàn thành có thêm điều mới, và đề xuất xem lại skill hay lỗi.</p>
440
+ <ul class="release-items">
441
+ <li data-kind="new"><span class="kind kind-new">Mới</span><span>Những gì memory đưa cho một lượt được gửi lại Studio, để Studio chấm theo câu tiếp theo của member và thôi đưa ghi chú bị nói là sai.</span></li>
442
+ <li data-kind="new"><span class="kind kind-new">Mới</span><span>Lệnh lỗi giống nhau hai lần trong một lượt thành bài học, giữ dòng lỗi đầu tiên và không đoán nguyên nhân.</span></li>
443
+ <li data-kind="new"><span class="kind kind-new">Mới</span><span>Khi 3 lượt gần nhất của một skill bị lỗi, Piagent ghi đề xuất vào <code>.pi/piagent-state/skill-proposals/</code>, tối đa mỗi tuần; không tự sửa skill.</span></li>
444
+ <li data-kind="improved"><span class="kind kind-improved">Cải thiện</span><span>Memory của repo bỏ qua task chỉ đổi build output, cache, log hay trạng thái của Piagent, hoặc lặp lại file đã biết.</span></li>
445
+ </ul>
446
+ </div>
447
+ </div>
448
+ <div class="archive-row" id="v1-35-1">
449
+ <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>
450
+ <div class="archive-body">
451
+ <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>
452
+ <ul class="release-items">
453
+ <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>
454
+ <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>
455
+ <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>
456
+ <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>
457
+ </ul>
458
+ </div>
459
+ </div>
460
+ <div class="archive-row" id="v1-35-0">
461
+ <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>
462
+ <div class="archive-body">
463
+ <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>
464
+ <ul class="release-items">
465
+ <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>
466
+ <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>
467
+ <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>
468
+ <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>
469
+ <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>
470
+ </ul>
471
+ </div>
472
+ </div>
439
473
  <div class="archive-row" id="v1-34-3">
440
474
  <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
475
  <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.2" title="v1.44.2 docs · VI"><span class="dot"></span>v1.44.2</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.2" title="v1.44.2 docs · VI"><span class="dot"></span>v1.44.2</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": "fdb22c2a7f5b1639663494491cd1d61d5eaeb39969a833e61f3befedc66995f1"
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.2",
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
  }
@@ -12,12 +12,30 @@ export const HELPER_ROLES = Object.freeze(['scout', 'research', 'verify', 'revie
12
12
  export const helperRoles = manifest => HELPER_ROLES.filter(role => manifest?.harness?.configuration?.[role]);
13
13
  const WIDE_READING = 'when understanding the task needs more reading than a few batches of files, such as a flow across many modules of an unfamiliar codebase';
14
14
  const NETWORK_COMMANDS = 'run_with_network only when a command itself needs the internet or starts a local server or browser, such as end-to-end tests (the user approves each one)';
15
- // How the main agent reaches the web. With a research helper it has no web
16
- // tools: searching and reading pages happen on the helper's model.
17
- export function webPrompt(roles) {
18
- return roles.includes('research')
19
- ? ` Shell commands run without network and you have no web tools: hand anything on the web (current information, news, documentation, releases, error messages) to the research helper, and use ${NETWORK_COMMANDS}.`
20
- : ` Shell commands run without network: use web_search for current information or documentation, web_fetch to read a public https page, and ${NETWORK_COMMANDS}.`;
15
+ // With a research helper the main agent may still look one thing up itself:
16
+ // the Harness's workflow.main_web_lookups (0 to 5, default 0) web_search and
17
+ // web_fetch calls per member message. Anything wider is the helper's work.
18
+ export const MAIN_WEB_LOOKUPS_MAX = 5;
19
+ export function mainWebLookups(manifest) {
20
+ const n = manifest?.harness?.configuration?.workflow?.main_web_lookups;
21
+ return Number.isInteger(n) && n >= 0 && n <= MAIN_WEB_LOOKUPS_MAX ? n : 0;
22
+ }
23
+ // The main agent's web tools, counted against the current run's lookups.
24
+ export function limitedWebTools(tools, currentRun, limit) {
25
+ return tools.map(tool => ({ ...tool, execute: async (...args) => {
26
+ const run = currentRun();
27
+ if (run && ++run.webLookups > limit) throw Error(`managed-web-lookups-spent: you used your ${limit} quick web lookup(s) for this message. Hand the rest of the web work to the research helper (delegate role "research").`);
28
+ return tool.execute(...args);
29
+ } }));
30
+ }
31
+ // How the main agent reaches the web. With a research helper, searching and
32
+ // reading pages happen on the helper's model, beyond a few quick lookups.
33
+ export function webPrompt(roles, lookups = 0) {
34
+ if (!roles.includes('research'))
35
+ return ` Shell commands run without network: use web_search for current information or documentation, web_fetch to read a public https page, and ${NETWORK_COMMANDS}.`;
36
+ return lookups > 0
37
+ ? ` Shell commands run without network. For one quick fact (a version, a flag, one documentation page) use web_search or web_fetch yourself, at most ${lookups} call(s) per member message; hand anything wider on the web (several sources, comparisons, news, research) to the research helper, and use ${NETWORK_COMMANDS}.`
38
+ : ` Shell commands run without network and you have no web tools: hand anything on the web (current information, news, documentation, releases, error messages) to the research helper, and use ${NETWORK_COMMANDS}.`;
21
39
  }
22
40
  export function helperPrompt(roles) {
23
41
  const lines = [];
@@ -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,
@@ -0,0 +1,38 @@
1
+ // Risk lanes (the Harness's workflow.lanes, on unless Studio sets it false):
2
+ // the configured policy is the standard lane, sized on the patch the run made.
3
+ // A tiny change (few files and lines, nothing sensitive) ends after its
4
+ // checks, without a review; a risky one (a complex request, a sensitive file,
5
+ // a wide patch) has a suggested check and review required. "off" stays off.
6
+ export const LANE_LIMITS = Object.freeze({ tinyFiles: 2, tinyLines: 40, riskyFiles: 12, riskyLines: 400 });
7
+ const SENSITIVE = /(^|\/)(migrations?|auth|security|secrets?|permissions?|\.github|infra|terraform|helm|k8s)(\/|$)|(^|\/)(Dockerfile|docker-compose[^/]*|\.gitlab-ci\.yml|package\.json|package-lock\.json|pnpm-lock\.yaml|yarn\.lock|go\.mod|go\.sum|Cargo\.toml|Cargo\.lock|pyproject\.toml|uv\.lock|AGENTS\.md|\.env[^/]*)$|\.(sql|tf|pem|key)$/i;
8
+ export const sensitivePath = file => SENSITIVE.test(String(file ?? ''));
9
+ // Files and changed lines of a patch snapshot (readPatchSnapshot); null when
10
+ // it cannot be read. A new text file counts its lines, a binary one as one.
11
+ export function patchStats(snapshot) {
12
+ let value;
13
+ try { value = JSON.parse(snapshot?.patch); } catch { return null; }
14
+ if (!value || typeof value !== 'object') return null;
15
+ const paths = new Set(); let lines = 0;
16
+ for (const line of String(value.patch ?? '').split('\n')) {
17
+ if (line.startsWith('diff --git ')) paths.add(line.match(/^diff --git a\/(.+) b\/\1$/)?.[1] ?? line.slice(11));
18
+ else if (/^[+-]/.test(line) && !/^(\+\+\+|---) /.test(line)) lines += 1;
19
+ }
20
+ for (const file of Array.isArray(value.untracked) ? value.untracked : []) {
21
+ if (typeof file?.path !== 'string') continue;
22
+ paths.add(file.path); lines += file.encoding === 'utf8' ? String(file.contents ?? '').split('\n').filter((l, i, all) => l || i < all.length - 1).length : 1;
23
+ }
24
+ return { files: paths.size, lines, paths: [...paths] };
25
+ }
26
+ // An unreadable patch is standard: the configured policy applies.
27
+ export function changeLane(stats, { complex = false } = {}) {
28
+ if (!stats) return 'standard';
29
+ const L = LANE_LIMITS;
30
+ if (complex || stats.paths.some(sensitivePath) || stats.files > L.riskyFiles || stats.lines > L.riskyLines) return 'risky';
31
+ return stats.files <= L.tinyFiles && stats.lines <= L.tinyLines ? 'tiny' : 'standard';
32
+ }
33
+ export function lanePolicy(policy, lane) {
34
+ if (!policy.lanes || lane === 'standard') return policy;
35
+ if (lane === 'tiny') return { ...policy, review: 'off' };
36
+ const up = mode => mode === 'suggest' ? 'require' : mode;
37
+ return { ...policy, verify: up(policy.verify), review: up(policy.review) };
38
+ }