@piagent/platform 1.45.0 → 1.46.0
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 +19 -0
- package/README.md +5 -3
- package/README.vi.md +5 -3
- package/docs/command-reference-vietnamese.md +2 -2
- package/docs/distribution-standard.md +6 -6
- package/docs/languages.json +2 -2
- package/docs/operator-manual-vietnamese.md +7 -7
- package/docs/publishing-for-teams.md +1 -0
- package/docs/release-install-policy.md +2 -2
- package/docs/team-onboarding.md +2 -2
- package/docs-site/architecture.html +1 -1
- package/docs-site/assets/search-en.json +1 -1
- package/docs-site/assets/search-vi.json +1 -1
- package/docs-site/benchmark.html +1 -1
- package/docs-site/commands.html +1 -1
- package/docs-site/context-engine.html +1 -1
- package/docs-site/ecosystem.html +1 -1
- package/docs-site/en/architecture.html +1 -1
- package/docs-site/en/benchmark.html +1 -1
- package/docs-site/en/commands.html +1 -1
- package/docs-site/en/context-engine.html +1 -1
- package/docs-site/en/ecosystem.html +1 -1
- package/docs-site/en/index.html +9 -9
- package/docs-site/en/mcp-approval.html +1 -1
- package/docs-site/en/mcp-auth.html +1 -1
- package/docs-site/en/mcp-servers.html +1 -1
- package/docs-site/en/mcp.html +1 -1
- package/docs-site/en/permissions.html +1 -1
- package/docs-site/en/profiles.html +1 -1
- package/docs-site/en/quickstart.html +1 -1
- package/docs-site/en/runtime.html +1 -1
- package/docs-site/en/scope.html +1 -1
- package/docs-site/en/security.html +1 -1
- package/docs-site/en/team.html +1 -1
- package/docs-site/en/update.html +3 -3
- package/docs-site/en/whats-new.html +31 -19
- package/docs-site/en/windows.html +1 -1
- package/docs-site/en/workflows.html +1 -1
- package/docs-site/index.html +9 -9
- package/docs-site/mcp-approval.html +1 -1
- package/docs-site/mcp-auth.html +1 -1
- package/docs-site/mcp-servers.html +1 -1
- package/docs-site/mcp.html +1 -1
- package/docs-site/permissions.html +1 -1
- package/docs-site/profiles.html +1 -1
- package/docs-site/quickstart.html +1 -1
- package/docs-site/releases.json +39 -0
- package/docs-site/runtime.html +1 -1
- package/docs-site/scope.html +1 -1
- package/docs-site/security.html +1 -1
- package/docs-site/team.html +1 -1
- package/docs-site/update.html +3 -3
- package/docs-site/whats-new.html +31 -19
- package/docs-site/windows.html +1 -1
- package/docs-site/workflows.html +1 -1
- package/evals/private-holdout-v1/public-exposure.v2.json +2 -2
- package/package.json +1 -1
- package/packages/piagent-core/benchmark/benchmark-bootstrap.js +3 -1
- package/packages/piagent-core/extensions/agent-home.d.ts +4 -0
- package/packages/piagent-core/extensions/agent-home.js +52 -0
- package/packages/piagent-core/extensions/piagent-guard.ts +5 -1
- package/packages/piagent-core/mcp/mcp-config-layers.js +4 -1
- package/packages/piagent-core/package.json +1 -1
- package/packages/piagent-webui/extension/piagent-webui.ts +2 -0
- package/packages/piagent-webui/gateway/gateway-service.ts +4 -1
- package/packages/piagent-webui/gateway/pi-host.ts +2 -2
- package/packages/piagent-webui/ownership/profile-state.ts +10 -1
- package/packages/piagent-webui/server/benchmark-release-monitor.ts +2 -1
- package/scripts/benchmark-runner-support.mjs +2 -1
- package/scripts/dashboard-update-job.mjs +4 -2
- package/scripts/install-global.sh +113 -5
- package/scripts/model-scope-prune.mjs +2 -1
- package/scripts/personal-pi-config.mjs +2 -1
- package/scripts/personal-pi-restore.mjs +184 -0
- package/scripts/pi-usage-history.mjs +2 -1
- package/scripts/piagent-cli.mjs +49 -9
- package/scripts/piagent-dashboard.mjs +5 -3
- package/scripts/setup.sh +2 -6
- package/scripts/team-doctor.sh +11 -5
- package/scripts/uninstall-global.sh +17 -2
- package/scripts/update-global.mjs +5 -2
package/docs-site/whats-new.html
CHANGED
|
@@ -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.
|
|
40
|
+
<a class="version-badge" href="/whats-new" data-docs-version="v1.46.0" title="v1.46.0 docs · VI"><span class="dot"></span>v1.46.0</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,21 @@
|
|
|
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-
|
|
111
|
+
<article class="release latest" id="v1-46-0" data-release>
|
|
112
|
+
<div class="release-meta"><a class="release-version" href="#v1-46-0">v1.46.0</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-46-0-title">Piagent chạy trong Pi home riêng, pi của bạn giữ nguyên bản gốc</h3>
|
|
115
|
+
<p>Piagent cài vào ~/.piagent/agent và mở bằng <code>piagent</code>. <code>pi</code> thường không còn nạp Piagent, add-on, danh sách model hay panel footer.</p>
|
|
116
|
+
<ul class="release-items">
|
|
117
|
+
<li data-kind="breaking"><span class="kind kind-breaking">Thay đổi lớn</span><span>Piagent cài vào Pi home riêng ~/.piagent/agent và mở bằng <code>piagent</code>. <code>pi</code> thường trong ~/.pi/agent giữ nguyên bản gốc.</span></li>
|
|
118
|
+
<li data-kind="new"><span class="kind kind-new">Mới</span><span>Lần cài đầu trong terminal hỏi cài add-on nào và có dùng lại login của pi không; cờ dòng lệnh trả lời trước được.</span></li>
|
|
119
|
+
<li data-kind="new"><span class="kind kind-new">Mới</span><span><code>piagent restore-pi --apply</code> dời bản cài cũ khỏi ~/.pi/agent, có sao lưu; installer tự làm khi cập nhật.</span></li>
|
|
120
|
+
<li data-kind="fixed"><span class="kind kind-fixed">Sửa lỗi</span><span>Khi cài pi-mcp-adapter, Piagent tắt mcp có sẵn của Pi trong home của mình nên /mcp không còn xung đột.</span></li>
|
|
121
|
+
</ul>
|
|
122
|
+
<p class="release-requires"><strong>Cần:</strong> Agent Watch 0.15.16 để thấy session cá nhân của Piagent</p>
|
|
123
|
+
</div>
|
|
124
|
+
</article>
|
|
125
|
+
<article class="release" id="v1-45-0" data-release>
|
|
112
126
|
<div class="release-meta"><a class="release-version" href="#v1-45-0">v1.45.0</a><time class="release-date" datetime="2026-10-28">28/10/2026</time></div>
|
|
113
127
|
<div class="release-body">
|
|
114
128
|
<h3 data-toc-skip id="v1-45-0-title">File và ảnh trong prompt theo đúng quyền đọc, terminal không còn đứng hình</h3>
|
|
@@ -407,28 +421,26 @@
|
|
|
407
421
|
</ul>
|
|
408
422
|
</div>
|
|
409
423
|
</article>
|
|
410
|
-
<article class="release" id="v1-38-0" data-release>
|
|
411
|
-
<div class="release-meta"><a class="release-version" href="#v1-38-0">v1.38.0</a><time class="release-date" datetime="2026-10-23">23/10/2026</time></div>
|
|
412
|
-
<div class="release-body">
|
|
413
|
-
<h3 data-toc-skip id="v1-38-0-title">Piagent thành editor, Bypass không hỏi gì <span class="tag">không phát hành</span></h3>
|
|
414
|
-
<p>Dashboard có file, terminal, review inline và checkpoint, cùng chế độ Bypass không hỏi gì, cả trong cuộc trò chuyện công ty khi Harness cho phép.</p>
|
|
415
|
-
<ul class="release-items">
|
|
416
|
-
<li data-kind="breaking"><span class="kind kind-breaking">Thay đổi lớn</span><span>Cuộc trò chuyện công ty có Hỏi trước, Toàn quyền (trước đây gọi là Bypass) và Bypass, chỉ có khi Harness cho phép.</span></li>
|
|
417
|
-
<li data-kind="new"><span class="kind kind-new">Mới</span><span>Chế độ <code>bypass</code> (<code>/permission bypass</code>, <code>piagent-auto --bypass</code>) tắt mọi bước chặn; output vẫn được che secret và <code>/undo</code> vẫn hoàn tác được.</span></li>
|
|
418
|
-
<li data-kind="new"><span class="kind kind-new">Mới</span><span>Dashboard mở, sửa, lưu, đổi tên và xóa file của project, có Cmd/Ctrl+P, tìm kiếm và báo xung đột khi file đã đổi trên đĩa.</span></li>
|
|
419
|
-
<li data-kind="new"><span class="kind kind-new">Mới</span><span>Terminal của project ngay trên dashboard; terminal của cuộc trò chuyện công ty chạy trong sandbox, cả trên macOS, không bao giờ chạy trên host.</span></li>
|
|
420
|
-
<li data-kind="new"><span class="kind kind-new">Mới</span><span>Review inline từng hunk agent sửa với Giữ và Hoàn tác, và khôi phục trong Timeline có xem trước, dùng chung checkpoint với <code>/undo</code>.</span></li>
|
|
421
|
-
<li data-kind="fixed"><span class="kind kind-fixed">Sửa lỗi</span><span>Checkpoint không tạo được từng chặn mọi lần sửa; giờ thì không, và snapshot mất khoảng 0,5 s thay vì 35 s trên repo 4.000 file.</span></li>
|
|
422
|
-
</ul>
|
|
423
|
-
<p class="release-requires"><strong>Cần:</strong> Agent Studio 0.38.0 và Agent Watch 0.15.14 (Windows 0.1.17) cho mức Bypass ở chế độ công ty</p>
|
|
424
|
-
</div>
|
|
425
|
-
</article>
|
|
426
424
|
</section>
|
|
427
425
|
<section class="section archive">
|
|
428
426
|
<h2 id="archive">Các bản trước</h2>
|
|
429
427
|
<p class="section-lead">Bản cũ hơn, gom theo tháng. Mở một tháng để xem từng thay đổi.</p>
|
|
430
428
|
<details class="release-archive">
|
|
431
|
-
<summary><span>Tháng 10/2026</span><span class="archive-count">
|
|
429
|
+
<summary><span>Tháng 10/2026</span><span class="archive-count">57</span></summary>
|
|
430
|
+
<div class="archive-row" id="v1-38-0">
|
|
431
|
+
<div class="archive-head"><a class="release-version" href="#v1-38-0">v1.38.0</a> <span class="release-date">23/10/2026</span></div>
|
|
432
|
+
<div class="archive-body">
|
|
433
|
+
<p><strong>Piagent thành editor, Bypass không hỏi gì</strong> <span class="tag">không phát hành</span> — Dashboard có file, terminal, review inline và checkpoint, cùng chế độ Bypass không hỏi gì, cả trong cuộc trò chuyện công ty khi Harness cho phép.</p>
|
|
434
|
+
<ul class="release-items">
|
|
435
|
+
<li data-kind="breaking"><span class="kind kind-breaking">Thay đổi lớn</span><span>Cuộc trò chuyện công ty có Hỏi trước, Toàn quyền (trước đây gọi là Bypass) và Bypass, chỉ có khi Harness cho phép.</span></li>
|
|
436
|
+
<li data-kind="new"><span class="kind kind-new">Mới</span><span>Chế độ <code>bypass</code> (<code>/permission bypass</code>, <code>piagent-auto --bypass</code>) tắt mọi bước chặn; output vẫn được che secret và <code>/undo</code> vẫn hoàn tác được.</span></li>
|
|
437
|
+
<li data-kind="new"><span class="kind kind-new">Mới</span><span>Dashboard mở, sửa, lưu, đổi tên và xóa file của project, có Cmd/Ctrl+P, tìm kiếm và báo xung đột khi file đã đổi trên đĩa.</span></li>
|
|
438
|
+
<li data-kind="new"><span class="kind kind-new">Mới</span><span>Terminal của project ngay trên dashboard; terminal của cuộc trò chuyện công ty chạy trong sandbox, cả trên macOS, không bao giờ chạy trên host.</span></li>
|
|
439
|
+
<li data-kind="new"><span class="kind kind-new">Mới</span><span>Review inline từng hunk agent sửa với Giữ và Hoàn tác, và khôi phục trong Timeline có xem trước, dùng chung checkpoint với <code>/undo</code>.</span></li>
|
|
440
|
+
<li data-kind="fixed"><span class="kind kind-fixed">Sửa lỗi</span><span>Checkpoint không tạo được từng chặn mọi lần sửa; giờ thì không, và snapshot mất khoảng 0,5 s thay vì 35 s trên repo 4.000 file.</span></li>
|
|
441
|
+
</ul>
|
|
442
|
+
</div>
|
|
443
|
+
</div>
|
|
432
444
|
<div class="archive-row" id="v1-37-1">
|
|
433
445
|
<div class="archive-head"><a class="release-version" href="#v1-37-1">v1.37.1</a> <span class="release-date">22/10/2026</span></div>
|
|
434
446
|
<div class="archive-body">
|
package/docs-site/windows.html
CHANGED
|
@@ -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.
|
|
40
|
+
<a class="version-badge" href="/whats-new" data-docs-version="v1.46.0" title="v1.46.0 docs · VI"><span class="dot"></span>v1.46.0</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>
|
package/docs-site/workflows.html
CHANGED
|
@@ -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.
|
|
40
|
+
<a class="version-badge" href="/whats-new" data-docs-version="v1.46.0" title="v1.46.0 docs · VI"><span class="dot"></span>v1.46.0</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":
|
|
260
|
-
"sha256": "
|
|
259
|
+
"fileCount": 635,
|
|
260
|
+
"sha256": "e192ed7528a5d5a992cd33c3837ee6f779b404e45cedc06f79978e2bfa9272eb"
|
|
261
261
|
}
|
|
262
262
|
],
|
|
263
263
|
"custodianComparisonRules": {
|
package/package.json
CHANGED
|
@@ -494,7 +494,9 @@ function requestedPiProvider(model, configRoot, credentials) {
|
|
|
494
494
|
}
|
|
495
495
|
|
|
496
496
|
function snapshotPiAgentHome(temporaryRoot, runtimeParent, argv, cwd, replay, { providerFreeFinalization = false } = {}) {
|
|
497
|
-
|
|
497
|
+
// Piagent's own Pi home holds the login benchmarks borrow (see extensions/agent-home.js).
|
|
498
|
+
const personal = path.resolve(os.homedir(), ".pi", "agent"), configured = process.env.PI_CODING_AGENT_DIR;
|
|
499
|
+
const sourceRoot = path.resolve(process.env.PIAGENT_AGENT_DIR || (configured && path.resolve(configured) !== personal ? configured : path.join(os.homedir(), ".piagent", "agent")));
|
|
498
500
|
const configRoot = path.join(temporaryRoot, "pi-agent-config");
|
|
499
501
|
fs.mkdirSync(configRoot, { recursive: true, mode: 0o700 });
|
|
500
502
|
const copied = [];
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export function personalPiAgentDir(home?: string): string;
|
|
2
|
+
export function piagentAgentDir(env?: NodeJS.ProcessEnv, home?: string): string;
|
|
3
|
+
export function agentWatchControlDir(home?: string): string;
|
|
4
|
+
export function dormantInPersonalPi(env?: NodeJS.ProcessEnv, home?: string, argv?: string[]): boolean;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import os from "node:os";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
|
|
5
|
+
// Piagent runs Pi from its own home (~/.piagent/agent) so the member's
|
|
6
|
+
// personal `pi` stays the stock host: no Piagent package, add-ons, model scope
|
|
7
|
+
// or footer panel lands in ~/.pi/agent. Agent Watch still reads its control
|
|
8
|
+
// files (runtime record, managed binding, status) from ~/.pi/agent, so those
|
|
9
|
+
// stay where Watch looks; Pi itself ignores them.
|
|
10
|
+
|
|
11
|
+
/** The stock Pi home, the member's personal `pi`. */
|
|
12
|
+
export function personalPiAgentDir(home = os.homedir()) {
|
|
13
|
+
return path.resolve(home, ".pi", "agent");
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Where Piagent's Pi keeps settings, packages, login and sessions. An explicit
|
|
18
|
+
* PIAGENT_AGENT_DIR wins; a PI_CODING_AGENT_DIR that points anywhere but the
|
|
19
|
+
* personal home is honoured (tests, benchmarks, custom setups); otherwise
|
|
20
|
+
* ~/.piagent/agent.
|
|
21
|
+
*/
|
|
22
|
+
export function piagentAgentDir(env = process.env, home = os.homedir()) {
|
|
23
|
+
const own = env.PIAGENT_AGENT_DIR?.trim();
|
|
24
|
+
if (own) return path.resolve(own);
|
|
25
|
+
const configured = env.PI_CODING_AGENT_DIR?.trim();
|
|
26
|
+
if (configured && path.resolve(configured) !== personalPiAgentDir(home)) return path.resolve(configured);
|
|
27
|
+
return path.resolve(home, ".piagent", "agent");
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/** Agent Watch's files: the runtime record, the managed binding and status. */
|
|
31
|
+
export function agentWatchControlDir(home = os.homedir()) {
|
|
32
|
+
return personalPiAgentDir(home);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function realpath(file) {
|
|
36
|
+
try { return fs.realpathSync(file); } catch { return path.resolve(file); }
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* True when this process is the stock `pi` command running from the personal
|
|
41
|
+
* home: Piagent was registered there by an older release or a project's
|
|
42
|
+
* .pi/settings.json, and it stays out of the member's way. Hosts that embed Pi
|
|
43
|
+
* (studio, dashboard gateway, benchmarks) and `piagent` itself are never
|
|
44
|
+
* dormant; PIAGENT_ACTIVE=1 opts a personal `pi` back in.
|
|
45
|
+
*/
|
|
46
|
+
export function dormantInPersonalPi(env = process.env, home = os.homedir(), argv = process.argv) {
|
|
47
|
+
if (env.PIAGENT_ACTIVE === "1") return false;
|
|
48
|
+
const configured = env.PI_CODING_AGENT_DIR?.trim();
|
|
49
|
+
if (configured && path.resolve(configured) !== personalPiAgentDir(home)) return false;
|
|
50
|
+
const entry = argv[1] ? realpath(argv[1]) : "";
|
|
51
|
+
return /[\\/]@earendil-works[\\/]pi-coding-agent[\\/]/.test(entry);
|
|
52
|
+
}
|
|
@@ -37,6 +37,7 @@ import {
|
|
|
37
37
|
} from "./redaction-core.js";
|
|
38
38
|
import { detectProfileName } from "./project-shape.js";
|
|
39
39
|
import { evaluateUpdateCheck, isInstalledPlatform, readUpdateCache, startUpdateProbe } from "./update-check.js";
|
|
40
|
+
import { dormantInPersonalPi, personalPiAgentDir } from "./agent-home.js";
|
|
40
41
|
import {
|
|
41
42
|
REPOSITORY_SCOPES,
|
|
42
43
|
collectServers,
|
|
@@ -366,7 +367,7 @@ const PLATFORM_ROOT = findPlatformRoot(path.dirname(fileURLToPath(import.meta.ur
|
|
|
366
367
|
// package's and the user's (also those kept for other coding agents, such as
|
|
367
368
|
// ~/.claude/skills). Reading them is allowed; writes stay in the project.
|
|
368
369
|
const SKILL_READ_ROOTS = [path.join(PLATFORM_ROOT, "packages", "piagent-core", "skills"),
|
|
369
|
-
path.join(process.env.PI_CODING_AGENT_DIR ||
|
|
370
|
+
path.join(process.env.PI_CODING_AGENT_DIR || personalPiAgentDir(), "skills"), path.join(personalPiAgentDir(), "skills"), ...userSkillFolders()]
|
|
370
371
|
.flatMap((root) => { try { return [fs.realpathSync.native(root)]; } catch { return []; } });
|
|
371
372
|
const UPDATE_CHECK_MODULE = fileURLToPath(new URL("./update-check.js", import.meta.url));
|
|
372
373
|
// The installed version, read from the package this file ships in. A maintainer
|
|
@@ -3452,6 +3453,9 @@ function activeSessionTask(_cwd: string, _sessionId: string): TaskContract | und
|
|
|
3452
3453
|
const noTask = (..._args: unknown[]): undefined => undefined;
|
|
3453
3454
|
|
|
3454
3455
|
export default function piagentGuard(pi: ExtensionAPI) {
|
|
3456
|
+
// The member's own `pi` stays stock even when an older install or a project
|
|
3457
|
+
// still registers this package there; Piagent runs through `piagent`.
|
|
3458
|
+
if (dormantInPersonalPi()) return;
|
|
3455
3459
|
const extensionDir = path.dirname(fileURLToPath(import.meta.url));
|
|
3456
3460
|
const policy = loadPolicy(extensionDir);
|
|
3457
3461
|
const bashResults = createBashResultLedger({ maxEntries: 300 });
|
|
@@ -44,7 +44,10 @@ export function configPathForScope(scope, options = {}) {
|
|
|
44
44
|
case "global":
|
|
45
45
|
return path.join(env.XDG_CONFIG_HOME || path.join(home, ".config"), "mcp", "mcp.json");
|
|
46
46
|
case "pi-global":
|
|
47
|
-
|
|
47
|
+
// Piagent's own Pi home, not the member's personal pi (see extensions/agent-home.js).
|
|
48
|
+
if (env.PIAGENT_AGENT_DIR) return path.join(env.PIAGENT_AGENT_DIR, "mcp.json");
|
|
49
|
+
if (env.PI_CODING_AGENT_DIR && path.resolve(env.PI_CODING_AGENT_DIR) !== path.resolve(home, ".pi", "agent")) return path.join(env.PI_CODING_AGENT_DIR, "mcp.json");
|
|
50
|
+
return path.join(home, ".piagent", "agent", "mcp.json");
|
|
48
51
|
case "project":
|
|
49
52
|
return path.join(projectPath, ".mcp.json");
|
|
50
53
|
case "pi-project":
|
|
@@ -34,6 +34,7 @@ import { VSCodeHandoff } from "./vscode-handoff.ts";
|
|
|
34
34
|
import { browserCommand } from "../../piagent-core/runtime/host/browser-opener.mjs";
|
|
35
35
|
import { TerminalSessionAdapter } from "./terminal-session-adapter.ts";
|
|
36
36
|
import { isGatewayRuntimeContext } from "../ownership/gateway-runtime-context.ts";
|
|
37
|
+
import { dormantInPersonalPi } from "../../piagent-core/extensions/agent-home.js";
|
|
37
38
|
|
|
38
39
|
const PACKAGE_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
|
|
39
40
|
const PLATFORM_ROOT = path.resolve(PACKAGE_ROOT, "../..");
|
|
@@ -183,6 +184,7 @@ function readMethod(provider: CoreInspectionProvider, queue: HeldMessageQueue, s
|
|
|
183
184
|
}
|
|
184
185
|
|
|
185
186
|
export default function piagentWebUiExtension(pi: ExtensionAPI): void {
|
|
187
|
+
if (dormantInPersonalPi()) return;
|
|
186
188
|
const runtimeInstanceId = createWebUiExtensionRuntimeInstanceRef();
|
|
187
189
|
let terminalAdapter: TerminalSessionAdapter | null = null;
|
|
188
190
|
const managers = new Map<string, Manager>();
|
|
@@ -53,6 +53,7 @@ import { CompanyRelay, type CompanyConnector } from "./company-relay.ts";
|
|
|
53
53
|
import { ProviderAuthBroker } from "./provider-auth-broker.ts";
|
|
54
54
|
import { McpAuthBroker } from "./mcp-auth-broker.ts";
|
|
55
55
|
import { AgentStatusFiles } from "./agent-status-files.ts";
|
|
56
|
+
import { agentWatchControlDir, piagentAgentDir } from "../../piagent-core/extensions/agent-home.js";
|
|
56
57
|
import type { ScopedBrokerRouter, RuntimeFactory } from "./session-runtime-factory.ts";
|
|
57
58
|
import { UiPreferencesStore } from "./ui-preferences-store.ts";
|
|
58
59
|
|
|
@@ -249,7 +250,9 @@ export async function startPiagentGateway(options: {
|
|
|
249
250
|
// Agent Watch reads the member's ~/.pi/agent/status. The dashboard's
|
|
250
251
|
// agentDir is that folder; the company Gateway's is its private session
|
|
251
252
|
// folder under Agent Watch, so it writes to the member's folder instead.
|
|
252
|
-
|
|
253
|
+
// Piagent's own home serves the member's dashboard; a test or benchmark home keeps its status beside it.
|
|
254
|
+
const watchRoot = options.managed || state.agentDir === piagentAgentDir() ? agentWatchControlDir() : state.agentDir;
|
|
255
|
+
statusFiles = new AgentStatusFiles(path.join(watchRoot, "status", options.managed ? "company" : "dashboard"), async () => { const catalog = await readCatalog(); if (catalog.state !== "ready") throw new Error("catalog-not-ready"); return catalog; }, () => Boolean(options.managed)); statusFiles.start();
|
|
253
256
|
const projectFolder = async (projectRef: string) => projects.resolve(projectRef)
|
|
254
257
|
?? (await runtimes!.listSessions()).find((info) => typeof info.cwd === "string" && projectRefForCwd(key, info.cwd) === projectRef)?.cwd
|
|
255
258
|
?? (relay ? (await relay.folders()).find((folder) => projectRefForCwd(key, folder) === projectRef) : undefined);
|
|
@@ -5,6 +5,7 @@ import path from "node:path";
|
|
|
5
5
|
import { createRequire } from "node:module";
|
|
6
6
|
import { pathToFileURL } from "node:url";
|
|
7
7
|
import { privateHostRoot } from "../../piagent-core/managed/pi-host.mjs";
|
|
8
|
+
import { agentWatchControlDir } from "../../piagent-core/extensions/agent-home.js";
|
|
8
9
|
|
|
9
10
|
const require = createRequire(import.meta.url);
|
|
10
11
|
|
|
@@ -58,8 +59,7 @@ export function installedPiHostRoot(): string {
|
|
|
58
59
|
const home = os.homedir(), hostPackage = path.join("lib", "node_modules", "@earendil-works", "pi-coding-agent");
|
|
59
60
|
let recorded: string | null = null;
|
|
60
61
|
try {
|
|
61
|
-
|
|
62
|
-
recorded = JSON.parse(fs.readFileSync(path.join(agentDir, "piagent-runtime.json"), "utf8")).pi_sdk_root ?? null;
|
|
62
|
+
recorded = JSON.parse(fs.readFileSync(path.join(agentWatchControlDir(home), "piagent-runtime.json"), "utf8")).pi_sdk_root ?? null;
|
|
63
63
|
} catch { /* no record yet */ }
|
|
64
64
|
// npm's default Windows prefixes (%APPDATA%\npm, or beside node.exe) have no lib folder.
|
|
65
65
|
const appData = process.env.APPDATA ?? path.join(home, "AppData", "Roaming");
|
|
@@ -47,8 +47,17 @@ function shortControlSocket(agentDir: string): string {
|
|
|
47
47
|
return path.join(socketRoot, `${digest}.sock`);
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
+
// Piagent's own Pi home (~/.piagent/agent), never the member's personal pi.
|
|
51
|
+
// Same rule as piagent-core/extensions/agent-home.js, which this layer cannot import.
|
|
52
|
+
function defaultAgentDir(): string {
|
|
53
|
+
const own = process.env.PIAGENT_AGENT_DIR?.trim(), configured = process.env.PI_CODING_AGENT_DIR?.trim();
|
|
54
|
+
if (own) return own;
|
|
55
|
+
if (configured && path.resolve(configured) !== path.resolve(os.homedir(), ".pi", "agent")) return configured;
|
|
56
|
+
return path.join(os.homedir(), ".piagent", "agent");
|
|
57
|
+
}
|
|
58
|
+
|
|
50
59
|
export function gatewayProfileState(agentDirInput?: string): GatewayProfileState {
|
|
51
|
-
const agentDir = path.resolve(agentDirInput ||
|
|
60
|
+
const agentDir = path.resolve(agentDirInput || defaultAgentDir());
|
|
52
61
|
fs.mkdirSync(agentDir, { recursive: true, mode: 0o700 });
|
|
53
62
|
const agentStat = fs.lstatSync(agentDir);
|
|
54
63
|
if (!agentStat.isDirectory() || agentStat.isSymbolicLink()
|
|
@@ -10,6 +10,7 @@ import { assertBenchmarkLedgerBinding, inspectBenchmarkLedger, validateBenchmark
|
|
|
10
10
|
import { completedBenchmarkRecord } from "../../piagent-core/benchmark/benchmark-record-validation.js";
|
|
11
11
|
import { benchmarkGitEnvironment } from "../../piagent-core/benchmark/benchmark-runtime.js";
|
|
12
12
|
import { redactSensitiveText } from "../../piagent-core/extensions/redaction-core.js";
|
|
13
|
+
import { piagentAgentDir } from "../../piagent-core/extensions/agent-home.js";
|
|
13
14
|
|
|
14
15
|
const MAX_RUNS = 20, MAX_DIRECTORIES = 100, MAX_DIRECTORY_ENTRIES = 5_000, MAX_JSON_BYTES = 32 * 1024 * 1024;
|
|
15
16
|
type Identity = { projectRef: string; runtimeInstanceId: string; sessionRef: string; taskId: string | null; taskRunId: string | null;
|
|
@@ -210,7 +211,7 @@ function releaseReadiness(cwd: string, file: string, repo: ReturnType<typeof rep
|
|
|
210
211
|
export function projectBenchmarkReleaseMonitor(input: { cwd: string; identity: Identity; generatedAt?: string; benchmarkRoot?: string; releaseReportPath?: string }) {
|
|
211
212
|
const generatedAt = input.generatedAt ?? new Date().toISOString();
|
|
212
213
|
try {
|
|
213
|
-
const repo = repository(input.cwd), root = input.benchmarkRoot ?? path.join(
|
|
214
|
+
const repo = repository(input.cwd), root = input.benchmarkRoot ?? path.join(piagentAgentDir(), "benchmarks", "piagent");
|
|
214
215
|
const releasePath = input.releaseReportPath ?? path.join(input.cwd, "plans", "codex-first-product", "evidence", "p7-local-readiness", "report.json");
|
|
215
216
|
const benchmark = benchmarkRuns(input.cwd, root, repo), release = releaseReadiness(input.cwd, releasePath, repo);
|
|
216
217
|
const revision = `release-monitor.${createHash("sha256").update(JSON.stringify({ benchmark, release })).digest("hex")}`;
|
|
@@ -14,6 +14,7 @@ import { acquireBenchmarkRunLock } from "../packages/piagent-core/benchmark/benc
|
|
|
14
14
|
import { recoverBenchmarkObservationCheckpoints } from "../packages/piagent-core/benchmark/benchmark-resume-recovery.js";
|
|
15
15
|
import { benchmarkSurfaceLabel } from "../packages/piagent-core/benchmark/benchmark-core.js";
|
|
16
16
|
import { codexModelName, codexThinkingEffort } from "../packages/piagent-core/benchmark/benchmark-codex.js";
|
|
17
|
+
import { piagentAgentDir } from "../packages/piagent-core/extensions/agent-home.js";
|
|
17
18
|
|
|
18
19
|
export function fail(message, code = 2) {
|
|
19
20
|
const error = new Error(message);
|
|
@@ -96,7 +97,7 @@ export function registeredBenchmarkCustodyRoot(runRoot) {
|
|
|
96
97
|
|
|
97
98
|
export function defaultOutputRoot(bootstrapMetadata) {
|
|
98
99
|
if (bootstrapMetadata?.defaultOutputRoot) return bootstrapMetadata.defaultOutputRoot;
|
|
99
|
-
const agentRoot =
|
|
100
|
+
const agentRoot = piagentAgentDir();
|
|
100
101
|
return path.join(agentRoot, "benchmarks", "piagent");
|
|
101
102
|
}
|
|
102
103
|
|
|
@@ -59,8 +59,10 @@ if (installed !== to) finish("failed", { reason: "update-version-mismatch", ...(
|
|
|
59
59
|
// the launcher needs the binding imported again in Agent Watch.
|
|
60
60
|
let bindingChanged = false;
|
|
61
61
|
try {
|
|
62
|
-
|
|
63
|
-
const
|
|
62
|
+
// Agent Watch keeps the binding in the personal Pi folder; a test or custom home may hold its own.
|
|
63
|
+
const homes = [process.env.PI_CODING_AGENT_DIR?.trim(), path.join(home, ".pi", "agent")].filter(Boolean);
|
|
64
|
+
const file = homes.map((dir) => path.join(dir, "agent-watch-managed.json")).find((candidate) => fs.existsSync(candidate));
|
|
65
|
+
const binding = JSON.parse(fs.readFileSync(file, "utf8"));
|
|
64
66
|
if (typeof binding?.entrypoint === "string" && typeof binding?.entrypoint_sha256 === "string")
|
|
65
67
|
bindingChanged = crypto.createHash("sha256").update(fs.readFileSync(binding.entrypoint)).digest("hex") !== binding.entrypoint_sha256;
|
|
66
68
|
} catch { /* no company binding on this machine */ }
|
|
@@ -23,6 +23,9 @@ Options:
|
|
|
23
23
|
--with-web-access | --no-web-access
|
|
24
24
|
Install pi-web-access for the researcher subagent (default: install).
|
|
25
25
|
--with-herdr Also configure Herdr integration.
|
|
26
|
+
--copy-login | --no-copy-login Copy (or not) your personal pi login into Piagent's home.
|
|
27
|
+
Default: ask in a terminal; without one, copy only when
|
|
28
|
+
moving an older install out of your personal pi.
|
|
26
29
|
--model-scope <full|codex|claude>
|
|
27
30
|
Model families to enable in Pi (default: full). A member who
|
|
28
31
|
already has a default model and model list keeps them; an
|
|
@@ -36,7 +39,13 @@ Options:
|
|
|
36
39
|
-h, --help Print this help and exit.
|
|
37
40
|
|
|
38
41
|
Purpose:
|
|
39
|
-
Install
|
|
42
|
+
Install Piagent into its own Pi home (~/.piagent/agent; PIAGENT_AGENT_DIR overrides).
|
|
43
|
+
Your personal `pi` (~/.pi/agent) stays stock: open Piagent with `piagent`.
|
|
44
|
+
An install from an older release that lives in ~/.pi/agent is moved out of it.
|
|
45
|
+
|
|
46
|
+
Run in a terminal, a first install asks which add-ons to install and whether
|
|
47
|
+
to use your pi login; flags answer those questions up front, and a run
|
|
48
|
+
without a terminal (CI, the dashboard updater) takes the defaults.
|
|
40
49
|
|
|
41
50
|
Package source examples:
|
|
42
51
|
# Recommended stable install: exact current release tag
|
|
@@ -61,7 +70,8 @@ Package source examples:
|
|
|
61
70
|
Notes:
|
|
62
71
|
- `currentRelease` in output is the version of the terminal helper executing this command.
|
|
63
72
|
- Use exactly one package selector. The first CLI selector overrides environment defaults; a second selector fails closed.
|
|
64
|
-
- OAuth is intentionally not automated. Run `
|
|
73
|
+
- OAuth is intentionally not automated. Run `piagent` then `/login`, or let the
|
|
74
|
+
installer copy the login your personal pi already has.
|
|
65
75
|
- Model scope is configured with Pi's native `enabledModels` so users choose via `/model`, Ctrl+L, `/scoped-models`, and Ctrl+P.
|
|
66
76
|
- Herdr integration is optional and modifies user-level Herdr/Pi config.
|
|
67
77
|
- MCP is installed by default with the core preset: Context7 docs, Chrome DevTools, GitHub.
|
|
@@ -76,6 +86,21 @@ USAGE
|
|
|
76
86
|
}
|
|
77
87
|
|
|
78
88
|
PLATFORM_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
89
|
+
# Piagent's own Pi home (packages/piagent-core/extensions/agent-home.js has the
|
|
90
|
+
# same rule). Every `pi` call below works there, never in the personal home.
|
|
91
|
+
PERSONAL_PI_DIR="${HOME}/.pi/agent"
|
|
92
|
+
if [[ -n "${PIAGENT_AGENT_DIR:-}" ]]; then
|
|
93
|
+
PIAGENT_HOME="$PIAGENT_AGENT_DIR"
|
|
94
|
+
elif [[ -n "${PI_CODING_AGENT_DIR:-}" && "${PI_CODING_AGENT_DIR%/}" != "$PERSONAL_PI_DIR" ]]; then
|
|
95
|
+
PIAGENT_HOME="$PI_CODING_AGENT_DIR"
|
|
96
|
+
else
|
|
97
|
+
PIAGENT_HOME="${HOME}/.piagent/agent"
|
|
98
|
+
fi
|
|
99
|
+
export PI_CODING_AGENT_DIR="$PIAGENT_HOME"
|
|
100
|
+
MCP_EXPLICIT=false
|
|
101
|
+
WEB_ACCESS_EXPLICIT=false
|
|
102
|
+
MODEL_SCOPE_EXPLICIT=false
|
|
103
|
+
COPY_LOGIN=""
|
|
79
104
|
CURRENT_RELEASE_TAG=""
|
|
80
105
|
EXPECTED_PI_VERSION=""
|
|
81
106
|
EXPECTED_RELEASE_COMMIT="${PIAGENT_EXPECTED_RELEASE_COMMIT:-}"
|
|
@@ -486,10 +511,12 @@ while [[ $# -gt 0 ]]; do
|
|
|
486
511
|
;;
|
|
487
512
|
--with-mcp)
|
|
488
513
|
WITH_MCP=true
|
|
514
|
+
MCP_EXPLICIT=true
|
|
489
515
|
shift
|
|
490
516
|
;;
|
|
491
517
|
--no-mcp)
|
|
492
518
|
WITH_MCP=false
|
|
519
|
+
MCP_EXPLICIT=true
|
|
493
520
|
shift
|
|
494
521
|
;;
|
|
495
522
|
--mcp-preset)
|
|
@@ -520,10 +547,12 @@ while [[ $# -gt 0 ]]; do
|
|
|
520
547
|
;;
|
|
521
548
|
--with-web-access)
|
|
522
549
|
WITH_WEB_ACCESS=true
|
|
550
|
+
WEB_ACCESS_EXPLICIT=true
|
|
523
551
|
shift
|
|
524
552
|
;;
|
|
525
553
|
--no-web-access)
|
|
526
554
|
WITH_WEB_ACCESS=false
|
|
555
|
+
WEB_ACCESS_EXPLICIT=true
|
|
527
556
|
shift
|
|
528
557
|
;;
|
|
529
558
|
--with-herdr)
|
|
@@ -533,6 +562,7 @@ while [[ $# -gt 0 ]]; do
|
|
|
533
562
|
--model-scope)
|
|
534
563
|
require_value "$1" "${2:-}"
|
|
535
564
|
MODEL_SCOPE_PRESET="$2"
|
|
565
|
+
MODEL_SCOPE_EXPLICIT=true
|
|
536
566
|
shift 2
|
|
537
567
|
;;
|
|
538
568
|
--default-model)
|
|
@@ -546,6 +576,15 @@ while [[ $# -gt 0 ]]; do
|
|
|
546
576
|
;;
|
|
547
577
|
--no-model-scope)
|
|
548
578
|
CONFIGURE_MODEL_SCOPE=false
|
|
579
|
+
MODEL_SCOPE_EXPLICIT=true
|
|
580
|
+
shift
|
|
581
|
+
;;
|
|
582
|
+
--copy-login)
|
|
583
|
+
COPY_LOGIN=true
|
|
584
|
+
shift
|
|
585
|
+
;;
|
|
586
|
+
--no-copy-login)
|
|
587
|
+
COPY_LOGIN=false
|
|
549
588
|
shift
|
|
550
589
|
;;
|
|
551
590
|
-h|--help)
|
|
@@ -569,6 +608,54 @@ fi
|
|
|
569
608
|
|
|
570
609
|
require_node_version
|
|
571
610
|
|
|
611
|
+
# What personal Pi holds from an older Piagent release (packages, login).
|
|
612
|
+
LEGACY_REPORT="$(node "$PLATFORM_ROOT/scripts/personal-pi-restore.mjs" --json 2>/dev/null || echo '{}')"
|
|
613
|
+
legacy_field() {
|
|
614
|
+
node -e 'const r = JSON.parse(process.argv[1] || "{}"); const v = process.argv[2].split(".").reduce((o, k) => o?.[k], r); process.stdout.write(Array.isArray(v) ? v.join("\n") : String(v ?? ""));' "$LEGACY_REPORT" "$1"
|
|
615
|
+
}
|
|
616
|
+
LEGACY_INSTALL="$(legacy_field legacy)"
|
|
617
|
+
LEGACY_SUBAGENTS=false
|
|
618
|
+
if legacy_field remove | grep -q '^npm:pi-subagents@'; then LEGACY_SUBAGENTS=true; fi
|
|
619
|
+
FIRST_INSTALL=true
|
|
620
|
+
if [[ -f "$PIAGENT_HOME/settings.json" ]] && grep -qE '@piagent/platform|Vt-mmm/piagent' "$PIAGENT_HOME/settings.json" 2>/dev/null; then
|
|
621
|
+
FIRST_INSTALL=false
|
|
622
|
+
fi
|
|
623
|
+
|
|
624
|
+
# Ask, rather than decide for the member, what goes into Piagent's home: only on
|
|
625
|
+
# a first install (an update keeps what is there), only in a terminal, and never
|
|
626
|
+
# for a question a flag already answered.
|
|
627
|
+
ask_yes_no() {
|
|
628
|
+
local question="$1" default="$2" answer hint="[Y/n]"
|
|
629
|
+
[[ "$default" == false ]] && hint="[y/N]"
|
|
630
|
+
read -r -p "$question $hint " answer </dev/tty || answer=""
|
|
631
|
+
case "$answer" in
|
|
632
|
+
[Yy]*) echo true ;;
|
|
633
|
+
[Nn]*) echo false ;;
|
|
634
|
+
*) echo "$default" ;;
|
|
635
|
+
esac
|
|
636
|
+
}
|
|
637
|
+
if [[ "$FIRST_INSTALL" == true && "$DRY_RUN" == false && -t 0 && -t 1 && -z "${PIAGENT_INSTALL_DEFAULTS:-}" ]]; then
|
|
638
|
+
echo "Piagent installs into its own Pi home: $PIAGENT_HOME"
|
|
639
|
+
echo "Your personal pi ($PERSONAL_PI_DIR) is not changed by these choices."
|
|
640
|
+
[[ "$MCP_EXPLICIT" == true ]] || WITH_MCP="$(ask_yes_no "Install the MCP adapter (pi-mcp-adapter, servers: $MCP_PRESET)?" "$WITH_MCP")"
|
|
641
|
+
if [[ "$SUBAGENTS_EXPLICIT" == false ]]; then
|
|
642
|
+
WITH_SUBAGENTS="$(ask_yes_no "Install pi-subagents (optional parallel helpers; company sessions use their own)?" "$LEGACY_SUBAGENTS")"
|
|
643
|
+
SUBAGENTS_EXPLICIT=true
|
|
644
|
+
fi
|
|
645
|
+
[[ "$WEB_ACCESS_EXPLICIT" == true ]] || WITH_WEB_ACCESS="$(ask_yes_no "Install pi-web-access (web search and fetch for the researcher subagent)?" "$WITH_WEB_ACCESS")"
|
|
646
|
+
[[ "$MODEL_SCOPE_EXPLICIT" == true ]] || CONFIGURE_MODEL_SCOPE="$(ask_yes_no "Set Piagent's model list and default model ($DEFAULT_MODEL)?" "$CONFIGURE_MODEL_SCOPE")"
|
|
647
|
+
if [[ -z "$COPY_LOGIN" && "$(legacy_field loginAvailable)" == true ]]; then
|
|
648
|
+
COPY_LOGIN="$(ask_yes_no "Use the login your personal pi already has (copies auth.json once)?" true)"
|
|
649
|
+
fi
|
|
650
|
+
echo
|
|
651
|
+
fi
|
|
652
|
+
if [[ -z "$COPY_LOGIN" ]]; then
|
|
653
|
+
COPY_LOGIN="$LEGACY_INSTALL"
|
|
654
|
+
fi
|
|
655
|
+
if [[ "$LEGACY_SUBAGENTS" == true && "$SUBAGENTS_EXPLICIT" == false ]]; then
|
|
656
|
+
WITH_SUBAGENTS=true
|
|
657
|
+
fi
|
|
658
|
+
|
|
572
659
|
# The preset is only read at the very last step, after the platform package and
|
|
573
660
|
# the MCP adapter are already installed. A name with a typo therefore failed
|
|
574
661
|
# after two installs had landed, leaving a half-configured machine, and the
|
|
@@ -736,10 +823,25 @@ if [[ -n "$RESOLVED_PACKAGE_COMMIT" ]]; then
|
|
|
736
823
|
fi
|
|
737
824
|
echo " source: $PACKAGE_SOURCE"
|
|
738
825
|
sync_local_helper
|
|
826
|
+
echo " home: $PIAGENT_HOME (your personal pi stays in $PERSONAL_PI_DIR)"
|
|
827
|
+
run_cmd mkdir -p "$PIAGENT_HOME"
|
|
739
828
|
echo "Removing previous Pi Agent Platform package registrations:"
|
|
740
829
|
remove_existing_piagent_platform_sources
|
|
741
830
|
run_cmd pi install "$PACKAGE_SOURCE"
|
|
742
831
|
|
|
832
|
+
# An older release installed Piagent into personal Pi. Move it out: carry the
|
|
833
|
+
# member's model choices (and the login, when agreed) to Piagent's home, then
|
|
834
|
+
# leave personal Pi stock. Backups of every changed file stay beside it.
|
|
835
|
+
if [[ "$LEGACY_INSTALL" == true ]]; then
|
|
836
|
+
echo "Moving the older Piagent install out of your personal pi:"
|
|
837
|
+
restore_args=("$PLATFORM_ROOT/scripts/personal-pi-restore.mjs" --apply)
|
|
838
|
+
[[ "$COPY_LOGIN" == true ]] && restore_args+=(--copy-login)
|
|
839
|
+
run_cmd node "${restore_args[@]}"
|
|
840
|
+
elif [[ "$COPY_LOGIN" == true && "$(legacy_field loginAvailable)" == true ]]; then
|
|
841
|
+
echo "Copying your pi login to Piagent's home:"
|
|
842
|
+
run_cmd node -e 'const fs = require("node:fs"); fs.copyFileSync(process.argv[1], process.argv[2], fs.constants.COPYFILE_EXCL); fs.chmodSync(process.argv[2], 0o600);' "$PERSONAL_PI_DIR/auth.json" "$PIAGENT_HOME/auth.json"
|
|
843
|
+
fi
|
|
844
|
+
|
|
743
845
|
if [[ "$WITH_MCP" == true ]]; then
|
|
744
846
|
echo "Installing Pi MCP adapter:"
|
|
745
847
|
if [[ "$DRY_RUN" == false ]]; then
|
|
@@ -747,6 +849,9 @@ if [[ "$WITH_MCP" == true ]]; then
|
|
|
747
849
|
fi
|
|
748
850
|
remove_existing_npm_package_sources "pi-mcp-adapter"
|
|
749
851
|
run_cmd pi install "$PI_MCP_ADAPTER_SOURCE"
|
|
852
|
+
# Pi's built-in `mcp` extension registers the same /mcp command as the
|
|
853
|
+
# adapter; Piagent's home turns the built-in off so only one loads.
|
|
854
|
+
run_cmd node -e 'const fs = require("node:fs"); const f = process.argv[1]; const s = JSON.parse(fs.readFileSync(f, "utf8")); const e = Array.isArray(s.extensions) ? s.extensions : []; if (!e.includes("-builtin:mcp")) { s.extensions = [...e, "-builtin:mcp"]; fs.writeFileSync(f, JSON.stringify(s, null, 2) + "\n"); }' "$PIAGENT_HOME/settings.json"
|
|
750
855
|
if [[ "$DRY_RUN" == false ]] && command -v pi-mcp-adapter >/dev/null 2>&1; then
|
|
751
856
|
pi-mcp-adapter init || true
|
|
752
857
|
fi
|
|
@@ -802,10 +907,13 @@ if [[ "$DRY_RUN" == true ]]; then
|
|
|
802
907
|
print_cmd node "$PLATFORM_ROOT/scripts/personal-pi-config.mjs" repair
|
|
803
908
|
else
|
|
804
909
|
node "$PLATFORM_ROOT/scripts/personal-pi-config.mjs" repair || echo "WARN: could not check the personal Pi configuration; run: node \"$PLATFORM_ROOT/scripts/personal-pi-config.mjs\" check" >&2
|
|
910
|
+
node "$PLATFORM_ROOT/scripts/personal-pi-config.mjs" repair --agent-dir "$PIAGENT_HOME" >/dev/null || true
|
|
805
911
|
fi
|
|
806
912
|
|
|
807
913
|
echo
|
|
808
|
-
echo "
|
|
914
|
+
echo "Open Piagent with: piagent (your own pi in $PERSONAL_PI_DIR stays stock)"
|
|
915
|
+
echo
|
|
916
|
+
echo "Installed packages in $PIAGENT_HOME:"
|
|
809
917
|
if [[ "$DRY_RUN" == true ]]; then
|
|
810
918
|
print_cmd pi list
|
|
811
919
|
else
|
|
@@ -814,8 +922,8 @@ fi
|
|
|
814
922
|
|
|
815
923
|
echo
|
|
816
924
|
echo "Next:"
|
|
817
|
-
echo " pi"
|
|
818
|
-
echo " /login"
|
|
925
|
+
echo " piagent # Piagent in this terminal; plain \`pi\` stays your own"
|
|
926
|
+
echo " /login # unless the login of your pi was copied"
|
|
819
927
|
echo " /model # or Ctrl+L: select provider/model from Pi selector"
|
|
820
928
|
echo " /scoped-models # optional: edit Ctrl+P model cycle scope"
|
|
821
929
|
if [[ "$WITH_MCP" == true ]]; then
|
|
@@ -10,6 +10,7 @@ import fs from "node:fs";
|
|
|
10
10
|
import path from "node:path";
|
|
11
11
|
import { execFileSync } from "node:child_process";
|
|
12
12
|
import { pathToFileURL } from "node:url";
|
|
13
|
+
import { piagentAgentDir } from "../packages/piagent-core/extensions/agent-home.js";
|
|
13
14
|
|
|
14
15
|
// The Pi install `pi` runs from.
|
|
15
16
|
export function piPackageRoot(environment = process.env) {
|
|
@@ -55,7 +56,7 @@ export function pruneSettings(settingsPath, stale) {
|
|
|
55
56
|
|
|
56
57
|
if (process.argv[1] && path.resolve(process.argv[1]) === path.resolve(new URL(import.meta.url).pathname)) {
|
|
57
58
|
const args = process.argv.slice(2), at = args.indexOf("--settings");
|
|
58
|
-
const agentDir = process.env
|
|
59
|
+
const agentDir = piagentAgentDir(process.env, process.env.HOME ?? "");
|
|
59
60
|
const settingsPath = at >= 0 && args[at + 1] ? path.resolve(args[at + 1]) : path.join(agentDir, "settings.json");
|
|
60
61
|
const json = args.includes("--json"), fix = args.includes("--fix");
|
|
61
62
|
const out = (value, text) => process.stdout.write(json ? `${JSON.stringify(value)}\n` : `${text}\n`);
|
|
@@ -120,7 +120,8 @@ const invoked = process.argv[1] && real(process.argv[1]) === real(fileURLToPath(
|
|
|
120
120
|
if (invoked) {
|
|
121
121
|
const args = process.argv.slice(2), command = args[0];
|
|
122
122
|
const at = args.indexOf("--agent-dir");
|
|
123
|
-
|
|
123
|
+
// The member's personal pi, whatever home Piagent itself runs from.
|
|
124
|
+
const agentDir = at >= 0 ? path.resolve(args[at + 1]) : path.join(os.homedir(), ".pi", "agent");
|
|
124
125
|
if (!["check", "repair"].includes(command)) { console.error("Usage: personal-pi-config.mjs check|repair [--agent-dir <dir>] [--json]"); process.exit(2); }
|
|
125
126
|
const result = command === "repair" ? repair(agentDir) : inspect(agentDir);
|
|
126
127
|
if (args.includes("--json")) console.log(JSON.stringify(result, null, 2));
|