@piagent/platform 1.16.3 → 1.17.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 +8 -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/package.json +1 -1
- package/packages/piagent-webui/dist/client/assets/{MarkdownMessage-BDdLJYnZ.js → MarkdownMessage-CeQ79h30.js} +1 -1
- package/packages/piagent-webui/dist/client/assets/{index-DJGByyfL.js → index-BNQK7rHr.js} +11 -11
- package/packages/piagent-webui/dist/client/index.html +1 -1
- package/packages/piagent-webui/gateway/git-head.ts +52 -0
- package/packages/piagent-webui/gateway/session-catalog.ts +8 -2
- package/schemas/piagent-webui/session-catalog-v1.schema.json +3 -0
|
@@ -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-BNQK7rHr.js"></script>
|
|
11
11
|
<link rel="stylesheet" crossorigin href="/assets/index-Z91z6SlN.css">
|
|
12
12
|
</head>
|
|
13
13
|
<body>
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
|
|
4
|
+
export type GitHead = { name: string; detached: boolean };
|
|
5
|
+
|
|
6
|
+
const MAX_DEPTH = 40;
|
|
7
|
+
|
|
8
|
+
// The branch a project folder stands on, read from the repository's HEAD file
|
|
9
|
+
// rather than by running git: the catalog asks for every project each time the
|
|
10
|
+
// dashboard refreshes, and a file read costs nothing. A linked worktree's
|
|
11
|
+
// `.git` is a file naming its own git directory, which holds its own HEAD.
|
|
12
|
+
// Null when the folder is not inside a repository or HEAD cannot be read.
|
|
13
|
+
export function readGitHead(cwd: string): GitHead | null {
|
|
14
|
+
if (!cwd) return null;
|
|
15
|
+
let folder = path.resolve(cwd);
|
|
16
|
+
for (let depth = 0; depth < MAX_DEPTH; depth += 1) {
|
|
17
|
+
const dotGit = path.join(folder, ".git");
|
|
18
|
+
let stat: fs.Stats | null = null;
|
|
19
|
+
try { stat = fs.statSync(dotGit); } catch { /* keep walking up */ }
|
|
20
|
+
if (stat) return headAt(stat.isDirectory() ? dotGit : linkedGitDir(dotGit, folder));
|
|
21
|
+
const parent = path.dirname(folder);
|
|
22
|
+
if (parent === folder) return null;
|
|
23
|
+
folder = parent;
|
|
24
|
+
}
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function linkedGitDir(dotGitFile: string, folder: string): string | null {
|
|
29
|
+
try {
|
|
30
|
+
const match = /^gitdir:\s*(.+?)\s*$/m.exec(fs.readFileSync(dotGitFile, "utf8").slice(0, 4096));
|
|
31
|
+
return match ? path.resolve(folder, match[1]) : null;
|
|
32
|
+
} catch { return null; }
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function headAt(gitDir: string | null): GitHead | null {
|
|
36
|
+
if (!gitDir) return null;
|
|
37
|
+
let head: string;
|
|
38
|
+
try { head = fs.readFileSync(path.join(gitDir, "HEAD"), "utf8").slice(0, 1024).trim(); } catch { return null; }
|
|
39
|
+
const ref = /^ref:\s*refs\/heads\/(.+)$/.exec(head);
|
|
40
|
+
if (ref) return { name: ref[1], detached: false };
|
|
41
|
+
if (/^[0-9a-f]{40,64}$/i.test(head)) return { name: head.slice(0, 7), detached: true };
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// One read per project folder while a catalog is built.
|
|
46
|
+
export function gitHeadReader(): (cwd: string) => GitHead | null {
|
|
47
|
+
const seen = new Map<string, GitHead | null>();
|
|
48
|
+
return (cwd) => {
|
|
49
|
+
if (!seen.has(cwd)) seen.set(cwd, readGitHead(cwd));
|
|
50
|
+
return seen.get(cwd)!;
|
|
51
|
+
};
|
|
52
|
+
}
|
|
@@ -6,6 +6,7 @@ import { workflowCommandPattern } from "../../piagent-core/runtime/workflows/web
|
|
|
6
6
|
import type { Catalog, SessionRow } from "../contracts/generated/session-catalog-v1.ts";
|
|
7
7
|
import type { MetadataSnapshot, SessionMetadata } from "./session-metadata-store.ts";
|
|
8
8
|
import { projectRefForCwd, sessionRefForPath } from "../ownership/session-refs.ts";
|
|
9
|
+
import { gitHeadReader, type GitHead } from "./git-head.ts";
|
|
9
10
|
|
|
10
11
|
export { projectRefForCwd, sessionRefForPath } from "../ownership/session-refs.ts";
|
|
11
12
|
|
|
@@ -105,7 +106,8 @@ function revision(key: Buffer, value: unknown): string {
|
|
|
105
106
|
}
|
|
106
107
|
|
|
107
108
|
function row(key: Buffer, info: PiSessionInfo, metadata: SessionMetadata | undefined, metadataReason: string | null,
|
|
108
|
-
ownership?: SessionOwnerProjection, sessionOptions?: SessionOptionProjection): SessionRow {
|
|
109
|
+
ownership?: SessionOwnerProjection, sessionOptions?: SessionOptionProjection, gitHead?: GitHead | null): SessionRow {
|
|
110
|
+
const gitBranch = gitHead ? { name: display(gitHead.name, 200, "HEAD"), detached: gitHead.detached } : null;
|
|
109
111
|
const projectLabel = display(info.cwd ? path.basename(info.cwd) : "", 120, "Unknown project");
|
|
110
112
|
const projected = projectedSessionTitle(info);
|
|
111
113
|
return {
|
|
@@ -123,6 +125,7 @@ function row(key: Buffer, info: PiSessionInfo, metadata: SessionMetadata | undef
|
|
|
123
125
|
unread: metadata?.unread ?? false,
|
|
124
126
|
composerAvailable: metadata?.archived ? false : ownership?.composerAvailable ?? false,
|
|
125
127
|
needsAttention: metadata?.archived ? false : ownership?.needsAttention ?? false,
|
|
128
|
+
...(gitBranch ? { gitBranch } : {}),
|
|
126
129
|
...(sessionOptions?.managedHelpers ? {managedHelpers:{...sessionOptions.managedHelpers,
|
|
127
130
|
active: ownership?.liveState === 'idle' ? 0 : ownership?.liveState === 'running' || ownership?.liveState === 'waiting-approval' ? sessionOptions.managedHelpers.active : null}} : {}),
|
|
128
131
|
...(sessionOptions?.managedThinkingLevels ? {managedThinkingLevels:sessionOptions.managedThinkingLevels} : {}),
|
|
@@ -138,6 +141,7 @@ function row(key: Buffer, info: PiSessionInfo, metadata: SessionMetadata | undef
|
|
|
138
141
|
: ownership?.owner ?? { kind: "none", ownerEpoch: null, gatewayInstanceRef: null, runtimeInstanceRef: null, continuity: "unknown" },
|
|
139
142
|
sessionRevision: revision(key, [info.path, info.modified.toISOString(), info.messageCount, info.name ?? null, metadata?.revision ?? null,
|
|
140
143
|
sessionOptions?.modelLabel ?? null, sessionOptions?.thinkingLevel ?? "unknown", sessionOptions?.managedHelpers, sessionOptions?.managedThinkingLevels, sessionOptions?.managedPermission ?? null, sessionOptions?.managedPlan, sessionOptions?.managedProcess,
|
|
144
|
+
gitBranch,
|
|
141
145
|
metadata?.archived ? "archived" : ownership ? [ownership.state, ownership.liveState, ownership.owner.kind,
|
|
142
146
|
ownership.owner.ownerEpoch, ownership.owner.runtimeInstanceRef, ownership.reasonCode] : "offline"]),
|
|
143
147
|
reasonCode: metadata?.archived ? metadataReason : ownership?.reasonCode ?? metadataReason
|
|
@@ -151,16 +155,18 @@ export async function buildSessionCatalog(options: {
|
|
|
151
155
|
readMetadata?(): MetadataSnapshot;
|
|
152
156
|
readOwnership?(sessionRef: string): SessionOwnerProjection;
|
|
153
157
|
readSessionOptions?(info: PiSessionInfo): SessionOptionProjection;
|
|
158
|
+
readGitHead?(cwd: string): GitHead | null;
|
|
154
159
|
limit?: number;
|
|
155
160
|
}): Promise<Catalog> {
|
|
156
161
|
const limit = Math.max(1, Math.min(200, options.limit ?? 200));
|
|
157
162
|
try {
|
|
158
163
|
const found = (await options.listSessions()).filter(isUserConversationSession);
|
|
164
|
+
const readHead = options.readGitHead ?? gitHeadReader();
|
|
159
165
|
const metadata = options.readMetadata?.() ?? { state: "ready", revision: null, sessions: new Map(), reasonCode: null };
|
|
160
166
|
const sessions = found.map((info) => {
|
|
161
167
|
const sessionRef = sessionRefForPath(options.key, info.path);
|
|
162
168
|
return row(options.key, info, metadata.sessions.get(sessionRef), metadata.reasonCode, options.readOwnership?.(sessionRef),
|
|
163
|
-
options.readSessionOptions?.(info));
|
|
169
|
+
options.readSessionOptions?.(info), readHead(info.cwd));
|
|
164
170
|
}).sort((left, right) => Number(right.pinned) - Number(left.pinned)
|
|
165
171
|
|| Date.parse(right.updatedAt) - Date.parse(left.updatedAt)).slice(0, limit);
|
|
166
172
|
return {
|
|
@@ -99,6 +99,9 @@
|
|
|
99
99
|
"managedProcess": { "type": "object", "additionalProperties": false, "required": ["outcome", "verified", "reviewed", "blockingOpen"], "properties": {
|
|
100
100
|
"outcome": { "enum": ["no_change", "interrupted", "disputed", "blocking_open", "unverified", "review_unavailable", "unreviewed", "clean"] },
|
|
101
101
|
"verified": { "type": "boolean" }, "reviewed": { "type": "boolean" }, "blockingOpen": { "type": "integer", "minimum": 0, "maximum": 1000 }, "planSkipped": { "const": true } } },
|
|
102
|
+
"gitBranch": { "type": "object", "additionalProperties": false, "required": ["name", "detached"], "properties": {
|
|
103
|
+
"name": { "type": "string", "minLength": 1, "maxLength": 200, "pattern": "^[^\\u0000-\\u001F\\u007F]*$" },
|
|
104
|
+
"detached": { "type": "boolean" } } },
|
|
102
105
|
"modelLabel": { "$ref": "common-v1.schema.json#/$defs/nullableDisplayText" },
|
|
103
106
|
"thinkingLevel": { "enum": ["off", "minimal", "low", "medium", "high", "xhigh", "max", "unknown"] },
|
|
104
107
|
"contextUsage": { "$ref": "#/$defs/contextUsage" },
|