cofluxd 0.10.0 → 0.11.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/cofluxd.mjs +48 -2
- package/package.json +1 -1
- package/skills/coflux/SKILL.md +40 -2
package/cofluxd.mjs
CHANGED
|
@@ -761,6 +761,11 @@ async function cmdHook() {
|
|
|
761
761
|
|
|
762
762
|
const AGENT_TIMEOUT_MS = 30_000;
|
|
763
763
|
const DEFAULT_READ_LINES = 200;
|
|
764
|
+
// wait 的循环必须在 CLI 侧:单次 agentPost 撑不起长等待(daemon 控制 WS 有自己的往返超时)。
|
|
765
|
+
// 默认 30 分钟——编码任务常跑很久;轮询走 terminal.list(status 来自 sessionExit 事件链,
|
|
766
|
+
// 不受快照 ~2s 延迟影响),3 秒一次对本机 loopback 是零负担。
|
|
767
|
+
const DEFAULT_WAIT_TIMEOUT_S = 1800;
|
|
768
|
+
const WAIT_POLL_MS = 3000;
|
|
764
769
|
|
|
765
770
|
async function agentPost(body) {
|
|
766
771
|
const portResult = localGatewayPort();
|
|
@@ -824,8 +829,34 @@ async function cmdTerminal(values) {
|
|
|
824
829
|
console.log(`# ${result.status}${exit}`);
|
|
825
830
|
const text = tailLines(stripAnsi(result.ansi), lines);
|
|
826
831
|
console.log(text || "(暂无输出)");
|
|
832
|
+
} else if (sub === "send") {
|
|
833
|
+
const taskId = positionals[2];
|
|
834
|
+
if (!taskId) die("terminal send 需要 <taskId>(用 cofluxd terminal list 查)");
|
|
835
|
+
const text = values.text ?? "";
|
|
836
|
+
if (!text && !values.enter) die(`terminal send 需要 --text "<文本>"(或至少 --enter 发一个回车)`);
|
|
837
|
+
await agentPost({ action: "terminal.send", taskId, text, enter: Boolean(values.enter) });
|
|
838
|
+
console.log(`已写入终端 ${taskId}(用 cofluxd terminal read ${taskId} 核对效果)`);
|
|
839
|
+
} else if (sub === "wait") {
|
|
840
|
+
const taskId = positionals[2];
|
|
841
|
+
if (!taskId) die("terminal wait 需要 <taskId>(用 cofluxd terminal list 查)");
|
|
842
|
+
const requested = Number(values.timeout);
|
|
843
|
+
const timeoutSec = Number.isFinite(requested) && requested > 0 ? requested : DEFAULT_WAIT_TIMEOUT_S;
|
|
844
|
+
const deadline = Date.now() + timeoutSec * 1000;
|
|
845
|
+
for (;;) {
|
|
846
|
+
const { terminals } = await agentPost({ action: "terminal.list" });
|
|
847
|
+
const t = terminals.find((x) => x.taskId === taskId);
|
|
848
|
+
if (!t) die(`本工作区没有终端 ${taskId}(用 cofluxd terminal list 查)`);
|
|
849
|
+
if (t.status === "exited") {
|
|
850
|
+
const exit = t.exitCode === undefined || t.exitCode === null ? "" : ` exit=${t.exitCode}`;
|
|
851
|
+
return void console.log(`# exited${exit}`);
|
|
852
|
+
}
|
|
853
|
+
if (Date.now() >= deadline) {
|
|
854
|
+
die(`等待超时(${timeoutSec}s):终端 ${taskId} 仍是 ${t.status}。可加大 --timeout,或 cofluxd terminal read ${taskId} 看现场`);
|
|
855
|
+
}
|
|
856
|
+
await sleep(WAIT_POLL_MS);
|
|
857
|
+
}
|
|
827
858
|
} else {
|
|
828
|
-
die(`terminal 需要子命令:new | list | read`);
|
|
859
|
+
die(`terminal 需要子命令:new | list | read | wait | send`);
|
|
829
860
|
}
|
|
830
861
|
}
|
|
831
862
|
|
|
@@ -836,6 +867,13 @@ async function cmdNotify() {
|
|
|
836
867
|
console.log("已通知用户(工作区在侧栏转为「等待交互」)");
|
|
837
868
|
}
|
|
838
869
|
|
|
870
|
+
async function cmdProgress() {
|
|
871
|
+
const message = positionals.slice(1).join(" ").trim();
|
|
872
|
+
if (!message) die(`progress 需要一句话,例如:cofluxd progress "复现了,正在定位 relay 重连"`);
|
|
873
|
+
await agentPost({ action: "progress", message });
|
|
874
|
+
console.log("已更新进度(显示在工作区卡片上,被下一条覆盖)");
|
|
875
|
+
}
|
|
876
|
+
|
|
839
877
|
async function cmdPorts() {
|
|
840
878
|
const { ports } = await agentPost({ action: "ports" });
|
|
841
879
|
if (!ports.length) return void console.log("本工作区暂无监听端口");
|
|
@@ -864,7 +902,12 @@ const HELP = `cofluxd —— coflux daemon 管理
|
|
|
864
902
|
cofluxd terminal list 列出本工作区的终端(含 status / 退出码)
|
|
865
903
|
cofluxd terminal read <taskId> [--lines N]
|
|
866
904
|
读某个终端的内容(纯文本,默认最后 200 行;终端已退出也能读)
|
|
905
|
+
cofluxd terminal wait <taskId> [--timeout <秒>]
|
|
906
|
+
阻塞等到该终端退出,打印退出码(默认超时 30 分钟)
|
|
907
|
+
cofluxd terminal send <taskId> --text "<文本>" [--enter]
|
|
908
|
+
往终端里输入文本(--enter 追加回车)。用户正在接管时会被拒
|
|
867
909
|
cofluxd notify "<一句话>" 叫人:工作区在侧栏转为「等待交互」并显示这句话
|
|
910
|
+
cofluxd progress "<一句话>" 播报进度:显示在工作区卡片上,被下一条覆盖(不打扰用户)
|
|
868
911
|
cofluxd ports 列出本工作区的监听端口及可直接打开的预览 URL
|
|
869
912
|
|
|
870
913
|
up flags: --server <ws://.../daemon> --name <名> --shell <路径>
|
|
@@ -887,6 +930,9 @@ const { values, positionals } = parseArgs({
|
|
|
887
930
|
title: { type: "string" },
|
|
888
931
|
cmd: { type: "string" },
|
|
889
932
|
lines: { type: "string" },
|
|
933
|
+
timeout: { type: "string" },
|
|
934
|
+
text: { type: "string" },
|
|
935
|
+
enter: { type: "boolean", default: false },
|
|
890
936
|
version: { type: "string" },
|
|
891
937
|
"bin-dir": { type: "string" },
|
|
892
938
|
"no-start": { type: "boolean", default: false },
|
|
@@ -900,7 +946,7 @@ let cmd = positionals[0];
|
|
|
900
946
|
if (values.help || cmd === "help") { console.log(HELP); process.exit(0); }
|
|
901
947
|
if (!cmd) cmd = fs.existsSync(SETTINGS) ? "status" : "up"; // 首次裸跑 → 引导
|
|
902
948
|
|
|
903
|
-
const handlers = { up: cmdUp, update: cmdUpdate, restart: cmdRestart, down: cmdDown, status: cmdStatus, doctor: cmdDoctor, fda: cmdFda, logs: cmdLogs, uninstall: cmdUninstall, hook: cmdHook, terminal: cmdTerminal, notify: cmdNotify, ports: cmdPorts };
|
|
949
|
+
const handlers = { up: cmdUp, update: cmdUpdate, restart: cmdRestart, down: cmdDown, status: cmdStatus, doctor: cmdDoctor, fda: cmdFda, logs: cmdLogs, uninstall: cmdUninstall, hook: cmdHook, terminal: cmdTerminal, notify: cmdNotify, progress: cmdProgress, ports: cmdPorts };
|
|
904
950
|
const h = handlers[cmd];
|
|
905
951
|
if (!h) die(`未知命令: ${cmd}${MIGRATED[cmd] ? `\n${MIGRATED[cmd]}` : ""}\n\n${HELP}`);
|
|
906
952
|
await h(values);
|
package/package.json
CHANGED
package/skills/coflux/SKILL.md
CHANGED
|
@@ -56,7 +56,44 @@ cofluxd terminal read <taskId> --lines 50
|
|
|
56
56
|
**终端已经退出也能 read**——「命令跑完了看输出」正是最常用的场景。
|
|
57
57
|
|
|
58
58
|
内容有最多约 2 秒的延迟(来自中心的定期快照),所以刚 `new` 完立刻 `read` 可能是空的。
|
|
59
|
-
|
|
59
|
+
|
|
60
|
+
### 等命令跑完
|
|
61
|
+
|
|
62
|
+
```sh
|
|
63
|
+
cofluxd terminal wait <taskId> # 阻塞到该终端退出,打印退出码(默认最长等 30 分钟)
|
|
64
|
+
cofluxd terminal wait <taskId> --timeout 300 # 自定超时(秒);超时会明确报错并非零退出
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
要等一条命令跑完就用 `wait`,**别自己写轮询循环**——它一条命令阻塞到位,退出码直接给你。
|
|
68
|
+
超时不代表命令失败,只是还没跑完:`read` 看看现场再决定继续等还是处理。
|
|
69
|
+
|
|
70
|
+
### 往终端里输入
|
|
71
|
+
|
|
72
|
+
```sh
|
|
73
|
+
cofluxd terminal send <taskId> --text "y" --enter # 输入一行并回车
|
|
74
|
+
cofluxd terminal send <taskId> --enter # 只按一个回车
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
用在命令要交互确认(y/N、选项)、或想在跑完的同一 shell 里补一条命令的时候。纪律:
|
|
78
|
+
|
|
79
|
+
- **先 `read` 再 `send`**:看清终端现在在等什么再输入,别盲打。
|
|
80
|
+
- **用户正在接管时会被拒**——这不是错误,是设计:人永远优先。被拒就停手,
|
|
81
|
+
要沟通用 `notify`,别重试。
|
|
82
|
+
- send 超时后**不要直接重发**:先 `read` 确认刚才那次到底进没进去,重复输入比丢输入更糟。
|
|
83
|
+
|
|
84
|
+
### 播报进度
|
|
85
|
+
|
|
86
|
+
```sh
|
|
87
|
+
cofluxd progress "复现了,正在定位 relay 重连的时序"
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
一句话告诉用户你干到哪了,显示在工作区卡片上,被下一条覆盖。在关键节点更新:复现了、
|
|
91
|
+
定位到了、修完在验、卡在哪。它**不打扰用户**,和 `notify` 是两条信道:
|
|
92
|
+
|
|
93
|
+
- `progress` = 播报(用户扫一眼就知道进展,不需要回应)
|
|
94
|
+
- `notify` = 叫人(工作区转「等待交互」,用户该来看看了)
|
|
95
|
+
|
|
96
|
+
拿不准用哪个:不需要用户做任何事就用 `progress`。
|
|
60
97
|
|
|
61
98
|
### 叫人
|
|
62
99
|
|
|
@@ -82,7 +119,8 @@ cofluxd ports
|
|
|
82
119
|
|
|
83
120
|
## 边界
|
|
84
121
|
|
|
85
|
-
-
|
|
122
|
+
- 你能开、读、等、输入,但**输入是人类优先的受限写权**:用户正在接管的终端你写不进去
|
|
123
|
+
(会被明确拒绝),用户随时接管也会把你顶掉。别和人抢终端。
|
|
86
124
|
- 能看到的只有**你自己所在的工作区**,别的工作区和别的机器都看不见也碰不到。
|
|
87
125
|
- 一个工作区同时活着的终端有上限(默认 8,含用户自己开的)。撞上限先 `list` 看看,
|
|
88
126
|
多半是有跑完没收的;真是用户占满了,就 `notify` 告诉他,别硬试。
|