codex-autorunner 1.2.1__py3-none-any.whl → 1.3.0__py3-none-any.whl

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 (55) hide show
  1. codex_autorunner/bootstrap.py +26 -5
  2. codex_autorunner/core/config.py +176 -59
  3. codex_autorunner/core/filesystem.py +24 -0
  4. codex_autorunner/core/flows/controller.py +50 -12
  5. codex_autorunner/core/flows/runtime.py +8 -3
  6. codex_autorunner/core/hub.py +293 -16
  7. codex_autorunner/core/lifecycle_events.py +44 -5
  8. codex_autorunner/core/pma_delivery.py +81 -0
  9. codex_autorunner/core/pma_dispatches.py +224 -0
  10. codex_autorunner/core/pma_lane_worker.py +122 -0
  11. codex_autorunner/core/pma_queue.py +167 -18
  12. codex_autorunner/core/pma_reactive.py +91 -0
  13. codex_autorunner/core/pma_safety.py +58 -0
  14. codex_autorunner/core/pma_sink.py +104 -0
  15. codex_autorunner/core/pma_transcripts.py +183 -0
  16. codex_autorunner/core/safe_paths.py +117 -0
  17. codex_autorunner/housekeeping.py +77 -23
  18. codex_autorunner/integrations/agents/codex_backend.py +18 -12
  19. codex_autorunner/integrations/agents/wiring.py +2 -0
  20. codex_autorunner/integrations/app_server/client.py +31 -0
  21. codex_autorunner/integrations/app_server/supervisor.py +3 -0
  22. codex_autorunner/integrations/telegram/constants.py +1 -1
  23. codex_autorunner/integrations/telegram/handlers/commands/execution.py +16 -15
  24. codex_autorunner/integrations/telegram/handlers/commands/files.py +5 -8
  25. codex_autorunner/integrations/telegram/handlers/commands/github.py +10 -6
  26. codex_autorunner/integrations/telegram/handlers/commands/shared.py +9 -8
  27. codex_autorunner/integrations/telegram/handlers/commands/workspace.py +85 -2
  28. codex_autorunner/integrations/telegram/handlers/commands_runtime.py +29 -8
  29. codex_autorunner/integrations/telegram/helpers.py +30 -2
  30. codex_autorunner/integrations/telegram/ticket_flow_bridge.py +54 -3
  31. codex_autorunner/static/docChatCore.js +2 -0
  32. codex_autorunner/static/hub.js +59 -0
  33. codex_autorunner/static/index.html +70 -54
  34. codex_autorunner/static/notificationBell.js +173 -0
  35. codex_autorunner/static/notifications.js +154 -36
  36. codex_autorunner/static/pma.js +96 -35
  37. codex_autorunner/static/styles.css +415 -4
  38. codex_autorunner/static/utils.js +5 -1
  39. codex_autorunner/surfaces/cli/cli.py +206 -129
  40. codex_autorunner/surfaces/cli/template_repos.py +157 -0
  41. codex_autorunner/surfaces/web/app.py +193 -5
  42. codex_autorunner/surfaces/web/routes/file_chat.py +109 -61
  43. codex_autorunner/surfaces/web/routes/flows.py +125 -67
  44. codex_autorunner/surfaces/web/routes/pma.py +638 -57
  45. codex_autorunner/tickets/agent_pool.py +6 -1
  46. codex_autorunner/tickets/outbox.py +27 -14
  47. codex_autorunner/tickets/replies.py +4 -10
  48. codex_autorunner/tickets/runner.py +1 -0
  49. codex_autorunner/workspace/paths.py +8 -3
  50. {codex_autorunner-1.2.1.dist-info → codex_autorunner-1.3.0.dist-info}/METADATA +1 -1
  51. {codex_autorunner-1.2.1.dist-info → codex_autorunner-1.3.0.dist-info}/RECORD +55 -45
  52. {codex_autorunner-1.2.1.dist-info → codex_autorunner-1.3.0.dist-info}/WHEEL +0 -0
  53. {codex_autorunner-1.2.1.dist-info → codex_autorunner-1.3.0.dist-info}/entry_points.txt +0 -0
  54. {codex_autorunner-1.2.1.dist-info → codex_autorunner-1.3.0.dist-info}/licenses/LICENSE +0 -0
  55. {codex_autorunner-1.2.1.dist-info → codex_autorunner-1.3.0.dist-info}/top_level.txt +0 -0
