@piagent/platform 1.9.3 → 1.11.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 (88) hide show
  1. package/CHANGELOG.md +44 -0
  2. package/README.md +1 -1
  3. package/README.vi.md +1 -1
  4. package/docs/command-reference-vietnamese.md +2 -2
  5. package/docs/distribution-standard.md +6 -6
  6. package/docs/en/architecture.md +1 -1
  7. package/docs/languages.json +4 -4
  8. package/docs/managed-local-acceptance.md +35 -0
  9. package/docs/operator-manual-vietnamese.md +7 -7
  10. package/docs/publishing-for-teams.md +2 -0
  11. package/docs/release-install-policy.md +2 -2
  12. package/docs/team-onboarding.md +2 -2
  13. package/docs/vi/architecture.md +1 -1
  14. package/docs-site/architecture.html +1 -1
  15. package/docs-site/benchmark.html +1 -1
  16. package/docs-site/commands.html +1 -1
  17. package/docs-site/content/en/index.html +4 -4
  18. package/docs-site/content/en/whats-new.html +22 -0
  19. package/docs-site/content/index.html +4 -4
  20. package/docs-site/content/whats-new.html +22 -0
  21. package/docs-site/context-engine.html +1 -1
  22. package/docs-site/ecosystem.html +1 -1
  23. package/docs-site/en/architecture.html +1 -1
  24. package/docs-site/en/benchmark.html +1 -1
  25. package/docs-site/en/commands.html +1 -1
  26. package/docs-site/en/context-engine.html +1 -1
  27. package/docs-site/en/ecosystem.html +1 -1
  28. package/docs-site/en/index.html +5 -5
  29. package/docs-site/en/mcp-approval.html +1 -1
  30. package/docs-site/en/mcp-auth.html +1 -1
  31. package/docs-site/en/mcp-servers.html +1 -1
  32. package/docs-site/en/mcp.html +1 -1
  33. package/docs-site/en/permissions.html +1 -1
  34. package/docs-site/en/profiles.html +1 -1
  35. package/docs-site/en/quickstart.html +1 -1
  36. package/docs-site/en/runtime.html +1 -1
  37. package/docs-site/en/scope.html +1 -1
  38. package/docs-site/en/security.html +1 -1
  39. package/docs-site/en/team.html +1 -1
  40. package/docs-site/en/whats-new.html +23 -1
  41. package/docs-site/en/workflows.html +1 -1
  42. package/docs-site/index.html +5 -5
  43. package/docs-site/mcp-approval.html +1 -1
  44. package/docs-site/mcp-auth.html +1 -1
  45. package/docs-site/mcp-servers.html +1 -1
  46. package/docs-site/mcp.html +1 -1
  47. package/docs-site/permissions.html +1 -1
  48. package/docs-site/profiles.html +1 -1
  49. package/docs-site/quickstart.html +1 -1
  50. package/docs-site/runtime.html +1 -1
  51. package/docs-site/scope.html +1 -1
  52. package/docs-site/security.html +1 -1
  53. package/docs-site/team.html +1 -1
  54. package/docs-site/whats-new.html +23 -1
  55. package/docs-site/workflows.html +1 -1
  56. package/evals/private-holdout-v1/public-exposure.v2.json +2 -2
  57. package/package.json +1 -1
  58. package/packages/piagent-core/managed/grant-share.mjs +18 -0
  59. package/packages/piagent-core/managed/helper-roles.mjs +8 -4
  60. package/packages/piagent-core/managed/helper-run.mjs +116 -0
  61. package/packages/piagent-core/managed/member-questions.d.mts +15 -0
  62. package/packages/piagent-core/managed/member-questions.mjs +178 -0
  63. package/packages/piagent-core/managed/objections.mjs +73 -0
  64. package/packages/piagent-core/managed/patch-snapshot.mjs +108 -22
  65. package/packages/piagent-core/managed/request-stream.mjs +54 -7
  66. package/packages/piagent-core/managed/review-snapshot-worker.mjs +31 -13
  67. package/packages/piagent-core/managed/session.mjs +33 -85
  68. package/packages/piagent-core/managed/web-search.mjs +23 -2
  69. package/packages/piagent-core/managed/workflow.mjs +137 -51
  70. package/packages/piagent-core/package.json +1 -1
  71. package/packages/piagent-core/runtime/managed-failure.mjs +6 -2
  72. package/packages/piagent-webui/dist/client/assets/{MarkdownMessage-IaGBsZNX.js → MarkdownMessage-D70xkf0d.js} +1 -1
  73. package/packages/piagent-webui/dist/client/assets/index-BuIJR5rd.js +228 -0
  74. package/packages/piagent-webui/dist/client/assets/{index-DgSmcnP8.css → index-Z91z6SlN.css} +1 -1
  75. package/packages/piagent-webui/dist/client/index.html +2 -2
  76. package/packages/piagent-webui/gateway/gateway-service.ts +15 -1
  77. package/packages/piagent-webui/gateway/managed-projection.ts +1 -1
  78. package/packages/piagent-webui/gateway/session-questions.ts +15 -0
  79. package/packages/piagent-webui/gateway/session-runtime-supervisor.ts +7 -2
  80. package/packages/piagent-webui/gateway/update-center.ts +201 -0
  81. package/packages/piagent-webui/server/http-security.ts +15 -1
  82. package/packages/piagent-webui/server/loopback-server.ts +9 -16
  83. package/packages/piagent-webui/server/member-routes.ts +99 -0
  84. package/packages/piagent-webui/server/transcript-projection.ts +17 -4
  85. package/schemas/piagent-webui/session-catalog-v1.schema.json +1 -1
  86. package/schemas/piagent-webui/transcript-v1.schema.json +29 -2
  87. package/scripts/dashboard-update-job.mjs +72 -0
  88. package/packages/piagent-webui/dist/client/assets/index-Cv5u0MN8.js +0 -228
