conductor-remote 1.64.0 → 1.65.1
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 +11 -0
- package/dist/assets/index-87r9u-0C.css +1 -0
- package/dist/assets/index-fu-yJ_gW.js +47 -0
- package/dist/index.html +2 -2
- package/dist/sw.js +1 -1
- package/dist-node/src/conductor.applescript +193 -13
- package/dist-node/src/dev-server.js +693 -0
- package/dist-node/src/routes.js +4 -0
- package/dist-node/src/server.js +32 -0
- package/dist-node/src/writes.js +58 -9
- package/package.json +1 -1
- package/dist/assets/index-BhxPTIyU.css +0 -1
- package/dist/assets/index-C8s68scA.js +0 -47
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-fu-yJ_gW.js"></script>
|
|
17
|
+
<link rel="stylesheet" crossorigin href="/assets/index-87r9u-0C.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
|
|
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:"e1e682e2e5e88fa03b7808ae9db8e098"},{url:"index.html",revision:"96dea2763a1c11d8262211107568a7e1"},{url:"assets/workbox-window.prod.es5-BBnX5xw4.js",revision:null},{url:"assets/index-fu-yJ_gW.js",revision:null},{url:"assets/index-87r9u-0C.css",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\//]}))});
|
|
@@ -714,7 +714,39 @@ on normalizeNewlines(s)
|
|
|
714
714
|
return joined
|
|
715
715
|
end normalizeNewlines
|
|
716
716
|
|
|
717
|
-
on
|
|
717
|
+
on composerField()
|
|
718
|
+
-- The composer's AXTextArea: an AXGroup named "composer" in the chat pane, one
|
|
719
|
+
-- text area inside it. Resolved once and handed to both the fill and the send
|
|
720
|
+
-- confirm below, because reaching it means walking the pane from the tab strip
|
|
721
|
+
-- and that walk measured ~0.5s on a live window. Returns missing value when the
|
|
722
|
+
-- composer isn't there at all, which is the caller's cue to fall back to pasting.
|
|
723
|
+
set strips to my tabGroups()
|
|
724
|
+
if (count of strips) is 0 then return missing value
|
|
725
|
+
try
|
|
726
|
+
tell application "System Events" to tell process "Conductor"
|
|
727
|
+
set pane to value of attribute "AXParent" of (item 1 of strips)
|
|
728
|
+
set composerBox to item 1 of (UI elements of pane whose name is "composer")
|
|
729
|
+
return item 1 of (UI elements of composerBox whose role is "AXTextArea")
|
|
730
|
+
end tell
|
|
731
|
+
end try
|
|
732
|
+
return missing value
|
|
733
|
+
end composerField
|
|
734
|
+
|
|
735
|
+
on composerTextOf(textBox)
|
|
736
|
+
-- What the box holds now, or missing value when it cannot be read at all. A pane
|
|
737
|
+
-- that re-rendered leaves the old reference pointing at a dead element, and
|
|
738
|
+
-- "can't read it" must never be reported as "still holding the prompt": that is
|
|
739
|
+
-- the one state that presses Enter again, and it would do so at the moment the
|
|
740
|
+
-- box may already be empty.
|
|
741
|
+
try
|
|
742
|
+
tell application "System Events" to tell process "Conductor"
|
|
743
|
+
return (value of textBox) as text
|
|
744
|
+
end tell
|
|
745
|
+
end try
|
|
746
|
+
return missing value
|
|
747
|
+
end composerTextOf
|
|
748
|
+
|
|
749
|
+
on fillComposer(textBox, promptText)
|
|
718
750
|
-- Write the prompt straight into the composer's AXTextArea instead of
|
|
719
751
|
-- stashing the clipboard, pressing Cmd+L and pasting. AXFocused and AXValue
|
|
720
752
|
-- are both settable, so this needs no keystrokes and no clipboard hijack.
|
|
@@ -722,13 +754,9 @@ on fillComposer(promptText)
|
|
|
722
754
|
-- *clears whatever it wrote first*: leaving half a prompt behind would make
|
|
723
755
|
-- the fallback paste append to it and send a garbled prompt.
|
|
724
756
|
if promptText is "" then return false
|
|
725
|
-
|
|
726
|
-
if (count of strips) is 0 then return false
|
|
757
|
+
if textBox is missing value then return false
|
|
727
758
|
try
|
|
728
759
|
tell application "System Events" to tell process "Conductor"
|
|
729
|
-
set pane to value of attribute "AXParent" of (item 1 of strips)
|
|
730
|
-
set composerBox to item 1 of (UI elements of pane whose name is "composer")
|
|
731
|
-
set textBox to item 1 of (UI elements of composerBox whose role is "AXTextArea")
|
|
732
760
|
set value of attribute "AXFocused" of textBox to true
|
|
733
761
|
set value of textBox to promptText
|
|
734
762
|
delay 0.25
|
|
@@ -739,23 +767,75 @@ on fillComposer(promptText)
|
|
|
739
767
|
end tell
|
|
740
768
|
on error
|
|
741
769
|
try
|
|
742
|
-
my clearComposer()
|
|
770
|
+
my clearComposer(textBox)
|
|
743
771
|
end try
|
|
744
772
|
return false
|
|
745
773
|
end try
|
|
746
774
|
return true
|
|
747
775
|
end fillComposer
|
|
748
776
|
|
|
749
|
-
on clearComposer()
|
|
750
|
-
|
|
751
|
-
if (count of strips) is 0 then return
|
|
777
|
+
on clearComposer(textBox)
|
|
778
|
+
if textBox is missing value then return
|
|
752
779
|
tell application "System Events" to tell process "Conductor"
|
|
753
|
-
set
|
|
754
|
-
set composerBox to item 1 of (UI elements of pane whose name is "composer")
|
|
755
|
-
set value of (item 1 of (UI elements of composerBox whose role is "AXTextArea")) to ""
|
|
780
|
+
set value of textBox to ""
|
|
756
781
|
end tell
|
|
757
782
|
end clearComposer
|
|
758
783
|
|
|
784
|
+
on pressSend(queueIt)
|
|
785
|
+
-- Return sends, Command-Return queues the prompt behind the running answer.
|
|
786
|
+
-- The choice is made out here because inside a System Events tell an ordinary
|
|
787
|
+
-- parameter name can resolve as one of its own terms.
|
|
788
|
+
if queueIt then
|
|
789
|
+
tell application "System Events" to key code 36 using {command down}
|
|
790
|
+
else
|
|
791
|
+
tell application "System Events" to key code 36
|
|
792
|
+
end if
|
|
793
|
+
end pressSend
|
|
794
|
+
|
|
795
|
+
on submitComposer(textBox, promptText, queueIt)
|
|
796
|
+
-- Press Enter, then read the composer back. Conductor consumes the draft when it
|
|
797
|
+
-- accepts a prompt, so a box still holding the text is a keystroke that did
|
|
798
|
+
-- nothing — and that read is the only receipt a run can collect about its own
|
|
799
|
+
-- send.
|
|
800
|
+
--
|
|
801
|
+
-- Why it earns its place: the caller's other receipt is the transcript row, which
|
|
802
|
+
-- costs a 6s watch (CONFIRM_WINDOW_MS in server.ts) and then a whole second run
|
|
803
|
+
-- through activate, focus, tab and fill. Measured from this Mac's own relay logs,
|
|
804
|
+
-- a send whose single fault was a first Enter Conductor ignored took ~10s from the
|
|
805
|
+
-- prompt appearing in the composer to it being sent, with the text sitting on
|
|
806
|
+
-- screen the whole way. Exactly one user row was written, so the keystroke was
|
|
807
|
+
-- lost rather than delayed.
|
|
808
|
+
--
|
|
809
|
+
-- Pressing again is safe *because* of the read, not in spite of it: the prompt is
|
|
810
|
+
-- still in the box, so nothing was consumed, so there is nothing to duplicate.
|
|
811
|
+
-- A Conductor too busy to have handled the first Enter is also too busy to answer
|
|
812
|
+
-- an AX read, which blocks here rather than handing back stale text. Bounded at
|
|
813
|
+
-- three presses — a box that survives those is stuck on something this script
|
|
814
|
+
-- cannot see, and the caller's own retry, which re-focuses and re-fills, is the
|
|
815
|
+
-- better lever than a fourth keystroke.
|
|
816
|
+
--
|
|
817
|
+
-- Returns the press that cleared the box, or 0 for a box that never cleared. The
|
|
818
|
+
-- count is the point: a rescued send is otherwise indistinguishable from one that
|
|
819
|
+
-- worked first time, so the failure this handler exists for would stop appearing
|
|
820
|
+
-- in the log the day it stopped costing 10s, and nobody could tell whether it was
|
|
821
|
+
-- fixed or merely hidden.
|
|
822
|
+
if promptText is "" then
|
|
823
|
+
my pressSend(queueIt)
|
|
824
|
+
return 1
|
|
825
|
+
end if
|
|
826
|
+
repeat with pressCount from 1 to 3
|
|
827
|
+
my pressSend(queueIt)
|
|
828
|
+
if textBox is missing value then return pressCount
|
|
829
|
+
repeat with tick from 1 to 6
|
|
830
|
+
delay 0.2
|
|
831
|
+
set seen to my composerTextOf(textBox)
|
|
832
|
+
if seen is missing value then return pressCount
|
|
833
|
+
if seen does not contain promptText then return pressCount
|
|
834
|
+
end repeat
|
|
835
|
+
end repeat
|
|
836
|
+
return 0
|
|
837
|
+
end submitComposer
|
|
838
|
+
|
|
759
839
|
on pasteComposer()
|
|
760
840
|
-- Fallback for when the composer isn't reachable: Cmd+L focuses it (after the
|
|
761
841
|
-- palette, focus sits on a button, not the text box), then paste.
|
|
@@ -807,6 +887,106 @@ on selectChatTab()
|
|
|
807
887
|
end tell
|
|
808
888
|
end selectChatTab
|
|
809
889
|
|
|
890
|
+
-- The workspace toolbar's run process. This is deliberately separate from the
|
|
891
|
+
-- chat-strip targeting above: the terminal strip is the sibling AXTabGroup whose
|
|
892
|
+
-- direct radio buttons include Setup / Run / Terminal, and its task button is
|
|
893
|
+
-- named "Run <task>" or "Stop <task>". Conductor may add more terminal tabs, so
|
|
894
|
+
-- identify the strip by the Run radio rather than by its position.
|
|
895
|
+
on runStrip()
|
|
896
|
+
set matches to {}
|
|
897
|
+
repeat with entry in my tabGroups()
|
|
898
|
+
set tg to contents of entry
|
|
899
|
+
set hasRunTab to false
|
|
900
|
+
repeat with r in my stripRadios(tg)
|
|
901
|
+
if (my axName(contents of r)) is "Run" then set hasRunTab to true
|
|
902
|
+
end repeat
|
|
903
|
+
if hasRunTab then set end of matches to tg
|
|
904
|
+
end repeat
|
|
905
|
+
if (count of matches) is 0 then error "couldn't find Conductor's Run panel"
|
|
906
|
+
if (count of matches) > 1 then error "can't tell which panel holds Conductor's Run task"
|
|
907
|
+
return item 1 of matches
|
|
908
|
+
end runStrip
|
|
909
|
+
|
|
910
|
+
on runTaskButton(tg)
|
|
911
|
+
set matches to {}
|
|
912
|
+
tell application "System Events" to tell process "Conductor"
|
|
913
|
+
repeat with entry in (UI elements of tg whose role is "AXButton")
|
|
914
|
+
set node to contents of entry
|
|
915
|
+
set label to my axName(node)
|
|
916
|
+
if label starts with "Run " or label starts with "Stop " then set end of matches to node
|
|
917
|
+
end repeat
|
|
918
|
+
end tell
|
|
919
|
+
if (count of matches) is 0 then error "this workspace has no selected Run task"
|
|
920
|
+
if (count of matches) > 1 then error "Conductor exposed more than one selected Run task"
|
|
921
|
+
return item 1 of matches
|
|
922
|
+
end runTaskButton
|
|
923
|
+
|
|
924
|
+
on runTaskState(btn)
|
|
925
|
+
set label to my axName(btn)
|
|
926
|
+
if label starts with "Stop " then return "running"
|
|
927
|
+
if label starts with "Run " then return "stopped"
|
|
928
|
+
error "couldn't read Conductor's Run task state"
|
|
929
|
+
end runTaskState
|
|
930
|
+
|
|
931
|
+
on runTaskName(btn)
|
|
932
|
+
set label to my axName(btn)
|
|
933
|
+
if label starts with "Stop " then return text 6 thru -1 of label
|
|
934
|
+
if label starts with "Run " then return text 5 thru -1 of label
|
|
935
|
+
return label
|
|
936
|
+
end runTaskName
|
|
937
|
+
|
|
938
|
+
on openRunPorts(tg)
|
|
939
|
+
set found to {}
|
|
940
|
+
tell application "System Events" to tell process "Conductor"
|
|
941
|
+
repeat with entry in (UI elements of tg whose role is "AXButton")
|
|
942
|
+
set label to my axName(contents of entry)
|
|
943
|
+
if label starts with "Open :" then set end of found to text 7 thru -1 of label
|
|
944
|
+
end repeat
|
|
945
|
+
end tell
|
|
946
|
+
return found
|
|
947
|
+
end openRunPorts
|
|
948
|
+
|
|
949
|
+
on setRunTask(wantRunning)
|
|
950
|
+
my activateConductor()
|
|
951
|
+
my focusWorkspace()
|
|
952
|
+
set tg to my runStrip()
|
|
953
|
+
my assertWorkspace(tg)
|
|
954
|
+
set btn to my runTaskButton(tg)
|
|
955
|
+
set beforeState to my runTaskState(btn)
|
|
956
|
+
set taskName to my runTaskName(btn)
|
|
957
|
+
set wantedState to "stopped"
|
|
958
|
+
if wantRunning then set wantedState to "running"
|
|
959
|
+
set changed to "false"
|
|
960
|
+
|
|
961
|
+
if beforeState is not wantedState then
|
|
962
|
+
tell application "System Events" to tell process "Conductor"
|
|
963
|
+
perform action "AXPress" of btn
|
|
964
|
+
end tell
|
|
965
|
+
set changed to "true"
|
|
966
|
+
end if
|
|
967
|
+
|
|
968
|
+
-- The panel re-renders after the press, invalidating every old AX handle.
|
|
969
|
+
-- Re-find it on each poll and require the opposite label before reporting the
|
|
970
|
+
-- action as complete. A started web server gets a short second window in which
|
|
971
|
+
-- Conductor can surface its "Open :<port>" button; non-server tasks simply
|
|
972
|
+
-- return with an empty port list.
|
|
973
|
+
set currentState to beforeState
|
|
974
|
+
set ports to {}
|
|
975
|
+
repeat with attempt from 1 to 44
|
|
976
|
+
set tg to my runStrip()
|
|
977
|
+
set btn to my runTaskButton(tg)
|
|
978
|
+
set currentState to my runTaskState(btn)
|
|
979
|
+
set taskName to my runTaskName(btn)
|
|
980
|
+
if currentState is wantedState then
|
|
981
|
+
set ports to my openRunPorts(tg)
|
|
982
|
+
if not wantRunning or (count of ports) > 0 or attempt > 20 then exit repeat
|
|
983
|
+
end if
|
|
984
|
+
delay 0.25
|
|
985
|
+
end repeat
|
|
986
|
+
if currentState is not wantedState then error "Conductor's Run task did not switch to " & wantedState
|
|
987
|
+
return currentState & tab & taskName & tab & changed & tab & my joinList(ports, ",")
|
|
988
|
+
end setRunTask
|
|
989
|
+
|
|
810
990
|
on cancelAgent()
|
|
811
991
|
-- Stop the answer this chat is streaming: Conductor's own "Cancel agent"
|
|
812
992
|
-- command, Command-Shift-Delete (key code 51). Taken from its Keyboard
|