@@ -2,12 +2,13 @@
2
2
  /**
3
3
  * PMA (Project Management Agent) - Hub-level chat interface
4
4
  */
5
- import { api, confirmModal, resolvePath, getAuthToken, flash } from "./utils.js";
5
+ import { api, resolvePath, getAuthToken, flash } from "./utils.js";
6
6
  import { createDocChat, } from "./docChatCore.js";
7
7
  import { initChatPasteUpload } from "./chatUploads.js";
8
8
  import { clearAgentSelectionStorage, getSelectedAgent, getSelectedModel, getSelectedReasoning, initAgentControls, refreshAgentControls, } from "./agentControls.js";
9
9
  import { createFileBoxWidget } from "./fileboxUi.js";
10
10
  import { extractContextRemainingPercent } from "./streamUtils.js";
11
+ import { initNotificationBell } from "./notificationBell.js";
11
12
  const pmaStyling = {
12
13
  eventClass: "chat-event",
13
14
  eventTitleClass: "chat-event-title",
@@ -44,6 +45,7 @@ let isUnloading = false;
44
45
  let unloadHandlerInstalled = false;
45
46
  let currentEventsController = null;
46
47
  const PMA_PENDING_TURN_KEY = "car.pma.pendingTurn";
48
+ const PMA_VIEW_KEY = "car.pma.view";
47
49
  const DEFAULT_PMA_LANE_ID = "pma:default";
48
50
  let fileBoxCtrl = null;
49
51
  let pendingUploadNames = [];
@@ -94,6 +96,29 @@ function clearPendingTurn() {
94
96
  // ignore
95
97
  }
96
98
  }
99
+ function loadPMAView() {
100
+ const raw = localStorage.getItem(PMA_VIEW_KEY);
101
+ if (raw === "memory")
102
+ return "memory";
103
+ return "chat";
104
+ }
105
+ function setPMAView(view, options = {}) {
106
+ const elements = getElements();
107
+ const { persist = true } = options;
108
+ if (persist) {
109
+ localStorage.setItem(PMA_VIEW_KEY, view);
110
+ }
111
+ if (elements.shell) {
112
+ elements.shell.setAttribute("data-pma-view", view);
113
+ }
114
+ document.querySelectorAll(".pma-view-btn").forEach((btn) => {
115
+ const isActive = btn.dataset.view === view;
116
+ btn.classList.toggle("active", isActive);
117
+ btn.setAttribute("aria-selected", isActive ? "true" : "false");
118
+ });
119
+ elements.chatSection?.classList.toggle("hidden", view !== "chat");
120
+ elements.docsSection?.classList.toggle("hidden", view !== "memory");
121
+ }
97
122
  async function initFileBoxUI() {
98
123
  const elements = getElements();
99
124
  if (!elements.inboxFiles || !elements.outboxFiles)
@@ -124,6 +149,7 @@ async function initFileBoxUI() {
124
149
  }
125
150
  pendingUploadNames = [];
126
151
  }
152
+ updateClearButtons(listing);
127
153
  },
128
154
  onUpload: (names) => {
129
155
  pendingUploadNames = names;
@@ -172,11 +198,15 @@ async function loadPMADocContent(name) {
172
198
  return payload?.content || "";
173
199
  }
174
200
  catch (err) {
201
+ const content = await bootstrapPMADoc(name);
202
+ if (content) {
203
+ return content;
204
+ }
175
205
  flash(`Failed to load ${name}`, "error");
176
206
  return "";
177
207
  }
178
208
  }
