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/backend/dist/server.js +270 -65
- package/bin/webmux.js +239 -48
- package/frontend/dist/assets/{DiffDialog-1-WiuIC4.js → DiffDialog-CjMdljRY.js} +1 -1
- package/frontend/dist/assets/index-FETEudgI.js +33 -0
- package/frontend/dist/index.html +1 -1
- package/package.json +1 -1
- package/frontend/dist/assets/index-D4JuH244.js +0 -33
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=
|
|
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 == "
|
|
16567
|
-
|
|
16568
|
-
|
|
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
|
-
|
|
16574
|
-
|
|
16575
|
-
|
|
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
|
-
|
|
16578
|
-
|
|
16579
|
-
if
|
|
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
|
-
|
|
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
|
|
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 =
|
|
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
|
|
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
|
|
17597
|
+
return resolve8(this.deps.projectRoot, this.deps.config.workspace.worktreeRoot, branch);
|
|
17407
17598
|
}
|
|
17408
17599
|
listLocalBranches() {
|
|
17409
|
-
return this.deps.git.listLocalBranches(
|
|
17600
|
+
return this.deps.git.listLocalBranches(resolve8(this.deps.projectRoot));
|
|
17410
17601
|
}
|
|
17411
17602
|
listRemoteBranches() {
|
|
17412
|
-
return this.deps.git.listRemoteBranches(
|
|
17603
|
+
return this.deps.git.listRemoteBranches(resolve8(this.deps.projectRoot));
|
|
17413
17604
|
}
|
|
17414
17605
|
listCheckedOutBranches() {
|
|
17415
|
-
return new Set(this.deps.git.listWorktrees(
|
|
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 =
|
|
17419
|
-
return this.deps.git.listWorktrees(projectRoot2).filter((entry) => !entry.bare &&
|
|
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
|
|
18282
|
+
import { basename as basename4, resolve as resolve9 } from "path";
|
|
18092
18283
|
function makeUnmanagedWorktreeId(path) {
|
|
18093
|
-
return `unmanaged:${
|
|
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 =
|
|
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 &&
|
|
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
|
|
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 =
|
|
18637
|
-
return runtime.git.listWorktrees(projectDir).filter((entry) => !entry.bare &&
|
|
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(
|
|
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 =
|
|
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(
|
|
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
|
|
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.
|
|
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 =
|
|
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(
|
|
19187
|
-
await loadEnvFile(
|
|
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(
|
|
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-
|
|
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,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'").replace(/\//g,"/")}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(`
|