@piagent/platform 1.32.0 → 1.33.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.
Files changed (74) hide show
  1. package/CHANGELOG.md +37 -0
  2. package/README.md +1 -1
  3. package/README.vi.md +1 -1
  4. package/docs/command-reference-vietnamese.md +3 -3
  5. package/docs/distribution-standard.md +8 -8
  6. package/docs/languages.json +2 -2
  7. package/docs/managed-local-acceptance.md +1 -0
  8. package/docs/operator-manual-vietnamese.md +10 -10
  9. package/docs/publishing-for-teams.md +2 -0
  10. package/docs/quickstart-vietnamese.md +1 -1
  11. package/docs/release-install-policy.md +6 -6
  12. package/docs/team-onboarding.md +7 -7
  13. package/docs-site/architecture.html +1 -1
  14. package/docs-site/benchmark.html +1 -1
  15. package/docs-site/commands.html +1 -1
  16. package/docs-site/content/en/index.html +4 -4
  17. package/docs-site/content/en/runtime.html +1 -1
  18. package/docs-site/content/en/whats-new.html +12 -0
  19. package/docs-site/content/index.html +4 -4
  20. package/docs-site/content/runtime.html +2 -2
  21. package/docs-site/content/whats-new.html +12 -0
  22. package/docs-site/context-engine.html +1 -1
  23. package/docs-site/ecosystem.html +1 -1
  24. package/docs-site/en/architecture.html +1 -1
  25. package/docs-site/en/benchmark.html +1 -1
  26. package/docs-site/en/commands.html +1 -1
  27. package/docs-site/en/context-engine.html +1 -1
  28. package/docs-site/en/ecosystem.html +1 -1
  29. package/docs-site/en/index.html +5 -5
  30. package/docs-site/en/mcp-approval.html +1 -1
  31. package/docs-site/en/mcp-auth.html +1 -1
  32. package/docs-site/en/mcp-servers.html +1 -1
  33. package/docs-site/en/mcp.html +1 -1
  34. package/docs-site/en/permissions.html +1 -1
  35. package/docs-site/en/profiles.html +1 -1
  36. package/docs-site/en/quickstart.html +1 -1
  37. package/docs-site/en/runtime.html +2 -2
  38. package/docs-site/en/scope.html +1 -1
  39. package/docs-site/en/security.html +1 -1
  40. package/docs-site/en/team.html +1 -1
  41. package/docs-site/en/whats-new.html +13 -1
  42. package/docs-site/en/windows.html +1 -1
  43. package/docs-site/en/workflows.html +1 -1
  44. package/docs-site/index.html +5 -5
  45. package/docs-site/mcp-approval.html +1 -1
  46. package/docs-site/mcp-auth.html +1 -1
  47. package/docs-site/mcp-servers.html +1 -1
  48. package/docs-site/mcp.html +1 -1
  49. package/docs-site/permissions.html +1 -1
  50. package/docs-site/profiles.html +1 -1
  51. package/docs-site/quickstart.html +1 -1
  52. package/docs-site/runtime.html +3 -3
  53. package/docs-site/scope.html +1 -1
  54. package/docs-site/security.html +1 -1
  55. package/docs-site/team.html +1 -1
  56. package/docs-site/whats-new.html +13 -1
  57. package/docs-site/windows.html +1 -1
  58. package/docs-site/workflows.html +1 -1
  59. package/evals/private-holdout-v1/public-exposure.v2.json +2 -2
  60. package/package.json +3 -3
  61. package/packages/piagent-core/managed/native-catalog.mjs +9 -2
  62. package/packages/piagent-core/package.json +2 -2
  63. package/packages/piagent-core/runtime/hooks/agent-start-hook.ts +3 -0
  64. package/packages/piagent-core/runtime/inspection/same-process-bridge-proof.ts +1 -1
  65. package/packages/piagent-core/runtime/session/system-prompt.ts +14 -0
  66. package/packages/piagent-webui/dist/client/assets/{MarkdownMessage-ZFXG_br8.js → MarkdownMessage-dCzZ2b6f.js} +1 -1
  67. package/packages/piagent-webui/dist/client/assets/{index-B3ODBFGj.js → index-CZ02zZjO.js} +5 -5
  68. package/packages/piagent-webui/dist/client/index.html +1 -1
  69. package/packages/piagent-webui/server/loopback-server.ts +1 -0
  70. package/packages/piagent-webui/server/session-auth.ts +16 -3
  71. package/scripts/check-runtime-advisories.mjs +2 -1
  72. package/scripts/runtime-advisory-exceptions.json +1 -26
  73. package/scripts/verify-local.sh +2 -2
  74. package/scripts/verify-release-identity.mjs +1 -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-B3ODBFGj.js"></script>
