@phenx-inc/ctlsurf 0.1.2 → 0.1.4
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 +37 -78
- package/out/headless/index.mjs.map +2 -2
- package/out/main/index.js +3743 -112
- package/out/renderer/assets/{cssMode-DL0XItGB.js → cssMode-CY6x0qXW.js} +3 -3
- package/out/renderer/assets/{freemarker2-CrOEuDcF.js → freemarker2-BXSW9BAX.js} +1 -1
- package/out/renderer/assets/{handlebars-D4QYaBof.js → handlebars-BYUZ1IOs.js} +1 -1
- package/out/renderer/assets/{html-B2Dqk2ai.js → html-DPocQM4t.js} +1 -1
- package/out/renderer/assets/{htmlMode-CdZ0Prhd.js → htmlMode-CsPinKYA.js} +3 -3
- package/out/renderer/assets/{index-pZmE1QXB.js → index-Bml7oDn9.js} +84 -36
- package/out/renderer/assets/{index-CJ6RsQWP.css → index-DK9wLFFm.css} +146 -0
- package/out/renderer/assets/{javascript-CK8zNQXj.js → javascript-_HVGB-lj.js} +2 -2
- package/out/renderer/assets/{jsonMode-Cewaellc.js → jsonMode-JbrRQBOU.js} +3 -3
- package/out/renderer/assets/{liquid-Bd3GPNs2.js → liquid-B7izKdqo.js} +1 -1
- package/out/renderer/assets/{lspLanguageFeatures-DSDH7BnA.js → lspLanguageFeatures-DzxH499X.js} +1 -1
- package/out/renderer/assets/{mdx-CCPVCrXC.js → mdx-CmvUeYLw.js} +1 -1
- package/out/renderer/assets/{python-34jOtlcC.js → python-DJqYTFoi.js} +1 -1
- package/out/renderer/assets/{razor-DXRw694z.js → razor-CGEA5nUK.js} +1 -1
- package/out/renderer/assets/{tsMode-CmND5_wB.js → tsMode-CN0FOHMy.js} +1 -1
- package/out/renderer/assets/{typescript-BNNI0Euv.js → typescript-CIn-DSfY.js} +1 -1
- package/out/renderer/assets/{xml-CgdndrNB.js → xml-C5t3U2jS.js} +1 -1
- package/out/renderer/assets/{yaml-DNWPIf1s.js → yaml-n-Jb6xf1.js} +1 -1
- package/out/renderer/index.html +2 -2
- package/package.json +6 -4
- package/src/main/bridge.ts +25 -74
- package/src/main/orchestrator.ts +9 -11
- package/src/main/workerWs.ts +10 -2
- package/src/renderer/App.tsx +38 -12
- package/src/renderer/components/AgentPicker.tsx +49 -0
- package/src/renderer/styles.css +146 -0
package/out/headless/index.mjs
CHANGED
|
@@ -227,54 +227,24 @@ var CtlsurfApi = class {
|
|
|
227
227
|
|
|
228
228
|
// src/main/bridge.ts
|
|
229
229
|
var ConversationBridge = class {
|
|
230
|
-
|
|
231
|
-
logBlockId = null;
|
|
232
|
-
pageId = null;
|
|
230
|
+
wsClient = null;
|
|
233
231
|
buffer = "";
|
|
234
232
|
flushTimer = null;
|
|
235
233
|
flushIntervalMs = 3e3;
|
|
236
234
|
// flush every 3 seconds
|
|
237
|
-
agentName = "shell";
|
|
238
235
|
sessionActive = false;
|
|
239
236
|
inputBuffer = "";
|
|
240
|
-
|
|
241
|
-
this.
|
|
237
|
+
setWsClient(ws) {
|
|
238
|
+
this.wsClient = ws;
|
|
242
239
|
}
|
|
243
240
|
/**
|
|
244
241
|
* Start a new logging session.
|
|
245
|
-
* Creates a log block on the given dataspace page.
|
|
246
242
|
*/
|
|
247
|
-
|
|
248
|
-
if (!this.api.getApiKey()) {
|
|
249
|
-
console.log("[bridge] No API key set, skipping session logging");
|
|
250
|
-
return;
|
|
251
|
-
}
|
|
252
|
-
this.pageId = dataspacePageId;
|
|
253
|
-
this.agentName = agentName;
|
|
243
|
+
startSession() {
|
|
254
244
|
this.buffer = "";
|
|
255
245
|
this.inputBuffer = "";
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
const block = await this.api.createBlock(dataspacePageId, {
|
|
259
|
-
type: "log",
|
|
260
|
-
title: `${agentName} \u2014 ${timestamp} \u2014 ${cwd}`,
|
|
261
|
-
props: {
|
|
262
|
-
entries: [],
|
|
263
|
-
max_entries: 1e3
|
|
264
|
-
}
|
|
265
|
-
});
|
|
266
|
-
this.logBlockId = block.id;
|
|
267
|
-
this.sessionActive = true;
|
|
268
|
-
await this.api.appendLog(this.logBlockId, "session_start", `Started ${agentName} session`, {
|
|
269
|
-
agent: agentName,
|
|
270
|
-
cwd,
|
|
271
|
-
timestamp
|
|
272
|
-
});
|
|
273
|
-
console.log(`[bridge] Session started, log block: ${this.logBlockId}`);
|
|
274
|
-
} catch (err) {
|
|
275
|
-
console.error(`[bridge] Failed to start session:`, err.message);
|
|
276
|
-
this.sessionActive = false;
|
|
277
|
-
}
|
|
246
|
+
this.sessionActive = true;
|
|
247
|
+
console.log("[bridge] Session started");
|
|
278
248
|
}
|
|
279
249
|
/**
|
|
280
250
|
* Feed terminal output data into the bridge.
|
|
@@ -297,57 +267,44 @@ var ConversationBridge = class {
|
|
|
297
267
|
if (data.includes("\r") || data.includes("\n")) {
|
|
298
268
|
const input = this.inputBuffer.trim();
|
|
299
269
|
if (input.length > 0) {
|
|
300
|
-
this.
|
|
270
|
+
this.sendEntry("user_input", input);
|
|
301
271
|
}
|
|
302
272
|
this.inputBuffer = "";
|
|
303
273
|
}
|
|
304
274
|
}
|
|
305
275
|
/**
|
|
306
|
-
* Flush buffered output
|
|
276
|
+
* Flush buffered output via WebSocket.
|
|
307
277
|
*/
|
|
308
|
-
|
|
309
|
-
if (
|
|
278
|
+
flush() {
|
|
279
|
+
if (this.buffer.length === 0) return;
|
|
310
280
|
const chunk = this.buffer;
|
|
311
281
|
this.buffer = "";
|
|
312
282
|
const cleaned = stripAnsi(chunk);
|
|
313
283
|
if (cleaned.trim().length === 0) return;
|
|
314
|
-
|
|
315
|
-
await this.api.appendLog(this.logBlockId, "terminal_output", cleaned);
|
|
316
|
-
} catch (err) {
|
|
317
|
-
console.error(`[bridge] Failed to append log:`, err.message);
|
|
318
|
-
}
|
|
284
|
+
this.sendEntry("terminal_output", cleaned);
|
|
319
285
|
}
|
|
320
286
|
/**
|
|
321
|
-
*
|
|
287
|
+
* Send an entry to the backend via WebSocket.
|
|
322
288
|
*/
|
|
323
|
-
|
|
324
|
-
if (!this.
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
}
|
|
289
|
+
sendEntry(type, content) {
|
|
290
|
+
if (!this.wsClient) return;
|
|
291
|
+
this.wsClient.sendChatLog({
|
|
292
|
+
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
293
|
+
type,
|
|
294
|
+
content
|
|
295
|
+
});
|
|
330
296
|
}
|
|
331
297
|
/**
|
|
332
298
|
* End the current session.
|
|
333
299
|
*/
|
|
334
|
-
|
|
335
|
-
if (!this.sessionActive
|
|
336
|
-
|
|
337
|
-
try {
|
|
338
|
-
await this.api.appendLog(this.logBlockId, "session_end", `Session ended (exit code: ${exitCode ?? "unknown"})`, {
|
|
339
|
-
agent: this.agentName,
|
|
340
|
-
exitCode
|
|
341
|
-
});
|
|
342
|
-
} catch (err) {
|
|
343
|
-
console.error(`[bridge] Failed to log session end:`, err.message);
|
|
344
|
-
}
|
|
300
|
+
endSession() {
|
|
301
|
+
if (!this.sessionActive) return;
|
|
302
|
+
this.flush();
|
|
345
303
|
if (this.flushTimer) {
|
|
346
304
|
clearTimeout(this.flushTimer);
|
|
347
305
|
this.flushTimer = null;
|
|
348
306
|
}
|
|
349
307
|
this.sessionActive = false;
|
|
350
|
-
this.logBlockId = null;
|
|
351
308
|
this.buffer = "";
|
|
352
309
|
this.inputBuffer = "";
|
|
353
310
|
console.log("[bridge] Session ended");
|
|
@@ -360,6 +317,8 @@ function stripAnsi(str) {
|
|
|
360
317
|
// src/main/workerWs.ts
|
|
361
318
|
import os from "os";
|
|
362
319
|
import crypto from "crypto";
|
|
320
|
+
import WsModule from "ws";
|
|
321
|
+
var WS = typeof WebSocket !== "undefined" ? WebSocket : WsModule;
|
|
363
322
|
function log(...args) {
|
|
364
323
|
try {
|
|
365
324
|
console.log(...args);
|
|
@@ -451,6 +410,9 @@ var WorkerWsClient = class {
|
|
|
451
410
|
sendTerminalResize(cols, rows) {
|
|
452
411
|
this.send({ type: "terminal_resize", cols, rows });
|
|
453
412
|
}
|
|
413
|
+
sendChatLog(entry) {
|
|
414
|
+
this.send({ type: "chat_log", entry });
|
|
415
|
+
}
|
|
454
416
|
doConnect() {
|
|
455
417
|
if (!this.apiKey || !this.registration) {
|
|
456
418
|
log("[worker-ws] No API key or registration, skipping connect");
|
|
@@ -484,7 +446,7 @@ var WorkerWsClient = class {
|
|
|
484
446
|
const url = `${wsBase}/api/ws/worker?token=${encodeURIComponent(this.apiKey)}`;
|
|
485
447
|
log(`[worker-ws] Connecting to ${url.replace(/token=.*/, "token=***")}...`);
|
|
486
448
|
try {
|
|
487
|
-
this.ws = new
|
|
449
|
+
this.ws = new WS(url);
|
|
488
450
|
} catch (err) {
|
|
489
451
|
log("[worker-ws] Failed to create WebSocket:", err);
|
|
490
452
|
this.scheduleReconnect();
|
|
@@ -571,7 +533,7 @@ var WorkerWsClient = class {
|
|
|
571
533
|
}
|
|
572
534
|
}
|
|
573
535
|
send(data) {
|
|
574
|
-
if (this.ws && this.ws.readyState ===
|
|
536
|
+
if (this.ws && this.ws.readyState === WS.OPEN) {
|
|
575
537
|
this.ws.send(JSON.stringify(data));
|
|
576
538
|
}
|
|
577
539
|
}
|
|
@@ -625,7 +587,7 @@ var Orchestrator = class {
|
|
|
625
587
|
events;
|
|
626
588
|
// Core services
|
|
627
589
|
ctlsurfApi = new CtlsurfApi();
|
|
628
|
-
bridge = new ConversationBridge(
|
|
590
|
+
bridge = new ConversationBridge();
|
|
629
591
|
workerWs;
|
|
630
592
|
// State
|
|
631
593
|
ptyManager = null;
|
|
@@ -668,6 +630,7 @@ var Orchestrator = class {
|
|
|
668
630
|
this.ptyManager?.write(data);
|
|
669
631
|
}
|
|
670
632
|
});
|
|
633
|
+
this.bridge.setWsClient(this.workerWs);
|
|
671
634
|
}
|
|
672
635
|
// ─── Settings ───────────────────────────────────
|
|
673
636
|
getActiveProfile() {
|
|
@@ -821,7 +784,7 @@ var Orchestrator = class {
|
|
|
821
784
|
// ─── PTY & Agent ────────────────────────────────
|
|
822
785
|
async spawnAgent(agent, cwd) {
|
|
823
786
|
if (this.ptyManager) {
|
|
824
|
-
|
|
787
|
+
this.bridge.endSession();
|
|
825
788
|
this.ptyManager.kill();
|
|
826
789
|
}
|
|
827
790
|
this.currentAgent = agent;
|
|
@@ -837,18 +800,14 @@ var Orchestrator = class {
|
|
|
837
800
|
this.streamTerminalData(data);
|
|
838
801
|
});
|
|
839
802
|
const thisPtyManager = this.ptyManager;
|
|
840
|
-
this.ptyManager.onExit(
|
|
803
|
+
this.ptyManager.onExit((exitCode) => {
|
|
841
804
|
this.events.onPtyExit(exitCode);
|
|
842
|
-
|
|
805
|
+
this.bridge.endSession();
|
|
843
806
|
if (thisPtyManager === this.ptyManager && this.currentAgent && isCodingAgent(this.currentAgent)) {
|
|
844
807
|
this.workerWs.disconnect();
|
|
845
808
|
}
|
|
846
809
|
});
|
|
847
|
-
|
|
848
|
-
const dataspacePageId = profile.dataspacePageId || process.env.CTLSURF_DATASPACE_PAGE_ID || "";
|
|
849
|
-
if (dataspacePageId && this.ctlsurfApi.getApiKey()) {
|
|
850
|
-
await this.bridge.startSession(dataspacePageId, agent.name, cwd);
|
|
851
|
-
}
|
|
810
|
+
this.bridge.startSession();
|
|
852
811
|
if (isCodingAgent(agent)) {
|
|
853
812
|
this.connectWorkerWs(agent, cwd);
|
|
854
813
|
} else {
|
|
@@ -865,7 +824,7 @@ var Orchestrator = class {
|
|
|
865
824
|
this.workerWs.sendTerminalResize(cols, rows);
|
|
866
825
|
}
|
|
867
826
|
async killAgent() {
|
|
868
|
-
|
|
827
|
+
this.bridge.endSession();
|
|
869
828
|
this.ptyManager?.kill();
|
|
870
829
|
this.ptyManager = null;
|
|
871
830
|
if (this.currentAgent && isCodingAgent(this.currentAgent)) {
|
|
@@ -914,7 +873,7 @@ var Orchestrator = class {
|
|
|
914
873
|
}
|
|
915
874
|
// ─── Shutdown ───────────────────────────────────
|
|
916
875
|
async shutdown() {
|
|
917
|
-
|
|
876
|
+
this.bridge.endSession();
|
|
918
877
|
this.ptyManager?.kill();
|
|
919
878
|
this.ptyManager = null;
|
|
920
879
|
this.workerWs.disconnect();
|