- M0: libghostty SSH 终端(渲染/输入/连接)+ 白屏修复(OutputGate) + 会话状态机/自动重连 - M1: tsnet 用户态组网 + SSH-over-tsnet(fd 桥),shell 级真机验证;R5(Go+gvisor+C+++Swift 同进程) retire - M1.5: tmux -CC 原生 tab(MVP) - 结构: packages/(TXCore·TXTransport), apps/TerminalX, vendor/(libghostty-spm/libssh2/mbedtls/tsnet-bridge), artifacts/ - 文档: CLAUDE.md + docs/HANDOFF.md(新会话入口) - 环境: 认证代理→依赖 vendor 本地化;Go 在 ~/.local/go;仅模拟器/未签名 - 待续: M2 mosh, tmux 多 pane, M4 安全(host key/SE) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
198 lines
7.6 KiB
Bash
Executable File
198 lines
7.6 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
set -euo pipefail
|
|
|
|
SOURCE_DIR="${1:?Usage: $0 <ghostty-source-dir>}"
|
|
|
|
MARKER="LIBGHOSTTY_SPM_TRIM_PATCH"
|
|
|
|
# Skip if already applied
|
|
if grep -q "$MARKER" "$SOURCE_DIR/src/build/Config.zig" 2>/dev/null; then
|
|
echo "[+] trim patch already applied"
|
|
exit 0
|
|
fi
|
|
|
|
python3 - "$SOURCE_DIR" "$MARKER" <<'PYEOF'
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
source_dir = Path(sys.argv[1])
|
|
marker = sys.argv[2]
|
|
|
|
# ──────────────────────────────────────────────────────────────────────
|
|
# 1. Config.zig — add custom_shaders feature flag
|
|
# ──────────────────────────────────────────────────────────────────────
|
|
config_path = source_dir / "src/build/Config.zig"
|
|
text = config_path.read_text()
|
|
|
|
# Add field
|
|
text = text.replace(
|
|
"sentry: bool = true,",
|
|
f"sentry: bool = true,\ncustom_shaders: bool = true, // {marker}",
|
|
)
|
|
|
|
# Add option parsing after sentry block
|
|
sentry_end = """ ) orelse sentry: {
|
|
switch (target.result.os.tag) {
|
|
.macos, .ios => break :sentry true,
|
|
|
|
// Note its false for linux because the crash reports on Linux
|
|
// don't have much useful information.
|
|
else => break :sentry false,
|
|
}
|
|
};"""
|
|
|
|
new_options = sentry_end + """
|
|
|
|
config.custom_shaders = b.option(
|
|
bool,
|
|
"custom-shaders",
|
|
"Build with custom shader (glslang/spirv-cross) support.",
|
|
) orelse true;"""
|
|
|
|
text = text.replace(sentry_end, new_options)
|
|
|
|
# Add to addOptions
|
|
text = text.replace(
|
|
'step.addOption(bool, "sentry", self.sentry);',
|
|
'step.addOption(bool, "sentry", self.sentry);\n'
|
|
' step.addOption(bool, "custom_shaders", self.custom_shaders);',
|
|
)
|
|
|
|
config_path.write_text(text)
|
|
print("[+] patched Config.zig")
|
|
|
|
# ──────────────────────────────────────────────────────────────────────
|
|
# 2. SharedDeps.zig — gate glslang + spirv-cross on custom_shaders
|
|
# ──────────────────────────────────────────────────────────────────────
|
|
shared_path = source_dir / "src/build/SharedDeps.zig"
|
|
text = shared_path.read_text()
|
|
|
|
# Gate glslang — wrap with custom_shaders check
|
|
text = text.replace(
|
|
' // Glslang\n if (b.lazyDependency("glslang", .{',
|
|
' // Glslang — only needed for custom shaders\n if (self.config.custom_shaders) if (b.lazyDependency("glslang", .{',
|
|
)
|
|
# Close the extra if at end of glslang block
|
|
text = text.replace(
|
|
""" step.linkLibrary(glslang_dep.artifact("glslang"));
|
|
try static_libs.append(
|
|
b.allocator,
|
|
glslang_dep.artifact("glslang").getEmittedBin(),
|
|
);
|
|
}
|
|
}
|
|
|
|
// Spirv-cross""",
|
|
""" step.linkLibrary(glslang_dep.artifact("glslang"));
|
|
try static_libs.append(
|
|
b.allocator,
|
|
glslang_dep.artifact("glslang").getEmittedBin(),
|
|
);
|
|
}
|
|
};
|
|
|
|
// Spirv-cross""",
|
|
)
|
|
|
|
# Gate spirv-cross — wrap with custom_shaders check
|
|
text = text.replace(
|
|
' // Spirv-cross\n if (b.lazyDependency("spirv_cross", .{',
|
|
' // Spirv-cross — only needed for custom shaders\n if (self.config.custom_shaders) if (b.lazyDependency("spirv_cross", .{',
|
|
)
|
|
text = text.replace(
|
|
""" step.linkLibrary(spirv_cross_dep.artifact("spirv_cross"));
|
|
try static_libs.append(
|
|
b.allocator,
|
|
spirv_cross_dep.artifact("spirv_cross").getEmittedBin(),
|
|
);
|
|
}
|
|
}
|
|
|
|
// Sentry""",
|
|
""" step.linkLibrary(spirv_cross_dep.artifact("spirv_cross"));
|
|
try static_libs.append(
|
|
b.allocator,
|
|
spirv_cross_dep.artifact("spirv_cross").getEmittedBin(),
|
|
);
|
|
}
|
|
};
|
|
|
|
// Sentry""",
|
|
)
|
|
|
|
shared_path.write_text(text)
|
|
print("[+] patched SharedDeps.zig")
|
|
|
|
# ──────────────────────────────────────────────────────────────────────
|
|
# 3. build_config.zig — re-export custom_shaders flag
|
|
# ──────────────────────────────────────────────────────────────────────
|
|
bc_path = source_dir / "src/build_config.zig"
|
|
text = bc_path.read_text()
|
|
|
|
if "custom_shaders" not in text:
|
|
text = text.replace(
|
|
'const options = @import("build_options");',
|
|
'const options = @import("build_options");\npub const custom_shaders = options.custom_shaders;',
|
|
)
|
|
bc_path.write_text(text)
|
|
print("[+] patched build_config.zig")
|
|
|
|
# ──────────────────────────────────────────────────────────────────────
|
|
# 4. global.zig — conditional glslang init
|
|
# (global.zig already imports build_config)
|
|
# ──────────────────────────────────────────────────────────────────────
|
|
global_path = source_dir / "src/global.zig"
|
|
text = global_path.read_text()
|
|
|
|
text = text.replace(
|
|
'const glslang = @import("glslang");',
|
|
'const glslang = if (build_config.custom_shaders) @import("glslang") else struct {\n'
|
|
' pub fn init() !void {}\n'
|
|
'};',
|
|
)
|
|
|
|
global_path.write_text(text)
|
|
print("[+] patched global.zig")
|
|
|
|
# ──────────────────────────────────────────────────────────────────────
|
|
# 5. renderer/shadertoy.zig — gate shader imports and loadFromFile
|
|
# When custom_shaders is disabled, loadFromFile is unreachable
|
|
# so glslang/spirv_cross are never semantically analyzed
|
|
# ──────────────────────────────────────────────────────────────────────
|
|
shader_path = source_dir / "src/renderer/shadertoy.zig"
|
|
text = shader_path.read_text()
|
|
|
|
# Make imports conditional — these won't be analyzed if never reached
|
|
text = text.replace(
|
|
'const glslang = @import("glslang");',
|
|
'const build_config = @import("../build_config.zig");\n'
|
|
'const glslang = @import("glslang");',
|
|
)
|
|
|
|
# Add early return in loadFromFiles when custom_shaders is disabled
|
|
# This prevents loadFromFile (and thus spirvFromGlsl etc) from being analyzed
|
|
text = text.replace(
|
|
"""pub fn loadFromFiles(
|
|
alloc_gpa: Allocator,
|
|
paths: configpkg.RepeatablePath,
|
|
target: Target,
|
|
) ![]const [:0]const u8 {
|
|
var list: std.ArrayList([:0]const u8) = .empty;""",
|
|
"""pub fn loadFromFiles(
|
|
alloc_gpa: Allocator,
|
|
paths: configpkg.RepeatablePath,
|
|
target: Target,
|
|
) ![]const [:0]const u8 {
|
|
if (comptime !build_config.custom_shaders) return &.{};
|
|
var list: std.ArrayList([:0]const u8) = .empty;""",
|
|
)
|
|
|
|
shader_path.write_text(text)
|
|
print("[+] patched renderer/shadertoy.zig")
|
|
|
|
print(f"[+] all trim patches complete ({marker})")
|
|
PYEOF
|
|
|
|
echo "[+] trim patch applied"
|