@syrkos/filaxis 0.1.0-alpha.11 → 0.1.0-alpha.12
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.
Potentially problematic release.
This version of @syrkos/filaxis might be problematic. Click here for more details.
- package/bin/filaxis.ts +91 -6
- package/docs//346/265/213/350/257/2257.md +179 -0
- package/package.json +1 -1
package/bin/filaxis.ts
CHANGED
|
@@ -8,6 +8,11 @@
|
|
|
8
8
|
* edit 免 Shell 通道(第八季盲测实锤:Windows CommandLineToArgvW 剥引号、多行
|
|
9
9
|
* argv 要数缩进空格——Flash 卡 32 轮):--stdin-json / --request-file 走 JSON
|
|
10
10
|
* 载荷 {old,new,all},多行/引号/缩进 100% 保真,绕开宿主 Shell 转义。
|
|
11
|
+
*
|
|
12
|
+
* 路径描述对齐内核三件套(第九季盲测:CLI 只有 --host 族,跳板+容器场景 Agent
|
|
13
|
+
* 被迫读 19 轮源码写 6 个 TS 脚本):connParams(--jump/-J/--forward/--host-key/
|
|
14
|
+
* --known-hosts)+ sshHops 逐跳链(--hop 可重复)+ enterPipeline(--enter 可重复
|
|
15
|
+
* + --docker 糖)。每跳独立密钥等极端拓扑走 SDK descriptor 全量描述。
|
|
11
16
|
*/
|
|
12
17
|
import { RuntimeStack, LocalRuntimeDriver, SshPtyDriver, editFile, discoverLayer } from "../src/index.js";
|
|
13
18
|
import type { RuntimeDriver } from "../src/driver.js";
|
|
@@ -21,11 +26,14 @@ type MaybeAsync<T> = T | Promise<T>;
|
|
|
21
26
|
|
|
22
27
|
function parseOpts(argv: string[]): {
|
|
23
28
|
host?: string; user?: string; port?: number; key?: string;
|
|
29
|
+
jump?: string; hop: string[]; enter: string[];
|
|
30
|
+
docker?: string; dockerShell?: string; dockerRuntime?: string;
|
|
31
|
+
forward: string[]; hostKey?: string; knownHosts?: string;
|
|
24
32
|
timeout?: number; duration?: number; stream?: string; all?: boolean;
|
|
25
33
|
stdinJson?: boolean; requestFile?: string;
|
|
26
34
|
positional: string[];
|
|
27
35
|
} {
|
|
28
|
-
const o: ReturnType<typeof parseOpts> = { positional: [] };
|
|
36
|
+
const o: ReturnType<typeof parseOpts> = { positional: [], hop: [], enter: [], forward: [] };
|
|
29
37
|
for (let i = 0; i < argv.length; i++) {
|
|
30
38
|
const a = argv[i]!;
|
|
31
39
|
if (a === "--") continue; // 命令分隔符(可省)
|
|
@@ -34,6 +42,15 @@ function parseOpts(argv: string[]): {
|
|
|
34
42
|
case "--user": o.user = argv[++i]; break;
|
|
35
43
|
case "--port": o.port = parseInt(argv[++i]!, 10); break;
|
|
36
44
|
case "--key": o.key = argv[++i]; break;
|
|
45
|
+
case "-J": case "--jump": o.jump = argv[++i]; break;
|
|
46
|
+
case "--hop": o.hop.push(argv[++i]!); break;
|
|
47
|
+
case "--enter": o.enter.push(argv[++i]!); break;
|
|
48
|
+
case "--docker": o.docker = argv[++i]; break;
|
|
49
|
+
case "--docker-shell": o.dockerShell = argv[++i]; break;
|
|
50
|
+
case "--docker-runtime": o.dockerRuntime = argv[++i]; break;
|
|
51
|
+
case "--forward": o.forward.push(argv[++i]!); break;
|
|
52
|
+
case "--host-key": o.hostKey = argv[++i]; break;
|
|
53
|
+
case "--known-hosts": o.knownHosts = argv[++i]; break;
|
|
37
54
|
case "--timeout": o.timeout = parseInt(argv[++i]!, 10); break;
|
|
38
55
|
case "--duration": o.duration = parseInt(argv[++i]!, 10); break;
|
|
39
56
|
case "--stream": o.stream = argv[++i]; break;
|
|
@@ -46,12 +63,71 @@ function parseOpts(argv: string[]): {
|
|
|
46
63
|
return o;
|
|
47
64
|
}
|
|
48
65
|
|
|
66
|
+
/** 跳描述解析:user@host[:port](任一存在→结构化跳;纯 host→纯字符串跳,旧形态逐字节不变) */
|
|
67
|
+
function parseHopSpec(spec: string): { host: string; conn?: { user?: string; port?: number } } {
|
|
68
|
+
let rest = spec;
|
|
69
|
+
let user: string | undefined;
|
|
70
|
+
const at = rest.lastIndexOf("@");
|
|
71
|
+
if (at > 0) { user = rest.slice(0, at); rest = rest.slice(at + 1); }
|
|
72
|
+
let port: number | undefined;
|
|
73
|
+
const colon = rest.lastIndexOf(":");
|
|
74
|
+
if (colon > 0) {
|
|
75
|
+
const p = parseInt(rest.slice(colon + 1), 10);
|
|
76
|
+
if (Number.isFinite(p) && p > 0 && p < 65536) { port = p; rest = rest.slice(0, colon); }
|
|
77
|
+
}
|
|
78
|
+
return user != null || port != null ? { host: rest, conn: { user, port } } : { host: rest };
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/** 端口透传解析:L:8080:localhost:80 / R:... / D:1080(bind 走 SDK descriptor) */
|
|
82
|
+
function parseForwardSpec(spec: string): { kind: "L" | "R" | "D"; port: number; target?: string } {
|
|
83
|
+
const parts = spec.split(":");
|
|
84
|
+
const kind = (parts[0] ?? "").toUpperCase();
|
|
85
|
+
if (!["L", "R", "D"].includes(kind)) throw new Error(`--forward 格式非法: '${spec}'(应为 L:port:host:port / R:... / D:port)`);
|
|
86
|
+
const port = parseInt(parts[1] ?? "", 10);
|
|
87
|
+
if (!Number.isInteger(port) || port <= 0 || port > 65535) throw new Error(`--forward 端口非法: '${spec}'`);
|
|
88
|
+
const target = kind === "D" ? undefined : parts.slice(2).join(":");
|
|
89
|
+
if (kind !== "D" && !target) throw new Error(`--forward kind=${kind} 需 target(host:port): '${spec}'`);
|
|
90
|
+
return { kind: kind as "L" | "R" | "D", port, target };
|
|
91
|
+
}
|
|
92
|
+
|
|
49
93
|
async function driverFor(opts: ReturnType<typeof parseOpts>): Promise<RuntimeDriver> {
|
|
50
94
|
if (opts.host) {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
95
|
+
// ① connParams(root 连接参数——对齐内核 SshConnParams 全字段)
|
|
96
|
+
const connParams: Record<string, unknown> = {};
|
|
97
|
+
if (opts.user) connParams.user = opts.user;
|
|
98
|
+
if (opts.port != null) connParams.port = opts.port;
|
|
99
|
+
if (opts.key) connParams.keyFile = opts.key;
|
|
100
|
+
if (opts.jump) connParams.jump = opts.jump; // -J:途径机不占层,ssh 自身代理
|
|
101
|
+
if (opts.forward.length) connParams.forwards = opts.forward.map(parseForwardSpec);
|
|
102
|
+
if (opts.hostKey) {
|
|
103
|
+
if (opts.hostKey !== "tofu" && opts.hostKey !== "strict") {
|
|
104
|
+
throw new Error(`--host-key 取值非法: '${opts.hostKey}'(限 tofu | strict)`);
|
|
105
|
+
}
|
|
106
|
+
connParams.hostKeyPolicy = opts.hostKey;
|
|
107
|
+
}
|
|
108
|
+
if (opts.knownHosts) connParams.knownHostsFile = opts.knownHosts;
|
|
109
|
+
const config: Record<string, unknown> = {};
|
|
110
|
+
if (Object.keys(connParams).length) config.connParams = connParams;
|
|
111
|
+
// ② sshHops 逐跳链(每跳 user@host[:port],顺序=链序;密钥共享 --key——
|
|
112
|
+
// 每跳独立密钥等极端拓扑走 SDK descriptor)
|
|
113
|
+
if (opts.hop.length) config.sshHops = opts.hop.map(parseHopSpec);
|
|
114
|
+
// ③ enterPipeline 有序进入管线(--docker 糖在前 + --enter 按序追加;label
|
|
115
|
+
// 截取 cmd 前 30 字符=原版 push_enter 默认同款)
|
|
116
|
+
const enterSteps: Array<{ cmd: string; label: string }> = [];
|
|
117
|
+
if (opts.docker) {
|
|
118
|
+
const runtime = opts.dockerRuntime ?? "docker";
|
|
119
|
+
enterSteps.push({
|
|
120
|
+
cmd: `${runtime} exec -i ${opts.docker} ${opts.dockerShell ?? "sh"}`,
|
|
121
|
+
label: `${runtime}:${opts.docker}`,
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
for (const e of opts.enter) enterSteps.push({ cmd: e, label: e.slice(0, 30) });
|
|
125
|
+
if (enterSteps.length) config.enterPipeline = enterSteps;
|
|
126
|
+
return new SshPtyDriver({ driver: "ssh", target: opts.host, config });
|
|
127
|
+
}
|
|
128
|
+
// local 层无路径概念——路径参数在场而 --host 缺席 = 防呆报错(静默忽略=错机器风险)
|
|
129
|
+
if (opts.jump || opts.hop.length || opts.enter.length || opts.docker || opts.forward.length || opts.hostKey || opts.knownHosts) {
|
|
130
|
+
throw new Error("路径描述参数(--jump/--hop/--enter/--docker/--forward/--host-key/--known-hosts)需要 --host(local 层无路径概念)");
|
|
55
131
|
}
|
|
56
132
|
return new LocalRuntimeDriver();
|
|
57
133
|
}
|
|
@@ -154,7 +230,16 @@ async function main() {
|
|
|
154
230
|
<path> --stdin-json | --request-file <f> # 免 Shell 通道(JSON {old,new,all}——多行/引号保真)
|
|
155
231
|
filaxis observe [--host ...] [--stream stderr|stdout|both] [--duration MS] -- <command>
|
|
156
232
|
filaxis probe [--host ...] # 两段式环境探测
|
|
157
|
-
|
|
233
|
+
|
|
234
|
+
路径描述(需 --host;对齐内核三件套 connParams/sshHops/enterPipeline):
|
|
235
|
+
-J, --jump <j> 跳板(-J:途径机不占层,ssh 自身代理)
|
|
236
|
+
--hop <user@host[:port]> 逐跳登录链(可重复=链序;每跳独立端口/用户,密钥共享 --key)
|
|
237
|
+
--enter <cmd> 进入内层 shell(可重复=管线序,如 "docker exec -i web bash")
|
|
238
|
+
--docker <name> 糖 = --enter "docker exec -i <name> sh"(--docker-shell bash / --docker-runtime podman 可换)
|
|
239
|
+
--forward L:8080:host:80 端口透传(可重复;R:/D: 同构;bind 走 SDK descriptor)
|
|
240
|
+
--host-key tofu|strict 主机密钥策略(缺省 tofu=accept-new)
|
|
241
|
+
--known-hosts <file> 自定义 known_hosts
|
|
242
|
+
每跳独立密钥等极端拓扑请用 SDK descriptor 全量描述。缺省 --host 为 local。`);
|
|
158
243
|
process.exit(cmd ? 1 : 0);
|
|
159
244
|
}
|
|
160
245
|
} finally {
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
Ran download and extract @syrkos/filaxis@0.1.0-alpha.11 · Exited with code 1
|
|
2
|
+
Ran download and extract @syrkos/filaxis@0.1.0-alpha.11 via curl
|
|
3
|
+
Analyzed filaxis.ts:L1-168
|
|
4
|
+
Analyzed agent-toolkit.ts:L1-254
|
|
5
|
+
Analyzed index.ts:L1-38
|
|
6
|
+
Analyzed runtime-stack.ts:L1-128
|
|
7
|
+
Analyzed ssh-helpers.ts:L1-225
|
|
8
|
+
Analyzed ssh-pty-driver.ts:L1-655
|
|
9
|
+
Ran check local SSH config
|
|
10
|
+
Ran test SSH jump via vm-ai-server to vm-homelab and check docker
|
|
11
|
+
Ran list existing docker images on vm-homelab
|
|
12
|
+
Ran check available utilities in alpine:latest container on vm-homelab · Exited with code 1
|
|
13
|
+
Ran check utilities in alpine:latest container
|
|
14
|
+
Created test_alpha11_docker.ts
|
|
15
|
+
Canceled test SshPtyDriver with jump to vm-homelab
|
|
16
|
+
Killed task Test SshPtyDriver with jump to vm-homelab
|
|
17
|
+
Edited test_alpha11_docker.ts
|
|
18
|
+
Ran test SshPtyDriver with jump vm-ai-server to vm-homelab
|
|
19
|
+
Killing task Test SshPtyDriver with jump vm-ai-server to vm-homelab
|
|
20
|
+
Edited test_alpha11_docker.ts
|
|
21
|
+
Ran test SshPtyDriver jump + docker enterCmd on vm-homelab
|
|
22
|
+
|
|
23
|
+
已下载并解压 `@syrkos/filaxis@0.1.0-alpha.11`,正在通过 `vm-ai-server` 跳板机在 `vm-homelab` 的 Docker 容器层进行预检测试,稍候任务返回后继续部署新考题。
|
|
24
|
+
|
|
25
|
+
Analyzed remote-session-manager.ts:L1-286
|
|
26
|
+
Ran list files in filaxis 0.1.0-alpha.11 package
|
|
27
|
+
Edited test_alpha11_docker.ts
|
|
28
|
+
Ran test execSession and tailLines inside Alpine container via jump host
|
|
29
|
+
|
|
30
|
+
正在验证 `SshPtyDriver` 在 `vm-ai-server` 跳板机 + `vm-homelab` Docker 容器内的异步会话观察(`execSession` + `tailLines` + `stopSession`)表现,稍候完成后即刻构建第四轮对比考题。
|
|
31
|
+
|
|
32
|
+
Created setup_exam3_docker.ts
|
|
33
|
+
Ran setup exam3-edge-a and exam3-edge-b containers on vm-homelab via vm-ai-server
|
|
34
|
+
|
|
35
|
+
正在通过 `vm-ai-server` 跳板机在 `vm-homelab` 上初始化第四轮盲测的双容器沙箱(`exam3-edge-a` 与 `exam3-edge-b`,基于无 Python/jq 的纯净 `alpine:latest` 镜像),待环境就绪后立即并发启动两组 Gemini 3.8 Flash 子代理进行对决。
|
|
36
|
+
|
|
37
|
+
Used tool: invoke_subagent
|
|
38
|
+
Used tool: invoke_subagent
|
|
39
|
+
|
|
40
|
+
已部署第四轮(`0.1.0-alpha.11`)三层穿透容器盲测考题,并同时启动两组 **Gemini 3.8 Flash** 子代理并发执行:
|
|
41
|
+
|
|
42
|
+
1. **拓扑与环境**:`Windows 本地` $\rightarrow$ 跳板机 `vm-ai-server (10.0.20.2)` $\rightarrow$ 宿主机 `vm-homelab (10.0.20.1:3322)` $\rightarrow$ `alpine:latest` 纯净容器(**容器内无 `python3`、无 `jq`、无 `node`、无 `bash`**,仅 BusyBox `sh`)。
|
|
43
|
+
2. **三项复合故障**:
|
|
44
|
+
- **故障 1(残留进程锁 + `stderr` 诊断流)**:清理 `/usr/local/bin/edge-lock-holder` 进程与 `/var/run/edge-dispatcher.lock`,并捕获 `/usr/local/bin/edge-dispatcher --diagnose` 输出在 `stderr` 上的故障规范;
|
|
45
|
+
- **故障 2(无 Python/jq 容器内的多块同构 JSON 修改)**:修改 `/etc/edge-dispatcher/webhooks.json` 中 `id="billing-sync"` 路由块的 3 个字段,严禁误伤 `global`、`order-created`、`inventory-audit` 三个同构块;
|
|
46
|
+
- **故障 3(含 `$2a`、`!`、`#`、`&` 特殊字符的密钥配置)**:将 `/etc/edge-dispatcher/credentials.conf` 中的 `BILLING_HMAC_SECRET` 更新为 `"whsec_9f$2a!Kp#88_Live&Key"`(含触发 Shell 变量展开的 `$2a` 和触发 `sed` 替换展开的 `&`)。
|
|
47
|
+
3. **分组对决**:
|
|
48
|
+
- **A4 组(裸 SSH + Docker 组,`flash`)**:[`4ceee8c3-a385-49e4-8cf1-505e40db46cf`](conversation://4ceee8c3-a385-49e4-8cf1-505e40db46cf)(操作容器 `exam3-edge-a`)
|
|
49
|
+
- **B4 组(Filaxis `0.1.0-alpha.11` 组,`flash`)**:[`4e018b84-90c3-47d3-bcf8-28c8bea7f1d4`](conversation://4e018b84-90c3-47d3-bcf8-28c8bea7f1d4)(操作容器 `exam3-edge-b`)
|
|
50
|
+
|
|
51
|
+
正在等待两个子代理完成任务回报,随后为您解析完整的 `transcript_full.jsonl` Token 账单与轨迹对比。
|
|
52
|
+
|
|
53
|
+
Found 8 subagents
|
|
54
|
+
|
|
55
|
+
A4 组(裸 SSH + Docker 组,`4ceee8c3-a385-49e4-8cf1-505e40db46cf`)已完成汇报;B4 组(Filaxis `0.1.0-alpha.11` 组,`4e018b84-90c3-47d3-bcf8-28c8bea7f1d4`)正在执行最后的 `--self-test` 校验,稍候其返回后立即为您输出第四轮完整 Token 与执行轨迹对比分析。
|
|
56
|
+
|
|
57
|
+
Created analyze_r4_docker.ts
|
|
58
|
+
Ran analyze Round 4 subagent transcripts and token usage
|
|
59
|
+
Analyzed analyze_r3_flash.ts:L1-65
|
|
60
|
+
Edited analyze_r4_docker.ts
|
|
61
|
+
Ran run full Round 4 transcript and token analysis
|
|
62
|
+
Analyzed output.txt:L35-227
|
|
63
|
+
Analyzed test_connect.ts:L1-27
|
|
64
|
+
Analyzed remediate.ts:L1-70
|
|
65
|
+
Ran clean up exam3-edge-a and exam3-edge-b containers on vm-homelab
|
|
66
|
+
|
|
67
|
+
第四轮(`0.1.0-alpha.11`)**三层穿透(Windows $\rightarrow$ `vm-ai-server` 跳板机 $\rightarrow$ `vm-homelab` 宿主机 $\rightarrow$ `alpine:latest` 纯净容器)** 的 Gemini 3.8 Flash 同模型盲测已全部跑完,宿主机上的两个测试容器 `exam3-edge-a` / `exam3-edge-b` 也已清理完毕。
|
|
68
|
+
|
|
69
|
+
这轮实验出现了一个**非常关键的转折**:
|
|
70
|
+
- 上一轮(`alpha.10`)卡死 Filaxis 组 32 轮(303 秒)的**多行 JSON 与特殊字符编辑,在这一轮实现了 `0` 报错、`1` 次命中过关**!
|
|
71
|
+
- 与此同时,由于容器换成了**无 `python3`、无 `jq`、无 `node` 的 `alpine:latest`**,裸 SSH 组再也无法用 Python 逃课,被迫在本地手搓 Base64 整文件覆盖;而 Filaxis 组则暴露出了 **CLI 入口(`bin/filaxis.ts`)尚未透传 `--jump` 与 `--enter` 参数** 的新摩擦点。
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
### 一、 第四轮核心指标总表(Gemini 3.8 Flash 盲测)
|
|
76
|
+
|
|
77
|
+
> 原始轨迹日志:
|
|
78
|
+
> - **A4 组(裸 SSH + Docker)**:[`4ceee8c3-a385-49e4-8cf1-505e40db46cf`](conversation://4ceee8c3-a385-49e4-8cf1-505e40db46cf)
|
|
79
|
+
> - **B4 组(Filaxis `0.1.0-alpha.11` + Docker)**:[`4e018b84-90c3-47d3-bcf8-28c8bea7f1d4`](conversation://4e018b84-90c3-47d3-bcf8-28c8bea7f1d4)
|
|
80
|
+
> - 完整逐轮对账输出:[output.txt](file:///C:/Users/dream/.gemini/antigravity/brain/f7c26020-3bdd-4477-b804-f050d731bc85/.system_generated/steps/9174/output.txt)
|
|
81
|
+
|
|
82
|
+
| 评测维度 | 对照 A4 组(Flash + 裸 SSH + Docker) | 实验 B4 组(Flash + Filaxis `alpha.11` + Docker) | 跨版本演进(对比第三轮 `alpha.10` B3 组) |
|
|
83
|
+
| :--- | :--- | :--- | :--- |
|
|
84
|
+
| **推理轮次 (Planner Turns)** | **23 轮** | **43 轮** | 从 53 轮降至 **43 轮**(**-10 轮**) |
|
|
85
|
+
| **工具调用次数 (Tool Calls)** | **22 次** | **42 次** | 从 52 次降至 **42 次**(**-10 次**) |
|
|
86
|
+
| **总耗时 (Wall-Clock Time)** | **234.0 秒** | **347.0 秒** | 从 540.0 秒降至 **347.0 秒**(**快了 193 秒 / -35.7%**) |
|
|
87
|
+
| **编辑重试 / 引号翻车轮次** | 0 次(退化为手搓 Base64 全量覆盖) | **0 次(`editFile` 两次调用均 100% 一次命中)** | 从 **32 轮卡死(303 秒)** 降至 **0 轮(0 秒)** |
|
|
88
|
+
| **杀进程 / Shell 踩坑次数** | **2 次**(`pkill -f` 自杀 + PowerShell 吞 `$?`) | **0 次**(`stdin` 管道注入,零 Shell 展开污染) | 保持 **0 事故** |
|
|
89
|
+
| **计费新增输入 (New Input)** | `85,885` | `160,682` | 稳定(`162.5K` $\rightarrow$ `160.7K`) |
|
|
90
|
+
| **缓存读取输入 (Cache Read)** | `506,795` | `1,825,715` | 因前 19 轮读源码垫高了前期上下文基数 |
|
|
91
|
+
| **总输入上下文 (Total Input)** | **`592,680` (592.7K)** | **`1,986,397` (1,986.4K)** | 源码阅读(19 轮)+ 写脚本执行(22 轮)占大头 |
|
|
92
|
+
| **总输出 Token (Output)** | **`13,779`** | **`22,873`** | 含编写 6 个 `.ts` 脚本的代码输出 |
|
|
93
|
+
| **最终 `--self-test` 结果** | `ALL_CHECKS_PASSED (exit=0)` | `ALL_CHECKS_PASSED (exit=0)` | 均一次通过验收 |
|
|
94
|
+
|
|
95
|
+
---
|
|
96
|
+
|
|
97
|
+
### 二、 两组精彩现场复盘:当 Alpine 容器里没有 Python 时发生了什么?
|
|
98
|
+
|
|
99
|
+
#### 1. 裸 SSH 组(A4):没了 Python,只能退化为「无锁整文件 Base64 覆盖」+ 两处多层 Shell 翻车
|
|
100
|
+
在第三轮中,裸 SSH 组靠远端宿主机的 `python3` 5 秒改完了 JSON。但这轮进入纯净 `alpine:latest` 容器(无 `python3`、无 `jq`、无 `node`)后,裸 SSH 组的轨迹暴露了三层 Shell 嵌套(`PowerShell` $\rightarrow$ `ssh -J` $\rightarrow$ `docker exec sh -c`)的真实痛点:
|
|
101
|
+
- **踩坑 ①(Turn 9,`pkill -f` 自杀导致命令异常退出)**:
|
|
102
|
+
A4 执行 `ssh -J vm-ai-server vm-homelab "docker exec exam3-edge-a sh -c 'pkill -9 -f edge-lock-holder; rm -f /var/run/edge-dispatcher.lock; ps aux'"`。
|
|
103
|
+
因为外层 `sh -c '...'` 的命令行参数本身就包含字符串 `edge-lock-holder`,BusyBox 的 `pkill -9 -f edge-lock-holder` **当场把正在执行命令的 `sh -c` 自己给 `SIGKILL` 了**(返回 `exit code 1`,后面的 `rm -f` 和 `ps aux` 根本没执行)!A4 被迫花了 4 轮(Turn 9~12)改用手动查 PID `kill -9 106` 才杀掉。
|
|
104
|
+
- **踩坑 ②(Turn 12,宿主 PowerShell 吞掉远端 `\$?`)**:
|
|
105
|
+
A4 执行 `ssh ... "docker exec exam3-edge-a sh -c 'ps aux ...; echo EXIT: \$?'"`,结果宿主机的 PowerShell 抢先将双引号里的 `$?` 展开成了 PowerShell 布尔值 `True`,打印出 `EXIT: True`!
|
|
106
|
+
- **手搓无锁 Base64(Turn 14~19,耗时 61 秒)**:
|
|
107
|
+
面对含 `$2a!Kp#88_Live&Key` 的配置文件和同构 JSON,A4 发现容器里没有 Python,但有 `/bin/base64`(Turn 14),于是**在本地 PowerShell 里把整个文件全文硬编码敲了一遍**(Turn 15、16),算出 Base64 字符串后通过 `echo '<b64>' | docker exec -i exam3-edge-a sh -c 'base64 -d > ...'` 全量覆盖写回(Turn 17、19)。
|
|
108
|
+
- *隐患*:这种做法等于 Agent 在本地脑内重写整份文件再无锁覆盖(无 TOCTOU 校验,且一旦文件有几百行,Output Token 会成倍爆炸)。
|
|
109
|
+
|
|
110
|
+
#### 2. Filaxis `0.1.0-alpha.11` 组(B4):多层穿透与文件受控编辑“丝滑一次过”,但被 CLI 缺参数逼回写 TS 脚本
|
|
111
|
+
B4 组在 [`remediate.ts`](file:///C:/Users/dream/.gemini/antigravity/brain/4e018b84-90c3-47d3-bcf8-28c8bea7f1d4/scratch/remediate.ts#L4-L55) 中展现了 `SshPtyDriver` + `editFile` 在三层容器穿透下的威力:
|
|
112
|
+
```ts
|
|
113
|
+
const drv = new SshPtyDriver({
|
|
114
|
+
driver: "ssh",
|
|
115
|
+
target: "vm-homelab",
|
|
116
|
+
config: {
|
|
117
|
+
connParams: { jump: "vm-ai-server" },
|
|
118
|
+
enterCmd: "docker exec -i exam3-edge-b sh",
|
|
119
|
+
},
|
|
120
|
+
});
|
|
121
|
+
```
|
|
122
|
+
- **零嵌套转义**:通过 `renderExecChannel` 的 `docker exec -i exam3-edge-b sh -s` 标准输入管道注入,无论命令里有什么引号或 `$` 符号,宿主 PowerShell 与中间跳板机完全不解析。
|
|
123
|
+
- **`editFile` 100% 一次命中**:
|
|
124
|
+
- 修改 `credentials.conf` 中的 `BILLING_HMAC_SECRET="whsec_9f$2a!Kp#88_Live&Key"`(含 `$2a`、`!`、`#`、`&`):**1 次成功**(160B $\rightarrow$ 166B)。
|
|
125
|
+
- 修改 `webhooks.json` 中的 `billing-sync` 多行对象块:**1 次成功**(636B $\rightarrow$ 635B),其余三个同构块毫发无损。
|
|
126
|
+
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
### 三、 为什么 B4 组还是花了 43 轮(347 秒)?—— 罪魁祸首只有 6 行代码
|
|
130
|
+
|
|
131
|
+
既然 `editFile` 0 翻车一次过,为什么 B4 组还是跑了 43 轮?
|
|
132
|
+
拆解 [output.txt](file:///C:/Users/dream/.gemini/antigravity/brain/f7c26020-3bdd-4477-b804-f050d731bc85/.system_generated/steps/9174/output.txt) 的时间轴,原因一目了然:
|
|
133
|
+
|
|
134
|
+
| 阶段 | 轮次范围 | 消耗轮次 | 耗时 | 发生了什么? |
|
|
135
|
+
| :--- | :--- | :--- | :--- | :--- |
|
|
136
|
+
| **阶段 1:读源码找跳板与容器接口** | Turn 1 ~ 19 | **19 轮** | `93 秒` | Flash 在 Turn 5 读完 [`bin/filaxis.ts`](file:///C:/Users/dream/.gemini/antigravity/brain/f7c26020-3bdd-4477-b804-f050d731bc85/scratch/filaxis_alpha/package/bin/filaxis.ts#L22-L57) 发现:**CLI 只有 `--host --user --port --key`,没有 `--jump` 和 `--enter`!** 也就是说,`alpha.11` 在 `bin/filaxis.ts` 里刚加好的 `--stdin-json` / `--request-file`,在面对跳板机+容器时**根本用不上**!Flash 被迫连读 14 轮 `ssh-helpers.ts` 和 `ssh-pty-driver.ts` 源码去查 SDK 怎么配 `jump` 和 `enterCmd`。 |
|
|
137
|
+
| **阶段 2:写 6 个 `.ts` 脚本并执行** | Turn 20 ~ 41 | **14 轮** | `199 秒` | 因为不能用 CLI 一行流,Flash 每做一步操作都要先 `write_file(xxx.ts)` 再 `run_command(bun run xxx.ts)`(共写了 `test_connect.ts`、`step1_diagnose.ts`、`inspect_files.ts`、`run_self_test.ts`、`remediate.ts`、`final_check.ts` 6 个脚本)。 |
|
|
138
|
+
| **阶段 3:单脚本串行多次 SSH 触发后台轮询** | Turn 27~28, 34~38, 41 | **8 轮** | `40 秒` | 因为在单个 `.ts` 脚本里串行调了 4~6 次 `drv.exec` / `editFile`(每次跨跳板机+容器约 2.2s),单脚本总耗时约 12~15s,刚好超过 `run_command` 的 10s 同步等待阈值,触发了 8 次 `manage_task(status)` 轮询。 |
|
|
139
|
+
|
|
140
|
+
---
|
|
141
|
+
|
|
142
|
+
### 四、 给 `0.1.0-alpha.12` 的「最后一公里」建议:打通 CLI 的多层穿透参数
|
|
143
|
+
|
|
144
|
+
目前 Filaxis 的**内核层(`SshPtyDriver` + `renderExecChannel` + `editFile`)已经完全支持跳板机(`jump`)和容器/内层 Shell 穿透(`enterPipeline` / `enterCmd`)**,而 `alpha.11` 新增的 `--request-file` / `--stdin-json` 也已经在 [`bin/filaxis.ts`](file:///C:/Users/dream/.gemini/antigravity/brain/f7c26020-3bdd-4477-b804-f050d731bc85/scratch/filaxis_alpha/package/bin/filaxis.ts#L98-L120) 就位了。
|
|
145
|
+
|
|
146
|
+
唯一断掉的一环,就是 [`bin/filaxis.ts` (第 22-57 行)](file:///C:/Users/dream/.gemini/antigravity/brain/f7c26020-3bdd-4477-b804-f050d731bc85/scratch/filaxis_alpha/package/bin/filaxis.ts#L22-L57) 还没把 `jump` 和 `enter` 暴露成命令行参数!只需要在 `bin/filaxis.ts` 里加上 **6 行代码**:
|
|
147
|
+
|
|
148
|
+
```ts
|
|
149
|
+
// package/bin/filaxis.ts
|
|
150
|
+
function parseOpts(argv: string[]): {
|
|
151
|
+
host?: string; user?: string; port?: number; key?: string;
|
|
152
|
+
jump?: string; enter?: string[];
|
|
153
|
+
...
|
|
154
|
+
} {
|
|
155
|
+
const o: ReturnType<typeof parseOpts> = { positional: [], enter: [] };
|
|
156
|
+
for (let i = 0; i < argv.length; i++) {
|
|
157
|
+
...
|
|
158
|
+
case "--jump": case "-J": o.jump = argv[++i]; break;
|
|
159
|
+
case "--enter": o.enter!.push(argv[++i]!); break;
|
|
160
|
+
case "--docker": o.enter!.push(`docker exec -i ${argv[++i]!} sh`); break;
|
|
161
|
+
```
|
|
162
|
+
并在 `driverFor(opts)` 中透传:
|
|
163
|
+
```ts
|
|
164
|
+
if (opts.host) {
|
|
165
|
+
return new SshPtyDriver({
|
|
166
|
+
driver: "ssh", target: opts.host,
|
|
167
|
+
config: {
|
|
168
|
+
connParams: { user: opts.user, port: opts.port, keyFile: opts.key, jump: opts.jump },
|
|
169
|
+
enterPipeline: opts.enter?.length ? opts.enter.map((cmd) => ({ cmd })) : undefined,
|
|
170
|
+
},
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
一旦补上这几个参数:
|
|
176
|
+
1. Agent 看到 `filaxis --help` 就能直接写:
|
|
177
|
+
`filaxis edit --host vm-homelab -J vm-ai-server --docker exam3-edge-b /etc/edge-dispatcher/webhooks.json --request-file req.json`
|
|
178
|
+
2. **前 19 轮读源码(93 秒)直接归零**;
|
|
179
|
+
3. **6 次 `write_file(*.ts)` + 8 次后台任务轮询(14 轮)直接归零**,因为单次 CLI 调用都是 2~4 秒内同步返回的原子操作!
|