webmux 0.7.2 → 0.7.3

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/bin/webmux.js CHANGED
@@ -146,6 +146,12 @@ function W(t, e) {
146
146
  const s = t;
147
147
  s.isTTY && s.setRawMode(e);
148
148
  }
149
+ function Bt(t, e, s, i = s) {
150
+ const r = rt(t ?? R);
151
+ return K(e, r - s.length, { hard: true, trim: false }).split(`
152
+ `).map((n, u) => `${u === 0 ? i : s}${n}`).join(`
153
+ `);
154
+ }
149
155
 
150
156
  class B {
151
157
  input;
@@ -431,7 +437,7 @@ var import_sisteransi, at = (t) => t === 161 || t === 164 || t === 167 || t ===
431
437
  ` && (r && p && (i += st(r)), n && (i += it(n))), V += h.length, m = A, A = g.next();
432
438
  }
433
439
  return i;
434
- }, At, _, bt, z, rt = (t) => ("columns" in t) && typeof t.columns == "number" ? t.columns : 80, nt = (t) => ("rows" in t) && typeof t.rows == "number" ? t.rows : 20, Vt, kt, yt;
440
+ }, At, _, bt, z, rt = (t) => ("columns" in t) && typeof t.columns == "number" ? t.columns : 80, nt = (t) => ("rows" in t) && typeof t.rows == "number" ? t.rows : 20, Vt, kt, yt, Tt;
435
441
  var init_dist = __esm(() => {
436
442
  import_sisteransi = __toESM(require_src(), 1);
437
443
  O = /[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/y;
@@ -573,6 +579,33 @@ var init_dist = __esm(() => {
573
579
  });
574
580
  }
575
581
  };
582
+ Tt = class Tt extends B {
583
+ options;
584
+ cursor = 0;
585
+ get _selectedValue() {
586
+ return this.options[this.cursor];
587
+ }
588
+ changeValue() {
589
+ this.value = this._selectedValue.value;
590
+ }
591
+ constructor(e) {
592
+ super(e, false), this.options = e.options;
593
+ const s = this.options.findIndex(({ value: r }) => r === e.initialValue), i = s === -1 ? 0 : s;
594
+ this.cursor = this.options[i].disabled ? x(i, 1, this.options) : i, this.changeValue(), this.on("cursor", (r) => {
595
+ switch (r) {
596
+ case "left":
597
+ case "up":
598
+ this.cursor = x(this.cursor, -1, this.options);
599
+ break;
600
+ case "down":
601
+ case "right":
602
+ this.cursor = x(this.cursor, 1, this.options);
603
+ break;
604
+ }
605
+ this.changeValue();
606
+ });
607
+ }
608
+ };
576
609
  });
577
610
 
578
611
  // node_modules/.bun/@clack+prompts@1.1.0/node_modules/@clack/prompts/dist/index.mjs
@@ -600,6 +633,18 @@ var import_sisteransi2, ee, I2 = (e, r) => ee ? e : r, Re, $e, de, V, he, h, x2,
600
633
  case "submit":
601
634
  return t("green", V);
602
635
  }
636
+ }, ve = (e) => {
637
+ switch (e) {
638
+ case "initial":
639
+ case "active":
640
+ return t("cyan", h);
641
+ case "cancel":
642
+ return t("red", h);
643
+ case "error":
644
+ return t("yellow", h);
645
+ case "submit":
646
+ return t("green", h);
647
+ }
603
648
  }, mt2 = (e) => e === 161 || e === 164 || e === 167 || e === 168 || e === 170 || e === 173 || e === 174 || e >= 176 && e <= 180 || e >= 182 && e <= 186 || e >= 188 && e <= 191 || e === 198 || e === 208 || e === 215 || e === 216 || e >= 222 && e <= 225 || e === 230 || e >= 232 && e <= 234 || e === 236 || e === 237 || e === 240 || e === 242 || e === 243 || e >= 247 && e <= 250 || e === 252 || e === 254 || e === 257 || e === 273 || e === 275 || e === 283 || e === 294 || e === 295 || e === 299 || e >= 305 && e <= 307 || e === 312 || e >= 319 && e <= 322 || e === 324 || e >= 328 && e <= 331 || e === 333 || e === 338 || e === 339 || e === 358 || e === 359 || e === 363 || e === 462 || e === 464 || e === 466 || e === 468 || e === 470 || e === 472 || e === 474 || e === 476 || e === 593 || e === 609 || e === 708 || e === 711 || e >= 713 && e <= 715 || e === 717 || e === 720 || e >= 728 && e <= 731 || e === 733 || e === 735 || e >= 768 && e <= 879 || e >= 913 && e <= 929 || e >= 931 && e <= 937 || e >= 945 && e <= 961 || e >= 963 && e <= 969 || e === 1025 || e >= 1040 && e <= 1103 || e === 1105 || e === 8208 || e >= 8211 && e <= 8214 || e === 8216 || e === 8217 || e === 8220 || e === 8221 || e >= 8224 && e <= 8226 || e >= 8228 && e <= 8231 || e === 8240 || e === 8242 || e === 8243 || e === 8245 || e === 8251 || e === 8254 || e === 8308 || e === 8319 || e >= 8321 && e <= 8324 || e === 8364 || e === 8451 || e === 8453 || e === 8457 || e === 8467 || e === 8470 || e === 8481 || e === 8482 || e === 8486 || e === 8491 || e === 8531 || e === 8532 || e >= 8539 && e <= 8542 || e >= 8544 && e <= 8555 || e >= 8560 && e <= 8569 || e === 8585 || e >= 8592 && e <= 8601 || e === 8632 || e === 8633 || e === 8658 || e === 8660 || e === 8679 || e === 8704 || e === 8706 || e === 8707 || e === 8711 || e === 8712 || e === 8715 || e === 8719 || e === 8721 || e === 8725 || e === 8730 || e >= 8733 && e <= 8736 || e === 8739 || e === 8741 || e >= 8743 && e <= 8748 || e === 8750 || e >= 8756 && e <= 8759 || e === 8764 || e === 8765 || e === 8776 || e === 8780 || e === 8786 || e === 8800 || e === 8801 || e >= 8804 && e <= 8807 || e === 8810 || e === 8811 || e === 8814 || e === 8815 || e === 8834 || e === 8835 || e === 8838 || e === 8839 || e === 8853 || e === 8857 || e === 8869 || e === 8895 || e === 8978 || e >= 9312 && e <= 9449 || e >= 9451 && e <= 9547 || e >= 9552 && e <= 9587 || e >= 9600 && e <= 9615 || e >= 9618 && e <= 9621 || e === 9632 || e === 9633 || e >= 9635 && e <= 9641 || e === 9650 || e === 9651 || e === 9654 || e === 9655 || e === 9660 || e === 9661 || e === 9664 || e === 9665 || e >= 9670 && e <= 9672 || e === 9675 || e >= 9678 && e <= 9681 || e >= 9698 && e <= 9701 || e === 9711 || e === 9733 || e === 9734 || e === 9737 || e === 9742 || e === 9743 || e === 9756 || e === 9758 || e === 9792 || e === 9794 || e === 9824 || e === 9825 || e >= 9827 && e <= 9829 || e >= 9831 && e <= 9834 || e === 9836 || e === 9837 || e === 9839 || e === 9886 || e === 9887 || e === 9919 || e >= 9926 && e <= 9933 || e >= 9935 && e <= 9939 || e >= 9941 && e <= 9953 || e === 9955 || e === 9960 || e === 9961 || e >= 9963 && e <= 9969 || e === 9972 || e >= 9974 && e <= 9977 || e === 9979 || e === 9980 || e === 9982 || e === 9983 || e === 10045 || e >= 10102 && e <= 10111 || e >= 11094 && e <= 11097 || e >= 12872 && e <= 12879 || e >= 57344 && e <= 63743 || e >= 65024 && e <= 65039 || e === 65533 || e >= 127232 && e <= 127242 || e >= 127248 && e <= 127277 || e >= 127280 && e <= 127337 || e >= 127344 && e <= 127373 || e === 127375 || e === 127376 || e >= 127387 && e <= 127404 || e >= 917760 && e <= 917999 || e >= 983040 && e <= 1048573 || e >= 1048576 && e <= 1114109, gt2 = (e) => e === 12288 || e >= 65281 && e <= 65376 || e >= 65504 && e <= 65510, ft2 = (e) => e >= 4352 && e <= 4447 || e === 8986 || e === 8987 || e === 9001 || e === 9002 || e >= 9193 && e <= 9196 || e === 9200 || e === 9203 || e === 9725 || e === 9726 || e === 9748 || e === 9749 || e >= 9800 && e <= 9811 || e === 9855 || e === 9875 || e === 9889 || e === 9898 || e === 9899 || e === 9917 || e === 9918 || e === 9924 || e === 9925 || e === 9934 || e === 9940 || e === 9962 || e === 9970 || e === 9971 || e === 9973 || e === 9978 || e === 9981 || e === 9989 || e === 9994 || e === 9995 || e === 10024 || e === 10060 || e === 10062 || e >= 10067 && e <= 10069 || e === 10071 || e >= 10133 && e <= 10135 || e === 10160 || e === 10175 || e === 11035 || e === 11036 || e === 11088 || e === 11093 || e >= 11904 && e <= 11929 || e >= 11931 && e <= 12019 || e >= 12032 && e <= 12245 || e >= 12272 && e <= 12287 || e >= 12289 && e <= 12350 || e >= 12353 && e <= 12438 || e >= 12441 && e <= 12543 || e >= 12549 && e <= 12591 || e >= 12593 && e <= 12686 || e >= 12688 && e <= 12771 || e >= 12783 && e <= 12830 || e >= 12832 && e <= 12871 || e >= 12880 && e <= 19903 || e >= 19968 && e <= 42124 || e >= 42128 && e <= 42182 || e >= 43360 && e <= 43388 || e >= 44032 && e <= 55203 || e >= 63744 && e <= 64255 || e >= 65040 && e <= 65049 || e >= 65072 && e <= 65106 || e >= 65108 && e <= 65126 || e >= 65128 && e <= 65131 || e >= 94176 && e <= 94180 || e === 94192 || e === 94193 || e >= 94208 && e <= 100343 || e >= 100352 && e <= 101589 || e >= 101632 && e <= 101640 || e >= 110576 && e <= 110579 || e >= 110581 && e <= 110587 || e === 110589 || e === 110590 || e >= 110592 && e <= 110882 || e === 110898 || e >= 110928 && e <= 110930 || e === 110933 || e >= 110948 && e <= 110951 || e >= 110960 && e <= 111355 || e === 126980 || e === 127183 || e === 127374 || e >= 127377 && e <= 127386 || e >= 127488 && e <= 127490 || e >= 127504 && e <= 127547 || e >= 127552 && e <= 127560 || e === 127568 || e === 127569 || e >= 127584 && e <= 127589 || e >= 127744 && e <= 127776 || e >= 127789 && e <= 127797 || e >= 127799 && e <= 127868 || e >= 127870 && e <= 127891 || e >= 127904 && e <= 127946 || e >= 127951 && e <= 127955 || e >= 127968 && e <= 127984 || e === 127988 || e >= 127992 && e <= 128062 || e === 128064 || e >= 128066 && e <= 128252 || e >= 128255 && e <= 128317 || e >= 128331 && e <= 128334 || e >= 128336 && e <= 128359 || e === 128378 || e === 128405 || e === 128406 || e === 128420 || e >= 128507 && e <= 128591 || e >= 128640 && e <= 128709 || e === 128716 || e >= 128720 && e <= 128722 || e >= 128725 && e <= 128727 || e >= 128732 && e <= 128735 || e === 128747 || e === 128748 || e >= 128756 && e <= 128764 || e >= 128992 && e <= 129003 || e === 129008 || e >= 129292 && e <= 129338 || e >= 129340 && e <= 129349 || e >= 129351 && e <= 129535 || e >= 129648 && e <= 129660 || e >= 129664 && e <= 129672 || e >= 129680 && e <= 129725 || e >= 129727 && e <= 129733 || e >= 129742 && e <= 129755 || e >= 129760 && e <= 129768 || e >= 129776 && e <= 129784 || e >= 131072 && e <= 196605 || e >= 196608 && e <= 262141, we, re, ie, Ae, ne, Ft2, yt2, Le = (e, r = {}, s = {}) => {
604
649
  const i = r.limit ?? 1 / 0, a = r.ellipsis ?? "", o = r?.ellipsisWidth ?? (a ? Le(a, yt2, s).width : 0), u = s.ansiWidth ?? 0, l = s.controlWidth ?? 0, n = s.tabWidth ?? 8, c = s.ambiguousWidth ?? 1, p = s.emojiWidth ?? 2, f = s.fullWidthWidth ?? 2, g = s.regularWidth ?? 1, E = s.wideWidth ?? 2;
605
650
  let $ = 0, m = 0, d = e.length, F = 0, y2 = false, v = d, C = Math.max(0, i - o), A = 0, b = 0, w = 0, S2 = 0;
@@ -744,6 +789,39 @@ var import_sisteransi2, ee, I2 = (e, r) => ee ? e : r, Re, $e, de, V, he, h, x2,
744
789
  ` && (a && d && (i += Ue(a)), o && (i += Ke(o))), E += $.length, f = g, g = p.next();
745
790
  }
