@unlikeotherai/unloved 0.2.1 → 0.3.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/dist/index.js CHANGED
@@ -44,6 +44,7 @@ async function getVersion() {
44
44
  }
45
45
 
46
46
  // src/commands/start.ts
47
+ import { existsSync as existsSync2 } from "fs";
47
48
  import { createConnection } from "net";
48
49
  import { resolve as resolve6, dirname as dirname2 } from "path";
49
50
  import { fileURLToPath as fileURLToPath2 } from "url";
@@ -59,7 +60,7 @@ import { Router } from "express";
59
60
 
60
61
  // ../shared/src/config.ts
61
62
  var DEFAULT_CONFIG = {
62
- theme: "light"
63
+ theme: "dark"
63
64
  };
64
65
 
65
66
  // ../server/dist/index.js
@@ -261,6 +262,24 @@ tmuxRouter.post("/sessions", async (request, response) => {
261
262
  response.status(500).json({ error: "Failed to create tmux session" });
262
263
  }
263
264
  });
265
+ tmuxRouter.delete("/sessions/:name", async (request, response) => {
266
+ const { name } = request.params;
267
+ if (!name || !name.trim()) {
268
+ response.status(400).json({ error: "Session name is required" });
269
+ return;
270
+ }
271
+ try {
272
+ await execFileAsync2("tmux", ["kill-session", "-t", name.trim()]);
273
+ response.json({ name: name.trim(), killed: true });
274
+ } catch (error) {
275
+ const tmuxError = error;
276
+ if (tmuxError.code === "ENOENT") {
277
+ response.status(400).json({ error: "tmux is not installed" });
278
+ return;
279
+ }
280
+ response.status(500).json({ error: "Failed to kill tmux session" });
281
+ }
282
+ });
264
283
  var tmux_default = tmuxRouter;
265
284
  function createApp(options) {
266
285
  const app = express();
@@ -313,15 +332,15 @@ var GRACE_MS = 6e4;
313
332
  function sendJson(ws, msg) {
314
333
  ws.send(JSON.stringify(msg));
315
334
  }
316
- function attach(sessionName, ws) {
335
+ function attach(sessionName, ws, initialCols = 120, initialRows = 30) {
317
336
  let entry = entries.get(sessionName);
318
337
  if (!entry) {
319
338
  let pty;
320
339
  try {
321
340
  pty = spawn(tmuxBin, ["attach-session", "-t", sessionName], {
322
341
  name: "xterm-256color",
323
- cols: 120,
324
- rows: 30,
342
+ cols: initialCols,
343
+ rows: initialRows,
325
344
  cwd: process.env.HOME ?? "/",
326
345
  env: { ...process.env }
327
346
  });
@@ -354,6 +373,7 @@ function attach(sessionName, ws) {
354
373
  clearTimeout(entry.graceTimer);
355
374
  entry.graceTimer = null;
356
375
  }
376
+ entry.pty.resize(initialCols, initialRows);
357
377
  const replay = entry.buffer.getAll();
358
378
  if (replay.length > 0) {
359
379
  sendJson(ws, { type: "replay", data: replay.toString("utf-8") });
@@ -389,8 +409,11 @@ function createWsHandler(server) {
389
409
  wss.emit("connection", ws, req, match[1]);
390
410
  });
391
411
  });
392
- wss.on("connection", (ws, _req, sessionName) => {
393
- attach(sessionName, ws);
412
+ wss.on("connection", (ws, req, sessionName) => {
413
+ const url = new URL(req.url ?? "", "http://localhost");
414
+ const cols = Math.max(1, Number(url.searchParams.get("cols")) || 120);
415
+ const rows = Math.max(1, Number(url.searchParams.get("rows")) || 30);
416
+ attach(sessionName, ws, cols, rows);
394
417
  ws.on("message", (raw, isBinary) => {
395
418
  if (isBinary) {
396
419
  write(sessionName, raw.toString());
@@ -570,6 +593,10 @@ async function startCommand(args2) {
570
593
  process.exit(1);
571
594
  }
572
595
  const sessionName = args2.positional[0] ?? await detectTmuxSession() ?? void 0;
596
+ const homeDir = await ensureHome();
597
+ if (!args2.flags["no-sync"]) {
598
+ syncRepo(homeDir);
599
+ }
573
600
  if (await isPortInUse(port)) {
574
601
  console.log(`unloved is already running at http://localhost:${port}`);
575
602
  if (!args2.flags["no-open"]) {
@@ -577,16 +604,10 @@ async function startCommand(args2) {
577
604
  }
578
605
  process.exit(0);
579
606
  }
580
- const homeDir = await ensureHome();
581
607
  const __dirname = dirname2(fileURLToPath2(import.meta.url));
582
608
  const bundledDir = resolve6(__dirname, "..", "public");
583
- let staticDir = bundledDir;
584
- if (!args2.flags["no-sync"]) {
585
- const syncedDir = syncRepo(homeDir);
586
- if (syncedDir) {
587
- staticDir = syncedDir;
588
- }
589
- }
609
+ const syncedDir = resolve6(homeDir, "repo", "packages", "web", "dist");
610
+ const staticDir = !args2.flags["no-sync"] && existsSync2(syncedDir) ? syncedDir : bundledDir;
590
611
  startServer({ homeDir, staticDir, port });
591
612
  printBanner(port);
592
613
  if (!args2.flags["no-open"]) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@unlikeotherai/unloved",
3
- "version": "0.2.1",
3
+ "version": "0.3.1",
4
4
  "description": "Local multi-device AI coding cockpit",
5
5
  "type": "module",
6
6
  "bin": {