@sleep2agi/agent-network 2.3.0-preview.17 → 2.3.0-preview.170

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 (193) hide show
  1. package/README.md +35 -324
  2. package/dist/bin/anet.cjs +101 -0
  3. package/dist/bin/cli.d.ts +1 -0
  4. package/dist/bin/cli.js +20 -1
  5. package/dist/bin/goal-wake-log-render.d.ts +31 -0
  6. package/dist/src/active-network-task.d.ts +28 -0
  7. package/dist/src/batch-workdir.d.ts +9 -0
  8. package/dist/src/bootstrap-password-db.d.ts +13 -0
  9. package/dist/src/channel-attachments.d.ts +29 -0
  10. package/dist/src/channel-inbox-wake.d.ts +21 -0
  11. package/dist/src/channel-meta.d.ts +10 -0
  12. package/dist/src/channel-peer-reply.d.ts +41 -0
  13. package/dist/src/channel-task-trace.d.ts +14 -0
  14. package/dist/src/claude-vendor-env.d.ts +28 -0
  15. package/dist/src/cli-args.d.ts +8 -0
  16. package/dist/src/cli-auth-session.d.ts +47 -0
  17. package/dist/src/cli-errors.d.ts +41 -0
  18. package/dist/src/cli-exit.d.ts +11 -0
  19. package/dist/src/cli-help.d.ts +10 -0
  20. package/dist/src/cli-version-display.d.ts +16 -0
  21. package/dist/src/client-task-trace.d.ts +9 -0
  22. package/dist/src/client.js +1 -1
  23. package/dist/src/codex-adopt.d.ts +46 -0
  24. package/dist/src/codex-auth-fingerprint.d.ts +211 -0
  25. package/dist/src/codex-bin-pin.d.ts +23 -0
  26. package/dist/src/codex-commhub-mcp.d.ts +22 -0
  27. package/dist/src/codex-copresence-bridge-log.d.ts +44 -0
  28. package/dist/src/codex-copresence-env.d.ts +5 -0
  29. package/dist/src/codex-copresence-login-gate.d.ts +18 -0
  30. package/dist/src/codex-copresence-model.d.ts +23 -0
  31. package/dist/src/codex-copresence-preflight.d.ts +78 -0
  32. package/dist/src/codex-copresence-profile.d.ts +126 -0
  33. package/dist/src/codex-copresence-recovery.d.ts +70 -0
  34. package/dist/src/codex-copresence-resume-timeout.d.ts +28 -0
  35. package/dist/src/codex-copresence-rollout-guard.d.ts +36 -0
  36. package/dist/src/codex-copresence-rpc.d.ts +17 -0
  37. package/dist/src/codex-copresence-thread.d.ts +13 -0
  38. package/dist/src/codex-copresence-yolo.d.ts +16 -0
  39. package/dist/src/codex-external-appserver.d.ts +130 -0
  40. package/dist/src/codex-fork-recovery.d.ts +52 -0
  41. package/dist/src/codex-home-enforce.d.ts +88 -0
  42. package/dist/src/codex-lifecycle-account.d.ts +104 -0
  43. package/dist/src/codex-lifecycle-canary.d.ts +20 -0
  44. package/dist/src/codex-lifecycle-facts.d.ts +53 -0
  45. package/dist/src/codex-lifecycle-fork.d.ts +91 -0
  46. package/dist/src/codex-lifecycle-preflight.d.ts +79 -0
  47. package/dist/src/codex-lifecycle-receipt.d.ts +53 -0
  48. package/dist/src/codex-lifecycle-restart.d.ts +88 -0
  49. package/dist/src/codex-login-share-guard.d.ts +146 -0
  50. package/dist/src/codex-menu.d.ts +99 -0
  51. package/dist/src/codex-model-default.d.ts +6 -0
  52. package/dist/src/codex-node-login.d.ts +98 -0
  53. package/dist/src/codex-pending-thread-restart.d.ts +69 -0
  54. package/dist/src/codex-reasoning-effort.d.ts +17 -0
  55. package/dist/src/codex-recovery-lease.d.ts +39 -0
  56. package/dist/src/codex-recovery-resource-gate.d.ts +15 -0
  57. package/dist/src/codex-resume.d.ts +89 -0
  58. package/dist/src/codex-rollout-history-guard.d.ts +84 -0
  59. package/dist/src/codex-tui-client-health.d.ts +30 -0
  60. package/dist/src/commhub-response.d.ts +1 -0
  61. package/dist/src/controlled-upload.d.ts +83 -0
  62. package/dist/src/copresence-deps.d.ts +22 -0
  63. package/dist/src/copresence-identity.d.ts +363 -0
  64. package/dist/src/copresence-startup-diagnosis.d.ts +17 -0
  65. package/dist/src/daemon-adopt.d.ts +14 -0
  66. package/dist/src/daemon-anet-bin.d.ts +32 -0
  67. package/dist/src/daemon-capability-display.d.ts +110 -0
  68. package/dist/src/daemon-capability-display.js +21 -0
  69. package/dist/src/daemon-codex-inventory.d.ts +65 -0
  70. package/dist/src/daemon-inherited-env.d.ts +9 -0
  71. package/dist/src/daemon-provider-account-custody.d.ts +28 -0
  72. package/dist/src/daemon-provider-account-readback.d.ts +3 -0
  73. package/dist/src/daemon-provider-application.d.ts +36 -0
  74. package/dist/src/daemon-provider-apply-command.d.ts +9 -0
  75. package/dist/src/daemon-provider-collect.d.ts +29 -0
  76. package/dist/src/daemon-provider-command.d.ts +7 -0
  77. package/dist/src/daemon-provider-initialize.d.ts +27 -0
  78. package/dist/src/daemon-provider-lifecycle.d.ts +4 -0
  79. package/dist/src/daemon-provider-store.d.ts +104 -0
  80. package/dist/src/daemon-runtime-path-preflight.d.ts +22 -0
  81. package/dist/src/daemon-runtime-staleness.d.ts +13 -0
  82. package/dist/src/dashboard-managed-process.d.ts +35 -0
  83. package/dist/src/display-width.d.ts +27 -0
  84. package/dist/src/doctor-node-count.d.ts +28 -0
  85. package/dist/src/environ-alias.d.ts +14 -0
  86. package/dist/src/grok-attach-client.d.ts +129 -0
  87. package/dist/src/grok-build-drift.d.ts +15 -0
  88. package/dist/src/grok-copresence-disclosure.d.ts +11 -0
  89. package/dist/src/grok-copresence-orchestration.d.ts +75 -0
  90. package/dist/src/grok-copresence-profile.d.ts +65 -0
  91. package/dist/src/grok-create-mode.d.ts +19 -0
  92. package/dist/src/host-telemetry.d.ts +14 -0
  93. package/dist/src/hub-health-timeout.d.ts +4 -0
  94. package/dist/src/hub-server-version.d.ts +64 -0
  95. package/dist/src/hub-stop.d.ts +74 -0
  96. package/dist/src/hub-time-display.d.ts +20 -0
  97. package/dist/src/hub-version-skew.d.ts +19 -0
  98. package/dist/src/im/correlation-store.d.ts +34 -0
  99. package/dist/src/im/feishu/adapter.d.ts +43 -0
  100. package/dist/src/im/feishu/bridge.d.ts +78 -14
  101. package/dist/src/im/feishu/hub-upload.d.ts +1 -1
  102. package/dist/src/im/feishu/worker-lifecycle.d.ts +13 -0
  103. package/dist/src/im/feishu/worker.js +174 -161
  104. package/dist/src/inbox-drain.d.ts +20 -0
  105. package/dist/src/local-process-state.d.ts +12 -0
  106. package/dist/src/locale-diagnostic.d.ts +12 -0
  107. package/dist/src/login-client-label.d.ts +6 -0
  108. package/dist/src/ls-columns.d.ts +15 -0
  109. package/dist/src/mock-llm.d.ts +12 -0
  110. package/dist/src/node-activity-log.d.ts +4 -0
  111. package/dist/src/node-clone.d.ts +134 -0
  112. package/dist/src/node-delete-hub.d.ts +42 -0
  113. package/dist/src/node-files.d.ts +62 -0
  114. package/dist/src/node-locate.d.ts +60 -0
  115. package/dist/src/node-ls-all.d.ts +80 -0
  116. package/dist/src/node-menu.d.ts +40 -0
  117. package/dist/src/node-not-found.d.ts +1 -0
  118. package/dist/src/node-remote.d.ts +180 -0
  119. package/dist/src/node-running-guard.d.ts +9 -0
  120. package/dist/src/node-server-identity.d.ts +35 -0
  121. package/dist/src/node-server-payload.d.ts +66 -0
  122. package/dist/src/node-server-rules-file.d.ts +14 -0
  123. package/dist/src/node-server-version.d.ts +39 -0
  124. package/dist/src/node-server.js +8 -1
  125. package/dist/src/node-skills.d.ts +57 -0
  126. package/dist/src/normalize-runtime.d.ts +29 -2
  127. package/dist/src/offline-age.d.ts +29 -0
  128. package/dist/src/one-line-cell.d.ts +20 -0
  129. package/dist/src/opencode-agent-node-pair.d.ts +28 -0
  130. package/dist/src/opencode-auth-login.d.ts +43 -0
  131. package/dist/src/opencode-free-tier.d.ts +27 -0
  132. package/dist/src/opencode-generation-create.d.ts +27 -0
  133. package/dist/src/opencode-generation-record.d.ts +24 -0
  134. package/dist/src/opencode-launch-env.d.ts +13 -0
  135. package/dist/src/opencode-owner-mode.d.ts +6 -0
  136. package/dist/src/opencode-package-binary.d.ts +44 -0
  137. package/dist/src/opencode-pin.d.ts +61 -0
  138. package/dist/src/opencode-preset.d.ts +77 -0
  139. package/dist/src/opencode-runtime-binding.d.ts +30 -0
  140. package/dist/src/opencode-safe-root.d.ts +36 -0
  141. package/dist/src/opencode-smoke-env.d.ts +1 -0
  142. package/dist/src/opencode-start-mode.d.ts +8 -0
  143. package/dist/src/opencode-v2-configured-model.d.ts +34 -0
  144. package/dist/src/opencode-v2-create-align.d.ts +18 -0
  145. package/dist/src/opencode-versions.d.ts +44 -0
  146. package/dist/src/outbound-attachments.d.ts +60 -0
  147. package/dist/src/outbound-tool-names.d.ts +1 -0
  148. package/dist/src/owned-roots.d.ts +58 -0
  149. package/dist/src/owner-env-file.d.ts +2 -0
  150. package/dist/src/package-mode-preflight.d.ts +41 -0
  151. package/dist/src/posix-codex-copresence.d.ts +33 -0
  152. package/dist/src/posix-modes.d.ts +36 -0
  153. package/dist/src/primary-network.d.ts +23 -0
  154. package/dist/src/private-state.d.ts +10 -0
  155. package/dist/src/process-telemetry.d.ts +12 -0
  156. package/dist/src/profile-serialize.d.ts +1 -0
  157. package/dist/src/project-key.d.ts +1 -0
  158. package/dist/src/provider-application-contract.d.ts +11 -0
  159. package/dist/src/provider-apply.d.ts +28 -0
  160. package/dist/src/provider-presets.d.ts +76 -0
  161. package/dist/src/reply-local-links.d.ts +47 -0
  162. package/dist/src/reply-originator.d.ts +20 -0
  163. package/dist/src/resume-runtime-infer.d.ts +18 -0
  164. package/dist/src/rules-file.d.ts +53 -0
  165. package/dist/src/scoped-secrets.d.ts +33 -0
  166. package/dist/src/secret-shell-guidance.d.ts +4 -0
  167. package/dist/src/session-status-class.d.ts +48 -0
  168. package/dist/src/shared/provider-collection.d.ts +9 -0
  169. package/dist/src/shared/provider-initialization.d.ts +7 -0
  170. package/dist/src/shared/reserved-env.d.ts +3 -0
  171. package/dist/src/shared/scoped-secret-contract.d.ts +1 -0
  172. package/dist/src/shared/scoped-secret-env.d.ts +2 -0
  173. package/dist/src/sibling-agent-node.d.ts +23 -0
  174. package/dist/src/stale-socket.d.ts +118 -0
  175. package/dist/src/standalone-bin.d.ts +101 -0
  176. package/dist/src/standalone-build-stamp.d.ts +33 -0
  177. package/dist/src/start-resource-gate.d.ts +146 -0
  178. package/dist/src/stopped-receipt.d.ts +8 -0
  179. package/dist/src/subcommand-redirect.d.ts +26 -0
  180. package/dist/src/task-trace.d.ts +33 -0
  181. package/dist/src/tmux-attach.d.ts +11 -0
  182. package/dist/src/tmux-capability.d.ts +58 -0
  183. package/dist/src/tmux-exact-target.d.ts +36 -0
  184. package/dist/src/tmux-format.d.ts +20 -0
  185. package/dist/src/tmux-pane-prompt.d.ts +22 -0
  186. package/dist/src/tmux.d.ts +44 -0
  187. package/dist/src/token-cli.d.ts +13 -0
  188. package/dist/src/tool-allowlist.d.ts +28 -0
  189. package/dist/src/unsafe-package-path-reason.d.ts +31 -0
  190. package/dist/src/upgrade-channel.d.ts +31 -0
  191. package/dist/src/win-launcher.d.ts +20 -0
  192. package/dist/src/windows-codex-copresence.d.ts +60 -0
  193. package/package.json +15 -7
