@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.
Files changed (29) hide show
  1. package/out/headless/index.mjs +37 -78
  2. package/out/headless/index.mjs.map +2 -2
  3. package/out/main/index.js +3743 -112
  4. package/out/renderer/assets/{cssMode-DL0XItGB.js → cssMode-CY6x0qXW.js} +3 -3
  5. package/out/renderer/assets/{freemarker2-CrOEuDcF.js → freemarker2-BXSW9BAX.js} +1 -1
  6. package/out/renderer/assets/{handlebars-D4QYaBof.js → handlebars-BYUZ1IOs.js} +1 -1
  7. package/out/renderer/assets/{html-B2Dqk2ai.js → html-DPocQM4t.js} +1 -1
  8. package/out/renderer/assets/{htmlMode-CdZ0Prhd.js → htmlMode-CsPinKYA.js} +3 -3
  9. package/out/renderer/assets/{index-pZmE1QXB.js → index-Bml7oDn9.js} +84 -36
  10. package/out/renderer/assets/{index-CJ6RsQWP.css → index-DK9wLFFm.css} +146 -0
  11. package/out/renderer/assets/{javascript-CK8zNQXj.js → javascript-_HVGB-lj.js} +2 -2
  12. package/out/renderer/assets/{jsonMode-Cewaellc.js → jsonMode-JbrRQBOU.js} +3 -3
  13. package/out/renderer/assets/{liquid-Bd3GPNs2.js → liquid-B7izKdqo.js} +1 -1
  14. package/out/renderer/assets/{lspLanguageFeatures-DSDH7BnA.js → lspLanguageFeatures-DzxH499X.js} +1 -1
  15. package/out/renderer/assets/{mdx-CCPVCrXC.js → mdx-CmvUeYLw.js} +1 -1
  16. package/out/renderer/assets/{python-34jOtlcC.js → python-DJqYTFoi.js} +1 -1
  17. package/out/renderer/assets/{razor-DXRw694z.js → razor-CGEA5nUK.js} +1 -1
  18. package/out/renderer/assets/{tsMode-CmND5_wB.js → tsMode-CN0FOHMy.js} +1 -1
  19. package/out/renderer/assets/{typescript-BNNI0Euv.js → typescript-CIn-DSfY.js} +1 -1
  20. package/out/renderer/assets/{xml-CgdndrNB.js → xml-C5t3U2jS.js} +1 -1
  21. package/out/renderer/assets/{yaml-DNWPIf1s.js → yaml-n-Jb6xf1.js} +1 -1
  22. package/out/renderer/index.html +2 -2
  23. package/package.json +6 -4
  24. package/src/main/bridge.ts +25 -74
  25. package/src/main/orchestrator.ts +9 -11
  26. package/src/main/workerWs.ts +10 -2
  27. package/src/renderer/App.tsx +38 -12
  28. package/src/renderer/components/AgentPicker.tsx +49 -0
  29. package/src/renderer/styles.css +146 -0
@@ -227,54 +227,24 @@ var CtlsurfApi = class {
227
227
 
228
228
  // src/main/bridge.ts
229
229
  var ConversationBridge = class {
230
- api;
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
- constructor(api) {
241
- this.api = api;
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
- async startSession(dataspacePageId, agentName, cwd) {
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
- try {
257
- const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace("T", " ").substring(0, 19);
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.logEntry("user_input", input);
270
+ this.sendEntry("user_input", input);
301
271
  }
302
272
  this.inputBuffer = "";
303
273
  }
304
274
  }
305
275
  /**
306
- * Flush buffered output to ctlsurf.
276
+ * Flush buffered output via WebSocket.
307
277
  */
308
- async flush() {
309
- if (!this.logBlockId || this.buffer.length === 0) return;
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
- try {
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
- * Log a specific entry immediately.
287
+ * Send an entry to the backend via WebSocket.
322
288
  */
323
- async logEntry(action, message, data) {
324
- if (!this.logBlockId) return;
325
- try {
326
- await this.api.appendLog(this.logBlockId, action, message, data);
327
- } catch (err) {
328
- console.error(`[bridge] Failed to log entry:`, err.message);
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
- async endSession(exitCode) {
335
- if (!this.sessionActive || !this.logBlockId) return;
336
- await this.flush();
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 WebSocket(url);
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 === WebSocket.OPEN) {
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(this.ctlsurfApi);
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
- await this.bridge.endSession();
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(async (exitCode) => {
803
+ this.ptyManager.onExit((exitCode) => {
841
804
  this.events.onPtyExit(exitCode);
842
- await this.bridge.endSession(exitCode);
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
- const profile = this.getActiveProfile();
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
- await this.bridge.endSession();
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
- await this.bridge.endSession();
876
+ this.bridge.endSession();
918
877
  this.ptyManager?.kill();
919
878
  this.ptyManager = null;
920
879
  this.workerWs.disconnect();