conductor-remote 1.37.0 → 1.39.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-CHhZJBVH.js +42 -0
- package/dist/assets/index-UopM0hHW.css +1 -0
- package/dist/index.html +2 -2
- package/dist/sw.js +1 -1
- package/dist-node/src/conductor.applescript +189 -0
- package/dist-node/src/funnel-watchdog.js +39 -4
- package/dist-node/src/server.js +47 -1
- package/dist-node/src/transcript.js +11 -0
- package/dist-node/src/writes.js +82 -2
- package/package.json +1 -1
- package/dist/assets/index-BHetu12h.css +0 -1
- package/dist/assets/index-D3FckDjN.js +0 -42
|
@@ -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-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-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: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)}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.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-auto{pointer-events:auto}.pointer-events-none{pointer-events:none}.invisible{visibility:hidden}.visible{visibility:visible}.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-0\.5{top:calc(var(--spacing) * .5)}.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}.bottom-full{bottom:100%}.left-0{left:0}.left-0\.5{left:calc(var(--spacing) * .5)}.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-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)}.-mr-1{margin-right:calc(var(--spacing) * -1)}.-mr-2{margin-right:calc(var(--spacing) * -2)}.mr-1{margin-right:var(--spacing)}.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-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}.contents{display:contents}.flex{display:flex}.grid{display:grid}.hidden{display:none}.inline{display:inline}.inline-block{display:inline-block}.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-full{width:100%;height:100%}.h-6{height:calc(var(--spacing) * 6)}.h-12{height:calc(var(--spacing) * 12)}.h-full{height:100%}.max-h-40{max-height:calc(var(--spacing) * 40)}.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-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-44{width:calc(var(--spacing) * 44)}.w-56{width:calc(var(--spacing) * 56)}.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-40{max-width:calc(var(--spacing) * 40)}.max-w-64{max-width:calc(var(--spacing) * 64)}.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-\[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)}.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)}.translate-x-5{--tw-translate-x:calc(var(--spacing) * 5);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}.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-stretch{align-items:stretch}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.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}.overscroll-contain{overscroll-behavior:contain}.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-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-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-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\/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-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{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\/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)}}.bg-working\/15{background-color:#f5a62326}@supports (color:color-mix(in lab,red,red)){.bg-working\/15{background-color:color-mix(in oklab,var(--color-working) 15%,transparent)}}.object-contain{object-fit:contain}.object-cover{object-fit:cover}.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-2{padding-top:calc(var(--spacing) * 2)}.pt-2\.5{padding-top:calc(var(--spacing) * 2.5)}.pr-1{padding-right: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-2{padding-left:calc(var(--spacing) * 2)}.pl-3{padding-left:calc(var(--spacing) * 3)}.text-center{text-align:center}.text-left{text-align:left}.text-right{text-align:right}.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-\[13\.5px\]{font-size:13.5px}.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-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}.underline-offset-2{text-underline-offset:2px}.\[color-scheme\:dark\]{color-scheme:dark}.opacity-0{opacity:0}.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-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}.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-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-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\: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(min-width:48rem){.md\:static{position:static}.md\:inset-0{inset:0}.md\:inset-6{inset:calc(var(--spacing) * 6)}.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\: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\:border{border-style:var(--tw-border-style);border-width:1px}.md\:border-border-soft{border-color:var(--color-border-soft)}.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-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-CHhZJBVH.js"></script>
|
|
17
|
+
<link rel="stylesheet" crossorigin href="/assets/index-UopM0hHW.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 l={};const t=e=>i(e,o),c={module:{uri:o},exports:l,require:t};s[o]=Promise.all(n.map(e=>c[e]||t(e))).then(e=>(r(...e),l))}}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:"890f6a70e97d144f4d025254e90892a1"},{url:"index.html",revision:"
|
|
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 l={};const t=e=>i(e,o),c={module:{uri:o},exports:l,require:t};s[o]=Promise.all(n.map(e=>c[e]||t(e))).then(e=>(r(...e),l))}}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:"890f6a70e97d144f4d025254e90892a1"},{url:"index.html",revision:"79c117a92e7635dd0174f5aeb1f3940c"},{url:"assets/workbox-window.prod.es5-BBnX5xw4.js",revision:null},{url:"assets/index-UopM0hHW.css",revision:null},{url:"assets/index-CHhZJBVH.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\//]}))});
|
|
@@ -789,6 +789,40 @@ on selectChatTab()
|
|
|
789
789
|
end tell
|
|
790
790
|
end selectChatTab
|
|
791
791
|
|
|
792
|
+
on cancelAgent()
|
|
793
|
+
-- Stop the answer this chat is streaming: Conductor's own "Cancel agent"
|
|
794
|
+
-- command, Command-Shift-Delete (key code 51). Taken from its Keyboard
|
|
795
|
+
-- shortcuts dialog (Command-slash, section "Chat"), not guessed - and it is
|
|
796
|
+
-- the only lever there is. The menu bar carries no stop command and neither
|
|
797
|
+
-- does the palette, and the composer's stop BUTTON is unnamed to
|
|
798
|
+
-- Accessibility: no title, no description, no help, no identifier, telling
|
|
799
|
+
-- itself apart from the send button beside it only by its Tailwind classes.
|
|
800
|
+
-- Which is a distinction worth nothing at the moment it matters, because
|
|
801
|
+
-- while a chat is working with a draft in the composer BOTH buttons are on
|
|
802
|
+
-- screen - stop on the left, send on the right - so "press the last button"
|
|
803
|
+
-- steers the running agent with whatever was half-typed instead of stopping
|
|
804
|
+
-- it. A keystroke can't confuse the two.
|
|
805
|
+
--
|
|
806
|
+
-- The keystroke lands wherever focus is, so this asserts the pane first, the
|
|
807
|
+
-- same check a send makes before typing. Cancelling the wrong agent destroys
|
|
808
|
+
-- work that was running fine, which is the same class of damage as landing a
|
|
809
|
+
-- prompt in the wrong chat and gets the same answer: error out, never guess.
|
|
810
|
+
set strips to my tabGroups()
|
|
811
|
+
if (count of strips) is 0 then error "couldn't find the chat pane to cancel in"
|
|
812
|
+
my assertWorkspace(item 1 of strips)
|
|
813
|
+
-- Command-L ("Focus chat input") first, so the shortcut is delivered inside the
|
|
814
|
+
-- chat view rather than to a terminal panel that had focus, where the terminal
|
|
815
|
+
-- would swallow it. It also parks focus somewhere harmless: the composer keeps
|
|
816
|
+
-- its draft, since Conductor binds this chord to Cancel agent rather than to any
|
|
817
|
+
-- text-deletion the field would otherwise do with it.
|
|
818
|
+
tell application "System Events"
|
|
819
|
+
keystroke "l" using {command down}
|
|
820
|
+
delay 0.2
|
|
821
|
+
key code 51 using {command down, shift down}
|
|
822
|
+
end tell
|
|
823
|
+
delay 0.3
|
|
824
|
+
end cancelAgent
|
|
825
|
+
|
|
792
826
|
on composerControls()
|
|
793
827
|
set strips to my tabGroups()
|
|
794
828
|
if (count of strips) is 0 then error "couldn't find the composer"
|
|
@@ -1120,3 +1154,158 @@ on setWorkspaceStatus()
|
|
|
1120
1154
|
end tell
|
|
1121
1155
|
delay 0.6
|
|
1122
1156
|
end setWorkspaceStatus
|
|
1157
|
+
|
|
1158
|
+
(* -- Instant Hotspot ----------------------------------------------------------
|
|
1159
|
+
The funnel watchdog's last resort when this Mac has no route: press the row
|
|
1160
|
+
for a personal hotspot in Control Center's Wi-Fi popover. networksetup can
|
|
1161
|
+
only join a network that is broadcasting, and a personal hotspot usually
|
|
1162
|
+
is not - the row in the Wi-Fi menu is fed by Continuity over Bluetooth, and
|
|
1163
|
+
pressing it asks the phone to wake its hotspot, exactly like a human
|
|
1164
|
+
clicking the Wi-Fi menu. Everything here targets process "ControlCenter",
|
|
1165
|
+
not Conductor - same Accessibility grant, different process, which is why
|
|
1166
|
+
the refusal mapping below skips refusalReason's -1712 branch (its words are
|
|
1167
|
+
about a wedged Conductor).
|
|
1168
|
+
Addressed by AXIdentifier throughout ("com.apple.menuextra.wifi",
|
|
1169
|
+
"wifi-network-<name>", "wifi-header") - the items' names are missing value
|
|
1170
|
+
and any visible text is localized, the identifiers are neither (measured
|
|
1171
|
+
live on macOS 26.5, 2026-08). A "whose value of attribute ..." filter fails
|
|
1172
|
+
wholesale (-1728) when any element lacks the attribute - several menu bar
|
|
1173
|
+
items do - so every lookup here walks with a per-item try instead.
|
|
1174
|
+
The SE-terms trap at the top of CLAUDE.md's applescript section bit this
|
|
1175
|
+
code through a HANDLER PARAMETER: findAxId's first argument was once named
|
|
1176
|
+
`container`, a System Events dictionary word, so inside the tell it
|
|
1177
|
+
resolved as the term and the walk found nothing - through an error-eating
|
|
1178
|
+
try, so a provably open popover read as "no popover" for a whole debugging
|
|
1179
|
+
session while every direct read worked. osacompile accepts it, the handler
|
|
1180
|
+
check can't see it. Keep every identifier in these handlers boring and
|
|
1181
|
+
un-dictionary-like.
|
|
1182
|
+
The menu bar item is a TOGGLE: the same press opens and closes the
|
|
1183
|
+
popover, so nothing here presses it without first checking which state the
|
|
1184
|
+
popover is in (wifiPopoverWindow), and an already-open popover aborts the
|
|
1185
|
+
run - a human may be mid-gesture in it, and their next click kills an
|
|
1186
|
+
automated run anyway (contention looks exactly like the status-row menu's:
|
|
1187
|
+
fails while someone uses the Mac, clean when it is unattended). *)
|
|
1188
|
+
|
|
1189
|
+
on wifiMenuBarItem()
|
|
1190
|
+
try
|
|
1191
|
+
with timeout of 6 seconds
|
|
1192
|
+
tell application "System Events" to tell process "ControlCenter"
|
|
1193
|
+
repeat with mi in menu bar items of menu bar 1
|
|
1194
|
+
try
|
|
1195
|
+
if (value of attribute "AXIdentifier" of mi) is "com.apple.menuextra.wifi" then return contents of mi
|
|
1196
|
+
end try
|
|
1197
|
+
end repeat
|
|
1198
|
+
end tell
|
|
1199
|
+
end timeout
|
|
1200
|
+
on error errText number errNum
|
|
1201
|
+
if errNum is not -1712 then
|
|
1202
|
+
set refusal to my refusalReason({-1, errNum, errText})
|
|
1203
|
+
if refusal is not "" then error refusal
|
|
1204
|
+
end if
|
|
1205
|
+
error "reading the menu bar failed (" & errNum & "): " & errText
|
|
1206
|
+
end try
|
|
1207
|
+
error "the Wi-Fi control is not in the menu bar - turn on Show in Menu Bar for Wi-Fi in System Settings > Control Center"
|
|
1208
|
+
end wifiMenuBarItem
|
|
1209
|
+
|
|
1210
|
+
on findAxId(parentEl, wantedId, depth)
|
|
1211
|
+
-- Depth-capped even though the popover is small: the cap is what keeps a
|
|
1212
|
+
-- macOS reshuffle of this tree from turning one lookup into a full crawl.
|
|
1213
|
+
-- `parentEl` is deliberately not `container` - see the section comment.
|
|
1214
|
+
tell application "System Events"
|
|
1215
|
+
try
|
|
1216
|
+
set kids to UI elements of parentEl
|
|
1217
|
+
on error
|
|
1218
|
+
return missing value
|
|
1219
|
+
end try
|
|
1220
|
+
end tell
|
|
1221
|
+
repeat with el in kids
|
|
1222
|
+
try
|
|
1223
|
+
tell application "System Events"
|
|
1224
|
+
if (value of attribute "AXIdentifier" of el) is wantedId then return contents of el
|
|
1225
|
+
end tell
|
|
1226
|
+
end try
|
|
1227
|
+
if depth > 1 then
|
|
1228
|
+
set hit to my findAxId(el, wantedId, depth - 1)
|
|
1229
|
+
if hit is not missing value then return hit
|
|
1230
|
+
end if
|
|
1231
|
+
end repeat
|
|
1232
|
+
return missing value
|
|
1233
|
+
end findAxId
|
|
1234
|
+
|
|
1235
|
+
on wifiPopoverWindow()
|
|
1236
|
+
-- The popover is whichever ControlCenter window carries the "wifi-header"
|
|
1237
|
+
-- id. Existence is read fresh on every call: pressing a network row can
|
|
1238
|
+
-- close the popover by itself, and the menu bar item is a toggle, so a
|
|
1239
|
+
-- blind second press would reopen what just closed.
|
|
1240
|
+
tell application "System Events" to tell process "ControlCenter"
|
|
1241
|
+
try
|
|
1242
|
+
set wins to windows
|
|
1243
|
+
on error
|
|
1244
|
+
return missing value
|
|
1245
|
+
end try
|
|
1246
|
+
end tell
|
|
1247
|
+
repeat with w in wins
|
|
1248
|
+
if my findAxId(w, "wifi-header", 3) is not missing value then return contents of w
|
|
1249
|
+
end repeat
|
|
1250
|
+
return missing value
|
|
1251
|
+
end wifiPopoverWindow
|
|
1252
|
+
|
|
1253
|
+
on closeWifiPopover(wifiItem)
|
|
1254
|
+
if my wifiPopoverWindow() is not missing value then
|
|
1255
|
+
try
|
|
1256
|
+
tell application "System Events" to perform action "AXPress" of wifiItem
|
|
1257
|
+
end try
|
|
1258
|
+
end if
|
|
1259
|
+
end closeWifiPopover
|
|
1260
|
+
|
|
1261
|
+
on joinInstantHotspot()
|
|
1262
|
+
-- The name arrives via a file, like RELAY_PROMPT_FILE: do shell script
|
|
1263
|
+
-- output is decoded as UTF-8, so a name with non-ASCII letters survives
|
|
1264
|
+
-- where a system attribute read may not. AppleScript's default nonliteral
|
|
1265
|
+
-- text comparison then treats composed and decomposed accents as equal,
|
|
1266
|
+
-- which matters because the AX identifier uses whatever normalization
|
|
1267
|
+
-- macOS chose.
|
|
1268
|
+
set hotspotName to do shell script "cat " & quoted form of (system attribute "RELAY_HOTSPOT_FILE")
|
|
1269
|
+
if hotspotName is "" then error "no hotspot name provided"
|
|
1270
|
+
-- The lock screen hides the session from Accessibility, so behind it this
|
|
1271
|
+
-- press has nothing to land on. Named up front, in the same words the send
|
|
1272
|
+
-- path uses, instead of surfacing later as a popover that never opened.
|
|
1273
|
+
if my screenLocked() is "locked" then error "The Mac is locked - the Wi-Fi menu can't be pressed until it unlocks"
|
|
1274
|
+
set wifiItem to my wifiMenuBarItem()
|
|
1275
|
+
if my wifiPopoverWindow() is not missing value then error "the Wi-Fi popover is already open - someone may be using it, so nothing was pressed"
|
|
1276
|
+
tell application "System Events" to perform action "AXPress" of wifiItem
|
|
1277
|
+
-- The popover renders in its own time (measured 1-2s), and a human's click
|
|
1278
|
+
-- anywhere on the Mac closes it, so poll rather than sleep once.
|
|
1279
|
+
set pop to missing value
|
|
1280
|
+
repeat 8 times
|
|
1281
|
+
delay 0.5
|
|
1282
|
+
set pop to my wifiPopoverWindow()
|
|
1283
|
+
if pop is not missing value then exit repeat
|
|
1284
|
+
end repeat
|
|
1285
|
+
if pop is missing value then error "pressing the Wi-Fi control opened no popover - someone clicking on the Mac closes it the moment it opens (contention, not a fault); otherwise Control Center is not answering"
|
|
1286
|
+
set rowEl to missing value
|
|
1287
|
+
repeat 4 times
|
|
1288
|
+
set rowEl to my findAxId(pop, "wifi-network-" & hotspotName, 6)
|
|
1289
|
+
if rowEl is not missing value then exit repeat
|
|
1290
|
+
delay 0.5
|
|
1291
|
+
end repeat
|
|
1292
|
+
if rowEl is missing value then
|
|
1293
|
+
my closeWifiPopover(wifiItem)
|
|
1294
|
+
error quote & hotspotName & quote & " is not in the Wi-Fi menu - the iPhone is out of Bluetooth range, has Bluetooth off, or Personal Hotspot is off in its Settings"
|
|
1295
|
+
end if
|
|
1296
|
+
-- The row is a toggle too: value 1 means already connected, and pressing
|
|
1297
|
+
-- it then would DISCONNECT - the one outcome worse than doing nothing.
|
|
1298
|
+
-- Only a read of exactly 1 skips the press; an unreadable value presses.
|
|
1299
|
+
set rowValue to 0
|
|
1300
|
+
try
|
|
1301
|
+
tell application "System Events" to set rowValue to value of rowEl
|
|
1302
|
+
end try
|
|
1303
|
+
if rowValue is 1 then
|
|
1304
|
+
my closeWifiPopover(wifiItem)
|
|
1305
|
+
return "already-connected"
|
|
1306
|
+
end if
|
|
1307
|
+
tell application "System Events" to perform action "AXPress" of rowEl
|
|
1308
|
+
delay 1
|
|
1309
|
+
my closeWifiPopover(wifiItem)
|
|
1310
|
+
return "pressed"
|
|
1311
|
+
end joinInstantHotspot
|
|
@@ -31,6 +31,7 @@ import { promisify } from 'node:util';
|
|
|
31
31
|
import { readSettings } from "./settings.js";
|
|
32
32
|
import { magicDnsName, readExposeMode, relayPort, tailscaleBin } from "./tailscale.js";
|
|
33
33
|
import { hasDefaultRoute, joinNetwork, preferredNetworks } from "./wifi.js";
|
|
34
|
+
import { joinInstantHotspot } from "./writes.js";
|
|
34
35
|
const execFileP = promisify(execFile);
|
|
35
36
|
const PROBE_PATH = '/health'; // unauthenticated 200 on the relay — no token needed to prove reachability
|
|
36
37
|
const PROBE_TIMEOUT_MS = 8000;
|
|
@@ -157,6 +158,19 @@ let lastHealAt = 0;
|
|
|
157
158
|
let lastRejoinAt = 0;
|
|
158
159
|
const REJOIN_COOLDOWN_MS = 5 * 60 * 1000; // a network switch is disruptive; never churn on one
|
|
159
160
|
const REJOIN_SETTLE_MS = 12 * 1000; // DHCP + tailscaled noticing the new endpoint
|
|
161
|
+
// An Instant Hotspot press has the phone's Bluetooth wake + hotspot spin-up in front of the
|
|
162
|
+
// same DHCP wait, so it gets a longer leash than a plain join before the tick gives up on it.
|
|
163
|
+
const HOTSPOT_SETTLE_MS = 30 * 1000;
|
|
164
|
+
/** Poll for the default route instead of one fixed sleep — a join that lands early returns early. */
|
|
165
|
+
async function routeAppeared(waitMs) {
|
|
166
|
+
const until = Date.now() + waitMs;
|
|
167
|
+
while (Date.now() < until) {
|
|
168
|
+
if (await hasDefaultRoute())
|
|
169
|
+
return true;
|
|
170
|
+
await new Promise(r => setTimeout(r, 3000));
|
|
171
|
+
}
|
|
172
|
+
return hasDefaultRoute();
|
|
173
|
+
}
|
|
160
174
|
/**
|
|
161
175
|
* Last resort when the probe is down: this Mac has no link at all, so move it onto a
|
|
162
176
|
* configured fallback (your phone's hotspot) and re-register Funnel, whose ingress a
|
|
@@ -173,6 +187,14 @@ const REJOIN_SETTLE_MS = 12 * 1000; // DHCP + tailscaled noticing the new endpoi
|
|
|
173
187
|
* or passed; an SSID that isn't in the preferred list is named in the log, not tried.
|
|
174
188
|
* - Behind a cooldown, so a Mac that is simply off the air doesn't cycle its Wi-Fi.
|
|
175
189
|
*
|
|
190
|
+
* Two ways in, tried in order. `networksetup` first — cheap, no UI — and when it answers
|
|
191
|
+
* "Could not find network" (a hotspot doesn't broadcast until asked), the Accessibility
|
|
192
|
+
* press on the Wi-Fi menu's own row (`joinInstantHotspot` in writes.ts), which wakes the
|
|
193
|
+
* phone's hotspot over Continuity exactly like clicking it. The press needs an unlocked
|
|
194
|
+
* screen — the lock hides the session from Accessibility, and the failure names that —
|
|
195
|
+
* so a lid-closed Mac still wants macOS's own Auto-Join Hotspot set to Automatic as the
|
|
196
|
+
* layer below this one.
|
|
197
|
+
*
|
|
176
198
|
* Returns true if a join reported success, meaning the caller should re-register rather
|
|
177
199
|
* than treat this tick as an ordinary failure.
|
|
178
200
|
*/
|
|
@@ -194,17 +216,30 @@ async function tryRejoin() {
|
|
|
194
216
|
lastRejoinAt = Date.now();
|
|
195
217
|
for (const ssid of candidates) {
|
|
196
218
|
log(`no default route — joining fallback network "${ssid}"`);
|
|
219
|
+
let settleMs = REJOIN_SETTLE_MS;
|
|
197
220
|
const joined = await joinNetwork(ssid);
|
|
198
221
|
if (!joined.ok) {
|
|
199
222
|
log(`join "${ssid}" failed: ${joined.error}`);
|
|
200
|
-
|
|
223
|
+
// networksetup can only join a network that is broadcasting, and a personal
|
|
224
|
+
// hotspot usually isn't — its row in the Wi-Fi menu arrives over Continuity,
|
|
225
|
+
// and pressing it wakes the hotspot the way clicking it by hand does. Tried
|
|
226
|
+
// for every failed candidate rather than only hotspot-looking names: the
|
|
227
|
+
// name heuristic never decides anything (see looksLikeHotspot), and for an
|
|
228
|
+
// ordinary network that's simply out of range the press fails in words
|
|
229
|
+
// ("not in the Wi-Fi menu") that cost one popover flash.
|
|
230
|
+
log(`pressing the Wi-Fi menu's "${ssid}" row instead (Instant Hotspot)`);
|
|
231
|
+
const pressed = await joinInstantHotspot(ssid);
|
|
232
|
+
if (!pressed.ok) {
|
|
233
|
+
log(`Instant Hotspot press for "${ssid}" failed: ${pressed.error}`);
|
|
234
|
+
continue;
|
|
235
|
+
}
|
|
236
|
+
settleMs = HOTSPOT_SETTLE_MS;
|
|
201
237
|
}
|
|
202
|
-
|
|
203
|
-
if (await hasDefaultRoute()) {
|
|
238
|
+
if (await routeAppeared(settleMs)) {
|
|
204
239
|
log(`joined "${ssid}" and the link is up`);
|
|
205
240
|
return true;
|
|
206
241
|
}
|
|
207
|
-
log(`joined "${ssid}" but no default route appeared after ${
|
|
242
|
+
log(`joined "${ssid}" but no default route appeared after ${settleMs / 1000}s`);
|
|
208
243
|
}
|
|
209
244
|
return false;
|
|
210
245
|
}
|
package/dist-node/src/server.js
CHANGED
|
@@ -19,7 +19,7 @@ import { Reads } from "./reads.js";
|
|
|
19
19
|
import { readSettings, writeSettings } from "./settings.js";
|
|
20
20
|
import { driftWarningLines, tailscaleBin } from "./tailscale.js";
|
|
21
21
|
import { autoJoinHotspotMode, currentSsid, looksLikeHotspot, preferredNetworks } from "./wifi.js";
|
|
22
|
-
import { createWorkspace, describeActuator, EFFORT_LABELS, listAgentModels, lockBlocked, newChat, pickActuator, retryWontHelp, screenLocked, setAgentOptions, setRestartGuard, setWorkspaceStatus, WORKSPACE_STATUS_LABELS } from "./writes.js";
|
|
22
|
+
import { createWorkspace, describeActuator, EFFORT_LABELS, listAgentModels, lockBlocked, newChat, pickActuator, retryWontHelp, screenLocked, setAgentOptions, setRestartGuard, setWorkspaceStatus, stopTurn, WORKSPACE_STATUS_LABELS } from "./writes.js";
|
|
23
23
|
// Before anything that logs: from here on every console line is also kept in memory for
|
|
24
24
|
// `GET /api/logs`, so the phone can read why a send failed without ssh-ing into the Mac.
|
|
25
25
|
installLogCapture();
|
|
@@ -737,6 +737,52 @@ const server = http.createServer(async (req, res) => {
|
|
|
737
737
|
return json(req, res, 502, { ok: false, strategy: actuator.name, error: applied.error });
|
|
738
738
|
return json(req, res, 200, { ok: true, session: reads.listSessions(ws.id).find(s => s.id === sessionId) });
|
|
739
739
|
}
|
|
740
|
+
// POST /api/sessions/:id/stop — the desktop app's stop button, for one chat.
|
|
741
|
+
m = pathname.match(/^\/api\/sessions\/([^/]+)\/stop$/);
|
|
742
|
+
if (req.method === 'POST' && m) {
|
|
743
|
+
const sessionId = decodeURIComponent(m[1]);
|
|
744
|
+
const body = JSON.parse((await readBody(req)) || '{}');
|
|
745
|
+
const ws = body.workspaceId
|
|
746
|
+
? reads.getWorkspace(body.workspaceId)
|
|
747
|
+
: (reads.listWorkspaces().find(w => w.active_session_id === sessionId) ?? null);
|
|
748
|
+
if (!ws)
|
|
749
|
+
return json(req, res, 404, { error: 'workspace for session not found' });
|
|
750
|
+
const located = locateChat(ws, sessionId);
|
|
751
|
+
if ('error' in located)
|
|
752
|
+
return json(req, res, 409, { error: located.error });
|
|
753
|
+
// Nothing running is a success, not an error: the phone shows Stop the moment it
|
|
754
|
+
// sends (the optimistic hint) and a turn that ends on its own a beat before the tap
|
|
755
|
+
// is the common case, not a mistake worth a red banner. It also keeps the one
|
|
756
|
+
// keystroke this route presses off an idle chat entirely — Conductor's own
|
|
757
|
+
// composer has no stop button to mis-tap there either.
|
|
758
|
+
const before = reads.listSessions(ws.id).find(s => s.id === sessionId);
|
|
759
|
+
if (before?.status !== 'working') {
|
|
760
|
+
return json(req, res, 200, { ok: true, alreadyIdle: true, session: before });
|
|
761
|
+
}
|
|
762
|
+
const result = await stopTurn({ workspace: ws, sessionId, tab: located.tab });
|
|
763
|
+
if (!result.ok)
|
|
764
|
+
return json(req, res, 502, result);
|
|
765
|
+
// The DB is the receipt, exactly as it is for agent settings: the keystroke is
|
|
766
|
+
// fire-and-forget, so what counts is `status` leaving `working`. Conductor writes
|
|
767
|
+
// that a beat after it tears the turn down.
|
|
768
|
+
let observed = before.status;
|
|
769
|
+
for (let i = 0; i < 20 && observed === 'working'; i++) {
|
|
770
|
+
await sleep(300);
|
|
771
|
+
observed = reads.listSessions(ws.id).find(s => s.id === sessionId)?.status ?? observed;
|
|
772
|
+
}
|
|
773
|
+
if (observed === 'working') {
|
|
774
|
+
return json(req, res, 502, {
|
|
775
|
+
ok: false,
|
|
776
|
+
strategy: result.strategy,
|
|
777
|
+
error: 'Conductor took the stop but the agent is still working. Try again, or stop it on your Mac.'
|
|
778
|
+
});
|
|
779
|
+
}
|
|
780
|
+
return json(req, res, 200, {
|
|
781
|
+
ok: true,
|
|
782
|
+
strategy: result.strategy,
|
|
783
|
+
session: reads.listSessions(ws.id).find(s => s.id === sessionId)
|
|
784
|
+
});
|
|
785
|
+
}
|
|
740
786
|
// POST /api/sessions/:id/prompt { text, agent? } — agent is the phone's staged
|
|
741
787
|
// settings patch, applied before the prompt so the two can't come apart (and so
|
|
742
788
|
// both park together when the Mac turns out to be locked).
|
|
@@ -65,6 +65,17 @@ export function parseMessage(row, worktree = null) {
|
|
|
65
65
|
// Bookkeeping frames: hooks, init, token accounting, end-of-turn results.
|
|
66
66
|
if (parsed.type === 'system' || parsed.type === 'result')
|
|
67
67
|
return [];
|
|
68
|
+
// How a stopped turn ends: `{"type":"error","content":"aborted by user"}`, and it
|
|
69
|
+
// carries no `message.content`, so without this it fell through to the raw-JSON
|
|
70
|
+
// dump below. That was tolerable while stopping needed a Mac; the phone can do it
|
|
71
|
+
// now (`POST /api/sessions/:id/stop`), so it is the last line of every stopped
|
|
72
|
+
// chat. The SDK's own wording is kept rather than reworded — "aborted by user" is
|
|
73
|
+
// already plain, and inventing a phrase here would drift from what the desktop shows.
|
|
74
|
+
if (parsed.type === 'error') {
|
|
75
|
+
const said = str(parsed.content);
|
|
76
|
+
if (said)
|
|
77
|
+
return [{ ...base, id: row.id, role: 'system', text: clip(said, 200) }];
|
|
78
|
+
}
|
|
68
79
|
const blocks = parsed.message?.content;
|
|
69
80
|
if (!Array.isArray(blocks)) {
|
|
70
81
|
if (parsed.type === 'user' || parsed.type === 'assistant')
|
package/dist-node/src/writes.js
CHANGED
|
@@ -261,12 +261,12 @@ function targetEnv(target) {
|
|
|
261
261
|
};
|
|
262
262
|
}
|
|
263
263
|
/** osascript echoes the whole failing script back; keep just the reason for the phone. */
|
|
264
|
-
function osaError(err) {
|
|
264
|
+
function osaError(err, timeoutMsg = 'Conductor took too long to respond') {
|
|
265
265
|
const raw = err instanceof Error ? err.message : String(err);
|
|
266
266
|
// A timeout kill carries no execution error at all — its first line is
|
|
267
267
|
// "Command failed: osascript -e" plus the whole script, which is useless here.
|
|
268
268
|
if (err && typeof err === 'object' && 'killed' in err && err.killed) {
|
|
269
|
-
return
|
|
269
|
+
return timeoutMsg;
|
|
270
270
|
}
|
|
271
271
|
return raw.match(/execution error: (.+?) \(-?\d+\)/)?.[1] ?? raw.split('\n')[0];
|
|
272
272
|
}
|
|
@@ -330,6 +330,86 @@ end tell
|
|
|
330
330
|
}
|
|
331
331
|
}
|
|
332
332
|
}
|
|
333
|
+
/**
|
|
334
|
+
* Stop the answer a chat is streaming — the desktop app's stop button, reached
|
|
335
|
+
* through the same focus-and-assert path as a send and then Conductor's own
|
|
336
|
+
* "Cancel agent" shortcut (see `cancelAgent` in conductor.applescript for why a
|
|
337
|
+
* keystroke rather than the button).
|
|
338
|
+
*
|
|
339
|
+
* The branch is required rather than optional. Everywhere else a workspace with
|
|
340
|
+
* no branch merely loses the pane assertion; here that assertion is the only thing
|
|
341
|
+
* standing between "stop this agent" and "throw away a different agent's turn", so
|
|
342
|
+
* a target that can't be checked is refused instead of aimed.
|
|
343
|
+
*
|
|
344
|
+
* Nothing is confirmed here: `sessions.status` leaving `working` is the receipt and
|
|
345
|
+
* server.ts waits for it, the same way agent settings are confirmed against the DB
|
|
346
|
+
* rather than against the UI that was just driven.
|
|
347
|
+
*/
|
|
348
|
+
export async function stopTurn(target) {
|
|
349
|
+
if (!target.workspace.branch) {
|
|
350
|
+
return { ok: false, strategy: 'applescript', error: 'workspace has no branch to focus' };
|
|
351
|
+
}
|
|
352
|
+
const script = `
|
|
353
|
+
${CONDUCTOR_HANDLERS}
|
|
354
|
+
|
|
355
|
+
my activateConductor()
|
|
356
|
+
my focusWorkspace()
|
|
357
|
+
my selectChatTab()
|
|
358
|
+
my cancelAgent()
|
|
359
|
+
return "ok"`.trim();
|
|
360
|
+
try {
|
|
361
|
+
await uiTurn(() => exec('osascript', ['-e', script], {
|
|
362
|
+
env: { ...process.env, ...targetEnv(target) },
|
|
363
|
+
timeout: SEND_ATTEMPT_MS
|
|
364
|
+
}));
|
|
365
|
+
return { ok: true, strategy: 'applescript' };
|
|
366
|
+
}
|
|
367
|
+
catch (err) {
|
|
368
|
+
return { ok: false, strategy: 'applescript', error: osaError(err) };
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
/**
|
|
372
|
+
* Press the Wi-Fi menu's row for a personal hotspot — Instant Hotspot, the same
|
|
373
|
+
* button a human clicks. `networksetup` can only join a network that is
|
|
374
|
+
* broadcasting, and a personal hotspot usually isn't; the row in Control
|
|
375
|
+
* Center's Wi-Fi popover is fed by Continuity over Bluetooth, and pressing it
|
|
376
|
+
* asks the phone to wake its hotspot. The funnel watchdog reaches for this when
|
|
377
|
+
* a plain join answered "Could not find network".
|
|
378
|
+
*
|
|
379
|
+
* The one UI write here that doesn't target Conductor, and it still takes a
|
|
380
|
+
* uiTurn: the popover steals key focus, so a palette fallback running at the
|
|
381
|
+
* same moment would type into it. The name travels via a temp file like the
|
|
382
|
+
* prompt does — same escaping-and-encoding dodge, and hotspot names ("Han
|
|
383
|
+
* høyes iPhone") are non-ASCII more often than prompts are. Success here means
|
|
384
|
+
* *pressed*, nothing more: joining takes several seconds of Bluetooth wake +
|
|
385
|
+
* DHCP, so the caller owns the wait, and it watches `hasDefaultRoute()` — the
|
|
386
|
+
* one link signal that needs no permission — not this function's word.
|
|
387
|
+
* Everything else — the lock check, the toggle-aware close, the already-open
|
|
388
|
+
* abort, the contention story — lives with the handler in conductor.applescript.
|
|
389
|
+
*/
|
|
390
|
+
export async function joinInstantHotspot(name) {
|
|
391
|
+
const script = `
|
|
392
|
+
${CONDUCTOR_HANDLERS}
|
|
393
|
+
|
|
394
|
+
my joinInstantHotspot()`.trim();
|
|
395
|
+
const os = await import('node:os');
|
|
396
|
+
const fs = await import('node:fs/promises');
|
|
397
|
+
const tmp = path.join(os.tmpdir(), `relay-hotspot-${process.pid}-${Date.now()}.txt`);
|
|
398
|
+
await fs.writeFile(tmp, name, 'utf8');
|
|
399
|
+
try {
|
|
400
|
+
await uiTurn(() => exec('osascript', ['-e', script], {
|
|
401
|
+
env: { ...process.env, RELAY_HOTSPOT_FILE: tmp },
|
|
402
|
+
timeout: 25_000
|
|
403
|
+
}));
|
|
404
|
+
return { ok: true };
|
|
405
|
+
}
|
|
406
|
+
catch (err) {
|
|
407
|
+
return { ok: false, error: osaError(err, 'the Wi-Fi menu press took too long') };
|
|
408
|
+
}
|
|
409
|
+
finally {
|
|
410
|
+
await fs.rm(tmp, { force: true }).catch(() => undefined);
|
|
411
|
+
}
|
|
412
|
+
}
|
|
333
413
|
/**
|
|
334
414
|
* Conductor stores the effort level as `sessions.claude_effort_level`, but the
|
|
335
415
|
* composer button is labelled with the human name and *cycles* through them in
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "conductor-remote",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.39.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.",
|