@syrkos/filaxis 0.1.0-alpha.10

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.
Files changed (85) hide show
  1. package/AGENTS.md +46 -0
  2. package/LICENSE +202 -0
  3. package/NOTICE +10 -0
  4. package/README.md +61 -0
  5. package/bin/filaxis.ts +112 -0
  6. package/dist/agent-toolkit.d.ts +99 -0
  7. package/dist/dialect.d.ts +31 -0
  8. package/dist/driver.d.ts +130 -0
  9. package/dist/events.d.ts +26 -0
  10. package/dist/factory.d.ts +16 -0
  11. package/dist/file-edit.d.ts +43 -0
  12. package/dist/file-transfer.d.ts +44 -0
  13. package/dist/index.d.ts +38 -0
  14. package/dist/index.js +4200 -0
  15. package/dist/layer-discovery.d.ts +30 -0
  16. package/dist/layer-env.d.ts +95 -0
  17. package/dist/local-driver.d.ts +47 -0
  18. package/dist/local-session-manager.d.ts +98 -0
  19. package/dist/logger.d.ts +12 -0
  20. package/dist/remote-session-manager.d.ts +64 -0
  21. package/dist/runtime-stack.d.ts +52 -0
  22. package/dist/session-buffer.d.ts +73 -0
  23. package/dist/session-types.d.ts +74 -0
  24. package/dist/shell-discovery.d.ts +4 -0
  25. package/dist/ssh-helpers.d.ts +88 -0
  26. package/dist/ssh-pty-driver.d.ts +74 -0
  27. package/dist/stream-session-manager.d.ts +83 -0
  28. package/dist/stream-window.d.ts +124 -0
  29. package/dist/terminal/command-executer.d.ts +73 -0
  30. package/dist/terminal/output-buffer.d.ts +49 -0
  31. package/dist/terminal/session-launcher.d.ts +28 -0
  32. package/dist/terminal/session-registry.d.ts +29 -0
  33. package/dist/terminal/tmux-invoker.d.ts +8 -0
  34. package/dist/terminal/types.d.ts +56 -0
  35. package/dist/terminal-manager.d.ts +30 -0
  36. package/dist/tmux-driver.d.ts +49 -0
  37. package/dist/vt100-screen.d.ts +46 -0
  38. package/docs/DEVELOPMENT.md +38 -0
  39. package/docs/KNOWN-ISSUES.md +35 -0
  40. package/docs/implementation-notes.md +57 -0
  41. package/docs/skills/cross-host-diagnosis.md +21 -0
  42. package/docs/skills/file-sync.md +22 -0
  43. package/docs/skills/longrun-observe.md +20 -0
  44. package/docs/skills/stream-window.md +28 -0
  45. package/docs//345/256/214/346/225/264/345/267/241/346/243/200/346/212/245/345/221/212.md +141 -0
  46. package/docs//346/265/213/350/257/2252.md +112 -0
  47. package/docs//346/265/213/350/257/2253.md +73 -0
  48. package/docs//346/265/213/350/257/2254.md +138 -0
  49. package/docs//346/265/213/350/257/2255.md +124 -0
  50. package/docs//347/254/254/344/272/214/344/273/275/345/267/241/346/243/200/346/212/245/345/221/212.md +103 -0
  51. package/examples/agent-tools.ts +74 -0
  52. package/examples/cross-host-diagnosis.ts +49 -0
  53. package/examples/longrun-observe.ts +46 -0
  54. package/package.json +47 -0
  55. package/src/agent-toolkit.ts +247 -0
  56. package/src/dialect.ts +100 -0
  57. package/src/driver.ts +142 -0
  58. package/src/events.ts +96 -0
  59. package/src/factory.ts +51 -0
  60. package/src/file-edit.ts +195 -0
  61. package/src/file-transfer.ts +196 -0
  62. package/src/index.ts +38 -0
  63. package/src/layer-discovery.ts +79 -0
  64. package/src/layer-env.ts +331 -0
  65. package/src/local-driver.ts +325 -0
  66. package/src/local-session-manager.ts +397 -0
  67. package/src/logger.ts +19 -0
  68. package/src/remote-session-manager.ts +286 -0
  69. package/src/runtime-stack.ts +128 -0
  70. package/src/session-buffer.ts +183 -0
  71. package/src/session-types.ts +78 -0
  72. package/src/shell-discovery.ts +52 -0
  73. package/src/ssh-helpers.ts +225 -0
  74. package/src/ssh-pty-driver.ts +655 -0
  75. package/src/stream-session-manager.ts +296 -0
  76. package/src/stream-window.ts +309 -0
  77. package/src/terminal/command-executer.ts +374 -0
  78. package/src/terminal/output-buffer.ts +126 -0
  79. package/src/terminal/session-launcher.ts +146 -0
  80. package/src/terminal/session-registry.ts +98 -0
  81. package/src/terminal/tmux-invoker.ts +65 -0
  82. package/src/terminal/types.ts +85 -0
  83. package/src/terminal-manager.ts +83 -0
  84. package/src/tmux-driver.ts +167 -0
  85. package/src/vt100-screen.ts +166 -0