@@ -1 +1 @@
1
- :root{color:#f4f4ef;font-synthesis:none;text-rendering:optimizelegibility;--bg:#050505;--surface:#101114;--surface-strong:#15171b;--surface-2:#15171b;--line:#24262d;--line-strong:#343740;--text:#f4f4ef;--muted:#a4a6ad;--quiet:#898c95;--accent:#d8ff7a;--accent-soft:#d8ff7a1c;--blue:#8fa7ff;--amber:#ffd166;--warning:#ffd166;--red:#ff8f8f;--danger:#ff8f8f;--positive:#8be9c8;--page-glow:#8be9c81a;background:#050505;font-family:Inter,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,sans-serif}:root[data-piagent-color-mode=light]{color:#1c2018;--bg:#f5f6f0;--surface:#fff;--surface-strong:#f0f2eb;--surface-2:#f0f2eb;--line:#dfe2d8;--line-strong:#c8cdc0;--text:#1c2018;--muted:#62685c;--quiet:#6b7165;--accent:#627400;--accent-soft:#6274001a;--blue:#506db7;--amber:#9c6200;--warning:#9c6200;--red:#c43f4c;--danger:#c43f4c;--positive:#14775f;--page-glow:#d8ff7a33;background:#f5f6f0}*{box-sizing:border-box}html{background:var(--bg)}body{min-width:320px;min-height:100vh;color:var(--text);background:radial-gradient(circle at 62% -20%, var(--page-glow) 0, transparent 36rem), var(--bg);margin:0}button,input,select,textarea{font:inherit}strong,h1,h2,h3,p{overflow-wrap:anywhere}button:focus-visible,a:focus-visible,summary:focus-visible{outline:2px solid var(--accent);outline-offset:3px}.skip-link{z-index:100;color:#08130f;background:var(--accent);border-radius:7px;padding:9px 12px;font-size:11px;font-weight:800;position:fixed;top:8px;left:8px;transform:translateY(-160%)}.skip-link:focus{transform:translateY(0)}.app-shell{min-height:100vh}.topbar{z-index:10;-webkit-backdrop-filter:blur(20px);backdrop-filter:blur(20px);background:#090c12db;border-bottom:1px solid #354052b8;grid-template-columns:1fr minmax(220px,auto) 1fr;align-items:center;gap:24px;min-height:68px;padding:0 28px;display:grid;position:sticky;top:0}.brand,.session-title,.topbar-actions,.runtime-strip>div,.task-meta,.health-line{align-items:center;display:flex}.brand{gap:11px}.brand>div,.session-title{flex-direction:column;display:flex}.brand strong{letter-spacing:.01em;font-size:15px}.brand small,.session-title small{color:var(--quiet);letter-spacing:.04em;font-size:11px}.brand-mark{width:34px;height:34px;color:var(--accent);background:var(--accent-soft);border:1px solid #64e0b56b;border-radius:10px;place-items:center;font-family:Georgia,serif;font-size:21px;display:grid}.session-title{text-align:center;min-width:0}.session-title strong{text-overflow:ellipsis;white-space:nowrap;max-width:360px;font-size:13px;overflow:hidden}.topbar-actions{justify-content:flex-end;gap:10px}.read-only-badge{border:1px solid var(--line);color:var(--muted);text-transform:uppercase;letter-spacing:.08em;border-radius:7px;padding:5px 9px;font-size:11px;font-weight:700}.workspace{width:min(1460px,100% - 48px);margin:0 auto;padding:28px 0 64px}.runtime-strip{border:1px solid var(--line);background:#11161fb8;border-radius:13px;grid-template-columns:repeat(6,minmax(0,1fr));display:grid;overflow:hidden}.runtime-strip>div{border-right:1px solid var(--line);flex-direction:column;justify-content:center;align-items:flex-start;gap:7px;min-width:0;min-height:70px;padding:13px 16px}.runtime-strip>div:last-child{border-right:0}.runtime-strip span:first-child{color:var(--quiet);letter-spacing:.1em;text-transform:uppercase;font-size:10px;font-weight:800}.runtime-strip strong{color:#dfe6f2;text-overflow:ellipsis;white-space:nowrap;max-width:100%;font-size:13px;overflow:hidden}.content-grid{grid-template-columns:minmax(0,1fr) 290px;align-items:start;gap:18px;margin-top:18px;display:grid}.surface{border:1px solid var(--line);background:var(--surface);border-radius:15px;box-shadow:0 22px 60px #0000001f}.task-dashboard{padding:clamp(20px,3vw,34px)}.task-heading{grid-template-columns:minmax(0,1fr) auto;align-items:start;gap:24px;display:grid}.section-kicker{color:var(--accent);letter-spacing:.14em;text-transform:uppercase;margin:0 0 7px;font-size:10px;font-weight:800}.task-heading h2,.task-empty h2{color:#f2f5fa;letter-spacing:-.035em;max-width:900px;margin:0;font-size:clamp(23px,3vw,38px);font-weight:650;line-height:1.18}.task-meta{color:var(--muted);flex-wrap:wrap;gap:12px;margin-top:15px;font-size:12px}.task-meta>span:not(.status-pill){border-left:1px solid var(--line-strong);padding-left:12px}.progress-number{text-align:right;min-width:116px}.progress-number strong{color:var(--accent);letter-spacing:-.05em;font-size:32px;font-weight:650;display:block}.progress-number span{color:var(--muted);font-size:11px}.progress-track{background:#242b36;border-radius:9px;height:5px;margin:26px 0 30px;overflow:hidden}.progress-track span{border-radius:inherit;background:linear-gradient(90deg,#45c89b,#7ee6bd);height:100%;transition:width .25s;display:block;box-shadow:0 0 20px #64e0b552}.status-pill{color:#aab4c4;white-space:nowrap;align-items:center;gap:6px;width:-moz-fit-content;width:fit-content;min-width:0;font-size:11px;font-weight:700;line-height:1.2;display:inline-flex}.status-dot{width:6px;height:6px;box-shadow:0 0 0 3px color-mix(in srgb, currentColor 13%, transparent);background:currentColor;border-radius:50%;flex:none}.tone-positive{color:var(--accent)}.tone-warning{color:var(--amber)}.tone-danger{color:var(--red)}.tone-info{color:var(--blue)}.tone-neutral{color:#919cad}.criteria-heading{justify-content:space-between;align-items:baseline;gap:16px;margin-bottom:12px;display:flex}.criteria-heading h2{letter-spacing:.01em;margin:0;font-size:13px}.criteria-heading>span{color:var(--quiet);font-size:11px}.criteria-list{gap:8px;margin:0;padding:0;list-style:none;display:grid}.criterion-card{border:1px solid var(--line);background:#090c1257;border-radius:11px;grid-template-columns:38px minmax(0,1fr) auto;align-items:center;gap:14px;min-height:72px;padding:12px 15px;display:grid}.criterion-index{border:1px solid color-mix(in srgb, currentColor 28%, transparent);background:color-mix(in srgb, currentColor 7%, transparent);border-radius:9px;place-items:center;width:32px;height:32px;font-size:10px;font-weight:800;display:grid}.criterion-copy{min-width:0}.criterion-copy>div{align-items:center;gap:9px;display:flex}.criterion-copy p{color:#dce3ed;margin:0;font-size:13px;line-height:1.45}.criterion-copy small{color:var(--quiet);margin-top:4px;font-size:10px;display:block}.critical-tag{color:var(--amber);letter-spacing:.08em;text-transform:uppercase;border:1px solid #efba633d;border-radius:4px;flex:none;padding:3px 6px;font-size:8px;font-weight:800}.blocker{background:#ff7f8612;border:1px solid #ff7f8640;border-radius:9px;grid-template-columns:auto 1fr;gap:14px;margin:-9px 0 24px;padding:12px 14px;display:grid}.blocker span{color:var(--red);text-transform:uppercase;font-size:10px;font-weight:800}.blocker p{color:#e6c3c6;margin:0;font-size:12px}.work-plan{border-top:1px solid var(--line);color:var(--muted);margin-top:16px;padding-top:15px}.work-plan summary{cursor:pointer;font-size:12px;font-weight:700}.work-plan ol{gap:9px;margin:14px 0 0;padding:0;list-style:none;display:grid}.work-plan li{grid-template-columns:100px 1fr;align-items:center;gap:12px;font-size:12px;display:grid}.context-rail{gap:18px;display:grid}.compact-panel{padding:18px}.compact-panel dl{margin:0}.compact-panel dl>div{border-bottom:1px solid var(--line);justify-content:space-between;align-items:center;gap:16px;min-height:39px;display:flex}.compact-panel dl>div:last-child{border-bottom:0}.compact-panel dt{color:var(--muted);font-size:11px}.compact-panel dd{color:#d9e0eb;text-overflow:ellipsis;white-space:nowrap;max-width:170px;margin:0;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:10px;overflow:hidden}.health-line{justify-content:space-between;gap:12px}.health-line>span{color:var(--quiet);font-size:10px}.health-issue{border-top:1px solid var(--line);color:var(--muted);margin:13px 0 0;padding-top:12px;font-size:11px;line-height:1.5}.task-empty{grid-template-columns:auto minmax(0,620px);place-content:center;gap:24px;min-height:420px;padding:48px;display:grid}.task-empty .empty-mark{width:64px;height:64px;color:var(--accent);background:var(--accent-soft);border:1px solid #64e0b547;border-radius:18px;place-items:center;font-family:Georgia,serif;font-size:38px;display:grid}.task-empty p:last-child{color:var(--muted);margin:13px 0 0;font-size:13px;line-height:1.6}.chat-panel{margin-top:18px;position:relative;overflow:hidden}.chat-panel[data-dragging]{outline:2px dashed var(--accent);outline-offset:-4px}.chat-drop-overlay{z-index:4;background:color-mix(in srgb, var(--surface-strong) 88%, transparent);pointer-events:none;text-align:center;border-radius:12px;align-content:center;justify-items:center;gap:6px;padding:16px;display:grid;position:absolute;inset:0}.chat-drop-overlay strong{color:var(--accent);font-size:13px}.chat-drop-overlay small{color:var(--quiet);font-size:10px}@media (prefers-reduced-motion:no-preference){.chat-drop-overlay{animation:.12s ease-out chat-drop-in}}@keyframes chat-drop-in{0%{opacity:0}to{opacity:1}}.chat-heading{border-bottom:1px solid var(--line);justify-content:space-between;align-items:center;gap:20px;min-height:78px;padding:17px 22px;display:flex}.chat-heading h2{letter-spacing:-.02em;margin:0;font-size:18px}.chat-heading>div:last-child{color:var(--quiet);align-items:center;gap:12px;font-size:10px;display:flex}.chat-read-state{color:var(--amber);background:#efba630f;border:1px solid #efba633b;border-radius:7px;padding:5px 8px}.chat-body{overscroll-behavior:contain;background:#090c1238;gap:11px;max-height:620px;padding:18px 20px;display:grid;overflow:auto}.chat-empty{color:var(--quiet);text-align:center;margin:0;padding:28px;font-size:11px}.load-older{border:1px solid var(--line);color:var(--muted);background:var(--surface);cursor:pointer;border-radius:7px;justify-self:center;padding:6px 10px;font-size:10px}.chat-message{border:1px solid var(--line);background:#111720;border-radius:11px;width:min(82%,900px);padding:12px 14px}.chat-message>div{justify-content:space-between;align-items:center;gap:12px;display:flex}.chat-message strong{color:#e3e9f2;letter-spacing:.04em;text-transform:uppercase;font-size:10px}.chat-message time,.chat-message small{color:var(--quiet);font-size:9px}.chat-message p{color:#cbd3df;white-space:pre-wrap;margin:7px 0 0;font-size:12px;line-height:1.6}.chat-message small{color:var(--amber);margin-top:7px;display:block}.chat-user{background:#75a7ff12;border-color:#75a7ff38;justify-self:end}.chat-assistant{justify-self:start}.chat-streaming{box-shadow:inset 2px 0 var(--accent);border-color:#64e0b542}.stream-indicator{color:var(--accent);font-size:9px}.chat-tool-live,.chat-tool-result{border:1px solid var(--line);width:-moz-fit-content;width:fit-content;max-width:82%;color:var(--quiet);background:#0d1219;border-radius:8px;align-items:center;gap:9px;padding:8px 11px;font-size:9px;display:flex}.chat-tool-live strong,.chat-tool-result strong{color:#bac4d2;font-family:ui-monospace,monospace;font-size:10px}.tool-spinner{border:1px solid var(--blue);border-right-color:#0000;border-radius:50%;width:7px;height:7px;animation:.8s linear infinite spin}.held-queue{border-top:1px solid var(--line);background:#efba6309;padding:12px 16px}.held-queue-heading{justify-content:space-between;align-items:center;gap:12px;margin-bottom:8px;display:flex}.held-queue-heading strong{color:#dce3ed;letter-spacing:.04em;text-transform:uppercase;font-size:10px}.held-queue-heading span{color:var(--amber);font-size:9px}.held-queue ol{gap:7px;max-height:260px;margin:0;padding:0;list-style:none;display:grid;overflow:auto}.held-queue li{border:1px solid var(--line);background:#0d1219;border-radius:8px;grid-template-columns:minmax(0,1fr) auto;gap:7px 12px;padding:9px 10px;display:grid}.held-queue li[data-state=quarantined]{border-color:#efba6340}.held-queue p{color:#c4cdd9;text-overflow:ellipsis;white-space:nowrap;margin:0;font-size:10px;line-height:1.45;overflow:hidden}.held-queue textarea{resize:vertical;border:1px solid var(--line);color:#dce3ed;background:#090d13;border-radius:7px;min-width:0;padding:8px 9px;font-size:10px}.held-queue li>div{align-items:start;gap:5px;display:flex}.held-queue button{border:1px solid var(--line);color:var(--muted);background:var(--surface);cursor:pointer;border-radius:6px;padding:4px 7px;font-size:9px}.held-queue button:disabled{cursor:not-allowed;opacity:.45}.held-queue small{color:var(--amber);grid-column:1/-1;font-size:8px}.chat-composer-preview{border-top:1px solid var(--line);background:#10151d;grid-template-columns:minmax(0,1fr) auto;gap:10px;padding:14px 16px;display:grid}.attachment-list{flex-wrap:wrap;grid-column:1/-1;gap:7px;margin:0;padding:0;list-style:none;display:flex}.attachment-list li{background:#75a7ff0f;border:1px solid #75a7ff38;border-radius:8px;align-items:center;gap:8px;max-width:260px;padding:7px 8px;display:flex}.attachment-list span{flex-direction:column;min-width:0;display:flex}.attachment-list strong{color:#dce3ed;text-overflow:ellipsis;white-space:nowrap;font-size:9px;overflow:hidden}.attachment-list small{color:var(--quiet);font-size:8px}.attachment-list button{min-width:0;padding:3px 6px;font-size:8px}.chat-composer-preview textarea{resize:none;border:1px solid var(--line);color:var(--quiet);background:#0b0f15;border-radius:9px;padding:10px 12px;font-size:11px}.chat-composer-preview button{border:1px solid var(--line);min-width:76px;color:var(--quiet);background:var(--surface-strong);border-radius:9px}.composer-actions{grid-template-columns:repeat(2,minmax(76px,auto));gap:6px;display:grid}.composer-actions .interrupt-send{color:var(--amber);grid-column:1/-1}.attachment-list li[data-kind=document]{background:#7ee7b212;border-color:#7ee7b24d}.attachment-picker{border:1px solid var(--line);width:-moz-fit-content;width:fit-content;color:var(--blue);cursor:pointer;border-radius:8px;align-items:center;padding:6px 9px;font-size:9px;display:inline-flex}.attachment-picker.disabled{cursor:not-allowed;opacity:.45}.attachment-picker input{opacity:0;width:1px;height:1px;position:absolute;overflow:hidden}.chat-composer-preview>small{color:var(--muted);grid-column:1/-1;font-size:9px}@keyframes spin{to{transform:rotate(360deg)}}.document-workspace{margin-top:0;overflow:hidden}.document-heading{border-bottom:1px solid var(--line);justify-content:space-between;align-items:center;gap:18px;min-height:82px;padding:18px 22px;display:flex}.document-heading h2{letter-spacing:-.02em;margin:0;font-size:18px}.document-heading>span{color:var(--quiet);letter-spacing:.06em;text-transform:uppercase;font-size:10px;font-weight:700}.document-body{grid-template-columns:minmax(248px,320px) minmax(0,1fr);min-height:520px;display:grid}.document-list{border-right:1px solid var(--line);overscroll-behavior:contain;flex-direction:column;gap:10px;min-width:0;max-height:720px;padding:14px;display:flex;overflow:auto}.document-group{flex-direction:column;gap:2px;min-width:0;display:flex}.document-group-heading{flex-direction:column;padding:8px 6px 4px;display:flex}.document-group-heading strong{color:var(--quiet);letter-spacing:.08em;text-transform:uppercase;font-size:9px;font-weight:800}.document-group-heading span{color:var(--muted);text-overflow:ellipsis;white-space:nowrap;font-size:9px;overflow:hidden}.document-row{cursor:pointer;text-align:left;background:0 0;border:0;border-radius:8px;align-items:center;gap:9px;min-width:0;padding:7px 8px;display:flex}.document-row-copy{flex-direction:column;flex:1;min-width:0;display:flex}.document-row-copy strong{color:#dce3ed;text-overflow:ellipsis;white-space:nowrap;font-size:11px;overflow:hidden}.document-row-copy small{color:var(--quiet);text-overflow:ellipsis;white-space:nowrap;text-align:left;direction:rtl;font-size:9px;overflow:hidden}.document-row-meta{color:var(--muted);flex-shrink:0;font-size:9px}.document-viewer{overscroll-behavior:contain;flex-direction:column;min-width:0;max-height:720px;display:flex;overflow:auto}.document-toolbar{z-index:2;border-bottom:1px solid var(--line);background:var(--surface-strong);justify-content:space-between;align-items:center;gap:14px;padding:12px 18px;display:flex;position:sticky;top:0}.document-toolbar strong{font-size:12px;display:block}.document-toolbar small{color:var(--quiet);text-overflow:ellipsis;white-space:nowrap;font-size:9px;display:block;overflow:hidden}.document-badges{flex-shrink:0;gap:6px;display:flex}.document-content{color:#dce3ed;min-width:0;padding:18px 22px;font-size:12px}.document-plain{font-family:var(--mono,ui-monospace, SFMono-Regular, Menlo, monospace);white-space:pre-wrap;word-break:break-word;margin:0;font-size:11px;line-height:1.7;overflow-x:auto}.document-table{border-collapse:collapse;width:100%;font-size:11px}.document-table th,.document-table td{border:1px solid var(--line);text-overflow:ellipsis;white-space:nowrap;max-width:320px;padding:5px 9px;overflow:hidden}.document-table th{background:var(--surface-strong);text-align:left;font-weight:750;position:sticky;top:0}.document-placeholder{height:100%;color:var(--muted);text-align:center;align-content:center;justify-items:center;gap:8px;padding:48px 24px;display:grid}.document-placeholder .MuiSvgIcon-root{opacity:.5;font-size:30px}.document-empty{color:var(--muted);padding:14px;font-size:11px}@media (max-width:900px){.document-body{grid-template-columns:1fr}.document-list{border-right:0;border-bottom:1px solid var(--line);max-height:300px}}:root[data-piagent-color-mode=light] .document-row-copy strong,:root[data-piagent-color-mode=light] .document-content{color:var(--text)}.source-workspace{margin-top:0;overflow:hidden}.source-heading{border-bottom:1px solid var(--line);justify-content:space-between;align-items:center;gap:18px;min-height:82px;padding:18px 22px;display:flex}.source-heading h2{letter-spacing:-.02em;margin:0;font-size:18px}.source-heading>span{color:var(--quiet);letter-spacing:.06em;text-transform:uppercase;font-size:10px;font-weight:700}.source-tabs{border-bottom:1px solid var(--line);background:#090c1252;min-width:0;padding:0 14px;display:flex}.source-tabs button{min-width:0;color:var(--muted);cursor:pointer;background:0 0;border:0;border-bottom:2px solid #0000;align-items:center;gap:9px;padding:14px 15px 12px;font-size:11px;display:flex}.source-tabs button:hover{color:#dce3ed}.source-tabs button[aria-selected=true]{border-bottom-color:var(--accent);color:var(--accent)}.source-tabs button b{min-width:20px;color:inherit;background:color-mix(in srgb, currentColor 10%, transparent);text-align:center;border-radius:8px;padding:2px 6px;font-size:9px}.source-body{grid-template-columns:minmax(248px,304px) minmax(0,1fr);min-height:480px;display:grid}.file-panel{border-right:1px solid var(--line);background:color-mix(in srgb, var(--bg) 72%, var(--surface));min-width:0}.file-panel-meta{border-bottom:1px solid var(--line);min-height:42px;color:var(--muted);justify-content:space-between;align-items:center;gap:14px;padding:0 14px;font-size:10px;display:flex}.file-panel-meta small{color:var(--quiet);letter-spacing:.08em;text-transform:uppercase;font-weight:800}.source-list-retry{color:var(--accent);font:inherit;background:0 0;border:1px solid;border-radius:6px;padding:4px 8px;font-weight:800}.file-list{overscroll-behavior:contain;max-height:620px;overflow:auto}.file-group-label{min-height:28px;color:var(--quiet);align-items:center;gap:6px;padding:5px 10px 3px}.file-group-label svg{width:14px;height:14px}.file-group-label span{min-width:0;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:9px;font-weight:700}.file-row{width:100%;min-height:54px;color:inherit;cursor:pointer;text-align:left;background:0 0;border:0;border-radius:7px;grid-template-columns:26px minmax(0,1fr) auto;align-items:center;gap:9px;margin:0;padding:8px 9px;display:grid}.file-row:hover{background:#75a7ff0d}.file-row[data-selected=true]{box-shadow:inset 2px 0 var(--accent);background:#64e0b513}.file-status{border:1px solid var(--line-strong);width:23px;height:23px;color:var(--muted);border-radius:6px;place-items:center;font-family:ui-monospace,monospace;font-size:10px;font-weight:900;display:grid}.status-A,.status-U{color:var(--accent);border-color:#64e0b54d}.status-M,.status-R{color:var(--blue);border-color:#75a7ff4d}.status-D,.status-C{color:var(--red);border-color:#ff7f864d}.file-name{flex-direction:column;min-width:0;display:flex}.file-name strong{color:var(--text);text-overflow:ellipsis;white-space:nowrap;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:11px;font-weight:600;overflow:hidden}.file-name small,.file-provenance,.file-evidence{color:var(--quiet);text-overflow:ellipsis;white-space:nowrap;font-size:9px;overflow:hidden}.file-provenance,.file-evidence{display:none}.file-stats{color:var(--muted);white-space:nowrap;font-family:ui-monospace,monospace;font-size:9px}.files-empty,.diff-empty{min-height:220px;color:var(--quiet);text-align:center;place-items:center;padding:28px;font-size:12px;display:grid}.diff-empty{background:repeating-linear-gradient(-45deg,#0000,#0000 13px,#ffffff03 13px 14px);min-height:100%}.error-state{color:var(--red)}.diff-viewer{background:var(--surface);min-width:0;overflow:auto}.diff-toolbar{border-bottom:1px solid var(--line);background:var(--surface);justify-content:space-between;align-items:center;gap:15px;min-height:55px;padding:9px 13px;display:flex}.diff-toolbar>div:first-child{align-items:center;gap:10px;min-width:0;display:flex}.diff-actions{align-items:center;gap:10px;display:flex}.review-state{color:var(--quiet);align-items:center;gap:8px;font-size:9px;display:flex}.review-state>span{white-space:nowrap}.review-state button{border:1px solid var(--line);color:#d8e1ee;background:#18202b;border-radius:7px;min-height:28px;padding:0 9px;font-size:9px}.review-state button:disabled{cursor:not-allowed;opacity:.45}.review-reviewed>span{color:var(--accent)}.review-stale>span{color:var(--amber)}.source-mutation-preview{color:#aeb9c8;align-items:center;gap:8px;max-width:290px;font-size:9px;display:flex}.source-mutation-preview>span{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.source-mutation-preview button{color:#b8ead5;background:#42c2921a;border:1px solid #42c29266;border-radius:7px;flex:none;min-height:28px;padding:0 10px;font-size:9px;font-weight:750}.source-mutation-preview button:disabled{cursor:not-allowed;opacity:.45}.source-revert-preview{color:#d3b29a;align-items:center;gap:8px;max-width:290px;font-size:9px;display:flex}.source-revert-preview>span{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.source-revert-preview button,.hunk-header .revert-action{color:#f3b4b8;background:#ff7f8617;border:1px solid #ff7f8661;border-radius:7px;flex:none;min-height:28px;padding:0 10px;font-size:9px;font-weight:750}.source-revert-preview button:disabled{cursor:not-allowed;opacity:.45}.source-open-action button{color:#c2d5f8;white-space:nowrap;background:#75a7ff1a;border:1px solid #75a7ff61;border-radius:7px;min-height:28px;padding:0 10px;font-size:9px;font-weight:750}.source-open-action button:disabled{cursor:wait;opacity:.55}.source-open-status{color:#bfd1f2;background:#75a7ff14;border-bottom:1px solid #75a7ff38;padding:8px 14px;font-size:10px}.commit-summary-panel{border-bottom:1px solid var(--line);background:linear-gradient(120deg,#42c29214,#75a7ff0d);grid-template-columns:minmax(230px,.8fr) minmax(300px,1.5fr);align-items:start;gap:18px;padding:14px 16px;display:grid}.commit-summary-panel h3{color:#edf2f7;margin:1px 0 4px;font-size:14px}.commit-summary-panel>div>span{color:var(--quiet);font-size:9px}.commit-summary-panel>button{color:#b8ead5;background:#42c2921a;border:1px solid #42c29266;border-radius:8px;justify-self:start;min-height:32px;padding:0 12px;font-size:10px;font-weight:750}.commit-summary-output{background:#070a0f8c;border:1px solid #75a7ff33;border-radius:9px;gap:5px;padding:10px 12px;display:grid}.commit-summary-output>strong{color:#edf2f7;font:700 12px ui-monospace,monospace}.commit-summary-output>code{color:#aeb9c8;white-space:pre-wrap;font-size:9px}.commit-summary-output>div{flex-wrap:wrap;gap:7px;margin-top:4px;display:flex}.commit-summary-output button{border:1px solid var(--line);color:#d8e1ee;background:#18202b;border-radius:7px;min-height:28px;padding:0 10px;font-size:9px}.commit-summary-output button:last-child{color:#efd19e;background:#ecb35b17;border-color:#ecb35b59}.commit-summary-status{color:#bfd1f2;grid-column:1/-1;margin:0;font-size:10px}.model-summary-dialog{border-color:#ecb35b57}.review-error{color:#f2b0b4;background:#ff687414;border-bottom:1px solid #ff68743d;padding:8px 14px;font-size:10px}.source-revert-error{color:#f2b0b4;background:#ff687414;border-top:1px solid #ff68743d;padding:9px 14px;font-size:10px}.source-action-warning{color:#f0d49a;background:#f6be5214;border-top:1px solid #f6be523d;padding:9px 14px;font-size:10px}.detail-reconciliation-warning{color:#f0d49a;background:#f6be5214;border-bottom:1px solid #f6be523d;justify-content:space-between;align-items:center;gap:12px;padding:8px 14px;font-size:10px;display:flex}.detail-reconciliation-warning button{color:inherit;background:0 0;border:1px solid;border-radius:6px;padding:4px 8px}.diff-toolbar strong{color:#e3e9f2;text-overflow:ellipsis;white-space:nowrap;font-family:ui-monospace,monospace;font-size:11px;overflow:hidden}.access-badge{text-transform:uppercase;font-size:9px;font-weight:800}.mode-switch{border:1px solid var(--line);background:var(--bg);border-radius:7px;padding:2px;display:flex}.mode-switch button{color:var(--quiet);cursor:pointer;background:0 0;border:0;border-radius:5px;padding:5px 8px;font-size:9px}.mode-switch button[aria-pressed=true]{color:#e5ebf4;background:var(--surface-strong)}.mode-switch .MuiToggleButton-root.Mui-selected{color:#eef3f8;background:#293241;box-shadow:inset 0 0 0 1px #75a7ff4d}.diff-context{border-bottom:1px solid var(--line);min-height:37px;color:var(--quiet);align-items:center;gap:14px;padding:0 14px;font-size:9px;display:flex}.diff-context .additions{color:var(--accent);margin-left:auto}.diff-context .deletions{color:var(--red)}.diff-hunk{min-width:0;overflow:auto}.hunk-header{color:var(--blue);background:#75a7ff12;border-bottom:1px solid #75a7ff24;justify-content:space-between;align-items:center;gap:12px;padding:6px 12px;font-family:ui-monospace,monospace;font-size:9px;display:flex;position:sticky;left:0}.hunk-header button{color:#bcd0f5;background:#75a7ff1a;border:1px solid #75a7ff57;border-radius:6px;min-height:25px;padding:0 9px;font:700 9px Inter,sans-serif}.hunk-header button:disabled{cursor:not-allowed;opacity:.45}.hunk-actions{align-items:center;gap:6px;display:inline-flex}.dialog-backdrop{z-index:80;-webkit-backdrop-filter:blur(6px);backdrop-filter:blur(6px);background:#030508c2;place-items:center;padding:20px;display:grid;position:fixed;inset:0}.confirm-dialog{background:#151a23;border:1px solid #ff7f8652;border-radius:15px;width:min(520px,100%);padding:24px;box-shadow:0 30px 100px #00000094}.confirm-dialog h3{color:#f1f4f8;margin:0;font-size:21px}.confirm-dialog>p:not(.section-kicker){color:#cbd3de;margin:14px 0;font-size:12px;line-height:1.65}.confirm-dialog code{color:#e6bdc0}.revert-diff{border:1px solid var(--line);background:#0c1016;border-radius:9px;max-height:min(300px,42vh);margin:14px 0;overflow:auto}.revert-diff section>div{color:#9bb9ec;background:#182130;padding:6px 9px;font:9px ui-monospace,monospace;position:sticky;top:0}.revert-line{white-space:pre-wrap;min-height:19px;padding:2px 9px;font:10px/1.5 ui-monospace,monospace;display:block;color:#b9c3d0!important}.revert-line b{width:14px;color:inherit;display:inline-block}.revert-added{background:#42c29214;color:#a7e1c9!important}.revert-deleted{background:#ff687414;color:#efafb3!important}.revert-meta{color:#8b96a8!important}.revert-safety{background:#efba630f;border:1px solid #efba6338;border-radius:9px;gap:5px;padding:12px;display:grid}.revert-safety strong{color:#efd19e;font-size:11px}.revert-safety span{color:#a99c87;font-size:10px}.confirm-actions{justify-content:flex-end;gap:9px;margin-top:20px;display:flex}.confirm-actions button{border:1px solid var(--line-strong);color:#cbd3df;background:#1b222d;border-radius:8px;min-height:34px;padding:0 14px;font-size:11px;font-weight:750}.confirm-actions .danger-action{color:#ffd2d5;background:#ff7f8621;border-color:#ff7f866b}.confirm-actions button:disabled{cursor:not-allowed;opacity:.48}.diff-line{grid-template-columns:42px 42px 18px minmax(500px,1fr);min-width:max-content;min-height:21px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:10px;line-height:21px;display:grid}.diff-line>span{color:#566173;text-align:right;-webkit-user-select:none;user-select:none;padding:0 7px}.diff-line b{color:var(--quiet);text-align:center;-webkit-user-select:none;user-select:none}.diff-line code,.split-line code{color:#bdc6d3;white-space:pre;padding:0 8px}.syntax-keyword{color:#c8a5ff;font-weight:650}.syntax-string{color:#a8d98b}.syntax-number{color:#efbd78}.syntax-comment{color:#778294;font-style:italic}.syntax-literal{color:#81b7ff}.syntax-property{color:#8ed8cf}.diff-added{background:#42c2921a}.diff-added code,.diff-added b{color:#a7e6ca}.diff-deleted{background:#ff68741a}.diff-deleted code,.diff-deleted b{color:#f2b0b4}.split-line{border-bottom:1px solid #242c394d;grid-template-columns:42px minmax(350px,1fr) 42px minmax(350px,1fr);min-width:860px;min-height:21px;font-family:ui-monospace,monospace;font-size:10px;line-height:21px;display:grid}.split-line>span{color:#566173;text-align:right;border-right:1px solid #242c39b3;padding:0 7px}.split-line code:nth-child(2){border-right:1px solid var(--line)}.unchanged-region{border-block:1px solid var(--line);color:var(--quiet);text-align:center;background:#10151d;padding:7px 12px;font-size:9px}.diff-fallback{border:1px solid var(--line);color:var(--muted);background:var(--surface);border-radius:9px;gap:6px;margin:18px;padding:16px;font-size:11px;display:grid}.diff-fallback strong{color:var(--amber);text-transform:uppercase;font-size:10px}.activity-panel{margin-top:18px;overflow:hidden}.panel-heading{border-bottom:1px solid var(--line);justify-content:space-between;align-items:center;gap:18px;min-height:82px;padding:18px 22px;display:flex}.panel-heading h2{letter-spacing:-.02em;margin:0;font-size:18px}.panel-heading>div:last-child{color:var(--quiet);align-items:center;gap:14px;font-size:10px;display:flex}.running-count{color:var(--blue)}.activity-list{display:grid}.activity-row{border-bottom:1px solid var(--line);background:#090c1233;grid-template-columns:10px minmax(0,1fr) 150px;align-items:start;gap:14px;padding:15px 18px;display:grid}.activity-row:last-child{border-bottom:0}.activity-state{width:7px;height:7px;box-shadow:0 0 0 4px color-mix(in srgb, currentColor 10%, transparent);background:currentColor;border-radius:50%;margin-top:5px}.activity-copy{min-width:0}.activity-copy>div{align-items:center;gap:9px;display:flex}.activity-copy strong{color:#dce3ed;font-size:12px}.activity-copy>div>span{border:1px solid var(--line);color:var(--quiet);letter-spacing:.06em;text-transform:uppercase;border-radius:4px;padding:2px 5px;font-size:8px;font-weight:800}.activity-copy>p{color:var(--muted);text-overflow:ellipsis;white-space:nowrap;margin:4px 0 0;font-family:ui-monospace,monospace;font-size:10px;line-height:1.45;overflow:hidden}.activity-result{text-align:right;grid-template-columns:1fr auto;align-items:center;gap:4px 9px;display:grid}.activity-result strong{color:#c9d1dd;font-size:10px}.activity-result>span{color:var(--quiet);font-family:ui-monospace,monospace;font-size:9px}.activity-result button{color:var(--blue);cursor:pointer;background:0 0;border:0;grid-column:1/-1;justify-self:end;padding:2px 0;font-size:9px}.log-preview{border:1px solid var(--line);color:#aeb8c7;white-space:pre-wrap;background:#090d13;border-radius:7px;margin-top:10px;padding:10px 12px;font-family:ui-monospace,monospace;font-size:9px;line-height:1.55}.log-preview small{color:var(--amber);margin-top:5px;display:block}.activity-empty{min-height:150px;color:var(--quiet);place-items:center;padding:24px;font-size:11px;display:grid}.panel-footnote{border-top:1px solid var(--line);color:var(--quiet);text-align:center;padding:9px 18px;font-size:9px}.evidence-section{margin-top:34px}.section-title-row{justify-content:space-between;align-items:end;gap:24px;margin-bottom:14px;padding:0 3px;display:flex}.section-title-row h2{letter-spacing:-.025em;margin:0;font-size:20px}.section-title-row>span{max-width:440px;color:var(--muted);text-align:right;text-overflow:ellipsis;white-space:nowrap;font-size:10px;overflow:hidden}.evidence-grid{grid-template-columns:repeat(4,minmax(0,1fr));gap:12px;display:grid}.evidence-card{min-width:0;min-height:250px;padding:18px}.evidence-card h3{color:#e1e7f0;min-height:38px;margin:0 0 16px;font-size:14px;line-height:1.35}.evidence-list{margin:0}.evidence-list>div{border-bottom:1px solid var(--line);grid-template-columns:88px minmax(0,1fr);align-items:center;gap:8px;min-height:38px;display:grid}.evidence-list>div:last-child{border-bottom:0}.evidence-list dt,.budget-grid dt{color:var(--quiet);font-size:9px}.evidence-list dd{color:var(--muted);text-align:right;text-overflow:ellipsis;white-space:nowrap;margin:0;font-family:ui-monospace,monospace;font-size:9px;overflow:hidden}.context-meter{background:#28303c;border-radius:4px;height:4px;margin:-3px 0 12px;overflow:hidden}.context-meter span{border-radius:inherit;background:linear-gradient(90deg, var(--blue), var(--accent));height:100%;display:block}.budget-grid{grid-template-columns:repeat(3,1fr);gap:7px;margin:0;display:grid}.budget-grid>div{border:1px solid var(--line);background:#090c1259;border-radius:8px;padding:12px 8px}.budget-grid dt{margin-bottom:5px}.budget-grid dd{color:#dbe2ec;margin:0;font-family:ui-monospace,monospace;font-size:12px}.card-note,.card-empty{color:var(--quiet);margin:14px 0 0;font-size:10px;line-height:1.5}.handoff-copy>p{color:var(--muted);margin:0 0 13px;font-size:11px;line-height:1.55}.handoff-blocker,.next-action{background:#ff7f860d;border:1px solid #ff7f8638;border-radius:7px;gap:4px;margin-top:9px;padding:9px 10px;display:grid}.next-action{background:#64e0b50d;border-color:#64e0b533}.handoff-blocker strong,.next-action strong{color:var(--red);letter-spacing:.08em;text-transform:uppercase;font-size:8px}.next-action strong{color:var(--accent)}.handoff-blocker span,.next-action span{color:#b7c0ce;font-size:10px;line-height:1.4}.loading-shell{width:min(560px,100% - 40px);margin:0 auto;padding-top:22vh}.loading-shell .brand-mark{border-radius:14px;width:48px;height:48px;margin-bottom:25px;font-size:29px}.loading-shell h1{color:#f0f3f8;letter-spacing:-.045em;margin:0;font-size:clamp(30px,6vw,50px);line-height:1.05}.loading-shell>p:not(.section-kicker){max-width:460px;color:var(--muted);margin:18px 0 22px;font-size:14px;line-height:1.6}.session-options{grid-template-columns:minmax(220px,.75fr) minmax(420px,1.25fr);gap:22px;padding:20px;display:grid}.session-options-copy h2{color:#edf1f7;margin:2px 0 8px;font-size:16px}.session-options-copy>p:last-child{max-width:520px;color:var(--quiet);margin:0;font-size:10px;line-height:1.55}.session-options-controls{grid-template-columns:minmax(0,1.4fr) minmax(130px,.6fr);align-items:end;gap:10px;display:grid}.session-options-controls>label:not(.effect-ack){color:var(--quiet);gap:5px;font-size:9px;display:grid}.session-options-controls select{border:1px solid var(--line);color:#e4e9f1;background:#121821;border-radius:7px;width:100%;min-height:36px;padding:0 10px}.effect-ack{color:#b9c1cd;grid-column:1/-1;align-items:flex-start;gap:8px;font-size:10px;line-height:1.4;display:flex}.effect-ack input{accent-color:var(--accent);margin-top:1px}.session-option-actions{grid-column:1/-1;gap:8px;display:flex}.session-option-actions button{border:1px solid var(--line);color:#dbe2ec;background:#1a222d;border-radius:7px;min-height:34px;padding:0 13px}.session-option-actions button:disabled{opacity:.42}.session-options-controls>small{color:var(--quiet);grid-column:1/-1;font-size:9px}.session-options-unavailable{color:var(--quiet);flex-direction:column;justify-content:center;gap:5px;font-size:10px;display:flex}.session-options-unavailable strong{color:#d7dde7;font-size:12px}.lifecycle-panel{grid-template-columns:minmax(260px,1fr) minmax(150px,auto) minmax(360px,auto);align-items:center;gap:20px;margin-top:18px;padding:18px 20px;display:grid}.lifecycle-copy h2{color:#edf1f7;margin:2px 0 7px;font-size:16px}.lifecycle-copy>p:last-child{max-width:620px;color:var(--quiet);margin:0;font-size:10px;line-height:1.55}.lifecycle-state{border-left:1px solid var(--line);gap:4px;min-width:150px;padding-left:18px;display:grid}.lifecycle-state>span{color:var(--quiet);text-transform:uppercase;font-size:9px;font-weight:800}.lifecycle-state strong{color:#e5eaf2;font-size:12px}.lifecycle-state small{color:var(--quiet);font-size:9px}.lifecycle-actions{flex-wrap:wrap;justify-content:flex-end;gap:8px;display:flex}.lifecycle-actions button{cursor:pointer;border-radius:7px;min-height:36px;padding:0 13px;font-size:10px;font-weight:750}.lifecycle-actions button:disabled{cursor:not-allowed;opacity:.4}.primary-action{color:#07130f;background:var(--accent);border:1px solid #3cae88}.lifecycle-result{border-radius:7px;grid-column:1/-1;margin:-6px 0 0;padding:9px 11px;font-size:10px;line-height:1.45}.lifecycle-result.result-ok{color:#bcebd9;background:#64e0b512}.lifecycle-result.result-warning{color:#efd09b;background:#efba6314}.approval-stack{gap:12px;display:grid}.approval-card{background:linear-gradient(135deg,#412518eb,#19181bf5);border:1px solid #70462e;border-radius:13px;padding:20px;overflow:hidden;box-shadow:0 16px 42px #00000038}.approval-card.risk-critical,.approval-card.risk-high{border-color:#9d4d3f}.approval-card>header,.approval-card>footer{justify-content:space-between;align-items:center;gap:12px;display:flex}.approval-card h2{color:#fff1e7;margin:2px 0 0;font-size:18px}.approval-risk{color:#ffbd91;text-transform:uppercase;border:1px solid #ffad7c59;border-radius:999px;padding:5px 9px;font-size:10px;font-weight:800}.approval-reason{color:#f1d8c7;margin:13px 0;font-size:12px;line-height:1.55}.approval-preview{color:#f3e7df;white-space:pre-wrap;word-break:break-word;background:#141316;border:1px solid #ffffff17;border-radius:8px;max-height:180px;margin:0 0 14px;padding:12px;font:11px/1.55 ui-monospace,SFMono-Regular,Menlo,monospace;overflow:auto}.approval-facts{grid-template-columns:repeat(3,minmax(0,1fr));gap:8px;margin:0 0 13px;display:grid}.approval-facts>div{background:#ffffff09;border-radius:7px;min-width:0;padding:9px}.approval-facts dt{color:#bca393;text-transform:uppercase;font-size:9px;font-weight:800}.approval-facts dd{color:#f0e7e1;text-overflow:ellipsis;margin:4px 0 0;font-size:10px;overflow:hidden}.approval-targets,.approval-consequences{color:#d9c8bc;font-size:10px;line-height:1.55}.approval-targets ul{margin:6px 0 12px;padding-left:18px}.approval-consequences{grid-template-columns:1fr 1fr;gap:10px;margin:12px 0;display:grid}.approval-consequences p{background:#ffffff09;border-radius:7px;margin:0;padding:10px}.approval-card>footer{justify-content:flex-end;padding-top:4px}.approval-card button{border-radius:7px;min-height:36px;padding:0 14px;font-weight:750}.secondary-action{border:1px solid var(--line);color:#dbe2ec;background:#1a222d}.danger-action{color:#fff5ee;background:#8f3e31;border:1px solid #c56b52}.approval-card button:disabled{cursor:wait;opacity:.48}.task-run-index,.release-monitor{margin-top:18px;overflow:hidden}.release-monitor .source-heading button{border:1px solid var(--line);color:var(--text);background:var(--surface-2);border-radius:8px;padding:8px 12px}.release-monitor .source-heading button:disabled{opacity:.55}.release-monitor-grid{border-top:1px solid var(--line);grid-template-columns:minmax(0,1.15fr) minmax(320px,.85fr);display:grid}.release-monitor-column+.release-monitor-column{border-left:1px solid var(--line)}.release-monitor-column>header{border-bottom:1px solid var(--line);justify-content:space-between;align-items:center;gap:14px;padding:16px 20px;display:flex}.release-monitor-column h3{margin:2px 0 0}.benchmark-run-card{border-bottom:1px solid var(--line);padding:14px 20px}.benchmark-run-card>div:first-child{justify-content:space-between;align-items:center;gap:12px;display:flex}.benchmark-run-card small{color:var(--muted);margin-top:4px;display:block}.benchmark-run-facts{color:var(--muted);flex-wrap:wrap;gap:8px 18px;margin-top:9px;font-size:12px;display:flex}.release-readiness-facts{margin:0;padding:4px 20px 12px}.release-readiness-facts>div{border-bottom:1px solid var(--line);justify-content:space-between;align-items:center;gap:16px;padding:10px 0;display:flex}.release-readiness-facts dt{color:var(--muted)}.release-readiness-facts dd{text-align:right;margin:0}.release-blockers{border:1px solid color-mix(in srgb, var(--warning) 35%, var(--line));background:color-mix(in srgb, var(--warning) 7%, transparent);border-radius:8px;margin:0 20px 14px;padding:12px 14px}.release-blockers ul{color:var(--muted);margin:8px 0 0;padding-left:18px}.release-blockers li+li{margin-top:5px}.task-index-controls{border-bottom:1px solid var(--line);gap:8px;padding:0 20px 16px;display:flex}.task-index-controls button{border:1px solid var(--line);color:var(--muted);background:var(--surface-2);border-radius:999px;padding:7px 12px}.task-index-controls button[aria-pressed=true]{color:var(--text);border-color:var(--accent);background:color-mix(in srgb, var(--accent) 15%, var(--surface-2))}.task-run-list{display:grid}.task-run-card{border-bottom:1px solid var(--line);grid-template-columns:minmax(0,1fr) auto;align-items:center;gap:18px;padding:15px 20px;display:grid}.task-run-card[data-active=true]{box-shadow:inset 3px 0 var(--accent);background:color-mix(in srgb, var(--accent) 5%, transparent)}.task-run-card[data-selected=true]{outline:1px solid var(--accent);outline-offset:-1px}.task-run-main{min-width:0}.task-run-main>div{align-items:center;gap:9px;display:flex}.task-run-main strong,.task-run-main small{text-overflow:ellipsis;white-space:nowrap;display:block;overflow:hidden}.task-run-main small,.task-run-meta{color:var(--muted)}.active-run-tag{border:1px solid var(--accent);color:var(--accent);border-radius:999px;padding:2px 7px;font-size:11px}.task-run-meta{justify-content:flex-end;align-items:center;gap:12px;font-size:12px;display:flex}.task-index-empty,.task-index-warning{color:var(--muted);margin:0;padding:18px 20px}.task-index-warning{border-top:1px solid var(--line);color:var(--warning)}.task-run-meta button{border:1px solid var(--line);color:var(--text);background:var(--surface-2);border-radius:7px;padding:6px 9px}.task-run-meta button[aria-pressed=true]{border-color:var(--accent);color:var(--accent)}.task-timeline{border-top:1px solid var(--line)}.task-timeline>header{border-bottom:1px solid var(--line);justify-content:space-between;align-items:center;gap:16px;padding:18px 20px;display:flex}.task-timeline h3{margin:2px 0 0}.timeline-continuity{color:var(--muted);border-bottom:1px solid var(--line);flex-wrap:wrap;gap:10px 24px;padding:12px 20px;display:flex}.timeline-events{margin:0;padding:0;list-style:none}.timeline-events li{border-bottom:1px solid var(--line);grid-template-columns:12px minmax(0,1fr) auto;align-items:start;gap:12px;padding:13px 20px;display:grid}.timeline-events small,.timeline-events p{color:var(--muted);margin:3px 0 0;display:block}.timeline-dot{background:var(--muted);border-radius:999px;width:9px;height:9px;margin-top:5px}.timeline-dot.tone-positive{background:var(--positive)}.timeline-dot.tone-warning{background:var(--warning)}.timeline-dot.tone-danger{background:var(--danger)}.timeline-dot.tone-info{background:var(--accent)}.recovery-summary{grid-template-columns:repeat(4,minmax(0,1fr));display:grid}.retained-content-note{color:var(--muted);border-bottom:1px solid var(--line);margin:0;padding:10px 20px;font-size:12px}.next-action-card{border-bottom:1px solid var(--line);background:color-mix(in srgb, var(--accent) 7%, transparent);grid-template-columns:minmax(180px,.45fr) 1fr auto;align-items:center;gap:18px;padding:16px 20px;display:grid}.next-action-card span,.next-action-card strong{display:block}.next-action-card span,.next-action-card p,.next-action-card small{color:var(--muted)}.next-action-card p{margin:0}.handoff-summary{grid-template-columns:repeat(4,minmax(0,1fr));display:grid}.workspace-stack>.surface,.workspace-view>.surface,.workspace-stack>.evidence-section,.workspace-view>.evidence-section{margin-top:0}:root[data-piagent-color-mode=light] .task-heading h2,:root[data-piagent-color-mode=light] .task-empty h2,:root[data-piagent-color-mode=light] .criterion-copy p,:root[data-piagent-color-mode=light] .compact-panel dd,:root[data-piagent-color-mode=light] .chat-heading h2,:root[data-piagent-color-mode=light] .chat-message strong,:root[data-piagent-color-mode=light] .chat-message p,:root[data-piagent-color-mode=light] .attachment-list strong,:root[data-piagent-color-mode=light] .diff-toolbar strong,:root[data-piagent-color-mode=light] .activity-copy strong,:root[data-piagent-color-mode=light] .activity-result strong,:root[data-piagent-color-mode=light] .evidence-card h3,:root[data-piagent-color-mode=light] .budget-grid dd,:root[data-piagent-color-mode=light] .session-options-copy h2,:root[data-piagent-color-mode=light] .session-options-unavailable strong,:root[data-piagent-color-mode=light] .lifecycle-copy h2,:root[data-piagent-color-mode=light] .lifecycle-state strong{color:var(--text)}:root[data-piagent-color-mode=light] .chat-body,:root[data-piagent-color-mode=light] .activity-row{background:#62740006}:root[data-piagent-color-mode=light] .source-tabs{background:#f8f9f4}:root[data-piagent-color-mode=light] .source-tabs button:hover{color:var(--text)}:root[data-piagent-color-mode=light] .source-action-warning,:root[data-piagent-color-mode=light] .detail-reconciliation-warning{color:#755000;background:#ab740014}:root[data-piagent-color-mode=light] .chat-message,:root[data-piagent-color-mode=light] .chat-tool-live,:root[data-piagent-color-mode=light] .chat-tool-result,:root[data-piagent-color-mode=light] .held-queue li,:root[data-piagent-color-mode=light] .log-preview{color:var(--text);background:#fafbf7}:root[data-piagent-color-mode=light] .chat-user{background:#506db712}:root[data-piagent-color-mode=light] .chat-composer-preview,:root[data-piagent-color-mode=light] .unchanged-region{background:#f7f8f3}:root[data-piagent-color-mode=light] .chat-composer-preview textarea,:root[data-piagent-color-mode=light] .session-options-controls select{color:var(--text);background:#fff}:root[data-piagent-color-mode=light] .review-state button,:root[data-piagent-color-mode=light] .commit-summary-output button,:root[data-piagent-color-mode=light] .confirm-actions button,:root[data-piagent-color-mode=light] .session-option-actions button{color:var(--text);background:var(--surface-strong)}:root[data-piagent-color-mode=light] .commit-summary-panel h3,:root[data-piagent-color-mode=light] .commit-summary-output>strong{color:var(--text)}:root[data-piagent-color-mode=light] .commit-summary-output{background:#ffffffbf}:root[data-piagent-color-mode=light] .diff-line code,:root[data-piagent-color-mode=light] .split-line code{color:#3f443a}:root[data-piagent-color-mode=light] .diff-line>span,:root[data-piagent-color-mode=light] .split-line>span{color:#92988d}:root[data-piagent-color-mode=light] .syntax-keyword{color:#6e3bb2}:root[data-piagent-color-mode=light] .syntax-string{color:#317040}:root[data-piagent-color-mode=light] .syntax-number{color:#9b5a12}:root[data-piagent-color-mode=light] .syntax-comment{color:#7b8176}:root[data-piagent-color-mode=light] .syntax-literal{color:#235fa8}:root[data-piagent-color-mode=light] .syntax-property{color:#176f69}:root[data-piagent-color-mode=light] .mode-switch .MuiToggleButton-root.Mui-selected{color:#1c2018;background:#e8ecdf}:root[data-piagent-color-mode=light] .diff-added{background:#14775f1a}:root[data-piagent-color-mode=light] .diff-added code,:root[data-piagent-color-mode=light] .diff-added b{color:#0a654e}:root[data-piagent-color-mode=light] .diff-deleted{background:#c43f4c1a}:root[data-piagent-color-mode=light] .diff-deleted code,:root[data-piagent-color-mode=light] .diff-deleted b{color:#a02734}:root[data-piagent-color-mode=light] .confirm-dialog{color:var(--text);background:#fff}:root[data-piagent-color-mode=light] .confirm-dialog h3,:root[data-piagent-color-mode=light] .confirm-dialog>p:not(.section-kicker){color:var(--text)}:root[data-piagent-color-mode=light] .revert-diff{background:#f8f9f4}:root[data-piagent-color-mode=light] .approval-card{color:#3f2b20;background:linear-gradient(135deg,#fff7ef,#fff);border-color:#d7b18f}:root[data-piagent-color-mode=light] .approval-card h2,:root[data-piagent-color-mode=light] .approval-preview,:root[data-piagent-color-mode=light] .approval-facts dd{color:#3f2b20}:root[data-piagent-color-mode=light] .approval-preview{background:#fffaf5}:root[data-piagent-color-mode=light] .approval-reason,:root[data-piagent-color-mode=light] .approval-targets,:root[data-piagent-color-mode=light] .approval-consequences{color:#6d4d3c}@media (max-width:1080px){.lifecycle-panel{grid-template-columns:1fr auto}.lifecycle-actions{grid-column:1/-1;justify-content:flex-start}.lifecycle-result{grid-column:1/-1}.runtime-strip{grid-template-columns:repeat(3,1fr)}.runtime-strip>div:nth-child(3){border-right:0}.runtime-strip>div:nth-child(-n+3){border-bottom:1px solid var(--line)}.content-grid{grid-template-columns:1fr}.context-rail,.evidence-grid{grid-template-columns:repeat(2,1fr)}}@media (max-width:899px){.source-body{grid-template-columns:1fr}.file-panel{border-right:0;border-bottom:1px solid var(--line)}.file-list{max-height:300px}.diff-empty{min-height:300px}}@media (max-width:720px){.release-monitor-grid{grid-template-columns:1fr}.release-monitor-column+.release-monitor-column{border-left:0;border-top:1px solid var(--line)}.recovery-summary{grid-template-columns:repeat(2,minmax(0,1fr))}.handoff-summary,.next-action-card,.commit-summary-panel,.approval-facts,.approval-consequences{grid-template-columns:1fr}.approval-card>header,.approval-card>footer{flex-direction:column;align-items:flex-start}.approval-card>footer button{width:100%}.session-options,.session-options-controls{grid-template-columns:1fr}.effect-ack,.session-option-actions,.session-options-controls>small{grid-column:1}.lifecycle-panel{grid-template-columns:1fr;align-items:stretch}.lifecycle-state{border-left:0;padding:0}.lifecycle-actions{grid-column:1}.lifecycle-actions button{flex:150px}.lifecycle-result{grid-column:1}.topbar{grid-template-columns:1fr auto;min-height:60px;padding:0 16px}.session-title,.read-only-badge{display:none}.workspace{width:min(100% - 24px,1460px);padding-top:12px}.runtime-strip{grid-template-columns:repeat(2,1fr)}.runtime-strip>div{border-bottom:1px solid var(--line);min-height:62px;padding:11px}.runtime-strip>div:nth-child(2n){border-right:0}.runtime-strip>div:nth-last-child(-n+2){border-bottom:0}.task-dashboard{padding:19px 14px}.chat-heading{flex-direction:column;align-items:flex-start;padding:15px}.chat-heading>div:last-child{flex-direction:column;align-items:flex-start}.chat-body{padding:13px}.chat-message{width:94%}.chat-composer-preview,.task-heading{grid-template-columns:1fr}.progress-number{text-align:left;align-items:baseline;gap:10px;display:flex}.progress-number strong{font-size:25px}.progress-track{margin:18px 0 24px}.criterion-card{grid-template-columns:32px minmax(0,1fr);gap:10px}.criterion-card>.status-pill{grid-column:2}.criterion-copy>div{flex-direction:column;align-items:flex-start;gap:5px}.context-rail{grid-template-columns:1fr}.task-empty{grid-template-columns:1fr;min-height:340px;padding:28px 22px}.source-tabs{padding:0 8px;overflow-x:auto}.source-tabs button{flex:none}.source-heading{padding:16px}.source-heading>span,.file-provenance,.file-evidence{display:none}.file-row{grid-template-columns:26px minmax(0,1fr) auto}.diff-toolbar{flex-direction:column;align-items:flex-start}.panel-heading{flex-direction:column;align-items:flex-start;padding:16px}.activity-row{grid-template-columns:10px minmax(0,1fr)}.activity-result{text-align:left;grid-column:2;grid-template-columns:auto auto 1fr}.activity-result button{grid-column:auto;justify-self:end}.section-title-row{flex-direction:column;align-items:flex-start;gap:8px}.section-title-row>span{text-align:left;max-width:100%}.evidence-grid{grid-template-columns:1fr}.evidence-card{min-height:auto}.task-run-card{grid-template-columns:1fr;gap:9px}.task-run-meta{flex-wrap:wrap;justify-content:flex-start}}@media (prefers-reduced-motion:reduce){*,:before,:after{scroll-behavior:auto!important;transition:none!important;animation:none!important}}@media (forced-colors:active){.status-dot,.activity-state,.progress-track span,.context-meter span{forced-color-adjust:none;background:highlight}.file-row[data-selected=true],.source-tabs button[aria-selected=true]{outline:2px solid highlight}}@keyframes piagent-pulse{0%,to{opacity:1}50%{opacity:.3}}@media (prefers-reduced-motion:reduce){*{animation-duration:.01ms!important;animation-iteration-count:1!important}}
1
+ :root{color:#f4f4ef;font-synthesis:none;text-rendering:optimizelegibility;--bg:#050505;--surface:#101114;--surface-strong:#15171b;--surface-2:#15171b;--line:#24262d;--line-strong:#343740;--text:#f4f4ef;--muted:#a4a6ad;--quiet:#898c95;--accent:#d8ff7a;--accent-soft:#d8ff7a1c;--blue:#8fa7ff;--amber:#ffd166;--warning:#ffd166;--red:#ff8f8f;--danger:#ff8f8f;--positive:#8be9c8;--page-glow:#8be9c81a;background:#050505;font-family:Inter,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,sans-serif}:root[data-piagent-color-mode=light]{color:#1c2018;--bg:#f5f6f0;--surface:#fff;--surface-strong:#f0f2eb;--surface-2:#f0f2eb;--line:#dfe2d8;--line-strong:#c8cdc0;--text:#1c2018;--muted:#62685c;--quiet:#6b7165;--accent:#627400;--accent-soft:#6274001a;--blue:#506db7;--amber:#9c6200;--warning:#9c6200;--red:#c43f4c;--danger:#c43f4c;--positive:#14775f;--page-glow:#d8ff7a33;background:#f5f6f0}*{box-sizing:border-box}html{background:var(--bg)}body{min-width:320px;min-height:100vh;color:var(--text);background:radial-gradient(circle at 62% -20%, var(--page-glow) 0, transparent 36rem), var(--bg);margin:0}button,input,select,textarea{font:inherit}strong,h1,h2,h3,p{overflow-wrap:anywhere}button:focus-visible,a:focus-visible,summary:focus-visible{outline:2px solid var(--accent);outline-offset:3px}.skip-link{z-index:100;color:#08130f;background:var(--accent);border-radius:7px;padding:9px 12px;font-size:11px;font-weight:800;position:fixed;top:8px;left:8px;transform:translateY(-160%)}.skip-link:focus{transform:translateY(0)}.app-shell{min-height:100vh}.topbar{z-index:10;-webkit-backdrop-filter:blur(20px);backdrop-filter:blur(20px);background:#090c12db;border-bottom:1px solid #354052b8;grid-template-columns:1fr minmax(220px,auto) 1fr;align-items:center;gap:24px;min-height:68px;padding:0 28px;display:grid;position:sticky;top:0}.brand,.session-title,.topbar-actions,.runtime-strip>div,.task-meta,.health-line{align-items:center;display:flex}.brand{gap:11px}.brand>div,.session-title{flex-direction:column;display:flex}.brand strong{letter-spacing:.01em;font-size:15px}.brand small,.session-title small{color:var(--quiet);letter-spacing:.04em;font-size:11px}.brand-mark{width:34px;height:34px;color:var(--accent);background:var(--accent-soft);border:1px solid #64e0b56b;border-radius:10px;place-items:center;font-family:Georgia,serif;font-size:21px;display:grid}.session-title{text-align:center;min-width:0}.session-title strong{text-overflow:ellipsis;white-space:nowrap;max-width:360px;font-size:13px;overflow:hidden}.topbar-actions{justify-content:flex-end;gap:10px}.read-only-badge{border:1px solid var(--line);color:var(--muted);text-transform:uppercase;letter-spacing:.08em;border-radius:7px;padding:5px 9px;font-size:11px;font-weight:700}.workspace{width:min(1460px,100% - 48px);margin:0 auto;padding:28px 0 64px}.runtime-strip{border:1px solid var(--line);background:#11161fb8;border-radius:13px;grid-template-columns:repeat(6,minmax(0,1fr));display:grid;overflow:hidden}.runtime-strip>div{border-right:1px solid var(--line);flex-direction:column;justify-content:center;align-items:flex-start;gap:7px;min-width:0;min-height:70px;padding:13px 16px}.runtime-strip>div:last-child{border-right:0}.runtime-strip span:first-child{color:var(--quiet);letter-spacing:.1em;text-transform:uppercase;font-size:10px;font-weight:800}.runtime-strip strong{color:#dfe6f2;text-overflow:ellipsis;white-space:nowrap;max-width:100%;font-size:13px;overflow:hidden}.content-grid{grid-template-columns:minmax(0,1fr) 290px;align-items:start;gap:18px;margin-top:18px;display:grid}.surface{border:1px solid var(--line);background:var(--surface);border-radius:15px;box-shadow:0 22px 60px #0000001f}.task-dashboard{padding:clamp(20px,3vw,34px)}.task-heading{grid-template-columns:minmax(0,1fr) auto;align-items:start;gap:24px;display:grid}.section-kicker{color:var(--accent);letter-spacing:.14em;text-transform:uppercase;margin:0 0 7px;font-size:10px;font-weight:800}.task-heading h2,.task-empty h2{color:#f2f5fa;letter-spacing:-.035em;max-width:900px;margin:0;font-size:clamp(23px,3vw,38px);font-weight:650;line-height:1.18}.task-meta{color:var(--muted);flex-wrap:wrap;gap:12px;margin-top:15px;font-size:12px}.task-meta>span:not(.status-pill){border-left:1px solid var(--line-strong);padding-left:12px}.progress-number{text-align:right;min-width:116px}.progress-number strong{color:var(--accent);letter-spacing:-.05em;font-size:32px;font-weight:650;display:block}.progress-number span{color:var(--muted);font-size:11px}.progress-track{background:#242b36;border-radius:9px;height:5px;margin:26px 0 30px;overflow:hidden}.progress-track span{border-radius:inherit;background:linear-gradient(90deg,#45c89b,#7ee6bd);height:100%;transition:width .25s;display:block;box-shadow:0 0 20px #64e0b552}.status-pill{color:#aab4c4;white-space:nowrap;align-items:center;gap:6px;width:-moz-fit-content;width:fit-content;min-width:0;font-size:11px;font-weight:700;line-height:1.2;display:inline-flex}.status-dot{width:6px;height:6px;box-shadow:0 0 0 3px color-mix(in srgb, currentColor 13%, transparent);background:currentColor;border-radius:50%;flex:none}.tone-positive{color:var(--accent)}.tone-warning{color:var(--amber)}.tone-danger{color:var(--red)}.tone-info{color:var(--blue)}.tone-neutral{color:#919cad}.criteria-heading{justify-content:space-between;align-items:baseline;gap:16px;margin-bottom:12px;display:flex}.criteria-heading h2{letter-spacing:.01em;margin:0;font-size:13px}.criteria-heading>span{color:var(--quiet);font-size:11px}.criteria-list{gap:8px;margin:0;padding:0;list-style:none;display:grid}.criterion-card{border:1px solid var(--line);background:#090c1257;border-radius:11px;grid-template-columns:38px minmax(0,1fr) auto;align-items:center;gap:14px;min-height:72px;padding:12px 15px;display:grid}.criterion-index{border:1px solid color-mix(in srgb, currentColor 28%, transparent);background:color-mix(in srgb, currentColor 7%, transparent);border-radius:9px;place-items:center;width:32px;height:32px;font-size:10px;font-weight:800;display:grid}.criterion-copy{min-width:0}.criterion-copy>div{align-items:center;gap:9px;display:flex}.criterion-copy p{color:#dce3ed;margin:0;font-size:13px;line-height:1.45}.criterion-copy small{color:var(--quiet);margin-top:4px;font-size:10px;display:block}.critical-tag{color:var(--amber);letter-spacing:.08em;text-transform:uppercase;border:1px solid #efba633d;border-radius:4px;flex:none;padding:3px 6px;font-size:8px;font-weight:800}.blocker{background:#ff7f8612;border:1px solid #ff7f8640;border-radius:9px;grid-template-columns:auto 1fr;gap:14px;margin:-9px 0 24px;padding:12px 14px;display:grid}.blocker span{color:var(--red);text-transform:uppercase;font-size:10px;font-weight:800}.blocker p{color:#e6c3c6;margin:0;font-size:12px}.work-plan{border-top:1px solid var(--line);color:var(--muted);margin-top:16px;padding-top:15px}.work-plan summary{cursor:pointer;font-size:12px;font-weight:700}.work-plan ol{gap:9px;margin:14px 0 0;padding:0;list-style:none;display:grid}.work-plan li{grid-template-columns:100px 1fr;align-items:center;gap:12px;font-size:12px;display:grid}.context-rail{gap:18px;display:grid}.compact-panel{padding:18px}.compact-panel dl{margin:0}.compact-panel dl>div{border-bottom:1px solid var(--line);justify-content:space-between;align-items:center;gap:16px;min-height:39px;display:flex}.compact-panel dl>div:last-child{border-bottom:0}.compact-panel dt{color:var(--muted);font-size:11px}.compact-panel dd{color:#d9e0eb;text-overflow:ellipsis;white-space:nowrap;max-width:170px;margin:0;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:10px;overflow:hidden}.health-line{justify-content:space-between;gap:12px}.health-line>span{color:var(--quiet);font-size:10px}.health-issue{border-top:1px solid var(--line);color:var(--muted);margin:13px 0 0;padding-top:12px;font-size:11px;line-height:1.5}.task-empty{grid-template-columns:auto minmax(0,620px);place-content:center;gap:24px;min-height:420px;padding:48px;display:grid}.task-empty .empty-mark{width:64px;height:64px;color:var(--accent);background:var(--accent-soft);border:1px solid #64e0b547;border-radius:18px;place-items:center;font-family:Georgia,serif;font-size:38px;display:grid}.task-empty p:last-child{color:var(--muted);margin:13px 0 0;font-size:13px;line-height:1.6}.chat-panel{margin-top:18px;position:relative;overflow:hidden}.chat-panel[data-dragging]{outline:2px dashed var(--accent);outline-offset:-4px}.chat-drop-overlay{z-index:4;background:color-mix(in srgb, var(--surface-strong) 88%, transparent);pointer-events:none;text-align:center;border-radius:12px;align-content:center;justify-items:center;gap:6px;padding:16px;display:grid;position:absolute;inset:0}.chat-drop-overlay strong{color:var(--accent);font-size:13px}.chat-drop-overlay small{color:var(--quiet);font-size:10px}@media (prefers-reduced-motion:no-preference){.chat-drop-overlay{animation:.12s ease-out chat-drop-in}}@keyframes chat-drop-in{0%{opacity:0}to{opacity:1}}.chat-heading{border-bottom:1px solid var(--line);justify-content:space-between;align-items:center;gap:20px;min-height:78px;padding:17px 22px;display:flex}.chat-heading h2{letter-spacing:-.02em;margin:0;font-size:18px}.chat-heading>div:last-child{color:var(--quiet);align-items:center;gap:12px;font-size:10px;display:flex}.chat-read-state{color:var(--amber);background:#efba630f;border:1px solid #efba633b;border-radius:7px;padding:5px 8px}.chat-body{overscroll-behavior:contain;background:#090c1238;gap:11px;max-height:620px;padding:18px 20px;display:grid;overflow:auto}.chat-empty{color:var(--quiet);text-align:center;margin:0;padding:28px;font-size:11px}.load-older{border:1px solid var(--line);color:var(--muted);background:var(--surface);cursor:pointer;border-radius:7px;justify-self:center;padding:6px 10px;font-size:10px}.chat-message{border:1px solid var(--line);background:#111720;border-radius:11px;width:min(82%,900px);padding:12px 14px}.chat-message>div{justify-content:space-between;align-items:center;gap:12px;display:flex}.chat-message strong{color:#e3e9f2;letter-spacing:.04em;text-transform:uppercase;font-size:10px}.chat-message time,.chat-message small{color:var(--quiet);font-size:9px}.chat-message p{color:#cbd3df;white-space:pre-wrap;margin:7px 0 0;font-size:12px;line-height:1.6}.chat-message small{color:var(--amber);margin-top:7px;display:block}.chat-user{background:#75a7ff12;border-color:#75a7ff38;justify-self:end}.chat-assistant{justify-self:start}.chat-streaming{box-shadow:inset 2px 0 var(--accent);border-color:#64e0b542}.stream-indicator{color:var(--accent);font-size:9px}.chat-tool-live,.chat-tool-result{border:1px solid var(--line);width:-moz-fit-content;width:fit-content;max-width:82%;color:var(--quiet);background:#0d1219;border-radius:8px;align-items:center;gap:9px;padding:8px 11px;font-size:9px;display:flex}.chat-tool-live strong,.chat-tool-result strong{color:#bac4d2;font-family:ui-monospace,monospace;font-size:10px}.tool-spinner{border:1px solid var(--blue);border-right-color:#0000;border-radius:50%;width:7px;height:7px;animation:.8s linear infinite spin}.held-queue{border-top:1px solid var(--line);background:#efba6309;padding:12px 16px}.held-queue-heading{justify-content:space-between;align-items:center;gap:12px;margin-bottom:8px;display:flex}.held-queue-heading strong{color:#dce3ed;letter-spacing:.04em;text-transform:uppercase;font-size:10px}.held-queue-heading span{color:var(--amber);font-size:9px}.held-queue ol{gap:7px;max-height:260px;margin:0;padding:0;list-style:none;display:grid;overflow:auto}.held-queue li{border:1px solid var(--line);background:#0d1219;border-radius:8px;grid-template-columns:minmax(0,1fr) auto;gap:7px 12px;padding:9px 10px;display:grid}.held-queue li[data-state=quarantined]{border-color:#efba6340}.held-queue p{color:#c4cdd9;text-overflow:ellipsis;white-space:nowrap;margin:0;font-size:10px;line-height:1.45;overflow:hidden}.held-queue textarea{resize:vertical;border:1px solid var(--line);color:#dce3ed;background:#090d13;border-radius:7px;min-width:0;padding:8px 9px;font-size:10px}.held-queue li>div{align-items:start;gap:5px;display:flex}.held-queue button{border:1px solid var(--line);color:var(--muted);background:var(--surface);cursor:pointer;border-radius:6px;padding:4px 7px;font-size:9px}.held-queue button:disabled{cursor:not-allowed;opacity:.45}.held-queue small{color:var(--amber);grid-column:1/-1;font-size:8px}.chat-composer-preview{border-top:1px solid var(--line);background:#10151d;grid-template-columns:minmax(0,1fr) auto;gap:10px;padding:14px 16px;display:grid}.attachment-list{flex-wrap:wrap;grid-column:1/-1;gap:7px;margin:0;padding:0;list-style:none;display:flex}.attachment-list li{background:#75a7ff0f;border:1px solid #75a7ff38;border-radius:8px;align-items:center;gap:8px;max-width:260px;padding:7px 8px;display:flex}.attachment-list span{flex-direction:column;min-width:0;display:flex}.attachment-list strong{color:#dce3ed;text-overflow:ellipsis;white-space:nowrap;font-size:9px;overflow:hidden}.attachment-list small{color:var(--quiet);font-size:8px}.attachment-list button{min-width:0;padding:3px 6px;font-size:8px}.chat-composer-preview textarea{resize:none;border:1px solid var(--line);color:var(--quiet);background:#0b0f15;border-radius:9px;padding:10px 12px;font-size:11px}.chat-composer-preview button{border:1px solid var(--line);min-width:76px;color:var(--quiet);background:var(--surface-strong);border-radius:9px}.composer-actions{grid-template-columns:repeat(2,minmax(76px,auto));gap:6px;display:grid}.composer-actions .interrupt-send{color:var(--amber);grid-column:1/-1}.attachment-list li[data-kind=document]{background:#7ee7b212;border-color:#7ee7b24d}.attachment-picker{border:1px solid var(--line);width:-moz-fit-content;width:fit-content;color:var(--blue);cursor:pointer;border-radius:8px;align-items:center;padding:6px 9px;font-size:9px;display:inline-flex}.attachment-picker.disabled{cursor:not-allowed;opacity:.45}.attachment-picker input{opacity:0;width:1px;height:1px;position:absolute;overflow:hidden}.chat-composer-preview>small{color:var(--muted);grid-column:1/-1;font-size:9px}@keyframes spin{to{transform:rotate(360deg)}}.document-workspace{margin-top:0;overflow:hidden}.document-heading{border-bottom:1px solid var(--line);justify-content:space-between;align-items:center;gap:18px;min-height:82px;padding:18px 22px;display:flex}.document-heading h2{letter-spacing:-.02em;margin:0;font-size:18px}.document-heading>span{color:var(--quiet);letter-spacing:.06em;text-transform:uppercase;font-size:10px;font-weight:700}.document-body{grid-template-columns:minmax(248px,320px) minmax(0,1fr);min-height:520px;display:grid}.document-list{border-right:1px solid var(--line);overscroll-behavior:contain;flex-direction:column;gap:10px;min-width:0;max-height:720px;padding:14px;display:flex;overflow:auto}.document-group{flex-direction:column;gap:2px;min-width:0;display:flex}.document-group-heading{flex-direction:column;padding:8px 6px 4px;display:flex}.document-group-heading strong{color:var(--quiet);letter-spacing:.08em;text-transform:uppercase;font-size:9px;font-weight:800}.document-group-heading span{color:var(--muted);text-overflow:ellipsis;white-space:nowrap;font-size:9px;overflow:hidden}.document-row{cursor:pointer;text-align:left;background:0 0;border:0;border-radius:8px;align-items:center;gap:9px;min-width:0;padding:7px 8px;display:flex}.document-row-copy{flex-direction:column;flex:1;min-width:0;display:flex}.document-row-copy strong{color:#dce3ed;text-overflow:ellipsis;white-space:nowrap;font-size:11px;overflow:hidden}.document-row-copy small{color:var(--quiet);text-overflow:ellipsis;white-space:nowrap;text-align:left;direction:rtl;font-size:9px;overflow:hidden}.document-row-meta{color:var(--muted);flex-shrink:0;font-size:9px}.document-viewer{overscroll-behavior:contain;flex-direction:column;min-width:0;max-height:720px;display:flex;overflow:auto}.document-toolbar{z-index:2;border-bottom:1px solid var(--line);background:var(--surface-strong);justify-content:space-between;align-items:center;gap:14px;padding:12px 18px;display:flex;position:sticky;top:0}.document-toolbar strong{font-size:12px;display:block}.document-toolbar small{color:var(--quiet);text-overflow:ellipsis;white-space:nowrap;font-size:9px;display:block;overflow:hidden}.document-badges{flex-shrink:0;gap:6px;display:flex}.document-content{color:#dce3ed;min-width:0;padding:18px 22px;font-size:12px}.document-plain{font-family:var(--mono,ui-monospace, SFMono-Regular, Menlo, monospace);white-space:pre-wrap;word-break:break-word;margin:0;font-size:11px;line-height:1.7;overflow-x:auto}.document-table{border-collapse:collapse;width:100%;font-size:11px}.document-table th,.document-table td{border:1px solid var(--line);text-overflow:ellipsis;white-space:nowrap;max-width:320px;padding:5px 9px;overflow:hidden}.document-table th{background:var(--surface-strong);text-align:left;font-weight:750;position:sticky;top:0}.document-placeholder{height:100%;color:var(--muted);text-align:center;align-content:center;justify-items:center;gap:8px;padding:48px 24px;display:grid}.document-placeholder .MuiSvgIcon-root{opacity:.5;font-size:30px}.document-empty{color:var(--muted);padding:14px;font-size:11px}@media (max-width:900px){.document-body{grid-template-columns:1fr}.document-list{border-right:0;border-bottom:1px solid var(--line);max-height:300px}}:root[data-piagent-color-mode=light] .document-row-copy strong,:root[data-piagent-color-mode=light] .document-content{color:var(--text)}.source-workspace{margin-top:0;overflow:hidden}.source-heading{border-bottom:1px solid var(--line);justify-content:space-between;align-items:center;gap:18px;min-height:82px;padding:18px 22px;display:flex}.source-heading h2{letter-spacing:-.02em;margin:0;font-size:18px}.source-heading>span{color:var(--quiet);letter-spacing:.06em;text-transform:uppercase;font-size:10px;font-weight:700}.source-tabs{border-bottom:1px solid var(--line);background:#090c1252;min-width:0;padding:0 14px;display:flex}.source-tabs button{min-width:0;color:var(--muted);cursor:pointer;background:0 0;border:0;border-bottom:2px solid #0000;align-items:center;gap:9px;padding:14px 15px 12px;font-size:11px;display:flex}.source-tabs button:hover{color:#dce3ed}.source-tabs button[aria-selected=true]{border-bottom-color:var(--accent);color:var(--accent)}.source-tabs button b{min-width:20px;color:inherit;background:color-mix(in srgb, currentColor 10%, transparent);text-align:center;border-radius:8px;padding:2px 6px;font-size:9px}.source-body{grid-template-columns:minmax(248px,304px) minmax(0,1fr);min-height:480px;display:grid}.file-panel{border-right:1px solid var(--line);background:color-mix(in srgb, var(--bg) 72%, var(--surface));min-width:0}.file-panel-meta{border-bottom:1px solid var(--line);min-height:42px;color:var(--muted);justify-content:space-between;align-items:center;gap:14px;padding:0 14px;font-size:10px;display:flex}.file-panel-meta small{color:var(--quiet);letter-spacing:.08em;text-transform:uppercase;font-weight:800}.source-list-retry{color:var(--accent);font:inherit;background:0 0;border:1px solid;border-radius:6px;padding:4px 8px;font-weight:800}.file-list{overscroll-behavior:contain;max-height:620px;overflow:auto}.file-group-label{min-height:28px;color:var(--quiet);align-items:center;gap:6px;padding:5px 10px 3px}.file-group-label svg{width:14px;height:14px}.file-group-label span{min-width:0;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:9px;font-weight:700}.file-row{width:100%;min-height:54px;color:inherit;cursor:pointer;text-align:left;background:0 0;border:0;border-radius:7px;grid-template-columns:26px minmax(0,1fr) auto;align-items:center;gap:9px;margin:0;padding:8px 9px;display:grid}.file-row:hover{background:#75a7ff0d}.file-row[data-selected=true]{box-shadow:inset 2px 0 var(--accent);background:#64e0b513}.file-status{border:1px solid var(--line-strong);width:23px;height:23px;color:var(--muted);border-radius:6px;place-items:center;font-family:ui-monospace,monospace;font-size:10px;font-weight:900;display:grid}.status-A,.status-U{color:var(--accent);border-color:#64e0b54d}.status-M,.status-R{color:var(--blue);border-color:#75a7ff4d}.status-D,.status-C{color:var(--red);border-color:#ff7f864d}.file-name{flex-direction:column;min-width:0;display:flex}.file-name strong{color:var(--text);text-overflow:ellipsis;white-space:nowrap;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:11px;font-weight:600;overflow:hidden}.file-name small,.file-provenance,.file-evidence{color:var(--quiet);text-overflow:ellipsis;white-space:nowrap;font-size:9px;overflow:hidden}.file-provenance,.file-evidence{display:none}.file-stats{color:var(--muted);white-space:nowrap;font-family:ui-monospace,monospace;font-size:9px}.files-empty,.diff-empty{min-height:220px;color:var(--quiet);text-align:center;place-items:center;padding:28px;font-size:12px;display:grid}.diff-empty{background:repeating-linear-gradient(-45deg,#0000,#0000 13px,#ffffff03 13px 14px);min-height:100%}.error-state{color:var(--red)}.diff-viewer{background:var(--surface);min-width:0;overflow:auto}.diff-toolbar{border-bottom:1px solid var(--line);background:var(--surface);justify-content:space-between;align-items:center;gap:15px;min-height:55px;padding:9px 13px;display:flex}.diff-toolbar>div:first-child{align-items:center;gap:10px;min-width:0;display:flex}.diff-actions{align-items:center;gap:10px;display:flex}.review-state{color:var(--quiet);align-items:center;gap:8px;font-size:9px;display:flex}.review-state>span{white-space:nowrap}.review-state button{border:1px solid var(--line);color:#d8e1ee;background:#18202b;border-radius:7px;min-height:28px;padding:0 9px;font-size:9px}.review-state button:disabled{cursor:not-allowed;opacity:.45}.review-reviewed>span{color:var(--accent)}.review-stale>span{color:var(--amber)}.source-mutation-preview{color:#aeb9c8;align-items:center;gap:8px;max-width:290px;font-size:9px;display:flex}.source-mutation-preview>span{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.source-mutation-preview button{color:#b8ead5;background:#42c2921a;border:1px solid #42c29266;border-radius:7px;flex:none;min-height:28px;padding:0 10px;font-size:9px;font-weight:750}.source-mutation-preview button:disabled{cursor:not-allowed;opacity:.45}.source-revert-preview{color:#d3b29a;align-items:center;gap:8px;max-width:290px;font-size:9px;display:flex}.source-revert-preview>span{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.source-revert-preview button,.hunk-header .revert-action{color:#f3b4b8;background:#ff7f8617;border:1px solid #ff7f8661;border-radius:7px;flex:none;min-height:28px;padding:0 10px;font-size:9px;font-weight:750}.source-revert-preview button:disabled{cursor:not-allowed;opacity:.45}.source-open-action button{color:#c2d5f8;white-space:nowrap;background:#75a7ff1a;border:1px solid #75a7ff61;border-radius:7px;min-height:28px;padding:0 10px;font-size:9px;font-weight:750}.source-open-action button:disabled{cursor:wait;opacity:.55}.source-open-status{color:#bfd1f2;background:#75a7ff14;border-bottom:1px solid #75a7ff38;padding:8px 14px;font-size:10px}.commit-summary-panel{border-bottom:1px solid var(--line);background:linear-gradient(120deg,#42c29214,#75a7ff0d);grid-template-columns:minmax(230px,.8fr) minmax(300px,1.5fr);align-items:start;gap:18px;padding:14px 16px;display:grid}.commit-summary-panel h3{color:#edf2f7;margin:1px 0 4px;font-size:14px}.commit-summary-panel>div>span{color:var(--quiet);font-size:9px}.commit-summary-panel>button{color:#b8ead5;background:#42c2921a;border:1px solid #42c29266;border-radius:8px;justify-self:start;min-height:32px;padding:0 12px;font-size:10px;font-weight:750}.commit-summary-output{background:#070a0f8c;border:1px solid #75a7ff33;border-radius:9px;gap:5px;padding:10px 12px;display:grid}.commit-summary-output>strong{color:#edf2f7;font:700 12px ui-monospace,monospace}.commit-summary-output>code{color:#aeb9c8;white-space:pre-wrap;font-size:9px}.commit-summary-output>div{flex-wrap:wrap;gap:7px;margin-top:4px;display:flex}.commit-summary-output button{border:1px solid var(--line);color:#d8e1ee;background:#18202b;border-radius:7px;min-height:28px;padding:0 10px;font-size:9px}.commit-summary-output button:last-child{color:#efd19e;background:#ecb35b17;border-color:#ecb35b59}.commit-summary-status{color:#bfd1f2;grid-column:1/-1;margin:0;font-size:10px}.model-summary-dialog{border-color:#ecb35b57}.review-error{color:#f2b0b4;background:#ff687414;border-bottom:1px solid #ff68743d;padding:8px 14px;font-size:10px}.source-revert-error{color:#f2b0b4;background:#ff687414;border-top:1px solid #ff68743d;padding:9px 14px;font-size:10px}.source-action-warning{color:#f0d49a;background:#f6be5214;border-top:1px solid #f6be523d;padding:9px 14px;font-size:10px}.detail-reconciliation-warning{color:#f0d49a;background:#f6be5214;border-bottom:1px solid #f6be523d;justify-content:space-between;align-items:center;gap:12px;padding:8px 14px;font-size:10px;display:flex}.detail-reconciliation-warning button{color:inherit;background:0 0;border:1px solid;border-radius:6px;padding:4px 8px}.diff-toolbar strong{color:#e3e9f2;text-overflow:ellipsis;white-space:nowrap;font-family:ui-monospace,monospace;font-size:11px;overflow:hidden}.access-badge{text-transform:uppercase;font-size:9px;font-weight:800}.mode-switch{border:1px solid var(--line);background:var(--bg);border-radius:7px;padding:2px;display:flex}.mode-switch button{color:var(--quiet);cursor:pointer;background:0 0;border:0;border-radius:5px;padding:5px 8px;font-size:9px}.mode-switch button[aria-pressed=true]{color:#e5ebf4;background:var(--surface-strong)}.mode-switch .MuiToggleButton-root.Mui-selected{color:#eef3f8;background:#293241;box-shadow:inset 0 0 0 1px #75a7ff4d}.diff-context{border-bottom:1px solid var(--line);min-height:37px;color:var(--quiet);align-items:center;gap:14px;padding:0 14px;font-size:9px;display:flex}.diff-context .additions{color:var(--accent);margin-left:auto}.diff-context .deletions{color:var(--red)}.diff-hunk{min-width:0;overflow:auto}.hunk-header{color:var(--blue);background:#75a7ff12;border-bottom:1px solid #75a7ff24;justify-content:space-between;align-items:center;gap:12px;padding:6px 12px;font-family:ui-monospace,monospace;font-size:9px;display:flex;position:sticky;left:0}.hunk-header button{color:#bcd0f5;background:#75a7ff1a;border:1px solid #75a7ff57;border-radius:6px;min-height:25px;padding:0 9px;font:700 9px Inter,sans-serif}.hunk-header button:disabled{cursor:not-allowed;opacity:.45}.hunk-actions{align-items:center;gap:6px;display:inline-flex}.dialog-backdrop{z-index:80;-webkit-backdrop-filter:blur(6px);backdrop-filter:blur(6px);background:#030508c2;place-items:center;padding:20px;display:grid;position:fixed;inset:0}.confirm-dialog{background:#151a23;border:1px solid #ff7f8652;border-radius:15px;width:min(520px,100%);padding:24px;box-shadow:0 30px 100px #00000094}.confirm-dialog h3{color:#f1f4f8;margin:0;font-size:21px}.confirm-dialog>p:not(.section-kicker){color:#cbd3de;margin:14px 0;font-size:12px;line-height:1.65}.confirm-dialog code{color:#e6bdc0}.revert-diff{border:1px solid var(--line);background:#0c1016;border-radius:9px;max-height:min(300px,42vh);margin:14px 0;overflow:auto}.revert-diff section>div{color:#9bb9ec;background:#182130;padding:6px 9px;font:9px ui-monospace,monospace;position:sticky;top:0}.revert-line{white-space:pre-wrap;min-height:19px;padding:2px 9px;font:10px/1.5 ui-monospace,monospace;display:block;color:#b9c3d0!important}.revert-line b{width:14px;color:inherit;display:inline-block}.revert-added{background:#42c29214;color:#a7e1c9!important}.revert-deleted{background:#ff687414;color:#efafb3!important}.revert-meta{color:#8b96a8!important}.revert-safety{background:#efba630f;border:1px solid #efba6338;border-radius:9px;gap:5px;padding:12px;display:grid}.revert-safety strong{color:#efd19e;font-size:11px}.revert-safety span{color:#a99c87;font-size:10px}.confirm-actions{justify-content:flex-end;gap:9px;margin-top:20px;display:flex}.confirm-actions button{border:1px solid var(--line-strong);color:#cbd3df;background:#1b222d;border-radius:8px;min-height:34px;padding:0 14px;font-size:11px;font-weight:750}.confirm-actions .danger-action{color:#ffd2d5;background:#ff7f8621;border-color:#ff7f866b}.confirm-actions button:disabled{cursor:not-allowed;opacity:.48}.diff-line{grid-template-columns:42px 42px 18px minmax(500px,1fr);min-width:max-content;min-height:21px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:10px;line-height:21px;display:grid}.diff-line>span{color:#566173;text-align:right;-webkit-user-select:none;user-select:none;padding:0 7px}.diff-line b{color:var(--quiet);text-align:center;-webkit-user-select:none;user-select:none}.diff-line code,.split-line code{color:#bdc6d3;white-space:pre;padding:0 8px}.syntax-keyword{color:#c8a5ff;font-weight:650}.syntax-string{color:#a8d98b}.syntax-number{color:#efbd78}.syntax-comment{color:#778294;font-style:italic}.syntax-literal{color:#81b7ff}.syntax-property{color:#8ed8cf}.diff-added{background:#42c2921a}.diff-added code,.diff-added b{color:#a7e6ca}.diff-deleted{background:#ff68741a}.diff-deleted code,.diff-deleted b{color:#f2b0b4}.split-line{border-bottom:1px solid #242c394d;grid-template-columns:42px minmax(350px,1fr) 42px minmax(350px,1fr);min-width:860px;min-height:21px;font-family:ui-monospace,monospace;font-size:10px;line-height:21px;display:grid}.split-line>span{color:#566173;text-align:right;border-right:1px solid #242c39b3;padding:0 7px}.split-line code:nth-child(2){border-right:1px solid var(--line)}.unchanged-region{border-block:1px solid var(--line);color:var(--quiet);text-align:center;background:#10151d;padding:7px 12px;font-size:9px}.diff-fallback{border:1px solid var(--line);color:var(--muted);background:var(--surface);border-radius:9px;gap:6px;margin:18px;padding:16px;font-size:11px;display:grid}.diff-fallback strong{color:var(--amber);text-transform:uppercase;font-size:10px}.activity-panel{margin-top:18px;overflow:hidden}.panel-heading{border-bottom:1px solid var(--line);justify-content:space-between;align-items:center;gap:18px;min-height:82px;padding:18px 22px;display:flex}.panel-heading h2{letter-spacing:-.02em;margin:0;font-size:18px}.panel-heading>div:last-child{color:var(--quiet);align-items:center;gap:14px;font-size:10px;display:flex}.running-count{color:var(--blue)}.activity-list{display:grid}.activity-row{border-bottom:1px solid var(--line);background:#090c1233;grid-template-columns:10px minmax(0,1fr) 150px;align-items:start;gap:14px;padding:15px 18px;display:grid}.activity-row:last-child{border-bottom:0}.activity-state{width:7px;height:7px;box-shadow:0 0 0 4px color-mix(in srgb, currentColor 10%, transparent);background:currentColor;border-radius:50%;margin-top:5px}.activity-copy{min-width:0}.activity-copy>div{align-items:center;gap:9px;display:flex}.activity-copy strong{color:#dce3ed;font-size:12px}.activity-copy>div>span{border:1px solid var(--line);color:var(--quiet);letter-spacing:.06em;text-transform:uppercase;border-radius:4px;padding:2px 5px;font-size:8px;font-weight:800}.activity-copy>p{color:var(--muted);text-overflow:ellipsis;white-space:nowrap;margin:4px 0 0;font-family:ui-monospace,monospace;font-size:10px;line-height:1.45;overflow:hidden}.activity-result{text-align:right;grid-template-columns:1fr auto;align-items:center;gap:4px 9px;display:grid}.activity-result strong{color:#c9d1dd;font-size:10px}.activity-result>span{color:var(--quiet);font-family:ui-monospace,monospace;font-size:9px}.activity-result button{color:var(--blue);cursor:pointer;background:0 0;border:0;grid-column:1/-1;justify-self:end;padding:2px 0;font-size:9px}.log-preview{border:1px solid var(--line);color:#aeb8c7;white-space:pre-wrap;background:#090d13;border-radius:7px;margin-top:10px;padding:10px 12px;font-family:ui-monospace,monospace;font-size:9px;line-height:1.55}.log-preview small{color:var(--amber);margin-top:5px;display:block}.activity-empty{min-height:150px;color:var(--quiet);place-items:center;padding:24px;font-size:11px;display:grid}.panel-footnote{border-top:1px solid var(--line);color:var(--quiet);text-align:center;padding:9px 18px;font-size:9px}.evidence-section{margin-top:34px}.section-title-row{justify-content:space-between;align-items:end;gap:24px;margin-bottom:14px;padding:0 3px;display:flex}.section-title-row h2{letter-spacing:-.025em;margin:0;font-size:20px}.section-title-row>span{max-width:440px;color:var(--muted);text-align:right;text-overflow:ellipsis;white-space:nowrap;font-size:10px;overflow:hidden}.evidence-grid{grid-template-columns:repeat(4,minmax(0,1fr));gap:12px;display:grid}.evidence-card{min-width:0;min-height:250px;padding:18px}.evidence-card h3{color:#e1e7f0;min-height:38px;margin:0 0 16px;font-size:14px;line-height:1.35}.evidence-list{margin:0}.evidence-list>div{border-bottom:1px solid var(--line);grid-template-columns:88px minmax(0,1fr);align-items:center;gap:8px;min-height:38px;display:grid}.evidence-list>div:last-child{border-bottom:0}.evidence-list dt,.budget-grid dt{color:var(--quiet);font-size:9px}.evidence-list dd{color:var(--muted);text-align:right;text-overflow:ellipsis;white-space:nowrap;margin:0;font-family:ui-monospace,monospace;font-size:9px;overflow:hidden}.context-meter{background:#28303c;border-radius:4px;height:4px;margin:-3px 0 12px;overflow:hidden}.context-meter span{border-radius:inherit;background:linear-gradient(90deg, var(--blue), var(--accent));height:100%;display:block}.budget-grid{grid-template-columns:repeat(3,1fr);gap:7px;margin:0;display:grid}.budget-grid>div{border:1px solid var(--line);background:#090c1259;border-radius:8px;padding:12px 8px}.budget-grid dt{margin-bottom:5px}.budget-grid dd{color:#dbe2ec;margin:0;font-family:ui-monospace,monospace;font-size:12px}.card-note,.card-empty{color:var(--quiet);margin:14px 0 0;font-size:10px;line-height:1.5}.handoff-copy>p{color:var(--muted);margin:0 0 13px;font-size:11px;line-height:1.55}.handoff-blocker,.next-action{background:#ff7f860d;border:1px solid #ff7f8638;border-radius:7px;gap:4px;margin-top:9px;padding:9px 10px;display:grid}.next-action{background:#64e0b50d;border-color:#64e0b533}.handoff-blocker strong,.next-action strong{color:var(--red);letter-spacing:.08em;text-transform:uppercase;font-size:8px}.next-action strong{color:var(--accent)}.handoff-blocker span,.next-action span{color:#b7c0ce;font-size:10px;line-height:1.4}.loading-shell{width:min(560px,100% - 40px);margin:0 auto;padding-top:22vh}.loading-shell .brand-mark{border-radius:14px;width:48px;height:48px;margin-bottom:25px;font-size:29px}.loading-shell h1{color:#f0f3f8;letter-spacing:-.045em;margin:0;font-size:clamp(30px,6vw,50px);line-height:1.05}.loading-shell>p:not(.section-kicker){max-width:460px;color:var(--muted);margin:18px 0 22px;font-size:14px;line-height:1.6}.session-options{grid-template-columns:minmax(220px,.75fr) minmax(420px,1.25fr);gap:22px;padding:20px;display:grid}.session-options-copy h2{color:#edf1f7;margin:2px 0 8px;font-size:16px}.session-options-copy>p:last-child{max-width:520px;color:var(--quiet);margin:0;font-size:10px;line-height:1.55}.session-options-controls{grid-template-columns:minmax(0,1.4fr) minmax(130px,.6fr);align-items:end;gap:10px;display:grid}.session-options-controls>label:not(.effect-ack){color:var(--quiet);gap:5px;font-size:9px;display:grid}.session-options-controls select{border:1px solid var(--line);color:#e4e9f1;background:#121821;border-radius:7px;width:100%;min-height:36px;padding:0 10px}.effect-ack{color:#b9c1cd;grid-column:1/-1;align-items:flex-start;gap:8px;font-size:10px;line-height:1.4;display:flex}.effect-ack input{accent-color:var(--accent);margin-top:1px}.session-option-actions{grid-column:1/-1;gap:8px;display:flex}.session-option-actions button{border:1px solid var(--line);color:#dbe2ec;background:#1a222d;border-radius:7px;min-height:34px;padding:0 13px}.session-option-actions button:disabled{opacity:.42}.session-options-controls>small{color:var(--quiet);grid-column:1/-1;font-size:9px}.session-options-unavailable{color:var(--quiet);flex-direction:column;justify-content:center;gap:5px;font-size:10px;display:flex}.session-options-unavailable strong{color:#d7dde7;font-size:12px}.lifecycle-panel{grid-template-columns:minmax(260px,1fr) minmax(150px,auto) minmax(360px,auto);align-items:center;gap:20px;margin-top:18px;padding:18px 20px;display:grid}.lifecycle-copy h2{color:#edf1f7;margin:2px 0 7px;font-size:16px}.lifecycle-copy>p:last-child{max-width:620px;color:var(--quiet);margin:0;font-size:10px;line-height:1.55}.lifecycle-state{border-left:1px solid var(--line);gap:4px;min-width:150px;padding-left:18px;display:grid}.lifecycle-state>span{color:var(--quiet);text-transform:uppercase;font-size:9px;font-weight:800}.lifecycle-state strong{color:#e5eaf2;font-size:12px}.lifecycle-state small{color:var(--quiet);font-size:9px}.lifecycle-actions{flex-wrap:wrap;justify-content:flex-end;gap:8px;display:flex}.lifecycle-actions button{cursor:pointer;border-radius:7px;min-height:36px;padding:0 13px;font-size:10px;font-weight:750}.lifecycle-actions button:disabled{cursor:not-allowed;opacity:.4}.primary-action{color:#07130f;background:var(--accent);border:1px solid #3cae88}.lifecycle-result{border-radius:7px;grid-column:1/-1;margin:-6px 0 0;padding:9px 11px;font-size:10px;line-height:1.45}.lifecycle-result.result-ok{color:#bcebd9;background:#64e0b512}.lifecycle-result.result-warning{color:#efd09b;background:#efba6314}.approval-stack{gap:12px;display:grid}.approval-card{background:linear-gradient(135deg,#412518eb,#19181bf5);border:1px solid #70462e;border-radius:13px;padding:20px;overflow:hidden;box-shadow:0 16px 42px #00000038}.approval-card.risk-critical,.approval-card.risk-high{border-color:#9d4d3f}.approval-card>header,.approval-card>footer{justify-content:space-between;align-items:center;gap:12px;display:flex}.approval-card h2{color:#fff1e7;margin:2px 0 0;font-size:18px}.approval-risk{color:#ffbd91;text-transform:uppercase;border:1px solid #ffad7c59;border-radius:999px;padding:5px 9px;font-size:10px;font-weight:800}.approval-reason{color:#f1d8c7;margin:13px 0;font-size:12px;line-height:1.55}.approval-preview{color:#f3e7df;white-space:pre-wrap;word-break:break-word;background:#141316;border:1px solid #ffffff17;border-radius:8px;max-height:180px;margin:0 0 14px;padding:12px;font:11px/1.55 ui-monospace,SFMono-Regular,Menlo,monospace;overflow:auto}.approval-facts{grid-template-columns:repeat(3,minmax(0,1fr));gap:8px;margin:0 0 13px;display:grid}.approval-facts>div{background:#ffffff09;border-radius:7px;min-width:0;padding:9px}.approval-facts dt{color:#bca393;text-transform:uppercase;font-size:9px;font-weight:800}.approval-facts dd{color:#f0e7e1;text-overflow:ellipsis;margin:4px 0 0;font-size:10px;overflow:hidden}.approval-targets,.approval-consequences{color:#d9c8bc;font-size:10px;line-height:1.55}.approval-targets ul{margin:6px 0 12px;padding-left:18px}.approval-consequences{grid-template-columns:1fr 1fr;gap:10px;margin:12px 0;display:grid}.approval-consequences p{background:#ffffff09;border-radius:7px;margin:0;padding:10px}.approval-card>footer{justify-content:flex-end;padding-top:4px}.approval-card button{border-radius:7px;min-height:36px;padding:0 14px;font-weight:750}.secondary-action{border:1px solid var(--line);color:#dbe2ec;background:#1a222d}.danger-action{color:#fff5ee;background:#8f3e31;border:1px solid #c56b52}.approval-card button:disabled{cursor:wait;opacity:.48}.question-stack{gap:12px;display:grid}.question-card{background:linear-gradient(135deg,#162e3af0,#16181ef7);border:1px solid #2f5f73;border-radius:13px;padding:20px;overflow:hidden;box-shadow:0 16px 42px #00000038}.question-card>header,.question-card>footer{justify-content:space-between;align-items:center;gap:12px;display:flex}.question-card h2{color:#eef7fb;margin:2px 0 0;font-size:18px}.question-hint{color:#8fb3c4;font-size:10px;font-weight:700}.question-block{border:0;min-width:0;margin:14px 0 0;padding:0}.question-block legend{color:#eef7fb;flex-wrap:wrap;align-items:baseline;gap:6px;padding:0;font-size:13px;font-weight:700;line-height:1.5;display:flex}.question-number{color:#8fb3c4}.question-chip{color:#9ed7f0;border:1px solid #7cc4e459;border-radius:999px;padding:2px 8px;font-size:10px;font-weight:800}.question-text{overflow-wrap:anywhere;min-width:0}.question-multi{color:#8fb3c4;margin:4px 0 0;font-size:10px}.question-card:focus-visible,.question-block:focus-visible{outline-offset:3px;border-radius:8px;outline:2px solid #4fa3c7}.question-block.active .question-number{color:#7fd0ef}.question-options{gap:5px;margin:8px 0 0;padding:0;list-style:none;display:grid}.question-options label{cursor:pointer;background:#ffffff08;border:1px solid #ffffff14;border-radius:8px;align-items:flex-start;gap:10px;padding:7px 10px;display:flex}.question-options label:hover{border-color:#7cc4e459}.question-options label.selected{background:#4fa3c724;border-color:#4fa3c7}.question-options input[type=radio],.question-options input[type=checkbox]{opacity:0;pointer-events:none;position:absolute}.question-options label:focus-within{outline-offset:2px;outline:2px solid #4fa3c7}.option-number{color:#0d1d25;background:#8fc9e2;border-radius:6px;flex:none;place-items:center;width:22px;height:22px;font-size:11px;font-weight:800;display:inline-grid}.option-body{color:#e3eef3;gap:2px;min-width:0;font-size:12px;line-height:1.45;display:grid}.option-body small{color:#9db4c0;font-size:11px}.question-other input[type=text]{box-sizing:border-box;color:#eef7fb;width:100%;font:inherit;background:#121a20;border:1px solid #4fa3c7;border-radius:8px;margin-top:6px;padding:9px 11px;font-size:12px}.question-card>footer{justify-content:flex-end;padding-top:14px}.question-card button{border-radius:7px;min-height:36px;padding:0 14px;font-weight:750}.question-card button:disabled{cursor:not-allowed;opacity:.48}.task-run-index,.release-monitor{margin-top:18px;overflow:hidden}.release-monitor .source-heading button{border:1px solid var(--line);color:var(--text);background:var(--surface-2);border-radius:8px;padding:8px 12px}.release-monitor .source-heading button:disabled{opacity:.55}.release-monitor-grid{border-top:1px solid var(--line);grid-template-columns:minmax(0,1.15fr) minmax(320px,.85fr);display:grid}.release-monitor-column+.release-monitor-column{border-left:1px solid var(--line)}.release-monitor-column>header{border-bottom:1px solid var(--line);justify-content:space-between;align-items:center;gap:14px;padding:16px 20px;display:flex}.release-monitor-column h3{margin:2px 0 0}.benchmark-run-card{border-bottom:1px solid var(--line);padding:14px 20px}.benchmark-run-card>div:first-child{justify-content:space-between;align-items:center;gap:12px;display:flex}.benchmark-run-card small{color:var(--muted);margin-top:4px;display:block}.benchmark-run-facts{color:var(--muted);flex-wrap:wrap;gap:8px 18px;margin-top:9px;font-size:12px;display:flex}.release-readiness-facts{margin:0;padding:4px 20px 12px}.release-readiness-facts>div{border-bottom:1px solid var(--line);justify-content:space-between;align-items:center;gap:16px;padding:10px 0;display:flex}.release-readiness-facts dt{color:var(--muted)}.release-readiness-facts dd{text-align:right;margin:0}.release-blockers{border:1px solid color-mix(in srgb, var(--warning) 35%, var(--line));background:color-mix(in srgb, var(--warning) 7%, transparent);border-radius:8px;margin:0 20px 14px;padding:12px 14px}.release-blockers ul{color:var(--muted);margin:8px 0 0;padding-left:18px}.release-blockers li+li{margin-top:5px}.task-index-controls{border-bottom:1px solid var(--line);gap:8px;padding:0 20px 16px;display:flex}.task-index-controls button{border:1px solid var(--line);color:var(--muted);background:var(--surface-2);border-radius:999px;padding:7px 12px}.task-index-controls button[aria-pressed=true]{color:var(--text);border-color:var(--accent);background:color-mix(in srgb, var(--accent) 15%, var(--surface-2))}.task-run-list{display:grid}.task-run-card{border-bottom:1px solid var(--line);grid-template-columns:minmax(0,1fr) auto;align-items:center;gap:18px;padding:15px 20px;display:grid}.task-run-card[data-active=true]{box-shadow:inset 3px 0 var(--accent);background:color-mix(in srgb, var(--accent) 5%, transparent)}.task-run-card[data-selected=true]{outline:1px solid var(--accent);outline-offset:-1px}.task-run-main{min-width:0}.task-run-main>div{align-items:center;gap:9px;display:flex}.task-run-main strong,.task-run-main small{text-overflow:ellipsis;white-space:nowrap;display:block;overflow:hidden}.task-run-main small,.task-run-meta{color:var(--muted)}.active-run-tag{border:1px solid var(--accent);color:var(--accent);border-radius:999px;padding:2px 7px;font-size:11px}.task-run-meta{justify-content:flex-end;align-items:center;gap:12px;font-size:12px;display:flex}.task-index-empty,.task-index-warning{color:var(--muted);margin:0;padding:18px 20px}.task-index-warning{border-top:1px solid var(--line);color:var(--warning)}.task-run-meta button{border:1px solid var(--line);color:var(--text);background:var(--surface-2);border-radius:7px;padding:6px 9px}.task-run-meta button[aria-pressed=true]{border-color:var(--accent);color:var(--accent)}.task-timeline{border-top:1px solid var(--line)}.task-timeline>header{border-bottom:1px solid var(--line);justify-content:space-between;align-items:center;gap:16px;padding:18px 20px;display:flex}.task-timeline h3{margin:2px 0 0}.timeline-continuity{color:var(--muted);border-bottom:1px solid var(--line);flex-wrap:wrap;gap:10px 24px;padding:12px 20px;display:flex}.timeline-events{margin:0;padding:0;list-style:none}.timeline-events li{border-bottom:1px solid var(--line);grid-template-columns:12px minmax(0,1fr) auto;align-items:start;gap:12px;padding:13px 20px;display:grid}.timeline-events small,.timeline-events p{color:var(--muted);margin:3px 0 0;display:block}.timeline-dot{background:var(--muted);border-radius:999px;width:9px;height:9px;margin-top:5px}.timeline-dot.tone-positive{background:var(--positive)}.timeline-dot.tone-warning{background:var(--warning)}.timeline-dot.tone-danger{background:var(--danger)}.timeline-dot.tone-info{background:var(--accent)}.recovery-summary{grid-template-columns:repeat(4,minmax(0,1fr));display:grid}.retained-content-note{color:var(--muted);border-bottom:1px solid var(--line);margin:0;padding:10px 20px;font-size:12px}.next-action-card{border-bottom:1px solid var(--line);background:color-mix(in srgb, var(--accent) 7%, transparent);grid-template-columns:minmax(180px,.45fr) 1fr auto;align-items:center;gap:18px;padding:16px 20px;display:grid}.next-action-card span,.next-action-card strong{display:block}.next-action-card span,.next-action-card p,.next-action-card small{color:var(--muted)}.next-action-card p{margin:0}.handoff-summary{grid-template-columns:repeat(4,minmax(0,1fr));display:grid}.workspace-stack>.surface,.workspace-view>.surface,.workspace-stack>.evidence-section,.workspace-view>.evidence-section{margin-top:0}:root[data-piagent-color-mode=light] .task-heading h2,:root[data-piagent-color-mode=light] .task-empty h2,:root[data-piagent-color-mode=light] .criterion-copy p,:root[data-piagent-color-mode=light] .compact-panel dd,:root[data-piagent-color-mode=light] .chat-heading h2,:root[data-piagent-color-mode=light] .chat-message strong,:root[data-piagent-color-mode=light] .chat-message p,:root[data-piagent-color-mode=light] .attachment-list strong,:root[data-piagent-color-mode=light] .diff-toolbar strong,:root[data-piagent-color-mode=light] .activity-copy strong,:root[data-piagent-color-mode=light] .activity-result strong,:root[data-piagent-color-mode=light] .evidence-card h3,:root[data-piagent-color-mode=light] .budget-grid dd,:root[data-piagent-color-mode=light] .session-options-copy h2,:root[data-piagent-color-mode=light] .session-options-unavailable strong,:root[data-piagent-color-mode=light] .lifecycle-copy h2,:root[data-piagent-color-mode=light] .lifecycle-state strong{color:var(--text)}:root[data-piagent-color-mode=light] .chat-body,:root[data-piagent-color-mode=light] .activity-row{background:#62740006}:root[data-piagent-color-mode=light] .source-tabs{background:#f8f9f4}:root[data-piagent-color-mode=light] .source-tabs button:hover{color:var(--text)}:root[data-piagent-color-mode=light] .source-action-warning,:root[data-piagent-color-mode=light] .detail-reconciliation-warning{color:#755000;background:#ab740014}:root[data-piagent-color-mode=light] .chat-message,:root[data-piagent-color-mode=light] .chat-tool-live,:root[data-piagent-color-mode=light] .chat-tool-result,:root[data-piagent-color-mode=light] .held-queue li,:root[data-piagent-color-mode=light] .log-preview{color:var(--text);background:#fafbf7}:root[data-piagent-color-mode=light] .chat-user{background:#506db712}:root[data-piagent-color-mode=light] .chat-composer-preview,:root[data-piagent-color-mode=light] .unchanged-region{background:#f7f8f3}:root[data-piagent-color-mode=light] .chat-composer-preview textarea,:root[data-piagent-color-mode=light] .session-options-controls select{color:var(--text);background:#fff}:root[data-piagent-color-mode=light] .review-state button,:root[data-piagent-color-mode=light] .commit-summary-output button,:root[data-piagent-color-mode=light] .confirm-actions button,:root[data-piagent-color-mode=light] .session-option-actions button{color:var(--text);background:var(--surface-strong)}:root[data-piagent-color-mode=light] .commit-summary-panel h3,:root[data-piagent-color-mode=light] .commit-summary-output>strong{color:var(--text)}:root[data-piagent-color-mode=light] .commit-summary-output{background:#ffffffbf}:root[data-piagent-color-mode=light] .diff-line code,:root[data-piagent-color-mode=light] .split-line code{color:#3f443a}:root[data-piagent-color-mode=light] .diff-line>span,:root[data-piagent-color-mode=light] .split-line>span{color:#92988d}:root[data-piagent-color-mode=light] .syntax-keyword{color:#6e3bb2}:root[data-piagent-color-mode=light] .syntax-string{color:#317040}:root[data-piagent-color-mode=light] .syntax-number{color:#9b5a12}:root[data-piagent-color-mode=light] .syntax-comment{color:#7b8176}:root[data-piagent-color-mode=light] .syntax-literal{color:#235fa8}:root[data-piagent-color-mode=light] .syntax-property{color:#176f69}:root[data-piagent-color-mode=light] .mode-switch .MuiToggleButton-root.Mui-selected{color:#1c2018;background:#e8ecdf}:root[data-piagent-color-mode=light] .diff-added{background:#14775f1a}:root[data-piagent-color-mode=light] .diff-added code,:root[data-piagent-color-mode=light] .diff-added b{color:#0a654e}:root[data-piagent-color-mode=light] .diff-deleted{background:#c43f4c1a}:root[data-piagent-color-mode=light] .diff-deleted code,:root[data-piagent-color-mode=light] .diff-deleted b{color:#a02734}:root[data-piagent-color-mode=light] .confirm-dialog{color:var(--text);background:#fff}:root[data-piagent-color-mode=light] .confirm-dialog h3,:root[data-piagent-color-mode=light] .confirm-dialog>p:not(.section-kicker){color:var(--text)}:root[data-piagent-color-mode=light] .revert-diff{background:#f8f9f4}:root[data-piagent-color-mode=light] .approval-card{color:#3f2b20;background:linear-gradient(135deg,#fff7ef,#fff);border-color:#d7b18f}:root[data-piagent-color-mode=light] .question-card{color:#1d3540;background:linear-gradient(135deg,#f1f9fc,#fff);border-color:#9cc8da}:root[data-piagent-color-mode=light] .question-card h2,:root[data-piagent-color-mode=light] .question-block legend,:root[data-piagent-color-mode=light] .option-body{color:#1d3540}:root[data-piagent-color-mode=light] .question-hint,:root[data-piagent-color-mode=light] .question-number,:root[data-piagent-color-mode=light] .question-multi,:root[data-piagent-color-mode=light] .option-body small{color:#557482}:root[data-piagent-color-mode=light] .question-chip{color:#1e6f92;border-color:#9cc8da}:root[data-piagent-color-mode=light] .question-options label{background:#fff;border-color:#d6e6ed}:root[data-piagent-color-mode=light] .question-options label.selected{background:#e6f4fa;border-color:#3b8fb3}:root[data-piagent-color-mode=light] .question-other input[type=text]{color:#1d3540;background:#fff}:root[data-piagent-color-mode=light] .approval-card h2,:root[data-piagent-color-mode=light] .approval-preview,:root[data-piagent-color-mode=light] .approval-facts dd{color:#3f2b20}:root[data-piagent-color-mode=light] .approval-preview{background:#fffaf5}:root[data-piagent-color-mode=light] .approval-reason,:root[data-piagent-color-mode=light] .approval-targets,:root[data-piagent-color-mode=light] .approval-consequences{color:#6d4d3c}@media (max-width:1080px){.lifecycle-panel{grid-template-columns:1fr auto}.lifecycle-actions{grid-column:1/-1;justify-content:flex-start}.lifecycle-result{grid-column:1/-1}.runtime-strip{grid-template-columns:repeat(3,1fr)}.runtime-strip>div:nth-child(3){border-right:0}.runtime-strip>div:nth-child(-n+3){border-bottom:1px solid var(--line)}.content-grid{grid-template-columns:1fr}.context-rail,.evidence-grid{grid-template-columns:repeat(2,1fr)}}@media (max-width:899px){.source-body{grid-template-columns:1fr}.file-panel{border-right:0;border-bottom:1px solid var(--line)}.file-list{max-height:300px}.diff-empty{min-height:300px}}@media (max-width:720px){.release-monitor-grid{grid-template-columns:1fr}.release-monitor-column+.release-monitor-column{border-left:0;border-top:1px solid var(--line)}.recovery-summary{grid-template-columns:repeat(2,minmax(0,1fr))}.handoff-summary,.next-action-card,.commit-summary-panel,.approval-facts,.approval-consequences{grid-template-columns:1fr}.approval-card>header,.approval-card>footer{flex-direction:column;align-items:flex-start}.approval-card>footer button{width:100%}.question-card{padding:16px}.question-card>header,.question-card>footer{flex-direction:column;align-items:stretch}.question-card>footer{flex-direction:column-reverse}.question-card>footer button{width:100%}.session-options,.session-options-controls{grid-template-columns:1fr}.effect-ack,.session-option-actions,.session-options-controls>small{grid-column:1}.lifecycle-panel{grid-template-columns:1fr;align-items:stretch}.lifecycle-state{border-left:0;padding:0}.lifecycle-actions{grid-column:1}.lifecycle-actions button{flex:150px}.lifecycle-result{grid-column:1}.topbar{grid-template-columns:1fr auto;min-height:60px;padding:0 16px}.session-title,.read-only-badge{display:none}.workspace{width:min(100% - 24px,1460px);padding-top:12px}.runtime-strip{grid-template-columns:repeat(2,1fr)}.runtime-strip>div{border-bottom:1px solid var(--line);min-height:62px;padding:11px}.runtime-strip>div:nth-child(2n){border-right:0}.runtime-strip>div:nth-last-child(-n+2){border-bottom:0}.task-dashboard{padding:19px 14px}.chat-heading{flex-direction:column;align-items:flex-start;padding:15px}.chat-heading>div:last-child{flex-direction:column;align-items:flex-start}.chat-body{padding:13px}.chat-message{width:94%}.chat-composer-preview,.task-heading{grid-template-columns:1fr}.progress-number{text-align:left;align-items:baseline;gap:10px;display:flex}.progress-number strong{font-size:25px}.progress-track{margin:18px 0 24px}.criterion-card{grid-template-columns:32px minmax(0,1fr);gap:10px}.criterion-card>.status-pill{grid-column:2}.criterion-copy>div{flex-direction:column;align-items:flex-start;gap:5px}.context-rail{grid-template-columns:1fr}.task-empty{grid-template-columns:1fr;min-height:340px;padding:28px 22px}.source-tabs{padding:0 8px;overflow-x:auto}.source-tabs button{flex:none}.source-heading{padding:16px}.source-heading>span,.file-provenance,.file-evidence{display:none}.file-row{grid-template-columns:26px minmax(0,1fr) auto}.diff-toolbar{flex-direction:column;align-items:flex-start}.panel-heading{flex-direction:column;align-items:flex-start;padding:16px}.activity-row{grid-template-columns:10px minmax(0,1fr)}.activity-result{text-align:left;grid-column:2;grid-template-columns:auto auto 1fr}.activity-result button{grid-column:auto;justify-self:end}.section-title-row{flex-direction:column;align-items:flex-start;gap:8px}.section-title-row>span{text-align:left;max-width:100%}.evidence-grid{grid-template-columns:1fr}.evidence-card{min-height:auto}.task-run-card{grid-template-columns:1fr;gap:9px}.task-run-meta{flex-wrap:wrap;justify-content:flex-start}}@media (prefers-reduced-motion:reduce){*,:before,:after{scroll-behavior:auto!important;transition:none!important;animation:none!important}}@media (forced-colors:active){.status-dot,.activity-state,.progress-track span,.context-meter span{forced-color-adjust:none;background:highlight}.file-row[data-selected=true],.source-tabs button[aria-selected=true]{outline:2px solid highlight}}@keyframes piagent-pulse{0%,to{opacity:1}50%{opacity:.3}}@media (prefers-reduced-motion:reduce){*{animation-duration:.01ms!important;animation-iteration-count:1!important}}
@@ -7,8 +7,8 @@
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-Cv5u0MN8.js"></script>
11
- <link rel="stylesheet" crossorigin href="/assets/index-DgSmcnP8.css">
10
+ <script type="module" crossorigin src="/assets/index-BuIJR5rd.js"></script>
11
+ <link rel="stylesheet" crossorigin href="/assets/index-Z91z6SlN.css">
12
12
  </head>
13
13
  <body>
14
14
  <div id="root"></div>
@@ -9,6 +9,7 @@ import type { PiagentWebUICanonicalSnapshotV1 } from "../contracts/generated/sna
9
9
  import { startLoopbackServer } from "../server/loopback-server.ts";
10
10
  import { startGatewayControlSocket, type GatewayControlResponse } from "./control-socket.ts";
11
11
  import { loadPinnedPiHost } from "./pi-host.ts";
12
+ import { UpdateCenter } from "./update-center.ts";
12
13
  import {
13
14
  gatewayProfileState,
14
15
  profileRef,
@@ -113,6 +114,7 @@ export async function startPiagentGateway(options: {
113
114
  let mcpAuth: McpAuthBroker | null = null;
114
115
  let attachments: SessionAttachmentRegistry | null = null;
115
116
  let relay: CompanyRelay | null = null;
117
+ let updates: UpdateCenter | null = null;
116
118
  let closing: Promise<void> | null = null;
117
119
  let settleWait: (() => void) | null = null;
118
120
  const waited = new Promise<void>((resolve) => { settleWait = resolve; });
@@ -121,7 +123,7 @@ export async function startPiagentGateway(options: {
121
123
  if (closing) return await closing;
122
124
  closing = (async () => {
123
125
  removeGatewayDescriptor(state, gatewayInstanceRef);
124
- relay?.close();
126
+ relay?.close(); updates?.close();
125
127
  await loopback?.close().catch(() => undefined);
126
128
  // Staged bytes are private temp files. Closing deletes them rather than
127
129
  // leaving a directory per session behind for the TTL sweep that will never
@@ -242,6 +244,10 @@ export async function startPiagentGateway(options: {
242
244
  attachments = new SessionAttachmentRegistry({
243
245
  inspect: async (sessionRef) => await (await inspections.provider(sessionRef)).snapshot() as PiagentWebUICanonicalSnapshotV1
244
246
  });
247
+ // Piagent's own updates: Pi and Piagent together, never while a turn runs.
248
+ updates = new UpdateCenter({ packageRoot: options.packageRoot, piVersion: options.expectedPiVersion, managed: Boolean(options.managed),
249
+ busy: async () => runtimes!.currentOperations().length + (relay ? (await relay.operations()).length : 0) });
250
+ updates.start();
245
251
  loopback = await startLoopbackServer({
246
252
  staticRoot,
247
253
  mode: "gateway",
@@ -276,6 +282,14 @@ export async function startPiagentGateway(options: {
276
282
  ? relayPost("/api/v1/runtime-commands", command) : runtimeCommands.execute(command),
277
283
  executeSessionAttachment: (sessionRef, command) => company(sessionRef)
278
284
  ? relayPost(`/api/v1/sessions/${encodeURIComponent(sessionRef)}/attachments`, command) : attachments.execute(sessionRef, command),
285
+ // The main agent's questions to the member, read and answered where the
286
+ // conversation runs (the company Gateway for a company conversation).
287
+ readSessionQuestions: (sessionRef) => company(sessionRef)
288
+ ? relay!.json("GET", `/api/v1/sessions/${encodeURIComponent(sessionRef)}/questions`) : runtimes!.questions(sessionRef),
289
+ updates: { status: () => updates!.status(), check: () => updates!.check(), apply: (request) => updates!.apply(request) },
290
+ answerSessionQuestion: (sessionRef, questionRef, answer) => company(sessionRef)
291
+ ? relayPost(`/api/v1/sessions/${encodeURIComponent(sessionRef)}/questions/${encodeURIComponent(questionRef)}/answer`, answer)
292
+ : runtimes!.answerQuestion(sessionRef, questionRef, answer),
279
293
  // Approval refs carry no session; a company approval is not pending here.
280
294
  executeApproval: async (approvalRef, decision) => {
281
295
  try { return await runtimes!.decideApproval(approvalRef, decision); }
@@ -1,6 +1,6 @@
1
1
  // Public managed state contains no provider/model route or credential.
2
2
  const STATUS = ['pending', 'in_progress', 'completed'];
3
- const OUTCOMES = ['no_change', 'interrupted', 'blocking_open', 'unverified', 'review_unavailable', 'unreviewed', 'clean'];
3
+ const OUTCOMES = ['no_change', 'interrupted', 'disputed', 'blocking_open', 'unverified', 'review_unavailable', 'unreviewed', 'clean'];
4
4
  export function managedProjection(context: any, entries: any[]) {
5
5
  if (context?.model?.provider !== 'agent_watch_managed') return {};
6
6
  const last = (type: string) => entries.filter(e => e.type === 'custom' && e.customType === type).at(-1)?.data;
@@ -0,0 +1,15 @@
1
+ import { memberQuestions } from "../../piagent-core/managed/member-questions.mjs";
2
+
3
+ // The main agent's questions to the member of a conversation this Gateway
4
+ // runs: the conversation's runtime is where they are answered, and a question
5
+ // waiting for its answer keeps the running turn alive (`progress`).
6
+ export function bindSessionQuestions(sessionId: string, progress: () => void): () => void {
7
+ return memberQuestions.bindSurface(sessionId, progress);
8
+ }
9
+ export function sessionQuestions(sessionId: string | null): { questions: ReturnType<typeof memberQuestions.pending> } {
10
+ return { questions: sessionId ? memberQuestions.pending(sessionId) : [] };
11
+ }
12
+ export function answerSessionQuestion(sessionId: string | null, questionRef: string, answer: unknown): unknown {
13
+ if (!sessionId) throw new Error("question-not-pending");
14
+ return memberQuestions.answer(sessionId, questionRef, answer);
15
+ }
@@ -6,6 +6,7 @@ import { activeSessionTask } from "../../piagent-core/extensions/task-state.js";
6
6
  import { createSessionOperationSettlement } from "./session-operation-settlement.ts";
7
7
  import { inspectTaskControlState } from "../../piagent-core/runtime/inspection/task-control-journal.ts";
8
8
  import { piApprovalBroker, type ApprovalBrokerEvent } from "../../piagent-core/runtime/inspection/approval-broker.ts";
9
+ import { answerSessionQuestion, bindSessionQuestions, sessionQuestions } from "./session-questions.ts";
9
10
  import { isUserConversationSession, projectRefForCwd, sessionRefForPath, type SessionOwnerProjection, type PiSessionInfo } from "./session-catalog.ts";
10
11
  import { SessionLeaseStore, type SessionLeaseSnapshot } from "./session-lease-store.ts";
11
12
  import { GatewayEventStore } from "./gateway-events.ts";
@@ -311,8 +312,10 @@ export class SessionRuntimeSupervisor {
311
312
  }
312
313
  #bindApproval(sessionRef: string, active: ActiveRuntime): void {
313
314
  const authority = () => sessionApprovalAuthority(this.#key, sessionRef, active);
314
- active.unbindApproval = piApprovalBroker.bind({ cwd: active.info.cwd, rawSessionId: active.info.id,
315
- runtimeInstanceId: active.lease.runtimeInstanceRef!, authority });
315
+ // The main agent's questions to the member are answered here too (session-questions.ts).
316
+ const unbindQuestions = bindSessionQuestions(active.info.id, () => active.watchdog?.progress()), unbindApproval = piApprovalBroker.bind({
317
+ cwd: active.info.cwd, rawSessionId: active.info.id, runtimeInstanceId: active.lease.runtimeInstanceRef!, authority });
318
+ active.unbindApproval = () => { unbindQuestions(); unbindApproval(); };
316
319
  active.unsubscribeApproval = piApprovalBroker.subscribe(active.info.cwd, active.info.id, (event: ApprovalBrokerEvent) => {
317
320
  active.watchdog?.progress();
318
321
  const projection = piApprovalBroker.projection(active.info.cwd, active.info.id);
@@ -388,6 +391,8 @@ export class SessionRuntimeSupervisor {
388
391
  const active = this.#active.get(sessionRef);
389
392
  return active ? piApprovalBroker.detail(active.info.cwd, active.info.id, approvalRef) : null;
390
393
  }
394
+ questions(sessionRef: string) { return sessionQuestions(this.#active.get(sessionRef)?.info.id ?? null); }
395
+ answerQuestion(sessionRef: string, questionRef: string, answer: unknown): unknown { return answerSessionQuestion(this.#active.get(sessionRef)?.info.id ?? null, questionRef, answer); }
391
396
  async decideApproval(approvalRef: string, decision: unknown): Promise<unknown> {
392
397
  for (const active of this.#active.values()) {
393
398
  if (piApprovalBroker.detail(active.info.cwd, active.info.id, approvalRef)) {
@@ -0,0 +1,201 @@
1
+ import fs from "node:fs";
2
+ import os from "node:os";
3
+ import path from "node:path";
4
+ import { execFile, spawn } from "node:child_process";
5
+
6
+ import { compareReleaseVersions, releaseVersion, writeUpdateCache } from "../../piagent-core/extensions/update-check.js";
7
+
8
+ // Piagent updates from the dashboard: what is installed, what the registry
9
+ // offers, and one click that moves the machine to it. Pi is never offered
10
+ // past the version the newest Piagent pins (its peer dependency): that is the
11
+ // host its managed runtime is qualified on. A newer Pi is shown as untested.
12
+ //
13
+ // The registry is asked in the background, at most every 6 hours unless the
14
+ // member asks now; the dashboard reads the cached answer. Everything read from
15
+ // outside (registry answers, the cache and job files any local process could
16
+ // write) is accepted only as release versions and known codes.
17
+ const PLATFORM = "@piagent/platform";
18
+ const HOST = "@earendil-works/pi-coding-agent";
19
+ export const CHECK_EVERY_MS = 6 * 60 * 60 * 1000;
20
+ const FORCED_CHECK_GAP_MS = 30_000;
21
+ const PROBE_TIMEOUT_MS = 20_000;
22
+ const MAX_FILE_BYTES = 4096;
23
+ const STATUS_FILE = "piagent-update-status.json", JOB_FILE = "piagent-update-job.json";
24
+ // A run that has not finished in this time died with its process.
25
+ const JOB_STALE_MS = 45 * 60 * 1000;
26
+ // A finished run is reported for a day, then no longer.
27
+ const JOB_REPORTED_MS = 24 * 60 * 60 * 1000;
28
+ const JOB_STATES = new Set(["starting", "running", "succeeded", "failed"]);
29
+ const JOB_REASONS = new Set(["update-command-failed", "update-version-mismatch", "dashboard-restart-failed", "update-interrupted", "update-start-failed"]);
30
+
31
+ export type Registry = { latest?: string; latestHost?: string; hostLatest?: string; checkedAt?: number };
32
+ export type UpdateJob = { state: "starting" | "running" | "succeeded" | "failed"; from: string; to: string; startedAt: string;
33
+ finishedAt?: string; pid?: number; reason?: string; installed?: string; bindingChanged?: boolean };
34
+ export type UpdateStatus = {
35
+ schemaVersion: 1; version: "piagent-update-status-v1";
36
+ installable: boolean; reason: "working-copy" | "company-runtime" | null;
37
+ checkedAt: string | null; checking: boolean; checkEveryHours: number;
38
+ piagent: { installed: string | null; latest: string | null; updateAvailable: boolean };
39
+ pi: { installed: string | null; required: string | null; latest: string | null; updateAvailable: boolean; newerUntested: boolean };
40
+ updateAvailable: boolean; runningConversations: number; job: UpdateJob | null;
41
+ };
42
+
43
+ const stateDirectory = (home: string) => path.join(home, ".pi");
44
+ function readSmallJson(file: string): any {
45
+ try { if (fs.statSync(file).size > MAX_FILE_BYTES) return undefined; return JSON.parse(fs.readFileSync(file, "utf8")); }
46
+ catch { return undefined; }
47
+ }
48
+ function writeJson(file: string, value: unknown): void {
49
+ fs.mkdirSync(path.dirname(file), { recursive: true });
50
+ const temporary = `${file}.${process.pid}.tmp`;
51
+ fs.writeFileSync(temporary, `${JSON.stringify(value, null, 2)}\n`, { mode: 0o600 });
52
+ fs.renameSync(temporary, file);
53
+ }
54
+ const version = (value: unknown) => releaseVersion(value) ?? undefined;
55
+
56
+ export function readRegistryCache(home: string): Registry {
57
+ const value = readSmallJson(path.join(stateDirectory(home), STATUS_FILE)), checkedAt = Date.parse(value?.checkedAt);
58
+ return { latest: version(value?.latest), latestHost: version(value?.latestHost), hostLatest: version(value?.hostLatest),
59
+ checkedAt: Number.isFinite(checkedAt) ? checkedAt : undefined };
60
+ }
61
+ export function writeRegistryCache(home: string, registry: Registry, now: number): void {
62
+ writeJson(path.join(stateDirectory(home), STATUS_FILE), { schemaVersion: 1, latest: registry.latest ?? null, latestHost: registry.latestHost ?? null,
63
+ hostLatest: registry.hostLatest ?? null, checkedAt: new Date(now).toISOString() });
64
+ // The Terminal's own notice reads the shared cache: keep both on one answer.
65
+ if (registry.latest) writeUpdateCache(home, registry.latest, now);
66
+ }
67
+
68
+ export function readUpdateJob(home: string, now = Date.now(), alive = processAlive): UpdateJob | null {
69
+ const value = readSmallJson(path.join(stateDirectory(home), JOB_FILE));
70
+ const from = version(value?.from), to = version(value?.to), startedAt = Date.parse(value?.startedAt);
71
+ if (!value || !JOB_STATES.has(value.state) || !from || !to || !Number.isFinite(startedAt)) return null;
72
+ const job: UpdateJob = { state: value.state, from, to, startedAt: new Date(startedAt).toISOString() };
73
+ const finishedAt = Date.parse(value.finishedAt);
74
+ if (Number.isFinite(finishedAt)) job.finishedAt = new Date(finishedAt).toISOString();
75
+ if ((job.state === "succeeded" || job.state === "failed") && Number.isFinite(finishedAt) && now - finishedAt > JOB_REPORTED_MS) return null;
76
+ if (Number.isSafeInteger(value.pid) && value.pid > 0) job.pid = value.pid;
77
+ if (JOB_REASONS.has(value.reason)) job.reason = value.reason;
78
+ if (version(value.installed)) job.installed = version(value.installed);
79
+ if (value.bindingChanged === true) job.bindingChanged = true;
80
+ // A run whose process is gone (or never reported one) did not finish.
81
+ if ((job.state === "running" || job.state === "starting") && (now - startedAt > JOB_STALE_MS || (job.pid ? !alive(job.pid) : now - startedAt > 120_000)))
82
+ return { ...job, state: "failed", reason: "update-interrupted" };
83
+ return job;
84
+ }
85
+ export function writeUpdateJob(home: string, job: UpdateJob): void { writeJson(path.join(stateDirectory(home), JOB_FILE), job); }
86
+ function processAlive(pid: number): boolean { try { process.kill(pid, 0); return true; } catch (error) { return (error as NodeJS.ErrnoException).code === "EPERM"; } }
87
+
88
+ // The npm helper this dashboard runs from can update itself; a working copy
89
+ // is updated with git, and a company runtime by the dashboard that owns it.
90
+ export function updateTarget(packageRoot: string, managed: boolean): { installable: boolean; reason: UpdateStatus["reason"] } {
91
+ if (managed) return { installable: false, reason: "company-runtime" };
92
+ const parts = path.resolve(packageRoot).split(path.sep);
93
+ const installed = parts.includes("node_modules") && !parts.some((part) => part === "_npx" || part === "_cacache");
94
+ return installed ? { installable: true, reason: null } : { installable: false, reason: "working-copy" };
95
+ }
96
+
97
+ export function composeUpdateStatus(input: { installedPiagent?: string; installedPi?: string; target: ReturnType<typeof updateTarget>;
98
+ registry: Registry; job: UpdateJob | null; runningConversations: number; checking: boolean }): UpdateStatus {
99
+ const installedPiagent = version(input.installedPiagent) ?? null, installedPi = version(input.installedPi) ?? null;
100
+ const { latest, latestHost, hostLatest } = input.registry;
101
+ const piagentNewer = Boolean(installedPiagent && latest && compareReleaseVersions(latest, installedPiagent) > 0);
102
+ // The Pi update is the version the newest Piagent pins, whichever way it
103
+ // moves; it is only offered together with that Piagent.
104
+ const piChange = Boolean(latestHost && installedPi !== latestHost && (piagentNewer || installedPiagent === latest));
105
+ return { schemaVersion: 1, version: "piagent-update-status-v1", installable: input.target.installable, reason: input.target.reason,
106
+ checkedAt: input.registry.checkedAt ? new Date(input.registry.checkedAt).toISOString() : null, checking: input.checking,
107
+ checkEveryHours: CHECK_EVERY_MS / 3_600_000,
108
+ piagent: { installed: installedPiagent, latest: latest ?? null, updateAvailable: piagentNewer },
109
+ pi: { installed: installedPi, required: latestHost ?? null, latest: hostLatest ?? null, updateAvailable: piChange,
110
+ newerUntested: Boolean(hostLatest && latestHost && compareReleaseVersions(hostLatest, latestHost) > 0) },
111
+ updateAvailable: piagentNewer || piChange, runningConversations: input.runningConversations, job: input.job };
112
+ }
113
+
114
+ type NpmView = (spec: string, field: string) => Promise<unknown>;
115
+ const npmView: NpmView = (spec, field) => new Promise((resolve) => {
116
+ execFile("npm", ["view", spec, field, "--json"], { timeout: PROBE_TIMEOUT_MS, windowsHide: true, maxBuffer: 256 * 1024 },
117
+ (error, stdout) => { if (error) return resolve(undefined); try { const value = JSON.parse(String(stdout).trim() || "null"); resolve(Array.isArray(value) && value.length === 1 ? value[0] : value); } catch { resolve(undefined); } });
118
+ });
119
+
120
+ // One answer from the registry, or null when it could not be read.
121
+ export async function probeRegistry(view: NpmView = npmView): Promise<Registry | null> {
122
+ const latest = version(await view(PLATFORM, "version"));
123
+ if (!latest) return null;
124
+ const peers = await view(`${PLATFORM}@${latest}`, "peerDependencies") as Record<string, unknown> | undefined;
125
+ return { latest, latestHost: version(peers?.[HOST]), hostLatest: version(await view(HOST, "version")) };
126
+ }
127
+
128
+ export class UpdateCenter {
129
+ #home: string; #packageRoot: string; #piVersion?: string; #target: ReturnType<typeof updateTarget>;
130
+ #busy: () => Promise<number>; #view: NpmView; #now: () => number; #spawnJob: (args: string[]) => number | undefined;
131
+ #probe: Promise<void> | null = null; #lastForced = 0; #timer: NodeJS.Timeout | null = null;
132
+
133
+ constructor(options: { packageRoot: string; piVersion?: string; managed: boolean; busy: () => Promise<number>; home?: string;
134
+ view?: NpmView; now?: () => number; spawnJob?: (args: string[]) => number | undefined }) {
135
+ this.#home = options.home ?? os.homedir(); this.#packageRoot = options.packageRoot; this.#piVersion = options.piVersion;
136
+ this.#target = updateTarget(options.packageRoot, options.managed); this.#busy = options.busy;
137
+ this.#view = options.view ?? npmView; this.#now = options.now ?? Date.now;
138
+ this.#spawnJob = options.spawnJob ?? ((args) => {
139
+ const child = spawn(process.execPath, args, { detached: true, stdio: "ignore", windowsHide: true, cwd: this.#home,
140
+ env: { ...process.env, PIAGENT_NO_UPDATE_CHECK: "1" } });
141
+ child.unref(); return child.pid;
142
+ });
143
+ }
144
+
145
+ // Only a machine that can update itself asks the registry (a working copy
146
+ // or a company runtime never does, nor any run with PIAGENT_NO_UPDATE_CHECK).
147
+ #asks(): boolean { return this.#target.installable && !process.env.PIAGENT_NO_UPDATE_CHECK?.trim(); }
148
+ // Checks now when the cached answer is older than the period, then on it.
149
+ start(): void {
150
+ if (this.#timer || !this.#asks()) return;
151
+ void this.#refreshIfStale();
152
+ this.#timer = setInterval(() => void this.#refreshIfStale(), 15 * 60 * 1000); this.#timer.unref();
153
+ }
154
+ close(): void { if (this.#timer) clearInterval(this.#timer); this.#timer = null; }
155
+
156
+ #installedPiagent(): string | undefined {
157
+ try { return version(JSON.parse(fs.readFileSync(path.join(this.#packageRoot, "package.json"), "utf8")).version); } catch { return undefined; }
158
+ }
159
+ async #refreshIfStale(): Promise<void> {
160
+ const checkedAt = readRegistryCache(this.#home).checkedAt;
161
+ if (!checkedAt || this.#now() - checkedAt >= CHECK_EVERY_MS) await this.#refresh();
162
+ }
163
+ #refresh(): Promise<void> {
164
+ this.#probe ??= (async () => {
165
+ try { const registry = await probeRegistry(this.#view); if (registry) writeRegistryCache(this.#home, registry, this.#now()); }
166
+ catch { /* the next period tries again */ }
167
+ finally { this.#probe = null; }
168
+ })();
169
+ return this.#probe;
170
+ }
171
+
172
+ async status(): Promise<UpdateStatus> {
173
+ return composeUpdateStatus({ installedPiagent: this.#installedPiagent(), installedPi: this.#piVersion, target: this.#target,
174
+ registry: readRegistryCache(this.#home), job: readUpdateJob(this.#home, this.#now()), runningConversations: await this.#busy().catch(() => 0),
175
+ checking: this.#probe !== null });
176
+ }
177
+ async check(): Promise<UpdateStatus> {
178
+ if (!this.#asks()) return this.status();
179
+ if (this.#now() - this.#lastForced >= FORCED_CHECK_GAP_MS) { this.#lastForced = this.#now(); await this.#refresh(); }
180
+ else if (this.#probe) await this.#probe;
181
+ return this.status();
182
+ }
183
+ // `request.version`: the Piagent version the member chose to install.
184
+ async apply(request: unknown): Promise<{ job: UpdateJob }> {
185
+ const wanted = version((request as { version?: unknown } | null)?.version);
186
+ if (!wanted) throw new Error("update-request-invalid");
187
+ const status = await this.status();
188
+ if (!status.installable) throw new Error("update-not-installable");
189
+ if (status.job && (status.job.state === "running" || status.job.state === "starting")) throw new Error("update-already-running");
190
+ if (status.runningConversations > 0) throw new Error("update-blocked-running");
191
+ if (!status.updateAvailable) throw new Error("update-not-available");
192
+ if (wanted !== status.piagent.latest) throw new Error("update-version-changed");
193
+ const from = status.piagent.installed ?? wanted;
194
+ const job: UpdateJob = { state: "starting", from, to: wanted, startedAt: new Date(this.#now()).toISOString() };
195
+ writeUpdateJob(this.#home, job);
196
+ const pid = this.#spawnJob([path.join(this.#packageRoot, "scripts", "dashboard-update-job.mjs"), "--from", from, "--to", wanted]);
197
+ if (!pid) { const failed: UpdateJob = { ...job, state: "failed", reason: "update-start-failed", finishedAt: new Date(this.#now()).toISOString() }; writeUpdateJob(this.#home, failed); return { job: failed }; }
198
+ const started: UpdateJob = { ...job, pid }; writeUpdateJob(this.#home, started);
199
+ return { job: started };
200
+ }
201
+ }
@@ -1,4 +1,4 @@
1
- import type { ServerResponse } from "node:http";
1
+ import type { IncomingMessage, ServerResponse } from "node:http";
2
2
 
3
3
  export const SECURITY_HEADERS = Object.freeze({
4
4
  "Cross-Origin-Opener-Policy": "same-origin",
@@ -25,3 +25,17 @@ export function jsonResponse(response: ServerResponse, status: number, value: un
25
25
  export function errorResponse(response: ServerResponse, status: number, code: string): void {
26
26
  jsonResponse(response, status, { error: { code } });
27
27
  }
28
+
29
+ export function requestBody(request: IncomingMessage, maximumBytes: number): Promise<Buffer> {
30
+ return new Promise((resolve, reject) => {
31
+ const chunks: Buffer[] = []; let bytes = 0, failed = false;
32
+ request.on("data", (chunk: Buffer) => {
33
+ if (failed) return;
34
+ bytes += chunk.length;
35
+ if (bytes > maximumBytes) { failed = true; reject(new Error("body-limit")); }
36
+ else chunks.push(chunk);
37
+ });
38
+ request.on("end", () => { if (!failed) resolve(Buffer.concat(chunks)); });
39
+ request.on("error", (error) => { if (!failed) reject(error); });
40
+ });
41
+ }