claude-mux 0.7.0 → 0.7.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.
Files changed (115) hide show
  1. package/README.md +4 -2
  2. package/dist/cli.d.ts +1 -1
  3. package/dist/cli.js +1 -1
  4. package/dist/utils/version.d.ts +1 -1
  5. package/dist/utils/version.js +1 -1
  6. package/dist/web/client/_app/immutable/chunks/{DU91Ml7U.js → BGcEgn7w.js} +1 -1
  7. package/{web/.svelte-kit/output/client/_app/immutable/chunks/DmdO6ygw.js → dist/web/client/_app/immutable/chunks/By6CYjmE.js} +1 -1
  8. package/dist/web/client/_app/immutable/chunks/{HKNo9LID.js → CR5jMWGV.js} +1 -1
  9. package/{web/.svelte-kit/output/client/_app/immutable/entry/app.CGIBnoln.js → dist/web/client/_app/immutable/entry/app.DmtnygN7.js} +2 -2
  10. package/dist/web/client/_app/immutable/entry/start.fYmelGlC.js +1 -0
  11. package/dist/web/client/_app/immutable/nodes/{0.CqlJ9a31.js → 0.DGDAdwT5.js} +1 -1
  12. package/dist/web/client/_app/immutable/nodes/{1.BQUZh2-w.js → 1.Cg8dWgUN.js} +1 -1
  13. package/dist/web/client/_app/immutable/nodes/{2.CCV1YdgF.js → 2.DItUEo3e.js} +1 -1
  14. package/dist/web/client/_app/immutable/nodes/{3.D9tDCdq8.js → 3.dHui0twF.js} +1 -1
  15. package/dist/web/client/_app/immutable/nodes/{4.BqPyNkFA.js → 4.CiEHP0cr.js} +1 -1
  16. package/dist/web/client/_app/version.json +1 -1
  17. package/dist/web/server/chunks/{0-BHWsmCJv.js → 0-BmRg-l2z.js} +5 -5
  18. package/dist/web/server/chunks/{0-BHWsmCJv.js.map → 0-BmRg-l2z.js.map} +1 -1
  19. package/dist/web/server/chunks/{1-YRx6A8Tm.js → 1-CPgO8U7d.js} +3 -3
  20. package/dist/web/server/chunks/{1-YRx6A8Tm.js.map → 1-CPgO8U7d.js.map} +1 -1
  21. package/dist/web/server/chunks/{2-eC6JuGAo.js → 2--ZO5fZp_.js} +5 -5
  22. package/dist/web/server/chunks/{2-eC6JuGAo.js.map → 2--ZO5fZp_.js.map} +1 -1
  23. package/dist/web/server/chunks/{3-Bk-wV20p.js → 3-7HqSep9c.js} +3 -3
  24. package/dist/web/server/chunks/{3-Bk-wV20p.js.map → 3-7HqSep9c.js.map} +1 -1
  25. package/dist/web/server/chunks/{4-nteBgDrW.js → 4-C1PCdmY0.js} +4 -4
  26. package/dist/web/server/chunks/{4-nteBgDrW.js.map → 4-C1PCdmY0.js.map} +1 -1
  27. package/dist/web/server/index.js +1 -1
  28. package/dist/web/server/index.js.map +1 -1
  29. package/dist/web/server/manifest.js +10 -10
  30. package/dist/web/server/manifest.js.map +1 -1
  31. package/docs/release-checklist.md +8 -34
  32. package/docs/removing-hooks.md +14 -14
  33. package/package.json +1 -1
  34. package/src/cli.ts +1 -1
  35. package/src/utils/version.ts +1 -1
  36. package/web/.svelte-kit/adapter-bun/chunks/internal.js +1 -1
  37. package/web/.svelte-kit/adapter-bun/manifest-full.js +1 -1
  38. package/web/.svelte-kit/adapter-bun/manifest.js +1 -1
  39. package/web/.svelte-kit/adapter-bun/nodes/0.js +1 -1
  40. package/web/.svelte-kit/adapter-bun/nodes/1.js +1 -1
  41. package/web/.svelte-kit/adapter-bun/nodes/2.js +1 -1
  42. package/web/.svelte-kit/adapter-bun/nodes/3.js +1 -1
  43. package/web/.svelte-kit/adapter-bun/nodes/4.js +1 -1
  44. package/web/.svelte-kit/adapter-node/.vite/manifest.json +200 -15
  45. package/web/.svelte-kit/adapter-node/_app/immutable/assets/AllSessionsPanel.BKhqOrbV.css +1 -0
  46. package/web/.svelte-kit/adapter-node/_app/immutable/assets/_layout.WptSHSUl.css +1 -0
  47. package/web/.svelte-kit/adapter-node/_app/immutable/assets/_page.DldLgTc-.css +1 -0
  48. package/web/.svelte-kit/adapter-node/_app/immutable/assets/_page.DoNWy7tW.css +1 -0
  49. package/web/.svelte-kit/adapter-node/chunks/AllSessionsPanel.svelte_svelte_type_style_lang.js +49 -0
  50. package/web/.svelte-kit/adapter-node/chunks/alert-dialog-description.js +2670 -0
  51. package/web/.svelte-kit/adapter-node/chunks/auth.js +59 -0
  52. package/web/.svelte-kit/adapter-node/chunks/button.js +82 -0
  53. package/web/.svelte-kit/adapter-node/chunks/client.js +29 -0
  54. package/web/.svelte-kit/adapter-node/chunks/context.js +28 -16
  55. package/web/.svelte-kit/adapter-node/chunks/events.js +121 -0
  56. package/web/.svelte-kit/adapter-node/chunks/index.js +1 -1
  57. package/web/.svelte-kit/adapter-node/chunks/index2.js +186 -68
  58. package/web/.svelte-kit/adapter-node/chunks/internal.js +5 -90
  59. package/web/.svelte-kit/adapter-node/chunks/pane.js +82 -0
  60. package/web/.svelte-kit/adapter-node/chunks/sessions-json.js +16 -1
  61. package/web/.svelte-kit/adapter-node/chunks/sessions.svelte.js +174 -12
  62. package/web/.svelte-kit/adapter-node/chunks/ws-handlers.js +782 -0
  63. package/web/.svelte-kit/adapter-node/entries/endpoints/api/auth/login/_server.ts.js +22 -0
  64. package/web/.svelte-kit/adapter-node/entries/endpoints/api/auth/logout/_server.ts.js +9 -0
  65. package/web/.svelte-kit/adapter-node/entries/endpoints/api/beads/_server.ts.js +22 -0
  66. package/web/.svelte-kit/adapter-node/entries/endpoints/api/chrome/_server.ts.js +30 -0
  67. package/web/.svelte-kit/adapter-node/entries/endpoints/api/files/image/_server.ts.js +53 -0
  68. package/web/.svelte-kit/adapter-node/entries/endpoints/api/sessions/_id_/kill/_server.ts.js +12 -6
  69. package/web/.svelte-kit/adapter-node/entries/endpoints/api/sessions/_id_/restart/_server.ts.js +40 -0
  70. package/web/.svelte-kit/adapter-node/entries/endpoints/api/sessions/_id_/screenshots/_server.ts.js +28 -0
  71. package/web/.svelte-kit/adapter-node/entries/endpoints/api/sessions/_id_/send/_server.ts.js +11 -4
  72. package/web/.svelte-kit/adapter-node/entries/endpoints/api/sessions/_server.ts.js +1 -78
  73. package/web/.svelte-kit/adapter-node/entries/endpoints/api/sessions/_target_/output/_server.ts.js +2 -2
  74. package/web/.svelte-kit/adapter-node/entries/endpoints/api/tmux/panes/_server.ts.js +21 -0
  75. package/web/.svelte-kit/adapter-node/entries/fallbacks/error.svelte.js +1 -18
  76. package/web/.svelte-kit/adapter-node/entries/hooks.server.js +105 -0
  77. package/web/.svelte-kit/adapter-node/entries/pages/_layout.svelte.js +493 -6
  78. package/web/.svelte-kit/adapter-node/entries/pages/_page.svelte.js +3024 -54
  79. package/web/.svelte-kit/adapter-node/entries/pages/login/_page.server.ts.js +15 -0
  80. package/web/.svelte-kit/adapter-node/entries/pages/login/_page.svelte.js +37 -0
  81. package/web/.svelte-kit/adapter-node/entries/pages/session/_target_/_page.svelte.js +623 -46
  82. package/web/.svelte-kit/adapter-node/manifest-full.js +67 -3
  83. package/web/.svelte-kit/adapter-node/manifest.js +67 -3
  84. package/web/.svelte-kit/adapter-node/nodes/0.js +2 -2
  85. package/web/.svelte-kit/adapter-node/nodes/1.js +1 -1
  86. package/web/.svelte-kit/adapter-node/nodes/2.js +2 -2
  87. package/web/.svelte-kit/adapter-node/nodes/3.js +6 -4
  88. package/web/.svelte-kit/adapter-node/nodes/4.js +8 -0
  89. package/web/.svelte-kit/ambient.d.ts +28 -2
  90. package/web/.svelte-kit/generated/server/internal.js +1 -1
  91. package/web/.svelte-kit/output/client/.vite/manifest.json +44 -44
  92. package/web/.svelte-kit/output/client/_app/immutable/chunks/{DU91Ml7U.js → BGcEgn7w.js} +1 -1
  93. package/{dist/web/client/_app/immutable/chunks/DmdO6ygw.js → web/.svelte-kit/output/client/_app/immutable/chunks/By6CYjmE.js} +1 -1
  94. package/web/.svelte-kit/output/client/_app/immutable/chunks/{HKNo9LID.js → CR5jMWGV.js} +1 -1
  95. package/{dist/web/client/_app/immutable/entry/app.CGIBnoln.js → web/.svelte-kit/output/client/_app/immutable/entry/app.DmtnygN7.js} +2 -2
  96. package/web/.svelte-kit/output/client/_app/immutable/entry/start.fYmelGlC.js +1 -0
  97. package/web/.svelte-kit/output/client/_app/immutable/nodes/{0.CqlJ9a31.js → 0.DGDAdwT5.js} +1 -1
  98. package/web/.svelte-kit/output/client/_app/immutable/nodes/{1.BQUZh2-w.js → 1.Cg8dWgUN.js} +1 -1
  99. package/web/.svelte-kit/output/client/_app/immutable/nodes/{2.CCV1YdgF.js → 2.DItUEo3e.js} +1 -1
  100. package/web/.svelte-kit/output/client/_app/immutable/nodes/{3.D9tDCdq8.js → 3.dHui0twF.js} +1 -1
  101. package/web/.svelte-kit/output/client/_app/immutable/nodes/{4.BqPyNkFA.js → 4.CiEHP0cr.js} +1 -1
  102. package/web/.svelte-kit/output/client/_app/version.json +1 -1
  103. package/web/.svelte-kit/output/server/chunks/internal.js +1 -1
  104. package/web/.svelte-kit/output/server/manifest-full.js +1 -1
  105. package/web/.svelte-kit/output/server/manifest.js +1 -1
  106. package/web/.svelte-kit/output/server/nodes/0.js +1 -1
  107. package/web/.svelte-kit/output/server/nodes/1.js +1 -1
  108. package/web/.svelte-kit/output/server/nodes/2.js +1 -1
  109. package/web/.svelte-kit/output/server/nodes/3.js +1 -1
  110. package/web/.svelte-kit/output/server/nodes/4.js +1 -1
  111. package/dist/web/client/_app/immutable/entry/start.CJk8zB1j.js +0 -1
  112. package/web/.svelte-kit/adapter-node/_app/immutable/assets/_layout.4NiX29PU.css +0 -1
  113. package/web/.svelte-kit/adapter-node/_app/immutable/assets/_page.BEMzYUGV.css +0 -1
  114. package/web/.svelte-kit/adapter-node/_app/immutable/assets/_page.DOJn7TG7.css +0 -1
  115. package/web/.svelte-kit/output/client/_app/immutable/entry/start.CJk8zB1j.js +0 -1
