conductor-remote 1.17.0 → 1.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/assets/index-BTmIqTa9.js +40 -0
- package/dist/assets/index-Dtq6pwjg.css +1 -0
- package/dist/index.html +2 -2
- package/dist/sw.js +1 -1
- package/dist-node/src/git.js +21 -1
- package/dist-node/src/merge.js +29 -91
- package/dist-node/src/pr.js +5 -1
- package/dist-node/src/reads.js +20 -3
- package/dist-node/src/server.js +13 -11
- package/dist-node/src/transcript.js +77 -52
- package/package.json +1 -1
- package/dist/assets/index-CFZawBc8.css +0 -1
- package/dist/assets/index-CFyDd-9V.js +0 -41
|
@@ -0,0 +1 @@
|
|
|
1
|
+
@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-translate-x:0;--tw-translate-y:0;--tw-translate-z:0;--tw-rotate-x:initial;--tw-rotate-y:initial;--tw-rotate-z:initial;--tw-skew-x:initial;--tw-skew-y:initial;--tw-border-style:solid;--tw-leading:initial;--tw-font-weight:initial;--tw-tracking:initial;--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;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial;--tw-backdrop-blur:initial;--tw-backdrop-brightness:initial;--tw-backdrop-contrast:initial;--tw-backdrop-grayscale:initial;--tw-backdrop-hue-rotate:initial;--tw-backdrop-invert:initial;--tw-backdrop-opacity:initial;--tw-backdrop-saturate:initial;--tw-backdrop-sepia:initial;--tw-duration:initial;--tw-ease:initial;--tw-scale-x:1;--tw-scale-y:1;--tw-scale-z:1}}}@layer theme{:root,:host{--font-sans:ui-sans-serif, system-ui, -apple-system, "SF Pro Text", "Segoe UI", Roboto, sans-serif;--font-mono:ui-monospace, "SF Mono", "JetBrains Mono", "Fira Code", Menlo, monospace;--color-black:#000;--color-white:#fff;--spacing:.25rem;--container-xs:20rem;--container-sm:24rem;--text-xs:.75rem;--text-xs--line-height:calc(1 / .75);--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--text-base:1rem;--text-base--line-height: 1.5 ;--text-lg:1.125rem;--text-lg--line-height:calc(1.75 / 1.125);--text-xl:1.25rem;--text-xl--line-height:calc(1.75 / 1.25);--font-weight-normal:400;--font-weight-medium:500;--font-weight-semibold:600;--font-weight-bold:700;--tracking-wide:.025em;--leading-tight:1.25;--leading-relaxed:1.625;--radius-md:.375rem;--radius-lg:.5rem;--radius-xl:.75rem;--radius-2xl:1rem;--radius-3xl:1.5rem;--ease-out:cubic-bezier(0, 0, .2, 1);--animate-spin:spin 1s linear infinite;--blur-xl:24px;--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-bg:#0a0b0e;--color-surface:#14161b;--color-surface-2:#1b1e26;--color-border:#262a33;--color-border-soft:#1e222a;--color-text:#e7e9ee;--color-muted:#8b909d;--color-faint:#5c616d;--color-accent:#8b7dff;--color-accent-soft:#2a2650;--color-working:#f5a623;--color-idle:#3ecf8e;--color-done:#5b9dff;--color-pr-merged:#ac47ff;--color-pr-draft:#a4a3a2;--color-pr-conflicts:#fd9a00;--color-pr-mergeable:#49de80;--color-add:#3ecf8e;--color-del:#ff6b6b}}@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%;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]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}*{-webkit-tap-highlight-color:transparent}html,body,#root{height:100dvh}html{background:var(--color-bg)}body{background:var(--color-bg);color:var(--color-text);font-family:var(--font-sans);-webkit-font-smoothing:antialiased;overscroll-behavior:none;margin:0;overflow-x:hidden}button{font:inherit;color:inherit;cursor:pointer}::-webkit-scrollbar{width:0;height:0}}@layer components{.card{align-items:center;gap:calc(var(--spacing) * 3);border-radius:var(--radius-2xl);border-style:var(--tw-border-style);border-width:1px;border-color:var(--color-border);background-color:var(--color-surface);padding-inline:calc(var(--spacing) * 4);padding-block:calc(var(--spacing) * 3.5);text-align:left;transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to,opacity,box-shadow,transform,translate,scale,rotate,filter,-webkit-backdrop-filter,backdrop-filter,display,content-visibility,overlay,pointer-events;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));display:flex}.card:active{background-color:var(--color-surface-2);scale:.985}.pill{padding-inline:calc(var(--spacing) * 3.5);padding-block:calc(var(--spacing) * 1.5);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium);color:var(--color-muted);transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to,opacity,box-shadow,transform,translate,scale,rotate,filter,-webkit-backdrop-filter,backdrop-filter,display,content-visibility,overlay,pointer-events;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));border-radius:3.40282e38px}.pill-active{background-color:var(--color-surface-2);color:var(--color-text)}.dot{width:calc(var(--spacing) * 2.5);height:calc(var(--spacing) * 2.5);background-color:var(--color-faint);--pulse-color:var(--color-working);border-radius:3.40282e38px;flex-shrink:0}.dot-pulse{box-shadow:0 0 0 0 var(--pulse-color)}@supports (color:color-mix(in lab,red,red)){.dot-pulse{box-shadow:0 0 color-mix(in srgb,var(--pulse-color) 60%,transparent)}}.dot-pulse{animation:1.6s ease-out infinite pulse}.dot-working{background:var(--color-working);box-shadow:0 0 #f5a62399}@supports (color:color-mix(in lab,red,red)){.dot-working{box-shadow:0 0 color-mix(in srgb,var(--color-working) 60%,transparent)}}.dot-working{animation:1.6s ease-out infinite pulse}.dot-idle{background:var(--color-idle)}.dot-done{background:var(--color-done)}.md>:first-child{margin-top:0}.md>:last-child{margin-bottom:0}.md p{margin:.5em 0}.md h1,.md h2,.md h3,.md h4,.md h5,.md h6{margin:.9em 0 .4em;font-weight:600;line-height:1.3}.md h1{font-size:1.25em}.md h2{font-size:1.15em}.md h3{font-size:1.05em}.md ul,.md ol{margin:.5em 0;padding-left:1.4em}.md ul{list-style:outside}.md ol{list-style:decimal}.md li,.md li>ul,.md li>ol{margin:.2em 0}.md code{background:#1b1e26cc;border-radius:.3rem}@supports (color:color-mix(in lab,red,red)){.md code{background:color-mix(in srgb,var(--color-surface-2) 80%,transparent)}}.md code{font-family:var(--font-mono);padding:.1em .35em;font-size:.85em}.md pre{border:1px solid var(--color-border-soft);background:var(--color-bg);border-radius:.6rem;margin:.5em 0;padding:.6em .75em;overflow-x:auto}.md pre code{background:0 0;padding:0;font-size:12px;line-height:1.5}.md a{color:var(--color-accent);text-underline-offset:2px;text-decoration:underline}.md blockquote{border-left:2px solid var(--color-border);color:var(--color-muted);margin:.5em 0;padding-left:.75em}.md hr{border:0;border-top:1px solid var(--color-border-soft);margin:.75em 0}.md table{border-collapse:collapse;max-width:100%;margin:.5em 0;font-size:.9em;display:block;overflow-x:auto}.md th,.md td{border:1px solid var(--color-border);text-align:left;padding:.3em .6em}.md th{background:var(--color-surface-2);font-weight:600}.md strong{font-weight:600}.md input[type=checkbox]{margin-right:.4em}}@layer utilities{.pointer-events-none{pointer-events:none}.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.static{position:static}.sticky{position:sticky}.inset-0{inset:0}.inset-x-0{inset-inline:0}.inset-y-0{inset-block:0}.top-0{top:0}.top-1\.5{top:calc(var(--spacing) * 1.5)}.top-full{top:100%}.-right-0\.5{right:calc(var(--spacing) * -.5)}.right-1\.5{right:calc(var(--spacing) * 1.5)}.right-2{right:calc(var(--spacing) * 2)}.-bottom-0\.5{bottom:calc(var(--spacing) * -.5)}.bottom-0{bottom:0}.left-0{left:0}.z-10{z-index:10}.z-20{z-index:20}.z-30{z-index:30}.z-40{z-index:40}.z-50{z-index:50}.z-\[60\]{z-index:60}.mx-auto{margin-inline:auto}.mt-1{margin-top:var(--spacing)}.mt-2{margin-top:calc(var(--spacing) * 2)}.-mr-1{margin-right:calc(var(--spacing) * -1)}.mr-1{margin-right:var(--spacing)}.mb-0\.5{margin-bottom:calc(var(--spacing) * .5)}.mb-1{margin-bottom:var(--spacing)}.mb-1\.5{margin-bottom:calc(var(--spacing) * 1.5)}.mb-2{margin-bottom:calc(var(--spacing) * 2)}.-ml-1{margin-left:calc(var(--spacing) * -1)}.ml-auto{margin-left:auto}.line-clamp-4{-webkit-line-clamp:4;-webkit-box-orient:vertical;display:-webkit-box;overflow:hidden}.flex{display:flex}.grid{display:grid}.hidden{display:none}.inline{display:inline}.inline-block{display:inline-block}.size-1\.5{width:calc(var(--spacing) * 1.5);height:calc(var(--spacing) * 1.5)}.size-1\.5\!{width:calc(var(--spacing) * 1.5)!important;height:calc(var(--spacing) * 1.5)!important}.size-2{width:calc(var(--spacing) * 2);height:calc(var(--spacing) * 2)}.size-4{width:calc(var(--spacing) * 4);height:calc(var(--spacing) * 4)}.size-7{width:calc(var(--spacing) * 7);height:calc(var(--spacing) * 7)}.size-8{width:calc(var(--spacing) * 8);height:calc(var(--spacing) * 8)}.size-9{width:calc(var(--spacing) * 9);height:calc(var(--spacing) * 9)}.size-20{width:calc(var(--spacing) * 20);height:calc(var(--spacing) * 20)}.size-60{width:calc(var(--spacing) * 60);height:calc(var(--spacing) * 60)}.size-full{width:100%;height:100%}.h-full{height:100%}.max-h-40{max-height:calc(var(--spacing) * 40)}.w-1{width:var(--spacing)}.w-64{width:calc(var(--spacing) * 64)}.w-\[85\%\]{width:85%}.w-full{width:100%}.max-w-36{max-width:calc(var(--spacing) * 36)}.max-w-80{max-width:calc(var(--spacing) * 80)}.max-w-\[70vw\]{max-width:70vw}.max-w-\[85\%\]{max-width:85%}.max-w-\[92\%\]{max-width:92%}.max-w-full{max-width:100%}.max-w-sm{max-width:var(--container-sm)}.max-w-xs{max-width:var(--container-xs)}.min-w-0{min-width:0}.min-w-5{min-width:calc(var(--spacing) * 5)}.flex-1{flex:1}.shrink-0{flex-shrink:0}.-translate-x-full{--tw-translate-x:-100%;translate:var(--tw-translate-x) var(--tw-translate-y)}.translate-x-0{--tw-translate-x:0;translate:var(--tw-translate-x) var(--tw-translate-y)}.-rotate-90{rotate:-90deg}.transform{transform:var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,)}.animate-spin{animation:var(--animate-spin)}.cursor-pointer{cursor:pointer}.resize-none{resize:none}.list-none{list-style-type:none}.flex-col{flex-direction:column}.place-items-center{place-items:center}.items-baseline{align-items:baseline}.items-center{align-items:center}.items-end{align-items:flex-end}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.justify-end{justify-content:flex-end}.justify-start{justify-content:flex-start}.gap-0\.5{gap:calc(var(--spacing) * .5)}.gap-1{gap:var(--spacing)}.gap-1\.5{gap:calc(var(--spacing) * 1.5)}.gap-2{gap:calc(var(--spacing) * 2)}.gap-2\.5{gap:calc(var(--spacing) * 2.5)}.gap-3{gap:calc(var(--spacing) * 3)}.gap-4{gap:calc(var(--spacing) * 4)}.gap-5{gap:calc(var(--spacing) * 5)}.self-start{align-self:flex-start}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.overflow-x-hidden{overflow-x:hidden}.overflow-y-auto{overflow-y:auto}.rounded-2xl{border-radius:var(--radius-2xl)}.rounded-3xl{border-radius:var(--radius-3xl)}.rounded-full{border-radius:3.40282e38px}.rounded-lg{border-radius:var(--radius-lg)}.rounded-md{border-radius:var(--radius-md)}.rounded-xl{border-radius:var(--radius-xl)}.rounded-t-3xl{border-top-left-radius:var(--radius-3xl);border-top-right-radius:var(--radius-3xl)}.border{border-style:var(--tw-border-style);border-width:1px}.border-2{border-style:var(--tw-border-style);border-width:2px}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.border-r{border-right-style:var(--tw-border-style);border-right-width:1px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-l-2{border-left-style:var(--tw-border-style);border-left-width:2px}.border-accent\/50{border-color:#8b7dff80}@supports (color:color-mix(in lab,red,red)){.border-accent\/50{border-color:color-mix(in oklab,var(--color-accent) 50%,transparent)}}.border-border{border-color:var(--color-border)}.border-border-soft{border-color:var(--color-border-soft)}.border-del\/30{border-color:#ff6b6b4d}@supports (color:color-mix(in lab,red,red)){.border-del\/30{border-color:color-mix(in oklab,var(--color-del) 30%,transparent)}}.border-faint{border-color:var(--color-faint)}.border-white\/80{border-color:#fffc}@supports (color:color-mix(in lab,red,red)){.border-white\/80{border-color:color-mix(in oklab,var(--color-white) 80%,transparent)}}.border-t-accent{border-top-color:var(--color-accent)}.bg-accent{background-color:var(--color-accent)}.bg-accent-soft{background-color:var(--color-accent-soft)}.bg-add{background-color:var(--color-add)}.bg-add\/10{background-color:#3ecf8e1a}@supports (color:color-mix(in lab,red,red)){.bg-add\/10{background-color:color-mix(in oklab,var(--color-add) 10%,transparent)}}.bg-bg{background-color:var(--color-bg)}.bg-bg\/80{background-color:#0a0b0ecc}@supports (color:color-mix(in lab,red,red)){.bg-bg\/80{background-color:color-mix(in oklab,var(--color-bg) 80%,transparent)}}.bg-black{background-color:var(--color-black)}.bg-black\/50{background-color:#00000080}@supports (color:color-mix(in lab,red,red)){.bg-black\/50{background-color:color-mix(in oklab,var(--color-black) 50%,transparent)}}.bg-black\/60{background-color:#0009}@supports (color:color-mix(in lab,red,red)){.bg-black\/60{background-color:color-mix(in oklab,var(--color-black) 60%,transparent)}}.bg-black\/75{background-color:#000000bf}@supports (color:color-mix(in lab,red,red)){.bg-black\/75{background-color:color-mix(in oklab,var(--color-black) 75%,transparent)}}.bg-del\/5{background-color:#ff6b6b0d}@supports (color:color-mix(in lab,red,red)){.bg-del\/5{background-color:color-mix(in oklab,var(--color-del) 5%,transparent)}}.bg-del\/10{background-color:#ff6b6b1a}@supports (color:color-mix(in lab,red,red)){.bg-del\/10{background-color:color-mix(in oklab,var(--color-del) 10%,transparent)}}.bg-idle\/10{background-color:#3ecf8e1a}@supports (color:color-mix(in lab,red,red)){.bg-idle\/10{background-color:color-mix(in oklab,var(--color-idle) 10%,transparent)}}.bg-surface{background-color:var(--color-surface)}.bg-surface-2{background-color:var(--color-surface-2)}.bg-surface\/60{background-color:#14161b99}@supports (color:color-mix(in lab,red,red)){.bg-surface\/60{background-color:color-mix(in oklab,var(--color-surface) 60%,transparent)}}.bg-surface\/95{background-color:#14161bf2}@supports (color:color-mix(in lab,red,red)){.bg-surface\/95{background-color:color-mix(in oklab,var(--color-surface) 95%,transparent)}}.bg-transparent{background-color:#0000}.bg-white{background-color:var(--color-white)}.bg-working{background-color:var(--color-working)}.bg-working\/10{background-color:#f5a6231a}@supports (color:color-mix(in lab,red,red)){.bg-working\/10{background-color:color-mix(in oklab,var(--color-working) 10%,transparent)}}.object-contain{object-fit:contain}.object-cover{object-fit:cover}.p-3{padding:calc(var(--spacing) * 3)}.p-4{padding:calc(var(--spacing) * 4)}.p-5{padding:calc(var(--spacing) * 5)}.p-6{padding:calc(var(--spacing) * 6)}.px-1{padding-inline:var(--spacing)}.px-1\.5{padding-inline:calc(var(--spacing) * 1.5)}.px-2{padding-inline:calc(var(--spacing) * 2)}.px-2\.5{padding-inline:calc(var(--spacing) * 2.5)}.px-3{padding-inline:calc(var(--spacing) * 3)}.px-3\.5{padding-inline:calc(var(--spacing) * 3.5)}.px-6{padding-inline:calc(var(--spacing) * 6)}.px-8{padding-inline:calc(var(--spacing) * 8)}.py-0\.5{padding-block:calc(var(--spacing) * .5)}.py-1{padding-block:var(--spacing)}.py-1\.5{padding-block:calc(var(--spacing) * 1.5)}.py-2{padding-block:calc(var(--spacing) * 2)}.py-2\.5{padding-block:calc(var(--spacing) * 2.5)}.py-3{padding-block:calc(var(--spacing) * 3)}.py-16{padding-block:calc(var(--spacing) * 16)}.pt-2{padding-top:calc(var(--spacing) * 2)}.pb-2{padding-bottom:calc(var(--spacing) * 2)}.pb-2\.5{padding-bottom:calc(var(--spacing) * 2.5)}.pl-2{padding-left:calc(var(--spacing) * 2)}.pl-3{padding-left:calc(var(--spacing) * 3)}.text-center{text-align:center}.font-mono{font-family:var(--font-mono)}.text-base{font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height))}.text-lg{font-size:var(--text-lg);line-height:var(--tw-leading,var(--text-lg--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xl{font-size:var(--text-xl);line-height:var(--tw-leading,var(--text-xl--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.text-\[10px\]{font-size:10px}.text-\[11\.5px\]{font-size:11.5px}.text-\[11px\]{font-size:11px}.text-\[12\.5px\]{font-size:12.5px}.text-\[12px\]{font-size:12px}.text-\[13px\]{font-size:13px}.text-\[14px\]{font-size:14px}.text-\[15px\]{font-size:15px}.leading-\[1\.5\]{--tw-leading:1.5;line-height:1.5}.leading-none{--tw-leading:1;line-height:1}.leading-relaxed{--tw-leading:var(--leading-relaxed);line-height:var(--leading-relaxed)}.leading-tight{--tw-leading:var(--leading-tight);line-height:var(--leading-tight)}.font-bold{--tw-font-weight:var(--font-weight-bold);font-weight:var(--font-weight-bold)}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-normal{--tw-font-weight:var(--font-weight-normal);font-weight:var(--font-weight-normal)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.tracking-wide{--tw-tracking:var(--tracking-wide);letter-spacing:var(--tracking-wide)}.\[overflow-wrap\:anywhere\]{overflow-wrap:anywhere}.whitespace-nowrap{white-space:nowrap}.whitespace-pre{white-space:pre}.whitespace-pre-wrap{white-space:pre-wrap}.text-accent{color:var(--color-accent)}.text-add{color:var(--color-add)}.text-black{color:var(--color-black)}.text-del{color:var(--color-del)}.text-del\/80{color:#ff6b6bcc}@supports (color:color-mix(in lab,red,red)){.text-del\/80{color:color-mix(in oklab,var(--color-del) 80%,transparent)}}.text-faint{color:var(--color-faint)}.text-idle{color:var(--color-idle)}.text-muted{color:var(--color-muted)}.text-text{color:var(--color-text)}.text-white{color:var(--color-white)}.text-working{color:var(--color-working)}.uppercase{text-transform:uppercase}.italic{font-style:italic}.underline-offset-2{text-underline-offset:2px}.\[color-scheme\:dark\]{color-scheme:dark}.opacity-60{opacity:.6}.shadow-\[0_0_0_100vmax_rgba\(0\,0\,0\,0\.5\)\]{--tw-shadow:0 0 0 100vmax var(--tw-shadow-color,#00000080);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-xl{--tw-shadow:0 20px 25px -5px var(--tw-shadow-color,#0000001a), 0 8px 10px -6px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.ring-2{--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)}.ring-surface{--tw-ring-color:var(--color-surface)}.filter{filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.backdrop-blur{--tw-backdrop-blur:blur(8px);-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,)}.backdrop-blur-xl{--tw-backdrop-blur:blur(var(--blur-xl));-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,)}.transition{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to,opacity,box-shadow,transform,translate,scale,rotate,filter,-webkit-backdrop-filter,backdrop-filter,display,content-visibility,overlay,pointer-events;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-transform{transition-property:transform,translate,scale,rotate;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.duration-200{--tw-duration:.2s;transition-duration:.2s}.ease-out{--tw-ease:var(--ease-out);transition-timing-function:var(--ease-out)}.outline-none{--tw-outline-style:none;outline-style:none}.select-none{-webkit-user-select:none;user-select:none}.group-open\:rotate-90:is(:where(.group):is([open],:popover-open,:open) *){rotate:90deg}.placeholder\:font-sans::placeholder{font-family:var(--font-sans)}.placeholder\:text-faint::placeholder{color:var(--color-faint)}.focus-within\:border-accent\/60:focus-within{border-color:#8b7dff99}@supports (color:color-mix(in lab,red,red)){.focus-within\:border-accent\/60:focus-within{border-color:color-mix(in oklab,var(--color-accent) 60%,transparent)}}@media(hover:hover){.hover\:underline:hover{text-decoration-line:underline}}.active\:scale-90:active{--tw-scale-x:90%;--tw-scale-y:90%;--tw-scale-z:90%;scale:var(--tw-scale-x) var(--tw-scale-y)}.active\:scale-95:active{--tw-scale-x:95%;--tw-scale-y:95%;--tw-scale-z:95%;scale:var(--tw-scale-x) var(--tw-scale-y)}.active\:bg-black\/70:active{background-color:#000000b3}@supports (color:color-mix(in lab,red,red)){.active\:bg-black\/70:active{background-color:color-mix(in oklab,var(--color-black) 70%,transparent)}}.active\:bg-surface:active{background-color:var(--color-surface)}.active\:bg-surface-2:active,.disabled\:bg-surface-2:disabled{background-color:var(--color-surface-2)}.disabled\:text-faint:disabled{color:var(--color-faint)}.disabled\:opacity-40:disabled{opacity:.4}.disabled\:opacity-50:disabled{opacity:.5}.disabled\:opacity-60:disabled{opacity:.6}@media(min-width:48rem){.md\:static{position:static}.md\:inset-0{inset:0}.md\:z-auto{z-index:auto}.md\:m-auto{margin:auto}.md\:block{display:block}.md\:hidden{display:none}.md\:h-fit{height:fit-content}.md\:w-72{width:calc(var(--spacing) * 72)}.md\:max-w-none{max-width:none}.md\:shrink-0{flex-shrink:0}.md\:translate-x-0{--tw-translate-x:0;translate:var(--tw-translate-x) var(--tw-translate-y)}.md\:rounded-3xl{border-radius:var(--radius-3xl)}.md\:transition-none{transition-property:none}}@media(min-width:64rem){.lg\:static{position:static}.lg\:z-auto{z-index:auto}.lg\:w-80{width:calc(var(--spacing) * 80)}.lg\:w-\[380px\]{width:380px}.lg\:shrink-0{flex-shrink:0}.lg\:border-l{border-left-style:var(--tw-border-style);border-left-width:1px}.lg\:border-border-soft{border-color:var(--color-border-soft)}}@media(min-width:80rem){.xl\:w-\[460px\]{width:460px}}.\[\&\:\:-webkit-details-marker\]\:hidden::-webkit-details-marker{display:none}}@keyframes pulse{50%{opacity:.5}}@keyframes fade-in{0%{opacity:0;transform:translateY(4px)}to{opacity:1;transform:none}}.fade-in{animation:.18s ease-out fade-in}.pt-safe{padding-top:max(env(safe-area-inset-top),.5rem)}.pb-safe{padding-bottom:max(env(safe-area-inset-bottom),.5rem)}@property --tw-translate-x{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-y{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-z{syntax:"*";inherits:false;initial-value:0}@property --tw-rotate-x{syntax:"*";inherits:false}@property --tw-rotate-y{syntax:"*";inherits:false}@property --tw-rotate-z{syntax:"*";inherits:false}@property --tw-skew-x{syntax:"*";inherits:false}@property --tw-skew-y{syntax:"*";inherits:false}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-leading{syntax:"*";inherits:false}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@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}@property --tw-blur{syntax:"*";inherits:false}@property --tw-brightness{syntax:"*";inherits:false}@property --tw-contrast{syntax:"*";inherits:false}@property --tw-grayscale{syntax:"*";inherits:false}@property --tw-hue-rotate{syntax:"*";inherits:false}@property --tw-invert{syntax:"*";inherits:false}@property --tw-opacity{syntax:"*";inherits:false}@property --tw-saturate{syntax:"*";inherits:false}@property --tw-sepia{syntax:"*";inherits:false}@property --tw-drop-shadow{syntax:"*";inherits:false}@property --tw-drop-shadow-color{syntax:"*";inherits:false}@property --tw-drop-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-drop-shadow-size{syntax:"*";inherits:false}@property --tw-backdrop-blur{syntax:"*";inherits:false}@property --tw-backdrop-brightness{syntax:"*";inherits:false}@property --tw-backdrop-contrast{syntax:"*";inherits:false}@property --tw-backdrop-grayscale{syntax:"*";inherits:false}@property --tw-backdrop-hue-rotate{syntax:"*";inherits:false}@property --tw-backdrop-invert{syntax:"*";inherits:false}@property --tw-backdrop-opacity{syntax:"*";inherits:false}@property --tw-backdrop-saturate{syntax:"*";inherits:false}@property --tw-backdrop-sepia{syntax:"*";inherits:false}@property --tw-duration{syntax:"*";inherits:false}@property --tw-ease{syntax:"*";inherits:false}@property --tw-scale-x{syntax:"*";inherits:false;initial-value:1}@property --tw-scale-y{syntax:"*";inherits:false;initial-value:1}@property --tw-scale-z{syntax:"*";inherits:false;initial-value:1}@keyframes spin{to{transform:rotate(360deg)}}
|
package/dist/index.html
CHANGED
|
@@ -11,8 +11,8 @@
|
|
|
11
11
|
<link rel="apple-touch-icon" href="/apple-touch-icon.png" />
|
|
12
12
|
<link rel="icon" type="image/svg+xml" href="/icon.svg" />
|
|
13
13
|
<title>Conductor Remote</title>
|
|
14
|
-
<script type="module" crossorigin src="/assets/index-
|
|
15
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
14
|
+
<script type="module" crossorigin src="/assets/index-BTmIqTa9.js"></script>
|
|
15
|
+
<link rel="stylesheet" crossorigin href="/assets/index-Dtq6pwjg.css">
|
|
16
16
|
<link rel="manifest" href="/manifest.webmanifest"></head>
|
|
17
17
|
<body>
|
|
18
18
|
<div id="root"></div>
|
package/dist/sw.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
if(!self.define){let e,i={};const n=(n,s)=>(n=new URL(n+".js",s).href,i[n]||new Promise(i=>{if("document"in self){const e=document.createElement("script");e.src=n,e.onload=i,document.head.appendChild(e)}else e=n,importScripts(n),i()}).then(()=>{let e=i[n];if(!e)throw new Error(`Module ${n} didn’t register its module`);return e}));self.define=(s,o)=>{const r=e||("document"in self?document.currentScript.src:"")||location.href;if(i[r])return;let
|
|
1
|
+
if(!self.define){let e,i={};const n=(n,s)=>(n=new URL(n+".js",s).href,i[n]||new Promise(i=>{if("document"in self){const e=document.createElement("script");e.src=n,e.onload=i,document.head.appendChild(e)}else e=n,importScripts(n),i()}).then(()=>{let e=i[n];if(!e)throw new Error(`Module ${n} didn’t register its module`);return e}));self.define=(s,o)=>{const r=e||("document"in self?document.currentScript.src:"")||location.href;if(i[r])return;let t={};const l=e=>n(e,r),c={module:{uri:r},exports:t,require:l};i[r]=Promise.all(s.map(e=>c[e]||l(e))).then(e=>(o(...e),t))}}define(["./workbox-9c191d2f"],function(e){"use strict";self.skipWaiting(),e.clientsClaim(),e.precacheAndRoute([{url:"index.html",revision:"f6f8ecb9ae2d872381f30361b5905ab7"},{url:"assets/workbox-window.prod.es5-BBnX5xw4.js",revision:null},{url:"assets/index-Dtq6pwjg.css",revision:null},{url:"assets/index-BTmIqTa9.js",revision:null},{url:"apple-touch-icon.png",revision:"2b9301416b880d45d4bb655f2600d1f2"},{url:"icon-192.png",revision:"c5e01ac58768627e18ee7b8b6a9239ef"},{url:"icon-512.png",revision:"a40638c55e310312457a621c9a0002c8"},{url:"icon-maskable-512.png",revision:"a40638c55e310312457a621c9a0002c8"},{url:"icon.svg",revision:"c1aee186821798733dd477e69a0ef243"},{url:"manifest.webmanifest",revision:"cf88fbc5755108a7fe0616fa160a8a15"}],{}),e.cleanupOutdatedCaches(),e.registerRoute(new e.NavigationRoute(e.createHandlerBoundToURL("/index.html"),{denylist:[/^\/api\//]}))});
|
package/dist-node/src/git.js
CHANGED
|
@@ -94,5 +94,25 @@ export async function workspaceDiff(worktree, base) {
|
|
|
94
94
|
const truncated = patch.length > MAX_PATCH_BYTES;
|
|
95
95
|
if (truncated)
|
|
96
96
|
patch = `${patch.slice(0, MAX_PATCH_BYTES)}\n\n… diff truncated (${patch.length} bytes) …`;
|
|
97
|
-
|
|
97
|
+
const { dirty, unpushed } = await localState(worktree);
|
|
98
|
+
return { base: ref, mergeBase, files, patch, truncated, dirty, unpushed };
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Local publish state of the worktree: does it have uncommitted changes, and are
|
|
102
|
+
* there commits not yet on its remote-tracking branch? Together these drive the
|
|
103
|
+
* bar's "Commit & push" action (you must land local work before a PR reflects it).
|
|
104
|
+
*/
|
|
105
|
+
async function localState(worktree) {
|
|
106
|
+
const status = await git(worktree, ['status', '--porcelain']).catch(() => '');
|
|
107
|
+
const dirty = status.trim() !== '';
|
|
108
|
+
let unpushed = false;
|
|
109
|
+
try {
|
|
110
|
+
// `@{upstream}` throws when no upstream is configured — then there's nothing to compare against.
|
|
111
|
+
const count = (await git(worktree, ['rev-list', '--count', '@{upstream}..HEAD'])).trim();
|
|
112
|
+
unpushed = Number(count) > 0;
|
|
113
|
+
}
|
|
114
|
+
catch {
|
|
115
|
+
unpushed = false;
|
|
116
|
+
}
|
|
117
|
+
return { dirty, unpushed };
|
|
98
118
|
}
|
package/dist-node/src/merge.js
CHANGED
|
@@ -1,115 +1,53 @@
|
|
|
1
1
|
import { execFile } from 'node:child_process';
|
|
2
2
|
import { promisify } from 'node:util';
|
|
3
3
|
const exec = promisify(execFile);
|
|
4
|
-
async function
|
|
5
|
-
const { stdout } = await exec('
|
|
6
|
-
encoding: 'utf8',
|
|
7
|
-
maxBuffer: 8 * 1024 * 1024,
|
|
8
|
-
timeout: 20_000
|
|
9
|
-
});
|
|
4
|
+
async function gh(root, args) {
|
|
5
|
+
const { stdout } = await exec('gh', args, { cwd: root, encoding: 'utf8', timeout: 30_000 });
|
|
10
6
|
return stdout;
|
|
11
7
|
}
|
|
12
|
-
/** Count of uncommitted (tracked + untracked) entries in a checkout. */
|
|
13
|
-
async function countDirty(cwd) {
|
|
14
|
-
const out = await git(cwd, ['status', '--porcelain']).catch(() => '');
|
|
15
|
-
return out.split('\n').filter(Boolean).length;
|
|
16
|
-
}
|
|
17
|
-
/** Commits on `branch` not reachable from `base`. */
|
|
18
|
-
async function countAhead(root, base, branch) {
|
|
19
|
-
const out = await git(root, ['rev-list', '--count', `${base}..${branch}`]).catch(() => '0');
|
|
20
|
-
const n = Number(out.trim());
|
|
21
|
-
return Number.isFinite(n) ? n : 0;
|
|
22
|
-
}
|
|
23
8
|
/**
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
9
|
+
* The repo's merge method, preferring squash (this project's convention), then a
|
|
10
|
+
* merge commit, then rebase — whichever GitHub allows for the repo. Defaults to
|
|
11
|
+
* squash if the query fails.
|
|
27
12
|
*/
|
|
28
|
-
async function
|
|
13
|
+
async function preferredMethod(root) {
|
|
29
14
|
try {
|
|
30
|
-
await
|
|
31
|
-
|
|
15
|
+
const out = await gh(root, ['repo', 'view', '--json', 'squashMergeAllowed,mergeCommitAllowed,rebaseMergeAllowed']);
|
|
16
|
+
const a = JSON.parse(out);
|
|
17
|
+
if (a.squashMergeAllowed)
|
|
18
|
+
return 'squash';
|
|
19
|
+
if (a.mergeCommitAllowed)
|
|
20
|
+
return 'merge';
|
|
21
|
+
if (a.rebaseMergeAllowed)
|
|
22
|
+
return 'rebase';
|
|
32
23
|
}
|
|
33
|
-
catch
|
|
34
|
-
|
|
24
|
+
catch {
|
|
25
|
+
// gh missing / not a GitHub repo → fall back; the merge call will surface any real error.
|
|
35
26
|
}
|
|
27
|
+
return 'squash';
|
|
36
28
|
}
|
|
37
29
|
/**
|
|
38
|
-
*
|
|
39
|
-
*
|
|
30
|
+
* Merge the workspace's open PR. `gh pr merge <branch>` resolves the PR from its
|
|
31
|
+
* head branch, so we need no PR number. We don't `--delete-branch` (the worktree
|
|
32
|
+
* still has it checked out; Conductor deletes it on archive, not on merge) and
|
|
33
|
+
* push nothing — GitHub performs the merge. Any GitHub-side refusal (checks,
|
|
34
|
+
* reviews, conflicts, draft) comes back as a loud error.
|
|
40
35
|
*/
|
|
41
|
-
export async function
|
|
36
|
+
export async function mergePr(ws) {
|
|
42
37
|
const branch = ws.branch ?? '';
|
|
43
|
-
const base = ws.baseBranch;
|
|
44
38
|
const root = ws.repo_root;
|
|
45
|
-
const block = (reason, detail, extra = {}) => ({
|
|
46
|
-
base,
|
|
47
|
-
branch,
|
|
48
|
-
canMerge: false,
|
|
49
|
-
reason,
|
|
50
|
-
detail,
|
|
51
|
-
ahead: 0,
|
|
52
|
-
uncommitted: 0,
|
|
53
|
-
...extra
|
|
54
|
-
});
|
|
55
39
|
if (!branch)
|
|
56
|
-
return
|
|
40
|
+
return { ok: false, branch, error: 'workspace has no branch' };
|
|
57
41
|
if (!root)
|
|
58
|
-
return
|
|
59
|
-
const
|
|
60
|
-
// The primary checkout must be on the base branch — we never switch Conductor's
|
|
61
|
-
// checkout out from under it; refuse and tell the user to check it out instead.
|
|
62
|
-
const head = (await git(root, ['rev-parse', '--abbrev-ref', 'HEAD']).catch(() => '')).trim();
|
|
63
|
-
if (head && head !== base)
|
|
64
|
-
return block('not-on-base', `the ${ws.repo_name ?? 'repo'} checkout is on '${head}', not '${base}'`, {
|
|
65
|
-
uncommitted,
|
|
66
|
-
headBranch: head
|
|
67
|
-
});
|
|
68
|
-
if (await countDirty(root))
|
|
69
|
-
return block('dirty-base', `the '${base}' checkout has uncommitted changes`, { uncommitted });
|
|
70
|
-
const ahead = await countAhead(root, base, branch);
|
|
71
|
-
if (ahead === 0)
|
|
72
|
-
return block('nothing-to-merge', `nothing new to merge into '${base}'`, { uncommitted });
|
|
73
|
-
if (await wouldConflict(root, base, branch))
|
|
74
|
-
return {
|
|
75
|
-
base,
|
|
76
|
-
branch,
|
|
77
|
-
canMerge: false,
|
|
78
|
-
reason: 'conflicts',
|
|
79
|
-
detail: `merging into '${base}' would conflict`,
|
|
80
|
-
ahead,
|
|
81
|
-
uncommitted
|
|
82
|
-
};
|
|
83
|
-
return { base, branch, canMerge: true, reason: 'ok', ahead, uncommitted };
|
|
84
|
-
}
|
|
85
|
-
/**
|
|
86
|
-
* Perform the merge, faithful to Conductor: a local `git merge --no-edit <branch>`
|
|
87
|
-
* into the base branch in the primary checkout. Re-runs the precheck as the
|
|
88
|
-
* authoritative gate (the PWA's copy is advisory and may be stale), and aborts a
|
|
89
|
-
* conflicting merge so the checkout is never left half-merged.
|
|
90
|
-
*/
|
|
91
|
-
export async function mergeWorkspace(ws) {
|
|
92
|
-
const pre = await mergePrecheck(ws);
|
|
93
|
-
if (!pre.canMerge)
|
|
94
|
-
return { ok: false, base: pre.base, branch: pre.branch, error: pre.detail, reason: pre.reason };
|
|
95
|
-
const root = ws.repo_root;
|
|
42
|
+
return { ok: false, branch, error: 'repo root unresolved' };
|
|
43
|
+
const method = await preferredMethod(root);
|
|
96
44
|
try {
|
|
97
|
-
|
|
98
|
-
return { ok: true,
|
|
45
|
+
await gh(root, ['pr', 'merge', branch, `--${method}`]);
|
|
46
|
+
return { ok: true, branch, method };
|
|
99
47
|
}
|
|
100
48
|
catch (err) {
|
|
101
49
|
const stderr = err.stderr;
|
|
102
50
|
const message = (stderr || (err instanceof Error ? err.message : String(err))).trim();
|
|
103
|
-
|
|
104
|
-
// Leave the primary checkout clean rather than stuck mid-merge.
|
|
105
|
-
if (conflicted)
|
|
106
|
-
await git(root, ['merge', '--abort']).catch(() => undefined);
|
|
107
|
-
return {
|
|
108
|
-
ok: false,
|
|
109
|
-
base: pre.base,
|
|
110
|
-
branch: pre.branch,
|
|
111
|
-
error: message,
|
|
112
|
-
reason: conflicted ? 'conflicts' : 'error'
|
|
113
|
-
};
|
|
51
|
+
return { ok: false, branch, method, error: message };
|
|
114
52
|
}
|
|
115
53
|
}
|
package/dist-node/src/pr.js
CHANGED
|
@@ -19,12 +19,16 @@ export function attachPrStatus(workspaces) {
|
|
|
19
19
|
const repos = new Set();
|
|
20
20
|
for (const w of workspaces) {
|
|
21
21
|
w.pr_status = null;
|
|
22
|
+
w.pr_number = null;
|
|
23
|
+
w.pr_url = null;
|
|
22
24
|
if (!w.branch || !w.repo_root)
|
|
23
25
|
continue;
|
|
24
26
|
repos.add(w.repo_root);
|
|
25
27
|
const pr = repoCache.get(w.repo_root)?.prs?.get(w.branch);
|
|
26
28
|
if (!pr)
|
|
27
29
|
continue;
|
|
30
|
+
w.pr_number = pr.number;
|
|
31
|
+
w.pr_url = pr.url;
|
|
28
32
|
if (pr.state === 'MERGED')
|
|
29
33
|
w.pr_status = 'merged';
|
|
30
34
|
else if (pr.state === 'OPEN') {
|
|
@@ -57,7 +61,7 @@ function refreshRepo(root) {
|
|
|
57
61
|
/** One `gh` call per repo → its PRs keyed by head branch. Never rejects. */
|
|
58
62
|
async function fetchRepoPRs(root) {
|
|
59
63
|
try {
|
|
60
|
-
const { stdout } = await exec('gh', ['pr', 'list', '--state', 'all', '--limit', '100', '--json', 'headRefName,state,isDraft,updatedAt'], { cwd: root, encoding: 'utf8', timeout: 15_000 });
|
|
64
|
+
const { stdout } = await exec('gh', ['pr', 'list', '--state', 'all', '--limit', '100', '--json', 'headRefName,number,url,state,isDraft,updatedAt'], { cwd: root, encoding: 'utf8', timeout: 15_000 });
|
|
61
65
|
const list = JSON.parse(stdout);
|
|
62
66
|
// Oldest first so the newest PR wins when a branch has been reused across PRs.
|
|
63
67
|
list.sort((a, b) => a.updatedAt.localeCompare(b.updatedAt));
|
package/dist-node/src/reads.js
CHANGED
|
@@ -90,19 +90,36 @@ export class Reads {
|
|
|
90
90
|
WHERE workspace_id = ? AND COALESCE(is_hidden, 0) = 0
|
|
91
91
|
ORDER BY created_at ASC`, [workspaceId]);
|
|
92
92
|
}
|
|
93
|
+
/** Session → worktree path, cached: it's stable for a session's lifetime and polled every tick. */
|
|
94
|
+
worktreeBySession = new Map();
|
|
95
|
+
sessionWorktree(sessionId) {
|
|
96
|
+
const cached = this.worktreeBySession.get(sessionId);
|
|
97
|
+
if (cached !== undefined)
|
|
98
|
+
return cached;
|
|
99
|
+
const rows = this.db.query(`SELECT w.directory_name, w.branch, r.name AS repo_name, r.root_path AS repo_root
|
|
100
|
+
FROM sessions s
|
|
101
|
+
JOIN workspaces w ON w.id = s.workspace_id
|
|
102
|
+
LEFT JOIN repos r ON r.id = w.repository_id
|
|
103
|
+
WHERE s.id = ? LIMIT 1`, [sessionId]);
|
|
104
|
+
const r = rows[0];
|
|
105
|
+
const worktree = r
|
|
106
|
+
? resolveWorktree(this.workspacesRoot, r.repo_name, r.directory_name, r.branch, r.repo_root)
|
|
107
|
+
: null;
|
|
108
|
+
this.worktreeBySession.set(sessionId, worktree);
|
|
109
|
+
return worktree;
|
|
110
|
+
}
|
|
93
111
|
/** Incremental transcript fetch. `afterRowid` is the cursor from a prior call. */
|
|
94
112
|
getMessages(sessionId, afterRowid = 0) {
|
|
95
113
|
const rows = this.db.query(`SELECT rowid, id, role, content, full_message, created_at, sent_at, queue_order
|
|
96
114
|
FROM session_messages
|
|
97
115
|
WHERE session_id = ? AND rowid > ?
|
|
98
116
|
ORDER BY rowid ASC`, [sessionId, afterRowid]);
|
|
117
|
+
const worktree = this.sessionWorktree(sessionId);
|
|
99
118
|
const entries = [];
|
|
100
119
|
let cursor = afterRowid;
|
|
101
120
|
for (const row of rows) {
|
|
102
121
|
cursor = row.rowid;
|
|
103
|
-
|
|
104
|
-
if (entry)
|
|
105
|
-
entries.push(entry);
|
|
122
|
+
entries.push(...parseMessage(row, worktree));
|
|
106
123
|
}
|
|
107
124
|
return { entries, cursor };
|
|
108
125
|
}
|
package/dist-node/src/server.js
CHANGED
|
@@ -7,7 +7,7 @@ import { startAutoUpdate, updateStatus } from "./autoupdate.js";
|
|
|
7
7
|
import { loadConfig } from "./config.js";
|
|
8
8
|
import { ConductorDb } from "./db.js";
|
|
9
9
|
import { workspaceDiff } from "./git.js";
|
|
10
|
-
import {
|
|
10
|
+
import { mergePr } from "./merge.js";
|
|
11
11
|
import { attachPrStatus } from "./pr.js";
|
|
12
12
|
import { Reads } from "./reads.js";
|
|
13
13
|
import { describeActuator, newChat, pickActuator } from "./writes.js";
|
|
@@ -82,9 +82,12 @@ function cacheControl(rel) {
|
|
|
82
82
|
}
|
|
83
83
|
function serveStatic(_req, res, pathname) {
|
|
84
84
|
const rel = pathname === '/' ? 'index.html' : pathname.replace(/^\/+/, '');
|
|
85
|
-
const filePath = path.
|
|
86
|
-
// Contain to publicDir.
|
|
87
|
-
|
|
85
|
+
const filePath = path.resolve(cfg.publicDir, rel);
|
|
86
|
+
// Contain to publicDir. The URL parser already collapses `..`/`%2e%2e` dot-segments, but don't lean on
|
|
87
|
+
// that: reject anything that resolves outside the dir (a bare `startsWith` would also admit a sibling
|
|
88
|
+
// like `dist-node/`). An empty relative (filePath === publicDir) falls through to the SPA shell below.
|
|
89
|
+
const within = path.relative(cfg.publicDir, filePath);
|
|
90
|
+
if (within.startsWith('..') || path.isAbsolute(within)) {
|
|
88
91
|
res.writeHead(403).end();
|
|
89
92
|
return;
|
|
90
93
|
}
|
|
@@ -173,16 +176,13 @@ const server = http.createServer(async (req, res) => {
|
|
|
173
176
|
const diff = await workspaceDiff(ws.worktree, ws.baseBranch);
|
|
174
177
|
return json(req, res, 200, diff);
|
|
175
178
|
}
|
|
176
|
-
//
|
|
177
|
-
// POST /api/workspaces/:id/merge — do it (local `git merge`, mirroring Conductor’s merge button)
|
|
179
|
+
// POST /api/workspaces/:id/merge — merge the workspace's open PR (mirrors Conductor's merge button)
|
|
178
180
|
m = pathname.match(/^\/api\/workspaces\/([^/]+)\/merge$/);
|
|
179
|
-
if (
|
|
181
|
+
if (req.method === 'POST' && m) {
|
|
180
182
|
const ws = reads.getWorkspace(decodeURIComponent(m[1]));
|
|
181
183
|
if (!ws)
|
|
182
184
|
return json(req, res, 404, { error: 'workspace not found' });
|
|
183
|
-
|
|
184
|
-
return json(req, res, 200, await mergePrecheck(ws));
|
|
185
|
-
const result = await mergeWorkspace(ws);
|
|
185
|
+
const result = await mergePr(ws);
|
|
186
186
|
return json(req, res, result.ok ? 200 : 409, result);
|
|
187
187
|
}
|
|
188
188
|
// GET /api/sessions/:id/messages?after=<rowid>
|
|
@@ -210,7 +210,9 @@ const server = http.createServer(async (req, res) => {
|
|
|
210
210
|
return json(req, res, 404, { error: 'no route', pathname });
|
|
211
211
|
}
|
|
212
212
|
catch (err) {
|
|
213
|
-
|
|
213
|
+
// Log the detail locally; don't reflect internals (paths, stack strings) back over the wire.
|
|
214
|
+
console.error(`[relay] ${req.method} ${pathname} failed:`, err);
|
|
215
|
+
return json(req, res, 500, { error: 'internal error' });
|
|
214
216
|
}
|
|
215
217
|
});
|
|
216
218
|
server.listen(cfg.port, cfg.host, () => {
|
|
@@ -1,36 +1,40 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Conductor stores each turn's raw Claude Code SDK stream JSON in
|
|
3
3
|
* `session_messages.content`. User-typed prompts are stored as plain text.
|
|
4
|
-
* This turns a row into
|
|
4
|
+
* This turns a row into compact, phone-renderable entries.
|
|
5
|
+
*
|
|
6
|
+
* Classification rule (verified against the whole DB): a JSON frame with
|
|
7
|
+
* `type:"user"` is ALWAYS tool plumbing — every one of them carries
|
|
8
|
+
* tool_result blocks, never the user's own words. Real prompts are the
|
|
9
|
+
* plain-text rows. Never render an SDK user frame as a user bubble.
|
|
5
10
|
*/
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
const inputStr = summarizeToolInput(b.input);
|
|
17
|
-
parts.push(inputStr ? `▸ ${b.name}: ${inputStr}` : `▸ ${b.name}`);
|
|
18
|
-
}
|
|
19
|
-
else if (b.type === 'tool_result') {
|
|
20
|
-
parts.push(summarizeToolResult(b.content));
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
return { text: parts.join('\n').trim(), tool };
|
|
11
|
+
const clip = (s, n) => (s.length > n ? `${s.slice(0, n)}…` : s);
|
|
12
|
+
const str = (v) => (typeof v === 'string' && v.trim() ? v.trim() : undefined);
|
|
13
|
+
/** Make tool details repo-relative: absolute worktree paths waste the whole line on a phone. */
|
|
14
|
+
function stripWorktree(s, worktree) {
|
|
15
|
+
if (!worktree)
|
|
16
|
+
return s;
|
|
17
|
+
// Conductor prefixes commands with `cd <worktree>` (newline- or &&-joined) — drop the whole clause.
|
|
18
|
+
if (s.startsWith(`cd ${worktree}`))
|
|
19
|
+
s = s.slice(`cd ${worktree}`.length).replace(/^\s*(&&)?\s*/, '');
|
|
20
|
+
return s.replaceAll(`${worktree}/`, '').replaceAll(worktree, '.');
|
|
24
21
|
}
|
|
25
|
-
|
|
22
|
+
/**
|
|
23
|
+
* Mirror Conductor's one-line tool rows: the human description as the title
|
|
24
|
+
* (Bash always has one), the primary input as a mono detail. Tools without a
|
|
25
|
+
* recognizable primary input get the title alone — dumping raw JSON is noise.
|
|
26
|
+
*/
|
|
27
|
+
function summarizeToolUse(name, input, worktree) {
|
|
26
28
|
if (!input || typeof input !== 'object')
|
|
27
|
-
return
|
|
29
|
+
return { text: name };
|
|
28
30
|
const o = input;
|
|
29
|
-
const
|
|
30
|
-
const
|
|
31
|
-
|
|
31
|
+
const text = str(o.description) ?? name;
|
|
32
|
+
const detail = str(o.command) ?? str(o.file_path) ?? str(o.path) ?? str(o.pattern) ?? str(o.url) ?? str(o.skill) ?? str(o.prompt);
|
|
33
|
+
if (!detail || detail === text)
|
|
34
|
+
return { text };
|
|
35
|
+
return { text, detail: clip(stripWorktree(detail, worktree).replace(/\s+/g, ' '), 160) };
|
|
32
36
|
}
|
|
33
|
-
function
|
|
37
|
+
function resultText(content) {
|
|
34
38
|
let s = '';
|
|
35
39
|
if (typeof content === 'string')
|
|
36
40
|
s = content;
|
|
@@ -39,45 +43,66 @@ function summarizeToolResult(content) {
|
|
|
39
43
|
.map(c => (c && typeof c === 'object' && 'text' in c ? String(c.text) : ''))
|
|
40
44
|
.join('');
|
|
41
45
|
}
|
|
42
|
-
|
|
43
|
-
if (!s)
|
|
44
|
-
return '↳ (result)';
|
|
45
|
-
return `↳ ${s.length > 200 ? `${s.slice(0, 200)}…` : s}`;
|
|
46
|
+
return clip(s.replace(/<\/?tool_use_error>/g, '').trim(), 400);
|
|
46
47
|
}
|
|
47
|
-
export function parseMessage(row) {
|
|
48
|
+
export function parseMessage(row, worktree = null) {
|
|
48
49
|
const queued = row.queue_order !== null && row.sent_at === null;
|
|
49
|
-
const base = {
|
|
50
|
+
const base = { rowid: row.rowid, ts: row.created_at, queued };
|
|
50
51
|
const content = row.content ?? '';
|
|
51
|
-
// Plain user prompt (not SDK JSON).
|
|
52
|
+
// Plain user prompt (not SDK JSON) — the only source of real user bubbles.
|
|
52
53
|
if (!content.startsWith('{')) {
|
|
53
54
|
if (!content.trim())
|
|
54
|
-
return
|
|
55
|
-
return { ...base, role: 'user', text: content };
|
|
55
|
+
return [];
|
|
56
|
+
return [{ ...base, id: row.id, role: 'user', text: content }];
|
|
56
57
|
}
|
|
57
58
|
let parsed;
|
|
58
59
|
try {
|
|
59
60
|
parsed = JSON.parse(content);
|
|
60
61
|
}
|
|
61
62
|
catch {
|
|
62
|
-
return { ...base, role: 'system', text: content
|
|
63
|
+
return [{ ...base, id: row.id, role: 'system', text: clip(content, 200) }];
|
|
63
64
|
}
|
|
64
|
-
//
|
|
65
|
-
if (parsed.type === 'system'
|
|
66
|
-
return
|
|
67
|
-
if (parsed.type === 'result')
|
|
68
|
-
return null;
|
|
65
|
+
// Bookkeeping frames: hooks, init, token accounting, end-of-turn results.
|
|
66
|
+
if (parsed.type === 'system' || parsed.type === 'result')
|
|
67
|
+
return [];
|
|
69
68
|
const blocks = parsed.message?.content;
|
|
70
|
-
if (Array.isArray(blocks)) {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
69
|
+
if (!Array.isArray(blocks)) {
|
|
70
|
+
if (parsed.type === 'user' || parsed.type === 'assistant')
|
|
71
|
+
return [];
|
|
72
|
+
// Unknown frame shape — keep a dim raw dump so Conductor drift stays visible.
|
|
73
|
+
return [{ ...base, id: row.id, role: 'system', text: clip(content, 200) }];
|
|
74
|
+
}
|
|
75
|
+
const entries = [];
|
|
76
|
+
const push = (e) => entries.push({ ...base, ...e, id: `${row.id}:${entries.length}` });
|
|
77
|
+
let pending = [];
|
|
78
|
+
const flush = () => {
|
|
79
|
+
const text = pending.join('\n').trim();
|
|
80
|
+
if (text)
|
|
81
|
+
push({ role: 'assistant', text });
|
|
82
|
+
pending = [];
|
|
83
|
+
};
|
|
84
|
+
for (const b of blocks) {
|
|
85
|
+
if (b.type === 'text' && typeof b.text === 'string') {
|
|
86
|
+
// Text inside an SDK user frame would be injected context, not the user.
|
|
87
|
+
if (parsed.type !== 'user')
|
|
88
|
+
pending.push(b.text);
|
|
89
|
+
}
|
|
90
|
+
else if (b.type === 'thinking') {
|
|
91
|
+
flush();
|
|
92
|
+
const text = str(b.thinking) ?? str(b.text);
|
|
93
|
+
if (text)
|
|
94
|
+
push({ role: 'thinking', text });
|
|
95
|
+
}
|
|
96
|
+
else if (b.type === 'tool_use' && typeof b.name === 'string') {
|
|
97
|
+
flush();
|
|
98
|
+
push({ role: 'tool', tool: b.name, ...summarizeToolUse(b.name, b.input, worktree) });
|
|
99
|
+
}
|
|
100
|
+
else if (b.type === 'tool_result' && b.is_error) {
|
|
101
|
+
// Successful results are noise on a phone; surface only failures.
|
|
102
|
+
flush();
|
|
103
|
+
push({ role: 'tool', error: true, text: resultText(b.content) || '(tool error)' });
|
|
104
|
+
}
|
|
79
105
|
}
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
return { ...base, role: 'system', text: content.slice(0, 200) };
|
|
106
|
+
flush();
|
|
107
|
+
return entries;
|
|
83
108
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "conductor-remote",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.18.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"packageManager": "yarn@4.15.0",
|
|
6
6
|
"description": "Phone control panel for local Conductor agents. Reads ride SQLite + git; prompts ride Conductor's own dispatch path.",
|