10
+ <script type="module" crossorigin src="/assets/index-CZ02zZjO.js"></script>
11
11
  <link rel="stylesheet" crossorigin href="/assets/index-B5XOKQy-.css">
12
12
  </head>
13
13
  <body>
@@ -112,6 +112,7 @@ export async function startLoopbackServer(options: {
112
112
  // Charging every tab and every prior launch to one localhost IP lets a
113
113
  // refresh or an unauthenticated local process lock out the active operator.
114
114
  const browserSession = auth.authenticate(request, now);
115
+ if (browserSession && auth.renew(browserSession, now)) response.setHeader("Set-Cookie", auth.cookieHeader(browserSession));
115
116
  const rateKey = browserSession ? `${remote}:${browserSession.id}` : `remote:${remote}`;
116
117
  for (const [key, value] of rates) if (now - value.windowStart >= 60_000) rates.delete(key);
117
118
  const rate = rates.get(rateKey) ?? { windowStart: now, requests: 0, bootstrapFailures: 0 };
@@ -20,20 +20,23 @@ function cookie(request: IncomingMessage, name: string): string | null {
20
20
  return null;
21
21
  }
22
22
 
23
- export type BrowserSession = { id: string; csrf: string; expiresAt: number };
23
+ export type BrowserSession = { id: string; csrf: string; expiresAt: number; startedAt: number };
24
24
 
25
25
  export class SessionAuthority {
26
26
  readonly #initialBootstrap: string;
27
27
  readonly #bootstrapTtlMs: number;
28
28
  readonly #sessionTtlMs: number;
29
+ readonly #sessionMaxMs: number;
29
30
  readonly #cookieSigningKey = randomBytes(32);
30
31
  #cookieName = SESSION_COOKIE;
31
32
  #bootstraps = new Map<string, number>();
32
33
  #sessions = new Map<string, BrowserSession>();
33
34
 
34
- constructor(options: { now?: number; bootstrapTtlMs?: number; sessionTtlMs?: number } = {}) {
35
+ constructor(options: { now?: number; bootstrapTtlMs?: number; sessionTtlMs?: number; sessionMaxMs?: number } = {}) {
35
36
  this.#bootstrapTtlMs = options.bootstrapTtlMs ?? 60_000;
37
+ // 8 hours unused; a tab in use is renewed (renew), up to 7 days.
36
38
  this.#sessionTtlMs = options.sessionTtlMs ?? 8 * 60 * 60_000;
39
+ this.#sessionMaxMs = options.sessionMaxMs ?? 7 * 24 * 60 * 60_000;
37
40
  this.#initialBootstrap = this.issueBootstrapCapability(options.now ?? Date.now());
38
41
  }
39
42
 
@@ -59,7 +62,7 @@ export class SessionAuthority {
59
62
  const match = [...this.#bootstraps].find(([value, createdAt]) => now <= createdAt + this.#bootstrapTtlMs && equal(candidate, value));
60
63
  if (!match) return null;
61
64
  this.#bootstraps.delete(match[0]);
62
- const session = { id: randomUUID(), csrf: secret(), expiresAt: now + this.#sessionTtlMs };
65
+ const session = { id: randomUUID(), csrf: secret(), expiresAt: now + this.#sessionTtlMs, startedAt: now };
63
66
  this.#sessions.set(session.id, session);
64
67
  return session;
65
68
  }
@@ -79,6 +82,16 @@ export class SessionAuthority {
79
82
  return session;
80
83
  }
81
84
 
85
+ // A session ended 8 hours after its launch even while its tab was in use:
86
+ // a turn that ran or hung that long ended on the expired screen. An open
87
+ // tab asks every minute, so past half its time a request moves the expiry
88
+ // on, within the cap; true when the caller must send the cookie again.
89
+ renew(session: BrowserSession, now = Date.now()): boolean {
90
+ const next = Math.min(now + this.#sessionTtlMs, session.startedAt + this.#sessionMaxMs);
91
+ if (next - session.expiresAt < this.#sessionTtlMs / 2) return false;
92
+ session.expiresAt = next; return true;
93
+ }
94
+
82
95
  authorizeMutation(request: IncomingMessage, now = Date.now()): BrowserSession | null {
83
96
  const session = this.authenticate(request, now);
84
97
  const csrf = request.headers["x-piagent-csrf"];
@@ -45,7 +45,8 @@ if (report.auditReportVersion !== 2) {
45
45
  process.exit(1);
46
46
  }
47
47
 
48
- const { exceptions } = JSON.parse(fs.readFileSync(new URL("./runtime-advisory-exceptions.json", import.meta.url), "utf8"));
48
+ // PIAGENT_ADVISORY_EXCEPTIONS points the tests at a fixture list.
49
+ const { exceptions } = JSON.parse(fs.readFileSync(process.env.PIAGENT_ADVISORY_EXCEPTIONS || new URL("./runtime-advisory-exceptions.json", import.meta.url), "utf8"));
49
50
  // A test seam for the day exceptions are judged on; the gate uses today (UTC).
50
51
  const today = process.env.PIAGENT_ADVISORY_TODAY ?? new Date().toISOString().slice(0, 10);
51
52
 
@@ -1,29 +1,4 @@
1
1
  {
2
2
  "version": 1,
3
- "exceptions": [
4
- {
5
- "id": "GHSA-q2hr-2g5m-vwhr",
6
- "package": "brace-expansion",
7
- "node": "node_modules/@earendil-works/pi-coding-agent/node_modules/brace-expansion",
8
- "decided": "2026-10-02",
9
- "until": "2026-10-31",
10
- "reason": "Denial of service (CPU) through a crafted brace pattern in a glob; no data exposure. brace-expansion 5.0.9 is pinned by the npm-shrinkwrap of every published Pi host (0.87.1 to 1.0.0), so no Piagent change can update it; 5.0.12 fixes it. Remove when a Pi host carries brace-expansion >= 5.0.12."
11
- },
12
- {
13
- "id": "GHSA-qhr7-859c-m2p7",
14
- "package": "brace-expansion",
15
- "node": "node_modules/@earendil-works/pi-coding-agent/node_modules/brace-expansion",
16
- "decided": "2026-10-02",
17
- "until": "2026-10-31",
18
- "reason": "Denial of service (stack exhaustion) through nested brace groups in a glob; no data exposure. Pinned by the Pi host's npm-shrinkwrap as above; fixed in 5.0.11."
19
- },
20
- {
21
- "id": "GHSA-6j4f-fj2g-mc7p",
22
- "package": "brace-expansion",
23
- "node": "node_modules/@earendil-works/pi-coding-agent/node_modules/brace-expansion",
24
- "decided": "2026-10-02",
25
- "until": "2026-10-31",
26
- "reason": "Denial of service (stack exhaustion) in parseCommaParts; no data exposure. Pinned by the Pi host's npm-shrinkwrap as above; fixed in 5.0.10."
27
- }
28
- ]
3
+ "exceptions": []
29
4
  }
@@ -641,8 +641,8 @@ if (!rootPkg.pi.subagents?.agents?.length) {
641
641
  throw new Error("root package.json missing pi.subagents.agents");
642
642
  }
643
643
  const expectedPeers = {
644
- "@earendil-works/pi-ai": "0.87.1",
645
- "@earendil-works/pi-coding-agent": "0.87.1",
644
+ "@earendil-works/pi-ai": "1.3.0",
645
+ "@earendil-works/pi-coding-agent": "1.3.0",
646
646
  typebox: "1.3.27"
647
647
  };
648
648
  for (const [name, version] of Object.entries(expectedPeers)) {
@@ -58,7 +58,7 @@ const packageLock = readJson("package-lock.json");
58
58
  const capabilityLock = readJson(".pi/piagent-profile.lock.json");
59
59
  const version = rootPackage.version;
60
60
  const expectedTag = `v${version}`;
61
- const supportedPiHost = "0.87.1";
61
+ const supportedPiHost = "1.3.0";
62
62
 
63
63
  // The package is published now, so the old private-forever rule is gone. What
64
64
  // still has to hold is that a scoped package cannot reach the registry as