@@ -0,0 +1,65 @@
1
+ export declare const GROK_UNIX_SOCKET_PATH_MAX_BYTES = 100;
2
+ export declare const GROK_COPRESENCE_CAPABILITY_MARKER = "ANET_CAPABILITY_GROK_COPRESENCE_V2";
3
+ export declare const GROK_PREVIEW_RESOLVER_INHERITED_ENV_KEYS: readonly ["PATH", "TMPDIR", "TMP", "TEMP", "LANG", "LC_ALL", "LC_CTYPE", "TZ"];
4
+ export declare const GROK_AGENT_NODE_INHERITED_ENV_KEYS: readonly ["PATH", "HOME", "TMPDIR", "TMP", "TEMP", "LANG", "LC_ALL", "LC_CTYPE", "TZ", "SHELL", "USER", "LOGNAME", "TERM", "COLORTERM", "NO_COLOR"];
5
+ export declare const GROK_AGENT_NODE_OPTIONAL_ENV_KEYS: readonly ["GROK_BINARY", "GROK_HOME", "FLOCK_BINARY", "SETPRIV_BINARY", "UNSHARE_BINARY", "GROK_CLI_TIMEOUT_MS", "GROK_HANDSHAKE_TIMEOUT_MS", "LOG_LEVEL", "ANET_GOAL_TICK_MS", "COMMHUB_MAX_GOALS_PER_NODE"];
6
+ /** Exact environment for the long-lived agent-node parent of the Grok TUI. */
7
+ export declare function buildGrokAgentNodeEnv(parentEnv: NodeJS.ProcessEnv): Record<string, string>;
8
+ export declare function grokPreviewResolverConfigPaths(home: string): {
9
+ directory: string;
10
+ userConfig: string;
11
+ globalConfig: string;
12
+ };
13
+ /**
14
+ * npm rejects loading the same file as both user and global config. Prepare
15
+ * two distinct, empty, owner-only files without following a final symlink so
16
+ * the resolver cannot inherit a user's ordinary npmrc credentials.
17
+ */
18
+ export declare function prepareGrokPreviewResolverConfigs(home: string): void;
19
+ /** Exact environment for the short-lived npm resolver and capability probe. */
20
+ export declare function buildGrokPreviewResolverEnv(parentEnv: NodeJS.ProcessEnv, home: string): Record<string, string>;
21
+ /** Old headless-only agent-node builds already advertised grok-build-cli. */
22
+ export declare function agentNodeHelpSupportsGrokCopresence(help: string): boolean;
23
+ export interface GrokCopresenceProfileFields {
24
+ grokCopresence: boolean;
25
+ grokLeaderSocket?: string;
26
+ grokAttachSocket?: string;
27
+ }
28
+ export interface GrokSocketPathOptions {
29
+ cwd?: string;
30
+ home?: string;
31
+ xdgRuntimeDir?: string;
32
+ uid?: number;
33
+ platform?: NodeJS.Platform;
34
+ }
35
+ /**
36
+ * Allocate deterministic Unix socket paths without creating anything.
37
+ *
38
+ * Grok's workspace sandbox does not admit an otherwise owner-controlled
39
+ * XDG_RUNTIME_DIR such as /run/user/<uid>. Keep the primary sockets under the
40
+ * node's owner-bound state home, which the runtime already admits, and use a
41
+ * short private tmp path only when the Unix socket length limit requires it.
42
+ * The runtime owns directory creation and permissions; `anet node create`
43
+ * only persists the identity of the two sockets.
44
+ */
45
+ export declare function grokCopresenceSocketPaths(nodeId: string, options?: GrokSocketPathOptions): {
46
+ leaderSocket: string;
47
+ attachSocket: string;
48
+ };
49
+ export type GrokAttachTarget = {
50
+ ok: true;
51
+ socketPath: string;
52
+ } | {
53
+ ok: false;
54
+ reason: "not_grok_build_cli" | "headless" | "missing_attach_socket";
55
+ };
56
+ /**
57
+ * `anet grok attach` eligibility. The CLI is the only human join path;
58
+ * this is the shipped decision so tests can drive it without a TTY.
59
+ */
60
+ export declare function resolveGrokAttachTarget(input: {
61
+ runtime: string;
62
+ grokCopresence?: unknown;
63
+ grokAttachSocket?: unknown;
64
+ }): GrokAttachTarget;
65
+ export declare function grokBuildCliCreationFields(runtime: string, nodeId: string, headless?: boolean, options?: GrokSocketPathOptions): GrokCopresenceProfileFields | Record<string, never>;
@@ -0,0 +1,19 @@
1
+ /** One-line limitation list shown wherever co-presence is offered (CLI help,
2
+ * picker, create warning). Keep it one line — it is appended to menus. */
3
+ export declare const GROK_COPRESENCE_EXPERIMENTAL_NOTE_ZH = "\u5B9E\u9A8C\u6027\uFF1A\u4EBA\u5728 TUI \u8F93\u5165\u6846\u6253\u5B57\u65F6\u7F51\u7EDC\u4EFB\u52A1\u4F1A\u6392\u961F\u76F4\u5230\u8D85\u65F6\uFF1Bgrok \u987B\u9489\u5728\u5DF2\u9A8C\u8BC1\u7248\u672C\uFF08\u65B0\u7248\u4F1A\u62D2\u7EDD\u542F\u52A8\uFF09\uFF1BmacOS \u9700\u7279\u6B8A\u5904\u7406\uFF1B\u4E0D\u52A0\u8F7D .agents/skills \u6280\u80FD\u3002\u8981\u7A33\u5B9A\u63A5\u6D3B\u7528\u9ED8\u8BA4\u7684 ACP\u3002";
4
+ export declare const GROK_COPRESENCE_EXPERIMENTAL_NOTE_EN = "Experimental: network tasks queue until timeout while a human is typing in the TUI; grok must be pinned to a verified build (newer builds refuse to start); macOS needs special handling; .agents/skills skills are not loaded. For a stable node use the default ACP mode.";
5
+ export type GrokCreateModeResult = {
6
+ ok: true;
7
+ runtime: string | undefined;
8
+ copresenceRequested: boolean;
9
+ } | {
10
+ ok: false;
11
+ error: string;
12
+ };
13
+ /**
14
+ * Resolve the runtime string a NEW node is created with.
15
+ *
16
+ * Non-Grok runtimes (and an absent runtime) pass through untouched — this
17
+ * helper only decides between the two Grok lanes.
18
+ */
19
+ export declare function resolveGrokCreateRuntime(rawRuntime: string | undefined, copresence: unknown): GrokCreateModeResult;
@@ -0,0 +1,14 @@
1
+ export interface HostTelemetry {
2
+ hostname: string;
3
+ ip: string | null;
4
+ cpu_load_1min: number | null;
5
+ cpu_cores: number | null;
6
+ mem_total_gb: number | null;
7
+ mem_used_gb: number | null;
8
+ mem_avail_gb: number | null;
9
+ disk_total_gb: number | null;
10
+ disk_used_gb: number | null;
11
+ disk_avail_gb: number | null;
12
+ }
13
+ export declare function getHostTelemetry(): HostTelemetry;
14
+ export declare function _clearHostTelemetryCache(): void;
@@ -0,0 +1,4 @@
1
+ export declare const LOOPBACK_HUB_HEALTH_TIMEOUT_MS = 2000;
2
+ export declare const REMOTE_HUB_HEALTH_TIMEOUT_MS = 10000;
3
+ export declare const HUB_HEALTH_TIMEOUT_ENV = "ANET_HUB_HEALTH_TIMEOUT_MS";
4
+ export declare function hubHealthTimeoutMs(hub: string, env?: NodeJS.ProcessEnv): number;
@@ -0,0 +1,64 @@
1
+ export declare const COMMHUB_SERVER_PKG = "@sleep2agi/commhub-server";
2
+ export declare const AGENT_NETWORK_PKG = "@sleep2agi/agent-network";
3
+ export type HubReleaseChannel = "latest" | "preview";
4
+ export type HubVersionSource = "explicit" | "registry" | "cache" | "pinned-floor";
5
+ export interface DistTags {
6
+ latest?: string | null;
7
+ preview?: string | null;
8
+ }
9
+ export declare function isExactSemver(v: string | null | undefined): boolean;
10
+ /** Semver precedence. Unparseable versions sort lowest. */
11
+ export declare function compareSemver(a: string, b: string): number;
12
+ export declare function resolveHubChannel(input: {
13
+ anetVersion: string;
14
+ flag?: string | null;
15
+ anetDistTags: DistTags | null;
16
+ }): {
17
+ channel: HubReleaseChannel;
18
+ reason: string;
19
+ };
20
+ export interface HubVersionDecision {
21
+ version: string;
22
+ source: HubVersionSource;
23
+ channel: HubReleaseChannel | null;
24
+ /** true when `version` is already present in the local bun install cache. */
25
+ cached: boolean;
26
+ /** One-line, human readable "where it came from". */
27
+ origin: string;
28
+ /** Must be printed prominently (stderr). */
29
+ warnings: string[];
30
+ }
31
+ export declare function decideHubServerVersion(input: {
32
+ explicit?: string | null;
33
+ channelFlag?: string | null;
34
+ anetVersion: string;
35
+ anetDistTags: DistTags | null;
36
+ serverDistTags: DistTags | null;
37
+ floor: string;
38
+ cachedVersions: string[];
39
+ }): HubVersionDecision;
40
+ export type ExecFn = (cmd: string, args: string[]) => string;
41
+ export declare function fetchDistTags(exec: ExecFn, pkg: string): DistTags | null;
42
+ export interface CacheFs {
43
+ existsSync(p: string): boolean;
44
+ readdirSync(p: string): string[];
45
+ readFileSync(p: string): string;
46
+ }
47
+ export declare function bunInstallCacheDir(env?: NodeJS.ProcessEnv, home?: string): string;
48
+ /**
49
+ * Versions of commhub-server present in bun's install cache. Bun uses two
50
+ * layouts (`@sleep2agi/commhub-server@<ver-or-hash>@@@1/` and
51
+ * `@sleep2agi/commhub-server/<ver-or-hash>@@@1/`); prerelease parts are
52
+ * hashed in the directory name, so the version is read from package.json.
53
+ */
54
+ export declare function listCachedServerVersions(cacheDir: string, fs?: CacheFs): string[];
55
+ export declare function resolveHubServerVersion(input: {
56
+ explicit?: string | null;
57
+ channelFlag?: string | null;
58
+ anetVersion: string;
59
+ floor: string;
60
+ exec: ExecFn;
61
+ cacheDir: string;
62
+ fs?: CacheFs;
63
+ }): HubVersionDecision;
64
+ export declare function formatHubVersionBanner(d: HubVersionDecision): string;
@@ -0,0 +1,74 @@
1
+ export type ProbeName = "proc" | "ss" | "lsof" | "netstat";
2
+ /** null = 这条探针在本机跑不了(没有 /proc、没装 ss …);数组 = 跑了,这些 PID 在监听。 */
3
+ export interface SocketProbeResult {
4
+ pids: number[];
5
+ /** 端口确实被监听、但属主 PID 读不到(别的用户的进程)。 */
6
+ unresolved?: number;
7
+ }
8
+ export interface HubPidRecord {
9
+ pid: number;
10
+ port: number;
11
+ launcher_pid?: number;
12
+ started_at?: string;
13
+ }
14
+ export interface HubStopProbes {
15
+ platform: NodeJS.Platform;
16
+ socket: Partial<Record<ProbeName, (port: number) => SocketProbeResult | null>>;
17
+ readPidFile: (port: number) => HubPidRecord | null;
18
+ cmdline: (pid: number) => string | null;
19
+ alive: (pid: number) => boolean;
20
+ }
21
+ export type CandidateVerdict = "commhub" | "not-commhub" | "cmdline-unreadable";
22
+ export interface Candidate {
23
+ pid: number;
24
+ source: ProbeName | "pidfile";
25
+ cmdline: string | null;
26
+ verdict: CandidateVerdict;
27
+ }
28
+ export interface HubListenerResolution {
29
+ port: number;
30
+ /** 每条探针的结果,按尝试顺序。 */
31
+ tried: {
32
+ probe: ProbeName | "pidfile";
33
+ outcome: string;
34
+ }[];
35
+ /** 给出端口归属的那条探针;null = 本机没有一条能跑。 */
36
+ authority: ProbeName | null;
37
+ /** 端口被监听但读不到属主 PID 的个数。 */
38
+ unresolved: number;
39
+ /** 核实过是 commhub-server 的 PID —— 只有这些会被停。 */
40
+ hubPids: Candidate[];
41
+ /** 端口上的其他进程 / cmdline 读不到的进程 —— 拒绝动手。 */
42
+ refused: Candidate[];
43
+ }
44
+ export declare function probeOrder(platform: NodeJS.Platform): ProbeName[];
45
+ /** cmdline 是不是 commhub-server。只做核实,不用来挑选进程。 */
46
+ export declare function isCommhubServerCmdline(cmdline: string | null | undefined): boolean;
47
+ /** /proc/net/tcp 或 tcp6 文本 → 在 port 上 LISTEN(st=0A)的 socket inode。 */
48
+ export declare function parseProcNetTcp(text: string, port: number): string[];
49
+ /** `ss -Hltnp 'sport = :PORT'` → pids;有行却没有 users:(…) 的算 unresolved。 */
50
+ export declare function parseSsOutput(text: string, port: number): SocketProbeResult;
51
+ /** Windows `netstat -ano`:`TCP 127.0.0.1:9200 0.0.0.0:0 LISTENING 1234`。 */
52
+ export declare function parseNetstatWindows(text: string, port: number): SocketProbeResult;
53
+ /** macOS `netstat -anv -p tcp`:按表头找 pid 列;本地地址形如 `127.0.0.1.9200` / `*.9200`。 */
54
+ export declare function parseNetstatDarwin(text: string, port: number): SocketProbeResult;
55
+ export declare function resolveHubListener(port: number, probes: HubStopProbes): HubListenerResolution;
56
+ export interface StopHubDeps {
57
+ probes: HubStopProbes;
58
+ kill: (pid: number, signal: "SIGTERM" | "SIGKILL") => void;
59
+ sleep: (ms: number) => Promise<void>;
60
+ /** /health 是否 ok —— 与探针无关的独立判据。 */
61
+ healthy: () => Promise<boolean>;
62
+ log: (line: string) => void;
63
+ error: (line: string) => void;
64
+ graceMs?: number;
65
+ }
66
+ export interface StopHubResult {
67
+ code: 0 | 1;
68
+ killed: number[];
69
+ refused: Candidate[];
70
+ }
71
+ export declare function stopHub(port: number, d: StopHubDeps): Promise<StopHubResult>;
72
+ export declare function procNetListeners(port: number, procRoot?: string): SocketProbeResult | null;
73
+ export declare function defaultHubStopProbes(readPidFile: (port: number) => HubPidRecord | null, platform?: NodeJS.Platform): HubStopProbes;
74
+ export declare function readCmdline(pid: number, platform?: NodeJS.Platform): string | null;
@@ -0,0 +1,20 @@
1
+ /**
2
+ * 把 hub 的 TEXT 时间戳显示给人看。
3
+ *
4
+ * 🔴 原先是**原样打印**:
5
+ *
6
+ * updated: 2026-08-31 00:20:11
7
+ *
8
+ * 那是 UTC,**没有任何时区标记**。同一时刻本地是 `08:22:41 CST` ——
9
+ * 于是一个 **2 分钟前**刚心跳过的节点,在 UTC+8 的用户眼里像是 **8 小时前**的。
10
+ *
11
+ * 这不是假想:2026-08-31 我自己就这么读错过一次,据此差点报出「舰队心跳陈旧
12
+ * 8.3 小时」。**CLI 在主动制造这个误读。**
13
+ *
14
+ * 所以显示两样东西:
15
+ * - **相对时长**(人真正想知道的那个)
16
+ * - 绝对值,并**显式标 UTC**(便于和日志、issue 里的时间对齐)
17
+ */
18
+ export declare function formatHubTime(raw: unknown, nowMs?: number): string;
19
+ /** 人读的时长。负数(时钟偏差/未来时间)如实说,不折成 0。 */
20
+ export declare function formatAgo(deltaMs: number): string;
@@ -0,0 +1,19 @@
1
+ /**
2
+ * #1595 —— `anet doctor` 原先只印 hub 自报的版本:
3
+ *
4
+ * ✅ CommHub reachable (http://127.0.0.1:9200 v0.9.0-preview.38)
5
+ *
6
+ * 读的人**看不到自己这台 CLI 钉的是哪个**。实测(2026-08-31):生产 hub 在
7
+ * `.38`,而 `anet hub start` 的 `PINNED_SERVER_VERSION` 是 `.44` —— 两个数
8
+ * 差 6 个版本,而屏幕上只有一个。今天有一整条排查(agent→用户消息为什么
9
+ * 验不了端到端)就卡在这个差上:`.44` 之前 `send_desktop_message` 是
10
+ * fire-and-forget 且仍返回 `ok:true`,所以在 `.38` 上拿到的 `ok:true`
11
+ * 不是「用户看到了」的证据。
12
+ *
13
+ * 🔴 **只并排摆出两个数,不判断谁对、不给阈值、不发警告。**
14
+ * hub 比 CLI 的 pin 老或新都可能完全合理 —— 连的是别人运维的 hub、
15
+ * 本机 hub 还没重启、或者故意钉在旧版。给一个猜出来的「应该一致」
16
+ * 判据,会在这些正常情况下变成误报,而一个会误报的检查第一周就会被关掉。
17
+ * 让读的人自己看见差在哪,是这一格能诚实做到的全部。
18
+ */
19
+ export declare function formatHubVersionDetail(hubUrl: string, hubVersion: unknown, pinnedVersion: string): string;
@@ -0,0 +1,34 @@
1
+ import type { IMCorrelationStore, IMTaskCorrelation } from "./types";
2
+ export interface JsonIMCorrelationStoreOptions {
3
+ now?: () => number;
4
+ /** How long idempotency keys remain valid. Defaults to 24h. */
5
+ seenTtlMs?: number;
6
+ /** How long terminal correlations remain queryable. Defaults to 24h. */
7
+ terminalTtlMs?: number;
8
+ }
9
+ /**
10
+ * Small durable store for RFC-020 §2.9④ / §4.4 correlation state.
11
+ *
12
+ * The first gateway PR needs this as a standalone data structure before the
13
+ * bridge is rewired: idempotency keys survive process restart, and task replies
14
+ * can be routed back to their originating IM conversation.
15
+ */
16
+ export declare class JsonIMCorrelationStore implements IMCorrelationStore {
17
+ private readonly path;
18
+ private readonly now;
19
+ private readonly seenTtlMs;
20
+ private readonly terminalTtlMs;
21
+ constructor(path: string, options?: JsonIMCorrelationStoreOptions);
22
+ hasSeen(idempotencyKey: string): Promise<string | null>;
23
+ recordSeen(idempotencyKey: string, taskId: string): Promise<void>;
24
+ getCorrelation(taskId: string): Promise<IMTaskCorrelation | null>;
25
+ putCorrelation(taskId: string, correlation: IMTaskCorrelation): Promise<void>;
26
+ updateStatus(taskId: string, status: IMTaskCorrelation["status"]): Promise<void>;
27
+ gc(now: number): Promise<{
28
+ removed: number;
29
+ }>;
30
+ private isExpired;
31
+ private load;
32
+ private save;
33
+ }
34
+ export declare function createJsonIMCorrelationStore(path: string, options?: JsonIMCorrelationStoreOptions): IMCorrelationStore;
@@ -1,5 +1,40 @@
1
+ /**
2
+ * RFC-020 §3.1 — Feishu (Lark) adapter for the IM compatibility layer.
3
+ *
4
+ * Uses `@larksuiteoapi/node-sdk` in WebSocket long-connection mode (WSClient).
5
+ * No public IP / no domain verification / no webhook signature decryption —
6
+ * the three biggest 飞书 接入 risks all live in the HTTP event-callback path,
7
+ * not in WSClient mode.
8
+ *
9
+ * Milestones:
10
+ * M1: contract scaffold.
11
+ * M2 (this file): WSClient init + EventDispatcher for `im.message.receive_v1`
12
+ * + event normalization + access whitelist gate + audit log.
13
+ * M3: outbound `im.message.create` (text), edit support (≤20/msg).
14
+ * M5: image upload / download (`im.image.create` / `im.messageResource.get`)
15
+ * + group @bot detection refined to match the bot's own open_id.
16
+ */
17
+ import * as lark from "@larksuiteoapi/node-sdk";
1
18
  import type { IMAdapter, IMAdapterHealth, IMChannelConfig, IMConversationRef, IMIngressMode, NormalizedIMEvent, NormalizedIMMessage } from "../types.js";
