@sleep2agi/agent-network 2.3.0-preview.8 → 2.3.0-preview.80
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/README.md +35 -324
- package/dist/bin/anet.cjs +101 -0
- package/dist/bin/cli.d.ts +1 -0
- package/dist/bin/cli.js +20 -1
- package/dist/bin/goal-wake-log-render.d.ts +31 -0
- package/dist/src/active-network-task.d.ts +28 -0
- package/dist/src/batch-workdir.d.ts +9 -0
- package/dist/src/bootstrap-password-db.d.ts +13 -0
- package/dist/src/channel-attachments.d.ts +29 -0
- package/dist/src/channel-meta.d.ts +10 -0
- package/dist/src/channel-task-trace.d.ts +14 -0
- package/dist/src/claude-vendor-env.d.ts +28 -0
- package/dist/src/cli-args.d.ts +8 -0
- package/dist/src/cli-version-display.d.ts +16 -0
- package/dist/src/client-task-trace.d.ts +9 -0
- package/dist/src/client.js +1 -1
- package/dist/src/codex-copresence-preflight.d.ts +65 -0
- package/dist/src/codex-copresence-profile.d.ts +125 -0
- package/dist/src/codex-copresence-recovery.d.ts +43 -0
- package/dist/src/codex-copresence-thread.d.ts +13 -0
- package/dist/src/codex-model-default.d.ts +6 -0
- package/dist/src/codex-tui-client-health.d.ts +17 -0
- package/dist/src/commhub-response.d.ts +1 -0
- package/dist/src/controlled-upload.d.ts +83 -0
- package/dist/src/copresence-deps.d.ts +22 -0
- package/dist/src/copresence-identity.d.ts +339 -0
- package/dist/src/copresence-startup-diagnosis.d.ts +17 -0
- package/dist/src/daemon-capability-display.d.ts +110 -0
- package/dist/src/daemon-capability-display.js +21 -0
- package/dist/src/daemon-runtime-path-preflight.d.ts +22 -0
- package/dist/src/daemon-runtime-staleness.d.ts +13 -0
- package/dist/src/dashboard-managed-process.d.ts +35 -0
- package/dist/src/display-width.d.ts +27 -0
- package/dist/src/doctor-node-count.d.ts +28 -0
- package/dist/src/environ-alias.d.ts +14 -0
- package/dist/src/grok-attach-client.d.ts +129 -0
- package/dist/src/grok-build-drift.d.ts +15 -0
- package/dist/src/grok-copresence-disclosure.d.ts +11 -0
- package/dist/src/grok-copresence-orchestration.d.ts +75 -0
- package/dist/src/grok-copresence-profile.d.ts +65 -0
- package/dist/src/host-telemetry.d.ts +14 -0
- package/dist/src/hub-time-display.d.ts +20 -0
- package/dist/src/hub-version-skew.d.ts +19 -0
- package/dist/src/im/correlation-store.d.ts +34 -0
- package/dist/src/im/feishu/adapter.d.ts +87 -1
- package/dist/src/im/feishu/bridge.d.ts +85 -14
- package/dist/src/im/feishu/config.d.ts +31 -0
- package/dist/src/im/feishu/hub-upload.d.ts +88 -0
- package/dist/src/im/feishu/outbound-marker.d.ts +140 -0
- package/dist/src/im/feishu/outbound-paths.d.ts +50 -0
- package/dist/src/im/feishu/outbound-route.d.ts +62 -0
- package/dist/src/im/feishu/worker-lifecycle.d.ts +13 -0
- package/dist/src/im/feishu/worker.js +190 -139
- package/dist/src/im/types.d.ts +38 -1
- package/dist/src/local-process-state.d.ts +12 -0
- package/dist/src/locale-diagnostic.d.ts +12 -0
- package/dist/src/ls-columns.d.ts +15 -0
- package/dist/src/mock-llm.d.ts +12 -0
- package/dist/src/node-activity-log.d.ts +4 -0
- package/dist/src/node-not-found.d.ts +1 -0
- package/dist/src/node-server-payload.d.ts +66 -0
- package/dist/src/node-server.js +7 -1
- package/dist/src/normalize-runtime.d.ts +29 -2
- package/dist/src/offline-age.d.ts +29 -0
- package/dist/src/one-line-cell.d.ts +20 -0
- package/dist/src/opencode-agent-node-pair.d.ts +25 -0
- package/dist/src/opencode-auth-login.d.ts +43 -0
- package/dist/src/opencode-launch-env.d.ts +13 -0
- package/dist/src/opencode-owner-mode.d.ts +6 -0
- package/dist/src/opencode-package-binary.d.ts +21 -0
- package/dist/src/opencode-pin.d.ts +44 -0
- package/dist/src/opencode-preset.d.ts +73 -0
- package/dist/src/opencode-runtime-binding.d.ts +30 -0
- package/dist/src/opencode-safe-root.d.ts +27 -0
- package/dist/src/opencode-smoke-env.d.ts +1 -0
- package/dist/src/outbound-attachments.d.ts +57 -0
- package/dist/src/outbound-tool-names.d.ts +1 -0
- package/dist/src/owned-roots.d.ts +58 -0
- package/dist/src/owner-env-file.d.ts +2 -0
- package/dist/src/package-mode-preflight.d.ts +41 -0
- package/dist/src/posix-codex-copresence.d.ts +8 -0
- package/dist/src/posix-modes.d.ts +36 -0
- package/dist/src/primary-network.d.ts +23 -0
- package/dist/src/private-state.d.ts +10 -0
- package/dist/src/process-telemetry.d.ts +12 -0
- package/dist/src/profile-serialize.d.ts +1 -0
- package/dist/src/project-key.d.ts +1 -0
- package/dist/src/reply-originator.d.ts +20 -0
- package/dist/src/resume-runtime-infer.d.ts +18 -0
- package/dist/src/secret-shell-guidance.d.ts +3 -0
- package/dist/src/session-status-class.d.ts +48 -0
- package/dist/src/stale-socket.d.ts +118 -0
- package/dist/src/subcommand-redirect.d.ts +26 -0
- package/dist/src/task-trace.d.ts +33 -0
- package/dist/src/tmux-attach.d.ts +8 -0
- package/dist/src/tmux-capability.d.ts +58 -0
- package/dist/src/tmux-exact-target.d.ts +34 -0
- package/dist/src/tmux-pane-prompt.d.ts +22 -0
- package/dist/src/token-cli.d.ts +13 -0
- package/dist/src/tool-allowlist.d.ts +28 -0
- package/dist/src/unsafe-package-path-reason.d.ts +17 -0
- package/dist/src/win-launcher.d.ts +20 -0
- package/dist/src/windows-codex-copresence.d.ts +60 -0
- package/package.json +10 -5
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export interface ProcessTelemetry {
|
|
2
|
+
rss_bytes: number;
|
|
3
|
+
rss_mb: number;
|
|
4
|
+
cpu_pct: number | null;
|
|
5
|
+
uptime_seconds: number;
|
|
6
|
+
in_flight_count: number;
|
|
7
|
+
}
|
|
8
|
+
export declare function incrementInFlight(): void;
|
|
9
|
+
export declare function decrementInFlight(): void;
|
|
10
|
+
export declare function getInFlightCount(): number;
|
|
11
|
+
export declare function getProcessTelemetry(): ProcessTelemetry;
|
|
12
|
+
export declare function _resetProcessTelemetry(): void;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function serializeProfileForConfigJson(normalized: Record<string, any>, profile: Record<string, any>): Record<string, any>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function encodeCwd(cwd: string): string;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export type ReplyAliasDecision =
|
|
2
|
+
/** 把 alias 显式发出去 */
|
|
3
|
+
{
|
|
4
|
+
readonly kind: "known";
|
|
5
|
+
readonly alias: string;
|
|
6
|
+
}
|
|
7
|
+
/** 省略 alias,交给 hub 从 in_reply_to 推导 */
|
|
8
|
+
| {
|
|
9
|
+
readonly kind: "derive";
|
|
10
|
+
}
|
|
11
|
+
/** 没有 task_id 可推导:保持历史行为,发给 hub */
|
|
12
|
+
| {
|
|
13
|
+
readonly kind: "hub";
|
|
14
|
+
readonly alias: "hub";
|
|
15
|
+
};
|
|
16
|
+
export declare function decideReplyAlias(taskId: string | null | undefined, lookup: (taskId: string) => string | undefined): ReplyAliasDecision;
|
|
17
|
+
/** 把决策摊成 send_reply 的参数片段。`derive` 时**不含** alias 键。 */
|
|
18
|
+
export declare function replyAliasArgs(d: ReplyAliasDecision): {
|
|
19
|
+
alias?: string;
|
|
20
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export interface ResumeRuntimeInput {
|
|
2
|
+
/** raw --resume value; "true" means the flag was present with no value */
|
|
3
|
+
resume?: string;
|
|
4
|
+
/** whether --resume-latest was passed */
|
|
5
|
+
resumeLatest?: boolean;
|
|
6
|
+
/** an already-resolved session id, if any (skips inference) */
|
|
7
|
+
session?: string;
|
|
8
|
+
/** normalized --runtime, or empty/undefined when the user passed none */
|
|
9
|
+
explicitRuntime?: string;
|
|
10
|
+
}
|
|
11
|
+
export interface ResumeRuntimeResult {
|
|
12
|
+
/** runtime to force onto opts when it was left to default */
|
|
13
|
+
inferredRuntime?: string;
|
|
14
|
+
/** set when an explicit non-cli runtime conflicts with --resume */
|
|
15
|
+
conflictError?: string;
|
|
16
|
+
}
|
|
17
|
+
export declare const CLAUDE_CODE_CLI = "claude-code-cli";
|
|
18
|
+
export declare function resolveRuntimeForResume(input: ResumeRuntimeInput): ResumeRuntimeResult;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `anet status` 的会话状态分类。
|
|
3
|
+
*
|
|
4
|
+
* 🔴 为什么单独成文件:原先它是 statusCommand 里的一个闭包,没有任何测试碰得到它 ——
|
|
5
|
+
* 而它决定了运维看到的那三个数字。一个把「卡住」算成「在干活」的分类器,
|
|
6
|
+
* 和一个正确的分类器,在输出上长得一模一样(都是一个数)。
|
|
7
|
+
*
|
|
8
|
+
* 🔴 改了什么:`blocked` / `error` 原先被折进 `working`。
|
|
9
|
+
* 它们的含义是**需要人看一眼**,不是**正在推进**。
|
|
10
|
+
* 运维看到「5 working」会认为一切正常,而其中可能有几个卡了很久 ——
|
|
11
|
+
* #1548 已经证明 `blocked` 是一个**没有出口**的状态:
|
|
12
|
+
* 只有 report_completion 能把它拉回 idle,所以一个 agent 可以永远停在那里。
|
|
13
|
+
*
|
|
14
|
+
* `waiting_input` 保留在 working 里:它是一个**进行中的回合**在等人,
|
|
15
|
+
* 与 blocked/error 不同 —— 那是回合本身出了问题。
|
|
16
|
+
*/
|
|
17
|
+
export type SessionClass = "idle" | "working" | "attention" | "offline";
|
|
18
|
+
export declare function classifySessionStatus(raw: unknown): SessionClass;
|
|
19
|
+
/**
|
|
20
|
+
* `anet status` 顶部那三/四个数字。
|
|
21
|
+
*
|
|
22
|
+
* 🔴 为什么它必须和上面的分类器用同一套判据(#1625):
|
|
23
|
+
* 原先 `cli.ts` 是 `statusRes.summary || sessions.reduce(…)`,而
|
|
24
|
+
* `/api/status` **总是**返回 summary ⇒ 右边那支从不执行,屏幕上的数字
|
|
25
|
+
* 来自**服务端**一份还停在 #1548 之前的分类(它把 `blocked`/`error`
|
|
26
|
+
* 折进 `working`)。于是一个 blocked 节点同时出现在 `working` 和
|
|
27
|
+
* `needs attention` 两格里,四个数加起来比总数多一个。
|
|
28
|
+
*
|
|
29
|
+
* 🔴 为什么本地算是安全的:`/api/status` 只加 `addNetworkScope`,没有任何
|
|
30
|
+
* 状态/别名过滤,而它的 summary 就是从**同一个 sessions 数组** reduce 出来的
|
|
31
|
+
* —— 两者范围逐字相同。(这一点对 MCP 的 `get_all_status` **不成立**:
|
|
32
|
+
* 那边 summary 走独立的 `GROUP BY status` 查询、无视 filter,所以别照搬。)
|
|
33
|
+
*
|
|
34
|
+
* 🔴 `attention` 必须显式初始化为 0。原来的累加器只有
|
|
35
|
+
* `{idle, working, offline, total}`,`acc["attention"]++` 会得到 **NaN**,
|
|
36
|
+
* 而 `summary.attention ?? attention.length` 里的 `??` **不接 NaN**,
|
|
37
|
+
* 屏幕会印 `NaN needs attention`。那一支从不执行,所以从没人见过。
|
|
38
|
+
*/
|
|
39
|
+
export type SessionSummary = {
|
|
40
|
+
idle: number;
|
|
41
|
+
working: number;
|
|
42
|
+
attention: number;
|
|
43
|
+
offline: number;
|
|
44
|
+
total: number;
|
|
45
|
+
};
|
|
46
|
+
export declare function summarizeSessions(sessions: Array<{
|
|
47
|
+
status?: unknown;
|
|
48
|
+
}>): SessionSummary;
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
export interface StaleSocketProbes {
|
|
2
|
+
/** 读 /proc/net/unix 全文;读不到就 throw(调用方按 fail-closed 处理)。 */
|
|
3
|
+
procNetUnix(): string;
|
|
4
|
+
/** 路径不存在返回 null。 */
|
|
5
|
+
lstat(path: string): {
|
|
6
|
+
dev: number;
|
|
7
|
+
ino: number;
|
|
8
|
+
uid: number;
|
|
9
|
+
isSocket: boolean;
|
|
10
|
+
} | null;
|
|
11
|
+
unlink(path: string): void;
|
|
12
|
+
/** 当前进程 uid —— 只回收自己拥有的 socket。 */
|
|
13
|
+
currentUid(): number;
|
|
14
|
+
}
|
|
15
|
+
export interface ReapScope {
|
|
16
|
+
/**
|
|
17
|
+
* 只允许回收这个目录**之下**的路径。
|
|
18
|
+
* 🔴 这一格防的不是文件系统竞态,是**被污染的 identity**:socket 路径来自
|
|
19
|
+
* profile,如果 profile 被写坏成 `/run/systemd/private` 之类,前面所有
|
|
20
|
+
* "无监听者"检查都会照常通过,然后 unlink 掉一个不属于这个节点的东西。
|
|
21
|
+
* 删除不可逆,所以范围校验必须在**所有**其它检查之前。
|
|
22
|
+
*/
|
|
23
|
+
allowedRoot: string;
|
|
24
|
+
}
|
|
25
|
+
export type ReapOutcome =
|
|
26
|
+
/** 路径已经不在了 —— 正常的成功拆卸,无事可做。 */
|
|
27
|
+
{
|
|
28
|
+
kind: "absent";
|
|
29
|
+
}
|
|
30
|
+
/** 确认无人引用,已删除。 */
|
|
31
|
+
| {
|
|
32
|
+
kind: "removed";
|
|
33
|
+
}
|
|
34
|
+
/** /proc/net/unix 里仍能找到这个路径 ⇒ 有人在用,**不删**,调用方应判红。 */
|
|
35
|
+
| {
|
|
36
|
+
kind: "in-use";
|
|
37
|
+
}
|
|
38
|
+
/** /proc/net/unix 读不到 ⇒ fail-closed,不删。 */
|
|
39
|
+
| {
|
|
40
|
+
kind: "unreadable";
|
|
41
|
+
detail: string;
|
|
42
|
+
}
|
|
43
|
+
/** 检查与删除之间文件身份变了(dev/ino/uid),或已不是 socket ⇒ 不删。 */
|
|
44
|
+
| {
|
|
45
|
+
kind: "changed";
|
|
46
|
+
}
|
|
47
|
+
/** 路径不在该节点自己的 runtime 目录之下 ⇒ 一律不删。 */
|
|
48
|
+
| {
|
|
49
|
+
kind: "out-of-scope";
|
|
50
|
+
detail: string;
|
|
51
|
+
};
|
|
52
|
+
/**
|
|
53
|
+
* `/proc/net/unix` 的每一行以路径结尾(没有绑定路径的行就没有这一列)。
|
|
54
|
+
* 这里只问「这个路径出现过没有」,不解释 flags/type/state。
|
|
55
|
+
*/
|
|
56
|
+
export declare function unixSocketPathInUse(procNetUnix: string, path: string): boolean;
|
|
57
|
+
/**
|
|
58
|
+
* 属主进程**已被证明消失之后**,回收一个陈旧的 socket 路径名。
|
|
59
|
+
* 任何一种不确定都不删 —— 删文件不可逆,而留下一个 socket 只是让 stop 判红,
|
|
60
|
+
* 那正是本函数之前的行为。
|
|
61
|
+
*/
|
|
62
|
+
export declare function reapStaleSocket(path: string, probes: StaleSocketProbes, scope: ReapScope): ReapOutcome;
|
|
63
|
+
/**
|
|
64
|
+
* 从「本次 stop 看到的残留路径」里挑出**允许回收**的那些。
|
|
65
|
+
*
|
|
66
|
+
* 🔴 判据是「与重新算出来的规范路径**完全相等**」,不是前缀、不是包含。
|
|
67
|
+
* profile 里存的 socket 路径是**被写坏就会跟着坏**的数据;
|
|
68
|
+
* grokCopresenceSocketPaths 是纯函数,同样的 nodeId + home 永远算出同一个值。
|
|
69
|
+
* 所以这里不问「这条路径看起来对不对」,只问「它是不是我自己算出来的那两个之一」。
|
|
70
|
+
* ——一个被污染的 profile 因此一条都带不进来。
|
|
71
|
+
*/
|
|
72
|
+
export declare function planReapableSockets(canonical: {
|
|
73
|
+
leaderSocket: string;
|
|
74
|
+
attachSocket: string;
|
|
75
|
+
}, residualPaths: readonly (string | undefined)[]): string[];
|
|
76
|
+
export interface CanonicalSocketProfile {
|
|
77
|
+
node_id?: string;
|
|
78
|
+
grokLeaderSocket?: string;
|
|
79
|
+
grokAttachSocket?: string;
|
|
80
|
+
}
|
|
81
|
+
export type CanonicalSocketsOutcome = {
|
|
82
|
+
kind: "ok";
|
|
83
|
+
leaderSocket: string;
|
|
84
|
+
attachSocket: string;
|
|
85
|
+
}
|
|
86
|
+
/** profile 里没有 node_id —— 算不出来,不动手。 */
|
|
87
|
+
| {
|
|
88
|
+
kind: "no-node-id";
|
|
89
|
+
}
|
|
90
|
+
/** 重新算出来的与 profile 存的不一致 —— profile 被写坏、HOME 变了、或**调用方喂错了 id**。 */
|
|
91
|
+
| {
|
|
92
|
+
kind: "mismatch";
|
|
93
|
+
recomputedLeader: string;
|
|
94
|
+
storedLeader: string;
|
|
95
|
+
}
|
|
96
|
+
/** 路径算不出来(grokCopresenceSocketPaths 抛错)—— 不动手,但也不该把 stop 整个弄失败。 */
|
|
97
|
+
| {
|
|
98
|
+
kind: "uncomputable";
|
|
99
|
+
detail: string;
|
|
100
|
+
};
|
|
101
|
+
/**
|
|
102
|
+
* 从 profile 推出规范 socket 路径,并**与 profile 里存的那份交叉校验**。
|
|
103
|
+
*
|
|
104
|
+
* 🔴 这个交叉校验是一次真实缺陷催生的,不是补全性写的:
|
|
105
|
+
* 我第一版在 cli.ts 里写的是 `grokCopresenceSocketPaths(resolved.id)`,而
|
|
106
|
+
* `resolveNodeRef` 返回的 `id` 是**目录名(别名)**,socket 路径却是
|
|
107
|
+
* `anet node create` 用 **node_id** 算的。两者哈希不同 ⇒ 算出的路径永远对不上 ⇒
|
|
108
|
+
* 可回收集合恒为空 ⇒ **一条都回收不了,而且完全静默**(循环体一次都不进)。
|
|
109
|
+
* 12 轮验收里 4 次红、0 次回收,红话与修复前逐字相同 —— 从外面看,
|
|
110
|
+
* 「守卫拒绝了一切」和「这个修复不存在」是同一个样子。
|
|
111
|
+
*
|
|
112
|
+
* 所以判据不能只是「算一个路径出来」,必须是「算出来的和存着的对得上」。
|
|
113
|
+
* 对不上就说出来,别静默跳过。
|
|
114
|
+
*/
|
|
115
|
+
export declare function canonicalSocketsForProfile(profile: CanonicalSocketProfile, compute: (nodeId: string) => {
|
|
116
|
+
leaderSocket: string;
|
|
117
|
+
attachSocket: string;
|
|
118
|
+
}): CanonicalSocketsOutcome;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `anet daemon <sub>` 认不出子命令时,原先只走 `suggestSimilar`,而它的候选集
|
|
3
|
+
* 是 `["init","start","restart","up","list"]` —— **全是会改变状态的命令**。
|
|
4
|
+
*
|
|
5
|
+
* 🔴 实测(用仓里那个 `suggestSimilar` 本身跑的,不是推的):
|
|
6
|
+
*
|
|
7
|
+
* anet daemon rm → 建议 "up" 想删,被指去「创建 + 启动」
|
|
8
|
+
* anet daemon state → 建议 "start" 想看状态,被指去「启动」
|
|
9
|
+
* anet daemon stat → 建议 "start" 同上
|
|
10
|
+
* anet daemon stop → 建议 null (levenshtein("stop","start") = 3)
|
|
11
|
+
*
|
|
12
|
+
* 一个「你是不是想 X」的提示,把只读/销毁意图导向一个会动世界的命令,
|
|
13
|
+
* 比不给提示更贵。
|
|
14
|
+
*
|
|
15
|
+
* 而这些动作**本来就有**:daemon 就是一个 role=host_supervisor 的 agent-node,
|
|
16
|
+
* `anet daemon restart` 内部调的正是 `anet node stop` 用的那个 stopCommand()。
|
|
17
|
+
* 缺的从来不是功能,是**可发现性**。
|
|
18
|
+
*/
|
|
19
|
+
/** 这些是 `anet daemon` 自己的子命令 —— 它们**会改变状态**,所以任何
|
|
20
|
+
* 只读/销毁意图都不该被导向它们。测试用它做对照。 */
|
|
21
|
+
export declare const DAEMON_STATE_CHANGING: readonly ["init", "start", "restart", "up"];
|
|
22
|
+
export declare const PROJECT_STATE_CHANGING: readonly ["up", "restart"];
|
|
23
|
+
export declare const NODE_STATE_CHANGING: readonly ["create", "start", "restart", "resume", "rename", "loop"];
|
|
24
|
+
export declare const daemonSubcommandRedirect: (sub: unknown, name?: unknown) => string[] | null;
|
|
25
|
+
export declare const projectSubcommandRedirect: (sub: unknown, name?: unknown) => string[] | null;
|
|
26
|
+
export declare const nodeSubcommandRedirect: (sub: unknown, name?: unknown) => string[] | null;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
export type TaskTraceTransport = "mcp_http" | "sdk_mcp_proxy" | "channel_mcp_proxy";
|
|
2
|
+
export type TaskTraceStatus = "sending" | "delivered" | "failed" | "acked" | "started" | "replied" | "expired";
|
|
3
|
+
export interface TaskTraceEvent {
|
|
4
|
+
event: string;
|
|
5
|
+
from_alias: string;
|
|
6
|
+
to_alias: string;
|
|
7
|
+
task_id: string | null;
|
|
8
|
+
parent_task_id: string | null;
|
|
9
|
+
network_id: string | null;
|
|
10
|
+
transport: TaskTraceTransport;
|
|
11
|
+
status: TaskTraceStatus;
|
|
12
|
+
duration_ms: number;
|
|
13
|
+
lifecycle_tracking: "tracked" | "not_tracked";
|
|
14
|
+
error_code?: string;
|
|
15
|
+
error_message?: string;
|
|
16
|
+
}
|
|
17
|
+
export declare function safeTaskTraceError(value: unknown): string;
|
|
18
|
+
export declare function renderTaskTrace(event: TaskTraceEvent, json?: boolean): string;
|
|
19
|
+
export declare function taskTraceEvent(input: Omit<TaskTraceEvent, "event">): TaskTraceEvent;
|
|
20
|
+
export interface SendTaskTraceInput {
|
|
21
|
+
fromAlias: string;
|
|
22
|
+
toAlias: string;
|
|
23
|
+
parentTaskId: string | null;
|
|
24
|
+
networkId: string | null;
|
|
25
|
+
transport: TaskTraceTransport;
|
|
26
|
+
lifecycleTracking: "tracked" | "not_tracked";
|
|
27
|
+
}
|
|
28
|
+
export interface SendTaskTraceDependencies {
|
|
29
|
+
send: () => Promise<any>;
|
|
30
|
+
log: (line: string) => void;
|
|
31
|
+
now?: () => number;
|
|
32
|
+
}
|
|
33
|
+
export declare function sendTaskWithTrace(input: SendTaskTraceInput, dependencies: SendTaskTraceDependencies): Promise<any>;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export type TmuxSession = {
|
|
2
|
+
id: string;
|
|
3
|
+
name: string;
|
|
4
|
+
};
|
|
5
|
+
export declare function parseTmuxSessions(output: string): TmuxSession[];
|
|
6
|
+
/** Resolve by exact decoded session name, then attach by tmux's opaque ID.
|
|
7
|
+
* This avoids tmux target prefix matching and works for Unicode names. */
|
|
8
|
+
export declare function findExactTmuxSession(output: string, expectedName: string): TmuxSession | null;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/** Lowest tmux version whose `new-session` understands `-e KEY=VALUE`. */
|
|
2
|
+
export declare const MIN_TMUX_MAJOR = 3;
|
|
3
|
+
export declare const MIN_TMUX_MINOR = 2;
|
|
4
|
+
export interface TmuxVersion {
|
|
5
|
+
major: number;
|
|
6
|
+
minor: number;
|
|
7
|
+
/** Trailing letter suffix, e.g. the "a" of "3.0a". Not used for ordering. */
|
|
8
|
+
suffix: string;
|
|
9
|
+
raw: string;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Parse the output of `tmux -V`, e.g.:
|
|
13
|
+
* "tmux 3.2a" → { major: 3, minor: 2, suffix: "a" }
|
|
14
|
+
* "tmux 3.0a" → { major: 3, minor: 0, suffix: "a" }
|
|
15
|
+
* "tmux 3.4" → { major: 3, minor: 4, suffix: "" }
|
|
16
|
+
* "tmux next-3.4" → { major: 3, minor: 4, suffix: "" }
|
|
17
|
+
* "tmux 2.9" → { major: 2, minor: 9, suffix: "" }
|
|
18
|
+
*
|
|
19
|
+
* Returns null when no version can be extracted (unknown build, empty
|
|
20
|
+
* output, `tmux master` with no numbers). Callers must treat null as
|
|
21
|
+
* "unknown" and NOT as "too old" — refusing to start on an unparseable
|
|
22
|
+
* version string would break hosts whose tmux is perfectly capable.
|
|
23
|
+
*/
|
|
24
|
+
export declare function parseTmuxVersion(raw: string): TmuxVersion | null;
|
|
25
|
+
/**
|
|
26
|
+
* True when this version's `new-session` supports `-e KEY=VALUE` (>= 3.2).
|
|
27
|
+
* Note 3.0a / 3.1c sort BELOW 3.2 — the letter suffix is a patch marker,
|
|
28
|
+
* never a minor bump, so it must not participate in the comparison.
|
|
29
|
+
*/
|
|
30
|
+
export declare function tmuxSupportsSessionEnv(v: TmuxVersion): boolean;
|
|
31
|
+
export type TmuxCapabilityVerdict = {
|
|
32
|
+
kind: "ok";
|
|
33
|
+
version: TmuxVersion;
|
|
34
|
+
} | {
|
|
35
|
+
kind: "unknown";
|
|
36
|
+
detail: string;
|
|
37
|
+
} | {
|
|
38
|
+
kind: "too_old";
|
|
39
|
+
version: TmuxVersion;
|
|
40
|
+
detail: string;
|
|
41
|
+
remedy: string[];
|
|
42
|
+
} | {
|
|
43
|
+
kind: "missing";
|
|
44
|
+
detail: string;
|
|
45
|
+
remedy: string[];
|
|
46
|
+
};
|
|
47
|
+
/**
|
|
48
|
+
* Pure decision function — `runVersionCmd` returns `tmux -V` output, or
|
|
49
|
+
* throws if tmux is absent/unrunnable. Split from the printing/exiting
|
|
50
|
+
* wrapper so tests drive every branch without a tmux binary.
|
|
51
|
+
*/
|
|
52
|
+
export declare function checkTmuxCapability(runVersionCmd: () => string): TmuxCapabilityVerdict;
|
|
53
|
+
/**
|
|
54
|
+
* cli.ts wrapper: run the check, print an actionable message, and exit
|
|
55
|
+
* non-zero when tmux cannot carry the marker. `unknown` is deliberately
|
|
56
|
+
* permissive — we log and continue.
|
|
57
|
+
*/
|
|
58
|
+
export declare function assertTmuxSupportsSessionEnv(runVersionCmd: () => string, log: (msg: string) => void, fail: (msg: string) => never): void;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Exact-match tmux target for a session name.
|
|
3
|
+
*
|
|
4
|
+
* tmux treats a leading `=` as "this exact name, no prefix matching". Names are
|
|
5
|
+
* passed to tmux as argv entries, never through a shell, so no quoting belongs
|
|
6
|
+
* here — callers that build a copy-pasteable command for a human should shell-
|
|
7
|
+
* quote the result themselves.
|
|
8
|
+
*/
|
|
9
|
+
export declare function exactSession(name: string): string;
|
|
10
|
+
/**
|
|
11
|
+
* True when this target is already pinned to an exact session.
|
|
12
|
+
*
|
|
13
|
+
* Applying the prefix twice would look for a session literally named `=x`.
|
|
14
|
+
*/
|
|
15
|
+
export declare function isExactTarget(target: string): boolean;
|
|
16
|
+
/** Idempotent form, for call sites that may receive either shape. */
|
|
17
|
+
export declare function ensureExactSession(nameOrTarget: string): string;
|
|
18
|
+
/** One row of `tmux list-panes -a -F '#{session_name}\t#{window_index}.#{pane_index}'`. */
|
|
19
|
+
export interface PaneRow {
|
|
20
|
+
session: string;
|
|
21
|
+
/** `window.pane`, e.g. `0.0`. */
|
|
22
|
+
coord: string;
|
|
23
|
+
}
|
|
24
|
+
export declare function parsePaneRows(listOutput: string): PaneRow[];
|
|
25
|
+
/**
|
|
26
|
+
* Pane target for a session, or null when that exact session has no pane.
|
|
27
|
+
*
|
|
28
|
+
* Matching is exact string equality on the session name — the whole point is to
|
|
29
|
+
* not hand tmux a name it might prefix-match, and to not hand it a `=` form it
|
|
30
|
+
* cannot resolve for non-ASCII names.
|
|
31
|
+
*/
|
|
32
|
+
export declare function paneTargetFor(listOutput: string, sessionName: string): string | null;
|
|
33
|
+
/** The format string the two functions above expect. */
|
|
34
|
+
export declare const PANE_LIST_FORMAT = "#{session_name}::ANET_PANE::#{window_index}.#{pane_index}";
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/** A prompt the watcher knows how to answer, or null. */
|
|
2
|
+
export type PanePrompt = "dev-channels" | "folder-trust";
|
|
3
|
+
/**
|
|
4
|
+
* Which known prompt (if any) the pane is currently blocking on.
|
|
5
|
+
*
|
|
6
|
+
* Dev-channels is checked FIRST, even though it appears second in time. The two
|
|
7
|
+
* prompts are sequential — trust, then channels — so a capture showing both
|
|
8
|
+
* means the trust prompt is already answered and only its text is still sitting
|
|
9
|
+
* in the pane. Classifying that as "folder-trust" would make a watcher that has
|
|
10
|
+
* already answered trust ignore the prompt it was waiting for, and the node
|
|
11
|
+
* would hang exactly as if the fix had never been made. Preferring the later
|
|
12
|
+
* prompt keeps a stale line of scrollback from outranking the live prompt.
|
|
13
|
+
*/
|
|
14
|
+
export declare function classifyPanePrompt(pane: string): PanePrompt | null;
|
|
15
|
+
/**
|
|
16
|
+
* Best-effort one-line explanation of why a detached start died, taken from the
|
|
17
|
+
* dead pane's own output.
|
|
18
|
+
*
|
|
19
|
+
* Returns null when the pane holds nothing that looks like a refusal — the
|
|
20
|
+
* caller must then fall back to a generic message rather than inventing one.
|
|
21
|
+
*/
|
|
22
|
+
export declare function extractStartFailureReason(pane: string): string | null;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export type TokenCreateNameResult = {
|
|
2
|
+
ok: true;
|
|
3
|
+
name: string;
|
|
4
|
+
} | {
|
|
5
|
+
ok: false;
|
|
6
|
+
error: string;
|
|
7
|
+
};
|
|
8
|
+
/** Parse only `anet token create` operands.
|
|
9
|
+
*
|
|
10
|
+
* The legacy positional form stays supported, while flag parsing is strict so
|
|
11
|
+
* a typo cannot become the name of a newly issued credential.
|
|
12
|
+
*/
|
|
13
|
+
export declare function parseTokenCreateName(argv: readonly string[]): TokenCreateNameResult;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export declare const CLAUDE_KNOWN_TOOLS: readonly string[];
|
|
2
|
+
type Runtime = string;
|
|
3
|
+
/** Parse the comma-joined --tools string, validate each token, return the
|
|
4
|
+
* trimmed list. Runtime-scoped:
|
|
5
|
+
*
|
|
6
|
+
* Claude-lineage → each token must be in CLAUDE_KNOWN_TOOLS OR match
|
|
7
|
+
* the MCP pattern (mcp__<server>__<tool>).
|
|
8
|
+
* Other runtimes → only the basic per-token format check runs, so grok /
|
|
9
|
+
* codex / opencode tools flow through unchanged and get
|
|
10
|
+
* validated by their own downstream layers.
|
|
11
|
+
*
|
|
12
|
+
* Throws on the first offense with a message naming the bad token and,
|
|
13
|
+
* for Claude-side violations, the expected set. Never returns a
|
|
14
|
+
* partially-cleaned list — a typo must surface, not silently reshape the
|
|
15
|
+
* persisted profile.
|
|
16
|
+
*/
|
|
17
|
+
export declare function parseAndValidateTools(raw: string, runtime: Runtime): string[];
|
|
18
|
+
/** Minimal --model validation: non-empty after trim, no whitespace inside.
|
|
19
|
+
*
|
|
20
|
+
* We do NOT enforce a known-model allowlist — models are vendor-defined,
|
|
21
|
+
* evolve independently, and a strict list would break the first time
|
|
22
|
+
* MiniMax/DeepSeek/GLM/etc. ships a new variant. This catches the obvious
|
|
23
|
+
* user-side typos (`--model " claude-3 " `, `--model ""`) without
|
|
24
|
+
* over-restricting legitimate values. Vendor-side model resolution
|
|
25
|
+
* (defaultCodexModelForRuntime etc.) already validates its own contract.
|
|
26
|
+
*/
|
|
27
|
+
export declare function validateModel(raw: string): string;
|
|
28
|
+
export {};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export interface PathModeFacts {
|
|
2
|
+
/** Owner uid of the path. */
|
|
3
|
+
uid: number;
|
|
4
|
+
/** Permission bits (st_mode & 0o777). */
|
|
5
|
+
mode: number;
|
|
6
|
+
/** uid of the process doing the check. */
|
|
7
|
+
processUid: number;
|
|
8
|
+
}
|
|
9
|
+
export type UnsafePathReason = "owner" | "group-writable" | "world-writable" | null;
|
|
10
|
+
/** Which condition makes this path unsafe to execute from, if any. */
|
|
11
|
+
export declare function classifyUnsafePath(facts: PathModeFacts): UnsafePathReason;
|
|
12
|
+
/**
|
|
13
|
+
* Operator-facing explanation. Names the path, the offending bits, and the
|
|
14
|
+
* command that fixes it — a message that says only "unsafe" leaves the reader
|
|
15
|
+
* guessing between four different conditions.
|
|
16
|
+
*/
|
|
17
|
+
export declare function describeUnsafePath(path: string, facts: PathModeFacts): string;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { type ExecFileSyncOptions, type ExecFileSyncOptionsWithStringEncoding, type SpawnOptions } from "child_process";
|
|
2
|
+
/** Windows needs a command interpreter to run a .cmd; POSIX runs the file. */
|
|
3
|
+
export declare function launcherNeedsShell(platform?: NodeJS.Platform): boolean;
|
|
4
|
+
/**
|
|
5
|
+
* Quote one argument for `cmd.exe /c`.
|
|
6
|
+
*
|
|
7
|
+
* cmd's rules are not the shell's: a double quote is escaped by doubling it,
|
|
8
|
+
* and the metacharacters below must be quoted or cmd will act on them. Anything
|
|
9
|
+
* safe is left bare, so the common case stays readable in a process listing.
|
|
10
|
+
*/
|
|
11
|
+
export declare function quoteForCmd(arg: string): string;
|
|
12
|
+
/** The argv to hand to execFile/spawn so `cmd args…` runs on this platform. */
|
|
13
|
+
export declare function launcherArgv(cmd: string, args: readonly string[], platform?: NodeJS.Platform, comspec?: string | undefined): {
|
|
14
|
+
file: string;
|
|
15
|
+
argv: string[];
|
|
16
|
+
};
|
|
17
|
+
export declare function runLauncherSync(cmd: string, args: readonly string[], options: ExecFileSyncOptionsWithStringEncoding): string;
|
|
18
|
+
export declare function runLauncherSync(cmd: string, args: readonly string[], options?: ExecFileSyncOptions): Buffer;
|
|
19
|
+
/** spawn for a launcher, correct on Windows. */
|
|
20
|
+
export declare function spawnLauncher(cmd: string, args: readonly string[], options?: SpawnOptions): import("node:child_process").ChildProcess;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
export type WindowsCopresenceRole = "appsrv" | "bridge";
|
|
2
|
+
export interface WindowsManagedProcess {
|
|
3
|
+
role: WindowsCopresenceRole;
|
|
4
|
+
pid: number;
|
|
5
|
+
creationDate: string;
|
|
6
|
+
logPath: string;
|
|
7
|
+
}
|
|
8
|
+
export interface WindowsCopresenceRecord {
|
|
9
|
+
version: 1 | 2;
|
|
10
|
+
nodeId: string;
|
|
11
|
+
createdAt: string;
|
|
12
|
+
marker?: string;
|
|
13
|
+
processes: WindowsManagedProcess[];
|
|
14
|
+
}
|
|
15
|
+
export declare function windowsCopresenceRecordPath(nodesDir: string, nodeId: string): string;
|
|
16
|
+
export declare function windowsCopresenceLogPath(nodesDir: string, nodeId: string, role: WindowsCopresenceRole): string;
|
|
17
|
+
export declare function openPrivateAppendLog(path: string): number;
|
|
18
|
+
/** Protect credential-bearing state with native Windows ACLs. */
|
|
19
|
+
export declare function ensureWindowsPrivateDirectory(path: string): void;
|
|
20
|
+
export declare function closeLog(fd: number): void;
|
|
21
|
+
export type CreationDateProbe = (pid: number) => string | null;
|
|
22
|
+
/** Uses CIM instead of locale-dependent tasklist output. */
|
|
23
|
+
export declare function probeWindowsCreationDate(pid: number): string | null;
|
|
24
|
+
/**
|
|
25
|
+
* Attribute an ESTABLISHED loopback connection to the launched TUI process
|
|
26
|
+
* tree. This is deliberately stronger than counting listeners/connections:
|
|
27
|
+
* an unrelated local client cannot satisfy it.
|
|
28
|
+
*/
|
|
29
|
+
export declare function probeWindowsOwnedLoopbackConnection(rootPid: number, expectedCreationDate: string, port: number, runPowerShell?: (script: string) => string): boolean;
|
|
30
|
+
/**
|
|
31
|
+
* #1342 —— 只在健康检查**即将失败**时跑一次,用来回答一个此前没人量过的问题:
|
|
32
|
+
* 那 10.5 秒到底花在 **PowerShell 启动**上,还是花在 `Get-CimInstance Win32_Process`
|
|
33
|
+
* 这个全表查询上?
|
|
34
|
+
*
|
|
35
|
+
* 实测背景(由 #1628/#1637 加的 probeMs 量到,2026-08-31):
|
|
36
|
+
* probes=1 waited=10897ms probeMsLast=10490 ← 单次探测吃掉 96% 的预算
|
|
37
|
+
* 而 #1636 把全表枚举提到循环外之后这个数**没有变小**(9963 → 10490),
|
|
38
|
+
* 说明成本不在"重复枚举",而在那一次调用本身。但"那一次调用"包含两段:
|
|
39
|
+
* 起一个 powershell 进程,和在里面跑 CIM 查询。**这两段要查的东西完全不同** ——
|
|
40
|
+
* 前者是 runner/镜像的问题,后者是查询写法的问题。
|
|
41
|
+
*
|
|
42
|
+
* 🔴 这里跑的是一个**什么都不做**的脚本(`'x'`),所以它测到的就是启动那一段的下界。
|
|
43
|
+
* 只在失败路径调用一次,不进探测循环 —— 不给正常路径增加任何成本,
|
|
44
|
+
* 也**不可能**改变探测的返回值。
|
|
45
|
+
*
|
|
46
|
+
* 拿不到就返回 null(未知),不返回 0 —— 0 会被读成「启动不花时间」。
|
|
47
|
+
*/
|
|
48
|
+
export declare function measurePowerShellStartupMs(): number | null;
|
|
49
|
+
export declare function writeWindowsCopresenceRecord(nodesDir: string, nodeId: string, processes: WindowsManagedProcess[], marker?: string): void;
|
|
50
|
+
export declare function readWindowsCopresenceRecord(nodesDir: string, nodeId: string): WindowsCopresenceRecord | null;
|
|
51
|
+
export interface WindowsStopDecision {
|
|
52
|
+
safe: WindowsManagedProcess[];
|
|
53
|
+
refused: Array<{
|
|
54
|
+
process: WindowsManagedProcess;
|
|
55
|
+
reason: "missing" | "pid-reused";
|
|
56
|
+
}>;
|
|
57
|
+
}
|
|
58
|
+
/** PID alone is never authority: Windows reuses PIDs, so CreationDate must match. */
|
|
59
|
+
export declare function decideWindowsManagedStop(record: WindowsCopresenceRecord, probe: CreationDateProbe): WindowsStopDecision;
|
|
60
|
+
export declare function taskkillWindowsProcessTree(pid: number): void;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sleep2agi/agent-network",
|
|
3
|
-
"version": "2.3.0-preview.
|
|
4
|
-
"description": "AI Agent Network CLI
|
|
3
|
+
"version": "2.3.0-preview.80",
|
|
4
|
+
"description": "AI Agent Network CLI — Local-first multi-agent orchestration across 6 runtimes (Claude Code CLI / Claude Agent SDK / Codex SDK / Codex app-server / Grok Build ACP / OpenCode CLI) and 8+ LLM providers. Apache 2.0.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/src/client.js",
|
|
7
7
|
"types": "dist/client.d.ts",
|
|
@@ -9,10 +9,14 @@
|
|
|
9
9
|
".": {
|
|
10
10
|
"import": "./dist/src/client.js",
|
|
11
11
|
"types": "./dist/client.d.ts"
|
|
12
|
+
},
|
|
13
|
+
"./daemon-capability-display": {
|
|
14
|
+
"import": "./dist/src/daemon-capability-display.js",
|
|
15
|
+
"types": "./dist/src/daemon-capability-display.d.ts"
|
|
12
16
|
}
|
|
13
17
|
},
|
|
14
18
|
"bin": {
|
|
15
|
-
"anet": "dist/bin/
|
|
19
|
+
"anet": "dist/bin/anet.cjs"
|
|
16
20
|
},
|
|
17
21
|
"files": [
|
|
18
22
|
"dist"
|
|
@@ -20,7 +24,7 @@
|
|
|
20
24
|
"scripts": {
|
|
21
25
|
"typecheck": "tsc --noEmit",
|
|
22
26
|
"test:feishu-bridge": "bun tests/feishu-bridge-ackplaceholder.test.ts",
|
|
23
|
-
"build": "bun build src/client.ts --outdir dist/src --target node --minify && bun build bin/cli.ts --outdir dist/bin --target node --minify --external @sleep2agi/commhub-server --external bun:sqlite --external '../../server/*' && bun build src/node-server.ts --outdir dist/src --target node --minify
|
|
27
|
+
"build": "bun build src/client.ts --outdir dist/src --target node --minify && bun build src/daemon-capability-display.ts --outdir dist/src --target browser --minify && bun build bin/cli.ts --outdir dist/bin --target node --minify --external @sleep2agi/commhub-server --external bun:sqlite --external '../../server/*' && bun build src/node-server.ts --outdir dist/src --target node --minify && bun build src/im/feishu/worker.ts --outdir dist/src/im/feishu --target node --minify --external @larksuiteoapi/node-sdk && tsc --emitDeclarationOnly --declaration --outDir dist && npx javascript-obfuscator dist/bin/cli.js --output dist/bin/cli.js --compact true --string-array true --string-array-encoding base64 && npx javascript-obfuscator dist/src/client.js --output dist/src/client.js --compact true --string-array true && npx javascript-obfuscator dist/src/node-server.js --output dist/src/node-server.js --compact true --string-array true && cp bin/anet.cjs dist/bin/anet.cjs",
|
|
24
28
|
"prepublishOnly": "npm run build"
|
|
25
29
|
},
|
|
26
30
|
"keywords": [
|
|
@@ -54,7 +58,8 @@
|
|
|
54
58
|
"directory": "agent-network"
|
|
55
59
|
},
|
|
56
60
|
"publishConfig": {
|
|
57
|
-
"access": "public"
|
|
61
|
+
"access": "public",
|
|
62
|
+
"tag": "preview"
|
|
58
63
|
},
|
|
59
64
|
"bugs": {
|
|
60
65
|
"url": "https://github.com/sleep2agi/agent-network/issues"
|