746
791
  return i;
792
+ }, bt2 = (e, r, s, i, a) => {
793
+ let o = r, u = 0;
794
+ for (let l = s;l < i; l++) {
795
+ const n = e[l];
796
+ if (o = o - n.length, u++, o <= a)
797
+ break;
798
+ }
799
+ return { lineCount: o, removals: u };
800
+ }, X2 = ({ cursor: e, options: r, style: s, output: i = process.stdout, maxItems: a = Number.POSITIVE_INFINITY, columnPadding: o = 0, rowPadding: u = 4 }) => {
801
+ const l = rt(i) - o, n = nt(i), c = t("dim", "..."), p = Math.max(n - u, 0), f = Math.max(Math.min(a, p), 5);
802
+ let g = 0;
803
+ e >= f - 3 && (g = Math.max(Math.min(e - f + 3, r.length - f), 0));
804
+ let E = f < r.length && g > 0, $ = f < r.length && g + f < r.length;
805
+ const m = Math.min(g + f, r.length), d = [];
806
+ let F = 0;
807
+ E && F++, $ && F++;
808
+ const y2 = g + (E ? 1 : 0), v = m - ($ ? 1 : 0);
809
+ for (let A = y2;A < v; A++) {
810
+ const b = J(s(r[A], A === e), l, { hard: true, trim: false }).split(`
811
+ `);
812
+ d.push(b), F += b.length;
813
+ }
814
+ if (F > p) {
815
+ let A = 0, b = 0, w = F;
816
+ const S2 = e - y2, T2 = (M2, O2) => bt2(d, w, M2, O2, p);
817
+ E ? ({ lineCount: w, removals: A } = T2(0, S2), w > p && ({ lineCount: w, removals: b } = T2(S2 + 1, d.length))) : ({ lineCount: w, removals: b } = T2(S2 + 1, d.length), w > p && ({ lineCount: w, removals: A } = T2(0, S2))), A > 0 && (E = true, d.splice(0, A)), b > 0 && ($ = true, d.splice(d.length - b, b));
818
+ }
819
+ const C = [];
820
+ E && C.push(c);
821
+ for (const A of d)
822
+ for (const b of A)
823
+ C.push(b);
824
+ return $ && C.push(c), C;
747
825
  }, Rt = (e) => {
748
826
  const r = e.active ?? "Yes", s = e.inactive ?? "No";
749
827
  return new kt({ active: r, inactive: s, signal: e.signal, input: e.input, output: e.output, initialValue: e.initialValue ?? true, render() {
@@ -796,7 +874,50 @@ ${t("gray", x2)} ` : "";
796
874
  ${c}
797
875
  ${t("gray", f + se.repeat(n + 2) + me)}
798
876
  `);
799
- }, ze, Qe;
877
+ }, ze, oe = (e, r) => e.includes(`
878
+ `) ? e.split(`
879
+ `).map((s) => r(s)).join(`
880
+ `) : r(e), Jt = (e) => {
881
+ const r = (s, i) => {
882
+ const a = s.label ?? String(s.value);
883
+ switch (i) {
884
+ case "disabled":
885
+ return `${t("gray", H2)} ${oe(a, (o) => t("gray", o))}${s.hint ? ` ${t("dim", `(${s.hint ?? "disabled"})`)}` : ""}`;
886
+ case "selected":
887
+ return `${oe(a, (o) => t("dim", o))}`;
888
+ case "active":
889
+ return `${t("green", z2)} ${a}${s.hint ? ` ${t("dim", `(${s.hint})`)}` : ""}`;
890
+ case "cancelled":
891
+ return `${oe(a, (o) => t(["strikethrough", "dim"], o))}`;
892
+ default:
893
+ return `${t("dim", H2)} ${oe(a, (o) => t("dim", o))}`;
894
+ }
895
+ };
896
+ return new Tt({ options: e.options, signal: e.signal, input: e.input, output: e.output, initialValue: e.initialValue, render() {
897
+ const s = e.withGuide ?? _.withGuide, i = `${W2(this.state)} `, a = `${ve(this.state)} `, o = Bt(e.output, e.message, a, i), u = `${s ? `${t("gray", h)}
898
+ ` : ""}${o}
899
+ `;
900
+ switch (this.state) {
901
+ case "submit": {
902
+ const l = s ? `${t("gray", h)} ` : "", n = Bt(e.output, r(this.options[this.cursor], "selected"), l);
903
+ return `${u}${n}`;
904
+ }
905
+ case "cancel": {
906
+ const l = s ? `${t("gray", h)} ` : "", n = Bt(e.output, r(this.options[this.cursor], "cancelled"), l);
907
+ return `${u}${n}${s ? `
908
+ ${t("gray", h)}` : ""}`;
909
+ }
910
+ default: {
911
+ const l = s ? `${t("cyan", h)} ` : "", n = s ? t("cyan", x2) : "", c = u.split(`
912
+ `).length, p = s ? 2 : 1;
913
+ return `${u}${l}${X2({ output: e.output, cursor: this.cursor, options: this.options, maxItems: e.maxItems, columnPadding: l.length, rowPadding: c + p, style: (f, g) => r(f, f.disabled ? "disabled" : g ? "active" : "inactive") }).join(`
914
+ ${l}`)}
915
+ ${n}
916
+ `;
917
+ }
918
+ }
919
+ } }).prompt();
920
+ }, Qe;
800
921
  var init_dist2 = __esm(() => {
801
922
  init_dist();
802
923
  init_dist();
@@ -902,10 +1023,467 @@ function detectProjectName(gitRoot) {
902
1023
  }
903
1024
  var init_shared = () => {};
904
1025
 
1026
+ // bin/src/init-helpers.ts
1027
+ import { existsSync as existsSync2, readFileSync as readFileSync2, rmSync } from "fs";
1028
+ import { tmpdir } from "os";
1029
+ import { join as join2 } from "path";
1030
+ function isRecord(value) {
1031
+ return typeof value === "object" && value !== null && !Array.isArray(value);
1032
+ }
1033
+ function readString(value) {
1034
+ return typeof value === "string" && value.trim().length > 0 ? value : null;
1035
+ }
1036
+ function detectPackageManager(gitRoot) {
1037
+ if (existsSync2(join2(gitRoot, "bun.lock")) || existsSync2(join2(gitRoot, "bun.lockb")))
1038
+ return "bun";
1039
+ if (existsSync2(join2(gitRoot, "pnpm-lock.yaml")))
1040
+ return "pnpm";
1041
+ if (existsSync2(join2(gitRoot, "yarn.lock")))
1042
+ return "yarn";
1043
+ return "npm";
1044
+ }
1045
+ function detectMainBranch(gitRoot) {
1046
+ const originHead = run("git", ["symbolic-ref", "--quiet", "--short", "refs/remotes/origin/HEAD"], { cwd: gitRoot });
1047
+ if (originHead.success) {
1048
+ const branch = originHead.stdout.toString().trim().split("/").pop();
1049
+ if (branch)
1050
+ return branch;
1051
+ }
1052
+ const mainBranch = run("git", ["branch", "--list", "main"], { cwd: gitRoot });
1053
+ if (mainBranch.success && mainBranch.stdout.toString().trim())
1054
+ return "main";
1055
+ const masterBranch = run("git", ["branch", "--list", "master"], { cwd: gitRoot });
1056
+ if (masterBranch.success && masterBranch.stdout.toString().trim())
1057
+ return "master";
1058
+ const currentBranch = run("git", ["rev-parse", "--abbrev-ref", "HEAD"], { cwd: gitRoot });
1059
+ if (currentBranch.success) {
1060
+ const branch = currentBranch.stdout.toString().trim();
1061
+ if (branch && branch !== "HEAD")
1062
+ return branch;
1063
+ }
1064
+ return "main";
1065
+ }
1066
+ function buildRunScriptCommand(packageManager, scriptName) {
1067
+ if (packageManager === "bun")
1068
+ return `bun run ${scriptName}`;
1069
+ if (packageManager === "pnpm")
1070
+ return `pnpm ${scriptName}`;
1071
+ if (packageManager === "yarn")
1072
+ return `yarn ${scriptName}`;
1073
+ return `npm run ${scriptName}`;
1074
+ }
1075
+ function detectInitProjectContext(gitRoot, defaultAgent) {
1076
+ return {
1077
+ gitRoot,
1078
+ projectName: detectProjectName(gitRoot),
1079
+ mainBranch: detectMainBranch(gitRoot),
1080
+ defaultAgent,
1081
+ packageManager: detectPackageManager(gitRoot)
1082
+ };
1083
+ }
1084
+ function buildInitPromptSpec(context) {
1085
+ const systemPrompt = [
1086
+ "You are bootstrapping a local repository for webmux.",
1087
+ "A starter `.webmux.yaml` already exists at the repo root.",
1088
+ "Inspect the repository in the current working directory and edit that existing `.webmux.yaml` in place.",
1089
+ "Do not modify any other file.",
1090
+ "Do not ask the user questions. Infer the config from the repository contents.",
1091
+ "Be efficient: inspect only the files needed to determine the project name, main branch, service layout, dev commands, and ports.",
1092
+ "The YAML must be valid and minimal.",
1093
+ `Set workspace.defaultAgent to ${context.defaultAgent}.`,
1094
+ "Use this config shape:",
1095
+ "name: infer from the repository",
1096
+ "workspace.mainBranch: infer from git",
1097
+ "workspace.worktreeRoot: keep __worktrees unless there is clear evidence of an existing alternative",
1098
+ "services: one entry per real dev service with name, portEnv, and portStart when a default port is clear",
1099
+ "profiles.default.runtime: host",
1100
+ "profiles.default.envPassthrough: []",
1101
+ "profiles.default.panes: start with an agent pane focused true, then add command panes for real services",
1102
+ "Command panes should use the repository's real dev command and pass the relevant port env var into the command when needed.",
1103
+ "Use split: right for the first command pane and split: bottom for later command panes.",
1104
+ "Include integrations.github.linkedRepos as an empty list, integrations.linear.enabled as true, and startupEnvs as an empty object.",
1105
+ "Only include optional sections like auto_name, lifecycleHooks, sandbox/docker config, mounts, or systemPrompt if the repository gives clear evidence they are needed.",
1106
+ "Prefer editing the existing keys over replacing the file with a completely different shape.",
1107
+ "Before finishing, verify that `.webmux.yaml` exists and contains the final YAML."
1108
+ ].join(`
1109
+ `);
1110
+ return {
1111
+ systemPrompt,
1112
+ userPrompt: "Adapt the existing starter `.webmux.yaml` for this repository."
1113
+ };
1114
+ }
1115
+ function buildInitAgentCommand(agent, prompt, outputPrefix = "webmux-init") {
1116
+ if (agent === "claude") {
1117
+ return {
1118
+ agent,
1119
+ cmd: "claude",
1120
+ args: [
1121
+ "-p",
1122
+ "--verbose",
1123
+ "--permission-mode",
1124
+ "bypassPermissions",
1125
+ "--model",
1126
+ FAST_CLAUDE_MODEL,
1127
+ "--effort",
1128
+ FAST_CLAUDE_EFFORT,
1129
+ "--output-format",
1130
+ "stream-json",
1131
+ "--include-partial-messages",
1132
+ "--append-system-prompt",
1133
+ prompt.systemPrompt,
1134
+ prompt.userPrompt
1135
+ ]
1136
+ };
1137
+ }
1138
+ const summaryPath = join2(tmpdir(), `${outputPrefix}-${Date.now()}-${Math.random().toString(36).slice(2, 8)}.txt`);
1139
+ return {
1140
+ agent,
1141
+ cmd: "codex",
1142
+ args: [
1143
+ "exec",
1144
+ "--sandbox",
1145
+ "workspace-write",
1146
+ "--color",
1147
+ "never",
1148
+ "--json",
1149
+ "-m",
1150
+ FAST_CODEX_MODEL,
1151
+ "-o",
1152
+ summaryPath,
1153
+ "-c",
1154
+ `model_reasoning_effort="${FAST_CODEX_REASONING}"`,
1155
+ "-c",
1156
+ `developer_instructions=${prompt.systemPrompt}`,
1157
+ prompt.userPrompt
1158
+ ],
1159
+ summaryPath
1160
+ };
1161
+ }
1162
+ function closeAssistant(state) {
1163
+ if (!state.assistantSnapshot)
1164
+ return [];
1165
+ state.assistantSnapshot = "";
1166
+ return [{ kind: "assistant_done", text: "" }];
1167
+ }
1168
+ function streamSnapshot(state, snapshot) {
1169
+ if (!snapshot)
1170
+ return [];
1171
+ if (!state.assistantSnapshot) {
1172
+ state.assistantSnapshot = snapshot;
1173
+ return [{ kind: "assistant_delta", text: snapshot }];
1174
+ }
1175
+ if (snapshot === state.assistantSnapshot)
1176
+ return [];
1177
+ if (snapshot.startsWith(state.assistantSnapshot)) {
1178
+ const delta = snapshot.slice(state.assistantSnapshot.length);
1179
+ state.assistantSnapshot = snapshot;
1180
+ return delta ? [{ kind: "assistant_delta", text: delta }] : [];
1181
+ }
1182
+ state.assistantSnapshot = snapshot;
1183
+ return [
1184
+ { kind: "assistant_done", text: "" },
1185
+ { kind: "assistant_delta", text: snapshot }
1186
+ ];
1187
+ }
1188
+ function emitStatus(state, text) {
1189
+ const status = text?.trim();
1190
+ if (!status || status === state.lastStatus)
1191
+ return [];
1192
+ state.lastStatus = status;
1193
+ return [...closeAssistant(state), { kind: "status", text: status }];
1194
+ }
1195
+ function emitWarning(state, text) {
1196
+ const warning = text?.trim();
1197
+ if (!warning)
1198
+ return [];
1199
+ return [...closeAssistant(state), { kind: "warning", text: warning }];
1200
+ }
1201
+ function extractTextBlocks(value) {
1202
+ if (typeof value === "string")
1203
+ return value;
1204
+ if (Array.isArray(value)) {
1205
+ return value.map((entry) => extractTextBlocks(entry)).filter((entry) => entry.length > 0).join("");
1206
+ }
1207
+ if (!isRecord(value))
1208
+ return "";
1209
+ if (value.type === "text" && typeof value.text === "string") {
1210
+ return value.text;
1211
+ }
1212
+ if (typeof value.output_text === "string")
1213
+ return value.output_text;
1214
+ if (typeof value.text === "string")
1215
+ return value.text;
1216
+ if (typeof value.delta === "string")
1217
+ return value.delta;
1218
+ if (Array.isArray(value.content))
1219
+ return extractTextBlocks(value.content);
1220
+ if (Array.isArray(value.contents))
1221
+ return extractTextBlocks(value.contents);
1222
+ if (Array.isArray(value.parts))
1223
+ return extractTextBlocks(value.parts);
1224
+ if (Array.isArray(value.output))
1225
+ return extractTextBlocks(value.output);
1226
+ return "";
1227
+ }
1228
+ function extractCommandText(value) {
1229
+ if (typeof value === "string" && value.trim().length > 0)
1230
+ return value.trim();
1231
+ if (Array.isArray(value) && value.every((entry) => typeof entry === "string")) {
1232
+ return value.join(" ").trim() || null;
1233
+ }
1234
+ return null;
1235
+ }
1236
+ function truncateText(text, limit = 120) {
1237
+ return text.length > limit ? `${text.slice(0, limit - 3)}...` : text;
1238
+ }
1239
+ function extractStructuredMessage(raw) {
1240
+ const candidates = [
1241
+ raw.message,
1242
+ raw.result,
1243
+ raw.item,
1244
+ raw.output,
1245
+ raw.content,
1246
+ raw.text,
1247
+ raw.response
1248
+ ];
1249
+ for (const candidate of candidates) {
1250
+ const text = extractTextBlocks(candidate).trim();
1251
+ if (text)
1252
+ return text;
1253
+ }
1254
+ return null;
1255
+ }
1256
+ function parseClaudeStreamLine(raw, state) {
1257
+ const type = readString(raw.type) ?? "unknown";
1258
+ if (type === "content_block_delta" && isRecord(raw.delta)) {
1259
+ if (raw.delta.type === "text_delta" && typeof raw.delta.text === "string") {
1260
+ return [{ kind: "assistant_delta", text: raw.delta.text }];
1261
+ }
1262
+ if (typeof raw.delta.text === "string") {
1263
+ return [{ kind: "assistant_delta", text: raw.delta.text }];
1264
+ }
1265
+ }
1266
+ if (type === "content_block_start" && isRecord(raw.content_block)) {
1267
+ if (raw.content_block.type === "tool_use") {
1268
+ return emitStatus(state, `Using ${readString(raw.content_block.name) ?? "tool"}...`);
1269
+ }
1270
+ const snapshot2 = extractTextBlocks(raw.content_block).trim();
1271
+ return streamSnapshot(state, snapshot2);
1272
+ }
1273
+ if (type === "message_stop" || type === "result_stop" || type === "content_block_stop") {
1274
+ return closeAssistant(state);
1275
+ }
1276
+ if (type === "error") {
1277
+ const message = isRecord(raw.error) ? readString(raw.error.message) : readString(raw.message);
1278
+ return emitWarning(state, message ?? "Claude returned an error.");
1279
+ }
1280
+ if (type.includes("tool")) {
1281
+ const toolName = readString(raw.tool_name) ?? (isRecord(raw.tool) ? readString(raw.tool.name) : null) ?? readString(raw.name);
1282
+ if (toolName)
1283
+ return emitStatus(state, `Using ${toolName}...`);
1284
+ }
1285
+ const snapshot = extractStructuredMessage(raw);
1286
+ if (snapshot)
1287
+ return streamSnapshot(state, snapshot);
1288
+ return [];
1289
+ }
1290
+ function parseCodexStatus(raw, type) {
1291
+ const command = extractCommandText(raw.command) ?? (isRecord(raw.item) ? extractCommandText(raw.item.command) : null);
1292
+ if (command && (type.includes("command") || type.includes("exec") || type.includes("shell"))) {
1293
+ return `Running ${truncateText(command)}`;
1294
+ }
1295
+ const toolName = readString(raw.tool_name) ?? readString(raw.name) ?? (isRecord(raw.item) ? readString(raw.item.name) : null);
1296
+ if (toolName && (type.includes("tool") || type.includes("function"))) {
1297
+ return `Using ${toolName}...`;
1298
+ }
1299
+ const status = readString(raw.status);
1300
+ if (status && !["completed", "done", "finished"].includes(status)) {
1301
+ return truncateText(status);
1302
+ }
1303
+ if (type.includes("turn"))
1304
+ return "Thinking...";
1305
+ return null;
1306
+ }
1307
+ function parseCodexStreamLine(raw, state) {
1308
+ const type = readString(raw.type) ?? readString(raw.event) ?? "unknown";
1309
+ if (type === "response.output_text.delta" && typeof raw.delta === "string") {
1310
+ return [{ kind: "assistant_delta", text: raw.delta }];
1311
+ }
1312
+ if (type === "response.output_text.done") {
1313
+ const text = readString(raw.text) ?? extractTextBlocks(raw.item).trim();
1314
+ return [...text ? streamSnapshot(state, text) : [], ...closeAssistant(state)];
1315
+ }
1316
+ if (type.includes("error")) {
1317
+ const message = isRecord(raw.error) ? readString(raw.error.message) : readString(raw.message);
1318
+ return emitWarning(state, message ?? "Codex returned an error.");
1319
+ }
1320
+ const status = parseCodexStatus(raw, type);
1321
+ if (status)
1322
+ return emitStatus(state, status);
1323
+ if (type.includes("delta") && typeof raw.delta === "string") {
1324
+ return [{ kind: "assistant_delta", text: raw.delta }];
1325
+ }
1326
+ const snapshot = extractStructuredMessage(raw);
1327
+ if (snapshot && (type.includes("assistant") || type.includes("message") || type.includes("output") || type.includes("response"))) {
1328
+ const events = streamSnapshot(state, snapshot);
1329
+ if (type.includes("done") || type.includes("completed") || type.includes("finished")) {
1330
+ events.push(...closeAssistant(state));
1331
+ }
1332
+ return events;
1333
+ }
1334
+ if (type.includes("done") || type.includes("completed") || type.includes("finished")) {
1335
+ return closeAssistant(state);
1336
+ }
1337
+ return [];
1338
+ }
1339
+ function parseInitAgentStreamLine(agent, line, state = { assistantSnapshot: "", lastStatus: null }) {
1340
+ const trimmed = line.trim();
1341
+ if (!trimmed)
1342
+ return [];
1343
+ let parsed;
1344
+ try {
1345
+ parsed = JSON.parse(trimmed);
1346
+ } catch {
1347
+ return [];
1348
+ }
1349
+ if (!isRecord(parsed))
1350
+ return [];
1351
+ return agent === "claude" ? parseClaudeStreamLine(parsed, state) : parseCodexStreamLine(parsed, state);
1352
+ }
1353
+ async function consumeStructuredStream(stream, agent, onEvent) {
1354
+ if (!stream)
1355
+ return { raw: "", assistantText: "" };
1356
+ const reader = stream.getReader();
1357
+ const decoder = new TextDecoder;
1358
+ const state = { assistantSnapshot: "", lastStatus: null };
1359
+ let buffer = "";
1360
+ let raw = "";
1361
+ let assistantText = "";
1362
+ while (true) {
1363
+ const { done, value } = await reader.read();
1364
+ if (done)
1365
+ break;
1366
+ const text = decoder.decode(value, { stream: true });
1367
+ raw += text;
1368
+ buffer += text;
1369
+ let newlineIndex = buffer.indexOf(`
1370
+ `);
1371
+ while (newlineIndex !== -1) {
1372
+ const line = buffer.slice(0, newlineIndex).replace(/\r$/, "");
1373
+ buffer = buffer.slice(newlineIndex + 1);
1374
+ for (const event of parseInitAgentStreamLine(agent, line, state)) {
1375
+ if (event.kind === "assistant_delta")
1376
+ assistantText += event.text;
1377
+ onEvent?.(event);
1378
+ }
1379
+ newlineIndex = buffer.indexOf(`
1380
+ `);
1381
+ }
1382
+ }
1383
+ const tail = decoder.decode();
1384
+ raw += tail;
1385
+ buffer += tail;
1386
+ const finalLine = buffer.replace(/\r$/, "");
1387
+ if (finalLine) {
1388
+ for (const event of parseInitAgentStreamLine(agent, finalLine, state)) {
1389
+ if (event.kind === "assistant_delta")
1390
+ assistantText += event.text;
1391
+ onEvent?.(event);
1392
+ }
1393
+ }
1394
+ for (const event of closeAssistant(state)) {
1395
+ onEvent?.(event);
1396
+ }
1397
+ return { raw, assistantText };
1398
+ }
1399
+ async function consumeRawStream(stream) {
1400
+ if (!stream)
1401
+ return "";
1402
+ const reader = stream.getReader();
1403
+ const decoder = new TextDecoder;
1404
+ let raw = "";
1405
+ while (true) {
1406
+ const { done, value } = await reader.read();
1407
+ if (done)
1408
+ break;
1409
+ raw += decoder.decode(value, { stream: true });
1410
+ }
1411
+ return raw + decoder.decode();
1412
+ }
1413
+ async function runInitAgentCommand(spec, cwd, handlers = {}) {
1414
+ const proc = Bun.spawn([spec.cmd, ...spec.args], {
1415
+ cwd,
1416
+ stdout: "pipe",
1417
+ stderr: "pipe"
1418
+ });
1419
+ const [exitCode, stdoutResult, stderr] = await Promise.all([
1420
+ proc.exited,
1421
+ consumeStructuredStream(proc.stdout, spec.agent, handlers.onEvent),
1422
+ consumeRawStream(proc.stderr)
1423
+ ]);
1424
+ let summary = stdoutResult.assistantText.trim();
1425
+ if (spec.summaryPath && existsSync2(spec.summaryPath)) {
1426
+ try {
1427
+ summary = readFileSync2(spec.summaryPath, "utf8").trim() || summary;
1428
+ } finally {
1429
+ rmSync(spec.summaryPath, { force: true });
1430
+ }
1431
+ }
1432
+ return { exitCode, stdout: stdoutResult.raw, stderr, summary };
1433
+ }
1434
+ function buildStarterTemplate(input) {
1435
+ const defaultAgent = input.defaultAgent ?? "claude";
1436
+ const packageManager = input.packageManager ?? "npm";
1437
+ const devCommand = buildRunScriptCommand(packageManager, "dev");
1438
+ return `# Project display name in the dashboard
1439
+ name: ${input.projectName}
1440
+
1441
+ workspace:
1442
+ mainBranch: ${input.mainBranch}
1443
+ worktreeRoot: __worktrees
1444
+ defaultAgent: ${defaultAgent}
1445
+
1446
+ # Each service defines a port env var that webmux injects into pane and agent
1447
+ # process environments when creating a worktree. Ports are auto-assigned:
1448
+ # base + (slot x step).
1449
+ services:
1450
+ - name: app
1451
+ portEnv: PORT
1452
+ portStart: 3000
1453
+ portStep: 10
1454
+
1455
+ profiles:
1456
+ default:
1457
+ runtime: host
1458
+ yolo: false
1459
+ envPassthrough: []
1460
+ panes:
1461
+ - id: agent
1462
+ kind: agent
1463
+ focus: true
1464
+ - id: app
1465
+ kind: command
1466
+ split: right
1467
+ command: PORT=$PORT ${devCommand}
1468
+
1469
+ integrations:
1470
+ github:
1471
+ linkedRepos: []
1472
+ linear:
1473
+ enabled: true
1474
+
1475
+ startupEnvs: {}
1476
+ `;
1477
+ }
1478
+ var FAST_CLAUDE_MODEL = "haiku", FAST_CLAUDE_EFFORT = "low", FAST_CODEX_MODEL = "gpt-5.1-codex", FAST_CODEX_REASONING = "low";
1479
+ var init_init_helpers = __esm(() => {
1480
+ init_shared();
1481
+ });
1482
+
905
1483
  // bin/src/init.ts
906
1484
  var exports_init = {};
907
- import { existsSync as existsSync2 } from "fs";
908
- import { join as join2 } from "path";
1485
+ import { existsSync as existsSync3 } from "fs";
1486
+ import { join as join3 } from "path";
909
1487
  function checkDeps() {
910
1488
  const missing = [];
911
1489
  for (const dep of deps) {
@@ -921,82 +1499,77 @@ function checkDeps() {
921
1499
  }
922
1500
  return missing;
923
1501
  }
924
- function webmuxTemplate(name) {
925
- return `# Project display name in the dashboard
926
- name: ${name}
927
-
928
- # Each service defines a port env var that webmux injects into .env.local
929
- # when creating a worktree. Ports are auto-assigned: base + (slot \xD7 step).
930
- # Use \`source .env.local\` in your .workmux.yaml pane commands to pick them up.
931
- services:
932
- - name: app
933
- portEnv: PORT
934
- portStart: 3000 # Port for the main branch (slot 0)
935
- portStep: 10 # Increment per worktree (3010, 3020, ...)
936
-
937
- # Agent profiles determine how AI agents run in worktrees
938
- profiles:
939
- default:
940
- name: default
941
-
942
- # --- Sandbox profile (uncomment to enable) ---
943
- # Runs agents in Docker containers for full isolation.
944
- # Requires: docker + a built image.
945
- # sandbox:
946
- # name: sandbox
947
- # image: my-project-sandbox
948
- # envPassthrough: # Env vars forwarded into the container
949
- # - DATABASE_URL
950
- # systemPrompt: >
951
- # You are running inside a sandboxed container.
952
- # Start the dev server with: npm run dev
953
-
954
- # --- Linked repos (uncomment to enable) ---
955
- # Monitor PRs from related repos in the dashboard.
956
- # linkedRepos:
957
- # - repo: org/other-repo
958
- # alias: other
959
-
960
- # --- Startup environment variables ---
961
- # These will appear as configurable fields in the UI when creating a worktree.
962
- # startupEnvs:
963
- # NODE_ENV: development
964
- `;
1502
+ function agentLabel(agent) {
1503
+ return agent === "claude" ? "Claude" : "Codex";
965
1504
  }
966
- function workmuxTemplate() {
967
- return `main_branch: main
968
-
969
- panes:
970
- # Agent pane \u2014 runs the AI coding assistant
971
- - command: >-
972
- claude --append-system-prompt
973
- "You are running inside a git worktree managed by workmux.\\n
974
- Pane layout (current window):\\n
975
- - Pane 0: this pane (claude agent)\\n
976
- - Pane 1: dev server\\n\\n
977
- To check dev server logs: tmux capture-pane -t .1 -p -S -50\\n
978
- To restart dev server: tmux send-keys -t .1 C-c 'source .env.local && PORT=\\$PORT npm run dev' Enter"
979
- focus: true
980
-
981
- # Dev server \u2014 waits for .env.local (written by webmux) then starts
982
- - command: >-
983
- npm install &&
984
- until [ -f .env.local ]; do sleep 0.2; done;
985
- source .env.local;
986
- PORT=$PORT npm run dev
987
- split: horizontal
988
- `;
1505
+ function defaultTemplateAgent() {
1506
+ return which("codex") && !which("claude") ? "codex" : "claude";
989
1507
  }
990
- var deps, gitRoot, missing, workmuxYaml, webmuxYaml;
1508
+ function createAgentStreamPrinter(label) {
1509
+ const prefix = ` ${label}: `;
1510
+ let atLineStart = true;
1511
+ let assistantActive = false;
1512
+ let sawAssistantText = false;
1513
+ const closeAssistantLine = () => {
1514
+ if (assistantActive && !atLineStart) {
1515
+ process.stdout.write(`
1516
+ `);
1517
+ }
1518
+ assistantActive = false;
1519
+ atLineStart = true;
1520
+ };
1521
+ const writeAssistantChunk = (text) => {
1522
+ if (!text)
1523
+ return;
1524
+ assistantActive = true;
1525
+ sawAssistantText = true;
1526
+ for (const char of text) {
1527
+ if (atLineStart) {
1528
+ process.stdout.write(prefix);
1529
+ atLineStart = false;
1530
+ }
1531
+ process.stdout.write(char);
1532
+ if (char === `
1533
+ `) {
1534
+ atLineStart = true;
1535
+ }
1536
+ }
1537
+ };
1538
+ return {
1539
+ onEvent(event) {
1540
+ if (event.kind === "assistant_delta") {
1541
+ writeAssistantChunk(event.text);
1542
+ return;
1543
+ }
1544
+ if (event.kind === "assistant_done") {
1545
+ closeAssistantLine();
1546
+ return;
1547
+ }
1548
+ closeAssistantLine();
1549
+ const tag = event.kind === "warning" ? "warning" : "status";
1550
+ console.log(` ${label} ${tag}: ${event.text}`);
1551
+ },
1552
+ finish() {
1553
+ closeAssistantLine();
1554
+ },
1555
+ sawAssistantText() {
1556
+ return sawAssistantText;
1557
+ }
1558
+ };
1559
+ }
1560
+ var deps, gitRoot, missing, webmuxYaml;
991
1561
  var init_init = __esm(async () => {
992
1562
  init_dist2();
993
1563
  init_shared();
1564
+ init_init_helpers();
994
1565
  deps = [
995
1566
  { tool: "git", required: true, hint: "https://git-scm.com/downloads" },
996
1567
  { tool: "bun", required: true, hint: "https://bun.sh" },
1568
+ { tool: "python3", required: true, hint: "https://www.python.org/downloads/ or brew install python or sudo apt install python3" },
997
1569
  { tool: "tmux", required: true, hint: "brew install tmux / sudo apt install tmux" },
998
- { tool: "workmux", required: true, hint: "cargo install workmux or https://workmux.raine.dev" },
999
1570
  { tool: "gh", required: false, hint: "brew install gh then gh auth login" },
1571
+ { tool: "claude", required: false, hint: "Install the Claude Code CLI to let Claude scaffold .webmux.yaml" },
1572
+ { tool: "codex", required: false, hint: "Install the Codex CLI to let Codex scaffold .webmux.yaml" },
1000
1573
  { tool: "docker", required: false, hint: "https://docs.docker.com/get-started/get-docker/" }
1001
1574
  ];
1002
1575
  Wt2("webmux init");
@@ -1025,26 +1598,107 @@ var init_init = __esm(async () => {
1025
1598
  }
1026
1599
  }
1027
1600
  R2.step("Checking config files...");
1028
- workmuxYaml = join2(gitRoot, ".workmux.yaml");
1029
- if (existsSync2(workmuxYaml)) {
1030
- R2.info(".workmux.yaml already exists, skipping");
1031
- } else {
1032
- await Bun.write(workmuxYaml, workmuxTemplate());
1033
- R2.success(".workmux.yaml created");
1034
- }
1035
- webmuxYaml = join2(gitRoot, ".webmux.yaml");
1036
- if (existsSync2(webmuxYaml)) {
1601
+ webmuxYaml = join3(gitRoot, ".webmux.yaml");
1602
+ if (existsSync3(webmuxYaml)) {
1037
1603
  R2.info(".webmux.yaml already exists, skipping");
1038
1604
  } else {
1039
- const name = detectProjectName(gitRoot);
1040
- await Bun.write(webmuxYaml, webmuxTemplate(name));
1041
- R2.success(".webmux.yaml created");
1605
+ const claudeAvailable = which("claude");
1606
+ const codexAvailable = which("codex");
1607
+ const choice = await Jt({
1608
+ message: "No .webmux.yaml found. How should webmux create it?",
1609
+ initialValue: claudeAvailable ? "claude" : codexAvailable ? "codex" : "manual",
1610
+ options: [
1611
+ {
1612
+ value: "claude",
1613
+ label: "Claude",
1614
+ hint: claudeAvailable ? "Claude inspects the repo and adapts the starter .webmux.yaml" : "Claude CLI not found",
1615
+ disabled: !claudeAvailable
1616
+ },
1617
+ {
1618
+ value: "codex",
1619
+ label: "Codex",
1620
+ hint: codexAvailable ? "Codex inspects the repo and adapts the starter .webmux.yaml" : "Codex CLI not found",
1621
+ disabled: !codexAvailable
1622
+ },
1623
+ {
1624
+ value: "manual",
1625
+ label: "I'll do it myself",
1626
+ hint: "Create the starter template now so you can edit it manually"
1627
+ }
1628
+ ]
1629
+ });
1630
+ if (Ct(choice)) {
1631
+ Gt("Aborted.");
1632
+ process.exit(1);
1633
+ }
1634
+ const selectedAgent = choice === "codex" ? "codex" : defaultTemplateAgent();
1635
+ const context = detectInitProjectContext(gitRoot, selectedAgent);
1636
+ if (choice === "manual") {
1637
+ await Bun.write(webmuxYaml, buildStarterTemplate({
1638
+ projectName: context.projectName,
1639
+ mainBranch: context.mainBranch,
1640
+ defaultAgent: context.defaultAgent,
1641
+ packageManager: context.packageManager
1642
+ }));
1643
+ R2.success(".webmux.yaml starter template created");
1644
+ } else {
1645
+ const label = agentLabel(choice);
1646
+ const starterTemplate = buildStarterTemplate({
1647
+ projectName: context.projectName,
1648
+ mainBranch: context.mainBranch,
1649
+ defaultAgent: choice,
1650
+ packageManager: context.packageManager
1651
+ });
1652
+ await Bun.write(webmuxYaml, starterTemplate);
1653
+ const prompt = buildInitPromptSpec({ ...context, defaultAgent: choice });
1654
+ const command = buildInitAgentCommand(choice, prompt);
1655
+ const streamPrinter = createAgentStreamPrinter(label);
1656
+ R2.step(`Running ${label} to adapt the starter .webmux.yaml...`);
1657
+ const result = await runInitAgentCommand(command, gitRoot, { onEvent: streamPrinter.onEvent });
1658
+ streamPrinter.finish();
1659
+ if (!existsSync3(webmuxYaml)) {
1660
+ R2.error(`${label} removed .webmux.yaml`);
1661
+ const details = [
1662
+ result.summary ? `Summary:
1663
+ ${result.summary}` : "",
1664
+ result.stderr.trim() ? `stderr:
1665
+ ${result.stderr.trim()}` : ""
1666
+ ].filter((entry) => entry.length > 0).join(`
1667
+
1668
+ `);
1669
+ if (details) {
1670
+ Vt2(details, `${label} output`);
1671
+ }
1672
+ Gt("Setup incomplete.");
1673
+ process.exit(1);
1674
+ }
1675
+ const finalYaml = await Bun.file(webmuxYaml).text();
1676
+ const changedTemplate = finalYaml !== starterTemplate;
1677
+ if (result.exitCode === 0 && changedTemplate) {
1678
+ R2.success(`${label} adapted .webmux.yaml`);
1679
+ } else if (result.exitCode === 0) {
1680
+ R2.warning(`${label} left the starter template unchanged`);
1681
+ R2.warning(`${label} did not change the starter template. Review .webmux.yaml manually.`);
1682
+ } else if (changedTemplate) {
1683
+ R2.warning(`${label} updated .webmux.yaml`);
1684
+ R2.warning(`${label} exited with code ${result.exitCode}. Review the generated file before using it.`);
1685
+ } else {
1686
+ R2.warning(`${label} left the starter template in place`);
1687
+ R2.warning(`${label} exited with code ${result.exitCode}. The starter template is still there for manual editing.`);
1688
+ }
1689
+ if (result.summary && !streamPrinter.sawAssistantText()) {
1690
+ Vt2(result.summary, `${label} summary`);
1691
+ }
1692
+ const trimmedStderr = result.stderr.trim();
1693
+ if (trimmedStderr) {
1694
+ Vt2(trimmedStderr, `${label} stderr`);
1695
+ }
1696
+ }
1042
1697
  }
1043
1698
  Gt("You're all set! Next steps:");
1044
1699
  console.log();
1045
- console.log(" 1. Edit .workmux.yaml to configure pane layout for your project");
1046
- console.log(" 2. Edit .webmux.yaml to set up service ports and profiles");
1047
- console.log(" 3. Run: webmux");
1700
+ console.log(" 1. Review .webmux.yaml and adjust panes, ports, and profiles if needed");
1701
+ console.log(" 2. Run: webmux");
1048
1702
  console.log();
1049
1703
  });
1050
1704
 
@@ -1053,8 +1707,8 @@ var exports_service = {};
1053
1707
  __export(exports_service, {
1054
1708
  default: () => service
1055
1709
  });
1056
- import { existsSync as existsSync3, mkdirSync, unlinkSync } from "fs";
1057
- import { join as join3 } from "path";
1710
+ import { existsSync as existsSync4, mkdirSync, unlinkSync } from "fs";
1711
+ import { join as join4 } from "path";
1058
1712
  import { homedir } from "os";
1059
1713
  function getPlatform() {
1060
1714
  const plat = process.platform;
@@ -1084,10 +1738,10 @@ function printRunResult(result) {
1084
1738
  console.error(err);
1085
1739
  }
1086
1740
  function systemdUnitPath(serviceName) {
1087
- return join3(homedir(), ".config", "systemd", "user", `${serviceName}.service`);
1741
+ return join4(homedir(), ".config", "systemd", "user", `${serviceName}.service`);
1088
1742
  }
1089
1743
  function launchdPlistPath(serviceName) {
1090
- return join3(homedir(), "Library", "LaunchAgents", `com.webmux.${serviceName}.plist`);
1744
+ return join4(homedir(), "Library", "LaunchAgents", `com.webmux.${serviceName}.plist`);
1091
1745
  }
1092
1746
  function serviceFilePath(config) {
1093
1747
  if (config.platform === "linux")
@@ -1113,7 +1767,7 @@ WantedBy=default.target
1113
1767
  `;
1114
1768
  }
1115
1769
  function generateLaunchdPlist(config) {
1116
- const logPath = join3(homedir(), "Library", "Logs", `webmux-${config.serviceName}.log`);
1770
+ const logPath = join4(homedir(), "Library", "Logs", `webmux-${config.serviceName}.log`);
1117
1771
  return `<?xml version="1.0" encoding="UTF-8"?>
1118
1772
  <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
1119
1773
  <plist version="1.0">
@@ -1180,7 +1834,7 @@ function uninstallCommands(config) {
1180
1834
  ];
1181
1835
  }
1182
1836
  function isInstalled(config) {
1183
- return existsSync3(serviceFilePath(config));
1837
+ return existsSync4(serviceFilePath(config));
1184
1838
  }
1185
1839
  async function install(config) {
1186
1840
  const filePath = serviceFilePath(config);
@@ -1284,8 +1938,8 @@ function logs(config) {
1284
1938
  if (config.platform === "linux") {
1285
1939
  proc = Bun.spawn(["journalctl", "--user", "-u", config.serviceName, "-f", "--no-pager"], { stdout: "inherit", stderr: "inherit" });
1286
1940
  } else {
1287
- const logPath = join3(homedir(), "Library", "Logs", `webmux-${config.serviceName}.log`);
1288
- if (!existsSync3(logPath)) {
1941
+ const logPath = join4(homedir(), "Library", "Logs", `webmux-${config.serviceName}.log`);
1942
+ if (!existsSync4(logPath)) {
1289
1943
  R2.error(`Log file not found: ${logPath}`);
1290
1944
  return;
1291
1945
  }
@@ -1382,8 +2036,8 @@ var init_service = __esm(() => {
1382
2036
  });
1383
2037
 
1384
2038
  // bin/src/webmux.ts
1385
- import { resolve, dirname, join as join4 } from "path";
1386
- import { existsSync as existsSync4 } from "fs";
2039
+ import { resolve, dirname, join as join5 } from "path";
2040
+ import { existsSync as existsSync5 } from "fs";
1387
2041
  import { fileURLToPath } from "url";
1388
2042
  var PKG_ROOT = resolve(dirname(fileURLToPath(import.meta.url)), "..");
1389
2043
  function usage2() {
@@ -1437,12 +2091,12 @@ Run webmux --help for usage.`);
1437
2091
  process.exit(1);
1438
2092
  }
1439
2093
  }
1440
- if (!existsSync4(resolve(process.cwd(), ".webmux.yaml"))) {
2094
+ if (!existsSync5(resolve(process.cwd(), ".webmux.yaml"))) {
1441
2095
  console.error("No .webmux.yaml found in this directory.\nRun `webmux init` to set up your project.");
1442
2096
  process.exit(1);
1443
2097
  }
1444
2098
  async function loadEnvFile(path) {
1445
- if (!existsSync4(path))
2099
+ if (!existsSync5(path))
1446
2100
  return;
1447
2101
  const lines = (await Bun.file(path).text()).split(`
1448
2102
  `);
@@ -1507,9 +2161,9 @@ function cleanup() {
1507
2161
  }
1508
2162
  process.on("SIGINT", cleanup);
1509
2163
  process.on("SIGTERM", cleanup);
1510
- var backendEntry = join4(PKG_ROOT, "backend", "dist", "server.js");
1511
- var staticDir = join4(PKG_ROOT, "frontend", "dist");
1512
- if (!existsSync4(staticDir)) {
2164
+ var backendEntry = join5(PKG_ROOT, "backend", "dist", "server.js");
2165
+ var staticDir = join5(PKG_ROOT, "frontend", "dist");
2166
+ if (!existsSync5(staticDir)) {
1513
2167
  console.error(`Error: frontend/dist/ not found. Run 'bun run build' first.`);
1514
2168
  process.exit(1);
1515
2169
  }