webmux 0.29.0 → 0.30.0

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
@@ -16413,7 +16413,7 @@ var init_archive_state_service = __esm(() => {
16413
16413
 
16414
16414
  // backend/src/adapters/agent-runtime.ts
16415
16415
  import { chmod as chmod2, mkdir as mkdir3 } from "fs/promises";
16416
- import { dirname as dirname4, join as join9 } from "path";
16416
+ import { dirname as dirname4, join as join9, resolve as resolve6 } from "path";
16417
16417
  function shellQuote(value) {
16418
16418
  return `'${value.replaceAll("'", "'\\''")}'`;
16419
16419
  }
@@ -16432,6 +16432,7 @@ from pathlib import Path
16432
16432
 
16433
16433
 
16434
16434
  CONTROL_ENV_PATH = Path(__file__).resolve().with_name("control.env")
16435
+ CONTROL_REQUEST_TIMEOUT_SECONDS = 2
16435
16436
 
16436
16437
 
16437
16438
  def read_control_env():
@@ -16461,6 +16462,7 @@ def build_parser():
16461
16462
 
16462
16463
  status_changed = subparsers.add_parser("status-changed")
16463
16464
  status_changed.add_argument("--lifecycle", choices=["starting", "running", "idle", "stopped"], required=True)
16465
+ status_changed.add_argument("--best-effort", action="store_true")
16464
16466
 
16465
16467
  pr_opened = subparsers.add_parser("pr-opened")
16466
16468
  pr_opened.add_argument("--url")
@@ -16470,6 +16472,11 @@ def build_parser():
16470
16472
 
16471
16473
  subparsers.add_parser("claude-user-prompt-submit")
16472
16474
  subparsers.add_parser("claude-post-tool-use")
16475
+ subparsers.add_parser("codex-session-start")
16476
+ subparsers.add_parser("codex-user-prompt-submit")
16477
+ subparsers.add_parser("codex-permission-request")
16478
+ subparsers.add_parser("codex-post-tool-use")
16479
+ subparsers.add_parser("codex-stop")
16473
16480
 
16474
16481
  return parser
16475
16482
 
@@ -16512,6 +16519,41 @@ def read_hook_payload():
16512
16519
  return parsed if isinstance(parsed, dict) else {}
16513
16520
 
16514
16521
 
16522
+ def iter_string_values(value):
16523
+ if isinstance(value, str):
16524
+ yield value
16525
+ return
16526
+ if isinstance(value, dict):
16527
+ for child in value.values():
16528
+ yield from iter_string_values(child)
16529
+ return
16530
+ if isinstance(value, list):
16531
+ for child in value:
16532
+ yield from iter_string_values(child)
16533
+
16534
+
16535
+ def find_pr_url(value):
16536
+ for text in iter_string_values(value):
16537
+ match = re.search(r"https://github\\.com/[^\\s\\"]+/pull/\\d+", text)
16538
+ if match:
16539
+ return match.group(0)
16540
+ return None
16541
+
16542
+
16543
+ def maybe_send_pr_opened(hook_payload, control_env):
16544
+ tool_name = hook_payload.get("tool_name")
16545
+ tool_input = hook_payload.get("tool_input")
16546
+ if not isinstance(tool_input, dict) or tool_name != "Bash":
16547
+ return True
16548
+
16549
+ command = tool_input.get("command")
16550
+ if not isinstance(command, str) or "gh pr create" not in command:
16551
+ return True
16552
+
16553
+ pr_args = argparse.Namespace(url=find_pr_url(hook_payload.get("tool_response")))
16554
+ return send_payload(build_payload("pr-opened", pr_args, control_env), control_env)
16555
+
16556
+
16515
16557
  def send_payload(payload, control_env):
16516
16558
  request = urllib.request.Request(
16517
16559
  control_env["WEBMUX_CONTROL_URL"],
@@ -16524,7 +16566,7 @@ def send_payload(payload, control_env):
16524
16566
  )
16525
16567
 
16526
16568
  try:
16527
- with urllib.request.urlopen(request, timeout=10) as response:
16569
+ with urllib.request.urlopen(request, timeout=CONTROL_REQUEST_TIMEOUT_SECONDS) as response:
16528
16570
  if response.status < 200 or response.status >= 300:
16529
16571
  print(f"control endpoint returned HTTP {response.status}", file=sys.stderr)
16530
16572
  return False
@@ -16558,34 +16600,40 @@ def main():
16558
16600
  print(f"missing control env keys: {', '.join(missing)}", file=sys.stderr)
16559
16601
  return 1
16560
16602
 
16603
+ if parsed.command == "codex-session-start":
16604
+ send_payload(build_payload("status-changed", argparse.Namespace(lifecycle="idle"), control_env), control_env)
16605
+ return 0
16606
+
16607
+ if parsed.command == "codex-user-prompt-submit":
16608
+ send_payload(build_payload("status-changed", argparse.Namespace(lifecycle="running"), control_env), control_env)
16609
+ return 0
16610
+
16561
16611
  if parsed.command == "claude-user-prompt-submit":
16562
16612
  if not send_payload(build_payload("status-changed", argparse.Namespace(lifecycle="running"), control_env), control_env):
16563
16613
  return 1
16564
16614
  return 0
16565
16615
 
16566
- if parsed.command == "claude-post-tool-use":
16567
- hook_payload = read_hook_payload()
16568
- tool_name = hook_payload.get("tool_name")
16569
- tool_input = hook_payload.get("tool_input")
16570
- if not isinstance(tool_input, dict) or tool_name != "Bash":
16571
- return 0
16616
+ if parsed.command == "codex-permission-request":
16617
+ send_payload(build_payload("status-changed", argparse.Namespace(lifecycle="idle"), control_env), control_env)
16618
+ return 0
16572
16619
 
16573
- command = tool_input.get("command")
16574
- if not isinstance(command, str) or "gh pr create" not in command:
16575
- return 0
16620
+ if parsed.command == "codex-post-tool-use":
16621
+ hook_payload = read_hook_payload()
16622
+ maybe_send_pr_opened(hook_payload, control_env)
16623
+ return 0
16576
16624
 
16577
- pr_args = argparse.Namespace(url=None)
16578
- tool_response = hook_payload.get("tool_response")
16579
- if isinstance(tool_response, str):
16580
- match = re.search(r"https://github\\.com/[^\\s\\"]+/pull/\\d+", tool_response)
16581
- if match:
16582
- pr_args.url = match.group(0)
16625
+ if parsed.command == "claude-post-tool-use":
16626
+ hook_payload = read_hook_payload()
16627
+ return 0 if maybe_send_pr_opened(hook_payload, control_env) else 1
16583
16628
 
16584
- return 0 if send_payload(build_payload("pr-opened", pr_args, control_env), control_env) else 1
16629
+ if parsed.command == "codex-stop":
16630
+ send_payload(build_payload("agent-stopped", parsed, control_env), control_env)
16631
+ print(json.dumps({}))
16632
+ return 0
16585
16633
 
16586
16634
  payload = build_payload(parsed.command, parsed, control_env)
16587
16635
  if not send_payload(payload, control_env):
16588
- return 1
16636
+ return 0 if getattr(parsed, "best_effort", False) else 1
16589
16637
 
16590
16638
  return 0
16591
16639
 
@@ -16655,6 +16703,81 @@ function buildClaudeHookSettings(input) {
16655
16703
  }
16656
16704
  };
16657
16705
  }
