github-issue-tower-defence-management 1.116.8 → 1.117.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 (60) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/README.md +1 -1
  3. package/bin/adapter/entry-points/console/consoleReadApi.js +13 -1
  4. package/bin/adapter/entry-points/console/consoleReadApi.js.map +1 -1
  5. package/bin/adapter/entry-points/console/ui-dist/assets/index-CJJsRF8i.js +101 -0
  6. package/bin/adapter/entry-points/console/ui-dist/assets/{index-D1V2fi29.css → index-DGVKvwux.css} +1 -1
  7. package/bin/adapter/entry-points/console/ui-dist/index.html +2 -2
  8. package/bin/adapter/repositories/issue/ApiV3CheerioRestIssueRepository.js +1 -0
  9. package/bin/adapter/repositories/issue/ApiV3CheerioRestIssueRepository.js.map +1 -1
  10. package/bin/domain/usecases/NotifySilentLiveSessionsUseCase.js +10 -2
  11. package/bin/domain/usecases/NotifySilentLiveSessionsUseCase.js.map +1 -1
  12. package/package.json +1 -1
  13. package/src/adapter/entry-points/console/consoleReadApi.test.ts +4 -0
  14. package/src/adapter/entry-points/console/consoleReadApi.ts +18 -0
  15. package/src/adapter/entry-points/console/ui/e2e/consoleTestHarness.ts +2 -0
  16. package/src/adapter/entry-points/console/ui/src/features/console/components/detail/ConsoleItemDetail.stories.tsx +2 -0
  17. package/src/adapter/entry-points/console/ui/src/features/console/components/detail/ConsoleItemDetail.test.tsx +3 -1
  18. package/src/adapter/entry-points/console/ui/src/features/console/components/detail/ConsoleItemDetail.tsx +1 -1
  19. package/src/adapter/entry-points/console/ui/src/features/console/components/detail/ConsolePullRequestDetail.test.tsx +1 -0
  20. package/src/adapter/entry-points/console/ui/src/features/console/components/detail/ConsolePullRequestDetail.tsx +1 -1
  21. package/src/adapter/entry-points/console/ui/src/features/console/components/detail/ConsolePullRequestStatusBadges.stories.tsx +15 -5
  22. package/src/adapter/entry-points/console/ui/src/features/console/components/detail/ConsolePullRequestStatusBadges.test.tsx +38 -8
  23. package/src/adapter/entry-points/console/ui/src/features/console/components/detail/ConsolePullRequestStatusBadges.tsx +35 -12
  24. package/src/adapter/entry-points/console/ui/src/features/console/hooks/useConsoleDetailPrefetch.test.ts +117 -0
  25. package/src/adapter/entry-points/console/ui/src/features/console/hooks/useConsoleDetailPrefetch.ts +83 -0
  26. package/src/adapter/entry-points/console/ui/src/features/console/hooks/useConsoleItemDetailData.test.ts +2 -0
  27. package/src/adapter/entry-points/console/ui/src/features/console/hooks/useConsoleItemDetailData.ts +1 -0
  28. package/src/adapter/entry-points/console/ui/src/features/console/hooks/useConsoleOperations.test.ts +67 -0
  29. package/src/adapter/entry-points/console/ui/src/features/console/hooks/useConsoleOperations.ts +26 -6
  30. package/src/adapter/entry-points/console/ui/src/features/console/lib/consoleApi.test.ts +21 -0
  31. package/src/adapter/entry-points/console/ui/src/features/console/lib/consoleApi.ts +14 -0
  32. package/src/adapter/entry-points/console/ui/src/features/console/lib/resourceCache.test.ts +48 -0
  33. package/src/adapter/entry-points/console/ui/src/features/console/lib/resourceCache.ts +24 -0
  34. package/src/adapter/entry-points/console/ui/src/features/console/logic/types.ts +4 -0
  35. package/src/adapter/entry-points/console/ui/src/features/console/pages/ConsoleItemDetailContainer.test.tsx +1 -0
  36. package/src/adapter/entry-points/console/ui/src/features/console/pages/ConsolePage.tsx +9 -1
  37. package/src/adapter/entry-points/console/ui/src/features/console/testing/fixtures.ts +1 -0
  38. package/src/adapter/entry-points/console/ui/src/index.css +10 -1
  39. package/src/adapter/entry-points/console/ui-dist/assets/index-CJJsRF8i.js +101 -0
  40. package/src/adapter/entry-points/console/ui-dist/assets/{index-D1V2fi29.css → index-DGVKvwux.css} +1 -1
  41. package/src/adapter/entry-points/console/ui-dist/index.html +2 -2
  42. package/src/adapter/entry-points/console/webServer.test.ts +2 -0
  43. package/src/adapter/entry-points/handlers/notifySilentTmuxSessions.test.ts +30 -2
  44. package/src/adapter/repositories/issue/ApiV3CheerioRestIssueRepository.ts +1 -0
  45. package/src/domain/usecases/CheckIssueReviewReadinessUseCase.test.ts +1 -0
  46. package/src/domain/usecases/IssueRejectionEvaluator.test.ts +1 -0
  47. package/src/domain/usecases/NotifySilentLiveSessionsUseCase.test.ts +194 -33
  48. package/src/domain/usecases/NotifySilentLiveSessionsUseCase.ts +19 -1
  49. package/src/domain/usecases/RevertOrphanedPreparationUseCase.test.ts +1 -0
  50. package/src/domain/usecases/StartPreparationUseCase.test.ts +9 -0
  51. package/src/domain/usecases/adapter-interfaces/IssueRepository.ts +1 -0
  52. package/types/adapter/entry-points/console/consoleReadApi.d.ts +4 -0
  53. package/types/adapter/entry-points/console/consoleReadApi.d.ts.map +1 -1
  54. package/types/adapter/repositories/issue/ApiV3CheerioRestIssueRepository.d.ts.map +1 -1
  55. package/types/domain/usecases/NotifySilentLiveSessionsUseCase.d.ts +1 -0
  56. package/types/domain/usecases/NotifySilentLiveSessionsUseCase.d.ts.map +1 -1
  57. package/types/domain/usecases/adapter-interfaces/IssueRepository.d.ts +1 -0
  58. package/types/domain/usecases/adapter-interfaces/IssueRepository.d.ts.map +1 -1
  59. package/bin/adapter/entry-points/console/ui-dist/assets/index-Bm0wt3Mn.js +0 -101
  60. package/src/adapter/entry-points/console/ui-dist/assets/index-Bm0wt3Mn.js +0 -101
