@piagent/platform 1.38.2 → 1.39.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 +12 -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 +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/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 +6 -0
- package/docs-site/content/index.html +4 -4
- package/docs-site/content/whats-new.html +6 -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 +7 -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 +7 -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/request-stream.mjs +3 -0
- package/packages/piagent-core/managed/workspace-report.mjs +51 -0
- package/packages/piagent-core/package.json +1 -1
- package/packages/piagent-webui/dist/client/assets/{MarkdownMessage-DtEwqme0.js → MarkdownMessage-CMZESBjK.js} +1 -1
- package/packages/piagent-webui/dist/client/assets/{TerminalPanel-C3vkzjQ6.js → TerminalPanel-DlcfsRaR.js} +2 -2
- package/packages/piagent-webui/dist/client/assets/{TerminalView-TNjhBGfa.js → TerminalView-B83HGKgY.js} +1 -1
- package/packages/piagent-webui/dist/client/assets/{WorkspaceCodeEditor-BAhYwQNM.js → WorkspaceCodeEditor-Ctf0VMQh.js} +1 -1
- package/packages/piagent-webui/dist/client/assets/{WorkspaceExplorer-Coh_GWCO.js → WorkspaceExplorer-fO2uXHZg.js} +3 -3
- package/packages/piagent-webui/dist/client/assets/{WorkspaceQuickOpen-Bn4miZq4.js → WorkspaceQuickOpen-ClaXnKl1.js} +1 -1
- package/packages/piagent-webui/dist/client/assets/{index-a-perpOX.js → index-BeBiJUDV.js} +18 -18
- package/packages/piagent-webui/dist/client/assets/{tab-close-nAxrK7Lq.js → tab-close-ggR0dHlZ.js} +1 -1
- package/packages/piagent-webui/dist/client/index.html +1 -1
- package/packages/piagent-webui/gateway/gateway-service.ts +3 -0
- package/packages/piagent-webui/gateway/managed-projection.ts +6 -1
- package/packages/piagent-webui/gateway/session-catalog.ts +3 -2
- package/packages/piagent-webui/gateway/ui-preferences-store.ts +45 -0
- package/packages/piagent-webui/server/loopback-server.ts +2 -1
- package/packages/piagent-webui/server/member-routes.ts +20 -0
- package/packages/piagent-webui/shared/project-warning-copy.ts +16 -0
- package/schemas/piagent-webui/session-catalog-v1.schema.json +1 -1
- package/scripts/company-terminal.mjs +2 -0
package/packages/piagent-webui/dist/client/assets/{tab-close-nAxrK7Lq.js → tab-close-ggR0dHlZ.js}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{D as e}from"./ui-preferences-BO3AV7QE.js";import{m as t}from"./Alert-DGWhP2MM.js";import{E as n}from"./index-
|
|
1
|
+
import{D as e}from"./ui-preferences-BO3AV7QE.js";import{m as t}from"./Alert-DGWhP2MM.js";import{E as n}from"./index-BeBiJUDV.js";var r=e(),i=t((0,r.jsx)(`path`,{d:`M19 6.41 17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z`}),`Close`);function a(e,t,a){let o=e=>{e.stopPropagation(),e.preventDefault(),a()};return(0,r.jsxs)(n,{component:`span`,sx:{display:`inline-flex`,alignItems:`center`,gap:.75},children:[(0,r.jsx)(`span`,{children:e}),(0,r.jsx)(n,{component:`span`,role:`button`,tabIndex:0,"aria-label":t,title:t,onClick:o,onMouseDown:e=>e.stopPropagation(),onKeyDown:e=>{(e.key===`Enter`||e.key===` `)&&o(e)},sx:{display:`inline-grid`,placeItems:`center`,width:18,height:18,borderRadius:`2px`,opacity:.7,"&:hover":{opacity:1,bgcolor:`action.hover`}},children:(0,r.jsx)(i,{sx:{fontSize:14}})})]})}export{i as n,a as t};
|
|
@@ -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-BeBiJUDV.js"></script>
|
|
11
11
|
<link rel="modulepreload" crossorigin href="/assets/rolldown-runtime-hePW80VL.js">
|
|
12
12
|
<link rel="modulepreload" crossorigin href="/assets/ui-preferences-BO3AV7QE.js">
|
|
13
13
|
<link rel="modulepreload" crossorigin href="/assets/useId-DEefKUAT.js">
|
|
@@ -54,6 +54,7 @@ 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
56
|
import type { ScopedBrokerRouter, RuntimeFactory } from "./session-runtime-factory.ts";
|
|
57
|
+
import { UiPreferencesStore } from "./ui-preferences-store.ts";
|
|
57
58
|
|
|
58
59
|
function unavailable(reasonCode: string) {
|
|
59
60
|
return { status: "unavailable" as const, version: null, reasonCode };
|
|
@@ -292,7 +293,9 @@ export async function startPiagentGateway(options: {
|
|
|
292
293
|
const sourceReverts = options.managed ? new ManagedSourceRevertSessions({ root: state.root, key, gatewayInstanceRef, runtimes,
|
|
293
294
|
managedSource: options.managed.managedSource, changed: sessionRef => events.publish("session.changed", { sessionRef }) }) : new SourceRevertSessions({ root: state.root, key, runtimes, managed: !!options.managed,
|
|
294
295
|
provider: sessionRef => inspections.provider(sessionRef), changed: sessionRef => events.publish("session.changed", { sessionRef }) });
|
|
296
|
+
const uiPreferences = new UiPreferencesStore(state.root);
|
|
295
297
|
loopback = await startLoopbackServer({
|
|
298
|
+
uiPreferences: { read: () => uiPreferences.read(), write: value => uiPreferences.write(value) },
|
|
296
299
|
checkpoints: {
|
|
297
300
|
state: sessionRef => company(sessionRef) ? relay!.json("GET", `/api/v1/sessions/${encodeURIComponent(sessionRef)}/checkpoints`) : checkpoints.state(sessionRef),
|
|
298
301
|
preview: (sessionRef, target) => company(sessionRef) ? relay!.json("GET", `/api/v1/sessions/${encodeURIComponent(sessionRef)}/checkpoints/${encodeURIComponent(target)}`) : checkpoints.preview(sessionRef, target),
|
|
@@ -36,7 +36,12 @@ export function managedProjection(context: any, entries: any[]) {
|
|
|
36
36
|
const permission = chosen === 'bypass' ? (bypassAllowed ? 'bypass' : 'trusted-full-access') : chosen === 'trusted-full-access' ? 'trusted-full-access' : 'workspace-write';
|
|
37
37
|
// Fast mode, only where the conversation's Harness allows it (fast-mode.mjs).
|
|
38
38
|
const fast = last('agent-watch-fast');
|
|
39
|
+
// Repositories Studio says do not belong to the key's team (workspace-report.mjs).
|
|
40
|
+
const project = last('agent-watch-project'), kinds = ['other_team', 'unlisted'];
|
|
41
|
+
const projectWarnings = Array.isArray(project?.warnings) ? project.warnings.filter((w: any) => kinds.includes(w?.kind) && typeof w.repo === 'string' && w.repo.trim())
|
|
42
|
+
.slice(0, 6).map((w: any) => ({ repo: w.repo.trim().slice(0, 200), kind: w.kind })) : [];
|
|
43
|
+
const projectWarning = projectWarnings.length ? { warnings: projectWarnings, ...(typeof project.team === 'string' && project.team.trim() ? { team: project.team.trim().slice(0, 80) } : {}) } : null;
|
|
39
44
|
return {modelLabel:'agent-watch-auto', managedPermission: permission, ...(bypassAllowed ? {managedBypass: true as const} : {}), ...(fast?.allowed === true ? {managedFast: fast.enabled === true ? 'on' as const : 'off' as const} : {}), managedHelpers:{active:Number.isInteger(counter?.active) && counter.active>=0 && counter.active<=maximum ? counter.active : 0, maximum},
|
|
40
45
|
...(Array.isArray(capabilities)?{managedThinkingLevels:levels.filter(level=>capabilities.includes(level))}:{}),
|
|
41
|
-
...(steps ? {managedPlan:{steps}} : {}), ...(process ? {managedProcess:process} : {}), ...(turnEnd ? {managedTurnEnd:turnEnd} : {}), ...(review ? {managedReview:review} : {})};
|
|
46
|
+
...(steps ? {managedPlan:{steps}} : {}), ...(process ? {managedProcess:process} : {}), ...(turnEnd ? {managedTurnEnd:turnEnd} : {}), ...(review ? {managedReview:review} : {}), ...(projectWarning ? {managedProjectWarning:projectWarning} : {})};
|
|
42
47
|
}
|
|
@@ -49,7 +49,7 @@ function catalogRef(key: Buffer, namespace: string, value: string): string {
|
|
|
49
49
|
}
|
|
50
50
|
|
|
51
51
|
export type SessionOwnerProjection = Pick<SessionRow, "state" | "liveState" | "composerAvailable" | "needsAttention" | "owner" | "reasonCode">;
|
|
52
|
-
export type SessionOptionProjection = Pick<SessionRow, "modelLabel" | "thinkingLevel" | "managedHelpers" | "managedThinkingLevels" | "managedPermission" | "managedBypass" | "managedFast" | "managedPlan" | "managedProcess" | "managedTurnEnd" | "managedReview">;
|
|
52
|
+
export type SessionOptionProjection = Pick<SessionRow, "modelLabel" | "thinkingLevel" | "managedHelpers" | "managedThinkingLevels" | "managedPermission" | "managedBypass" | "managedFast" | "managedPlan" | "managedProcess" | "managedTurnEnd" | "managedReview" | "managedProjectWarning">;
|
|
53
53
|
|
|
54
54
|
function display(value: unknown, maximum: number, fallback: string): string {
|
|
55
55
|
const clean = redactSensitiveText(String(value ?? "")).text
|
|
@@ -141,6 +141,7 @@ function row(key: Buffer, info: PiSessionInfo, metadata: SessionMetadata | undef
|
|
|
141
141
|
...(sessionOptions?.managedProcess ? {managedProcess:sessionOptions.managedProcess} : {}),
|
|
142
142
|
...(sessionOptions?.managedTurnEnd ? {managedTurnEnd:sessionOptions.managedTurnEnd} : {}),
|
|
143
143
|
...(sessionOptions?.managedReview ? {managedReview:sessionOptions.managedReview} : {}),
|
|
144
|
+
...(sessionOptions?.managedProjectWarning ? {managedProjectWarning:sessionOptions.managedProjectWarning} : {}),
|
|
144
145
|
modelLabel: sessionOptions?.modelLabel ?? null,
|
|
145
146
|
thinkingLevel: sessionOptions?.thinkingLevel ?? "unknown",
|
|
146
147
|
contextUsage: { usedTokens: null, contextWindow: null, ratio: null, state: "unknown" },
|
|
@@ -149,7 +150,7 @@ function row(key: Buffer, info: PiSessionInfo, metadata: SessionMetadata | undef
|
|
|
149
150
|
? { kind: "none", ownerEpoch: null, gatewayInstanceRef: null, runtimeInstanceRef: null, continuity: "released" }
|
|
150
151
|
: ownership?.owner ?? { kind: "none", ownerEpoch: null, gatewayInstanceRef: null, runtimeInstanceRef: null, continuity: "unknown" },
|
|
151
152
|
sessionRevision: revision(key, [info.path, info.modified.toISOString(), info.messageCount, info.name ?? null, metadata?.revision ?? null,
|
|
152
|
-
sessionOptions?.modelLabel ?? null, sessionOptions?.thinkingLevel ?? "unknown", sessionOptions?.managedHelpers, sessionOptions?.managedThinkingLevels, sessionOptions?.managedPermission ?? null, sessionOptions?.managedBypass ?? null, sessionOptions?.managedFast ?? null, sessionOptions?.managedPlan, sessionOptions?.managedProcess, sessionOptions?.managedTurnEnd, sessionOptions?.managedReview,
|
|
153
|
+
sessionOptions?.modelLabel ?? null, sessionOptions?.thinkingLevel ?? "unknown", sessionOptions?.managedHelpers, sessionOptions?.managedThinkingLevels, sessionOptions?.managedPermission ?? null, sessionOptions?.managedBypass ?? null, sessionOptions?.managedFast ?? null, sessionOptions?.managedPlan, sessionOptions?.managedProcess, sessionOptions?.managedTurnEnd, sessionOptions?.managedReview, sessionOptions?.managedProjectWarning,
|
|
153
154
|
gitBranch, gitRepositories,
|
|
154
155
|
metadata?.archived ? "archived" : ownership ? [ownership.state, ownership.liveState, ownership.owner.kind,
|
|
155
156
|
ownership.owner.ownerEpoch, ownership.owner.runtimeInstanceRef, ownership.reasonCode] : "offline"]),
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { randomBytes } from "node:crypto";
|
|
4
|
+
|
|
5
|
+
// The dashboard's language and colour theme, kept by the Gateway so they
|
|
6
|
+
// survive a restart: the browser's own storage belongs to one origin, and the
|
|
7
|
+
// dashboard's port changes each time it starts.
|
|
8
|
+
export type UiPreferences = { locale?: "vi" | "en"; themeId?: string };
|
|
9
|
+
const MAX_BYTES = 4096, THEME = /^[a-z0-9][a-z0-9-]{0,39}$/;
|
|
10
|
+
|
|
11
|
+
function valid(value: unknown): UiPreferences | null {
|
|
12
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return null;
|
|
13
|
+
const { locale, themeId, ...rest } = value as Record<string, unknown>;
|
|
14
|
+
if (Object.keys(rest).length) return null;
|
|
15
|
+
if (locale !== undefined && locale !== "vi" && locale !== "en") return null;
|
|
16
|
+
if (themeId !== undefined && (typeof themeId !== "string" || !THEME.test(themeId))) return null;
|
|
17
|
+
return { ...(locale ? { locale: locale as "vi" | "en" } : {}), ...(themeId ? { themeId: themeId as string } : {}) };
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export class UiPreferencesStore {
|
|
21
|
+
readonly file: string;
|
|
22
|
+
#root: string;
|
|
23
|
+
constructor(root: string) { this.#root = root; this.file = path.join(root, "ui-preferences.json"); }
|
|
24
|
+
|
|
25
|
+
read(): UiPreferences {
|
|
26
|
+
try {
|
|
27
|
+
const stat = fs.lstatSync(this.file);
|
|
28
|
+
if (!stat.isFile() || stat.size > MAX_BYTES) return {};
|
|
29
|
+
return valid(JSON.parse(fs.readFileSync(this.file, "utf8"))) ?? {};
|
|
30
|
+
} catch { return {}; }
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Merges what the browser sent; anything else is refused unchanged.
|
|
34
|
+
write(value: unknown): UiPreferences {
|
|
35
|
+
const change = valid(value);
|
|
36
|
+
if (!change) throw new Error("preferences-invalid");
|
|
37
|
+
const next = { ...this.read(), ...change };
|
|
38
|
+
const temporary = path.join(this.#root, `.ui-preferences-${process.pid}-${randomBytes(8).toString("hex")}.tmp`);
|
|
39
|
+
const descriptor = fs.openSync(temporary, fs.constants.O_WRONLY | fs.constants.O_CREAT | fs.constants.O_EXCL, 0o600);
|
|
40
|
+
try { fs.writeFileSync(descriptor, `${JSON.stringify(next)}\n`); fs.fsyncSync(descriptor); }
|
|
41
|
+
finally { fs.closeSync(descriptor); }
|
|
42
|
+
fs.renameSync(temporary, this.file);
|
|
43
|
+
return next;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -3,7 +3,7 @@ import http, { type ServerResponse } from "node:http";
|
|
|
3
3
|
import { randomBytes } from "node:crypto";
|
|
4
4
|
|
|
5
5
|
import { errorResponse, applySecurityHeaders, jsonResponse, requestBody } from "./http-security.ts";
|
|
6
|
-
import { routeMemberRequest, type UpdateRoutes } from "./member-routes.ts";
|
|
6
|
+
import { routeMemberRequest, type UiPreferenceRoutes, type UpdateRoutes } from "./member-routes.ts";
|
|
7
7
|
import { routeWorkspaceWrite, type WorkspaceWriteRoutes } from "./workspace-write-routes.ts";
|
|
8
8
|
import { routeCheckpoint, type CheckpointRoutes } from "./checkpoint-routes.ts";
|
|
9
9
|
import { ReadModelNotFound, type WebUiReadModelProvider } from "./read-model-provider.ts";
|
|
@@ -81,6 +81,7 @@ export async function startLoopbackServer(options: {
|
|
|
81
81
|
listBranches?: (projectRef: string, repository: string | null) => unknown | Promise<unknown>;
|
|
82
82
|
switchBranch?: (projectRef: string, request: unknown) => unknown | Promise<unknown>;
|
|
83
83
|
updates?: UpdateRoutes;
|
|
84
|
+
uiPreferences?: UiPreferenceRoutes;
|
|
84
85
|
bootstrapTtlMs?: number;
|
|
85
86
|
sessionTtlMs?: number;
|
|
86
87
|
// Requests a minute from one address before it has a browser session (the
|
|
@@ -23,6 +23,9 @@ export type UpdateRoutes = {
|
|
|
23
23
|
apply(request: unknown): unknown | Promise<unknown>;
|
|
24
24
|
};
|
|
25
25
|
|
|
26
|
+
// The dashboard's language and theme, kept across restarts (the Gateway only).
|
|
27
|
+
export type UiPreferenceRoutes = { read(): unknown | Promise<unknown>; write(value: unknown): unknown | Promise<unknown> };
|
|
28
|
+
|
|
26
29
|
type Context = {
|
|
27
30
|
request: IncomingMessage; response: ServerResponse; url: URL; origin: string; requestOrigin: string | undefined;
|
|
28
31
|
auth: SessionAuthority; now: number; consumeControl(sessionId: string, now: number): boolean;
|
|
@@ -40,6 +43,7 @@ type Options = {
|
|
|
40
43
|
listBranches?: (projectRef: string, repository: string | null) => unknown | Promise<unknown>;
|
|
41
44
|
switchBranch?: (projectRef: string, request: unknown) => unknown | Promise<unknown>;
|
|
42
45
|
updates?: UpdateRoutes;
|
|
46
|
+
uiPreferences?: UiPreferenceRoutes;
|
|
43
47
|
};
|
|
44
48
|
|
|
45
49
|
// The checks every change shares; a refusal is answered here and false returned.
|
|
@@ -137,6 +141,22 @@ export async function routeMemberRequest(context: Context, options: Options): Pr
|
|
|
137
141
|
return true;
|
|
138
142
|
}
|
|
139
143
|
|
|
144
|
+
if (options.uiPreferences && url.pathname === "/api/v1/preferences") {
|
|
145
|
+
const store = options.uiPreferences;
|
|
146
|
+
if (request.method === "GET") {
|
|
147
|
+
if (!auth.authenticate(request)) { errorResponse(response, 401, "authentication-required"); return true; }
|
|
148
|
+
try { jsonResponse(response, 200, await store.read()); } catch { errorResponse(response, 503, "preferences-unavailable"); }
|
|
149
|
+
return true;
|
|
150
|
+
}
|
|
151
|
+
if (request.method !== "POST") { errorResponse(response, 405, "method-not-allowed"); return true; }
|
|
152
|
+
if (!authorizeChange(context)) return true;
|
|
153
|
+
const body = await jsonBody(context, "preferences-invalid");
|
|
154
|
+
if (!body.ok) return true;
|
|
155
|
+
try { jsonResponse(response, 200, await store.write(body.value)); }
|
|
156
|
+
catch (error) { const invalid = error instanceof Error && error.message === "preferences-invalid"; errorResponse(response, invalid ? 400 : 503, invalid ? "preferences-invalid" : "preferences-unavailable"); }
|
|
157
|
+
return true;
|
|
158
|
+
}
|
|
159
|
+
|
|
140
160
|
if (!options.updates || !url.pathname.startsWith("/api/v1/updates")) return false;
|
|
141
161
|
const updates = options.updates;
|
|
142
162
|
if (request.method === "GET" && url.pathname === "/api/v1/updates") {
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// The line a member reads when Studio says their company conversation works
|
|
2
|
+
// in a repository that does not belong to the key's team
|
|
3
|
+
// ("agent-watch-project"), in the dashboard and in the company Terminal.
|
|
4
|
+
import type { CopyLocale } from "./company-copy.ts";
|
|
5
|
+
|
|
6
|
+
export type ProjectWarningItem = { repo: string; kind: "other_team" | "unlisted" };
|
|
7
|
+
|
|
8
|
+
export function projectWarningText(warnings: readonly ProjectWarningItem[], team: string | null | undefined, locale: CopyLocale): string {
|
|
9
|
+
const repos = warnings.map(item => item.repo).join(", "), name = team ? ` ${team}` : "";
|
|
10
|
+
if (warnings.some(item => item.kind === "other_team")) return locale === "vi"
|
|
11
|
+
? `${repos} thuộc team khác, không phải team${name} của key này. Admin Studio đã được báo.`
|
|
12
|
+
: `${repos} belongs to another team, not this key's team${name}. Studio administrators were told.`;
|
|
13
|
+
return locale === "vi"
|
|
14
|
+
? `${repos} chưa có trong danh sách repository của team${name}. Admin Studio đã được báo.`
|
|
15
|
+
: `${repos} is not in the repository list of team${name}. Studio administrators were told.`;
|
|
16
|
+
}
|
|
@@ -92,7 +92,7 @@
|
|
|
92
92
|
"composerAvailable": { "type": "boolean" },
|
|
93
93
|
"needsAttention": { "type": "boolean" },
|
|
94
94
|
"managedHelpers": { "type": "object", "additionalProperties": false, "required": ["active", "maximum"], "properties": {"active": {"type": ["integer", "null"], "minimum": 0, "maximum": 4}, "maximum": {"type": "integer", "minimum": 0, "maximum": 4}} },
|
|
95
|
-
"managedThinkingLevels": {"type": "array", "uniqueItems": true, "maxItems": 7, "items": {"enum": ["off","minimal","low","medium","high","xhigh","max"]}}, "managedPermission": {"enum": ["workspace-write","trusted-full-access","bypass"]}, "managedBypass": {"const": true}, "managedFast": {"enum": ["off","on"]},
|
|
95
|
+
"managedThinkingLevels": {"type": "array", "uniqueItems": true, "maxItems": 7, "items": {"enum": ["off","minimal","low","medium","high","xhigh","max"]}}, "managedPermission": {"enum": ["workspace-write","trusted-full-access","bypass"]}, "managedBypass": {"const": true}, "managedProjectWarning": {"type": "object", "additionalProperties": false, "required": ["warnings"], "properties": {"team": {"type": "string", "minLength": 1, "maxLength": 80}, "warnings": {"type": "array", "minItems": 1, "maxItems": 6, "items": {"type": "object", "additionalProperties": false, "required": ["repo", "kind"], "properties": {"repo": {"type": "string", "minLength": 1, "maxLength": 200}, "kind": {"enum": ["other_team", "unlisted"]}}}}}}, "managedFast": {"enum": ["off","on"]},
|
|
96
96
|
"managedPlan": { "type": "object", "additionalProperties": false, "required": ["steps"], "properties": {
|
|
97
97
|
"steps": { "type": "array", "minItems": 1, "maxItems": 30, "items": { "type": "object", "additionalProperties": false, "required": ["step", "status"], "properties": {
|
|
98
98
|
"step": { "type": "string", "minLength": 1, "maxLength": 200 }, "status": { "enum": ["pending", "in_progress", "completed", "deferred"] } } } } } },
|
|
@@ -16,6 +16,7 @@ import { memoryOn } from '../packages/piagent-core/managed/memory.mjs';
|
|
|
16
16
|
import { companyFailureText } from '../packages/piagent-webui/shared/company-copy.ts';
|
|
17
17
|
import { headlineText, outcomeText, processItems } from '../packages/piagent-webui/shared/process-copy.ts';
|
|
18
18
|
import { turnEndCopy, turnEndOf } from '../packages/piagent-webui/shared/turn-end.ts';
|
|
19
|
+
import { projectWarningText } from '../packages/piagent-webui/shared/project-warning-copy.ts';
|
|
19
20
|
|
|
20
21
|
const LOCALE = 'vi';
|
|
21
22
|
|
|
@@ -399,6 +400,7 @@ export function companyTerminalExtension({ managed, packageRoot, sdkRoot, bindin
|
|
|
399
400
|
void showBranch();
|
|
400
401
|
session.subscribe((event) => {
|
|
401
402
|
if (event?.type === 'managed_helpers') ctx.ui?.setStatus?.('agent-watch-helpers', event.active ? `Subagent ${event.active}/${event.maximum}` : undefined);
|
|
403
|
+
if (event?.type === 'managed_project_warning') ctx.ui?.notify?.(projectWarningText(event.warnings, event.team, LOCALE), 'warning');
|
|
402
404
|
const end = event?.type === 'managed_turn_end' ? turnEndOf(event.end) : null;
|
|
403
405
|
if (!end) return;
|
|
404
406
|
const copy = turnEndCopy(end, LOCALE), stats = turnStats(session.messages);
|