@piagent/platform 1.48.3 → 1.48.4
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 +10 -0
- package/docs/command-reference-vietnamese.md +2 -2
- package/docs/distribution-standard.md +6 -6
- 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 +26 -15
- 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 +31 -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 +26 -15
- package/docs-site/windows.html +1 -1
- package/docs-site/workflows.html +1 -1
- package/evals/private-holdout-v1/public-exposure.v2.json +1 -1
- package/package.json +1 -1
- package/packages/piagent-core/package.json +1 -1
- package/packages/piagent-core/runtime/update/terminal-reload.mjs +23 -13
- package/scripts/company-terminal.mjs +10 -5
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
//
|
|
3
3
|
// `piagent reload` (and `piagent-update` once it installed a release) writes
|
|
4
4
|
// one request file. Each Terminal started before that request takes it when it
|
|
5
|
-
// is idle: no run going, nothing queued, nothing typed in the editor
|
|
6
|
-
// progress is never cut: the footer says the reload
|
|
7
|
-
// the run
|
|
5
|
+
// is idle: no run going, nothing queued, nothing typed in the editor, and quiet
|
|
6
|
+
// for a moment. A run in progress is never cut: the footer says the reload
|
|
7
|
+
// waits, and it happens once the run has settled. How a Terminal reloads is its own: the personal Terminal
|
|
8
8
|
// runs Pi's /reload (Piagent's extensions are read again from disk), the
|
|
9
9
|
// company Terminal starts again in place on the same conversation, since its
|
|
10
10
|
// company code is loaded once per process.
|
|
@@ -14,7 +14,15 @@ import path from "node:path";
|
|
|
14
14
|
|
|
15
15
|
const REQUEST_FILE = "piagent-reload.json";
|
|
16
16
|
const POLL_MS = 2_000;
|
|
17
|
+
// A member who stops a run with Esc usually types the next message right away:
|
|
18
|
+
// a Terminal that starts again in that moment loses what they type.
|
|
19
|
+
const QUIET_MS = 10_000;
|
|
17
20
|
const STATUS_KEY = "piagent-reload";
|
|
21
|
+
// Per process, not per extension runtime: /reload runs this module again, and a
|
|
22
|
+
// request sent before it (the company Terminal's /reload loads no company code)
|
|
23
|
+
// must still be taken, while one already taken must not reload twice.
|
|
24
|
+
const APPLIED_AT = "PIAGENT_RELOAD_APPLIED_AT";
|
|
25
|
+
const processStartedAt = () => Date.now() - process.uptime() * 1000;
|
|
18
26
|
|
|
19
27
|
const requestPath = (home) => path.join(home ?? os.homedir(), ".pi", REQUEST_FILE);
|
|
20
28
|
|
|
@@ -47,8 +55,8 @@ function idle(ctx) {
|
|
|
47
55
|
|
|
48
56
|
// `apply(ctx, request)` reloads this Terminal; it runs at most once per
|
|
49
57
|
// process. Only Terminals with a UI take requests: scripted runs keep theirs.
|
|
50
|
-
export function watchTerminalReload(pi, { apply, home, startedAt =
|
|
51
|
-
let ctx = null, applied = false, waiting = false, timer = null;
|
|
58
|
+
export function watchTerminalReload(pi, { apply, home, startedAt = processStartedAt(), pollMs = POLL_MS, quietMs = QUIET_MS }) {
|
|
59
|
+
let ctx = null, applied = false, waiting = false, timer = null, busyAt = 0;
|
|
52
60
|
// A ctx kept from an earlier session (replaced, reloaded) throws on any use:
|
|
53
61
|
// a check that meets one does nothing, and the next session_start brings a new one.
|
|
54
62
|
const check = async () => {
|
|
@@ -56,17 +64,19 @@ export function watchTerminalReload(pi, { apply, home, startedAt = Date.now(), p
|
|
|
56
64
|
try {
|
|
57
65
|
if (applied || !ctx?.hasUI) return;
|
|
58
66
|
request = readReloadRequest(home);
|
|
59
|
-
if (!request || request.at <= startedAt) return;
|
|
60
|
-
|
|
61
|
-
|
|
67
|
+
if (!request || request.at <= Math.max(startedAt, Number(process.env[APPLIED_AT]) || 0)) return;
|
|
68
|
+
const quiet = idle(ctx);
|
|
69
|
+
if (!quiet) busyAt = Date.now();
|
|
70
|
+
if (!quiet || Date.now() - busyAt < quietMs) {
|
|
71
|
+
if (!waiting) { waiting = true; ctx.ui?.setStatus?.(STATUS_KEY, `⟳ Nạp Piagent${request.version ? ` ${request.version}` : " mới"} khi rảnh`); }
|
|
62
72
|
return;
|
|
63
73
|
}
|
|
64
|
-
applied = true;
|
|
74
|
+
applied = true; process.env[APPLIED_AT] = String(request.at);
|
|
65
75
|
ctx.ui?.setStatus?.(STATUS_KEY, undefined);
|
|
66
76
|
} catch { return; }
|
|
67
77
|
try { await apply(ctx, request); }
|
|
68
78
|
catch (error) {
|
|
69
|
-
applied = false;
|
|
79
|
+
applied = false; delete process.env[APPLIED_AT];
|
|
70
80
|
try { ctx.ui?.notify?.(`Chưa nạp được Piagent mới: ${error instanceof Error ? error.message : String(error)}`, "warning"); } catch { /* the session is gone */ }
|
|
71
81
|
}
|
|
72
82
|
};
|
|
@@ -75,9 +85,9 @@ export function watchTerminalReload(pi, { apply, home, startedAt = Date.now(), p
|
|
|
75
85
|
keep(event, next);
|
|
76
86
|
if (!timer) { timer = setInterval(() => { void check(); }, pollMs); timer.unref?.(); }
|
|
77
87
|
});
|
|
78
|
-
pi.on("agent_start", keep);
|
|
79
|
-
// The
|
|
80
|
-
pi.on("agent_settled", (event, next) => { keep(event, next);
|
|
88
|
+
pi.on("agent_start", (event, next) => { keep(event, next); busyAt = Date.now(); });
|
|
89
|
+
// The next check after the quiet time takes a request that waits.
|
|
90
|
+
pi.on("agent_settled", (event, next) => { keep(event, next); busyAt = Date.now(); });
|
|
81
91
|
pi.on("session_shutdown", () => { if (timer) clearInterval(timer); timer = null; ctx = null; });
|
|
82
92
|
return { check };
|
|
83
93
|
}
|
|
@@ -301,6 +301,7 @@ export function companyTerminalExtension({ managed, packageRoot, sdkRoot, bindin
|
|
|
301
301
|
let tui;
|
|
302
302
|
const components = async () => (tui ??= await import(pathToFileURL(require.resolve('@earendil-works/pi-tui')).href));
|
|
303
303
|
const installed = (() => { try { return JSON.parse(fs.readFileSync(path.join(packageRoot, 'package.json'), 'utf8')).version; } catch { return undefined; } })();
|
|
304
|
+
let stopHearing = null;
|
|
304
305
|
|
|
305
306
|
return async (pi) => {
|
|
306
307
|
const { Box, Text } = await components();
|
|
@@ -426,11 +427,12 @@ export function companyTerminalExtension({ managed, packageRoot, sdkRoot, bindin
|
|
|
426
427
|
});
|
|
427
428
|
// How the member's message ended (finished, stopped with steps open,
|
|
428
429
|
// failed, stopped), as the dashboard says it under the last answer.
|
|
429
|
-
let heard = null;
|
|
430
430
|
pi.on('session_start', async (_event, ctx) => {
|
|
431
431
|
const session = managed()?.session;
|
|
432
|
-
if (!session?.subscribe
|
|
433
|
-
|
|
432
|
+
if (!session?.subscribe) return;
|
|
433
|
+
// /reload runs this extension again on the same session: the listener of the
|
|
434
|
+
// runtime it replaces goes, or each event reaches a stale ctx and fails the run.
|
|
435
|
+
stopHearing?.();
|
|
434
436
|
// The conversation can close while git answers (a client ends right after a turn): its ctx is then stale.
|
|
435
437
|
const showBranch = async () => { try { const branch = await branchOf(managed()?.cwd ?? ctx.cwd); ctx.ui?.setStatus?.('agent-watch-branch', branch ? `⎇ ${branch}` : undefined); } catch { /* closed meanwhile */ } };
|
|
436
438
|
ctx.ui?.setWorkingMessage?.(WORKING);
|
|
@@ -438,7 +440,7 @@ export function companyTerminalExtension({ managed, packageRoot, sdkRoot, bindin
|
|
|
438
440
|
// The checklist and the subagents working now stay above the input (setWidget).
|
|
439
441
|
const showPlan = () => ctx.ui?.setWidget?.('agent-watch-plan', planWidget(currentPlan(session.sessionManager)));
|
|
440
442
|
showPlan();
|
|
441
|
-
|
|
443
|
+
const hear = (event) => {
|
|
442
444
|
if (event?.type === 'tool_execution_end' && event.toolName === 'update_plan' || event?.type === 'agent_end') showPlan();
|
|
443
445
|
if (event?.type === 'managed_helper_state') ctx.ui?.setWidget?.('agent-watch-helpers', helperLines(event.helpers));
|
|
444
446
|
if (event?.type === 'managed_helpers') ctx.ui?.setStatus?.('agent-watch-helpers', event.active ? `Subagent ${event.active}/${event.maximum}` : undefined);
|
|
@@ -448,7 +450,10 @@ export function companyTerminalExtension({ managed, packageRoot, sdkRoot, bindin
|
|
|
448
450
|
const copy = turnEndCopy(end, LOCALE), stats = turnStats(session.messages);
|
|
449
451
|
ctx.ui?.notify?.(`${copy.title}. ${copy.text.replace('Bấm Tiếp tục', 'Gửi "tiếp tục"').replace('bấm Tiếp tục', 'gửi "tiếp tục"')}${stats ? `\n${stats}` : ''}`, copy.tone === 'success' ? 'info' : copy.tone === 'error' ? 'error' : copy.tone === 'warning' ? 'warning' : 'info');
|
|
450
452
|
void showBranch();
|
|
451
|
-
}
|
|
453
|
+
};
|
|
454
|
+
// A session closing (a restart in place, /reload) can still report while its ctx is already stale.
|
|
455
|
+
const unsubscribe = session.subscribe((event) => { try { hear(event); } catch { /* the Terminal has moved on */ } });
|
|
456
|
+
stopHearing = unsubscribe;
|
|
452
457
|
});
|
|
453
458
|
pi.registerMessageRenderer('agent-watch-review-status', (_message, _options, theme) =>
|
|
454
459
|
box('Review đã cũ: code đổi sau khi review. Chỉ cần review lại khi đã sửa lỗi blocking.', theme, 'warning'));
|