@piagent/platform 1.29.0 → 1.30.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +26 -0
- package/README.md +1 -1
- package/README.vi.md +1 -1
- 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 +2 -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/benchmark.html +1 -1
- package/docs-site/commands.html +1 -1
- package/docs-site/content/en/index.html +4 -4
- package/docs-site/content/en/whats-new.html +13 -0
- package/docs-site/content/index.html +4 -4
- package/docs-site/content/whats-new.html +13 -0
- 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 +5 -5
- 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/whats-new.html +14 -1
- package/docs-site/en/windows.html +1 -1
- package/docs-site/en/workflows.html +1 -1
- package/docs-site/index.html +5 -5
- 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/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/whats-new.html +14 -1
- 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/managed/compressed-fetch.mjs +28 -0
- package/packages/piagent-core/managed/request-stream.mjs +2 -1
- package/packages/piagent-core/package.json +1 -1
- package/packages/piagent-webui/dist/client/assets/{MarkdownMessage-3vQTaeOO.js → MarkdownMessage-ZFXG_br8.js} +1 -1
- package/packages/piagent-webui/dist/client/assets/{index-Dve4GNQ7.js → index-B3ODBFGj.js} +3 -3
- package/packages/piagent-webui/dist/client/index.html +1 -1
- package/packages/piagent-webui/shared/company-copy.ts +1 -0
- package/scripts/company-terminal.mjs +75 -16
- package/scripts/piagent-studio.mjs +5 -1
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
<meta name="csp-nonce" content="__PIAGENT_CSP_NONCE__" />
|
|
8
8
|
<meta name="piagent-webui-mode" content="__PIAGENT_WEBUI_MODE__" />
|
|
9
9
|
<title>Piagent WebUI</title>
|
|
10
|
-
<script type="module" crossorigin src="/assets/index-
|
|
10
|
+
<script type="module" crossorigin src="/assets/index-B3ODBFGj.js"></script>
|
|
11
11
|
<link rel="stylesheet" crossorigin href="/assets/index-B5XOKQy-.css">
|
|
12
12
|
</head>
|
|
13
13
|
<body>
|
|
@@ -12,6 +12,7 @@ export const LAUNCH_REASONS: Record<string, [string, string]> = {
|
|
|
12
12
|
"managed-key-unavailable": ["Agent Watch không đọc được key công ty trên máy này. Mở Agent Watch, dán lại mã kết nối, bấm Kết nối Piagent trong WSL rồi kết nối lại.", "Agent Watch cannot read the company key on this computer. Open Agent Watch, paste the connection code again, choose Connect Piagent in WSL, then connect again."],
|
|
13
13
|
"managed-profile-disconnected": ["Cấu hình Piagent đang thuộc key công ty đã ngắt kết nối. Nhập lại cấu hình cho Piagent trong Agent Watch (trên Windows: Kết nối Piagent trong WSL).", "The Piagent configuration belongs to a disconnected company key. Import it again in Agent Watch (on Windows: Connect Piagent in WSL)."],
|
|
14
14
|
"managed-launch-binding-changed": ["Agent Watch hoặc Piagent vừa cập nhật. Nhập lại cấu hình cho Piagent trong Agent Watch (trên Windows: Kết nối Piagent trong WSL).", "Agent Watch or Piagent changed. Import the Piagent configuration again in Agent Watch (on Windows: Connect Piagent in WSL)."],
|
|
15
|
+
"managed-project-contains-config": ["Không mở Piagent công ty ở thư mục này (thường là thư mục home ~) vì nó chứa cấu hình công ty. Vào thư mục dự án rồi chạy lại: cd ~/đường-dẫn-dự-án && piagent studio, hoặc piagent studio --project ~/đường-dẫn-dự-án.", "The company Piagent cannot open this folder (usually your home folder ~) because it holds the company configuration. Go to a project folder and run it again: cd ~/your-project && piagent studio, or piagent studio --project ~/your-project."],
|
|
15
16
|
"managed-binding-update-pending": ["Agent Watch đang chạy nhưng chưa cập nhật cấu hình sau bản Piagent hoặc Agent Watch mới. Mở Agent Watch → Studio, bấm Áp dụng cho Piagent rồi mở lại.", "Agent Watch is running but has not updated the configuration after the Piagent or Agent Watch update yet. Open Agent Watch → Studio, apply for Piagent, then open it again."],
|
|
16
17
|
"managed-binding-watch-not-running": ["Piagent hoặc Agent Watch vừa cập nhật nhưng Agent Watch không chạy nên chưa cập nhật cấu hình. Mở Agent Watch, chờ vài giây rồi mở lại.", "Piagent or Agent Watch was updated but Agent Watch is not running, so the configuration was not updated. Open Agent Watch, wait a few seconds, then open it again."],
|
|
17
18
|
"managed-launch-version-mismatch": ["Agent Watch đang dùng một bản Piagent khác với dashboard này. Mở Agent Watch → Studio, bấm Áp dụng cho Piagent rồi kết nối lại.", "Agent Watch points at another Piagent install than this dashboard. Open Agent Watch → Studio, apply for Piagent, then connect again."],
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
import fs from 'node:fs';
|
|
6
6
|
import { createRequire } from 'node:module';
|
|
7
7
|
import path from 'node:path';
|
|
8
|
+
import { execFile } from 'node:child_process';
|
|
8
9
|
import { pathToFileURL } from 'node:url';
|
|
9
10
|
|
|
10
11
|
import { registerTerminalUpdateOffer } from '../packages/piagent-core/runtime/update/terminal-update-offer.mjs';
|
|
@@ -16,6 +17,45 @@ import { headlineText, outcomeText, processItems } from '../packages/piagent-web
|
|
|
16
17
|
import { turnEndCopy, turnEndOf } from '../packages/piagent-webui/shared/turn-end.ts';
|
|
17
18
|
|
|
18
19
|
const LOCALE = 'vi';
|
|
20
|
+
|
|
21
|
+
const WORKING = 'Đang làm…';
|
|
22
|
+
|
|
23
|
+
// A typed value that is already complete offers nothing, so the first Enter runs the command.
|
|
24
|
+
export const argumentCompletions = (values) => (prefix) => {
|
|
25
|
+
const typed = String(prefix ?? '').trim();
|
|
26
|
+
return values.includes(typed) ? [] : values.filter((v) => v.startsWith(typed)).map((value) => ({ value, label: value }));
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const compactTokens = (n) => n >= 1_000_000 ? `${(n / 1_000_000).toFixed(1)}M` : n >= 1000 ? `${Math.round(n / 1000)}k` : String(n);
|
|
30
|
+
const textOf = (content) => typeof content === 'string' ? content : Array.isArray(content) ? content.filter((p) => p?.type === 'text').map((p) => p.text ?? '').join('\n') : '';
|
|
31
|
+
|
|
32
|
+
// Model requests, tokens, time and output speed of the member's last message,
|
|
33
|
+
// as the dashboard writes them under a turn.
|
|
34
|
+
export function turnStats(messages, now = Date.now()) {
|
|
35
|
+
const list = Array.isArray(messages) ? messages : [];
|
|
36
|
+
const start = list.findLastIndex((m) => m?.role === 'user');
|
|
37
|
+
if (start < 0) return null;
|
|
38
|
+
const answers = list.slice(start + 1).filter((m) => m?.role === 'assistant');
|
|
39
|
+
if (!answers.length) return null;
|
|
40
|
+
const tokens = answers.reduce((n, m) => n + (m.usage?.totalTokens ?? 0), 0), output = answers.reduce((n, m) => n + (m.usage?.output ?? 0), 0);
|
|
41
|
+
const began = Number(list[start].timestamp) || null, seconds = began ? Math.max(0, Math.round((now - began) / 1000)) : null;
|
|
42
|
+
const parts = [`${answers.length} request`];
|
|
43
|
+
if (tokens) parts.push(`${compactTokens(tokens)} token`);
|
|
44
|
+
if (seconds) parts.push(seconds < 60 ? `${seconds} giây` : `${Math.floor(seconds / 60)} phút ${seconds % 60} giây`);
|
|
45
|
+
if (seconds && output) parts.push(`${Math.round(output / seconds)} tok/s`);
|
|
46
|
+
return parts.join(' · ');
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Team memory results stay short in the transcript (Ctrl+O shows all).
|
|
50
|
+
export function memoryResultLines(text, expanded = false) {
|
|
51
|
+
const lines = String(text ?? '').split('\n').map((l) => l.trimEnd()).filter((l) => l.trim());
|
|
52
|
+
if (expanded || lines.length <= 4) return lines;
|
|
53
|
+
const facts = lines.filter((l) => /^\s*-\s/.test(l)).length;
|
|
54
|
+
return [...lines.slice(0, 3), `… ${facts ? `${facts} ghi chú, ` : ''}${lines.length - 3} dòng nữa (Ctrl+O để xem hết)`];
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const branchOf = (cwd) => new Promise((resolve) => execFile('git', ['-C', cwd, 'rev-parse', '--abbrev-ref', 'HEAD'], { timeout: 3000 },
|
|
58
|
+
(error, out) => resolve(error ? null : String(out).trim() || null)));
|
|
19
59
|
export const HELP_TEXT = [
|
|
20
60
|
'Cuộc trò chuyện công ty: /undo hoàn tác file lượt trước đã sửa · /bypass on|off|status quyền lệnh cần internet · /fast on|off|status (khi Harness cho phép) · /skill:<tên> hoặc /<lệnh> của bạn và của project.',
|
|
21
61
|
'Pi: /session thông tin cuộc trò chuyện · /resume mở cuộc trò chuyện công ty khác · /new cuộc mới · /compact nén ngữ cảnh · /tree, /fork nhánh · /name đặt tên · /copy, /export · /hotkeys toàn bộ phím tắt · /quit thoát.',
|
|
@@ -33,15 +73,15 @@ const EFFORT = { off: 'Tắt', minimal: 'Tối thiểu', low: 'Thấp', medium:
|
|
|
33
73
|
export const effortText = (level) => EFFORT[level] ?? level ?? '';
|
|
34
74
|
|
|
35
75
|
// What the team's Harness decides for this conversation, as the header and
|
|
36
|
-
// footer say it
|
|
37
|
-
//
|
|
76
|
+
// footer say it: roles and effort only. A member never sees which model a
|
|
77
|
+
// role runs on, so no model id leaves this function. `last` is the main
|
|
78
|
+
// agent's latest run (its effort); before the first run, the Harness's effort.
|
|
38
79
|
export function harnessSummary(managed, { last = null, version = null } = {}) {
|
|
39
80
|
const manifest = managed?.manifest, config = manifest?.harness?.configuration ?? {};
|
|
40
|
-
const review = config.workflow?.review !== 'off' && config.review?.model_ids?.
|
|
81
|
+
const review = config.workflow?.review !== 'off' && Boolean(config.review?.model_ids?.length);
|
|
41
82
|
const fast = managed?.session?.managedFastState?.() ?? null;
|
|
42
83
|
return {
|
|
43
84
|
team: manifest?.user?.team_name || null,
|
|
44
|
-
model: last?.model_id || config.main?.model_ids?.[0] || null,
|
|
45
85
|
effort: last?.effort || config.main?.effort || managed?.session?.state?.thinkingLevel || null,
|
|
46
86
|
review, permission: managed?.permission === 'trusted-full-access' ? 'Bypass' : 'Hỏi trước',
|
|
47
87
|
fast: fast === null ? null : fast === 'on', memory: managed ? memoryOn(managed) : false, version,
|
|
@@ -49,8 +89,8 @@ export function harnessSummary(managed, { last = null, version = null } = {}) {
|
|
|
49
89
|
}
|
|
50
90
|
export function headerText(summary) {
|
|
51
91
|
return ['Piagent công ty', summary.team && `team ${summary.team}`,
|
|
52
|
-
|
|
53
|
-
summary.review &&
|
|
92
|
+
`Main agent${summary.effort ? ` (${effortText(summary.effort)})` : ''}`,
|
|
93
|
+
summary.review && 'Subagent review bật', summary.permission,
|
|
54
94
|
summary.fast !== null && `Fast ${summary.fast ? 'bật' : 'tắt'}`, `memory ${summary.memory ? 'bật' : 'tắt'}`, summary.version].filter(Boolean).join(' · ');
|
|
55
95
|
}
|
|
56
96
|
export const HEADER_KEYS = 'Esc dừng lượt · Ctrl+C xoá ô nhập, hai lần để thoát · / lệnh · ! shell · Ctrl+O xem thêm · /help';
|
|
@@ -61,7 +101,7 @@ export const HEADER_KEYS = 'Esc dừng lượt · Ctrl+C xoá ô nhập, hai l
|
|
|
61
101
|
// Ctrl+P, Shift+Tab) answer the same.
|
|
62
102
|
const ADMIN = 'Admin đổi trong Agent Studio → Harness.';
|
|
63
103
|
export function companyCommandText(name, summary = {}) {
|
|
64
|
-
const main = summary.
|
|
104
|
+
const main = summary.effort ? ` (Main agent: ${effortText(summary.effort)})` : '';
|
|
65
105
|
switch (name) {
|
|
66
106
|
case 'share': return '/share bị tắt trong cuộc trò chuyện công ty: lệnh này đăng toàn bộ hội thoại lên GitHub Gist, ra ngoài công ty. Cần lưu lại thì dùng /export (file trên máy này).';
|
|
67
107
|
case 'bug': return '/bug bị tắt trong cuộc trò chuyện công ty: báo cáo gửi hội thoại và code cho nhà phát triển Pi, ra ngoài công ty. Gặp lỗi, gửi admin của team mã lỗi trong [ ] và giờ xảy ra.';
|
|
@@ -128,7 +168,7 @@ export function failureLines(errorMessage) {
|
|
|
128
168
|
|
|
129
169
|
const tokens = (n) => n < 1000 ? String(n) : n < 10000 ? `${(n / 1000).toFixed(1)}k` : n < 1e6 ? `${Math.round(n / 1000)}k` : `${(n / 1e6).toFixed(1)}M`;
|
|
130
170
|
// Pi's footer without the USD cost (company accounts are not billed per
|
|
131
|
-
// conversation) and with the
|
|
171
|
+
// conversation) and with the main agent's effort on the right (never its model).
|
|
132
172
|
export function footerLines({ session, summary, footerData, theme, width, truncateToWidth, visibleWidth }) {
|
|
133
173
|
const dim = (text) => theme.fg('dim', text);
|
|
134
174
|
if (!session) return [truncateToWidth(dim(headerText(summary)), width, dim('...'))];
|
|
@@ -148,7 +188,7 @@ export function footerLines({ session, summary, footerData, theme, width, trunca
|
|
|
148
188
|
const parts = [sum.input && `↑${tokens(sum.input)}`, sum.output && `↓${tokens(sum.output)}`, sum.cacheRead && `R${tokens(sum.cacheRead)}`, sum.cacheWrite && `W${tokens(sum.cacheWrite)}`].filter(Boolean);
|
|
149
189
|
const ctxText = `${shown === '?' ? '?' : shown + '%'}/${tokens(window)} (auto)`;
|
|
150
190
|
let left = [...parts, ctxText].join(' ');
|
|
151
|
-
const right =
|
|
191
|
+
const right = `Main agent${summary.effort ? ` • ${effortText(summary.effort)}` : ''}`;
|
|
152
192
|
if (visibleWidth(left) > width) left = truncateToWidth(left, width, '...');
|
|
153
193
|
const room = width - visibleWidth(left) - 2;
|
|
154
194
|
const tail = room > 0 && right ? truncateToWidth(right, room, '') : '';
|
|
@@ -165,7 +205,10 @@ export function footerLines({ session, summary, footerData, theme, width, trunca
|
|
|
165
205
|
export async function companyToolRenderers(sdkRoot) {
|
|
166
206
|
const require = createRequire(path.join(sdkRoot, 'package.json'));
|
|
167
207
|
const { Text } = await import(pathToFileURL(require.resolve('@earendil-works/pi-tui')).href);
|
|
168
|
-
|
|
208
|
+
const memory = (title) => ({
|
|
209
|
+
renderCall: (args, theme) => new Text(theme.fg('toolTitle', theme.bold(title)) + (args?.query || args?.name ? theme.fg('muted', ` ${args.query ?? args.name}`) : ''), 0, 0),
|
|
210
|
+
renderResult: (result, options, theme) => new Text(theme.fg('toolOutput', memoryResultLines((result?.content ?? []).map((c) => c.text ?? '').join('\n'), options?.expanded).join('\n')), 0, 0) });
|
|
211
|
+
return { memory_search: memory('Team memory'), memory_page: memory('Trang kiến thức'), update_plan: {
|
|
169
212
|
renderCall: (_args, theme) => new Text(theme.fg('toolTitle', theme.bold('Plan')), 0, 0),
|
|
170
213
|
renderResult: (result, _options, theme) => {
|
|
171
214
|
const plan = result?.details?.plan;
|
|
@@ -184,6 +227,15 @@ export async function companyInteractiveMode(api, { sdkRoot, packageRoot, summar
|
|
|
184
227
|
const changelog = () => { try { return fs.readFileSync(path.join(packageRoot, 'CHANGELOG.md'), 'utf8'); } catch { return ''; } };
|
|
185
228
|
return companyMode(api.InteractiveMode, { summary, whatsNew: () => whatsNewMarkdown(changelog()), components: { Markdown, Spacer, DynamicBorder: api.DynamicBorder } });
|
|
186
229
|
}
|
|
230
|
+
// Pi's own warnings, as the company Terminal says them: the crash notice
|
|
231
|
+
// without /bug, and no model id ("Could not restore model p/id").
|
|
232
|
+
export function companyWarning(message) {
|
|
233
|
+
const text = String(message ?? '');
|
|
234
|
+
const crash = /^\S+ crashed on (.+?) \((.*)\)\. Run \/bug/s.exec(text);
|
|
235
|
+
if (crash) return `Lần trước Piagent công ty dừng bất thường (${crash[1]}, ${crash[2]}). Cuộc trò chuyện vẫn còn: /resume để mở lại. Nếu lặp lại, gửi admin của team giờ xảy ra.`;
|
|
236
|
+
if (/^Could not restore model /.test(text)) return 'Cuộc trò chuyện này chạy theo Harness hiện tại của team.';
|
|
237
|
+
return text;
|
|
238
|
+
}
|
|
187
239
|
export function companyMode(Base, { summary, whatsNew, components }) {
|
|
188
240
|
const say = (mode, name, tone = 'warning') => mode.showExtensionNotify(companyCommandText(name, summary()), tone);
|
|
189
241
|
return class CompanyInteractiveMode extends Base {
|
|
@@ -191,6 +243,8 @@ export function companyMode(Base, { summary, whatsNew, components }) {
|
|
|
191
243
|
async handleBugCommand() { say(this, 'bug'); }
|
|
192
244
|
suggestBugReport() {}
|
|
193
245
|
crashReportInstructions() { return 'Lần sau mở lại: piagent studio, rồi /resume. Gửi admin của team giờ xảy ra lỗi.'; }
|
|
246
|
+
// Pi's start-up warnings point at /bug (off here) or name a model.
|
|
247
|
+
showWarning(message) { super.showWarning(companyWarning(message)); }
|
|
194
248
|
async handleLoginCommand() { say(this, 'login', 'info'); }
|
|
195
249
|
async showOAuthSelector() { say(this, 'logout', 'info'); }
|
|
196
250
|
async handleModelCommand() { say(this, 'model', 'info'); }
|
|
@@ -235,7 +289,7 @@ export function companyTerminalExtension({ managed, packageRoot, sdkRoot, bindin
|
|
|
235
289
|
pi.on('session_start', async (_event, ctx) => showPermission(ctx));
|
|
236
290
|
pi.registerCommand('bypass', {
|
|
237
291
|
description: 'Bật/tắt Bypass cho cuộc trò chuyện công ty này (on, off, hoặc để trống để chọn)',
|
|
238
|
-
getArgumentCompletions: (
|
|
292
|
+
getArgumentCompletions: argumentCompletions(['on', 'off', 'status']),
|
|
239
293
|
handler: async (args, ctx) => {
|
|
240
294
|
const session = managed();
|
|
241
295
|
if (typeof session?.session?.managedSetPermission !== 'function') { ctx.ui.notify('Cuộc trò chuyện này chưa sẵn sàng.', 'error'); return; }
|
|
@@ -266,7 +320,7 @@ export function companyTerminalExtension({ managed, packageRoot, sdkRoot, bindin
|
|
|
266
320
|
pi.on('session_start', async (_event, ctx) => showFast(ctx));
|
|
267
321
|
pi.registerCommand('fast', {
|
|
268
322
|
description: 'Bật/tắt Fast cho cuộc trò chuyện công ty này (on, off, status); chỉ có khi Harness của team cho phép',
|
|
269
|
-
getArgumentCompletions: (
|
|
323
|
+
getArgumentCompletions: argumentCompletions(['on', 'off', 'status']),
|
|
270
324
|
handler: async (args, ctx) => {
|
|
271
325
|
const session = managed()?.session, state = session?.managedFastState?.();
|
|
272
326
|
if (typeof session?.managedSetFast !== 'function') { ctx.ui.notify('Cuộc trò chuyện này chưa sẵn sàng.', 'error'); return; }
|
|
@@ -294,7 +348,7 @@ export function companyTerminalExtension({ managed, packageRoot, sdkRoot, bindin
|
|
|
294
348
|
let last = null;
|
|
295
349
|
const summary = () => {
|
|
296
350
|
const grant = managed()?.grant;
|
|
297
|
-
if (grant?.
|
|
351
|
+
if (grant?.effort) last = { effort: grant.effort };
|
|
298
352
|
return harnessSummary(managed(), { last, version: installed });
|
|
299
353
|
};
|
|
300
354
|
pi.on('session_start', async (_event, ctx) => {
|
|
@@ -318,7 +372,7 @@ export function companyTerminalExtension({ managed, packageRoot, sdkRoot, bindin
|
|
|
318
372
|
});
|
|
319
373
|
pi.on('tool_execution_end', async (event, ctx) => {
|
|
320
374
|
if (event?.toolName !== 'ask_user') return;
|
|
321
|
-
ctx.ui?.setWorkingMessage?.(); ctx.ui?.setWorkingIndicator?.();
|
|
375
|
+
ctx.ui?.setWorkingMessage?.(WORKING); ctx.ui?.setWorkingIndicator?.();
|
|
322
376
|
});
|
|
323
377
|
|
|
324
378
|
// The Harness's notes carry English for the agent; the member reads them in Vietnamese.
|
|
@@ -334,11 +388,16 @@ export function companyTerminalExtension({ managed, packageRoot, sdkRoot, bindin
|
|
|
334
388
|
const session = managed()?.session;
|
|
335
389
|
if (!session?.subscribe || heard === session) return;
|
|
336
390
|
heard = session;
|
|
391
|
+
const showBranch = async () => { const branch = await branchOf(managed()?.cwd ?? ctx.cwd); ctx.ui?.setStatus?.('agent-watch-branch', branch ? `⎇ ${branch}` : undefined); };
|
|
392
|
+
ctx.ui?.setWorkingMessage?.(WORKING);
|
|
393
|
+
void showBranch();
|
|
337
394
|
session.subscribe((event) => {
|
|
395
|
+
if (event?.type === 'managed_helpers') ctx.ui?.setStatus?.('agent-watch-helpers', event.active ? `Subagent ${event.active}/${event.maximum}` : undefined);
|
|
338
396
|
const end = event?.type === 'managed_turn_end' ? turnEndOf(event.end) : null;
|
|
339
397
|
if (!end) return;
|
|
340
|
-
const copy = turnEndCopy(end, LOCALE);
|
|
341
|
-
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"')}`, copy.tone === 'success' ? 'info' : copy.tone === 'error' ? 'error' : copy.tone === 'warning' ? 'warning' : 'info');
|
|
398
|
+
const copy = turnEndCopy(end, LOCALE), stats = turnStats(session.messages);
|
|
399
|
+
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');
|
|
400
|
+
void showBranch();
|
|
342
401
|
});
|
|
343
402
|
});
|
|
344
403
|
pi.registerMessageRenderer('agent-watch-review-status', (_message, _options, theme) =>
|
|
@@ -23,6 +23,8 @@ for (let i = 0; i < args.length; i++) {
|
|
|
23
23
|
}
|
|
24
24
|
if (flags.has('--json') && !flags.has('--prompt')) throw Error('managed-launch-arguments');
|
|
25
25
|
const home = os.homedir();
|
|
26
|
+
// Joining Agent Watch takes a few seconds; keys typed before the Terminal draws are lost, so say so.
|
|
27
|
+
if (!['--check', '--prompt', '--serve', '--doctor', '--web'].some((f) => flags.has(f)) && process.stderr.isTTY) process.stderr.write('Piagent công ty: đang kết nối Agent Watch, chờ ô nhập hiện ra rồi gõ…\n');
|
|
26
28
|
// Do this before importing the SDK: it must not discover personal keys, Node
|
|
27
29
|
// preload hooks, proxy overrides or provider endpoints from an ambient shell.
|
|
28
30
|
const clean = { PATH: '/usr/bin:/bin', HOME: home, LANG: 'en_US.UTF-8', TERM: process.env.TERM || 'xterm-256color', ...interopEnvironment() };
|
|
@@ -81,7 +83,9 @@ try {
|
|
|
81
83
|
}
|
|
82
84
|
const agentDir = path.join(root, store);
|
|
83
85
|
const cwd = serve ? path.join(agentDir, 'probe') : fs.realpathSync(flags.get('--project') || process.cwd());
|
|
84
|
-
|
|
86
|
+
// A project folder that holds the company configuration (the home folder,
|
|
87
|
+
// ~/.pi) would put it in reach of the project's tools: refuse, and say so.
|
|
88
|
+
if (configPath.startsWith(cwd + path.sep)) throw Error('managed-project-contains-config');
|
|
85
89
|
fs.mkdirSync(agentDir, { recursive: true, mode: 0o700 }); fs.chmodSync(agentDir, 0o700);
|
|
86
90
|
if (serve) { fs.mkdirSync(cwd, { recursive: true, mode: 0o700 }); fs.chmodSync(cwd, 0o700); }
|
|
87
91
|
await import('./register-typescript-loader.mjs');
|