@@ -0,0 +1,22 @@
1
+ import { json } from "@sveltejs/kit";
2
+ import { i as isAuthEnabled, v as validatePassword, c as createAuthToken, A as AUTH_COOKIE } from "../../../../../chunks/auth.js";
3
+ const POST = async ({ request, cookies, url }) => {
4
+ if (!isAuthEnabled()) {
5
+ return json({ success: true, message: "Auth not enabled" });
6
+ }
7
+ const body = await request.json().catch(() => ({}));
8
+ const password = body.password;
9
+ if (!password || typeof password !== "string") {
10
+ return json({ error: "Password required" }, { status: 400 });
11
+ }
12
+ if (!validatePassword(password)) {
13
+ return json({ error: "Invalid password" }, { status: 401 });
14
+ }
15
+ const token = createAuthToken();
16
+ const isSecure = url.protocol === "https:";
17
+ cookies.set(AUTH_COOKIE.name, token, AUTH_COOKIE.options(isSecure));
18
+ return json({ success: true });
19
+ };
20
+ export {
21
+ POST
22
+ };
@@ -0,0 +1,9 @@
1
+ import { json } from "@sveltejs/kit";
2
+ import { A as AUTH_COOKIE } from "../../../../../chunks/auth.js";
3
+ const POST = async ({ cookies }) => {
4
+ cookies.delete(AUTH_COOKIE.name, { path: "/" });
5
+ return json({ success: true });
6
+ };
7
+ export {
8
+ POST
9
+ };
@@ -0,0 +1,22 @@
1
+ import { json } from "@sveltejs/kit";
2
+ import { g as getBeadsIssues } from "../../../../chunks/ws-handlers.js";
3
+ const GET = async ({ url }) => {
4
+ const project = url.searchParams.get("project");
5
+ if (!project) {
6
+ return json({ error: "Missing project parameter" }, { status: 400 });
7
+ }
8
+ try {
9
+ const projectPath = decodeURIComponent(project);
10
+ const issues = getBeadsIssues(projectPath);
11
+ return json({
12
+ issues,
13
+ project: projectPath,
14
+ timestamp: Date.now()
15
+ });
16
+ } catch (err) {
17
+ return json({ error: "Failed to fetch beads issues" }, { status: 500 });
18
+ }
19
+ };
20
+ export {
21
+ GET
22
+ };
@@ -0,0 +1,30 @@
1
+ import { json } from "@sveltejs/kit";
2
+ import { execSync } from "child_process";
3
+ const DELETE = async () => {
4
+ try {
5
+ let killed = 0;
6
+ try {
7
+ const psOutput = execSync(
8
+ "ps aux | grep -E '(chrome|chromium|brave)' | grep -E 'remote-debugging-(pipe|port)' | grep -v grep | awk '{print $2}'",
9
+ { encoding: "utf-8" }
10
+ ).trim();
11
+ if (psOutput) {
12
+ const pids = psOutput.split("\n").filter(Boolean);
13
+ for (const pid of pids) {
14
+ try {
15
+ execSync(`kill ${pid}`, { stdio: "ignore" });
16
+ killed++;
17
+ } catch {
18
+ }
19
+ }
20
+ }
21
+ } catch {
22
+ }
23
+ return json({ ok: true, killed });
24
+ } catch {
25
+ return json({ error: "Failed to close Chrome" }, { status: 500 });
26
+ }
27
+ };
28
+ export {
29
+ DELETE
30
+ };
@@ -0,0 +1,53 @@
1
+ import { json } from "@sveltejs/kit";
2
+ import { existsSync, statSync, readFileSync } from "fs";
3
+ import { extname } from "path";
4
+ const MIME_TYPES = {
5
+ ".png": "image/png",
6
+ ".jpg": "image/jpeg",
7
+ ".jpeg": "image/jpeg",
8
+ ".webp": "image/webp",
9
+ ".gif": "image/gif"
10
+ };
11
+ const GET = async ({ url }) => {
12
+ const path = url.searchParams.get("path");
13
+ if (!path) {
14
+ return json({ error: "path parameter required" }, { status: 400 });
15
+ }
16
+ if (path.includes("..")) {
17
+ return json({ error: "Invalid path" }, { status: 400 });
18
+ }
19
+ try {
20
+ if (!existsSync(path)) {
21
+ return json({ error: "File not found" }, { status: 404 });
22
+ }
23
+ const stat = statSync(path);
24
+ if (!stat.isFile()) {
25
+ return json({ error: "Not a file" }, { status: 400 });
26
+ }
27
+ if (stat.size > 50 * 1024 * 1024) {
28
+ return json({ error: "File too large" }, { status: 413 });
29
+ }
30
+ const ext = extname(path).toLowerCase();
31
+ const mimeType = MIME_TYPES[ext];
32
+ if (!mimeType) {
33
+ return json({ error: "Unsupported image format" }, { status: 400 });
34
+ }
35
+ const content = readFileSync(path);
36
+ return new Response(content, {
37
+ headers: {
38
+ "Content-Type": mimeType,
39
+ "Content-Length": String(content.length),
40
+ "Cache-Control": "public, max-age=300"
41
+ }
42
+ });
43
+ } catch (err) {
44
+ const e = err;
45
+ if (e.code === "EACCES") {
46
+ return json({ error: "Permission denied" }, { status: 403 });
47
+ }
48
+ return json({ error: "Failed to read file" }, { status: 500 });
49
+ }
50
+ };
51
+ export {
52
+ GET
53
+ };
@@ -1,16 +1,22 @@
1
1
  import { json } from "@sveltejs/kit";