2
19
  type OnEventHandler = (event: NormalizedIMEvent) => Promise<void>;
20
+ export type FeishuWsClientLike = Pick<lark.WSClient, "start" | "close">;
21
+ export type FeishuWsClientFactory = (params: ConstructorParameters<typeof lark.WSClient>[0]) => FeishuWsClientLike;
22
+ type FeishuInboundHandler = (rawEvent: unknown) => Promise<unknown>;
23
+ export interface FeishuEventDispatcherLike {
24
+ register(handlers: Record<string, FeishuInboundHandler>): unknown;
25
+ }
26
+ export interface FeishuAdapterOptions {
27
+ /** @internal Avoids real bot-info HTTP calls in lifecycle tests. */
28
+ createClient?: (params: ConstructorParameters<typeof lark.Client>[0]) => lark.Client;
29
+ /** @internal Test seam; production uses the pinned Lark SDK WSClient. */
30
+ createWsClient?: FeishuWsClientFactory;
31
+ /** @internal Test seam; production uses the pinned Lark SDK dispatcher. */
32
+ createEventDispatcher?: () => FeishuEventDispatcherLike;
33
+ /** Independent outer bound in case the SDK promise/callback path stalls. */
34
+ wsReadyTimeoutMs?: number;
35
+ /** Called once when an already-ready socket exhausts reconnect attempts. */
36
+ onTerminalError?: (error: Error) => void;
37
+ }
3
38
  export declare class FeishuAdapter implements IMAdapter {
4
39
  readonly platform = "feishu";
5
40
  readonly ingressMode: IMIngressMode;
@@ -7,6 +42,8 @@ export declare class FeishuAdapter implements IMAdapter {
7
42
  private connectionName_;
8
43
  private client;
9
44
  private wsClient;
45
+ private lifecycleGeneration;
46
+ private readonly options;
10
47
  /**
11
48
  * The bot's own open_id, resolved at init() via /open-apis/bot/v3/info.
12
49
  * Used to detect real @bot mentions (vs any mention) in group messages.
@@ -17,6 +54,7 @@ export declare class FeishuAdapter implements IMAdapter {
17
54
  /** Where to persist downloaded inbound media (M5c). */
18
55
  private mediaDir;
19
56
  private health_;
57
+ constructor(options?: FeishuAdapterOptions);
20
58
  /**
21
59
  * Snapshot of the current `access.allowFrom` list (from access.json).
22
60
  * Used by the bridge's rate-limiter to exempt operator-vouched explicit
@@ -131,4 +169,9 @@ export declare const FEISHU_TEXT_SINGLE_LIMIT = 4000;
131
169
  * If the input is already short enough, returns a single-element array.
132
170
  */
133
171
  export declare function splitTextForFeishu(text: string, maxChars: number): string[];
172
+ /**
173
+ * Lark errors may echo request/config values. Keep worker logs actionable while
174
+ * ensuring credentials and multiline payloads never cross the process boundary.
175
+ */
176
+ export declare function sanitizeFeishuWsError(rawError: unknown, appId: string, appSecret: string): Error;
134
177
  export {};
@@ -2,22 +2,36 @@
2
2
  * RFC-020 §2.5 / RFC-002 §2.2 — Feishu bridge worker.
3
3
  *
4
4
  * Entry point spawned by agent-node when a node profile has `channels.feishu`
5
- * enabled. Per Vincent 2026-06-24 decision, the first-cut is the simplified
6
- * "agent-node direct bridge" model, not the full commhub-gateway:
5
+ * enabled. This worker owns the FeishuAdapter and its WSClient connection.
7
6
  *
8
- * - This worker owns the FeishuAdapter and its WSClient connection.
9
- * - Inbound IM event → access whitelist gate → forward to agent-node's main
10
- * `think()` via parent IPC.
11
- * - think() result → adapter.send() back to the originating conversation.
7
+ * 🔴 There are TWO outbound paths, and which one runs is decided at line ~445:
12
8
  *
13
- * Differences vs RFC-020 §2.5 full commhub-gateway path:
9
+ * const client = commhubClient ?? createEnvCommHubClient();
10
+ * if (client) return createCommHubEventHandler(...); // (A)
11
+ * if (typeof process.send === "function") ... // (B)
12
+ *
13
+ * (A) CommHub task dispatch — **the default on any real node.**
14
+ * `createEnvCommHubClient()` returns null only when neither COMMHUB_URL
15
+ * nor ANET_HUB_URL is set, and every provisioned node has one. Replies
16
+ * carry `in_reply_to`, and the correlation store tracks task status.
17
+ * (B) parent IPC → agent-node's `think()` — the fallback when there is no
18
+ * hub URL in env (standalone / test harness).
19
+ *
20
+ * Both paths end at adapter.send() back to the originating conversation.
21
+ *
22
+ * 🔴 This block used to say the opposite —— verbatim:
23
+ * "IM messages do NOT pass through commhub task dispatch."
24
+ * That was true of the 2026-06-24 first cut, and stayed in the file after
25
+ * the commhub path landed (#1252, merged 2026-08-27). It is the first thing
26
+ * anyone reads in this file, so it mis-answered the question "does Feishu go
27
+ * through CommHub" for at least one reader before being caught. If you change
28
+ * which path is default, change these lines in the same commit.
29
+ *
30
+ * Still true of both paths (unchanged from the first cut):
14
31
  * - No separate gateway ntok_ / dedicated commhub alias.
15
- * - IM messages do NOT pass through commhub task dispatch.
16
- * - Feishu messages do NOT appear in Dashboard topology / Chat.
17
32
  *
18
- * The full §2.9 path (meta_json columns, SSE passthrough, persisted
19
- * IMCorrelationStore) lands as the follow-up PR after this demo ships
20
- * — tracked in #182.
33
+ * The remaining §2.9 work (meta_json columns, SSE passthrough, Dashboard
34
+ * topology / Chat visibility for Feishu conversations) is tracked in #182.
21
35
  *
22
36
  * Milestones:
23
37
  * M1: worker entry scaffold.
@@ -29,8 +43,29 @@
29
43
  * M4: agent-node spawn integration (fork(this) wired by agent-node).
30
44
  * M5: group @bot trigger refinement, image up/down, Docker smoke.
31
45
  */
32
- import type { NormalizedIMEvent } from "../types.js";
46
+ import type { IMCorrelationStore, NormalizedIMEvent } from "../types.js";
33
47
  import { FeishuAdapter } from "./adapter.js";
48
+ export type IMBridgeCommHubInboxMessage = {
49
+ id: string;
50
+ type?: string;
51
+ content: string;
52
+ from_session?: string;
53
+ in_reply_to?: string;
54
+ meta?: unknown;
55
+ };
56
+ export interface IMBridgeCommHubClient {
57
+ sendTask(args: {
58
+ alias: string;
59
+ task: string;
60
+ priority?: "high" | "normal" | "low";
61
+ ttlSeconds?: number;
62
+ meta?: unknown;
63
+ }): Promise<{
64
+ taskId: string;
65
+ }>;
66
+ getInbox(alias: string): Promise<IMBridgeCommHubInboxMessage[]>;
67
+ ackInbox(alias: string, messageId: string): Promise<void>;
68
+ }
34
69
  export interface FeishuBridgeOptions {
35
70
  /** Absolute path to `.anet/nodes/<node>/channels/feishu/`. */
36
71
  channelDir: string;
@@ -44,6 +79,16 @@ export interface FeishuBridgeOptions {
44
79
  * - stderr logger otherwise (standalone smoke debugging).
45
80
  */
46
81
  onEvent?: (event: NormalizedIMEvent) => Promise<void>;
82
+ /** Fatal WS failure after initial readiness (for worker lifecycle ownership). */
83
+ onTerminalError?: (error: Error) => void;
84
+ /** Persistent task/message correlation state. Defaults to channelDir/state.json. */
85
+ correlationStore?: IMCorrelationStore;
86
+ /** CommHub task transport. Defaults to COMMHUB_URL/COMMHUB_TOKEN when available. */
87
+ commhubClient?: IMBridgeCommHubClient;
88
+ /** Poll interval for CommHub replies. Defaults to 1500ms. */
89
+ commhubPollMs?: number;
90
+ /** 出站传输模式。省略时按 ANET_FEISHU_BRIDGE_MODE,再省略则 "direct"。 */
91
+ bridgeMode?: FeishuBridgeMode;
47
92
  }
48
93
  /** Bridge → parent: inbound IM event ready for think(). */
49
94
  export interface BridgeIncomingEnvelope {
@@ -101,6 +146,24 @@ export type WithRateLimitHandle = {
101
146
  floodKeyCount: number;
102
147
  };
103
148
  };
149
+ /**
150
+ * 出站传输模式。**显式声明,不靠环境变量在场与否去猜。**
151
+ *
152
+ * direct — parent IPC → agent-node 的 think()。**默认。**
153
+ * 2026-06-24 的第一版路径,飞书消息不进 CommHub 任务分发,
154
+ * 也不出现在 Dashboard 拓扑 / Chat 里。
155
+ * commhub — 入站事件变成一个 CommHub task,回复带 in_reply_to,
156
+ * correlation store 跟踪状态。**必须显式打开。**
157
+ *
158
+ * 🔴 为什么要显式:在此之前是 `commhubClient ?? createEnvCommHubClient()` ——
159
+ * 有 COMMHUB_URL 就走 commhub、没有就悄悄回落 IPC。两条路径的可观测性、
160
+ * Dashboard 可见性、失败语义完全不同,而**运维看不出自己在哪条上**,
161
+ * 文件头注释也因此和代码说了相反的话长达一次发布。
162
+ */
163
+ export type FeishuBridgeMode = "commhub" | "direct";
164
+ export declare const DEFAULT_FEISHU_BRIDGE_MODE: FeishuBridgeMode;
165
+ /** 解析模式。优先级:显式入参 > 环境变量 > 默认。非法值直接抛,不静默取默认。 */
166
+ export declare function resolveFeishuBridgeMode(explicit?: FeishuBridgeMode, env?: NodeJS.ProcessEnv): FeishuBridgeMode;
104
167
  /**
105
168
  * IPC handler — forwards inbound events to the parent agent-node and routes
106
169
  * the parent's reply back to Feishu via the adapter. The parent contract is
@@ -125,7 +188,8 @@ export type WithRateLimitHandle = {
125
188
  * the agent-node.log (closes the prior silent-success blindspot).
126
189
  */
127
190
  /** @internal exported for test harness; not intended for production callers. */
128
- export declare function createIPCEventHandler(adapter: FeishuAdapter, ttlMs: number, ackPlaceholder: boolean): (event: NormalizedIMEvent) => Promise<void>;
191
+ export declare function createIPCEventHandler(adapter: FeishuAdapter, ttlMs: number, ackPlaceholder: boolean, correlationStore?: IMCorrelationStore): (event: NormalizedIMEvent) => Promise<void>;
192
+ export declare function createCommHubEventHandler(nodeAlias: string, adapter: FeishuAdapter, ttlMs: number, ackPlaceholder: boolean, correlationStore: IMCorrelationStore | undefined, commhubClient: IMBridgeCommHubClient, pollMs?: number): (event: NormalizedIMEvent) => Promise<void>;
129
193
  export { FeishuAdapter } from "./adapter.js";
130
194
  export { loadFeishuChannelConfig } from "./config.js";
131
195
  export type { FeishuAccessList, FeishuChannelConfig, FeishuChannelEnv, } from "./config.js";
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * RFC-020 §17 — feishu inbound bridge → hub `/api/upload` integration.
3
3
  *
4
- * Vincent 2026-06-30: cross-machine agents (e.g. TM门户运维@toodadev2)
4
+ * Vincent 2026-06-30: cross-machine agents (e.g. a partner-team node on a partner-team host)
5
5
  * delegated by the feishu-local bot can't read inbound attachments
6
6
  * because the only thing they get is a host-local path that doesn't
7
7
  * exist on the receiver's filesystem. #351 already wired agent-node's
@@ -0,0 +1,13 @@
1
+ interface WorkerProcessBoundary {
2
+ stderr: {
3
+ write(message: string): unknown;
4
+ };
5
+ exit(code: number): unknown;
6
+ }
7
+ /**
8
+ * A terminal WS error means this worker no longer owns a live ingress path.
9
+ * Exit non-zero so the parent/supervisor cannot continue advertising it as
10
+ * healthy. Kept separate from worker.ts so the real exit contract is testable.
11
+ */
12
+ export declare function exitFeishuWorker(error: Error, boundary?: WorkerProcessBoundary): void;
13
+ export {};