16706
+ function buildCodexHookSettings(input) {
16707
+ const statusCommand = `${shellQuote(input.agentCtlPath)} status-changed --lifecycle running --best-effort`;
16708
+ return {
16709
+ hooks: {
16710
+ SessionStart: [
16711
+ {
16712
+ matcher: "startup|resume|clear",
16713
+ hooks: [
16714
+ {
16715
+ type: "command",
16716
+ command: `${shellQuote(input.agentCtlPath)} codex-session-start`,
16717
+ timeout: 30
16718
+ }
16719
+ ]
16720
+ }
16721
+ ],
16722
+ UserPromptSubmit: [
16723
+ {
16724
+ hooks: [
16725
+ {
16726
+ type: "command",
16727
+ command: `${shellQuote(input.agentCtlPath)} codex-user-prompt-submit`,
16728
+ timeout: 30
16729
+ }
16730
+ ]
16731
+ }
16732
+ ],
16733
+ PermissionRequest: [
16734
+ {
16735
+ hooks: [
16736
+ {
16737
+ type: "command",
16738
+ command: `${shellQuote(input.agentCtlPath)} codex-permission-request`,
16739
+ timeout: 30
16740
+ }
16741
+ ]
16742
+ }
16743
+ ],
16744
+ PreToolUse: [
16745
+ {
16746
+ hooks: [
16747
+ {
16748
+ type: "command",
16749
+ command: statusCommand,
16750
+ timeout: 30
16751
+ }
16752
+ ]
16753
+ }
16754
+ ],
16755
+ PostToolUse: [
16756
+ {
16757
+ matcher: "Bash",
16758
+ hooks: [
16759
+ {
16760
+ type: "command",
16761
+ command: `${shellQuote(input.agentCtlPath)} codex-post-tool-use`,
16762
+ timeout: 30
16763
+ }
16764
+ ]
16765
+ }
16766
+ ],
16767
+ Stop: [
16768
+ {
16769
+ hooks: [
16770
+ {
16771
+ type: "command",
16772
+ command: `${shellQuote(input.agentCtlPath)} codex-stop`,
16773
+ timeout: 30
16774
+ }
16775
+ ]
16776
+ }
16777
+ ]
16778
+ }
16779
+ };
16780
+ }
16658
16781
  async function mergeClaudeSettings(settingsPath, hookSettings) {
16659
16782
  let existing = {};
16660
16783
  try {
@@ -16674,13 +16797,77 @@ async function mergeClaudeSettings(settingsPath, hookSettings) {
16674
16797
  await Bun.write(settingsPath, JSON.stringify(merged, null, 2) + `
16675
16798
  `);
16676
16799
  }
16800
+ function commandStartsWithAgentCtl(command, agentCtlPath) {
16801
+ const trimmedCommand = command.trimStart();
16802
+ const quotedAgentCtlPath = shellQuote(agentCtlPath);
16803
+ return trimmedCommand === agentCtlPath || trimmedCommand.startsWith(`${agentCtlPath} `) || trimmedCommand === quotedAgentCtlPath || trimmedCommand.startsWith(`${quotedAgentCtlPath} `);
16804
+ }
16805
+ function isWebmuxHookGroup(group, agentCtlPath) {
16806
+ if (!isRecord5(group) || !Array.isArray(group.hooks))
16807
+ return false;
16808
+ return group.hooks.some((hook) => isRecord5(hook) && typeof hook.command === "string" && commandStartsWithAgentCtl(hook.command, agentCtlPath));
16809
+ }
16810
+ async function mergeCodexHooksFile(hooksPath, hookSettings, agentCtlPath) {
16811
+ let existing = {};
16812
+ try {
16813
+ const file = Bun.file(hooksPath);
16814
+ if (await file.exists()) {
16815
+ const parsed = await file.json();
16816
+ if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
16817
+ existing = parsed;
16818
+ }
16819
+ }
16820
+ } catch {
16821
+ existing = {};
16822
+ }
16823
+ const existingHooks = isRecord5(existing.hooks) ? existing.hooks : {};
16824
+ const mergedHooks = { ...existingHooks };
16825
+ for (const [eventName, groups] of Object.entries(hookSettings)) {
16826
+ const eventGroups = existingHooks[eventName];
16827
+ const preservedGroups = Array.isArray(eventGroups) ? eventGroups.filter((group) => !isWebmuxHookGroup(group, agentCtlPath)) : [];
16828
+ mergedHooks[eventName] = [...preservedGroups, ...groups];
16829
+ }
16830
+ await Bun.write(hooksPath, JSON.stringify({ ...existing, hooks: mergedHooks }, null, 2) + `
16831
+ `);
16832
+ }
16833
+ async function resolveGitCommonDir(gitDir) {
16834
+ try {
16835
+ const commonDir = (await Bun.file(join9(gitDir, "commondir")).text()).trim();
16836
+ if (!commonDir)
16837
+ return gitDir;
16838
+ return commonDir.startsWith("/") ? commonDir : resolve6(gitDir, commonDir);
16839
+ } catch {
16840
+ return gitDir;
16841
+ }
16842
+ }
16843
+ async function ensureGeneratedCodexHooksIgnored(gitDir) {
16844
+ const commonDir = await resolveGitCommonDir(gitDir);
16845
+ const excludePath = join9(commonDir, "info", "exclude");
16846
+ let existing = "";
16847
+ try {
16848
+ existing = await Bun.file(excludePath).text();
16849
+ } catch {
16850
+ existing = "";
16851
+ }
16852
+ const lines = existing.split(/\r?\n/).map((line) => line.trim());
16853
+ if (lines.includes(GENERATED_CODEX_HOOKS_EXCLUDE))
16854
+ return;
16855
+ await mkdir3(dirname4(excludePath), { recursive: true });
16856
+ const separator = existing.length > 0 && !existing.endsWith(`
16857
+ `) ? `
16858
+ ` : "";
16859
+ await Bun.write(excludePath, `${existing}${separator}${GENERATED_CODEX_HOOKS_EXCLUDE}
16860
+ `);
16861
+ }
16677
16862
  async function ensureAgentRuntimeArtifacts(input) {
16678
16863
  const storagePaths = getWorktreeStoragePaths(input.gitDir);
16679
16864
  const artifacts = {
16680
16865
  agentCtlPath: join9(storagePaths.webmuxDir, "webmux-agentctl"),
16681
- claudeSettingsPath: join9(input.worktreePath, ".claude", "settings.local.json")
16866
+ claudeSettingsPath: join9(input.worktreePath, ".claude", "settings.local.json"),
16867
+ codexHooksPath: join9(input.worktreePath, ".codex", "hooks.json")
16682
16868
  };
16683
16869
  await mkdir3(dirname4(artifacts.claudeSettingsPath), { recursive: true });
16870
+ await mkdir3(dirname4(artifacts.codexHooksPath), { recursive: true });
16684
16871
  await Bun.write(artifacts.agentCtlPath, buildAgentCtlScript());
16685
16872
  await chmod2(artifacts.agentCtlPath, 493);
16686
16873
  const hookSettings = buildClaudeHookSettings(artifacts);
@@ -16689,8 +16876,11 @@ async function ensureAgentRuntimeArtifacts(input) {
16689
16876
  throw new Error("Invalid Claude hook settings");
16690
16877
  }
16691
16878
  await mergeClaudeSettings(artifacts.claudeSettingsPath, hooks);
16879
+ await ensureGeneratedCodexHooksIgnored(input.gitDir);
16880
+ await mergeCodexHooksFile(artifacts.codexHooksPath, buildCodexHookSettings(artifacts).hooks, artifacts.agentCtlPath);
16692
16881
  return artifacts;
16693
16882
  }
16883
+ var GENERATED_CODEX_HOOKS_EXCLUDE = ".codex/hooks.json";
16694
16884
  var init_agent_runtime = __esm(() => {
16695
16885
  init_fs();
16696
16886
  });
@@ -16707,15 +16897,16 @@ function buildDockerRuntimeBootstrap(runtimeEnvPath) {
16707
16897
  }
16708
16898
  function buildBuiltInAgentInvocation(input) {
16709
16899
  if (input.agent === "codex") {
16900
+ const hooksFlag = " --enable codex_hooks";
16710
16901
  const yoloFlag2 = input.yolo ? " --yolo" : "";
16711
16902
  if (input.launchMode === "resume") {
16712
- return `codex${yoloFlag2} resume --last`;
16903
+ return `codex${hooksFlag}${yoloFlag2} resume --last`;
16713
16904
  }
16714
16905
  const promptSuffix2 = input.prompt ? ` -- ${quoteShell(input.prompt)}` : "";
16715
16906
  if (input.systemPrompt) {
16716
- return `codex${yoloFlag2} -c ${quoteShell(`developer_instructions=${input.systemPrompt}`)}${promptSuffix2}`;
16907
+ return `codex${hooksFlag}${yoloFlag2} -c ${quoteShell(`developer_instructions=${input.systemPrompt}`)}${promptSuffix2}`;
16717
16908
  }
16718
- return `codex${yoloFlag2}${promptSuffix2}`;
16909
+ return `codex${hooksFlag}${yoloFlag2}${promptSuffix2}`;
16719
16910
  }
16720
16911
  const yoloFlag = input.yolo ? " --dangerously-skip-permissions" : "";
16721
16912
  if (input.launchMode === "resume") {
@@ -16891,7 +17082,7 @@ var init_agent_registry = __esm(() => {
16891
17082
  });
16892
17083
 
16893
17084
  // backend/src/services/session-service.ts
16894
- import { resolve as resolve6 } from "path";
17085
+ import { resolve as resolve7 } from "path";
16895
17086
  function quoteShell2(value) {
16896
17087
  return `'${value.replaceAll("'", "'\\''")}'`;
16897
17088
  }
@@ -16905,7 +17096,7 @@ function buildCommandPaneStartupCommand(template, ctx) {
16905
17096
  if (!template.workingDir) {
16906
17097
  return template.command;
16907
17098
  }
16908
- const workingDir = resolve6(resolvePaneCwd(template, ctx), template.workingDir);
17099
+ const workingDir = resolve7(resolvePaneCwd(template, ctx), template.workingDir);
16909
17100
  return `cd -- ${quoteShell2(workingDir)} && ${template.command}`;
16910
17101
  }
16911
17102
  function resolvePaneStartupCommand(template, ctx) {
@@ -17135,7 +17326,7 @@ var init_worktree_service = __esm(() => {
17135
17326
 
17136
17327
  // backend/src/services/lifecycle-service.ts
17137
17328
  import { mkdir as mkdir4 } from "fs/promises";
17138
- import { dirname as dirname5, resolve as resolve7 } from "path";
17329
+ import { dirname as dirname5, resolve as resolve8 } from "path";
17139
17330
  function toErrorMessage2(error) {
17140
17331
  return error instanceof Error ? error.message : String(error);
17141
17332
  }
@@ -17403,20 +17594,20 @@ class LifecycleService {
17403
17594
  return allocateServicePorts(metas, this.deps.config.services);
17404
17595
  }
17405
17596
  resolveWorktreePath(branch) {
17406
- return resolve7(this.deps.projectRoot, this.deps.config.workspace.worktreeRoot, branch);
17597
+ return resolve8(this.deps.projectRoot, this.deps.config.workspace.worktreeRoot, branch);
17407
17598
  }
17408
17599
  listLocalBranches() {
17409
- return this.deps.git.listLocalBranches(resolve7(this.deps.projectRoot));
17600
+ return this.deps.git.listLocalBranches(resolve8(this.deps.projectRoot));
17410
17601
  }
17411
17602
  listRemoteBranches() {
17412
- return this.deps.git.listRemoteBranches(resolve7(this.deps.projectRoot));
17603
+ return this.deps.git.listRemoteBranches(resolve8(this.deps.projectRoot));
17413
17604
  }
17414
17605
  listCheckedOutBranches() {
17415
- return new Set(this.deps.git.listWorktrees(resolve7(this.deps.projectRoot)).filter((entry) => !entry.bare && entry.branch !== null).map((entry) => entry.branch));
17606
+ return new Set(this.deps.git.listWorktrees(resolve8(this.deps.projectRoot)).filter((entry) => !entry.bare && entry.branch !== null).map((entry) => entry.branch));
17416
17607
  }
17417
17608
  listProjectWorktrees() {
17418
- const projectRoot2 = resolve7(this.deps.projectRoot);
17419
- return this.deps.git.listWorktrees(projectRoot2).filter((entry) => !entry.bare && resolve7(entry.path) !== projectRoot2);
17609
+ const projectRoot2 = resolve8(this.deps.projectRoot);
17610
+ return this.deps.git.listWorktrees(projectRoot2).filter((entry) => !entry.bare && resolve8(entry.path) !== projectRoot2);
17420
17611
  }
17421
17612
  async readManagedMetas() {
17422
17613
  const metas = await Promise.all(this.listProjectWorktrees().map(async (entry) => {
@@ -18088,9 +18279,9 @@ async function mapWithConcurrency(items, limit, fn) {
18088
18279
  }
18089
18280
 
18090
18281
  // backend/src/services/reconciliation-service.ts
18091
- import { basename as basename4, resolve as resolve8 } from "path";
18282
+ import { basename as basename4, resolve as resolve9 } from "path";
18092
18283
  function makeUnmanagedWorktreeId(path) {
18093
- return `unmanaged:${resolve8(path)}`;
18284
+ return `unmanaged:${resolve9(path)}`;
18094
18285
  }
18095
18286
  function isValidPort2(port) {
18096
18287
  return port !== null && Number.isInteger(port) && port >= 1 && port <= 65535;
@@ -18147,7 +18338,7 @@ class ReconciliationService {
18147
18338
  if (!options.force && this.now() - this.lastReconciledAt < this.freshnessMs) {
18148
18339
  return;
18149
18340
  }
18150
- const normalizedRepoRoot = resolve8(repoRoot);
18341
+ const normalizedRepoRoot = resolve9(repoRoot);
18151
18342
  const reconcilePromise = this.runReconcile(normalizedRepoRoot).then(() => {
18152
18343
  this.lastReconciledAt = this.now();
18153
18344
  });
@@ -18166,7 +18357,7 @@ class ReconciliationService {
18166
18357
  windows = [];
18167
18358
  }
18168
18359
  const seenWorktreeIds = new Set;
18169
- const candidateEntries = worktrees.filter((entry) => !entry.bare && resolve8(entry.path) !== normalizedRepoRoot);
18360
+ const candidateEntries = worktrees.filter((entry) => !entry.bare && resolve9(entry.path) !== normalizedRepoRoot);
18170
18361
  const reconciledStates = await mapWithConcurrency(candidateEntries, this.concurrency, async (entry) => {
18171
18362
  const gitDir = this.deps.git.resolveWorktreeGitDir(entry.path);
18172
18363
  const meta = await readWorktreeMeta(gitDir);
@@ -18352,7 +18543,7 @@ __export(exports_worktree_commands, {
18352
18543
  parseAddCommandArgs: () => parseAddCommandArgs,
18353
18544
  getWorktreeCommandUsage: () => getWorktreeCommandUsage
18354
18545
  });
18355
- import { basename as basename5, resolve as resolve9 } from "path";
18546
+ import { basename as basename5, resolve as resolve10 } from "path";
18356
18547
  function getWorktreeCommandUsage(command) {
18357
18548
  switch (command) {
18358
18549
  case "add":
@@ -18633,8 +18824,8 @@ function parseListCommandArgs(args) {
18633
18824
  return { mode, search };
18634
18825
  }
18635
18826
  function listProjectWorktrees(runtime) {
18636
- const projectDir = resolve9(runtime.projectDir);
18637
- return runtime.git.listWorktrees(projectDir).filter((entry) => !entry.bare && resolve9(entry.path) !== projectDir);
18827
+ const projectDir = resolve10(runtime.projectDir);
18828
+ return runtime.git.listWorktrees(projectDir).filter((entry) => !entry.bare && resolve10(entry.path) !== projectDir);
18638
18829
  }
18639
18830
  async function defaultConfirmPrune(worktreeCount) {
18640
18831
  const response = await ot2({
@@ -18644,7 +18835,7 @@ async function defaultConfirmPrune(worktreeCount) {
18644
18835
  return !q(response) && response;
18645
18836
  }
18646
18837
  function defaultSwitchToTmuxWindow(projectDir, branch) {
18647
- const sessionName = buildProjectSessionName(resolve9(projectDir));
18838
+ const sessionName = buildProjectSessionName(resolve10(projectDir));
18648
18839
  const windowName = buildWorktreeWindowName(branch);
18649
18840
  const target = `${sessionName}:${windowName}`;
18650
18841
  const selectResult = Bun.spawnSync(["tmux", "select-window", "-t", target], {
@@ -18676,7 +18867,7 @@ function matchesListSearch(row, query) {
18676
18867
  return query.length === 0 || row.searchText.toLowerCase().includes(query.toLowerCase());
18677
18868
  }
18678
18869
  async function listWorktrees(runtime, stdout, options) {
18679
- const projectDir = resolve9(runtime.projectDir);
18870
+ const projectDir = resolve10(runtime.projectDir);
18680
18871
  const entries = listProjectWorktrees(runtime);
18681
18872
  if (entries.length === 0) {
18682
18873
  stdout("No worktrees found.");
@@ -18701,7 +18892,7 @@ async function listWorktrees(runtime, stdout, options) {
18701
18892
  return {
18702
18893
  branch,
18703
18894
  isOpen,
18704
- archived: archivedPaths.has(resolve9(entry.path)),
18895
+ archived: archivedPaths.has(resolve10(entry.path)),
18705
18896
  info,
18706
18897
  searchText: [
18707
18898
  branch,
@@ -18905,13 +19096,13 @@ var init_worktree_commands = __esm(() => {
18905
19096
  });
18906
19097
 
18907
19098
  // bin/src/webmux.ts
18908
- import { resolve as resolve10, dirname as dirname6, join as join11 } from "path";
19099
+ import { resolve as resolve11, dirname as dirname6, join as join11 } from "path";
18909
19100
  import { existsSync as existsSync5 } from "fs";
18910
19101
  import { fileURLToPath } from "url";
18911
19102
  // package.json
18912
19103
  var package_default = {
18913
19104
  name: "webmux",
18914
- version: "0.29.0",
19105
+ version: "0.30.0",
18915
19106
  description: "Web dashboard for workmux \u2014 browser UI with embedded terminals, PR monitoring, and CI integration",
18916
19107
  type: "module",
18917
19108
  repository: {
@@ -18968,7 +19159,7 @@ var package_default = {
18968
19159
  };
18969
19160
 
18970
19161
  // bin/src/webmux.ts
18971
- var PKG_ROOT = resolve10(dirname6(fileURLToPath(import.meta.url)), "..");
19162
+ var PKG_ROOT = resolve11(dirname6(fileURLToPath(import.meta.url)), "..");
18972
19163
  function usage2() {
18973
19164
  console.log(`
18974
19165
  webmux \u2014 Dev dashboard for managing Git worktrees
@@ -19183,8 +19374,8 @@ async function main(args = process.argv.slice(2)) {
19183
19374
  const code = await proc.exited;
19184
19375
  process.exit(code);
19185
19376
  }
19186
- await loadEnvFile(resolve10(process.cwd(), ".env.local"));
19187
- await loadEnvFile(resolve10(process.cwd(), ".env"));
19377
+ await loadEnvFile(resolve11(process.cwd(), ".env.local"));
19378
+ await loadEnvFile(resolve11(process.cwd(), ".env"));
19188
19379
  if (isWorktreeCommand(parsed.command)) {
19189
19380
  const { runWorktreeCommand: runWorktreeCommand2 } = await Promise.resolve().then(() => (init_worktree_commands(), exports_worktree_commands));
19190
19381
  const exitCode2 = await runWorktreeCommand2({
@@ -19199,7 +19390,7 @@ async function main(args = process.argv.slice(2)) {
19199
19390
  usage2();
19200
19391
  process.exit(0);
19201
19392
  }
19202
- if (!existsSync5(resolve10(process.cwd(), ".webmux.yaml"))) {
19393
+ if (!existsSync5(resolve11(process.cwd(), ".webmux.yaml"))) {
19203
19394
  console.error("No .webmux.yaml found in this directory.\nRun `webmux init` to set up your project.");
19204
19395
  process.exit(1);
19205
19396
  }
@@ -1,4 +1,4 @@
1
- import{t as ue,a as rt,b as Be,g as we,r as at,c as lt,N as ot,d as dt,p as ct,e as ft,s as de,f as ut,u as Re,h as Y,i as ht,j as pt,k as D,B as bt,l as We,m as ee,n as X,o as ye,q as mt,v as gt,w as Q,x as ce,C as vt,y as Ee,z as Se,A as wt,D as Le,E as yt,F as se,G as xt}from"./index-D4JuH244.js";import"./vendor-xterm-DvXGiZvM.js";function Tt(s,n,t=!1,e=!1,i=!1,o=!1){var r=s,f="";if(t)var c=s;ue(()=>{var u=rt;if(f!==(f=n()??"")){if(t){u.nodes=null,c.innerHTML=f,f!==""&&Be(we(c),c.lastChild);return}if(u.nodes!==null&&(at(u.nodes.start,u.nodes.end),u.nodes=null),f!==""){var g=e?ot:i?dt:void 0,x=lt(e?"svg":i?"math":"template",g);x.innerHTML=f;var S=e||i?x:x.content;if(Be(we(S),S.lastChild),e||i)for(;we(S);)r.before(we(S));else r.before(S)}}})}var A;(function(s){s.INSERT="insert",s.DELETE="delete",s.CONTEXT="context"})(A||(A={}));const Nt={LINE_BY_LINE:"line-by-line"},Ct={NONE:"none"},Et={WORD:"word"};var he;(function(s){s.AUTO="auto",s.DARK="dark",s.LIGHT="light"})(he||(he={}));const St=["-","[","]","/","{","}","(",")","*","+","?",".","\\","^","$","|"],Lt=RegExp("["+St.join("\\")+"]","g");function Dt(s){return s.replace(Lt,"\\$&")}function je(s){return s&&s.replace(/\\/g,"/")}function _t(s){let n,t,e,i=0;for(n=0,e=s.length;n<e;n++)t=s.charCodeAt(n),i=(i<<5)-i+t,i|=0;return i}function Je(s){const n=s.length;let t=-1/0;for(let e=0;e<n;e++)t=Math.max(t,s[e]);return t}function ke(s,n){const t=s.split(".");return t.length>1?t[t.length-1]:n}function ze(s,n){return n.reduce((t,e)=>t||s.startsWith(e),!1)}const Ue=["a/","b/","i/","w/","c/","o/"];function ae(s,n,t){const e=t!==void 0?[...Ue,t]:Ue,i=n?new RegExp(`^${Dt(n)} "?(.+?)"?$`):new RegExp('^"?(.+?)"?$'),[,o=""]=i.exec(s)||[],r=e.find(c=>o.indexOf(c)===0);return(r?o.slice(r.length):o).replace(/\s+\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}(?:\.\d+)? [+-]\d{4}.*$/,"")}function Pt(s,n){return ae(s,"---",n)}function It(s,n){return ae(s,"+++",n)}function Mt(s,n={}){const t=[];let e=null,i=null,o=null,r=null,f=null,c=null,u=null;const g="--- ",x="+++ ",S="@@",a=/^old mode (\d{6})/,d=/^new mode (\d{6})/,m=/^deleted file mode (\d{6})/,p=/^new file mode (\d{6})/,y=/^copy from "?(.+)"?/,N=/^copy to "?(.+)"?/,T=/^rename from "?(.+)"?/,P=/^rename to "?(.+)"?/,L=/^similarity index (\d+)%/,I=/^dissimilarity index (\d+)%/,ie=/^index ([\da-z]+)\.\.([\da-z]+)\s*(\d{6})?/,l=/^Binary files (.*) and (.*) differ/,h=/^GIT binary patch/,w=/^index ([\da-z]+),([\da-z]+)\.\.([\da-z]+)/,C=/^mode (\d{6}),(\d{6})\.\.(\d{6})/,M=/^new file mode (\d{6})/,V=/^deleted file mode (\d{6}),(\d{6})/,k=s.replace(/\/g,"").replace(/\r\n?/g,`
1
+ import{t as ue,a as rt,b as Be,g as we,r as at,c as lt,N as ot,d as dt,p as ct,e as ft,s as de,f as ut,u as Re,h as Y,i as ht,j as pt,k as D,B as bt,l as We,m as ee,n as X,o as ye,q as mt,v as gt,w as Q,x as ce,C as vt,y as Ee,z as Se,A as wt,D as Le,E as yt,F as se,G as xt}from"./index-FETEudgI.js";import"./vendor-xterm-DvXGiZvM.js";function Tt(s,n,t=!1,e=!1,i=!1,o=!1){var r=s,f="";if(t)var c=s;ue(()=>{var u=rt;if(f!==(f=n()??"")){if(t){u.nodes=null,c.innerHTML=f,f!==""&&Be(we(c),c.lastChild);return}if(u.nodes!==null&&(at(u.nodes.start,u.nodes.end),u.nodes=null),f!==""){var g=e?ot:i?dt:void 0,x=lt(e?"svg":i?"math":"template",g);x.innerHTML=f;var S=e||i?x:x.content;if(Be(we(S),S.lastChild),e||i)for(;we(S);)r.before(we(S));else r.before(S)}}})}var A;(function(s){s.INSERT="insert",s.DELETE="delete",s.CONTEXT="context"})(A||(A={}));const Nt={LINE_BY_LINE:"line-by-line"},Ct={NONE:"none"},Et={WORD:"word"};var he;(function(s){s.AUTO="auto",s.DARK="dark",s.LIGHT="light"})(he||(he={}));const St=["-","[","]","/","{","}","(",")","*","+","?",".","\\","^","$","|"],Lt=RegExp("["+St.join("\\")+"]","g");function Dt(s){return s.replace(Lt,"\\$&")}function je(s){return s&&s.replace(/\\/g,"/")}function _t(s){let n,t,e,i=0;for(n=0,e=s.length;n<e;n++)t=s.charCodeAt(n),i=(i<<5)-i+t,i|=0;return i}function Je(s){const n=s.length;let t=-1/0;for(let e=0;e<n;e++)t=Math.max(t,s[e]);return t}function ke(s,n){const t=s.split(".");return t.length>1?t[t.length-1]:n}function ze(s,n){return n.reduce((t,e)=>t||s.startsWith(e),!1)}const Ue=["a/","b/","i/","w/","c/","o/"];function ae(s,n,t){const e=t!==void 0?[...Ue,t]:Ue,i=n?new RegExp(`^${Dt(n)} "?(.+?)"?$`):new RegExp('^"?(.+?)"?$'),[,o=""]=i.exec(s)||[],r=e.find(c=>o.indexOf(c)===0);return(r?o.slice(r.length):o).replace(/\s+\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}(?:\.\d+)? [+-]\d{4}.*$/,"")}function Pt(s,n){return ae(s,"---",n)}function It(s,n){return ae(s,"+++",n)}function Mt(s,n={}){const t=[];let e=null,i=null,o=null,r=null,f=null,c=null,u=null;const g="--- ",x="+++ ",S="@@",a=/^old mode (\d{6})/,d=/^new mode (\d{6})/,m=/^deleted file mode (\d{6})/,p=/^new file mode (\d{6})/,y=/^copy from "?(.+)"?/,N=/^copy to "?(.+)"?/,T=/^rename from "?(.+)"?/,P=/^rename to "?(.+)"?/,L=/^similarity index (\d+)%/,I=/^dissimilarity index (\d+)%/,ie=/^index ([\da-z]+)\.\.([\da-z]+)\s*(\d{6})?/,l=/^Binary files (.*) and (.*) differ/,h=/^GIT binary patch/,w=/^index ([\da-z]+),([\da-z]+)\.\.([\da-z]+)/,C=/^mode (\d{6}),(\d{6})\.\.(\d{6})/,M=/^new file mode (\d{6})/,V=/^deleted file mode (\d{6}),(\d{6})/,k=s.replace(/\/g,"").replace(/\r\n?/g,`
2
2
  `).split(`
3
3
  `);function E(){i!==null&&e!==null&&(e.blocks.push(i),i=null)}function R(){e!==null&&(!e.oldName&&c!==null&&(e.oldName=c),!e.newName&&u!==null&&(e.newName=u),e.newName&&(t.push(e),e=null)),c=null,u=null}function $(){E(),R(),e={blocks:[],deletedLines:0,addedLines:0}}function j(b){E();let _;e!==null&&((_=/^@@ -(\d+)(?:,\d+)? \+(\d+)(?:,\d+)? @@.*/.exec(b))?(e.isCombined=!1,o=parseInt(_[1],10),f=parseInt(_[2],10)):(_=/^@@@ -(\d+)(?:,\d+)? -(\d+)(?:,\d+)? \+(\d+)(?:,\d+)? @@@.*/.exec(b))?(e.isCombined=!0,o=parseInt(_[1],10),r=parseInt(_[2],10),f=parseInt(_[3],10)):(b.startsWith(S)&&console.error("Failed to parse lines, starting in 0!"),o=0,f=0,e.isCombined=!1)),i={lines:[],oldStartLine:o,oldStartLine2:r,newStartLine:f,header:b}}function O(b){if(e===null||i===null||o===null||f===null)return;const _={content:b},v=e.isCombined?["+ "," +","++"]:["+"],z=e.isCombined?["- "," -","--"]:["-"];ze(b,v)?(e.addedLines++,_.type=A.INSERT,_.oldNumber=void 0,_.newNumber=f++):ze(b,z)?(e.deletedLines++,_.type=A.DELETE,_.oldNumber=o++,_.newNumber=void 0):(_.type=A.CONTEXT,_.oldNumber=o++,_.newNumber=f++),i.lines.push(_)}function q(b,_){let v=_;for(;v<k.length-3;){if(b.startsWith("diff"))return!1;if(k[v].startsWith(g)&&k[v+1].startsWith(x)&&k[v+2].startsWith(S))return!0;v++}return!1}return k.forEach((b,_)=>{if(!b||b.startsWith("*"))return;let v;const z=k[_-1],le=k[_+1],be=k[_+2];if(b.startsWith("diff --git")||b.startsWith("diff --combined")){if($(),(v=/^diff --git "?([a-ciow]\/.+)"? "?([a-ciow]\/.+)"?/.exec(b))&&(c=ae(v[1],void 0,n.dstPrefix),u=ae(v[2],void 0,n.srcPrefix)),e===null)throw new Error("Where is my file !!!");e.isGitDiff=!0;return}if(b.startsWith("Binary files")&&!(e!=null&&e.isGitDiff)){if($(),(v=/^Binary files "?([a-ciow]\/.+)"? and "?([a-ciow]\/.+)"? differ/.exec(b))&&(c=ae(v[1],void 0,n.dstPrefix),u=ae(v[2],void 0,n.srcPrefix)),e===null)throw new Error("Where is my file !!!");e.isBinary=!0;return}if((!e||!e.isGitDiff&&e&&b.startsWith(g)&&le.startsWith(x)&&be.startsWith(S))&&$(),e!=null&&e.isTooBig)return;if(e&&(typeof n.diffMaxChanges=="number"&&e.addedLines+e.deletedLines>n.diffMaxChanges||typeof n.diffMaxLineLength=="number"&&b.length>n.diffMaxLineLength)){e.isTooBig=!0,e.addedLines=0,e.deletedLines=0,e.blocks=[],i=null;const oe=typeof n.diffTooBigMessage=="function"?n.diffTooBigMessage(t.length):"Diff too big to be displayed";j(oe);return}if(b.startsWith(g)&&le.startsWith(x)||b.startsWith(x)&&z.startsWith(g)){if(e&&!e.oldName&&b.startsWith("--- ")&&(v=Pt(b,n.srcPrefix))){e.oldName=v,e.language=ke(e.oldName,e.language);return}if(e&&!e.newName&&b.startsWith("+++ ")&&(v=It(b,n.dstPrefix))){e.newName=v,e.language=ke(e.newName,e.language);return}}if(e&&(b.startsWith(S)||e.isGitDiff&&e.oldName&&e.newName&&!i)){j(b);return}if(i&&(b.startsWith("+")||b.startsWith("-")||b.startsWith(" "))){O(b);return}const re=!q(b,_);if(e===null)throw new Error("Where is my file !!!");(v=a.exec(b))?e.oldMode=v[1]:(v=d.exec(b))?e.newMode=v[1]:(v=m.exec(b))?(e.deletedFileMode=v[1],e.isDeleted=!0):(v=p.exec(b))?(e.newFileMode=v[1],e.isNew=!0):(v=y.exec(b))?(re&&(e.oldName=v[1]),e.isCopy=!0):(v=N.exec(b))?(re&&(e.newName=v[1]),e.isCopy=!0):(v=T.exec(b))?(re&&(e.oldName=v[1]),e.isRename=!0):(v=P.exec(b))?(re&&(e.newName=v[1]),e.isRename=!0):(v=l.exec(b))?(e.isBinary=!0,e.oldName=ae(v[1],void 0,n.srcPrefix),e.newName=ae(v[2],void 0,n.dstPrefix),j("Binary file")):h.test(b)?(e.isBinary=!0,j(b)):(v=L.exec(b))?e.unchangedPercentage=parseInt(v[1],10):(v=I.exec(b))?e.changedPercentage=parseInt(v[1],10):(v=ie.exec(b))?(e.checksumBefore=v[1],e.checksumAfter=v[2],v[3]&&(e.mode=v[3])):(v=w.exec(b))?(e.checksumBefore=[v[2],v[3]],e.checksumAfter=v[1]):(v=C.exec(b))?(e.oldMode=[v[2],v[3]],e.newMode=v[1]):(v=M.exec(b))?(e.newFileMode=v[1],e.isNew=!0):(v=V.exec(b))&&(e.deletedFileMode=v[1],e.isDeleted=!0)}),E(),R(),t}class Qe{diff(n,t,e={}){let i;typeof e=="function"?(i=e,e={}):"callback"in e&&(i=e.callback);const o=this.castInput(n,e),r=this.castInput(t,e),f=this.removeEmpty(this.tokenize(o,e)),c=this.removeEmpty(this.tokenize(r,e));return this.diffWithOptionsObj(f,c,e,i)}diffWithOptionsObj(n,t,e,i){var o;const r=N=>{if(N=this.postProcess(N,e),i){setTimeout(function(){i(N)},0);return}else return N},f=t.length,c=n.length;let u=1,g=f+c;e.maxEditLength!=null&&(g=Math.min(g,e.maxEditLength));const x=(o=e.timeout)!==null&&o!==void 0?o:1/0,S=Date.now()+x,a=[{oldPos:-1,lastComponent:void 0}];let d=this.extractCommon(a[0],t,n,0,e);if(a[0].oldPos+1>=c&&d+1>=f)return r(this.buildValues(a[0].lastComponent,t,n));let m=-1/0,p=1/0;const y=()=>{for(let N=Math.max(m,-u);N<=Math.min(p,u);N+=2){let T;const P=a[N-1],L=a[N+1];P&&(a[N-1]=void 0);let I=!1;if(L){const l=L.oldPos-N;I=L&&0<=l&&l<f}const ie=P&&P.oldPos+1<c;if(!I&&!ie){a[N]=void 0;continue}if(!ie||I&&P.oldPos<L.oldPos?T=this.addToPath(L,!0,!1,0,e):T=this.addToPath(P,!1,!0,1,e),d=this.extractCommon(T,t,n,N,e),T.oldPos+1>=c&&d+1>=f)return r(this.buildValues(T.lastComponent,t,n))||!0;a[N]=T,T.oldPos+1>=c&&(p=Math.min(p,N-1)),d+1>=f&&(m=Math.max(m,N+1))}u++};if(i)(function N(){setTimeout(function(){if(u>g||Date.now()>S)return i(void 0);y()||N()},0)})();else for(;u<=g&&Date.now()<=S;){const N=y();if(N)return N}}addToPath(n,t,e,i,o){const r=n.lastComponent;return r&&!o.oneChangePerToken&&r.added===t&&r.removed===e?{oldPos:n.oldPos+i,lastComponent:{count:r.count+1,added:t,removed:e,previousComponent:r.previousComponent}}:{oldPos:n.oldPos+i,lastComponent:{count:1,added:t,removed:e,previousComponent:r}}}extractCommon(n,t,e,i,o){const r=t.length,f=e.length;let c=n.oldPos,u=c-i,g=0;for(;u+1<r&&c+1<f&&this.equals(e[c+1],t[u+1],o);)u++,c++,g++,o.oneChangePerToken&&(n.lastComponent={count:1,previousComponent:n.lastComponent,added:!1,removed:!1});return g&&!o.oneChangePerToken&&(n.lastComponent={count:g,previousComponent:n.lastComponent,added:!1,removed:!1}),n.oldPos=c,u}equals(n,t,e){return e.comparator?e.comparator(n,t):n===t||!!e.ignoreCase&&n.toLowerCase()===t.toLowerCase()}removeEmpty(n){const t=[];for(let e=0;e<n.length;e++)n[e]&&t.push(n[e]);return t}castInput(n,t){return n}tokenize(n,t){return Array.from(n)}join(n){return n.join("")}postProcess(n,t){return n}get useLongestToken(){return!1}buildValues(n,t,e){const i=[];let o;for(;n;)i.push(n),o=n.previousComponent,delete n.previousComponent,n=o;i.reverse();const r=i.length;let f=0,c=0,u=0;for(;f<r;f++){const g=i[f];if(g.removed)g.value=this.join(e.slice(u,u+g.count)),u+=g.count;else{if(!g.added&&this.useLongestToken){let x=t.slice(c,c+g.count);x=x.map(function(S,a){const d=e[u+a];return d.length>S.length?d:S}),g.value=this.join(x)}else g.value=this.join(t.slice(c,c+g.count));c+=g.count,g.added||(u+=g.count)}}return i}}class Ot extends Qe{}const Ft=new Ot;function Ht(s,n,t){return Ft.diff(s,n,t)}const Ge="a-zA-Z0-9_\\u{AD}\\u{C0}-\\u{D6}\\u{D8}-\\u{F6}\\u{F8}-\\u{2C6}\\u{2C8}-\\u{2D7}\\u{2DE}-\\u{2FF}\\u{1E00}-\\u{1EFF}";class At extends Qe{tokenize(n){const t=new RegExp(`(\\r?\\n)|[${Ge}]+|[^\\S\\n\\r]+|[^${Ge}]`,"ug");return n.match(t)||[]}}const Bt=new At;function Rt(s,n,t){return Bt.diff(s,n,t)}function Wt(s,n){if(s.length===0)return n.length;if(n.length===0)return s.length;const t=[];let e;for(e=0;e<=n.length;e++)t[e]=[e];let i;for(i=0;i<=s.length;i++)t[0][i]=i;for(e=1;e<=n.length;e++)for(i=1;i<=s.length;i++)n.charAt(e-1)===s.charAt(i-1)?t[e][i]=t[e-1][i-1]:t[e][i]=Math.min(t[e-1][i-1]+1,Math.min(t[e][i-1]+1,t[e-1][i]+1));return t[n.length][s.length]}function Me(s){return(n,t)=>{const e=s(n).trim(),i=s(t).trim();return Wt(e,i)/(e.length+i.length)}}function Oe(s){function n(e,i,o=new Map){let r=1/0,f;for(let c=0;c<e.length;++c)for(let u=0;u<i.length;++u){const g=JSON.stringify([e[c],i[u]]);let x;o.has(g)&&(x=o.get(g))||(x=s(e[c],i[u]),o.set(g,x)),x<r&&(r=x,f={indexA:c,indexB:u,score:r})}return f}function t(e,i,o=0,r=new Map){const f=n(e,i,r);if(!f||e.length+i.length<3)return[[e,i]];const c=e.slice(0,f.indexA),u=i.slice(0,f.indexB),g=[e[f.indexA]],x=[i[f.indexB]],S=f.indexA+1,a=f.indexB+1,d=e.slice(S),m=i.slice(a),p=t(c,u,o+1,r),y=t(g,x,o+1,r),N=t(d,m,o+1,r);let T=y;return(f.indexA>0||f.indexB>0)&&(T=p.concat(T)),(e.length>S||i.length>a)&&(T=T.concat(N)),T}return t}const G={INSERTS:"d2h-ins",DELETES:"d2h-del",CONTEXT:"d2h-cntx",INFO:"d2h-info",INSERT_CHANGES:"d2h-ins d2h-change",DELETE_CHANGES:"d2h-del d2h-change"},Te={matching:Ct.NONE,matchWordsThreshold:.25,maxLineLengthHighlight:1e4,diffStyle:Et.WORD,colorScheme:he.LIGHT},te="/",Ze=Me(s=>s.value),jt=Oe(Ze);function De(s){return s.indexOf("dev/null")!==-1}function kt(s){return s.replace(/(<ins[^>]*>((.|\n)*?)<\/ins>)/g,"")}function zt(s){return s.replace(/(<del[^>]*>((.|\n)*?)<\/del>)/g,"")}function xe(s){switch(s){case A.CONTEXT:return G.CONTEXT;case A.INSERT:return G.INSERTS;case A.DELETE:return G.DELETES}}function Fe(s){switch(s){case he.DARK:return"d2h-dark-color-scheme";case he.AUTO:return"d2h-auto-color-scheme";case he.LIGHT:default:return"d2h-light-color-scheme"}}function Ut(s){return s?2:1}function pe(s){return s.slice(0).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#x27;").replace(/\//g,"&#x2F;")}function ne(s,n,t=!0){const e=Ut(n);return{prefix:s.substring(0,e),content:t?pe(s.substring(e)):s.substring(e)}}function Ne(s){const n=je(s.oldName),t=je(s.newName);if(n!==t&&!De(n)&&!De(t)){const e=[],i=[],o=n.split(te),r=t.split(te),f=o.length,c=r.length;let u=0,g=f-1,x=c-1;for(;u<g&&u<x&&o[u]===r[u];)e.push(r[u]),u+=1;for(;g>u&&x>u&&o[g]===r[x];)i.unshift(r[x]),g-=1,x-=1;const S=e.join(te),a=i.join(te),d=o.slice(u,g+1).join(te),m=r.slice(u,x+1).join(te);return S.length&&a.length?S+te+"{"+d+" → "+m+"}"+te+a:S.length?S+te+"{"+d+" → "+m+"}":a.length?"{"+d+" → "+m+"}"+te+a:n+" → "+t}else return De(t)?n:t}function He(s){return`d2h-${_t(Ne(s)).toString().slice(-6)}`}function Ae(s){let n="file-changed";return s.isRename||s.isCopy?n="file-renamed":s.isNew?n="file-added":s.isDeleted?n="file-deleted":s.newName!==s.oldName&&(n="file-renamed"),n}function et(s,n,t,e={}){const{matching:i,maxLineLengthHighlight:o,matchWordsThreshold:r,diffStyle:f}=Object.assign(Object.assign({},Te),e),c=ne(s,t,!1),u=ne(n,t,!1);if(c.content.length>o||u.content.length>o)return{oldLine:{prefix:c.prefix,content:pe(c.content)},newLine:{prefix:u.prefix,content:pe(u.content)}};const g=f==="char"?Ht(c.content,u.content):Rt(c.content,u.content),x=[];if(f==="word"&&i==="words"){const a=g.filter(p=>p.removed),d=g.filter(p=>p.added);jt(d,a).forEach(p=>{p[0].length===1&&p[1].length===1&&Ze(p[0][0],p[1][0])<r&&(x.push(p[0][0]),x.push(p[1][0]))})}const S=g.reduce((a,d)=>{const m=d.added?"ins":d.removed?"del":null,p=x.indexOf(d)>-1?' class="d2h-change"':"",y=pe(d.value);return m!==null?`${a}<${m}${p}>${y}</${m}>`:`${a}${y}`},"");return{oldLine:{prefix:c.prefix,content:kt(S)},newLine:{prefix:u.prefix,content:zt(S)}}}const Ve="file-summary",Gt="icon",Vt={colorScheme:Te.colorScheme};class $t{constructor(n,t={}){this.hoganUtils=n,this.config=Object.assign(Object.assign({},Vt),t)}render(n){const t=n.map(e=>this.hoganUtils.render(Ve,"line",{fileHtmlId:He(e),oldName:e.oldName,newName:e.newName,fileName:Ne(e),deletedLines:"-"+e.deletedLines,addedLines:"+"+e.addedLines},{fileIcon:this.hoganUtils.template(Gt,Ae(e))})).join(`
4
4
  `);return this.hoganUtils.render(Ve,"wrapper",{colorScheme:Fe(this.config.colorScheme),filesNumber:n.length,files:t})}}const tt=Object.assign(Object.assign({},Te),{renderNothingWhenEmpty:!1,matchingMaxComparisons:2500,maxLineSizeInBlockForComparison:200}),me="generic",$e="line-by-line",Xt="icon",qt="tag";class Kt{constructor(n,t={}){this.hoganUtils=n,this.config=Object.assign(Object.assign({},tt),t)}render(n){const t=n.map(e=>{let i;return e.blocks.length?i=this.generateFileHtml(e):i=this.generateEmptyDiff(),this.makeFileDiffHtml(e,i)}).join(`