@phenx-inc/ctlsurf 0.1.21 → 0.2.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/out/headless/index.mjs +91 -57
- package/out/headless/index.mjs.map +2 -2
- package/out/main/index.js +145 -63
- package/out/preload/index.js +9 -8
- package/out/renderer/assets/{cssMode-C6bY9C4O.js → cssMode-D3kH1Kju.js} +3 -3
- package/out/renderer/assets/{freemarker2-CkAJiX1K.js → freemarker2-BCHZUSLb.js} +1 -1
- package/out/renderer/assets/{handlebars-DnLXVUXp.js → handlebars-DKx-Fw-H.js} +1 -1
- package/out/renderer/assets/{html-Ds5-qvDh.js → html-BSCM04uL.js} +1 -1
- package/out/renderer/assets/{htmlMode-DYFYy4MK.js → htmlMode-BucU1MUc.js} +3 -3
- package/out/renderer/assets/{index-DwSsD_Xm.js → index-BsdOeO0U.js} +230 -101
- package/out/renderer/assets/{index-DK9wLFFm.css → index-BzF7I1my.css} +111 -0
- package/out/renderer/assets/{javascript-CiHhG2a9.js → javascript-bPY5C4uq.js} +2 -2
- package/out/renderer/assets/{jsonMode-DdDRlbXP.js → jsonMode-BmJotb6E.js} +3 -3
- package/out/renderer/assets/{liquid-BP5mb-uD.js → liquid-Cja_Pzh3.js} +1 -1
- package/out/renderer/assets/{lspLanguageFeatures-Dljhj5Gh.js → lspLanguageFeatures-hoVZfVKv.js} +1 -1
- package/out/renderer/assets/{mdx-D4u3N7dt.js → mdx-C0s81MOq.js} +1 -1
- package/out/renderer/assets/{python-BQDHXVwp.js → python-CulkBOJr.js} +1 -1
- package/out/renderer/assets/{razor-BfXW9cDc.js → razor-czmzhwVZ.js} +1 -1
- package/out/renderer/assets/{tsMode-BGTjG8Ow.js → tsMode-B90EqYGx.js} +1 -1
- package/out/renderer/assets/{typescript-422MU_YO.js → typescript-Ckc6emP2.js} +1 -1
- package/out/renderer/assets/{xml-B6EKhHiy.js → xml-CKh-JyGN.js} +1 -1
- package/out/renderer/assets/{yaml-LkO_eGYb.js → yaml-B49zLim4.js} +1 -1
- package/out/renderer/index.html +2 -2
- package/package.json +1 -1
- package/src/main/headless.ts +8 -7
- package/src/main/index.ts +87 -13
- package/src/main/orchestrator.ts +98 -54
- package/src/preload/index.ts +16 -14
- package/src/renderer/App.tsx +161 -43
- package/src/renderer/components/TerminalPanel.tsx +101 -59
- package/src/renderer/styles.css +111 -0
package/out/headless/index.mjs
CHANGED
|
@@ -591,16 +591,14 @@ var Orchestrator = class {
|
|
|
591
591
|
bridge = new ConversationBridge();
|
|
592
592
|
workerWs;
|
|
593
593
|
// State
|
|
594
|
-
|
|
594
|
+
tabs = /* @__PURE__ */ new Map();
|
|
595
|
+
activeTabId = null;
|
|
595
596
|
currentAgent = null;
|
|
596
597
|
currentCwd = null;
|
|
597
598
|
settings = {
|
|
598
599
|
activeProfile: "production",
|
|
599
600
|
profiles: { ...DEFAULT_PROFILES }
|
|
600
601
|
};
|
|
601
|
-
// Terminal stream batching
|
|
602
|
-
termStreamBuffer = "";
|
|
603
|
-
termStreamTimer = null;
|
|
604
602
|
constructor(settingsDir, events) {
|
|
605
603
|
this.settingsDir = settingsDir;
|
|
606
604
|
this.events = events;
|
|
@@ -614,8 +612,9 @@ var Orchestrator = class {
|
|
|
614
612
|
events.onWorkerMessage(message);
|
|
615
613
|
this.workerWs.sendAck(message.id);
|
|
616
614
|
if (message.type === "prompt" || message.type === "task_dispatch") {
|
|
617
|
-
|
|
618
|
-
|
|
615
|
+
const activeTab = this.activeTabId ? this.tabs.get(this.activeTabId) : null;
|
|
616
|
+
if (activeTab) {
|
|
617
|
+
activeTab.ptyManager.write(message.content + "\r");
|
|
619
618
|
this.bridge.feedInput(message.content);
|
|
620
619
|
}
|
|
621
620
|
}
|
|
@@ -628,7 +627,8 @@ var Orchestrator = class {
|
|
|
628
627
|
}
|
|
629
628
|
},
|
|
630
629
|
onTerminalInput: (data) => {
|
|
631
|
-
this.
|
|
630
|
+
const activeTab = this.activeTabId ? this.tabs.get(this.activeTabId) : null;
|
|
631
|
+
activeTab?.ptyManager.write(data);
|
|
632
632
|
}
|
|
633
633
|
});
|
|
634
634
|
this.bridge.setWsClient(this.workerWs);
|
|
@@ -782,31 +782,41 @@ var Orchestrator = class {
|
|
|
782
782
|
this.saveSettings();
|
|
783
783
|
return { ok: true };
|
|
784
784
|
}
|
|
785
|
-
// ─── PTY & Agent
|
|
786
|
-
async spawnAgent(agent, cwd) {
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
785
|
+
// ─── PTY & Agent (multi-tab) ─────────────────────
|
|
786
|
+
async spawnAgent(tabId, agent, cwd) {
|
|
787
|
+
const existing = this.tabs.get(tabId);
|
|
788
|
+
if (existing) {
|
|
789
|
+
if (existing.termStreamTimer) clearTimeout(existing.termStreamTimer);
|
|
790
|
+
existing.ptyManager.kill();
|
|
791
|
+
this.tabs.delete(tabId);
|
|
790
792
|
}
|
|
791
793
|
this.currentAgent = agent;
|
|
792
794
|
const prevCwd = this.currentCwd;
|
|
793
795
|
this.currentCwd = cwd;
|
|
796
|
+
this.activeTabId = tabId;
|
|
794
797
|
if (prevCwd !== cwd) {
|
|
795
798
|
this.events.onCwdChanged();
|
|
796
799
|
}
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
this.
|
|
800
|
+
const ptyManager = new PtyManager(agent, cwd);
|
|
801
|
+
const tab = { ptyManager, agent, cwd, termStreamBuffer: "", termStreamTimer: null };
|
|
802
|
+
this.tabs.set(tabId, tab);
|
|
803
|
+
ptyManager.onData((data) => {
|
|
804
|
+
this.events.onPtyData(tabId, data);
|
|
805
|
+
if (tabId === this.activeTabId) {
|
|
806
|
+
this.bridge.feedOutput(data);
|
|
807
|
+
this.streamTerminalData(tabId, data);
|
|
808
|
+
}
|
|
802
809
|
});
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
this.
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
810
|
+
ptyManager.onExit(async (exitCode) => {
|
|
811
|
+
this.events.onPtyExit(tabId, exitCode);
|
|
812
|
+
if (tabId === this.activeTabId) {
|
|
813
|
+
this.bridge.endSession();
|
|
814
|
+
if (this.currentAgent && isCodingAgent(this.currentAgent)) {
|
|
815
|
+
this.workerWs.disconnect();
|
|
816
|
+
}
|
|
809
817
|
}
|
|
818
|
+
const t = this.tabs.get(tabId);
|
|
819
|
+
if (t?.termStreamTimer) clearTimeout(t.termStreamTimer);
|
|
810
820
|
});
|
|
811
821
|
this.bridge.startSession();
|
|
812
822
|
if (isCodingAgent(agent)) {
|
|
@@ -816,23 +826,45 @@ var Orchestrator = class {
|
|
|
816
826
|
this.checkProjectStatus(cwd);
|
|
817
827
|
}
|
|
818
828
|
}
|
|
819
|
-
writePty(data) {
|
|
820
|
-
this.ptyManager
|
|
821
|
-
this.
|
|
829
|
+
writePty(tabId, data) {
|
|
830
|
+
this.tabs.get(tabId)?.ptyManager.write(data);
|
|
831
|
+
if (tabId === this.activeTabId) {
|
|
832
|
+
this.bridge.feedInput(data);
|
|
833
|
+
}
|
|
822
834
|
}
|
|
823
|
-
resizePty(cols, rows) {
|
|
824
|
-
this.ptyManager
|
|
825
|
-
this.
|
|
826
|
-
|
|
835
|
+
resizePty(tabId, cols, rows) {
|
|
836
|
+
this.tabs.get(tabId)?.ptyManager.resize(cols, rows);
|
|
837
|
+
if (tabId === this.activeTabId) {
|
|
838
|
+
this.bridge.resize(cols, rows);
|
|
839
|
+
this.workerWs.sendTerminalResize(cols, rows);
|
|
840
|
+
}
|
|
827
841
|
}
|
|
828
|
-
async
|
|
829
|
-
this.
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
842
|
+
async killTab(tabId) {
|
|
843
|
+
const tab = this.tabs.get(tabId);
|
|
844
|
+
if (!tab) return;
|
|
845
|
+
if (tab.termStreamTimer) clearTimeout(tab.termStreamTimer);
|
|
846
|
+
tab.ptyManager.kill();
|
|
847
|
+
this.tabs.delete(tabId);
|
|
848
|
+
if (tabId === this.activeTabId) {
|
|
849
|
+
this.bridge.endSession();
|
|
850
|
+
if (isCodingAgent(tab.agent)) {
|
|
851
|
+
this.workerWs.disconnect();
|
|
852
|
+
}
|
|
853
|
+
const remaining = [...this.tabs.keys()];
|
|
854
|
+
this.activeTabId = remaining.length > 0 ? remaining[remaining.length - 1] : null;
|
|
855
|
+
}
|
|
856
|
+
}
|
|
857
|
+
setActiveTab(tabId) {
|
|
858
|
+
this.activeTabId = tabId;
|
|
859
|
+
const tab = this.tabs.get(tabId);
|
|
860
|
+
if (tab) {
|
|
861
|
+
this.currentAgent = tab.agent;
|
|
862
|
+
this.currentCwd = tab.cwd;
|
|
834
863
|
}
|
|
835
864
|
}
|
|
865
|
+
getTabIds() {
|
|
866
|
+
return [...this.tabs.keys()];
|
|
867
|
+
}
|
|
836
868
|
// ─── Worker WebSocket ───────────────────────────
|
|
837
869
|
connectWorkerWs(agent, cwd) {
|
|
838
870
|
const profile = this.getActiveProfile();
|
|
@@ -861,28 +893,29 @@ var Orchestrator = class {
|
|
|
861
893
|
this.events.onWorkerStatus("no_project");
|
|
862
894
|
}
|
|
863
895
|
}
|
|
864
|
-
streamTerminalData(data) {
|
|
865
|
-
this.
|
|
866
|
-
if (!
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
896
|
+
streamTerminalData(tabId, data) {
|
|
897
|
+
const tab = this.tabs.get(tabId);
|
|
898
|
+
if (!tab) return;
|
|
899
|
+
tab.termStreamBuffer += data;
|
|
900
|
+
if (!tab.termStreamTimer) {
|
|
901
|
+
tab.termStreamTimer = setTimeout(() => {
|
|
902
|
+
if (tab.termStreamBuffer) {
|
|
903
|
+
this.workerWs.sendTerminalData(tab.termStreamBuffer);
|
|
904
|
+
tab.termStreamBuffer = "";
|
|
871
905
|
}
|
|
872
|
-
|
|
906
|
+
tab.termStreamTimer = null;
|
|
873
907
|
}, TERM_STREAM_INTERVAL_MS);
|
|
874
908
|
}
|
|
875
909
|
}
|
|
876
910
|
// ─── Shutdown ───────────────────────────────────
|
|
877
911
|
async shutdown() {
|
|
878
912
|
this.bridge.endSession();
|
|
879
|
-
this.
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
if (this.termStreamTimer) {
|
|
883
|
-
clearTimeout(this.termStreamTimer);
|
|
884
|
-
this.termStreamTimer = null;
|
|
913
|
+
for (const [, tab] of this.tabs) {
|
|
914
|
+
if (tab.termStreamTimer) clearTimeout(tab.termStreamTimer);
|
|
915
|
+
tab.ptyManager.kill();
|
|
885
916
|
}
|
|
917
|
+
this.tabs.clear();
|
|
918
|
+
this.workerWs.disconnect();
|
|
886
919
|
}
|
|
887
920
|
};
|
|
888
921
|
|
|
@@ -1209,10 +1242,10 @@ async function main() {
|
|
|
1209
1242
|
});
|
|
1210
1243
|
tui.init();
|
|
1211
1244
|
const orchestrator = new Orchestrator(settingsDir, {
|
|
1212
|
-
onPtyData: (data) => {
|
|
1245
|
+
onPtyData: (_tabId, data) => {
|
|
1213
1246
|
tui.writePtyData(data);
|
|
1214
1247
|
},
|
|
1215
|
-
onPtyExit: (code) => {
|
|
1248
|
+
onPtyExit: (_tabId, code) => {
|
|
1216
1249
|
tui.destroy();
|
|
1217
1250
|
console.log(`Agent exited with code ${code}`);
|
|
1218
1251
|
orchestrator.shutdown().then(() => process.exit(code));
|
|
@@ -1233,12 +1266,13 @@ async function main() {
|
|
|
1233
1266
|
if (args.profile) orchestrator.switchProfile(args.profile);
|
|
1234
1267
|
if (args.apiKey) orchestrator.overrideApiKey(args.apiKey);
|
|
1235
1268
|
if (args.baseUrl) orchestrator.overrideBaseUrl(args.baseUrl);
|
|
1269
|
+
const HEADLESS_TAB = "headless";
|
|
1236
1270
|
const ptySize = tui.getPtySize();
|
|
1237
|
-
await orchestrator.spawnAgent(agent, args.cwd);
|
|
1238
|
-
orchestrator.resizePty(ptySize.cols, ptySize.rows);
|
|
1271
|
+
await orchestrator.spawnAgent(HEADLESS_TAB, agent, args.cwd);
|
|
1272
|
+
orchestrator.resizePty(HEADLESS_TAB, ptySize.cols, ptySize.rows);
|
|
1239
1273
|
if (isCodingAgent(agent)) {
|
|
1240
1274
|
setTimeout(() => {
|
|
1241
|
-
orchestrator.writePty("hello\r");
|
|
1275
|
+
orchestrator.writePty(HEADLESS_TAB, "hello\r");
|
|
1242
1276
|
}, 1e3);
|
|
1243
1277
|
}
|
|
1244
1278
|
const SCROLL_UP_RE = /\x1b\[<64;\d+;\d+M/;
|
|
@@ -1255,7 +1289,7 @@ async function main() {
|
|
|
1255
1289
|
if (SCROLL_UP_RE.test(str) || SCROLL_DOWN_RE.test(str)) {
|
|
1256
1290
|
return;
|
|
1257
1291
|
}
|
|
1258
|
-
orchestrator.writePty(str);
|
|
1292
|
+
orchestrator.writePty(HEADLESS_TAB, str);
|
|
1259
1293
|
});
|
|
1260
1294
|
}
|
|
1261
1295
|
process.stdout.on("resize", () => {
|
|
@@ -1263,7 +1297,7 @@ async function main() {
|
|
|
1263
1297
|
const rows = process.stdout.rows || 24;
|
|
1264
1298
|
tui.resize(cols, rows);
|
|
1265
1299
|
const size = tui.getPtySize();
|
|
1266
|
-
orchestrator.resizePty(size.cols, size.rows);
|
|
1300
|
+
orchestrator.resizePty(HEADLESS_TAB, size.cols, size.rows);
|
|
1267
1301
|
});
|
|
1268
1302
|
const shutdown = async () => {
|
|
1269
1303
|
if (process.stdin.isTTY) {
|