2
- import { execSync } from "child_process";
2
+ import { execFileSync } from "child_process";
3
3
  import { d as deleteSession } from "../../../../../../chunks/sessions-json.js";
4
4
  const POST = async ({ params, request }) => {
5
5
  const id = decodeURIComponent(params.id);
6
6
  const body = await request.json().catch(() => ({}));
7
7
  const { pid, tmux_target } = body;
8
8
  try {
9
- if (tmux_target) {
10
- const session = tmux_target.split(":")[0];
11
- execSync(`tmux kill-session -t "${session}" 2>/dev/null || true`, { stdio: "ignore" });
12
- } else if (pid && pid > 0) {
13
- execSync(`kill ${pid} 2>/dev/null || true`, { stdio: "ignore" });
9
+ if (typeof pid === "number" && pid > 0 && Number.isInteger(pid)) {
10
+ try {
11
+ execFileSync("kill", [String(pid)], { stdio: "ignore" });
12
+ } catch {
13
+ }
14
+ }
15
+ if (tmux_target && typeof tmux_target === "string") {
16
+ try {
17
+ execFileSync("tmux", ["kill-pane", "-t", tmux_target], { stdio: "ignore" });
18
+ } catch {
19
+ }
14
20
  }
15
21
  try {
16
22
  deleteSession(id);
@@ -0,0 +1,40 @@
1
+ import { json } from "@sveltejs/kit";
2
+ import { execFileSync } from "child_process";
3
+ import { d as deleteSession } from "../../../../../../chunks/sessions-json.js";
4
+ const POST = async ({ params, request }) => {
5
+ const id = decodeURIComponent(params.id);
6
+ const body = await request.json().catch(() => ({}));
7
+ const { pid, tmux_target, cwd } = body;
8
+ if (!tmux_target || typeof tmux_target !== "string") {
9
+ return json({ error: "tmux_target required" }, { status: 400 });
10
+ }
11
+ if (!cwd || typeof cwd !== "string") {
12
+ return json({ error: "cwd required" }, { status: 400 });
13
+ }
14
+ try {
15
+ if (typeof pid === "number" && pid > 0 && Number.isInteger(pid)) {
16
+ try {
17
+ execFileSync("kill", ["-9", String(pid)], { stdio: "ignore" });
18
+ } catch {
19
+ }
20
+ }
21
+ try {
22
+ deleteSession(id);
23
+ } catch {
24
+ }
25
+ await new Promise((resolve) => setTimeout(resolve, 300));
26
+ execFileSync("tmux", ["send-keys", "-t", tmux_target, "C-c"], {
27
+ stdio: "ignore"
28
+ });
29
+ await new Promise((resolve) => setTimeout(resolve, 100));
30
+ execFileSync("tmux", ["send-keys", "-t", tmux_target, `cd "${cwd}" && claude --dangerously-skip-permissions`, "Enter"], {
31
+ stdio: "ignore"
32
+ });
33
+ return json({ ok: true });
34
+ } catch (err) {
35
+ return json({ error: "Failed to restart session" }, { status: 500 });
36
+ }
37
+ };
38
+ export {
39
+ POST
40
+ };
@@ -0,0 +1,28 @@
1
+ import { json } from "@sveltejs/kit";
2
+ import { b as getSession, r as removeScreenshot } from "../../../../../../chunks/sessions-json.js";
3
+ const DELETE = async ({ params, url }) => {
4
+ const id = decodeURIComponent(params.id);
5
+ const path = url.searchParams.get("path");
6
+ if (!id) {
7
+ return json({ error: "Session ID required" }, { status: 400 });
8
+ }
9
+ if (!path) {
10
+ return json({ error: "Screenshot path required" }, { status: 400 });
11
+ }
12
+ try {
13
+ const session = getSession(id);
14
+ if (!session) {
15
+ return json({ error: "Session not found" }, { status: 404 });
16
+ }
17
+ const removed = removeScreenshot(id, path);
18
+ if (!removed) {
19
+ return json({ error: "Screenshot not found" }, { status: 404 });
20
+ }
21
+ return json({ ok: true });
22
+ } catch {
23
+ return json({ error: "Failed to remove screenshot" }, { status: 500 });
24
+ }
25
+ };
26
+ export {
27
+ DELETE
28
+ };
@@ -1,5 +1,5 @@
1
1
  import { json } from "@sveltejs/kit";
2
- import { execSync } from "child_process";
2
+ import { execSync, execFileSync } from "child_process";
3
3
  const POST = async ({ params, request }) => {
4
4
  const target = decodeURIComponent(params.id);
5
5
  const body = await request.json();
@@ -7,10 +7,17 @@ const POST = async ({ params, request }) => {
7
7
  const text = body.text;
8
8
  try {
9
9
  if (text) {
10
- execSync(`tmux send-keys -t "${target}" -l ${JSON.stringify(text)}`, { stdio: "ignore" });
11
- execSync(`tmux send-keys -t "${target}" Enter`, { stdio: "ignore" });
10
+ execSync(`tmux load-buffer -b claude-mux-input -`, {
11
+ input: text,
12
+ stdio: ["pipe", "ignore", "ignore"]
13
+ });
14
+ execFileSync("tmux", ["paste-buffer", "-b", "claude-mux-input", "-t", target], {
15
+ stdio: "ignore"
16
+ });
17
+ execFileSync("tmux", ["delete-buffer", "-b", "claude-mux-input"], { stdio: "ignore" });
18
+ execFileSync("tmux", ["send-keys", "-t", target, "Enter"], { stdio: "ignore" });
12
19
  } else {
13
- execSync(`tmux send-keys -t "${target}" ${keys}`, { stdio: "ignore" });
20
+ execFileSync("tmux", ["send-keys", "-t", target, keys], { stdio: "ignore" });
14
21
  }
15
22
  return json({ ok: true });
16
23
  } catch {
@@ -1,83 +1,6 @@
1
1
  import { json } from "@sveltejs/kit";
2
2
  import { g as getAllSessions, a as updateSession } from "../../../../chunks/sessions-json.js";
3
- import { execSync } from "child_process";
4
- function isInTmux() {
5
- return !!process.env.TMUX;
6
- }
7
- function getPaneTitle(target) {
8
- try {
9
- const result = execSync(`tmux display-message -p -t "${target}" "#{pane_title}"`, {
10
- encoding: "utf-8",
11
- stdio: ["pipe", "pipe", "pipe"],
12
- timeout: 1e3
13
- });
14
- return result.trim() || null;
15
- } catch {
16
- return null;
17
- }
18
- }
19
- function capturePaneContent(target) {
20
- if (!isInTmux()) {
21
- return null;
22
- }
23
- try {
24
- const result = execSync(`tmux capture-pane -p -t "${target}"`, {
25
- encoding: "utf-8",
26
- stdio: ["pipe", "pipe", "pipe"],
27
- timeout: 1e3
28
- });
29
- return result;
30
- } catch {
31
- return null;
32
- }
33
- }
34
- function detectRecentInterruption(content) {
35
- if (!content) return null;
36
- const lines = content.split("\n");
37
- const bottomLines = lines.slice(-5).join("\n");
38
- if (bottomLines.includes("Esc to cancel") || bottomLines.includes("Esc to interrupt")) {
39
- return null;
40
- }
41
- let bottomSepIdx = -1;
42
- for (let i = lines.length - 1; i >= 0; i--) {
43
- if (lines[i].startsWith("─────")) {
44
- bottomSepIdx = i;
45
- break;
46
- }
47
- }
48
- if (bottomSepIdx === -1) return null;
49
- let topSepIdx = -1;
50
- for (let i = bottomSepIdx - 1; i >= 0; i--) {
51
- if (lines[i].startsWith("─────")) {
52
- topSepIdx = i;
53
- break;
54
- }
55
- }
56
- if (topSepIdx === -1) return null;
57
- let interactionStartIdx = -1;
58
- const maxScan = Math.max(0, topSepIdx - 15);
59
- for (let i = topSepIdx - 1; i >= maxScan; i--) {
60
- const line = lines[i];
61
- if (line.startsWith("●") || line.startsWith("❯")) {
62
- interactionStartIdx = i;
63
- break;
64
- }
65
- }
66
- if (interactionStartIdx === -1) return null;
67
- const slice = lines.slice(interactionStartIdx, topSepIdx).join("\n");
68
- if (slice.includes("Interrupted")) return "interrupted";
69
- if (slice.includes("User declined to answer")) return "declined";
70
- return null;
71
- }
72
- function checkForInterruption(tmuxTarget) {
73
- const content = capturePaneContent(tmuxTarget);
74
- if (!content) return null;
75
- const interruption = detectRecentInterruption(content);
76
- if (interruption) {
77
- return { state: "idle", current_action: null, prompt_text: null };
78
- }
79
- return null;
80
- }
3
+ import { g as getPaneTitle, c as checkForInterruption } from "../../../../chunks/pane.js";
81
4
  function syncSessionStates() {
82
5
  const sessions = getAllSessions().filter((s) => s.tmux_target);
83
6
  for (const session of sessions) {
@@ -1,9 +1,9 @@
1
1
  import { json } from "@sveltejs/kit";
2
- import { execSync } from "child_process";
2
+ import { execFileSync } from "child_process";
3
3
  const GET = async ({ params }) => {
4
4
  const target = decodeURIComponent(params.target);
5
5
  try {
6
- const output = execSync(`tmux capture-pane -t "${target}" -p -S -100`, { encoding: "utf-8" });
6
+ const output = execFileSync("tmux", ["capture-pane", "-t", target, "-p", "-S", "-100"], { encoding: "utf-8" });
7
7
  return json({ output, timestamp: Date.now() });
8
8
  } catch {
9
9
  return json({ error: "Failed to capture pane" }, { status: 500 });
@@ -0,0 +1,21 @@
1
+ import { json } from "@sveltejs/kit";
2
+ import { execSync } from "child_process";
3
+ const GET = async () => {
4
+ try {
5
+ const output = execSync(
6
+ 'tmux list-panes -a -F "#{session_name}:#{window_index}.#{pane_index} #{pane_current_command}"',
7
+ { encoding: "utf-8" }
8
+ );
9
+ const panes = output.trim().split("\n").filter(Boolean).map((line) => {
10
+ const [target, command] = line.split(" ");
11
+ const session = target.split(":")[0];
12
+ return { target, session, command };
13
+ });
14
+ return json(panes);
15
+ } catch {
16
+ return json([]);
17
+ }
18
+ };
19
+ export {
20
+ GET
21
+ };
@@ -1,24 +1,7 @@
1
1
  import { g as getContext, e as escape_html } from "../../chunks/context.js";
2
2
  import "clsx";
3
3
  import "../../chunks/state.svelte.js";
4
- import "@sveltejs/kit/internal";
5
- import "../../chunks/exports.js";
6
- import "../../chunks/utils.js";
7
- import { w as writable } from "../../chunks/index.js";
8
- import "@sveltejs/kit/internal/server";
9
- function create_updated_store() {
10
- const { set, subscribe } = writable(false);
11
- {
12
- return {
13
- subscribe,
14
- // eslint-disable-next-line @typescript-eslint/require-await
15
- check: async () => false
16
- };
17
- }
18
- }
19
- const stores = {
20
- updated: /* @__PURE__ */ create_updated_store()
21
- };
4
+ import { s as stores } from "../../chunks/client.js";
22
5
  ({
23
6
  check: stores.updated.check
24
7
  });
@@ -0,0 +1,105 @@
1
+ import { redirect } from "@sveltejs/kit";
2
+ import { S as SessionsWsManager, T as TerminalWsManager, B as BeadsWsManager, p as parseWsPath, h as handleWsMessage, r as resizePane } from "../chunks/ws-handlers.js";
3
+ import { i as isAuthEnabled, A as AUTH_COOKIE, a as validateAuthToken } from "../chunks/auth.js";
4
+ const sessionsWsManager = new SessionsWsManager({ debug: true });
5
+ const terminalWsManager = new TerminalWsManager({ debug: true });
6
+ const beadsWsManager = new BeadsWsManager({ debug: true });
7
+ const wsDataMap = /* @__PURE__ */ new WeakMap();
8
+ const handle = async ({ event, resolve }) => {
9
+ const pathname = event.url.pathname;
10
+ const isAuthRoute = pathname.startsWith("/login") || pathname.startsWith("/api/auth");
11
+ if (isAuthEnabled() && !isAuthRoute) {
12
+ const token = event.cookies.get(AUTH_COOKIE.name);
13
+ const isAuthenticated = validateAuthToken(token);
14
+ if (!isAuthenticated) {
15
+ if (pathname.startsWith("/api/")) {
16
+ return new Response(JSON.stringify({ error: "Unauthorized" }), {
17
+ status: 401,
18
+ headers: { "Content-Type": "application/json" }
19
+ });
20
+ }
21
+ throw redirect(302, "/login");
22
+ }
23
+ }
24
+ const connectionHeader = event.request.headers.get("connection");
25
+ const upgradeHeader = event.request.headers.get("upgrade");
26
+ if (connectionHeader?.toLowerCase().includes("upgrade") && upgradeHeader?.toLowerCase() === "websocket") {
27
+ const url = new URL(event.request.url);
28
+ const parsed = parseWsPath(url.pathname, url.searchParams);
29
+ if (parsed) {
30
+ await event.platform.server.upgrade(event.platform.request, {
31
+ data: parsed
32
+ });
33
+ return new Response(null, { status: 101 });
34
+ }
35
+ }
36
+ return resolve(event);
37
+ };
38
+ const websocket = {
39
+ open(ws) {
40
+ const data = ws.data;
41
+ if (!data) return;
42
+ const client = {
43
+ send: (msg) => ws.send(msg),
44
+ isOpen: () => ws.readyState === WebSocket.OPEN,
45
+ close: () => ws.close(),
46
+ getBufferedAmount: () => ws.bufferedAmount
47
+ };
48
+ wsDataMap.set(ws, { ...data, client });
49
+ let accepted = false;
50
+ if (data.type === "sessions") {
51
+ accepted = sessionsWsManager.addClient(client);
52
+ } else if (data.type === "terminal" && data.target) {
53
+ accepted = terminalWsManager.addClient(client, data.target);
54
+ } else if (data.type === "beads" && data.project) {
55
+ accepted = beadsWsManager.addClient(client, data.project);
56
+ }
57
+ if (!accepted) {
58
+ ws.close(1013, "Max clients reached");
59
+ }
60
+ },
61
+ message(ws, message) {
62
+ const msgStr = message.toString();
63
+ const data = wsDataMap.get(ws);
64
+ const response = handleWsMessage(
65
+ msgStr,
66
+ data?.type === "terminal" && data.target ? (cols, rows) => resizePane(data.target, cols, rows) : void 0
67
+ );
68
+ if (response === "pong") {
69
+ ws.send("pong");
70
+ }
71
+ },
72
+ close(ws) {
73
+ const data = wsDataMap.get(ws);
74
+ if (!data) return;
75
+ if (data.type === "sessions") {
76
+ sessionsWsManager.removeClient(data.client);
77
+ } else if (data.type === "terminal") {
78
+ terminalWsManager.removeClient(data.client, data.target);
79
+ } else if (data.type === "beads") {
80
+ beadsWsManager.removeClient(data.client, data.project);
81
+ }
82
+ wsDataMap.delete(ws);
83
+ },
84
+ error(ws, error) {
85
+ const data = wsDataMap.get(ws);
86
+ console.log(`[ws:${data?.type ?? "unknown"}] WebSocket error`, {
87
+ code: error.code,
88
+ message: error.message
89
+ });
90
+ if (data) {
91
+ if (data.type === "sessions") {
92
+ sessionsWsManager.removeClient(data.client);
93
+ } else if (data.type === "terminal") {
94
+ terminalWsManager.removeClient(data.client, data.target);
95
+ } else if (data.type === "beads") {
96
+ beadsWsManager.removeClient(data.client, data.project);
97
+ }
98
+ wsDataMap.delete(ws);
99
+ }
100
+ }
101
+ };
102
+ export {
103
+ handle,
104
+ websocket
105
+ };