package/AGENTS.md ADDED
@@ -0,0 +1,46 @@
1
+ # Filaxis 包说明书(给使用方 Agent 读)
2
+
3
+ > 本文件只描述 `@syrkos/filaxis` 包本身,**不接管宿主仓库规范**——你的项目自有其 AGENTS.md。API 签名与详细参考见版本化文档(本文件不复制签名副本,防漂移)。
4
+
5
+ ## 心智模型(补充:流式观察窗)
6
+
7
+ - **观察窗(Stream Window)**:远端拉模式流反转为**本地推模式滚动窗**——帧号 per-window 单调递增(断连续编不归零)、peek 三模式全非破坏、多消费者游标互不干扰、stale 窗帧保留重连续编、关窗收割流进程。窗是滚动缓冲不是无限历史(完整历史查落盘日志)。
8
+
9
+ ## 心智模型
10
+
11
+ - **层(Layer)**:一个可执行环境(本机 / SSH 主机 / 容器 / 持久终端)。`stack.connect(descriptor)` 建立或复用。
12
+ - **会话(Session)**:长跑任务。`spawn` 即返,输出双文件落盘 + 热窗口。
13
+ - **观察流(Stream)**:独立 SSH channel 的真流式 tail——观察是廉价的,连接是稀缺的(自动复用主连接)。
14
+ - **两个身份键,两个职责**:连接拓扑指纹管「复用哪条连接」;环境身份键管「这台环境是什么」(同落点经不同跳板路径=同一环境)。
15
+
16
+ ## 核心不变量(执行语义的宪法)
17
+
18
+ > **没有经过验证的远端终态,就绝不能推导出执行成功;执行结果未知,也绝不能自动重放非幂等操作。**
19
+
20
+ 三条落地形态:
21
+
22
+ 1. **完成哨兵是唯一凭证**:exec 的退出码只认 `__FILAXIS_META_<nonce>` 尾缀(nonce 完整匹配 + 退出码可解析 + 取尾部出现)。无哨兵(断链/远端 kill -9/abort/信号杀)一律 `reject` 附半截现场,Error 挂 `outcome: "unknown"`——绝不 resolve 伪造退出码。
23
+ 2. **Abort ≠ 远端已取消**:abort/超时杀的是本地 ssh 进程,远端进程树状态未核实——`AbortError` 同时挂 `outcome: "unknown"`,上层须按未知处理(核实或上报),严禁直接推导远端已停。
24
+ 3. **内核零自动重放**:任何失败/未知路径都不自动重试非幂等命令——重放决策属上层(拿到 `outcome=unknown` 后先核实再决策)。
25
+ 4. **PTY 会话是有状态资源**:任务 Promise 的生命周期与 PTY 会话可复用生命周期必须分离——当前命令终态未经可信确认(自己 nonce 的 $? 行或 ^C trap 行),同一条 PTY 不得交给下一条命令(四阶段 RUNNING/INTERRUPTING/DRAINING/IDLE;确认不了就销毁重建,绝不定时强行复用)。
26
+
27
+ ## 防误用契约(用错就是生产事故的六条)
28
+
29
+ 1. **终止即请求、死亡须核实**:`stop()` 返回 `{status: "exited" | "stopped" | "unknown"}`。`unknown`(断线/分区/核实超时)**不是成功也不是失败**——严禁当已清理继续往下走;应重试核实或显式上报。
30
+ 2. **退出码是数据**:`exec` 非零退出码**不抛异常**(如实在 `exitCode` 字段);只有「无法执行」(超时/abort/连接死)才 reject。别把两者混为一谈。
31
+ 3. **`ready()` 有窗口语义**:先回溯热窗口再等增量——spawn 与 ready 之间输出的标记不会漏;若报「标记可能已滚出」,查落盘日志,别盲目重试。
32
+ 4. **通道语义**:缺省 `channel:"exec"`(stdout/stderr 分离、层上下文拼装);`channel:"pty"` 继承层内交互状态(su/cd),但 **stderr 混流是终端物理语义**,不是 bug。多跳 PTY 链与交互式二次跳转对 exec 通道**显式拒绝**——这是诚实行为,换 pty 或把途径机收敛为 `-J`。
33
+ 5. **跨流顺序**:双文件落盘后的聚合序是**本地到达序**(近似),不承诺进程真实写入序。
34
+ 6. **方言适配自动进行**:base64/sha256 按连接探测缓存(OPNsense/Alpine 形态已测)——但你自己的远端脚本原语若依赖 GNU 方言,请同样探测,勿硬编码。
35
+
36
+ ## 环境规格与漂移
37
+
38
+ 探测结果只存蒸馏值(版本/有无/型号);`upsert` 指纹不一致会标 **stale 且不覆盖**——重探是显式决定。nvidia-smi 驱动不通信的失败文案**不会**被记成 GPU 型号。
39
+
40
+ ## 安全边界
41
+
42
+ host key 缺省 TOFU(accept-new);高价值环境请配 `hostKeyPolicy:"strict"` + `knownHostsFile`。凭据只传**路径**;所有渲染与日志永不含密钥内容。高危操作授权属你的策略层,本包不越权预设。
43
+
44
+ ## 能力探测
45
+
46
+ 部署环境缺什么,`await stack.features()` 说了算(`mux/sftp/persistent/transports/stderrSeparated`)——降级不靠猜。
package/LICENSE ADDED
@@ -0,0 +1,202 @@
1
+
2
+ Apache License
3
+ Version 2.0, January 2004
4
+ http://www.apache.org/licenses/
5
+
6
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7
+
8
+ 1. Definitions.
9
+
10
+ "License" shall mean the terms and conditions for use, reproduction,
11
+ and distribution as defined by Sections 1 through 9 of this document.
12
+
13
+ "Licensor" shall mean the copyright owner or entity authorized by
14
+ the copyright owner that is granting the License.
15
+
16
+ "Legal Entity" shall mean the union of the acting entity and all
17
+ other entities that control, are controlled by, or are under common
18
+ control with that entity. For the purposes of this definition,
19
+ "control" means (i) the power, direct or indirect, to cause the
20
+ direction or management of such entity, whether by contract or
21
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
22
+ outstanding shares, or (iii) beneficial ownership of such entity.
23
+
24
+ "You" (or "Your") shall mean an individual or Legal Entity
25
+ exercising permissions granted by this License.
26
+
27
+ "Source" form shall mean the preferred form for making modifications,
28
+ including but not limited to software source code, documentation
29
+ source, and configuration files.
30
+
31
+ "Object" form shall mean any form resulting from mechanical
32
+ transformation or translation of a Source form, including but
33
+ not limited to compiled object code, generated documentation,
34
+ and conversions to other media types.
35
+
36
+ "Work" shall mean the work of authorship, whether in Source or
37
+ Object form, made available under the License, as indicated by a
38
+ copyright notice that is included in or attached to the work
39
+ (an example is provided in the Appendix below).
40
+
41
+ "Derivative Works" shall mean any work, whether in Source or Object
42
+ form, that is based on (or derived from) the Work and for which the
43
+ editorial revisions, annotations, elaborations, or other modifications
44
+ represent, as a whole, an original work of authorship. For the purposes
45
+ of this License, Derivative Works shall not include works that remain
46
+ separable from, or merely link (or bind by name) to the interfaces of,
47
+ the Work and Derivative Works thereof.
48
+
49
+ "Contribution" shall mean any work of authorship, including
50
+ the original version of the Work and any modifications or additions
51
+ to that Work or Derivative Works thereof, that is intentionally
52
+ submitted to Licensor for inclusion in the Work by the copyright owner
53
+ or by an individual or Legal Entity authorized to submit on behalf of
54
+ the copyright owner. For the purposes of this definition, "submitted"
55
+ means any form of electronic, verbal, or written communication sent
56
+ to the Licensor or its representatives, including but not limited to
57
+ communication on electronic mailing lists, source code control systems,
58
+ and issue tracking systems that are managed by, or on behalf of, the
59
+ Licensor for the purpose of discussing and improving the Work, but
60
+ excluding communication that is conspicuously marked or otherwise
61
+ designated in writing by the copyright owner as "Not a Contribution."
62
+
63
+ "Contributor" shall mean Licensor and any individual or Legal Entity
64
+ on behalf of whom a Contribution has been received by Licensor and
65
+ subsequently incorporated within the Work.
66
+
67
+ 2. Grant of Copyright License. Subject to the terms and conditions of
68
+ this License, each Contributor hereby grants to You a perpetual,
69
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70
+ copyright license to reproduce, prepare Derivative Works of,
71
+ publicly display, publicly perform, sublicense, and distribute the
72
+ Work and such Derivative Works in Source or Object form.
73
+
74
+ 3. Grant of Patent License. Subject to the terms and conditions of
75
+ this License, each Contributor hereby grants to You a perpetual,
76
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77
+ (except as stated in this section) patent license to make, have made,
78
+ use, offer to sell, sell, import, and otherwise transfer the Work,
79
+ where such license applies only to those patent claims licensable
80
+ by such Contributor that are necessarily infringed by their
81
+ Contribution(s) alone or by combination of their Contribution(s)
82
+ with the Work to which such Contribution(s) was submitted. If You
83
+ institute patent litigation against any entity (including a
84
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
85
+ or a Contribution incorporated within the Work constitutes direct
86
+ or contributory patent infringement, then any patent licenses
87
+ granted to You under this License for that Work shall terminate
88
+ as of the date such litigation is filed.
89
+
90
+ 4. Redistribution. You may reproduce and distribute copies of the
91
+ Work or Derivative Works thereof in any medium, with or without
92
+ modifications, and in Source or Object form, provided that You
93
+ meet the following conditions:
94
+
95
+ (a) You must give any other recipients of the Work or
96
+ Derivative Works a copy of this License; and
97
+
98
+ (b) You must cause any modified files to carry prominent notices
99
+ stating that You changed the files; and
100
+
101
+ (c) You must retain, in the Source form of any Derivative Works
102
+ that You distribute, all copyright, patent, trademark, and
103
+ attribution notices from the Source form of the Work,
104
+ excluding those notices that do not pertain to any part of
105
+ the Derivative Works; and
106
+
107
+ (d) If the Work includes a "NOTICE" text file as part of its
108
+ distribution, then any Derivative Works that You distribute must
109
+ include a readable copy of the attribution notices contained
110
+ within such NOTICE file, excluding those notices that do not
111
+ pertain to any part of the Derivative Works, in at least one
112
+ of the following places: within a NOTICE text file distributed
113
+ as part of the Derivative Works; within the Source form or
114
+ documentation, if provided along with the Derivative Works; or,
115
+ within a display generated by the Derivative Works, if and
116
+ wherever such third-party notices normally appear. The contents
117
+ of the NOTICE file are for informational purposes only and
118
+ do not modify the License. You may add Your own attribution
119
+ notices within Derivative Works that You distribute, alongside
120
+ or as an addendum to the NOTICE text from the Work, provided
121
+ that such additional attribution notices cannot be construed
122
+ as modifying the License.
123
+
124
+ You may add Your own copyright statement to Your modifications and
125
+ may provide additional or different license terms and conditions
126
+ for use, reproduction, or distribution of Your modifications, or
127
+ for any such Derivative Works as a whole, provided Your use,
128
+ reproduction, and distribution of the Work otherwise complies with
129
+ the conditions stated in this License.
130
+
131
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
132
+ any Contribution intentionally submitted for inclusion in the Work
133
+ by You to the Licensor shall be under the terms and conditions of
134
+ this License, without any additional terms or conditions.
135
+ Notwithstanding the above, nothing herein shall supersede or modify
136
+ the terms of any separate license agreement you may have executed
137
+ with Licensor regarding such Contributions.
138
+
139
+ 6. Trademarks. This License does not grant permission to use the trade
140
+ names, trademarks, service marks, or product names of the Licensor,
141
+ except as required for reasonable and customary use in describing the
142
+ origin of the Work and reproducing the content of the NOTICE file.
143
+
144
+ 7. Disclaimer of Warranty. Unless required by applicable law or
145
+ agreed to in writing, Licensor provides the Work (and each
146
+ Contributor provides its Contributions) on an "AS IS" BASIS,
147
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148
+ implied, including, without limitation, any warranties or conditions
149
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150
+ PARTICULAR PURPOSE. You are solely responsible for determining the
151
+ appropriateness of using or redistributing the Work and assume any
152
+ risks associated with Your exercise of permissions under this License.
153
+
154
+ 8. Limitation of Liability. In no event and under no legal theory,
155
+ whether in tort (including negligence), contract, or otherwise,
156
+ unless required by applicable law (such as deliberate and grossly
157
+ negligent acts) or agreed to in writing, shall any Contributor be
158
+ liable to You for damages, including any direct, indirect, special,
159
+ incidental, or consequential damages of any character arising as a
160
+ result of this License or out of the use or inability to use the
161
+ Work (including but not limited to damages for loss of goodwill,
162
+ work stoppage, computer failure or malfunction, or any and all
163
+ other commercial damages or losses), even if such Contributor
164
+ has been advised of the possibility of such damages.
165
+
166
+ 9. Accepting Warranty or Additional Liability. While redistributing
167
+ the Work or Derivative Works thereof, You may choose to offer,
168
+ and charge a fee for, acceptance of support, warranty, indemnity,
169
+ or other liability obligations and/or rights consistent with this
170
+ License. However, in accepting such obligations, You may act only
171
+ on Your own behalf and on Your sole responsibility, not on behalf
172
+ of any other Contributor, and only if You agree to indemnify,
173
+ defend, and hold each Contributor harmless for any liability
174
+ incurred by, or claims asserted against, such Contributor by reason
175
+ of your accepting any such warranty or additional liability.
176
+
177
+ END OF TERMS AND CONDITIONS
178
+
179
+ APPENDIX: How to apply the Apache License to your work.
180
+
181
+ To apply the Apache License to your work, attach the following
182
+ boilerplate notice, with the fields enclosed by brackets "[]"
183
+ replaced with your own identifying information. (Don't include
184
+ the brackets!) The text should be enclosed in the appropriate
185
+ comment syntax for the file format. We also recommend that a
186
+ file or class name and description of purpose be included on the
187
+ same "printed page" as the copyright notice for easier
188
+ identification within third-party archives.
189
+
190
+ Copyright [yyyy] [name of copyright owner]
191
+
192
+ Licensed under the Apache License, Version 2.0 (the "License");
193
+ you may not use this file except in compliance with the License.
194
+ You may obtain a copy of the License at
195
+
196
+ http://www.apache.org/licenses/LICENSE-2.0
197
+
198
+ Unless required by applicable law or agreed to in writing, software
199
+ distributed under the License is distributed on an "AS IS" BASIS,
200
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
201
+ See the License for the specific language governing permissions and
202
+ limitations under the License.
package/NOTICE ADDED
@@ -0,0 +1,10 @@
1
+ Syrkos Filaxis (牵丝)
2
+ Copyright 2026 Corolin (YiCheng Ji) and Syrkos Contributors.
3
+
4
+ This product includes software developed as part of the Syrkos (漩核) project.
5
+
6
+ "Syrkos", "漩核", "Filaxis", and "牵丝" are brand names claimed by Corolin (YiCheng Ji).
7
+
8
+ The Apache License, Version 2.0, does not grant trademark rights except as provided in Section 6 of that license.
9
+
10
+ All trademark rights, if any, are reserved by their respective owners.
package/README.md ADDED
@@ -0,0 +1,61 @@
1
+ # 牵丝 Filaxis
2
+
3
+ **千里一线,执行有迹。—— Connect · Execute · Observe · Reattach**
4
+
5
+ 面向自动化与 Agent 的远程执行运行时 SDK(Syrkos · 漩核旗下)。TypeScript 编写,Bun 与 Node LTS 双运行时,Windows 与 Linux 同构。
6
+
7
+ ```ts
8
+ import { RuntimeStack } from "@syrkos/filaxis";
9
+
10
+ const stack = new RuntimeStack();
11
+ const host = await stack.connect({ driver: "ssh", target: "my-server" });
12
+
13
+ // exec:退出码是数据,失败是异常;stdout/stderr 物理分离
14
+ const r = await host.exec("uname -a", { timeoutMs: 10_000 });
15
+ console.log(r.stdout, r.stderr, r.exitCode, r.effectiveUser);
16
+
17
+ // 长跑会话:spawn 即返 → 就绪握手 → 双流观察 → watcher → 终态核实
18
+ const cap = await host.execSession("tcpdump -i eth0 -c 100 -w /tmp/x.pcap");
19
+ await host.sessions /* tail / watch / stop——见示例 */;
20
+
21
+ // 事件(零消息队列依赖——消费方自行接队列/看板)
22
+ stack.events.on("exit", (e) => console.log("session", e.sessionId, "exit", e.exitCode));
23
+ ```
24
+
25
+ ## 能力矩阵
26
+
27
+ | 能力 | 说明 |
28
+ |---|---|
29
+ | 多 Transport 统一语义 | `local` / `ssh` / `tmux` 内置 + `registerDriver()` 开放注册;docker/k8s/teleport 经 launchCmd 接入 |
30
+ | exec 双通道 | 缺省非 PTY 通道(stdout/stderr 物理分离 + 层上下文拼装);`channel:"pty"` 继承层内交互状态 |
31
+ | 长跑会话生命周期 | spawn 即返、双文件 `.out/.err` 落盘、热窗口、行级 watcher、**终态三态** `exited/stopped/unknown` |
32
+ | ready() 就绪握手 | 回溯匹配热窗口(快输出进程竞态根治);滚出判定**有据**(evictedCount) |
33
+ | 观察流 | 独立 SSH channel 真流式直推(无轮询);ControlMaster 复用;注意力衰减回收 |
34
+ | 持久会话 | tmux 后端 terminalId 跨进程 re-attach + cwd 恢复 |
35
+ | 文件传输 | `putFile/getFile` base64 管道分块 + size/sha256 双校验 + **方言适配**(GNU/BSD/busybox——OPNsense/Alpine 不再必错) |
36
+ | 环境规格 | 两段式自发现(语言/GPU/关键包)蒸馏落盘;`matchLayers({needs})` 按需选层;指纹漂移标 stale |
37
+ | 连接治理 | 连接拓扑指纹复用(同拓扑零重建);3 次退避自动重连;层状态机与退化哨兵 |
38
+ | 安全边界 | host key 策略显式(tofu 缺省/strict+known_hosts);凭据只传路径永不外泄;渲染永不含密钥内容 |
39
+
40
+ ## 安装与运行时
41
+
42
+ ```bash
43
+ bun add @syrkos/filaxis # 或 npm install @syrkos/filaxis
44
+ ```
45
+
46
+ - 运行时:Bun ≥1.x / Node LTS(内核统一 `node:` 标准库,零 runtime 专有 API——CI lint 断言)
47
+ - npm 依赖:**零**(`dependencies` 为空是 AC 门禁项,见 `bun run check:boundaries`)
48
+ - 系统依赖按能力分列(`stack.features()` 运行时探测):`ssh`≥7.3 全功能(`-J`)、`tmux` 仅持久会话(缺席自动降级非持久)、`sftp` 仅传输快路径
49
+
50
+ ## 语义契约要点(使用前必读)
51
+
52
+ 详见包内 [AGENTS.md](./AGENTS.md)——**终止即请求、死亡须核实**(`unknown` 不是失败也不是成功);退出码非零是数据不是异常;PTY 通道 stderr 混流是终端语义;跨流聚合序为到达序。
53
+
54
+ ## 示例与技能剧本
55
+
56
+ - [examples/](./examples/):跨主机诊断 / 长跑观察 / Agent 工具面最小封装(三可运行示例)
57
+ - [docs/skills/](./docs/skills/):场景操作剧本(给人也给 Agent)
58
+
59
+ ## 许可
60
+
61
+ [Apache-2.0](./LICENSE) + [NOTICE](./NOTICE)(牵丝 Filaxis / Syrkos · 漩核 品牌归属声明)。
package/bin/filaxis.ts ADDED
@@ -0,0 +1,112 @@
1
+ #!/usr/bin/env bun
2
+ /**
3
+ * filaxis CLI — 极简宿主形态(第六季盲测摩擦点 ①:SDK 需要 bun -e 手拼几十行 TS——
4
+ * Agent 先跟宿主 Shell 引号搏斗。CLI 一行替代:filaxis exec|cat|edit|observe)
5
+ *
6
+ * 零依赖手写 argv。远端目标统一 --host(ssh);缺省 local。
7
+ */
8
+ import { RuntimeStack, LocalRuntimeDriver, SshPtyDriver, editFile, discoverLayer } from "../src/index.js";
9
+ import type { RuntimeDriver } from "../src/driver.js";
10
+
11
+ const args = process.argv.slice(2);
12
+ const cmd = args[0];
13
+
14
+ function parseOpts(argv: string[]): {
15
+ host?: string; user?: string; port?: number; key?: string;
16
+ timeout?: number; duration?: number; stream?: string; all?: boolean;
17
+ positional: string[];
18
+ } {
19
+ const o: ReturnType<typeof parseOpts> = { positional: [] };
20
+ for (let i = 0; i < argv.length; i++) {
21
+ const a = argv[i]!;
22
+ if (a === "--") continue; // 命令分隔符(可省)
23
+ switch (a) {
24
+ case "--host": o.host = argv[++i]; break;
25
+ case "--user": o.user = argv[++i]; break;
26
+ case "--port": o.port = parseInt(argv[++i]!, 10); break;
27
+ case "--key": o.key = argv[++i]; break;
28
+ case "--timeout": o.timeout = parseInt(argv[++i]!, 10); break;
29
+ case "--duration": o.duration = parseInt(argv[++i]!, 10); break;
30
+ case "--stream": o.stream = argv[++i]; break;
31
+ case "--all": o.all = true; break;
32
+ default: o.positional.push(a);
33
+ }
34
+ }
35
+ return o;
36
+ }
37
+
38
+ async function driverFor(opts: ReturnType<typeof parseOpts>): Promise<RuntimeDriver> {
39
+ if (opts.host) {
40
+ return new SshPtyDriver({
41
+ driver: "ssh", target: opts.host,
42
+ config: { connParams: { user: opts.user, port: opts.port, keyFile: opts.key } },
43
+ });
44
+ }
45
+ return new LocalRuntimeDriver();
46
+ }
47
+
48
+ async function main() {
49
+ const o = parseOpts(args.slice(1));
50
+ const drv = await driverFor(o);
51
+ try {
52
+ switch (cmd) {
53
+ case "exec": {
54
+ const r = await drv.exec(o.positional.join(" "), { timeoutMs: o.timeout ?? 120_000 });
55
+ process.stdout.write(r.stdout);
56
+ if (r.stderr) process.stderr.write(r.stderr);
57
+ console.error(`\n[exit=${r.exitCode} user=${r.effectiveUser ?? "?"}]`);
58
+ process.exit(r.exitCode);
59
+ break;
60
+ }
61
+ case "cat": {
62
+ const [p] = o.positional;
63
+ if (!p) throw new Error("用法: filaxis cat [--host ...] <path>");
64
+ process.stdout.write(await drv.fs.readFile(p));
65
+ break;
66
+ }
67
+ case "edit": {
68
+ const [p, old, newStr] = o.positional;
69
+ if (!p || old === undefined || newStr === undefined) {
70
+ throw new Error("用法: filaxis edit [--host ...] <path> <old> <new> [--all]");
71
+ }
72
+ const r = await editFile(drv, p, old, newStr, { all: o.all });
73
+ console.log(`edited: ${r.path} 替换 ${r.occurrences} 处,${r.bytesBefore}B → ${r.bytesAfter}B`);
74
+ break;
75
+ }
76
+ case "observe": {
77
+ const h = await drv.execSession(o.positional.join(" "), { name: "cli-observe" });
78
+ await new Promise((r) => setTimeout(r, o.duration ?? 8000));
79
+ const lines = (drv as unknown as {
80
+ sessions?: { tailLines?: (id: string, n?: number) => Array<{ stream: string; text: string }> };
81
+ }).sessions?.tailLines?.(h.sessionId, 500)
82
+ ?? (await drv.tailSession(h.sessionId, 500)).map((t) => ({ stream: "stdout", text: t }));
83
+ const filtered = (o.stream && o.stream !== "both") ? lines.filter((l) => l.stream === o.stream) : lines;
84
+ for (const l of filtered) console.log(`[${l.stream}] ${l.text}`);
85
+ await drv.stopSession(h.sessionId).catch(() => undefined);
86
+ break;
87
+ }
88
+ case "probe": {
89
+ const r = await discoverLayer(drv, { skipStage2: false });
90
+ console.log(JSON.stringify({ key: r.key, spec: r.spec, note: r.probeNote }, null, 2));
91
+ break;
92
+ }
93
+ default:
94
+ console.error(`filaxis CLI — 千里一线,执行有迹
95
+ 用法:
96
+ filaxis exec [--host u@h [--port N] [--key F]] [--timeout MS] -- <command>
97
+ filaxis cat [--host ...] <path>
98
+ filaxis edit [--host ...] <path> <old> <new> [--all] # 受控编辑(TOCTOU 锁+精确替换)
99
+ filaxis observe [--host ...] [--stream stderr|stdout|both] [--duration MS] -- <command>
100
+ filaxis probe [--host ...] # 两段式环境探测
101
+ 缺省 --host 为 local。`);
102
+ process.exit(cmd ? 1 : 0);
103
+ }
104
+ } finally {
105
+ await drv.destroy().catch(() => undefined);
106
+ }
107
+ }
108
+
109
+ void main().catch((err) => {
110
+ console.error(`[filaxis] ${(err as Error).message}`);
111
+ process.exit(1);
112
+ });
@@ -0,0 +1,99 @@
1
+ /**
2
+ * agent-toolkit.ts — 原生 Agent 工具集(Gemini 试用反馈 #3)
3
+ *
4
+ * 一行 `createAgentToolkit(stack)` 生成 LLM 工具面(run_command / spawn_and_observe /
5
+ * stop_and_verify)——OpenAI/Anthropic/Vercel AI SDK 通吃的 {tools, handlers} 双层结构:
6
+ * 定义层喂模型,执行层留宿主(桥到任意框架)。语义契约(退出码是数据/终态三态/
7
+ * 就绪握手)由内核承载,宿主零胶水。
8
+ */
9
+ import type { RuntimeStack } from "./runtime-stack.js";
10
+ import type { RuntimeDriver } from "./driver.js";
11
+ export interface AgentToolDef {
12
+ type: "function";
13
+ function: {
14
+ name: string;
15
+ description: string;
16
+ parameters: Record<string, unknown>;
17
+ };
18
+ }
19
+ export interface AgentToolHandlers {
20
+ run_command(args: {
21
+ command: string;
22
+ timeout_ms?: number;
23
+ layer?: string;
24
+ }): Promise<{
25
+ stdout: string;
26
+ stderr: string;
27
+ exit_code: number;
28
+ effective_user?: string;
29
+ }>;
30
+ read_file(args: {
31
+ path: string;
32
+ layer?: string;
33
+ }): Promise<{
34
+ path: string;
35
+ content: string;
36
+ size: number;
37
+ mtime_ms: number;
38
+ }>;
39
+ edit_file(args: {
40
+ path: string;
41
+ old: string;
42
+ new: string;
43
+ all?: boolean;
44
+ layer?: string;
45
+ }): Promise<{
46
+ path: string;
47
+ occurrences: number;
48
+ bytes_before: number;
49
+ bytes_after: number;
50
+ }>;
51
+ observe_stream(args: {
52
+ command: string;
53
+ duration_ms?: number;
54
+ stream?: "stdout" | "stderr" | "both";
55
+ name?: string;
56
+ }): Promise<{
57
+ session_id: string;
58
+ lines: Array<{
59
+ stream: string;
60
+ text: string;
61
+ }>;
62
+ }>;
63
+ spawn_and_observe(args: {
64
+ command: string;
65
+ ready_marker?: string;
66
+ error_pattern?: string;
67
+ name?: string;
68
+ }): Promise<{
69
+ session_id: string;
70
+ log_base: string;
71
+ note?: string;
72
+ }>;
73
+ stop_and_verify(args: {
74
+ session_id: string;
75
+ }): Promise<{
76
+ status: "exited" | "stopped" | "unknown";
77
+ exit_code?: number | null;
78
+ note?: string;
79
+ }>;
80
+ }
81
+ export interface AgentToolkit {
82
+ tools: AgentToolDef[];
83
+ handlers: AgentToolHandlers;
84
+ /** 工具面绑定的层(缺省 local;远端层经 stack.connect 后传入重绑) */
85
+ readonly layer: Promise<RuntimeDriver>;
86
+ }
87
+ export interface AgentToolkitOptions {
88
+ /** 层描述符(缺省 local);也可直接传已连接的 driver */
89
+ descriptor?: {
90
+ driver: string;
91
+ target?: string;
92
+ config?: Record<string, unknown>;
93
+ };
94
+ driver?: RuntimeDriver;
95
+ /** 就绪握手与 watcher 轮询的超时上限 */
96
+ readyTimeoutMs?: number;
97
+ }
98
+ /** 生成 Agent 工具集(定义层 + 执行层;宿主桥接到任意 LLM 框架) */
99
+ export declare function createAgentToolkit(stack: RuntimeStack, opts?: AgentToolkitOptions): AgentToolkit;
@@ -0,0 +1,31 @@
1
+ /**
2
+ * dialect.ts — 远端命令方言适配层(FEAT-14:GNU · BSD · busybox 三族原语探测与渲染)
3
+ *
4
+ * 动机(生产实锤):`base64 -w 0` 为纯 GNU 方言——FreeBSD/OPNsense 的 base64
5
+ * 不认 `-w`(BSD 用 `-b`,解码历史差异 `-d`/`-D`);sha256 工具 Linux=sha256sum /
6
+ * FreeBSD=/sbin/sha256 -q / 精简容器=busybox 或 openssl dgst。目标环境
7
+ * (OPNsense/Alpine)不探测必错。探测结果**按连接缓存**(探测键由调用方持有)。
8
+ */
9
+ import type { ExecResult } from "./driver.js";
10
+ export type DialectFamily = "gnu" | "bsd" | "busybox" | "openssl-fallback" | "unknown";
11
+ /** 一套已探测的远端原语(渲染为 argv 前缀,拼接数据参数后执行) */
12
+ export interface RemoteDialect {
13
+ family: DialectFamily;
14
+ /** 编码(无换行输出):["base64","-w","0"](GNU)/ ["base64"](BSD·默认不折行) */
15
+ base64Encode: string[];
16
+ /** 解码:GNU ["base64","-d"] / BSD ["base64","-D"] */
17
+ base64Decode: string[];
18
+ /** sha256 摘要:["sha256sum"] / ["sha256","-q"] / busybox ["sha256sum"] / openssl ["openssl","dgst","-sha256"] */
19
+ sha256: string[];
20
+ }
21
+ export type ExecFn = (command: string) => Promise<Pick<ExecResult, "stdout" | "exitCode">>;
22
+ /** 探测失败时的兜底:全部原语标记不可用(显式,不静默用错方言) */
23
+ export declare const NULL_DIALECT: RemoteDialect;
24
+ /** 探测远端方言(每命令独立判定;缺原语=该族标记跳过,非报错) */
25
+ export declare function probeDialect(exec: ExecFn): Promise<RemoteDialect>;
26
+ /** 按连接缓存:探测键(调用方用连接身份)→ 方言 */
27
+ export declare class DialectCache {
28
+ private cache;
29
+ get(probeKey: string, exec: ExecFn, force?: boolean): Promise<RemoteDialect>;
30
+ invalidate(probeKey?: string): void;
31
+ }