conductor-remote 1.69.0 → 1.71.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/README.md +5 -3
- package/dist/assets/index-27cwPLKx.js +47 -0
- package/dist/assets/index-Bk3X-Sz3.css +1 -0
- package/dist/index.html +2 -2
- package/dist/sw.js +1 -1
- package/dist-node/src/conductor.applescript +107 -0
- package/dist-node/src/mcp-tools.js +43 -4
- package/dist-node/src/routes.js +2 -0
- package/dist-node/src/server.js +65 -6
- package/dist-node/src/transcript.js +19 -0
- package/dist-node/src/writes.js +41 -0
- package/package.json +1 -1
- package/dist/assets/index-2nsPbh1M.js +0 -47
- package/dist/assets/index-CS-jxAPg.css +0 -1
|
@@ -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-space-y-reverse:0;--tw-border-style:solid;--tw-leading:initial;--tw-font-weight:initial;--tw-tracking:initial;--tw-ordinal:initial;--tw-slashed-zero:initial;--tw-numeric-figure:initial;--tw-numeric-spacing:initial;--tw-numeric-fraction: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-outline-style:solid;--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;--container-md:28rem;--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-snug:1.375;--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-attention:#facc15;--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:var(--app-height,100dvh)}html,body{overflow:hidden}@media(display-mode:standalone){html,body,#root{height:var(--app-height,100vh)}}html[data-standalone],html[data-standalone] body,html[data-standalone] #root{height:var(--app-height,100vh)}.app-height{height:var(--app-height,100dvh)}@media(display-mode:standalone){.app-height{height:var(--app-height,100vh)}}html[data-standalone] .app-height{height:var(--app-height,100vh)}@media(min-width:48rem){.app-height,html[data-standalone] .app-height{height:auto}}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}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)}.ctl{padding-inline:calc(var(--spacing) * 2);padding-block:var(--spacing);--tw-font-weight:var(--font-weight-medium);font-size:13px;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}.ctl-on{background-color:var(--color-surface-2);color:var(--color-text)}.ctl-staged{background-color:var(--color-accent-soft);color:var(--color-accent)}.dot{width:calc(var(--spacing) * 2.5);height:calc(var(--spacing) * 2.5);background-color:var(--color-faint);border-radius:3.40282e38px;flex-shrink:0}.dot-spinner{width:calc(var(--spacing) * 3.5);height:calc(var(--spacing) * 3.5);animation:var(--animate-spin);border-style:var(--tw-border-style);--spin-color:var(--color-working);border-width:2px;border-color:var(--spin-color);border-radius:3.40282e38px;flex-shrink:0}@supports (color:color-mix(in lab,red,red)){.dot-spinner{border-color:color-mix(in srgb,var(--spin-color) 30%,transparent)}}.dot-spinner{border-top-color:var(--spin-color);border-right-color:var(--spin-color)}.dot-idle{background:var(--color-idle)}.dot-done{background:var(--color-done)}.typing-dot{width:calc(var(--spacing) * 1.5);height:calc(var(--spacing) * 1.5);background-color:var(--color-muted);border-radius:3.40282e38px;animation:1.2s ease-in-out infinite typing}.typing-dot:nth-child(2){animation-delay:.15s}.typing-dot:nth-child(3){animation-delay:.3s}.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.6em}.md h2{font-size:1.4em}.md h3{font-size:1.2em}.md h4{font-size:1.1em}.md ul,.md ol{margin:.5em 0;padding-left:1.4em}.md ul{list-style:outside}.md ol{list-style:decimal}.md li{margin:.3em 0}.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:1.25em 0}.md img{border-radius:.6rem;max-width:100%;height:auto;margin:.5em 0;display:block}.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}.hljs-comment,.hljs-quote{color:var(--color-faint);font-style:italic}.hljs-keyword,.hljs-literal,.hljs-type,.hljs-built_in,.hljs-selector-tag,.hljs-doctag,.hljs-meta .hljs-keyword{color:var(--color-accent)}.hljs-string,.hljs-regexp,.hljs-char.escape_,.hljs-addition,.hljs-meta .hljs-string{color:var(--color-add)}.hljs-number,.hljs-symbol,.hljs-bullet,.hljs-link,.hljs-meta,.hljs-template-variable{color:var(--color-working)}.hljs-title,.hljs-title.class_,.hljs-title.function_,.hljs-name,.hljs-section,.hljs-selector-id,.hljs-selector-class{color:var(--color-done)}.hljs-attr,.hljs-attribute,.hljs-property,.hljs-variable,.hljs-params,.hljs-subst,.hljs-template-tag{color:var(--color-text)}.hljs-deletion{color:var(--color-del)}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:600}}@layer utilities{.pointer-events-auto{pointer-events:auto}.pointer-events-none{pointer-events:none}.invisible{visibility:hidden}.visible{visibility:visible}.sr-only{clip-path:inset(50%);white-space:nowrap;border-width:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.static{position:static}.sticky{position:sticky}.inset-0{inset:0}.inset-1{inset:var(--spacing)}.inset-x-0{inset-inline:0}.inset-y-0{inset-block:0}.top-0{top:0}.top-0\.5{top:calc(var(--spacing) * .5)}.top-1\.5{top:calc(var(--spacing) * 1.5)}.top-1\/2{top:50%}.top-full{top:100%}.-right-0\.5{right:calc(var(--spacing) * -.5)}.right-1{right:var(--spacing)}.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}.bottom-full{bottom:100%}.left-0{left:0}.left-0\.5{left:calc(var(--spacing) * .5)}.left-3{left:calc(var(--spacing) * 3)}.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}.col-span-3{grid-column:span 3/span 3}.m-0{margin:0}.mx-3{margin-inline:calc(var(--spacing) * 3)}.mx-auto{margin-inline:auto}.my-1\.5{margin-block:calc(var(--spacing) * 1.5)}.mt-0\.5{margin-top:calc(var(--spacing) * .5)}.mt-1{margin-top:var(--spacing)}.mt-1\.5{margin-top:calc(var(--spacing) * 1.5)}.mt-2{margin-top:calc(var(--spacing) * 2)}.mt-2\.5{margin-top:calc(var(--spacing) * 2.5)}.mt-3{margin-top:calc(var(--spacing) * 3)}.mt-4{margin-top:calc(var(--spacing) * 4)}.-mr-1{margin-right:calc(var(--spacing) * -1)}.-mr-2{margin-right:calc(var(--spacing) * -2)}.mr-1{margin-right:var(--spacing)}.mr-1\.5{margin-right:calc(var(--spacing) * 1.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)}.mb-3{margin-bottom:calc(var(--spacing) * 3)}.-ml-1{margin-left:calc(var(--spacing) * -1)}.ml-1{margin-left:var(--spacing)}.ml-1\.5{margin-left:calc(var(--spacing) * 1.5)}.ml-auto{margin-left:auto}.line-clamp-2{-webkit-line-clamp:2;-webkit-box-orient:vertical;display:-webkit-box;overflow:hidden}.line-clamp-4{-webkit-line-clamp:4;-webkit-box-orient:vertical;display:-webkit-box;overflow:hidden}.block{display:block}.flex{display:flex}.grid{display:grid}.hidden{display:none}.inline{display:inline}.inline-block{display:inline-block}.inline-flex{display:inline-flex}.table{display:table}.size-1\.5{width:calc(var(--spacing) * 1.5);height:calc(var(--spacing) * 1.5)}.size-2{width:calc(var(--spacing) * 2);height:calc(var(--spacing) * 2)}.size-2\.5{width:calc(var(--spacing) * 2.5);height:calc(var(--spacing) * 2.5)}.size-3{width:calc(var(--spacing) * 3);height:calc(var(--spacing) * 3)}.size-4{width:calc(var(--spacing) * 4);height:calc(var(--spacing) * 4)}.size-5{width:calc(var(--spacing) * 5);height:calc(var(--spacing) * 5)}.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-11{width:calc(var(--spacing) * 11);height:calc(var(--spacing) * 11)}.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-\[15px\]{width:15px;height:15px}.size-\[18px\]{width:18px;height:18px}.size-full{width:100%;height:100%}.h-4{height:calc(var(--spacing) * 4)}.h-6{height:calc(var(--spacing) * 6)}.h-7{height:calc(var(--spacing) * 7)}.h-8{height:calc(var(--spacing) * 8)}.h-12{height:calc(var(--spacing) * 12)}.h-\[15px\]{height:15px}.h-full{height:100%}.max-h-40{max-height:calc(var(--spacing) * 40)}.max-h-48{max-height:calc(var(--spacing) * 48)}.max-h-64{max-height:calc(var(--spacing) * 64)}.max-h-72{max-height:calc(var(--spacing) * 72)}.max-h-\[70\%\]{max-height:70%}.max-h-\[85dvh\]{max-height:85dvh}.min-h-0{min-height:0}.min-h-14{min-height:calc(var(--spacing) * 14)}.w-0\.5{width:calc(var(--spacing) * .5)}.w-1{width:var(--spacing)}.w-5{width:calc(var(--spacing) * 5)}.w-11{width:calc(var(--spacing) * 11)}.w-12{width:calc(var(--spacing) * 12)}.w-56{width:calc(var(--spacing) * 56)}.w-60{width:calc(var(--spacing) * 60)}.w-64{width:calc(var(--spacing) * 64)}.w-\[85\%\]{width:85%}.w-full{width:100%}.w-px{width:1px}.max-w-36{max-width:calc(var(--spacing) * 36)}.max-w-40{max-width:calc(var(--spacing) * 40)}.max-w-64{max-width:calc(var(--spacing) * 64)}.max-w-72{max-width:calc(var(--spacing) * 72)}.max-w-80{max-width:calc(var(--spacing) * 80)}.max-w-\[55vw\]{max-width:55vw}.max-w-\[70vw\]{max-width:70vw}.max-w-\[85\%\]{max-width:85%}.max-w-\[85vw\]{max-width:85vw}.max-w-\[92\%\]{max-width:92%}.max-w-full{max-width:100%}.max-w-md{max-width:var(--container-md)}.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)}.min-w-max{min-width:max-content}.flex-1{flex:1}.shrink-0{flex-shrink:0}.grow{flex-grow:1}.-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)}.translate-x-5{--tw-translate-x:calc(var(--spacing) * 5);translate:var(--tw-translate-x) var(--tw-translate-y)}.-translate-y-1\/2{--tw-translate-y: -50% ;translate:var(--tw-translate-x) var(--tw-translate-y)}.translate-y-0{--tw-translate-y:0;translate:var(--tw-translate-x) var(--tw-translate-y)}.translate-y-3{--tw-translate-y:calc(var(--spacing) * 3);translate:var(--tw-translate-x) var(--tw-translate-y)}.-rotate-90{rotate:-90deg}.rotate-180{rotate:180deg}.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-default{cursor:default}.cursor-pointer{cursor:pointer}.resize{resize:both}.resize-none{resize:none}.scrollbar-thin{scrollbar-width:thin}.list-none{list-style-type:none}.grid-cols-\[auto_1fr\]{grid-template-columns:auto 1fr}.grid-cols-\[minmax\(0\,1fr\)_auto_auto\]{grid-template-columns:minmax(0,1fr) auto auto}.grid-cols-subgrid{grid-template-columns:subgrid}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.place-items-center{place-items:center}.items-baseline{align-items:baseline}.items-center{align-items:center}.items-end{align-items:flex-end}.items-start{align-items:flex-start}.items-stretch{align-items:stretch}.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{gap:0}.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)}.gap-\[1\.5px\]{gap:1.5px}:where(.space-y-2>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 2) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 2) * calc(1 - var(--tw-space-y-reverse)))}.gap-x-2{column-gap:calc(var(--spacing) * 2)}.gap-y-1{row-gap:var(--spacing)}.self-start{align-self:flex-start}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.overflow-x-hidden{overflow-x:hidden}.overflow-y-auto{overflow-y:auto}.overscroll-contain{overscroll-behavior:contain}.rounded{border-radius:.25rem}.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-2xl{border-top-left-radius:var(--radius-2xl);border-top-right-radius:var(--radius-2xl)}.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-0{border-style:var(--tw-border-style);border-width:0}.border-2{border-style:var(--tw-border-style);border-width:2px}.border-x{border-inline-style:var(--tw-border-style);border-inline-width:1px}.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{border-left-style:var(--tw-border-style);border-left-width:1px}.border-l-2{border-left-style:var(--tw-border-style);border-left-width:2px}.border-dashed{--tw-border-style:dashed;border-style:dashed}.border-accent{border-color:var(--color-accent)}.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-del\/40{border-color:#ff6b6b66}@supports (color:color-mix(in lab,red,red)){.border-del\/40{border-color:color-mix(in oklab,var(--color-del) 40%,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)}.border-t-text{border-top-color:var(--color-text)}.border-l-accent{border-left-color:var(--color-accent)}.bg-accent{background-color:var(--color-accent)}.bg-accent-soft{background-color:var(--color-accent-soft)}.bg-accent-soft\/90{background-color:#2a2650e6}@supports (color:color-mix(in lab,red,red)){.bg-accent-soft\/90{background-color:color-mix(in oklab,var(--color-accent-soft) 90%,transparent)}}.bg-accent\/10{background-color:#8b7dff1a}@supports (color:color-mix(in lab,red,red)){.bg-accent\/10{background-color:color-mix(in oklab,var(--color-accent) 10%,transparent)}}.bg-accent\/25{background-color:#8b7dff40}@supports (color:color-mix(in lab,red,red)){.bg-accent\/25{background-color:color-mix(in oklab,var(--color-accent) 25%,transparent)}}.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-border-soft{background-color:var(--color-border-soft)}.bg-current{background-color:currentColor}.bg-del{background-color:var(--color-del)}.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-del\/15{background-color:#ff6b6b26}@supports (color:color-mix(in lab,red,red)){.bg-del\/15{background-color:color-mix(in oklab,var(--color-del) 15%,transparent)}}.bg-pr-merged\/10{background-color:#ac47ff1a}@supports (color:color-mix(in lab,red,red)){.bg-pr-merged\/10{background-color:color-mix(in oklab,var(--color-pr-merged) 10%,transparent)}}.bg-pr-merged\/15{background-color:#ac47ff26}@supports (color:color-mix(in lab,red,red)){.bg-pr-merged\/15{background-color:color-mix(in oklab,var(--color-pr-merged) 15%,transparent)}}.bg-surface{background-color:var(--color-surface)}.bg-surface-2{background-color:var(--color-surface-2)}.bg-surface-2\/60{background-color:#1b1e2699}@supports (color:color-mix(in lab,red,red)){.bg-surface-2\/60{background-color:color-mix(in oklab,var(--color-surface-2) 60%,transparent)}}.bg-surface\/40{background-color:#14161b66}@supports (color:color-mix(in lab,red,red)){.bg-surface\/40{background-color:color-mix(in oklab,var(--color-surface) 40%,transparent)}}.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\/70{background-color:#14161bb3}@supports (color:color-mix(in lab,red,red)){.bg-surface\/70{background-color:color-mix(in oklab,var(--color-surface) 70%,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-0{padding:0}.p-1\.5{padding:calc(var(--spacing) * 1.5)}.p-2{padding:calc(var(--spacing) * 2)}.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-0\.5{padding-inline:calc(var(--spacing) * .5)}.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-4{padding-inline:calc(var(--spacing) * 4)}.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)}.py-px{padding-block:1px}.pt-0\.5{padding-top:calc(var(--spacing) * .5)}.pt-1\.5{padding-top:calc(var(--spacing) * 1.5)}.pt-2{padding-top:calc(var(--spacing) * 2)}.pt-2\.5{padding-top:calc(var(--spacing) * 2.5)}.pr-1{padding-right:var(--spacing)}.pr-9{padding-right:calc(var(--spacing) * 9)}.pb-0\.5{padding-bottom:calc(var(--spacing) * .5)}.pb-1{padding-bottom:var(--spacing)}.pb-2{padding-bottom:calc(var(--spacing) * 2)}.pb-2\.5{padding-bottom:calc(var(--spacing) * 2.5)}.pb-3{padding-bottom:calc(var(--spacing) * 3)}.pl-1{padding-left:var(--spacing)}.pl-2{padding-left:calc(var(--spacing) * 2)}.pl-2\.5{padding-left:calc(var(--spacing) * 2.5)}.pl-3{padding-left:calc(var(--spacing) * 3)}.pl-8{padding-left:calc(var(--spacing) * 8)}.text-center{text-align:center}.text-left{text-align:left}.text-right{text-align:right}.align-baseline{vertical-align:baseline}.font-mono{font-family:var(--font-mono)}.font-sans{font-family:var(--font-sans)}.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-\[0\.9em\]{font-size:.9em}.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-\[13\.5px\]{font-size:13.5px}.text-\[13px\]{font-size:13px}.text-\[14px\]{font-size:14px}.text-\[15px\]{font-size:15px}.leading-6{--tw-leading:calc(var(--spacing) * 6);line-height:calc(var(--spacing) * 6)}.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-snug{--tw-leading:var(--leading-snug);line-height:var(--leading-snug)}.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}.break-words{overflow-wrap:break-word}.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-bg{color:var(--color-bg)}.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-muted{color:var(--color-muted)}.text-pr-merged{color:var(--color-pr-merged)}.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}.tabular-nums{--tw-numeric-spacing:tabular-nums;font-variant-numeric:var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,)}.underline{text-decoration-line:underline}.decoration-dotted{text-decoration-style:dotted}.underline-offset-2{text-underline-offset:2px}.\[color-scheme\:dark\]{color-scheme:dark}.opacity-0{opacity:0}.opacity-20{opacity:.2}.opacity-40{opacity:.4}.opacity-60{opacity:.6}.opacity-100{opacity:1}.shadow{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px 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)}.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-lg{--tw-shadow:0 10px 15px -3px var(--tw-shadow-color,#0000001a), 0 4px 6px -4px 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)}.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{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(1px + 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-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)}.shadow-black\/40{--tw-shadow-color:#0006}@supports (color:color-mix(in lab,red,red)){.shadow-black\/40{--tw-shadow-color:color-mix(in oklab, color-mix(in oklab, var(--color-black) 40%, transparent) var(--tw-shadow-alpha), transparent)}}.shadow-black\/60{--tw-shadow-color:#0009}@supports (color:color-mix(in lab,red,red)){.shadow-black\/60{--tw-shadow-color:color-mix(in oklab, color-mix(in oklab, var(--color-black) 60%, transparent) var(--tw-shadow-alpha), transparent)}}.ring-surface{--tw-ring-color:var(--color-surface)}.blur{--tw-blur:blur(8px);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,)}.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-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))}.transition-opacity{transition-property:opacity;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\/steps\:invisible:is(:where(.group\/steps):is([open],:popover-open,:open) *){visibility:hidden}.group-open\/steps\:rotate-90:is(:where(.group\/steps):is([open],:popover-open,:open) *),.group-open\/think\:rotate-90:is(:where(.group\/think):is([open],:popover-open,:open) *){rotate:90deg}.group-open\/tool\:invisible:is(:where(.group\/tool):is([open],:popover-open,:open) *){visibility:hidden}.group-open\/tool\:rotate-90:is(:where(.group\/tool):is([open],:popover-open,:open) *){rotate:90deg}.peer-focus-visible\:outline-2:is(:where(.peer):focus-visible~*){outline-style:var(--tw-outline-style);outline-width:2px}.peer-focus-visible\:outline-offset-2:is(:where(.peer):focus-visible~*){outline-offset:2px}.peer-focus-visible\:outline-accent:is(:where(.peer):focus-visible~*){outline-color:var(--color-accent)}.placeholder\:font-sans::placeholder{font-family:var(--font-sans)}.placeholder\:text-faint::placeholder{color:var(--color-faint)}@media(hover:hover){.hover\:underline:hover{text-decoration-line:underline}}.focus\:border-accent\/50:focus{border-color:#8b7dff80}@supports (color:color-mix(in lab,red,red)){.focus\:border-accent\/50:focus{border-color:color-mix(in oklab,var(--color-accent) 50%,transparent)}}.focus\:outline-none:focus{--tw-outline-style:none;outline-style:none}.focus-visible\:outline-2:focus-visible{outline-style:var(--tw-outline-style);outline-width:2px}.focus-visible\:-outline-offset-2:focus-visible{outline-offset:-2px}.focus-visible\:outline-accent:focus-visible{outline-color:var(--color-accent)}.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\:scale-\[0\.985\]:active{scale:.985}.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{background-color:var(--color-surface-2)}.active\:text-text:active{color:var(--color-text)}.active\:opacity-80:active{opacity:.8}.disabled\:bg-surface-2:disabled{background-color:var(--color-surface-2)}.disabled\:text-faint:disabled{color:var(--color-faint)}.disabled\:text-faint\/40:disabled{color:#5c616d66}@supports (color:color-mix(in lab,red,red)){.disabled\:text-faint\/40:disabled{color:color-mix(in oklab,var(--color-faint) 40%,transparent)}}.disabled\:opacity-40:disabled{opacity:.4}.disabled\:opacity-50:disabled{opacity:.5}.disabled\:opacity-60:disabled{opacity:.6}.has-\[textarea\:focus\]\:border-accent\/60:has(:is(textarea:focus)){border-color:#8b7dff99}@supports (color:color-mix(in lab,red,red)){.has-\[textarea\:focus\]\:border-accent\/60:has(:is(textarea:focus)){border-color:color-mix(in oklab,var(--color-accent) 60%,transparent)}}@media(prefers-reduced-motion:reduce){.motion-reduce\:transition-none{transition-property:none}}@media not all and (min-width:340px){.max-\[340px\]\:hidden{display:none}}@media(min-width:400px){.min-\[400px\]\:block{display:block}}@media(min-width:48rem){.md\:static{position:static}.md\:inset-0{inset:0}.md\:inset-6{inset:calc(var(--spacing) * 6)}.md\:inset-x-auto{inset-inline:auto}.md\:top-16{top:calc(var(--spacing) * 16)}.md\:left-1\/2{left:50%}.md\:z-auto{z-index:auto}.md\:m-auto{margin:auto}.md\:mb-6{margin-bottom:calc(var(--spacing) * 6)}.md\:block{display:block}.md\:hidden{display:none}.md\:h-fit{height:fit-content}.md\:max-h-\[70vh\]{max-height:70vh}.md\:w-72{width:calc(var(--spacing) * 72)}.md\:w-\[36rem\]{width:36rem}.md\:max-w-\[92vw\]{max-width:92vw}.md\:max-w-none{max-width:none}.md\:shrink-0{flex-shrink:0}.md\:-translate-x-1\/2{--tw-translate-x: -50% ;translate:var(--tw-translate-x) var(--tw-translate-y)}.md\:translate-x-0{--tw-translate-x:0;translate:var(--tw-translate-x) var(--tw-translate-y)}.md\:rounded-2xl{border-radius:var(--radius-2xl)}.md\:rounded-3xl{border-radius:var(--radius-3xl)}.md\:border{border-style:var(--tw-border-style);border-width:1px}.md\:border-border{border-color:var(--color-border)}.md\:border-border-soft{border-color:var(--color-border-soft)}.md\:shadow-2xl{--tw-shadow:0 25px 50px -12px var(--tw-shadow-color,#00000040);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.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 typing{0%,60%,to{opacity:.35;transform:none}30%{opacity:1;transform:translateY(-3px)}}@keyframes fade-in{0%{opacity:0;transform:translateY(4px)}to{opacity:1;transform:none}}.fade-in{animation:.18s ease-out fade-in}@media(prefers-reduced-motion:reduce){.fade-in{opacity:1;animation:none}.typing-dot{opacity:.6;animation:none}}.pt-safe{padding-top:max(env(safe-area-inset-top),.5rem)}.pb-safe{padding-bottom:max(env(safe-area-inset-bottom),.5rem)}html[data-keyboard] .pb-safe{padding-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-space-y-reverse{syntax:"*";inherits:false;initial-value:0}@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-ordinal{syntax:"*";inherits:false}@property --tw-slashed-zero{syntax:"*";inherits:false}@property --tw-numeric-figure{syntax:"*";inherits:false}@property --tw-numeric-spacing{syntax:"*";inherits:false}@property --tw-numeric-fraction{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-outline-style{syntax:"*";inherits:false;initial-value:solid}@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
|
@@ -13,8 +13,8 @@
|
|
|
13
13
|
<title>Conductor Remote</title>
|
|
14
14
|
<!-- Runs before the module bundle so it can catch a stale shell that fails to boot. -->
|
|
15
15
|
<script src="/self-heal.js"></script>
|
|
16
|
-
<script type="module" crossorigin src="/assets/index-
|
|
17
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
16
|
+
<script type="module" crossorigin src="/assets/index-27cwPLKx.js"></script>
|
|
17
|
+
<link rel="stylesheet" crossorigin href="/assets/index-Bk3X-Sz3.css">
|
|
18
18
|
<link rel="manifest" href="/manifest.webmanifest"></head>
|
|
19
19
|
<body>
|
|
20
20
|
<div id="root"></div>
|
package/dist/sw.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
if(!self.define){let e,s={};const i=(i,n)=>(i=new URL(i+".js",n).href,s[i]||new Promise(s=>{if("document"in self){const e=document.createElement("script");e.src=i,e.onload=s,document.head.appendChild(e)}else e=i,importScripts(i),s()}).then(()=>{let e=s[i];if(!e)throw new Error(`Module ${i} didn’t register its module`);return e}));self.define=(n,r)=>{const o=e||("document"in self?document.currentScript.src:"")||location.href;if(s[o])return;let
|
|
1
|
+
if(!self.define){let e,s={};const i=(i,n)=>(i=new URL(i+".js",n).href,s[i]||new Promise(s=>{if("document"in self){const e=document.createElement("script");e.src=i,e.onload=s,document.head.appendChild(e)}else e=i,importScripts(i),s()}).then(()=>{let e=s[i];if(!e)throw new Error(`Module ${i} didn’t register its module`);return e}));self.define=(n,r)=>{const o=e||("document"in self?document.currentScript.src:"")||location.href;if(s[o])return;let c={};const l=e=>i(e,o),t={module:{uri:o},exports:c,require:l};s[o]=Promise.all(n.map(e=>t[e]||l(e))).then(e=>(r(...e),c))}}define(["./workbox-9c191d2f"],function(e){"use strict";importScripts("/push-sw.js"),self.addEventListener("message",e=>{e.data&&"SKIP_WAITING"===e.data.type&&self.skipWaiting()}),e.clientsClaim(),e.precacheAndRoute([{url:"self-heal.js",revision:"49bd63adb25a09341f8d2610e8bd3c76"},{url:"push-sw.js",revision:"e1e682e2e5e88fa03b7808ae9db8e098"},{url:"index.html",revision:"69d94bf771c2ceb875f5b25b52dc1c4d"},{url:"assets/workbox-window.prod.es5-BBnX5xw4.js",revision:null},{url:"assets/index-Bk3X-Sz3.css",revision:null},{url:"assets/index-27cwPLKx.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\//]}))});
|
|
@@ -1241,6 +1241,113 @@ on cancelAgent()
|
|
|
1241
1241
|
delay 0.3
|
|
1242
1242
|
end cancelAgent
|
|
1243
1243
|
|
|
1244
|
+
on buttonsUnder(root, maxDepth)
|
|
1245
|
+
-- Every AXButton at or below root, level-order and bounded. Depth is the whole
|
|
1246
|
+
-- cost here: the transcript hangs off the same web area as anything Conductor
|
|
1247
|
+
-- portals into it, so each extra level multiplies the round trips and the sweep
|
|
1248
|
+
-- gets slower the longer the chat is. That is why the callers below pass the
|
|
1249
|
+
-- shallow depth that fits the thing they are looking for rather than one big cap.
|
|
1250
|
+
set acc to {}
|
|
1251
|
+
set level to {root}
|
|
1252
|
+
set depth to 0
|
|
1253
|
+
tell application "System Events" to tell process "Conductor"
|
|
1254
|
+
repeat while (count of level) > 0 and depth < maxDepth
|
|
1255
|
+
set nextLevel to {}
|
|
1256
|
+
repeat with entry in level
|
|
1257
|
+
set node to contents of entry
|
|
1258
|
+
try
|
|
1259
|
+
set acc to acc & (get UI elements of node whose role is "AXButton")
|
|
1260
|
+
set nextLevel to nextLevel & (get UI elements of node)
|
|
1261
|
+
end try
|
|
1262
|
+
end repeat
|
|
1263
|
+
set level to nextLevel
|
|
1264
|
+
set depth to depth + 1
|
|
1265
|
+
end repeat
|
|
1266
|
+
end tell
|
|
1267
|
+
return acc
|
|
1268
|
+
end buttonsUnder
|
|
1269
|
+
|
|
1270
|
+
on archiveButtons()
|
|
1271
|
+
-- Both places Conductor could be drawing its archive confirmation, each at the
|
|
1272
|
+
-- depth that shape actually sits at. A real sheet hangs off the window a level or
|
|
1273
|
+
-- two down; an in-webview dialog is a portal near the top of the web area, which
|
|
1274
|
+
-- is where the sidebar row's menu turns up at depth 4 (pressStatusMenu). Sweeping
|
|
1275
|
+
-- one deep cap from the window instead would reach neither any better and would
|
|
1276
|
+
-- walk the transcript to get there.
|
|
1277
|
+
my requireWindow()
|
|
1278
|
+
set fromWindow to {}
|
|
1279
|
+
tell application "System Events" to tell process "Conductor"
|
|
1280
|
+
set fromWindow to my buttonsUnder(window 1, 4)
|
|
1281
|
+
end tell
|
|
1282
|
+
return fromWindow & (my buttonsUnder(my webArea(), 4))
|
|
1283
|
+
end archiveButtons
|
|
1284
|
+
|
|
1285
|
+
on archiveConfirmButton()
|
|
1286
|
+
-- Conductor asks before archiving a workspace whose agents are still running:
|
|
1287
|
+
-- "Archive workspace?" over Cancel and "Stop agents and archive". Identified by
|
|
1288
|
+
-- the *pair* - a button naming the verb, with a Cancel somewhere beside it -
|
|
1289
|
+
-- rather than by the archive one alone, which is the same rule waitForMenuWith
|
|
1290
|
+
-- follows: press nothing that has not proved which thing it belongs to.
|
|
1291
|
+
-- "Unarchive" is excluded by name, since AppleScript's contains ignores case
|
|
1292
|
+
-- and would otherwise read that as a confirmation of this.
|
|
1293
|
+
set found to missing value
|
|
1294
|
+
set sawCancel to false
|
|
1295
|
+
repeat with entry in my archiveButtons()
|
|
1296
|
+
set node to contents of entry
|
|
1297
|
+
set label to my axName(node)
|
|
1298
|
+
if label is "Cancel" then set sawCancel to true
|
|
1299
|
+
if label contains "archive" and label does not contain "unarchive" then set found to node
|
|
1300
|
+
end repeat
|
|
1301
|
+
if sawCancel then return found
|
|
1302
|
+
return missing value
|
|
1303
|
+
end archiveConfirmButton
|
|
1304
|
+
|
|
1305
|
+
on archiveWorkspace()
|
|
1306
|
+
-- Put this workspace away: Conductor's own "Archive workspace", Command-Shift-A.
|
|
1307
|
+
-- A keystroke on purpose, like cancelAgent - the sidebar row menu carries an
|
|
1308
|
+
-- Archive item, but reaching it costs a sidebar scan plus two menu waits, and
|
|
1309
|
+
-- this chord acts on the workspace the pane is already showing.
|
|
1310
|
+
--
|
|
1311
|
+
-- Which is also the danger: it archives whatever is on screen, so the pane
|
|
1312
|
+
-- assertion is the whole guard. Archiving the wrong workspace deletes a worktree
|
|
1313
|
+
-- and kills a turn that was running fine, so a pane that cannot be checked is
|
|
1314
|
+
-- refused rather than aimed at (writes.ts requires the branch for that reason).
|
|
1315
|
+
--
|
|
1316
|
+
-- Command-L ("Focus chat input") first, exactly as cancelAgent does: the chord
|
|
1317
|
+
-- lands wherever focus is, and a focused terminal panel swallows it.
|
|
1318
|
+
set strips to my tabGroups()
|
|
1319
|
+
if (count of strips) is 0 then error "couldn't find the chat pane to archive from"
|
|
1320
|
+
my assertWorkspace(item 1 of strips)
|
|
1321
|
+
tell application "System Events"
|
|
1322
|
+
keystroke "l" using {command down}
|
|
1323
|
+
delay 0.2
|
|
1324
|
+
keystroke "a" using {command down, shift down}
|
|
1325
|
+
end tell
|
|
1326
|
+
-- A workspace with agents still working draws a confirmation; an idle one is
|
|
1327
|
+
-- archived by the chord alone. Both are live, so this waits a bounded moment for
|
|
1328
|
+
-- the dialog and treats its absence as the second case - the DB is the receipt
|
|
1329
|
+
-- either way (server.ts watches for state 'archived'), so nothing here has to
|
|
1330
|
+
-- decide whether the archive landed.
|
|
1331
|
+
set confirmEl to missing value
|
|
1332
|
+
repeat with attempt from 1 to 5
|
|
1333
|
+
delay 0.3
|
|
1334
|
+
set confirmEl to my archiveConfirmButton()
|
|
1335
|
+
if confirmEl is not missing value then exit repeat
|
|
1336
|
+
end repeat
|
|
1337
|
+
if confirmEl is missing value then return "archived"
|
|
1338
|
+
-- The caller has to have opted into the damage before we press this: stopping
|
|
1339
|
+
-- other people's agents is not something to infer from a tap that said Archive.
|
|
1340
|
+
if (system attribute "RELAY_ARCHIVE_AGENTS") is not "1" then
|
|
1341
|
+
tell application "System Events" to key code 53
|
|
1342
|
+
error "agents are still running in this workspace - archiving would stop them"
|
|
1343
|
+
end if
|
|
1344
|
+
tell application "System Events" to tell process "Conductor"
|
|
1345
|
+
perform action "AXPress" of confirmEl
|
|
1346
|
+
end tell
|
|
1347
|
+
delay 0.5
|
|
1348
|
+
return "archived"
|
|
1349
|
+
end archiveWorkspace
|
|
1350
|
+
|
|
1244
1351
|
on composerControls()
|
|
1245
1352
|
set strips to my tabGroups()
|
|
1246
1353
|
if (count of strips) is 0 then error "couldn't find the composer"
|
|
@@ -31,7 +31,7 @@ import { HIT_CLOSE, HIT_OPEN, isToolResult, workspaceTitle } from "./shared.js";
|
|
|
31
31
|
/** Versions we know how to speak. The client's choice wins when we know it. */
|
|
32
32
|
export const PROTOCOL_VERSIONS = ['2025-06-18', '2025-03-26', '2024-11-05'];
|
|
33
33
|
export const SERVER_INFO = { name: 'conductor-remote', version: '1' };
|
|
34
|
-
export const INSTRUCTIONS = 'Drives local Conductor agents through the conductor-remote relay. search_chats and read_chat reach archived workspaces, which is where most finished work lives. create_workspace opens its workspace link without direct UI control; requested agent settings and the first prompt are applied later through Conductor’s UI. dismiss_prompt, keep_awake and relay_logs touch no UI. send_prompt, split_chat, stop_turn, set_agent_options, a live list_models call and
|
|
34
|
+
export const INSTRUCTIONS = 'Drives local Conductor agents through the conductor-remote relay. search_chats and read_chat reach archived workspaces, which is where most finished work lives. create_workspace opens its workspace link without direct UI control; requested agent settings and the first prompt are applied later through Conductor’s UI. dismiss_prompt, keep_awake and relay_logs touch no UI. send_prompt, split_chat, stop_turn, set_agent_options, a live list_models call, set_workspace_status and archive_workspace drive the real Mac UI and steal focus for a few seconds — confirm with the user before using them on a chat they did not name. archive_workspace also deletes the worktree and stops whatever is running there.';
|
|
35
35
|
/** Reads are quick; a UI write is measured in tens of seconds (writes.ts ▸ SEND_ATTEMPT_MS). */
|
|
36
36
|
export const READ_TIMEOUT_MS = 10_000;
|
|
37
37
|
export const WRITE_TIMEOUT_MS = 75_000;
|
|
@@ -436,7 +436,7 @@ export function createTools(call) {
|
|
|
436
436
|
},
|
|
437
437
|
{
|
|
438
438
|
name: 'split_chat',
|
|
439
|
-
description: 'Move a tangent out of a chat: copy that chat into a fresh tab beside it, as a Conductor attachment, and ask the new agent your question there. Use it when a conversation has grown a second topic — a running agent steered mid-turn ends up holding three threads at once, which reads badly for everyone afterwards. The copy carries the prose and the reasoning, not the tool calls, so the new agent knows what was said and decided but not every file that was read. This DRIVES THE REAL UI twice (a new tab, then the send) and steals focus for a few seconds. To split the chat you are in, find its session_id with list_chats on your own workspace.',
|
|
439
|
+
description: 'Move a tangent out of a chat: copy that chat into a fresh tab beside it, as a Conductor attachment, and ask the new agent your question there. Use it when a conversation has grown a second topic — a running agent steered mid-turn ends up holding three threads at once, which reads badly for everyone afterwards. The copy carries the prose and the reasoning, not the tool calls, so the new agent knows what was said and decided but not every file that was read. It runs to the end of the chat unless through names an earlier message to stop at, which is how you branch from before the conversation turned. This DRIVES THE REAL UI twice (a new tab, then the send) and steals focus for a few seconds. To split the chat you are in, find its session_id with list_chats on your own workspace.',
|
|
440
440
|
inputSchema: {
|
|
441
441
|
type: 'object',
|
|
442
442
|
properties: {
|
|
@@ -450,6 +450,10 @@ export function createTools(call) {
|
|
|
450
450
|
include_tools: {
|
|
451
451
|
type: 'boolean',
|
|
452
452
|
description: 'Carry tool calls across as one line each (default false — mostly noise, and most of the bytes).'
|
|
453
|
+
},
|
|
454
|
+
through: {
|
|
455
|
+
type: 'string',
|
|
456
|
+
description: 'Stop the copy at this message, it included — a cursor from read_chat or search_chats. Default: the whole chat.'
|
|
453
457
|
}
|
|
454
458
|
},
|
|
455
459
|
required: ['session_id', 'prompt']
|
|
@@ -457,13 +461,19 @@ export function createTools(call) {
|
|
|
457
461
|
run: async (args) => {
|
|
458
462
|
const sessionId = need(args, 'session_id');
|
|
459
463
|
const prompt = need(args, 'prompt');
|
|
464
|
+
const through = str(args.through);
|
|
465
|
+
const throughRowid = through ? parseChatCursor(through) : null;
|
|
466
|
+
if (through && throughRowid === null) {
|
|
467
|
+
throw new Error('through must be a cursor returned by read_chat or search_chats');
|
|
468
|
+
}
|
|
460
469
|
const split = await call(routes.splitChat.path(sessionId), {
|
|
461
470
|
method: routes.splitChat.method,
|
|
462
471
|
body: {
|
|
463
472
|
prompt,
|
|
464
473
|
workspaceId: str(args.workspace_id),
|
|
465
474
|
includeThinking: args.include_thinking !== false,
|
|
466
|
-
includeTools: args.include_tools === true
|
|
475
|
+
includeTools: args.include_tools === true,
|
|
476
|
+
throughRowid: throughRowid ?? undefined
|
|
467
477
|
},
|
|
468
478
|
timeoutMs: WRITE_TIMEOUT_MS
|
|
469
479
|
});
|
|
@@ -474,7 +484,8 @@ export function createTools(call) {
|
|
|
474
484
|
// like a complete one to whoever gets it next.
|
|
475
485
|
const cut = [
|
|
476
486
|
file.elided.tools ? plural(file.elided.tools, 'tool call') : '',
|
|
477
|
-
file.elided.thinking ? plural(file.elided.thinking, 'thinking block') : ''
|
|
487
|
+
file.elided.thinking ? plural(file.elided.thinking, 'thinking block') : '',
|
|
488
|
+
file.elided.later ? plural(file.elided.later, 'entry after the cut', 'entries after the cut') : ''
|
|
478
489
|
].filter(Boolean);
|
|
479
490
|
const lines = [
|
|
480
491
|
`copied ${plural(file.kept, 'entry', 'entries')} (${Math.round(file.bytes / 1024)}kB) to ${file.path}${cut.length ? `, without ${cut.join(' or ')}` : ''}`
|
|
@@ -635,6 +646,34 @@ export function createTools(call) {
|
|
|
635
646
|
return `status set to ${status}`;
|
|
636
647
|
}
|
|
637
648
|
},
|
|
649
|
+
{
|
|
650
|
+
name: 'archive_workspace',
|
|
651
|
+
description: 'Archive a workspace — Conductor’s own ⌘⇧A, which deletes its worktree and takes any agent still working in it down with it. The chat survives archiving and stays readable through search_chats and read_chat. Drives the real UI: it focuses the workspace on the Mac first, so confirm with the user before archiving one they did not name. A workspace with an agent working is refused unless stop_agents is true.',
|
|
652
|
+
inputSchema: {
|
|
653
|
+
type: 'object',
|
|
654
|
+
properties: {
|
|
655
|
+
workspace_id: { type: 'string' },
|
|
656
|
+
stop_agents: {
|
|
657
|
+
type: 'boolean',
|
|
658
|
+
description: 'Archive even though agents are still working here, ending their turns.'
|
|
659
|
+
}
|
|
660
|
+
},
|
|
661
|
+
required: ['workspace_id']
|
|
662
|
+
},
|
|
663
|
+
run: async (args) => {
|
|
664
|
+
const id = need(args, 'workspace_id');
|
|
665
|
+
const data = await call(routes.archiveWorkspace.path(id), {
|
|
666
|
+
method: routes.archiveWorkspace.method,
|
|
667
|
+
body: { stopAgents: args.stop_agents === true },
|
|
668
|
+
timeoutMs: WRITE_TIMEOUT_MS
|
|
669
|
+
});
|
|
670
|
+
if (!data.ok)
|
|
671
|
+
throw new Error(data.error ?? 'the archive did not land');
|
|
672
|
+
if (data.alreadyArchived)
|
|
673
|
+
return 'already archived';
|
|
674
|
+
return `archived ${data.workspace ? workspaceTitle(data.workspace) : id}`;
|
|
675
|
+
}
|
|
676
|
+
},
|
|
638
677
|
{
|
|
639
678
|
name: 'dismiss_prompt',
|
|
640
679
|
description: 'Throw away a prompt the relay is still holding — a new workspace’s first prompt waiting on setup, or one parked behind a locked Mac. Touches no UI. list_workspaces shows these; a failed one stays visible until it is dismissed, on purpose. Pass session_id for a parked prompt, workspace_id for a first prompt.',
|
package/dist-node/src/routes.js
CHANGED
|
@@ -85,6 +85,8 @@ export const routes = {
|
|
|
85
85
|
workspaceFiles: param('GET', '/api/workspaces/:workspaceId/files'),
|
|
86
86
|
merge: param('POST', '/api/workspaces/:workspaceId/merge'),
|
|
87
87
|
workspaceStatus: param('POST', '/api/workspaces/:workspaceId/status'),
|
|
88
|
+
/** Put the workspace away (Conductor's ⌘⇧A) — the one write that deletes a worktree. */
|
|
89
|
+
archiveWorkspace: param('POST', '/api/workspaces/:workspaceId/archive'),
|
|
88
90
|
/** Read, start/forward, or stop a local workspace's selected Conductor Run task. */
|
|
89
91
|
devServer: param('GET', '/api/workspaces/:workspaceId/dev-server'),
|
|
90
92
|
startDevServer: param('POST', '/api/workspaces/:workspaceId/dev-server'),
|
package/dist-node/src/server.js
CHANGED
|
@@ -30,9 +30,9 @@ import { readSettings, writeSettings } from "./settings.js";
|
|
|
30
30
|
import { withoutWindowEvidence } from "./shared.js";
|
|
31
31
|
import { discardStagedAttachment, materializeStagedAttachments, stageAttachment, stagedAttachments } from "./staged-attachments.js";
|
|
32
32
|
import { driftWarningLines, readExposeMode, tailscaleBin } from "./tailscale.js";
|
|
33
|
-
import { renderTranscript } from "./transcript.js";
|
|
33
|
+
import { renderTranscript, transcriptThrough } from "./transcript.js";
|
|
34
34
|
import { autoJoinHotspotMode, currentSsid, looksLikeHotspot, preferredNetworks } from "./wifi.js";
|
|
35
|
-
import { createWorkspace, describeActuator, EFFORT_LABELS, listAgentModels, lockBlocked, newChat, pickActuator, retryWontHelp, screenLocked, sendNeverStarted, setAgentOptions, setRestartGuard, setWorkspaceStatus, stopTurn, UiBusyError, uiQueueDepth, WORKSPACE_STATUS_LABELS, withUiPriority } from "./writes.js";
|
|
35
|
+
import { archiveWorkspace, createWorkspace, describeActuator, EFFORT_LABELS, listAgentModels, lockBlocked, newChat, pickActuator, retryWontHelp, screenLocked, sendNeverStarted, setAgentOptions, setRestartGuard, setWorkspaceStatus, stopTurn, UiBusyError, uiQueueDepth, WORKSPACE_STATUS_LABELS, withUiPriority } from "./writes.js";
|
|
36
36
|
// Before anything that logs: from here on every console line is also kept in memory for
|
|
37
37
|
// `GET /api/logs`, so the phone can read why a send failed without ssh-ing into the Mac.
|
|
38
38
|
installLogCapture();
|
|
@@ -1259,6 +1259,51 @@ const server = http.createServer(async (req, res) => {
|
|
|
1259
1259
|
}
|
|
1260
1260
|
return json(req, res, 200, { ok: true, workspace: reads.getWorkspace(workspaceId) });
|
|
1261
1261
|
}
|
|
1262
|
+
// POST /api/workspaces/:id/archive { stopAgents? } — put the workspace away, the way
|
|
1263
|
+
// Conductor's own ⌘⇧A does. The one write here that destroys something: the worktree
|
|
1264
|
+
// goes, and any agent still working goes with it. So the running agents are counted
|
|
1265
|
+
// from the DB *before* the UI is touched and refused unless the caller has said it
|
|
1266
|
+
// meant that — the phone's own dialog then says so in the same words Conductor's does.
|
|
1267
|
+
const archiveOf = routeParam(routes.archiveWorkspace, req.method, pathname);
|
|
1268
|
+
if (archiveOf) {
|
|
1269
|
+
const workspaceId = archiveOf;
|
|
1270
|
+
const body = JSON.parse((await readBody(req)) || '{}');
|
|
1271
|
+
const ws = reads.getWorkspace(workspaceId);
|
|
1272
|
+
if (!ws) {
|
|
1273
|
+
// Already archived is the answer the caller asked for, not a 404. A phone whose
|
|
1274
|
+
// answer went missing retries, and `getWorkspace` only sees the live sidebar.
|
|
1275
|
+
const known = reads.getAnyWorkspace(workspaceId);
|
|
1276
|
+
if (known?.archived)
|
|
1277
|
+
return json(req, res, 200, { ok: true, alreadyArchived: true, workspace: known });
|
|
1278
|
+
return json(req, res, 404, { error: 'workspace not found' });
|
|
1279
|
+
}
|
|
1280
|
+
const working = reads.listSessions(ws.id).filter(s => s.status === 'working').length;
|
|
1281
|
+
if (working > 0 && body.stopAgents !== true) {
|
|
1282
|
+
return json(req, res, 409, {
|
|
1283
|
+
ok: false,
|
|
1284
|
+
agentsRunning: true,
|
|
1285
|
+
error: `${working} agent${working === 1 ? ' is' : 's are'} still working here. Archiving stops them.`
|
|
1286
|
+
});
|
|
1287
|
+
}
|
|
1288
|
+
const result = await archiveWorkspace(ws, body.stopAgents === true);
|
|
1289
|
+
if (!result.ok)
|
|
1290
|
+
return json(req, res, 502, result);
|
|
1291
|
+
// `state` becoming 'archived' is the receipt, like the status change above: the
|
|
1292
|
+
// keystroke is fire-and-forget and Conductor writes the row a beat later.
|
|
1293
|
+
let archived = reads.getAnyWorkspace(workspaceId);
|
|
1294
|
+
for (let i = 0; i < 20 && !archived?.archived; i++) {
|
|
1295
|
+
await sleep(300);
|
|
1296
|
+
archived = reads.getAnyWorkspace(workspaceId);
|
|
1297
|
+
}
|
|
1298
|
+
if (!archived?.archived) {
|
|
1299
|
+
return json(req, res, 502, {
|
|
1300
|
+
ok: false,
|
|
1301
|
+
strategy: result.strategy,
|
|
1302
|
+
error: 'Conductor took the archive but the workspace is still in the sidebar. Try again, or archive it on your Mac.'
|
|
1303
|
+
});
|
|
1304
|
+
}
|
|
1305
|
+
return json(req, res, 200, { ok: true, strategy: result.strategy, workspace: archived });
|
|
1306
|
+
}
|
|
1262
1307
|
// The selected Conductor Run task plus a tailnet-only HTTPS forward for
|
|
1263
1308
|
// its allocated port. Reads never touch Conductor's UI; start/stop use the
|
|
1264
1309
|
// same Accessibility lock and target assertion as every other UI write.
|
|
@@ -1494,7 +1539,7 @@ const server = http.createServer(async (req, res) => {
|
|
|
1494
1539
|
});
|
|
1495
1540
|
return json(req, res, answer.status, answer.body);
|
|
1496
1541
|
}
|
|
1497
|
-
// POST /api/sessions/:id/split { prompt?, includeThinking?, includeTools? }
|
|
1542
|
+
// POST /api/sessions/:id/split { prompt?, includeThinking?, includeTools?, throughRowid? }
|
|
1498
1543
|
//
|
|
1499
1544
|
// Conductor's own "Fork to new tab" resumes the agent's real session. This copies
|
|
1500
1545
|
// the conversation instead, as a Conductor attachment, which is the cut that
|
|
@@ -1527,7 +1572,15 @@ const server = http.createServer(async (req, res) => {
|
|
|
1527
1572
|
return json(req, res, 404, { error: 'chat not found in that workspace' });
|
|
1528
1573
|
const format = { thinking: body.includeThinking !== false, tools: body.includeTools === true };
|
|
1529
1574
|
const { entries } = reads.getMessages(sessionId);
|
|
1530
|
-
const
|
|
1575
|
+
const through = body.throughRowid;
|
|
1576
|
+
if (through !== undefined && (!Number.isSafeInteger(through) || through < 1)) {
|
|
1577
|
+
return json(req, res, 400, { error: 'throughRowid must be a positive integer' });
|
|
1578
|
+
}
|
|
1579
|
+
const cut = through === undefined ? { entries, later: 0 } : transcriptThrough(entries, through);
|
|
1580
|
+
if (!cut)
|
|
1581
|
+
return json(req, res, 409, { error: 'that message is not in this chat' });
|
|
1582
|
+
const rendered = renderTranscript(cut.entries, format);
|
|
1583
|
+
const elided = { ...rendered.elided, later: cut.later };
|
|
1531
1584
|
if (!rendered.kept)
|
|
1532
1585
|
return json(req, res, 409, { error: 'that chat has nothing to copy yet' });
|
|
1533
1586
|
// Conductor's own name for a copied transcript, so the chip reads the same as one
|
|
@@ -1536,18 +1589,24 @@ const server = http.createServer(async (req, res) => {
|
|
|
1536
1589
|
const title = source.title?.trim() || 'chat';
|
|
1537
1590
|
const carried = [`thinking ${format.thinking ? 'included' : 'omitted'}`];
|
|
1538
1591
|
carried.push(`tool calls ${format.tools ? 'included' : 'omitted'}`);
|
|
1592
|
+
const stops = cut.later
|
|
1593
|
+
? [
|
|
1594
|
+
`The copy stops partway through: ${cut.later} later ${cut.later === 1 ? 'entry is' : 'entries are'} not in it.`
|
|
1595
|
+
]
|
|
1596
|
+
: [];
|
|
1539
1597
|
const header = [
|
|
1540
1598
|
`# Transcript of ${title}`,
|
|
1541
1599
|
'',
|
|
1542
1600
|
`${[ws.repo_name, ws.branch].filter(Boolean).join(' · ')}`,
|
|
1543
1601
|
`Copied from the Conductor chat \`${sessionId}\` by conductor-remote. ${carried.join(', ')}.`,
|
|
1602
|
+
...stops,
|
|
1544
1603
|
'',
|
|
1545
1604
|
''
|
|
1546
1605
|
].join('\n');
|
|
1547
1606
|
const attachment = writeAttachment(ws.worktree, `Transcript of ${title}.md`, header + rendered.text);
|
|
1548
1607
|
const opened = await openChat(ws);
|
|
1549
1608
|
if ('error' in opened) {
|
|
1550
|
-
return json(req, res, 502, { ...opened.result, attachment: { ...attachment, ...rendered } });
|
|
1609
|
+
return json(req, res, 502, { ...opened.result, attachment: { ...attachment, ...rendered, elided } });
|
|
1551
1610
|
}
|
|
1552
1611
|
// The token is what Conductor turns into the attachment chip and supplies to the
|
|
1553
1612
|
// receiving agent. Do not repeat `attachment.relPath` in prose: that renders a
|
|
@@ -1563,7 +1622,7 @@ const server = http.createServer(async (req, res) => {
|
|
|
1563
1622
|
path: attachment.relPath,
|
|
1564
1623
|
bytes: attachment.bytes,
|
|
1565
1624
|
kept: rendered.kept,
|
|
1566
|
-
elided
|
|
1625
|
+
elided
|
|
1567
1626
|
}
|
|
1568
1627
|
});
|
|
1569
1628
|
}
|
|
@@ -259,6 +259,25 @@ function toolLine(e) {
|
|
|
259
259
|
function plural(n, one) {
|
|
260
260
|
return `${n} ${one}${n === 1 ? '' : 's'}`;
|
|
261
261
|
}
|
|
262
|
+
/**
|
|
263
|
+
* Cut a transcript at one message, that message included — a fork from an earlier point.
|
|
264
|
+
*
|
|
265
|
+
* The cut is made on the rowid rather than on a position, because that is the granularity
|
|
266
|
+
* every pointer into a chat already has: `read_chat`'s cursor is a rowid, and one source
|
|
267
|
+
* row yields several entries (the reasoning, the prose, the tool calls it made) that belong
|
|
268
|
+
* to the same message and have to cross together.
|
|
269
|
+
*
|
|
270
|
+
* Null means no message here carries that rowid — a cursor from a different chat, or one
|
|
271
|
+
* past the end of this one. Copying the whole chat in that case is the silent failure this
|
|
272
|
+
* exists to prevent: a transcript that stops at the wrong place reads exactly like one that
|
|
273
|
+
* stops where it was asked to.
|
|
274
|
+
*/
|
|
275
|
+
export function transcriptThrough(entries, rowid) {
|
|
276
|
+
if (!entries.some(entry => entry.rowid === rowid))
|
|
277
|
+
return null;
|
|
278
|
+
const kept = entries.filter(entry => entry.rowid <= rowid);
|
|
279
|
+
return { entries: kept, later: entries.length - kept.length };
|
|
280
|
+
}
|
|
262
281
|
/**
|
|
263
282
|
* A chat as markdown, in Conductor's own transcript layout.
|
|
264
283
|
*
|
package/dist-node/src/writes.js
CHANGED
|
@@ -578,6 +578,47 @@ return "ok"`.trim();
|
|
|
578
578
|
return { ok: false, strategy: 'applescript', error: osaError(err) };
|
|
579
579
|
}
|
|
580
580
|
}
|
|
581
|
+
/**
|
|
582
|
+
* Put a workspace away — Conductor's own "Archive workspace" (Command-Shift-A),
|
|
583
|
+
* pressed on the workspace this run has just focused and asserted.
|
|
584
|
+
*
|
|
585
|
+
* The chord acts on whatever the pane is showing, so the assertion is the entire
|
|
586
|
+
* guard and the branch is required rather than optional, exactly as it is for
|
|
587
|
+
* `stopTurn`. The damage is worse here than a mis-aimed prompt: archiving deletes
|
|
588
|
+
* the worktree and takes any agent mid-turn down with it, so a workspace whose pane
|
|
589
|
+
* cannot be checked is refused instead of guessed at.
|
|
590
|
+
*
|
|
591
|
+
* `stopAgents` is what the caller has said about that second half. Conductor draws a
|
|
592
|
+
* confirmation ("Stop agents and archive") when the workspace still has an agent
|
|
593
|
+
* working, and the script presses it only with this set; without it the dialog is
|
|
594
|
+
* dismissed and the run fails, so a tap that meant "archive" can never quietly end
|
|
595
|
+
* someone else's turn. An idle workspace draws no dialog at all.
|
|
596
|
+
*
|
|
597
|
+
* Nothing is confirmed here. `workspaces.state` becoming `archived` is the receipt
|
|
598
|
+
* and server.ts waits for it, the same way the stop and the status change do.
|
|
599
|
+
*/
|
|
600
|
+
export async function archiveWorkspace(workspace, stopAgents) {
|
|
601
|
+
if (!workspace.branch) {
|
|
602
|
+
return { ok: false, strategy: 'applescript', error: 'workspace has no branch to focus' };
|
|
603
|
+
}
|
|
604
|
+
const script = `
|
|
605
|
+
${CONDUCTOR_HANDLERS}
|
|
606
|
+
|
|
607
|
+
my activateConductor()
|
|
608
|
+
my focusWorkspace()
|
|
609
|
+
my archiveWorkspace()
|
|
610
|
+
return "ok"`.trim();
|
|
611
|
+
try {
|
|
612
|
+
await withTargetEnvironment({ workspace, sessionId: null }, targetEnvironment => uiTurn(() => exec('osascript', ['-e', script], {
|
|
613
|
+
env: { ...process.env, ...targetEnvironment, RELAY_ARCHIVE_AGENTS: stopAgents ? '1' : '' },
|
|
614
|
+
timeout: SEND_ATTEMPT_MS
|
|
615
|
+
})));
|
|
616
|
+
return { ok: true, strategy: 'applescript' };
|
|
617
|
+
}
|
|
618
|
+
catch (err) {
|
|
619
|
+
return { ok: false, strategy: 'applescript', error: osaError(err) };
|
|
620
|
+
}
|
|
621
|
+
}
|
|
581
622
|
/**
|
|
582
623
|
* The workspace statuses Conductor's sidebar groups by, mapped from the value it
|
|
583
624
|
* stores in `workspaces.manual_status` to the label on its own menu. `canceled`
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "conductor-remote",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.71.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.",
|