@@ -1 +1 @@
1
- /*! tailwindcss v4.3.0 | MIT License | https://tailwindcss.com */@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-border-style:solid;--tw-font-weight:initial;--tw-outline-style:solid;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000}}}@layer theme{:root,:host{--font-sans:ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--font-mono:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--spacing:.25rem;--text-xs:.75rem;--text-xs--line-height:calc(1 / .75);--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--font-weight-medium:500;--font-weight-semibold:600;--radius-md:.375rem;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono);--color-input:#e5e5e5;--color-ring:#0a0a0a;--color-background:#fff;--color-foreground:#0a0a0a;--color-primary:#171717;--color-primary-foreground:#fafafa;--color-secondary:#f5f5f5;--color-secondary-foreground:#171717;--color-accent:#f5f5f5;--color-accent-foreground:#171717}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;-moz-tab-size:4;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab,red,red)){::placeholder{color:color-mix(in oklab,currentcolor 50%,transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){-webkit-appearance:button;-moz-appearance:button;appearance:button}::file-selector-button{-webkit-appearance:button;-moz-appearance:button;appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.visible{visibility:visible}.relative{position:relative}.static{position:static}.container{width:100%}@media(min-width:40rem){.container{max-width:40rem}}@media(min-width:48rem){.container{max-width:48rem}}@media(min-width:64rem){.container{max-width:64rem}}@media(min-width:80rem){.container{max-width:80rem}}@media(min-width:96rem){.container{max-width:96rem}}.block{display:block}.hidden{display:none}.inline{display:inline}.inline-flex{display:inline-flex}.h-8{height:calc(var(--spacing) * 8)}.h-9{height:calc(var(--spacing) * 9)}.h-10{height:calc(var(--spacing) * 10)}.items-center{align-items:center}.justify-center{justify-content:center}.gap-2{gap:calc(var(--spacing) * 2)}.rounded-md{border-radius:var(--radius-md)}.border{border-style:var(--tw-border-style);border-width:1px}.border-input{border-color:var(--color-input)}.border-transparent{border-color:#0000}.bg-background{background-color:var(--color-background)}.bg-primary{background-color:var(--color-primary)}.bg-secondary{background-color:var(--color-secondary)}.px-2\.5{padding-inline:calc(var(--spacing) * 2.5)}.px-3{padding-inline:calc(var(--spacing) * 3)}.px-4{padding-inline:calc(var(--spacing) * 4)}.px-8{padding-inline:calc(var(--spacing) * 8)}.py-0\.5{padding-block:calc(var(--spacing) * .5)}.py-2{padding-block:calc(var(--spacing) * 2)}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.whitespace-nowrap{white-space:nowrap}.text-foreground{color:var(--color-foreground)}.text-primary-foreground{color:var(--color-primary-foreground)}.text-secondary-foreground{color:var(--color-secondary-foreground)}.lowercase{text-transform:lowercase}.outline{outline-style:var(--tw-outline-style);outline-width:1px}.transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}@media(hover:hover){.hover\:bg-accent:hover{background-color:var(--color-accent)}.hover\:bg-primary\/90:hover{background-color:#171717e6}@supports (color:color-mix(in lab,red,red)){.hover\:bg-primary\/90:hover{background-color:color-mix(in oklab,var(--color-primary) 90%,transparent)}}.hover\:bg-secondary\/80:hover{background-color:#f5f5f5cc}@supports (color:color-mix(in lab,red,red)){.hover\:bg-secondary\/80:hover{background-color:color-mix(in oklab,var(--color-secondary) 80%,transparent)}}.hover\:text-accent-foreground:hover{color:var(--color-accent-foreground)}}.focus-visible\:ring-2:focus-visible{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.focus-visible\:ring-ring:focus-visible{--tw-ring-color:var(--color-ring)}.focus-visible\:outline-none:focus-visible{--tw-outline-style:none;outline-style:none}.disabled\:pointer-events-none:disabled{pointer-events:none}.disabled\:opacity-50:disabled{opacity:.5}}html{font-size:clamp(15px,2.1vw,26px)}body{color:#e6edf3;background-color:#0d1117;margin:0;font-family:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica,Arial,sans-serif}.console-app{flex-direction:column;width:100%;min-height:100dvh;display:flex}.console-tabbar{-webkit-overflow-scrolling:touch;background:#161b22;border-bottom:2px solid #30363d;flex-wrap:nowrap;align-items:stretch;gap:0;min-height:42px;padding:0 8px;display:flex;overflow-x:auto}.console-tab{color:#8b949e;white-space:nowrap;cursor:pointer;background:0 0;border:none;border-bottom:2px solid #0000;align-items:center;gap:6px;margin-bottom:-2px;padding:10px 14px;font-size:.8125rem;font-weight:500;line-height:1.2;text-decoration:none;display:inline-flex}.console-tab:hover{color:#e6edf3}.console-tab[data-active=true]{color:#e6edf3;border-bottom-color:#2f81f7;font-weight:700}.console-tab-badge{text-align:center;color:#e6edf3;background:#484f58;border-radius:20px;min-width:20px;padding:1px 7px;font-size:.6875rem;font-weight:700;line-height:1.5}.console-tab-badge[data-zero=true]{color:#8b949e;background:#30363d}.console-tab-pjname{color:#8b949e;align-self:center;margin-left:auto;padding:0 8px;font-size:.7188rem}.console-tab-geninfo{color:#8b949e;align-self:center;padding:0 4px;font-size:.6875rem}.console-list{margin:0;padding:12px 18px 18px;list-style:none}.console-list-group{list-style:none}.console-item-row .console-item-icon{flex:none;margin-top:3px}.console-group-header{background:#0b0f14;border-bottom:1px solid #21262d;justify-content:space-between;align-items:center;padding:6px 12px;display:flex}.console-storytag{align-items:center;gap:8px;font-size:.8125rem;font-weight:700;display:inline-flex}.console-story-dot{border-radius:999px;width:10px;height:10px;display:inline-block}.console-group-count{color:#8b949e;font-size:.75rem}.console-item-row{color:#e6edf3;text-align:left;cursor:pointer;background:#161b22;border:1px solid #30363d;border-radius:8px;align-items:flex-start;gap:14px;width:100%;margin-bottom:10px;padding:12px 16px;display:flex}.console-item-row:hover{background:#1a2029;border-color:#484f58}.console-item-row[data-active=true]{background:#1a2029;border-color:#4493f8}.console-item-meta{flex:1;min-width:0}.console-item-title{font-size:.9063rem;font-weight:600;display:block}.console-item-sub{color:#8b949e;margin-top:3px;font-size:.7813rem;display:block}.console-item-pill{color:#8b949e;border:1px solid #30363d;border-radius:20px;margin-right:6px;padding:1px 8px;font-size:.6875rem;display:inline-block}.console-item-createdat{color:#8b949e;cursor:help}.console-item-fields{color:#adbac7;flex-wrap:wrap;gap:4px 10px;margin-top:4px;font-size:.7188rem;display:flex}.console-item-field{word-break:break-all;align-items:baseline;gap:4px;min-width:0;display:inline-flex}.console-item-field-label{color:#6e7681;text-transform:uppercase;letter-spacing:.03em;font-size:.625rem}.console-list-message{color:#8b949e;padding:16px;font-size:.875rem}.console-list-empty{text-align:center;color:#8b949e;padding:40px;font-size:.875rem}.console-list-error,.console-comment-error,.console-files-error,.console-commits-error,.console-detail-body-error{color:#f85149}.console-detail{flex-direction:column;flex:1 0 auto;gap:12px;padding:16px 16px 0;display:flex}.console-detail-title{align-items:center;gap:8px;margin:0;font-size:1.25rem;display:flex}.console-detail-title-text{flex:1}.console-detail-number{color:#8b949e;font-weight:400}.console-detail-closed-label{color:#a371f7;font-size:.8125rem}.console-detail-subbar{align-items:center;gap:12px;font-size:.8125rem;display:flex}.console-detail-link{color:#4493f8}.console-detail-repo{color:#8b949e;font-family:ui-monospace,SFMono-Regular,Menlo,monospace}.console-copy-url-button{color:#c9d1d9;border:1px solid #30363d;border-radius:6px;height:24px;padding:0 8px;font-size:.75rem}.console-copy-url-button:hover{color:#e6edf3;background-color:#21262d}.console-detail-pill,.console-label-chip,.console-detail-status-chip{border:1px solid #30363d;border-radius:999px;padding:2px 8px;font-size:.75rem;display:inline-block}.console-detail-pr-status-row{flex-wrap:wrap;align-items:center;gap:6px;margin-top:-4px;display:flex}.console-detail-pr-status{flex-wrap:wrap;align-items:center;gap:6px;display:inline-flex}.console-detail-ci-missing{opacity:.85;font-weight:400}.console-detail-labels{flex-wrap:wrap;gap:6px;display:flex}.console-detail-createdat{color:#8b949e;font-size:.75rem}.console-panel{border:1px solid #30363d;border-radius:8px;overflow:hidden}.console-panel-header{background:#161b22;justify-content:space-between;align-items:center;display:flex}.console-panel-toggle{color:#e6edf3;text-align:left;cursor:pointer;background:0 0;border:none;flex:1;align-items:center;gap:8px;padding:6px 12px;font-size:.875rem;font-weight:600;display:flex}.console-panel-toggle:hover{background:#1a2029}.console-panel-action{padding:6px 12px}.console-panel-body{padding:12px}.console-markdown{word-break:break-word;font-size:.875rem;line-height:1.5}.console-markdown ul{margin:.5em 0;padding-left:1.5em;list-style:outside}.console-markdown ol{margin:.5em 0;padding-left:1.5em;list-style:decimal}.console-markdown li{margin:.25em 0}.console-markdown table{border-collapse:collapse;margin:.5em 0}.console-markdown th,.console-markdown td{border:1px solid #30363d;padding:4px 8px}.console-markdown th{background:#161b22}.console-markdown h1,.console-markdown h2,.console-markdown h3,.console-markdown h4,.console-markdown h5,.console-markdown h6{margin:1em 0 .5em;font-weight:700;line-height:1.25}.console-markdown h1{font-size:1.6em}.console-markdown h2{font-size:1.4em}.console-markdown h3{font-size:1.2em}.console-markdown h4{font-size:1.05em}.console-markdown h5{font-size:.95em}.console-markdown h6{color:#8b949e;font-size:.9em}.console-markdown pre{background:#161b22;border:1px solid #30363d;border-radius:6px;margin:.5em 0;padding:12px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:.8125rem;line-height:1.45;overflow-x:auto}.console-markdown code{background:#6e768166;border-radius:4px;padding:.15em .4em;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:.9em}.console-markdown pre code{font-size:inherit;background:0 0;border-radius:0;padding:0}.console-markdown blockquote{color:#8b949e;border-left:3px solid #30363d;margin:.5em 0;padding:0 1em}.console-markdown a{color:#4493f8;text-decoration:none}.console-markdown a:hover{text-decoration:underline}.console-markdown-reference-host{display:inline}.console-markdown-reference{vertical-align:baseline;align-items:center;gap:.25em;display:inline-flex}.console-markdown-reference .console-item-icon{flex-shrink:0}.console-markdown-reference-title{text-decoration:none}.console-markdown-reference:hover .console-markdown-reference-title{text-decoration:underline}.console-markdown hr{border:none;border-top:1px solid #30363d;margin:1em 0}.console-mermaid-error{color:#f85149;font-size:.8125rem}.console-comment{border-top:1px solid #21262d;padding-top:8px}.console-comment-header{color:#8b949e;gap:8px;font-size:.75rem;display:flex}.console-comment-author{color:#e6edf3;font-weight:600}.console-files,.console-commits{margin:0;padding:0;list-style:none}.console-commit{align-items:center;gap:8px;padding:4px 0;font-size:.8125rem;display:flex}.console-file{flex-direction:column;font-size:.8125rem;display:flex}.console-file-badge{text-align:center;border:1px solid;border-radius:4px;width:18px;font-size:.6875rem}.console-file-path,.console-commit-message{flex:1;font-family:ui-monospace,SFMono-Regular,Menlo,monospace}.console-file-add,.console-pr-add{color:#3fb950}.console-file-del,.console-pr-del{color:#f85149}.console-commit-sha{color:#8b949e;font-family:ui-monospace,SFMono-Regular,Menlo,monospace}.console-actionbar{z-index:100;padding:10px 16px;padding-bottom:calc(10px + env(safe-area-inset-bottom));background:#161b22;border-top:2px solid #30363d;margin-top:auto;position:sticky;bottom:0}.console-operation-bar{flex-direction:column;gap:8px;width:100%;display:flex}.console-op-group{flex-wrap:wrap;justify-content:flex-end;align-items:center;gap:8px;display:flex}.console-op-group-review{gap:10px}.console-op-group-stories{max-height:33vh;overflow-y:auto}.console-op-button{color:#e6edf3;white-space:nowrap;cursor:pointer;background:#21262d;border:1px solid #30363d;border-radius:6px;padding:7px 16px;font-size:.8125rem;font-weight:600}.console-op-button:hover{border-color:#484f58}.console-op-button-approve{color:#fff;background:#238636;border-color:#2ea043}.console-op-button-reject{color:#ffd166;background:#7d5000;border-color:#a06800}.console-op-button-wrong{color:#f85149;background:#3a1518;border-color:#f85149}.console-op-button-unneeded{color:#aab0b8;background:#2a2d31;border-color:#6e7681}.console-op-button-snooze{color:#79c0ff;background:#1c2b4a;border-color:#4493f8}.console-pr-section{border:1px solid #30363d;border-radius:8px;flex-direction:column;gap:10px;padding:12px;display:flex}.console-pr-statbar{color:#8b949e;gap:12px;font-size:.75rem;display:flex}.console-detail-screen{flex-direction:column;flex:1 0 auto;display:flex}.console-panel-open-link{color:#4493f8;font-size:.8125rem;font-weight:400}.console-composer{margin-top:4px}.console-composer-toggle{color:#8b949e;cursor:pointer;background:0 0;border:none;padding:2px 0;font-size:.7813rem}.console-composer-toggle:hover{color:#e6edf3}.console-composer-posted{flex-direction:column;gap:8px;margin-top:8px;display:flex}.console-composer-form{margin-top:8px}.console-composer-input{box-sizing:border-box;color:#e6edf3;width:100%;font:inherit;resize:vertical;background:#21262d;border:1px solid #30363d;border-radius:6px;padding:8px;font-size:.875rem}.console-composer-row{align-items:center;gap:8px;margin-top:6px;display:flex}.console-composer-submit{color:#fff;cursor:pointer;background:#238636;border:1px solid #2ea043;border-radius:6px;padding:7px 16px;font-size:.8125rem;font-weight:600}.console-composer-submit:disabled{opacity:.6;cursor:default}.console-composer-status{color:#8b949e;font-size:.75rem}.console-composer-error{color:#f85149}.console-undo-toast{z-index:9998;white-space:nowrap;border-radius:10px;align-items:center;gap:12px;max-width:92vw;padding:12px 18px;font-size:.8438rem;display:flex;position:fixed;top:12px;left:50%;transform:translate(-50%);box-shadow:0 4px 20px #0009}.console-undo-toast-green{color:#3fb950;background:#0d3320;border:1px solid #2ea043}.console-undo-toast-amber{color:#ffd166;background:#3a2800;border:1px solid #a06800}.console-undo-toast-red{color:#f85149;background:#3a1518;border:1px solid #da3633}.console-undo-toast-gray{color:#aab0b8;background:#2a2d31;border:1px solid #6e7681}.console-undo-toast-blue{color:#79c0ff;background:#0d1f40;border:1px solid #4493f8}.console-undo-toast-error{color:#f85149;background:#3a1518;border:1px solid #f85149}.console-undo-toast-message{text-overflow:ellipsis;flex:1;min-width:0;overflow:hidden}.console-undo-toast-undo{cursor:pointer;color:inherit;background:#ffffff1f;border:none;border-radius:6px;flex:none;padding:4px 12px;font-size:.8125rem;font-weight:700}.console-undo-toast-undo:hover{background:#ffffff38}.console-undo-toast-countdown{opacity:.7;flex:none;font-size:.6875rem}.console-undo-toast-bar{opacity:.5;background:currentColor;border-radius:0 0 10px 10px;height:3px;transition:width .1s linear;position:absolute;bottom:0;left:0}.console-file-row{width:100%;color:inherit;font:inherit;text-align:left;cursor:pointer;background:0 0;border:none;align-items:center;gap:8px;padding:4px 0;font-size:.8125rem;display:flex}.console-file-row:hover{background:#1a2029}.console-file-caret{color:#8b949e;flex:none;width:1em}.console-file-diff{border-collapse:collapse;width:100%;margin:4px 0 8px;font:.8125rem/1.6 ui-monospace,SFMono-Regular,Menlo,monospace}.console-file-diff td{white-space:pre-wrap;word-break:break-word;vertical-align:top;padding:0 10px}.console-diff-ln{text-align:right;color:#6e7681;-webkit-user-select:none;user-select:none;white-space:nowrap;border-right:1px solid #30363d;width:1%;padding:0 8px}.console-file-diff td.console-diff-ln{white-space:nowrap;word-break:normal;overflow-wrap:normal}.console-diff-add td{background:#2ea04326}.console-diff-add .console-diff-code{color:#aff5b4}.console-diff-del td{background:#f8514926}.console-diff-del .console-diff-code{color:#ffdcd7}.console-diff-hunk td{color:#79c0ff;background:#161b22}.console-diff-ctx .console-diff-code{color:#c9d1d9}.console-file-diff-empty{color:#8b949e;padding:8px 14px;font-size:.75rem}.console-diff-comment-cell{text-align:center;-webkit-user-select:none;user-select:none;width:1%;padding:0 2px}.console-diff-comment-button{color:#6e7681;cursor:pointer;opacity:.6;background:0 0;border:1px solid #30363d;border-radius:4px;width:18px;height:18px;padding:0;font-size:.875rem;line-height:16px}.console-diff-row:hover .console-diff-comment-button,.console-diff-comment-button:focus-visible,.console-diff-comment-button[aria-expanded=true]{opacity:1;color:#fff;background:#1f6feb;border-color:#2f81f7}.console-diff-composer-row td{background:#0d1117;padding:6px 10px}.console-diff-composer{background:#161b22;border:1px solid #30363d;border-radius:6px;flex-direction:column;gap:6px;padding:8px;display:flex}.console-diff-composer-anchor{color:#8b949e;font-size:.6875rem}.console-diff-composer-input{resize:vertical;color:#c9d1d9;width:100%;font:inherit;background:#0d1117;border:1px solid #30363d;border-radius:6px;padding:6px 8px}.console-diff-composer-controls{align-items:center;gap:8px;display:flex}.console-diff-composer-submit{color:#fff;cursor:pointer;background:#238636;border:1px solid #238636;border-radius:6px;padding:4px 12px}.console-diff-composer-submit:disabled{opacity:.6;cursor:default}.console-diff-composer-cancel{color:#c9d1d9;cursor:pointer;background:0 0;border:1px solid #30363d;border-radius:6px;padding:4px 12px}.console-diff-composer-status{color:#8b949e;font-size:.75rem}.console-diff-composer-error{color:#ff7b72}.console-diff-composer-posted{color:#3fb950;margin:0;font-size:.75rem}.console-pr-header{flex-wrap:wrap;align-items:center;gap:10px;padding-top:4px;display:flex}.console-pr-section-title{color:#e6edf3;font-size:.9375rem;font-weight:600}.console-pr-section-state{color:#8b949e;border:1px solid #6e7681;border-radius:999px;padding:1px 8px;font-size:.6875rem}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-outline-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}
1
+ /*! tailwindcss v4.3.0 | MIT License | https://tailwindcss.com */@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-border-style:solid;--tw-font-weight:initial;--tw-outline-style:solid;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000}}}@layer theme{:root,:host{--font-sans:ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--font-mono:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--spacing:.25rem;--text-xs:.75rem;--text-xs--line-height:calc(1 / .75);--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--font-weight-medium:500;--font-weight-semibold:600;--radius-md:.375rem;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono);--color-input:#e5e5e5;--color-ring:#0a0a0a;--color-background:#fff;--color-foreground:#0a0a0a;--color-primary:#171717;--color-primary-foreground:#fafafa;--color-secondary:#f5f5f5;--color-secondary-foreground:#171717;--color-accent:#f5f5f5;--color-accent-foreground:#171717}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;-moz-tab-size:4;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab,red,red)){::placeholder{color:color-mix(in oklab,currentcolor 50%,transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){-webkit-appearance:button;-moz-appearance:button;appearance:button}::file-selector-button{-webkit-appearance:button;-moz-appearance:button;appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.visible{visibility:visible}.relative{position:relative}.static{position:static}.container{width:100%}@media(min-width:40rem){.container{max-width:40rem}}@media(min-width:48rem){.container{max-width:48rem}}@media(min-width:64rem){.container{max-width:64rem}}@media(min-width:80rem){.container{max-width:80rem}}@media(min-width:96rem){.container{max-width:96rem}}.block{display:block}.hidden{display:none}.inline{display:inline}.inline-flex{display:inline-flex}.h-8{height:calc(var(--spacing) * 8)}.h-9{height:calc(var(--spacing) * 9)}.h-10{height:calc(var(--spacing) * 10)}.items-center{align-items:center}.justify-center{justify-content:center}.gap-2{gap:calc(var(--spacing) * 2)}.rounded-md{border-radius:var(--radius-md)}.border{border-style:var(--tw-border-style);border-width:1px}.border-input{border-color:var(--color-input)}.border-transparent{border-color:#0000}.bg-background{background-color:var(--color-background)}.bg-primary{background-color:var(--color-primary)}.bg-secondary{background-color:var(--color-secondary)}.px-2\.5{padding-inline:calc(var(--spacing) * 2.5)}.px-3{padding-inline:calc(var(--spacing) * 3)}.px-4{padding-inline:calc(var(--spacing) * 4)}.px-8{padding-inline:calc(var(--spacing) * 8)}.py-0\.5{padding-block:calc(var(--spacing) * .5)}.py-2{padding-block:calc(var(--spacing) * 2)}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.whitespace-nowrap{white-space:nowrap}.text-foreground{color:var(--color-foreground)}.text-primary-foreground{color:var(--color-primary-foreground)}.text-secondary-foreground{color:var(--color-secondary-foreground)}.lowercase{text-transform:lowercase}.outline{outline-style:var(--tw-outline-style);outline-width:1px}.transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}@media(hover:hover){.hover\:bg-accent:hover{background-color:var(--color-accent)}.hover\:bg-primary\/90:hover{background-color:#171717e6}@supports (color:color-mix(in lab,red,red)){.hover\:bg-primary\/90:hover{background-color:color-mix(in oklab,var(--color-primary) 90%,transparent)}}.hover\:bg-secondary\/80:hover{background-color:#f5f5f5cc}@supports (color:color-mix(in lab,red,red)){.hover\:bg-secondary\/80:hover{background-color:color-mix(in oklab,var(--color-secondary) 80%,transparent)}}.hover\:text-accent-foreground:hover{color:var(--color-accent-foreground)}}.focus-visible\:ring-2:focus-visible{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.focus-visible\:ring-ring:focus-visible{--tw-ring-color:var(--color-ring)}.focus-visible\:outline-none:focus-visible{--tw-outline-style:none;outline-style:none}.disabled\:pointer-events-none:disabled{pointer-events:none}.disabled\:opacity-50:disabled{opacity:.5}}html{font-size:clamp(15px,2.1vw,26px)}body{color:#e6edf3;background-color:#0d1117;margin:0;font-family:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica,Arial,sans-serif}.console-app{flex-direction:column;width:100%;min-height:100dvh;display:flex}.console-tabbar{-webkit-overflow-scrolling:touch;background:#161b22;border-bottom:2px solid #30363d;flex-wrap:nowrap;align-items:stretch;gap:0;min-height:42px;padding:0 8px;display:flex;overflow-x:auto}.console-tab{color:#8b949e;white-space:nowrap;cursor:pointer;background:0 0;border:none;border-bottom:2px solid #0000;align-items:center;gap:6px;margin-bottom:-2px;padding:10px 14px;font-size:.8125rem;font-weight:500;line-height:1.2;text-decoration:none;display:inline-flex}.console-tab:hover{color:#e6edf3}.console-tab[data-active=true]{color:#e6edf3;border-bottom-color:#2f81f7;font-weight:700}.console-tab-badge{text-align:center;color:#e6edf3;background:#484f58;border-radius:20px;min-width:20px;padding:1px 7px;font-size:.6875rem;font-weight:700;line-height:1.5}.console-tab-badge[data-zero=true]{color:#8b949e;background:#30363d}.console-tab-pjname{color:#8b949e;align-self:center;margin-left:auto;padding:0 8px;font-size:.7188rem}.console-tab-geninfo{color:#8b949e;align-self:center;padding:0 4px;font-size:.6875rem}.console-list{margin:0;padding:12px 18px 18px;list-style:none}.console-list-group{list-style:none}.console-item-row .console-item-icon{flex:none;margin-top:3px}.console-group-header{background:#0b0f14;border-bottom:1px solid #21262d;justify-content:space-between;align-items:center;padding:6px 12px;display:flex}.console-storytag{align-items:center;gap:8px;font-size:.8125rem;font-weight:700;display:inline-flex}.console-story-dot{border-radius:999px;width:10px;height:10px;display:inline-block}.console-group-count{color:#8b949e;font-size:.75rem}.console-item-row{color:#e6edf3;text-align:left;cursor:pointer;background:#161b22;border:1px solid #30363d;border-radius:8px;align-items:flex-start;gap:14px;width:100%;margin-bottom:10px;padding:12px 16px;display:flex}.console-item-row:hover{background:#1a2029;border-color:#484f58}.console-item-row[data-active=true]{background:#1a2029;border-color:#4493f8}.console-item-meta{flex:1;min-width:0}.console-item-title{font-size:.9063rem;font-weight:600;display:block}.console-item-sub{color:#8b949e;margin-top:3px;font-size:.7813rem;display:block}.console-item-pill{color:#8b949e;border:1px solid #30363d;border-radius:20px;margin-right:6px;padding:1px 8px;font-size:.6875rem;display:inline-block}.console-item-createdat{color:#8b949e;cursor:help}.console-item-fields{color:#adbac7;flex-wrap:wrap;gap:4px 10px;margin-top:4px;font-size:.7188rem;display:flex}.console-item-field{word-break:break-all;align-items:baseline;gap:4px;min-width:0;display:inline-flex}.console-item-field-label{color:#6e7681;text-transform:uppercase;letter-spacing:.03em;font-size:.625rem}.console-list-message{color:#8b949e;padding:16px;font-size:.875rem}.console-list-empty{text-align:center;color:#8b949e;padding:40px;font-size:.875rem}.console-list-error,.console-comment-error,.console-files-error,.console-commits-error,.console-detail-body-error{color:#f85149}.console-detail{flex-direction:column;flex:1 0 auto;gap:12px;padding:16px 16px 0;display:flex}.console-detail-title{align-items:center;gap:8px;margin:0;font-size:1.25rem;display:flex}.console-detail-title-text{flex:1}.console-detail-number{color:#8b949e;font-weight:400}.console-detail-closed-label{color:#a371f7;font-size:.8125rem}.console-detail-subbar{align-items:center;gap:12px;font-size:.8125rem;display:flex}.console-detail-link{color:#4493f8}.console-detail-repo{color:#8b949e;font-family:ui-monospace,SFMono-Regular,Menlo,monospace}.console-copy-url-button{color:#c9d1d9;border:1px solid #30363d;border-radius:6px;height:24px;padding:0 8px;font-size:.75rem}.console-copy-url-button:hover{color:#e6edf3;background-color:#21262d}.console-detail-pill,.console-label-chip,.console-detail-status-chip{border:1px solid #30363d;border-radius:999px;padding:2px 8px;font-size:.75rem;display:inline-block}.console-detail-pr-status-row{flex-wrap:wrap;align-items:center;gap:6px;margin-top:-4px;display:flex}.console-detail-pr-status{flex-wrap:wrap;align-items:center;gap:6px;display:inline-flex}.console-detail-ci-missing{opacity:.85;font-weight:400}.console-detail-mergeable-chip{font-weight:600}.console-detail-mergeable-chip-unknown{opacity:.7;font-weight:400}.console-detail-labels{flex-wrap:wrap;gap:6px;display:flex}.console-detail-createdat{color:#8b949e;font-size:.75rem}.console-panel{border:1px solid #30363d;border-radius:8px;overflow:hidden}.console-panel-header{background:#161b22;justify-content:space-between;align-items:center;display:flex}.console-panel-toggle{color:#e6edf3;text-align:left;cursor:pointer;background:0 0;border:none;flex:1;align-items:center;gap:8px;padding:6px 12px;font-size:.875rem;font-weight:600;display:flex}.console-panel-toggle:hover{background:#1a2029}.console-panel-action{padding:6px 12px}.console-panel-body{padding:12px}.console-markdown{word-break:break-word;font-size:.875rem;line-height:1.5}.console-markdown ul{margin:.5em 0;padding-left:1.5em;list-style:outside}.console-markdown ol{margin:.5em 0;padding-left:1.5em;list-style:decimal}.console-markdown li{margin:.25em 0}.console-markdown table{border-collapse:collapse;margin:.5em 0}.console-markdown th,.console-markdown td{border:1px solid #30363d;padding:4px 8px}.console-markdown th{background:#161b22}.console-markdown h1,.console-markdown h2,.console-markdown h3,.console-markdown h4,.console-markdown h5,.console-markdown h6{margin:1em 0 .5em;font-weight:700;line-height:1.25}.console-markdown h1{font-size:1.6em}.console-markdown h2{font-size:1.4em}.console-markdown h3{font-size:1.2em}.console-markdown h4{font-size:1.05em}.console-markdown h5{font-size:.95em}.console-markdown h6{color:#8b949e;font-size:.9em}.console-markdown pre{background:#161b22;border:1px solid #30363d;border-radius:6px;margin:.5em 0;padding:12px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:.8125rem;line-height:1.45;overflow-x:auto}.console-markdown code{background:#6e768166;border-radius:4px;padding:.15em .4em;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:.9em}.console-markdown pre code{font-size:inherit;background:0 0;border-radius:0;padding:0}.console-markdown blockquote{color:#8b949e;border-left:3px solid #30363d;margin:.5em 0;padding:0 1em}.console-markdown a{color:#4493f8;text-decoration:none}.console-markdown a:hover{text-decoration:underline}.console-markdown-reference-host{display:inline}.console-markdown-reference{vertical-align:baseline;align-items:center;gap:.25em;display:inline-flex}.console-markdown-reference .console-item-icon{flex-shrink:0}.console-markdown-reference-title{text-decoration:none}.console-markdown-reference:hover .console-markdown-reference-title{text-decoration:underline}.console-markdown hr{border:none;border-top:1px solid #30363d;margin:1em 0}.console-mermaid-error{color:#f85149;font-size:.8125rem}.console-comment{border-top:1px solid #21262d;padding-top:8px}.console-comment-header{color:#8b949e;gap:8px;font-size:.75rem;display:flex}.console-comment-author{color:#e6edf3;font-weight:600}.console-files,.console-commits{margin:0;padding:0;list-style:none}.console-commit{align-items:center;gap:8px;padding:4px 0;font-size:.8125rem;display:flex}.console-file{flex-direction:column;font-size:.8125rem;display:flex}.console-file-badge{text-align:center;border:1px solid;border-radius:4px;width:18px;font-size:.6875rem}.console-file-path,.console-commit-message{flex:1;font-family:ui-monospace,SFMono-Regular,Menlo,monospace}.console-file-add,.console-pr-add{color:#3fb950}.console-file-del,.console-pr-del{color:#f85149}.console-commit-sha{color:#8b949e;font-family:ui-monospace,SFMono-Regular,Menlo,monospace}.console-actionbar{z-index:100;padding:10px 16px;padding-bottom:calc(10px + env(safe-area-inset-bottom));background:#161b22;border-top:2px solid #30363d;margin-top:auto;position:sticky;bottom:0}.console-operation-bar{flex-direction:column;gap:8px;width:100%;display:flex}.console-op-group{flex-wrap:wrap;justify-content:flex-end;align-items:center;gap:8px;display:flex}.console-op-group-review{gap:10px}.console-op-group-stories{max-height:33vh;overflow-y:auto}.console-op-button{color:#e6edf3;white-space:nowrap;cursor:pointer;background:#21262d;border:1px solid #30363d;border-radius:6px;padding:9px 16px;font-size:.8125rem;font-weight:600}.console-op-button:hover{border-color:#484f58}.console-op-button-approve{color:#fff;background:#238636;border-color:#2ea043}.console-op-button-reject{color:#ffd166;background:#7d5000;border-color:#a06800}.console-op-button-wrong{color:#f85149;background:#3a1518;border-color:#f85149}.console-op-button-unneeded{color:#aab0b8;background:#2a2d31;border-color:#6e7681}.console-op-button-snooze{color:#79c0ff;background:#1c2b4a;border-color:#4493f8}.console-pr-section{border:1px solid #30363d;border-radius:8px;flex-direction:column;gap:10px;padding:12px;display:flex}.console-pr-statbar{color:#8b949e;gap:12px;font-size:.75rem;display:flex}.console-detail-screen{flex-direction:column;flex:1 0 auto;display:flex}.console-panel-open-link{color:#4493f8;font-size:.8125rem;font-weight:400}.console-composer{margin-top:4px}.console-composer-toggle{color:#8b949e;cursor:pointer;background:0 0;border:none;padding:2px 0;font-size:.7813rem}.console-composer-toggle:hover{color:#e6edf3}.console-composer-posted{flex-direction:column;gap:8px;margin-top:8px;display:flex}.console-composer-form{margin-top:8px}.console-composer-input{box-sizing:border-box;color:#e6edf3;width:100%;font:inherit;resize:vertical;background:#21262d;border:1px solid #30363d;border-radius:6px;padding:8px;font-size:.875rem}.console-composer-row{align-items:center;gap:8px;margin-top:6px;display:flex}.console-composer-submit{color:#fff;cursor:pointer;background:#238636;border:1px solid #2ea043;border-radius:6px;padding:7px 16px;font-size:.8125rem;font-weight:600}.console-composer-submit:disabled{opacity:.6;cursor:default}.console-composer-status{color:#8b949e;font-size:.75rem}.console-composer-error{color:#f85149}.console-undo-toast{z-index:9998;white-space:nowrap;border-radius:10px;align-items:center;gap:12px;max-width:92vw;padding:12px 18px;font-size:.8438rem;display:flex;position:fixed;top:12px;left:50%;transform:translate(-50%);box-shadow:0 4px 20px #0009}.console-undo-toast-green{color:#3fb950;background:#0d3320;border:1px solid #2ea043}.console-undo-toast-amber{color:#ffd166;background:#3a2800;border:1px solid #a06800}.console-undo-toast-red{color:#f85149;background:#3a1518;border:1px solid #da3633}.console-undo-toast-gray{color:#aab0b8;background:#2a2d31;border:1px solid #6e7681}.console-undo-toast-blue{color:#79c0ff;background:#0d1f40;border:1px solid #4493f8}.console-undo-toast-error{color:#f85149;background:#3a1518;border:1px solid #f85149}.console-undo-toast-message{text-overflow:ellipsis;flex:1;min-width:0;overflow:hidden}.console-undo-toast-undo{cursor:pointer;color:inherit;background:#ffffff1f;border:none;border-radius:6px;flex:none;padding:4px 12px;font-size:.8125rem;font-weight:700}.console-undo-toast-undo:hover{background:#ffffff38}.console-undo-toast-countdown{opacity:.7;flex:none;font-size:.6875rem}.console-undo-toast-bar{opacity:.5;background:currentColor;border-radius:0 0 10px 10px;height:3px;transition:width .1s linear;position:absolute;bottom:0;left:0}.console-file-row{width:100%;color:inherit;font:inherit;text-align:left;cursor:pointer;background:0 0;border:none;align-items:center;gap:8px;padding:4px 0;font-size:.8125rem;display:flex}.console-file-row:hover{background:#1a2029}.console-file-caret{color:#8b949e;flex:none;width:1em}.console-file-diff{border-collapse:collapse;width:100%;margin:4px 0 8px;font:.8125rem/1.6 ui-monospace,SFMono-Regular,Menlo,monospace}.console-file-diff td{white-space:pre-wrap;word-break:break-word;vertical-align:top;padding:0 10px}.console-diff-ln{text-align:right;color:#6e7681;-webkit-user-select:none;user-select:none;white-space:nowrap;border-right:1px solid #30363d;width:1%;padding:0 8px}.console-file-diff td.console-diff-ln{white-space:nowrap;word-break:normal;overflow-wrap:normal}.console-diff-add td{background:#2ea04326}.console-diff-add .console-diff-code{color:#aff5b4}.console-diff-del td{background:#f8514926}.console-diff-del .console-diff-code{color:#ffdcd7}.console-diff-hunk td{color:#79c0ff;background:#161b22}.console-diff-ctx .console-diff-code{color:#c9d1d9}.console-file-diff-empty{color:#8b949e;padding:8px 14px;font-size:.75rem}.console-diff-comment-cell{text-align:center;-webkit-user-select:none;user-select:none;width:1%;padding:0 2px}.console-diff-comment-button{color:#6e7681;cursor:pointer;opacity:.6;background:0 0;border:1px solid #30363d;border-radius:4px;width:18px;height:18px;padding:0;font-size:.875rem;line-height:16px}.console-diff-row:hover .console-diff-comment-button,.console-diff-comment-button:focus-visible,.console-diff-comment-button[aria-expanded=true]{opacity:1;color:#fff;background:#1f6feb;border-color:#2f81f7}.console-diff-composer-row td{background:#0d1117;padding:6px 10px}.console-diff-composer{background:#161b22;border:1px solid #30363d;border-radius:6px;flex-direction:column;gap:6px;padding:8px;display:flex}.console-diff-composer-anchor{color:#8b949e;font-size:.6875rem}.console-diff-composer-input{resize:vertical;color:#c9d1d9;width:100%;font:inherit;background:#0d1117;border:1px solid #30363d;border-radius:6px;padding:6px 8px}.console-diff-composer-controls{align-items:center;gap:8px;display:flex}.console-diff-composer-submit{color:#fff;cursor:pointer;background:#238636;border:1px solid #238636;border-radius:6px;padding:4px 12px}.console-diff-composer-submit:disabled{opacity:.6;cursor:default}.console-diff-composer-cancel{color:#c9d1d9;cursor:pointer;background:0 0;border:1px solid #30363d;border-radius:6px;padding:4px 12px}.console-diff-composer-status{color:#8b949e;font-size:.75rem}.console-diff-composer-error{color:#ff7b72}.console-diff-composer-posted{color:#3fb950;margin:0;font-size:.75rem}.console-pr-header{flex-wrap:wrap;align-items:center;gap:10px;padding-top:4px;display:flex}.console-pr-section-title{color:#e6edf3;font-size:.9375rem;font-weight:600}.console-pr-section-state{color:#8b949e;border:1px solid #6e7681;border-radius:999px;padding:1px 8px;font-size:.6875rem}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-outline-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}
@@ -4,8 +4,8 @@
4
4
  <meta charset="UTF-8" />
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
6
  <title>TDPM Console</title>
7
- <script type="module" crossorigin src="/assets/index-Bm0wt3Mn.js"></script>
8
- <link rel="stylesheet" crossorigin href="/assets/index-D1V2fi29.css">
7
+ <script type="module" crossorigin src="/assets/index-CJJsRF8i.js"></script>
8
+ <link rel="stylesheet" crossorigin href="/assets/index-DGVKvwux.css">
9
9
  </head>
10
10
  <body>
11
11
  <div id="root"></div>
@@ -586,6 +586,7 @@ describe('webServer new routes integration', () => {
586
586
  createdAt: new Date('2026-06-18T03:21:00.000Z'),
587
587
  isDraft: false,
588
588
  isConflicted: true,
589
+ mergeable: 'CONFLICTING',
589
590
  isPassedAllCiJob: false,
590
591
  isCiStateSuccess: false,
591
592
  isResolvedAllReviewComments: false,
@@ -616,6 +617,7 @@ describe('webServer new routes integration', () => {
616
617
  found: true,
617
618
  status: {
618
619
  isConflicted: true,
620
+ mergeableStatus: 'CONFLICTING',
619
621
  isPassedAllCiJob: false,
620
622
  isCiStateSuccess: false,
621
623
  isBranchOutOfDate: true,
@@ -13,7 +13,7 @@ import {
13
13
 
14
14
  const NOW = new Date('2026-06-26T00:00:00.000Z');
15
15
  const NOW_EPOCH_SECONDS = Math.floor(NOW.getTime() / 1000);
16
- const SESSION_NAME = 'workbench';
16
+ const SESSION_NAME = 'https_//github_com/HiromiShikata/repo/issues/9';
17
17
  const SESSION_ID = 'wb-uuid';
18
18
  const PANE_PID = 200;
19
19
  const CLAUDE_PID = 201;
@@ -121,7 +121,7 @@ describe('notifySilentTmuxSessions', () => {
121
121
  ...DEFAULT_NOTIFY_SILENT_TMUX_SESSIONS_PARAMS,
122
122
  });
123
123
 
124
- it('sends a main stalled notification to a silent plain-named live session', async () => {
124
+ it('sends a main stalled notification to a silent github-named live session', async () => {
125
125
  silentAssistantTranscript();
126
126
  const runner = liveSessionRunner();
127
127
 
@@ -134,6 +134,34 @@ describe('notifySilentTmuxSessions', () => {
134
134
  expect(sendCall?.[1][4]).toContain('You have produced no output for');
135
135
  });
136
136
 
137
+ it('sends no notification to a silent non-github-named live session', async () => {
138
+ silentAssistantTranscript();
139
+ const runner = createMockRunner();
140
+ runner.runCommand.mockImplementation(async (program, args) => {
141
+ if (program === 'tmux' && args[0] === 'list-sessions') {
142
+ return { stdout: 'orchestrator\n', stderr: '', exitCode: 0 };
143
+ }
144
+ if (program === 'tmux' && args[0] === 'list-panes') {
145
+ return { stdout: `${PANE_PID}\n`, stderr: '', exitCode: 0 };
146
+ }
147
+ if (program === 'ps') {
148
+ return {
149
+ stdout: ` ${PANE_PID} 1 shell\n ${CLAUDE_PID} ${PANE_PID} claude --name orchestrator\n`,
150
+ stderr: '',
151
+ exitCode: 0,
152
+ };
153
+ }
154
+ return { stdout: '', stderr: '', exitCode: 0 };
155
+ });
156
+
157
+ await notifySilentTmuxSessions(baseParams(runner));
158
+
159
+ const sendCall = runner.runCommand.mock.calls.find(
160
+ (call) => call[0] === 'tmux' && call[1][0] === 'send-keys',
161
+ );
162
+ expect(sendCall).toBeUndefined();
163
+ });
164
+
137
165
  it('does nothing when the step is not enabled', async () => {
138
166
  silentAssistantTranscript();
139
167
  const runner = liveSessionRunner();
@@ -996,6 +996,7 @@ export class ApiV3CheerioRestIssueRepository
996
996
  createdAt: new Date(0),
997
997
  isDraft: data.isDraft === true,
998
998
  isConflicted,
999
+ mergeable: data.mergeable ?? null,
999
1000
  isPassedAllCiJob,
1000
1001
  isCiStateSuccess,
1001
1002
  isResolvedAllReviewComments,
@@ -46,6 +46,7 @@ const createReadyPr = (
46
46
  createdAt: new Date('2000-01-01T00:00:00Z'),
47
47
  isDraft: false,
48
48
  isConflicted: false,
49
+ mergeable: null,
49
50
  isPassedAllCiJob: true,
50
51
  isCiStateSuccess: true,
51
52
  isResolvedAllReviewComments: true,
@@ -10,6 +10,7 @@ const createReadyPr = (
10
10
  createdAt: new Date('2000-01-01T00:00:00Z'),
11
11
  isDraft: false,
12
12
  isConflicted: false,
13
+ mergeable: null,
13
14
  isPassedAllCiJob: true,
14
15
  isCiStateSuccess: true,
15
16
  isResolvedAllReviewComments: true,
@@ -2,6 +2,7 @@ import {
2
2
  NotifySilentLiveSessionsUseCase,
3
3
  HubTaskStatusResolver,
4
4
  parseHubTaskIssueUrlFromSessionName,
5
+ isGitHubIssueOrPullRequestSessionName,
5
6
  DEFAULT_MAIN_SILENT_THRESHOLD_SECONDS,
6
7
  DEFAULT_SUBAGENT_SILENT_THRESHOLD_SECONDS,
7
8
  DEFAULT_SUBAGENT_RUNNING_THRESHOLD_SECONDS,
@@ -38,6 +39,11 @@ describe('NotifySilentLiveSessionsUseCase', () => {
38
39
  let mockHubTaskStatusResolver: Mocked<HubTaskStatusResolver>;
39
40
  const now = new Date('2026-06-26T00:00:00Z');
40
41
  const nowEpochSeconds = Math.floor(now.getTime() / 1000);
42
+ const GITHUB_SESSION = 'https_//github_com/HiromiShikata/repo/issues/42';
43
+ const GITHUB_SESSION_ALPHA =
44
+ 'https_//github_com/HiromiShikata/repo/issues/100';
45
+ const GITHUB_SESSION_BRAVO =
46
+ 'https_//github_com/HiromiShikata/repo/issues/200';
41
47
 
42
48
  const runParams = (
43
49
  overrides?: Partial<{ activeHubTaskStatus: string | null }>,
@@ -208,12 +214,12 @@ describe('NotifySilentLiveSessionsUseCase', () => {
208
214
  expect(DEFAULT_NOTIFICATION_STAGGER_SECONDS).toBe(25);
209
215
  });
210
216
 
211
- it('notifies a plain-named live interactive session independently of any issue', async () => {
212
- setupLiveInteractiveSession('workbench');
217
+ it('notifies a session whose name encodes a github.com issue URL', async () => {
218
+ setupLiveInteractiveSession(GITHUB_SESSION);
213
219
  mockSessionOutputActivityRepository.listSessionOutputActivities.mockResolvedValue(
214
220
  [
215
221
  {
216
- sessionName: 'workbench',
222
+ sessionName: GITHUB_SESSION,
217
223
  lastOutputEpochSeconds:
218
224
  nowEpochSeconds - DEFAULT_MAIN_SILENT_THRESHOLD_SECONDS,
219
225
  },
@@ -227,15 +233,100 @@ describe('NotifySilentLiveSessionsUseCase', () => {
227
233
  );
228
234
  expect(
229
235
  mockNotificationRepository.sendSelfCheckNotification,
230
- ).toHaveBeenCalledWith('workbench', MAIN_STALLED_SECTION);
236
+ ).toHaveBeenCalledWith(GITHUB_SESSION, MAIN_STALLED_SECTION);
237
+ });
238
+
239
+ it('notifies a session whose name encodes a github.com pull-request URL', async () => {
240
+ const pullRequestSession = 'https_//github_com/HiromiShikata/repo/pull/77';
241
+ setupLiveInteractiveSession(pullRequestSession);
242
+ mockSessionOutputActivityRepository.listSessionOutputActivities.mockResolvedValue(
243
+ [
244
+ {
245
+ sessionName: pullRequestSession,
246
+ lastOutputEpochSeconds:
247
+ nowEpochSeconds - DEFAULT_MAIN_SILENT_THRESHOLD_SECONDS,
248
+ },
249
+ ],
250
+ );
251
+
252
+ await useCase.run(runParams());
253
+
254
+ expect(
255
+ mockNotificationRepository.sendSelfCheckNotification,
256
+ ).toHaveBeenCalledWith(pullRequestSession, MAIN_STALLED_SECTION);
257
+ });
258
+
259
+ it('excludes a non-github-named session from selection so it is never notified', async () => {
260
+ mockSnapshotProvider.getSnapshot.mockResolvedValue(
261
+ snapshotWithSessions(['workbench']),
262
+ );
263
+ mockSessionOutputActivityRepository.listSessionOutputActivities.mockResolvedValue(
264
+ [
265
+ {
266
+ sessionName: 'workbench',
267
+ lastOutputEpochSeconds:
268
+ nowEpochSeconds - DEFAULT_MAIN_SILENT_THRESHOLD_SECONDS,
269
+ },
270
+ ],
271
+ );
272
+
273
+ await useCase.run(runParams());
274
+
275
+ expect(mockTranscriptResolver.resolveTranscriptPaths).toHaveBeenCalledWith(
276
+ [],
277
+ );
278
+ expect(
279
+ mockSubAgentActivityRepository.listSubAgentActivitiesBySessionName,
280
+ ).toHaveBeenCalledWith([]);
281
+ expect(
282
+ mockMessageComposer.composeMainStalledSection,
283
+ ).not.toHaveBeenCalled();
284
+ expect(
285
+ mockNotificationRepository.sendSelfCheckNotification,
286
+ ).not.toHaveBeenCalled();
287
+ });
288
+
289
+ it('monitors only the github-named session when mixed with a non-github-named session', async () => {
290
+ mockSnapshotProvider.getSnapshot.mockResolvedValue(
291
+ snapshotWithSessions([GITHUB_SESSION, 'orchestrator']),
292
+ );
293
+ mockTranscriptResolver.resolveTranscriptPaths.mockReturnValue(
294
+ transcriptMapFor([GITHUB_SESSION]),
295
+ );
296
+ mockSessionOutputActivityRepository.listSessionOutputActivities.mockResolvedValue(
297
+ [
298
+ {
299
+ sessionName: GITHUB_SESSION,
300
+ lastOutputEpochSeconds:
301
+ nowEpochSeconds - DEFAULT_MAIN_SILENT_THRESHOLD_SECONDS,
302
+ },
303
+ {
304
+ sessionName: 'orchestrator',
305
+ lastOutputEpochSeconds:
306
+ nowEpochSeconds - DEFAULT_MAIN_SILENT_THRESHOLD_SECONDS,
307
+ },
308
+ ],
309
+ );
310
+
311
+ await useCase.run(runParams());
312
+
313
+ expect(mockTranscriptResolver.resolveTranscriptPaths).toHaveBeenCalledWith([
314
+ sessionFor(GITHUB_SESSION),
315
+ ]);
316
+ expect(
317
+ mockNotificationRepository.sendSelfCheckNotification,
318
+ ).toHaveBeenCalledTimes(1);
319
+ expect(
320
+ mockNotificationRepository.sendSelfCheckNotification,
321
+ ).toHaveBeenCalledWith(GITHUB_SESSION, MAIN_STALLED_SECTION);
231
322
  });
232
323
 
233
324
  it('passes the resolved transcript paths to the output and owner-call providers', async () => {
234
- setupLiveInteractiveSession('workbench');
325
+ setupLiveInteractiveSession(GITHUB_SESSION);
235
326
 
236
327
  await useCase.run(runParams());
237
328
 
238
- const expectedMap = transcriptMapFor(['workbench']);
329
+ const expectedMap = transcriptMapFor([GITHUB_SESSION]);
239
330
  expect(
240
331
  mockSessionOutputActivityRepository.listSessionOutputActivities,
241
332
  ).toHaveBeenCalledWith(expectedMap);
@@ -244,22 +335,22 @@ describe('NotifySilentLiveSessionsUseCase', () => {
244
335
  ).toHaveBeenCalledWith(expectedMap);
245
336
  expect(
246
337
  mockSubAgentActivityRepository.listSubAgentActivitiesBySessionName,
247
- ).toHaveBeenCalledWith(['workbench']);
338
+ ).toHaveBeenCalledWith([GITHUB_SESSION]);
248
339
  });
249
340
 
250
341
  it('suppresses the stalled section and sends nothing when an owner call is pending past the threshold', async () => {
251
- setupLiveInteractiveSession('workbench');
342
+ setupLiveInteractiveSession(GITHUB_SESSION);
252
343
  mockSessionOutputActivityRepository.listSessionOutputActivities.mockResolvedValue(
253
344
  [
254
345
  {
255
- sessionName: 'workbench',
346
+ sessionName: GITHUB_SESSION,
256
347
  lastOutputEpochSeconds:
257
348
  nowEpochSeconds - DEFAULT_MAIN_SILENT_THRESHOLD_SECONDS,
258
349
  },
259
350
  ],
260
351
  );
261
352
  mockOwnerCallStatusProvider.listSessionNamesWithUnansweredOwnerCall.mockResolvedValue(
262
- new Set(['workbench']),
353
+ new Set([GITHUB_SESSION]),
263
354
  );
264
355
 
265
356
  await useCase.run(runParams());
@@ -273,11 +364,11 @@ describe('NotifySilentLiveSessionsUseCase', () => {
273
364
  });
274
365
 
275
366
  it('sends the main stalled section when the session is silent past the threshold and not waiting on the owner', async () => {
276
- setupLiveInteractiveSession('workbench');
367
+ setupLiveInteractiveSession(GITHUB_SESSION);
277
368
  mockSessionOutputActivityRepository.listSessionOutputActivities.mockResolvedValue(
278
369
  [
279
370
  {
280
- sessionName: 'workbench',
371
+ sessionName: GITHUB_SESSION,
281
372
  lastOutputEpochSeconds:
282
373
  nowEpochSeconds - DEFAULT_MAIN_SILENT_THRESHOLD_SECONDS,
283
374
  },
@@ -294,15 +385,15 @@ describe('NotifySilentLiveSessionsUseCase', () => {
294
385
  );
295
386
  expect(
296
387
  mockNotificationRepository.sendSelfCheckNotification,
297
- ).toHaveBeenCalledWith('workbench', MAIN_STALLED_SECTION);
388
+ ).toHaveBeenCalledWith(GITHUB_SESSION, MAIN_STALLED_SECTION);
298
389
  });
299
390
 
300
391
  it('does not send the main stalled section when output is within the threshold', async () => {
301
- setupLiveInteractiveSession('workbench');
392
+ setupLiveInteractiveSession(GITHUB_SESSION);
302
393
  mockSessionOutputActivityRepository.listSessionOutputActivities.mockResolvedValue(
303
394
  [
304
395
  {
305
- sessionName: 'workbench',
396
+ sessionName: GITHUB_SESSION,
306
397
  lastOutputEpochSeconds:
307
398
  nowEpochSeconds - DEFAULT_MAIN_SILENT_THRESHOLD_SECONDS + 1,
308
399
  },
@@ -317,7 +408,7 @@ describe('NotifySilentLiveSessionsUseCase', () => {
317
408
  });
318
409
 
319
410
  it('sends the sub-agent section when a sub-agent exceeds the silent threshold', async () => {
320
- setupLiveInteractiveSession('workbench');
411
+ setupLiveInteractiveSession(GITHUB_SESSION);
321
412
  const subAgents: SubAgentActivity[] = [
322
413
  {
323
414
  label: 'sub-process-1',
@@ -326,7 +417,7 @@ describe('NotifySilentLiveSessionsUseCase', () => {
326
417
  },
327
418
  ];
328
419
  mockSubAgentActivityRepository.listSubAgentActivitiesBySessionName.mockResolvedValue(
329
- new Map([['workbench', subAgents]]),
420
+ new Map([[GITHUB_SESSION, subAgents]]),
330
421
  );
331
422
 
332
423
  await useCase.run(runParams());
@@ -336,7 +427,7 @@ describe('NotifySilentLiveSessionsUseCase', () => {
336
427
  );
337
428
  expect(
338
429
  mockNotificationRepository.sendSelfCheckNotification,
339
- ).toHaveBeenCalledWith('workbench', SUBAGENT_SECTION);
430
+ ).toHaveBeenCalledWith(GITHUB_SESSION, SUBAGENT_SECTION);
340
431
  });
341
432
 
342
433
  it('excludes an owner-handover spawn from selection so no notification is sent', async () => {
@@ -374,11 +465,11 @@ describe('NotifySilentLiveSessionsUseCase', () => {
374
465
  });
375
466
 
376
467
  it('re-notifies a session on every consecutive cycle while it remains a valid silent target', async () => {
377
- setupLiveInteractiveSession('workbench');
468
+ setupLiveInteractiveSession(GITHUB_SESSION);
378
469
  mockSessionOutputActivityRepository.listSessionOutputActivities.mockResolvedValue(
379
470
  [
380
471
  {
381
- sessionName: 'workbench',
472
+ sessionName: GITHUB_SESSION,
382
473
  lastOutputEpochSeconds:
383
474
  nowEpochSeconds - DEFAULT_MAIN_SILENT_THRESHOLD_SECONDS,
384
475
  },
@@ -393,18 +484,18 @@ describe('NotifySilentLiveSessionsUseCase', () => {
393
484
  ).toHaveBeenCalledTimes(2);
394
485
  expect(
395
486
  mockNotificationRepository.sendSelfCheckNotification,
396
- ).toHaveBeenNthCalledWith(1, 'workbench', MAIN_STALLED_SECTION);
487
+ ).toHaveBeenNthCalledWith(1, GITHUB_SESSION, MAIN_STALLED_SECTION);
397
488
  expect(
398
489
  mockNotificationRepository.sendSelfCheckNotification,
399
- ).toHaveBeenNthCalledWith(2, 'workbench', MAIN_STALLED_SECTION);
490
+ ).toHaveBeenNthCalledWith(2, GITHUB_SESSION, MAIN_STALLED_SECTION);
400
491
  });
401
492
 
402
493
  it('notifies on every repeated cycle at the same instant without reading any cooldown state', async () => {
403
- setupLiveInteractiveSession('workbench');
494
+ setupLiveInteractiveSession(GITHUB_SESSION);
404
495
  mockSessionOutputActivityRepository.listSessionOutputActivities.mockResolvedValue(
405
496
  [
406
497
  {
407
- sessionName: 'workbench',
498
+ sessionName: GITHUB_SESSION,
408
499
  lastOutputEpochSeconds:
409
500
  nowEpochSeconds - DEFAULT_MAIN_SILENT_THRESHOLD_SECONDS,
410
501
  },
@@ -426,20 +517,20 @@ describe('NotifySilentLiveSessionsUseCase', () => {
426
517
 
427
518
  it('sends to multiple sessions sequentially with a stagger delay between sends', async () => {
428
519
  mockSnapshotProvider.getSnapshot.mockResolvedValue(
429
- snapshotWithSessions(['alpha', 'bravo']),
520
+ snapshotWithSessions([GITHUB_SESSION_ALPHA, GITHUB_SESSION_BRAVO]),
430
521
  );
431
522
  mockTranscriptResolver.resolveTranscriptPaths.mockReturnValue(
432
- transcriptMapFor(['alpha', 'bravo']),
523
+ transcriptMapFor([GITHUB_SESSION_ALPHA, GITHUB_SESSION_BRAVO]),
433
524
  );
434
525
  mockSessionOutputActivityRepository.listSessionOutputActivities.mockResolvedValue(
435
526
  [
436
527
  {
437
- sessionName: 'alpha',
528
+ sessionName: GITHUB_SESSION_ALPHA,
438
529
  lastOutputEpochSeconds:
439
530
  nowEpochSeconds - DEFAULT_MAIN_SILENT_THRESHOLD_SECONDS,
440
531
  },
441
532
  {
442
- sessionName: 'bravo',
533
+ sessionName: GITHUB_SESSION_BRAVO,
443
534
  lastOutputEpochSeconds:
444
535
  nowEpochSeconds - DEFAULT_MAIN_SILENT_THRESHOLD_SECONDS,
445
536
  },
@@ -458,7 +549,11 @@ describe('NotifySilentLiveSessionsUseCase', () => {
458
549
 
459
550
  await useCase.run(runParams());
460
551
 
461
- expect(callOrder).toEqual(['send:alpha', 'sleep', 'send:bravo']);
552
+ expect(callOrder).toEqual([
553
+ `send:${GITHUB_SESSION_ALPHA}`,
554
+ 'sleep',
555
+ `send:${GITHUB_SESSION_BRAVO}`,
556
+ ]);
462
557
  expect(mockSleeper.sleep).toHaveBeenCalledTimes(1);
463
558
  expect(mockSleeper.sleep).toHaveBeenCalledWith(
464
559
  DEFAULT_NOTIFICATION_STAGGER_SECONDS * 1000,
@@ -466,11 +561,11 @@ describe('NotifySilentLiveSessionsUseCase', () => {
466
561
  });
467
562
 
468
563
  it('does not suppress errors raised while sending a notification', async () => {
469
- setupLiveInteractiveSession('workbench');
564
+ setupLiveInteractiveSession(GITHUB_SESSION);
470
565
  mockSessionOutputActivityRepository.listSessionOutputActivities.mockResolvedValue(
471
566
  [
472
567
  {
473
- sessionName: 'workbench',
568
+ sessionName: GITHUB_SESSION,
474
569
  lastOutputEpochSeconds:
475
570
  nowEpochSeconds - DEFAULT_MAIN_SILENT_THRESHOLD_SECONDS,
476
571
  },
@@ -538,7 +633,7 @@ describe('NotifySilentLiveSessionsUseCase', () => {
538
633
  ).not.toHaveBeenCalled();
539
634
  });
540
635
 
541
- it('leaves a non-URL session name unchecked and sends as before', async () => {
636
+ it('excludes a non-github-named session before the hub-task gate so the resolver is never consulted', async () => {
542
637
  setupSilentMainSession('workbench');
543
638
 
544
639
  await useCase.run(runParams({ activeHubTaskStatus: ACTIVE_STATUS }));
@@ -546,7 +641,7 @@ describe('NotifySilentLiveSessionsUseCase', () => {
546
641
  expect(mockHubTaskStatusResolver.getIssueByUrl).not.toHaveBeenCalled();
547
642
  expect(
548
643
  mockNotificationRepository.sendSelfCheckNotification,
549
- ).toHaveBeenCalledWith('workbench', MAIN_STALLED_SECTION);
644
+ ).not.toHaveBeenCalled();
550
645
  });
551
646
 
552
647
  it('does not call the resolver at all when the active status is unconfigured', async () => {
@@ -616,6 +711,72 @@ describe('NotifySilentLiveSessionsUseCase', () => {
616
711
  });
617
712
  });
618
713
 
714
+ describe('isGitHubIssueOrPullRequestSessionName', () => {
715
+ it('accepts the encoded form of a github.com issue URL session name', () => {
716
+ expect(
717
+ isGitHubIssueOrPullRequestSessionName(
718
+ 'https_//github_com/HiromiShikata/repo/issues/42',
719
+ ),
720
+ ).toBe(true);
721
+ });
722
+
723
+ it('accepts the encoded form of a github.com pull-request URL session name', () => {
724
+ expect(
725
+ isGitHubIssueOrPullRequestSessionName(
726
+ 'https_//github_com/HiromiShikata/repo/pull/77',
727
+ ),
728
+ ).toBe(true);
729
+ });
730
+
731
+ it('accepts the raw form of a github.com issue and pull-request URL session name', () => {
732
+ expect(
733
+ isGitHubIssueOrPullRequestSessionName(
734
+ 'https://github.com/HiromiShikata/repo/issues/42',
735
+ ),
736
+ ).toBe(true);
737
+ expect(
738
+ isGitHubIssueOrPullRequestSessionName(
739
+ 'https://github.com/HiromiShikata/repo/pull/77',
740
+ ),
741
+ ).toBe(true);
742
+ });
743
+
744
+ it('rejects a plain orchestrator-style session name', () => {
745
+ expect(isGitHubIssueOrPullRequestSessionName('workbench')).toBe(false);
746
+ expect(isGitHubIssueOrPullRequestSessionName('orchestrator')).toBe(false);
747
+ expect(isGitHubIssueOrPullRequestSessionName('aw-host')).toBe(false);
748
+ });
749
+
750
+ it('rejects a non-github host even in the encoded form', () => {
751
+ expect(
752
+ isGitHubIssueOrPullRequestSessionName(
753
+ 'https_//example_com/HiromiShikata/repo/issues/42',
754
+ ),
755
+ ).toBe(false);
756
+ });
757
+
758
+ it('rejects a github.com session name that is neither an issue nor a pull request', () => {
759
+ expect(
760
+ isGitHubIssueOrPullRequestSessionName(
761
+ 'https_//github_com/HiromiShikata/repo',
762
+ ),
763
+ ).toBe(false);
764
+ expect(
765
+ isGitHubIssueOrPullRequestSessionName(
766
+ 'https_//github_com/HiromiShikata/repo/discussions/42',
767
+ ),
768
+ ).toBe(false);
769
+ });
770
+
771
+ it('rejects a github.com issue URL whose trailing segment is not a number', () => {
772
+ expect(
773
+ isGitHubIssueOrPullRequestSessionName(
774
+ 'https_//github_com/HiromiShikata/repo/issues/new',
775
+ ),
776
+ ).toBe(false);
777
+ });
778
+ });
779
+
619
780
  it('uses the session entity helper for type completeness', () => {
620
781
  expect(sessionFor('workbench')).toEqual({
621
782
  sessionName: 'workbench',
@@ -25,6 +25,14 @@ export const parseHubTaskIssueUrlFromSessionName = (
25
25
  return GITHUB_ISSUE_URL_PATTERN.test(sessionName) ? sessionName : null;
26
26
  };
27
27
 
28
+ const GITHUB_ISSUE_OR_PULL_REQUEST_SESSION_NAME_PATTERN =
29
+ /^https(:\/\/|_\/\/)github(\.com|_com)\/[^/]+\/[^/]+\/(issues|pull)\/\d+$/;
30
+
31
+ export const isGitHubIssueOrPullRequestSessionName = (
32
+ sessionName: string,
33
+ ): boolean =>
34
+ GITHUB_ISSUE_OR_PULL_REQUEST_SESSION_NAME_PATTERN.test(sessionName);
35
+
28
36
  export type HubTaskStatusResolver = Pick<IssueRepository, 'getIssueByUrl'>;
29
37
 
30
38
  type NotifyCandidate = {
@@ -58,8 +66,18 @@ export class NotifySilentLiveSessionsUseCase {
58
66
  }): Promise<void> => {
59
67
  const snapshot =
60
68
  await this.liveSessionProcessSnapshotProvider.getSnapshot();
61
- const interactiveSessions =
69
+ const allInteractiveSessions =
62
70
  this.resolveInteractiveLiveSessions.resolve(snapshot);
71
+ const interactiveSessions = allInteractiveSessions.filter((session) =>
72
+ isGitHubIssueOrPullRequestSessionName(session.sessionName),
73
+ );
74
+ const skippedNonGitHubSessionCount =
75
+ allInteractiveSessions.length - interactiveSessions.length;
76
+ if (skippedNonGitHubSessionCount > 0) {
77
+ console.log(
78
+ `Silent live session notification: ignoring ${skippedNonGitHubSessionCount} non-github-named interactive session(s); only sessions named after a github.com issue or pull-request URL are monitored.`,
79
+ );
80
+ }
63
81
  const transcriptPathBySessionName =
64
82
  this.interactiveLiveSessionTranscriptResolver.resolveTranscriptPaths(
65
83
  interactiveSessions,