179
- async function loadPMADocDefaultContent(name) {
209
+ async function loadPMADocDefaultContent(name, options = {}) {
180
210
  try {
181
211
  const payload = (await api(`/hub/pma/docs/default/${encodeURIComponent(name)}`, {
182
212
  method: "GET",
@@ -184,10 +214,28 @@ async function loadPMADocDefaultContent(name) {
184
214
  return payload?.content || "";
185
215
  }
186
216
  catch (err) {
187
- flash(`Failed to load default ${name}`, "error");
217
+ if (!options.silent) {
218
+ flash(`Failed to load default ${name}`, "error");
219
+ }
188
220
  return "";
189
221
  }
190
222
  }
223
+ async function bootstrapPMADoc(name) {
224
+ const content = await loadPMADocDefaultContent(name, { silent: true });
225
+ if (!content)
226
+ return "";
227
+ try {
228
+ await api(`/hub/pma/docs/${encodeURIComponent(name)}`, {
229
+ method: "PUT",
230
+ body: { content },
231
+ });
232
+ await loadPMADocs();
233
+ return content;
234
+ }
235
+ catch {
236
+ return content;
237
+ }
238
+ }
191
239
  async function savePMADoc(name, content) {
192
240
  if (isSavingDoc)
193
241
  return;
@@ -282,9 +330,8 @@ async function snapshotActiveContext() {
282
330
  flash("Failed to snapshot active context", "error");
283
331
  }
284
332
  }
285
- async function resetActiveContext() {
286
- const confirmed = await confirmModal("Reset active context to default?");
287
- if (!confirmed)
333
+ function resetActiveContext() {
334
+ if (!confirm("Reset active context to default?"))
288
335
  return;
289
336
  const editor = document.getElementById("pma-docs-editor");
290
337
  if (!editor)
@@ -356,6 +403,7 @@ async function pollForTurnMeta(clientTurnId, options = {}) {
356
403
  function getElements() {
357
404
  return {
358
405
  shell: document.getElementById("pma-shell"),
406
+ chatSection: document.getElementById("pma-chat-section"),
359
407
  input: document.getElementById("pma-chat-input"),
360
408
  sendBtn: document.getElementById("pma-chat-send"),
361
409
  cancelBtn: document.getElementById("pma-chat-cancel"),
@@ -376,6 +424,8 @@ function getElements() {
376
424
  inboxFiles: document.getElementById("pma-inbox-files"),
377
425
  outboxFiles: document.getElementById("pma-outbox-files"),
378
426
  outboxRefresh: document.getElementById("pma-outbox-refresh"),
427
+ inboxClear: document.getElementById("pma-inbox-clear"),
428
+ outboxClear: document.getElementById("pma-outbox-clear"),
379
429
  threadInfo: document.getElementById("pma-thread-info"),
380
430
  threadInfoAgent: document.getElementById("pma-thread-info-agent"),
381
431
  threadInfoThreadId: document.getElementById("pma-thread-info-thread-id"),
@@ -471,6 +521,8 @@ async function initPMA() {
471
521
  await initFileBoxUI();
472
522
  await loadPMADocs();
473
523
  attachHandlers();
524
+ setPMAView(loadPMAView(), { persist: false });
525
+ initNotificationBell();
474
526
  // If we refreshed mid-turn, recover the final output from the server.
475
527
  await resumePendingTurn();
476
528
  // If the page refreshes/navigates while a turn is running, avoid showing a noisy
@@ -543,6 +595,23 @@ async function loadPMAThreadInfo() {
543
595
  elements.threadInfo?.classList.add("hidden");
544
596
  }
545
597
  }
598
+ function updateClearButtons(listing) {
599
+ const elements = getElements();
600
+ if (!elements.inboxClear || !elements.outboxClear)
601
+ return;
602
+ const inboxCount = listing?.inbox?.length ?? 0;
603
+ const outboxCount = listing?.outbox?.length ?? 0;
604
+ elements.inboxClear.classList.toggle("hidden", inboxCount <= 1);
605
+ elements.outboxClear.classList.toggle("hidden", outboxCount <= 1);
606
+ }
607
+ async function clearPMABox(box) {
608
+ const confirmed = window.confirm(`Clear ${box}? This will delete all files.`);
609
+ if (!confirmed)
610
+ return;
611
+ await api(`/hub/pma/files/${box}`, { method: "DELETE" });
612
+ flash(`Cleared ${box}`, "info");
613
+ await fileBoxCtrl?.refresh();
614
+ }
546
615
  async function sendMessage() {
547
616
  const elements = getElements();
548
617
  if (!elements.input || !pmaChat)
@@ -1006,6 +1075,14 @@ async function startNewThreadOnServer() {
1006
1075
  }
1007
1076
  function attachHandlers() {
1008
1077
  const elements = getElements();
1078
+ document.addEventListener("click", (event) => {
1079
+ const target = event.target;
1080
+ const btn = target?.closest?.(".pma-view-btn");
1081
+ if (!btn)
1082
+ return;
1083
+ const value = (btn.dataset.view || "chat");
1084
+ setPMAView(value);
1085
+ });
1009
1086
  if (elements.sendBtn) {
1010
1087
  elements.sendBtn.addEventListener("click", () => {
1011
1088
  void sendMessage();
@@ -1066,12 +1143,22 @@ function attachHandlers() {
1066
1143
  void fileBoxCtrl?.refresh();
1067
1144
  });
1068
1145
  }
1146
+ if (elements.inboxClear) {
1147
+ elements.inboxClear.addEventListener("click", () => {
1148
+ void clearPMABox("inbox");
1149
+ });
1150
+ }
1151
+ if (elements.outboxClear) {
1152
+ elements.outboxClear.addEventListener("click", () => {
1153
+ void clearPMABox("outbox");
1154
+ });
1155
+ }
1069
1156
  if (elements.scanReposBtn) {
1070
1157
  elements.scanReposBtn.addEventListener("click", async () => {
1158
+ const btn = elements.scanReposBtn;
1159
+ const originalText = btn.textContent || "";
1071
1160
  try {
1072
- const btn = elements.scanReposBtn;
1073
1161
  btn.disabled = true;
1074
- btn.textContent = "Scanning…";
1075
1162
  await api("/hub/repos/scan", { method: "POST" });
1076
1163
  flash("Repositories scanned", "info");
1077
1164
  }
@@ -1079,9 +1166,8 @@ function attachHandlers() {
1079
1166
  flash("Failed to scan repos", "error");
1080
1167
  }
1081
1168
  finally {
1082
- const btn = elements.scanReposBtn;
1083
1169
  btn.disabled = false;
1084
- btn.textContent = "Scan repos";
1170
+ btn.textContent = btn.textContent || originalText;
1085
1171
  }
1086
1172
  });
1087
1173
  }
@@ -1132,31 +1218,6 @@ function attachHandlers() {
1132
1218
  void snapshotActiveContext();
1133
1219
  });
1134
1220
  }
1135
- const pmaModeManual = document.getElementById("pma-mode-manual");
1136
- const pmaModePma = document.getElementById("pma-mode-pma");
1137
- const docsSection = document.getElementById("pma-docs-section");
1138
- if (pmaModeManual && pmaModePma) {
1139
- const handleModeChange = (mode) => {
1140
- if (!docsSection)
1141
- return;
1142
- if (mode === "manual") {
1143
- docsSection.classList.remove("hidden");
1144
- }
1145
- else {
1146
- docsSection.classList.add("hidden");
1147
- }
1148
- };
1149
- pmaModeManual.addEventListener("click", () => {
1150
- if (pmaModeManual.dataset.hubMode === "manual") {
1151
- handleModeChange("manual");
1152
- }
1153
- });
1154
- pmaModePma.addEventListener("click", () => {
1155
- if (pmaModePma.dataset.hubMode === "pma") {
1156
- handleModeChange("pma");
1157
- }
1158
- });
1159
- }
1160
1221
  if (elements.docsEditor) {
1161
1222
  elements.docsEditor.addEventListener("input", () => {
1162
1223
  elements.docsEditor.style.height = "auto";
@@ -1080,6 +1080,19 @@ main {
1080
1080
  gap: 8px;
1081
1081
  }
1082
1082
 
1083
+ .notifications-modal-links {
1084
+ display: flex;
1085
+ flex-direction: column;
1086
+ gap: 6px;
1087
+ margin-top: 8px;
1088
+ }
1089
+
1090
+ .notifications-modal-links a {
1091
+ color: var(--accent);
1092
+ text-decoration: none;
1093
+ font-size: 12px;
1094
+ }
1095
+
1083
1096
  .notifications-open-run {
1084
1097
  display: inline-flex;
1085
1098
  align-items: center;
@@ -12536,6 +12549,143 @@ button.filebox-delete:hover {
12536
12549
  overflow: hidden;
12537
12550
  }
12538
12551
 
12552
+ /* PMA Dispatches */
12553
+ .pma-dispatches-section {
12554
+ padding: 10px 12px;
12555
+ display: flex;
12556
+ flex-direction: column;
12557
+ gap: 10px;
12558
+ }
12559
+
12560
+ .pma-dispatches-header {
12561
+ display: flex;
12562
+ align-items: center;
12563
+ gap: 8px;
12564
+ }
12565
+
12566
+ .pma-dispatches-header h2 {
12567
+ margin: 0;
12568
+ font-size: 14px;
12569
+ font-weight: 600;
12570
+ color: var(--text);
12571
+ }
12572
+
12573
+ .pma-dispatches-content {
12574
+ display: grid;
12575
+ grid-template-columns: minmax(200px, 1fr) minmax(280px, 1.4fr);
12576
+ gap: 12px;
12577
+ min-height: 180px;
12578
+ }
12579
+
12580
+ .pma-dispatches-list {
12581
+ display: flex;
12582
+ flex-direction: column;
12583
+ gap: 8px;
12584
+ max-height: 320px;
12585
+ overflow-y: auto;
12586
+ border: 1px solid var(--border);
12587
+ border-radius: var(--radius);
12588
+ background: rgba(8, 10, 16, 0.4);
12589
+ padding: 8px;
12590
+ }
12591
+
12592
+ .pma-dispatch-item {
12593
+ display: flex;
12594
+ flex-direction: column;
12595
+ gap: 4px;
12596
+ padding: 8px;
12597
+ border: 1px solid transparent;
12598
+ border-radius: var(--radius);
12599
+ background: rgba(15, 18, 28, 0.7);
12600
+ cursor: pointer;
12601
+ transition: border-color 0.15s ease, background 0.15s ease;
12602
+ }
12603
+
12604
+ .pma-dispatch-item:hover {
12605
+ border-color: rgba(108, 245, 216, 0.4);
12606
+ }
12607
+
12608
+ .pma-dispatch-item.active {
12609
+ border-color: var(--accent);
12610
+ box-shadow: 0 0 0 1px rgba(108, 245, 216, 0.2);
12611
+ }
12612
+
12613
+ .pma-dispatch-item.resolved {
12614
+ opacity: 0.6;
12615
+ }
12616
+
12617
+ .pma-dispatch-item-title {
12618
+ font-size: 13px;
12619
+ font-weight: 600;
12620
+ color: var(--text);
12621
+ }
12622
+
12623
+ .pma-dispatch-item-meta {
12624
+ display: flex;
12625
+ align-items: center;
12626
+ gap: 6px;
12627
+ font-size: 11px;
12628
+ color: var(--muted);
12629
+ }
12630
+
12631
+ .pma-dispatches-detail {
12632
+ border: 1px solid var(--border);
12633
+ border-radius: var(--radius);
12634
+ background: rgba(8, 10, 16, 0.4);
12635
+ padding: 12px;
12636
+ min-height: 180px;
12637
+ }
12638
+
12639
+ .pma-dispatch-detail-title {
12640
+ margin: 0 0 6px;
12641
+ font-size: 14px;
12642
+ font-weight: 600;
12643
+ color: var(--text);
12644
+ }
12645
+
12646
+ .pma-dispatch-detail-meta {
12647
+ display: flex;
12648
+ align-items: center;
12649
+ gap: 8px;
12650
+ font-size: 11px;
12651
+ color: var(--muted);
12652
+ margin-bottom: 10px;
12653
+ }
12654
+
12655
+ .pma-dispatch-detail-body {
12656
+ font-size: 13px;
12657
+ line-height: 1.5;
12658
+ color: var(--text);
12659
+ margin-bottom: 12px;
12660
+ }
12661
+
12662
+ .pma-dispatch-detail-links {
12663
+ display: flex;
12664
+ flex-direction: column;
12665
+ gap: 6px;
12666
+ margin-bottom: 12px;
12667
+ }
12668
+
12669
+ .pma-dispatch-detail-links a {
12670
+ color: var(--accent);
12671
+ text-decoration: none;
12672
+ font-size: 12px;
12673
+ }
12674
+
12675
+ .pma-dispatch-detail-actions {
12676
+ display: flex;
12677
+ gap: 8px;
12678
+ }
12679
+
12680
+ @media (max-width: 900px) {
12681
+ .pma-dispatches-content {
12682
+ grid-template-columns: 1fr;
12683
+ }
12684
+ .pma-dispatches-list {
12685
+ max-height: 220px;
12686
+ }
12687
+ }
12688
+
12539
12689
  .pma-chat-main {
12540
12690
  flex: 1 1 0;
12541
12691
  display: flex;
@@ -13494,21 +13644,28 @@ button.filebox-delete:hover {
13494
13644
  /* PMA Top Bar */
13495
13645
  .pma-top-bar {
13496
13646
  display: flex;
13497
- flex-direction: column;
13498
- gap: 6px;
13499
- padding: 6px 8px;
13647
+ flex-direction: row;
13648
+ align-items: center;
13649
+ justify-content: space-between;
13650
+ gap: 10px;
13651
+ padding: 6px 10px;
13500
13652
  background: var(--bg-surface);
13501
13653
  border-bottom: 1px solid var(--border);
13502
13654
  flex-shrink: 0;
13503
13655
  }
13504
13656
 
13657
+ .pma-dispatches-section {
13658
+ padding: 10px 12px;
13659
+ border-bottom: 1px solid var(--border);
13660
+ background: var(--bg-surface);
13661
+ }
13662
+
13505
13663
  .pma-paused-runs-bar {
13506
13664
  display: flex;
13507
13665
  flex-direction: row;
13508
13666
  align-items: stretch;
13509
13667
  gap: 8px;
13510
13668
  padding: 6px 8px;
13511
- border-bottom: 1px solid var(--border);
13512
13669
  background: var(--panel);
13513
13670
  max-height: none;
13514
13671
  }
@@ -13573,6 +13730,37 @@ button.filebox-delete:hover {
13573
13730
  background: var(--panel);
13574
13731
  }
13575
13732
 
13733
+ .pma-view-tabs {
13734
+ display: flex;
13735
+ gap: 6px;
13736
+ padding: 8px 10px;
13737
+ border-bottom: 1px solid var(--border);
13738
+ background: var(--panel);
13739
+ }
13740
+
13741
+ .pma-view-tab {
13742
+ padding: 6px 12px;
13743
+ font-size: 11px;
13744
+ font-weight: 600;
13745
+ color: var(--muted);
13746
+ background: transparent;
13747
+ border: 1px solid transparent;
13748
+ border-radius: 999px;
13749
+ cursor: pointer;
13750
+ transition: color 0.15s, background 0.15s, border-color 0.15s;
13751
+ }
13752
+
13753
+ .pma-view-tab:hover {
13754
+ color: var(--text);
13755
+ background: var(--hover-bg);
13756
+ }
13757
+
13758
+ .pma-view-tab.active {
13759
+ color: var(--text);
13760
+ background: var(--primary-bg);
13761
+ border-color: var(--border);
13762
+ }
13763
+
13576
13764
  .pma-inbox-list {
13577
13765
  flex: 1;
13578
13766
  display: flex;
@@ -13583,6 +13771,219 @@ button.filebox-delete:hover {
13583
13771
  max-height: none;
13584
13772
  }
13585
13773
 
13774
+ .pma-dispatches-section .pma-paused-runs-bar {
13775
+ flex-direction: column;
13776
+ align-items: stretch;
13777
+ padding: 10px 12px;
13778
+ border: 1px solid var(--border);
13779
+ border-radius: var(--radius);
13780
+ }
13781
+
13782
+ .pma-dispatches-section .pma-inbox-list {
13783
+ flex-direction: column;
13784
+ align-items: stretch;
13785
+ gap: 10px;
13786
+ overflow-y: auto;
13787
+ overflow-x: hidden;
13788
+ }
13789
+
13790
+ .pma-dispatches-section .pma-inbox-item {
13791
+ max-width: none;
13792
+ width: 100%;
13793
+ padding: 10px 12px;
13794
+ border-radius: var(--radius);
13795
+ display: flex;
13796
+ flex-direction: column;
13797
+ align-items: stretch;
13798
+ gap: 6px;
13799
+ }
13800
+
13801
+ .pma-dispatches-section .pma-inbox-item-header {
13802
+ display: flex;
13803
+ align-items: center;
13804
+ gap: 8px;
13805
+ justify-content: space-between;
13806
+ }
13807
+
13808
+ .pma-dispatches-section .pma-inbox-title {
13809
+ display: block;
13810
+ }
13811
+
13812
+ .pma-dispatches-section .pma-inbox-excerpt {
13813
+ display: block;
13814
+ }
13815
+
13816
+ .pma-dispatches-section .pma-inbox-actions {
13817
+ display: flex;
13818
+ gap: 6px;
13819
+ flex-wrap: wrap;
13820
+ }
13821
+
13822
+ .pma-dispatches-section .pma-inbox-item-header .pill {
13823
+ display: inline-flex;
13824
+ }
13825
+
13826
+ .pma-view-toggle {
13827
+ display: inline-flex;
13828
+ align-items: center;
13829
+ gap: 2px;
13830
+ padding: 2px;
13831
+ border: 1px solid var(--border);
13832
+ border-radius: 999px;
13833
+ background: var(--panel);
13834
+ }
13835
+
13836
+ .pma-view-btn {
13837
+ height: 22px;
13838
+ padding: 0 10px;
13839
+ font-size: 10px;
13840
+ font-weight: 600;
13841
+ text-transform: uppercase;
13842
+ letter-spacing: 0.4px;
13843
+ border: none;
13844
+ border-radius: 999px;
13845
+ background: transparent;
13846
+ color: var(--muted);
13847
+ cursor: pointer;
13848
+ transition: color 0.15s ease, background 0.15s ease;
13849
+ }
13850
+
13851
+ .pma-view-btn:hover {
13852
+ color: var(--text);
13853
+ }
13854
+
13855
+ .pma-view-btn.active,
13856
+ .pma-view-btn[aria-selected="true"] {
13857
+ background: rgba(108, 245, 216, 0.16);
13858
+ color: var(--accent);
13859
+ }
13860
+
13861
+ .hub-shell[data-pma-view="chat"] #pma-docs-section {
13862
+ display: none !important;
13863
+ }
13864
+
13865
+ .hub-shell[data-pma-view="memory"] #pma-chat-section {
13866
+ display: none !important;
13867
+ }
13868
+
13869
+ .notification-bell {
13870
+ position: relative;
13871
+ overflow: visible;
13872
+ }
13873
+
13874
+ .notification-bell-icon {
13875
+ width: 18px;
13876
+ height: 18px;
13877
+ stroke: currentColor;
13878
+ stroke-width: 1.6;
13879
+ fill: none;
13880
+ }
13881
+
13882
+ .notification-bell:hover .notification-bell-icon {
13883
+ stroke: var(--accent);
13884
+ }
13885
+
13886
+ .notification-badge {
13887
+ position: absolute;
13888
+ top: 3px;
13889
+ right: 3px;
13890
+ min-width: 16px;
13891
+ height: 16px;
13892
+ padding: 0 4px;
13893
+ border-radius: 999px;
13894
+ background: var(--accent);
13895
+ color: #031311;
13896
+ font-size: 9px;
13897
+ font-weight: 700;
13898
+ display: inline-flex;
13899
+ align-items: center;
13900
+ justify-content: center;
13901
+ box-shadow: 0 0 0 2px var(--bg);
13902
+ }
13903
+
13904
+ .notification-dialog {
13905
+ max-width: 640px;
13906
+ }
13907
+
13908
+ .notification-modal-header {
13909
+ display: flex;
13910
+ align-items: center;
13911
+ justify-content: space-between;
13912
+ gap: 12px;
13913
+ }
13914
+
13915
+ .notification-modal-actions {
13916
+ display: inline-flex;
13917
+ align-items: center;
13918
+ gap: 6px;
13919
+ }
13920
+
13921
+ .notification-list {
13922
+ display: flex;
13923
+ flex-direction: column;
13924
+ gap: 10px;
13925
+ }
13926
+
13927
+ .notification-item {
13928
+ padding: 12px;
13929
+ border: 1px solid var(--border);
13930
+ border-radius: var(--radius);
13931
+ background: var(--panel);
13932
+ display: flex;
13933
+ flex-direction: column;
13934
+ gap: 6px;
13935
+ }
13936
+
13937
+ .notification-item-header {
13938
+ display: flex;
13939
+ align-items: center;
13940
+ justify-content: space-between;
13941
+ gap: 12px;
13942
+ }
13943
+
13944
+ .notification-repo {
13945
+ font-weight: 600;
13946
+ color: var(--accent);
13947
+ }
13948
+
13949
+ .notification-title {
13950
+ font-weight: 600;
13951
+ font-size: 13px;
13952
+ }
13953
+
13954
+ .notification-excerpt {
13955
+ font-size: 12px;
13956
+ color: var(--muted);
13957
+ }
13958
+
13959
+ .notification-actions {
13960
+ display: flex;
13961
+ gap: 6px;
13962
+ flex-wrap: wrap;
13963
+ }
13964
+
13965
+ .notification-actions .notification-action {
13966
+ border: 1px solid var(--border);
13967
+ border-radius: var(--radius);
13968
+ padding: 4px 8px;
13969
+ font-size: 10px;
13970
+ text-transform: uppercase;
13971
+ letter-spacing: 0.3px;
13972
+ color: var(--muted);
13973
+ background: transparent;
13974
+ cursor: pointer;
13975
+ text-decoration: none;
13976
+ }
13977
+
13978
+ .notification-actions .notification-action:hover {
13979
+ color: var(--text);
13980
+ border-color: rgba(108, 245, 216, 0.4);
13981
+ }
13982
+
13983
+ .pma-clear-btn {
13984
+ margin-left: 2px;
13985
+ }
13986
+
13586
13987
  .pma-inbox-item {
13587
13988
  display: inline-flex;
13588
13989
  flex-direction: row;
@@ -13790,6 +14191,16 @@ button.filebox-delete:hover {
13790
14191
  align-items: center;
13791
14192
  gap: 8px;
13792
14193
  padding: 8px 0;
14194
+ flex-wrap: wrap;
14195
+ }
14196
+
14197
+ .pma-docs-history {
14198
+ font-size: 11px;
14199
+ padding: 6px 10px;
14200
+ border-radius: 6px;
14201
+ border: 1px solid var(--border);
14202
+ background: var(--panel);
14203
+ color: var(--text);
13793
14204
  }
13794
14205
 
13795
14206
  .pma-docs-actions button:disabled {