@sleep2agi/agent-network 2.3.0-preview.18 → 2.3.0-preview.180

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/src/active-network-task.d.ts +28 -0
  6. package/dist/src/batch-workdir.d.ts +9 -0
  7. package/dist/src/bootstrap-password-db.d.ts +13 -0
  8. package/dist/src/channel-attachments.d.ts +29 -0
  9. package/dist/src/channel-inbox-wake.d.ts +21 -0
  10. package/dist/src/channel-meta.d.ts +10 -0
  11. package/dist/src/channel-peer-reply.d.ts +41 -0
  12. package/dist/src/channel-task-trace.d.ts +14 -0
  13. package/dist/src/claude-vendor-env.d.ts +28 -0
  14. package/dist/src/cli-args.d.ts +8 -0
  15. package/dist/src/cli-auth-session.d.ts +47 -0
  16. package/dist/src/cli-errors.d.ts +41 -0
  17. package/dist/src/cli-exit.d.ts +11 -0
  18. package/dist/src/cli-help.d.ts +10 -0
  19. package/dist/src/cli-version-display.d.ts +16 -0
  20. package/dist/src/client-task-trace.d.ts +9 -0
  21. package/dist/src/client.js +1 -1
  22. package/dist/src/codex-adopt.d.ts +46 -0
  23. package/dist/src/codex-auth-fingerprint.d.ts +211 -0
  24. package/dist/src/codex-bin-pin.d.ts +23 -0
  25. package/dist/src/codex-commhub-mcp.d.ts +22 -0
  26. package/dist/src/codex-copresence-bridge-log.d.ts +44 -0
  27. package/dist/src/codex-copresence-env.d.ts +5 -0
  28. package/dist/src/codex-copresence-login-gate.d.ts +18 -0
  29. package/dist/src/codex-copresence-model.d.ts +23 -0
  30. package/dist/src/codex-copresence-preflight.d.ts +78 -0
  31. package/dist/src/codex-copresence-profile.d.ts +126 -0
  32. package/dist/src/codex-copresence-recovery.d.ts +70 -0
  33. package/dist/src/codex-copresence-resume-timeout.d.ts +28 -0
  34. package/dist/src/codex-copresence-rollout-guard.d.ts +36 -0
  35. package/dist/src/codex-copresence-rpc.d.ts +17 -0
  36. package/dist/src/codex-copresence-thread.d.ts +13 -0
  37. package/dist/src/codex-copresence-yolo.d.ts +16 -0
  38. package/dist/src/codex-external-appserver.d.ts +130 -0
  39. package/dist/src/codex-fork-recovery.d.ts +52 -0
  40. package/dist/src/codex-home-enforce.d.ts +88 -0
  41. package/dist/src/codex-lifecycle-account.d.ts +104 -0
  42. package/dist/src/codex-lifecycle-canary.d.ts +20 -0
  43. package/dist/src/codex-lifecycle-facts.d.ts +53 -0
  44. package/dist/src/codex-lifecycle-fork.d.ts +91 -0
  45. package/dist/src/codex-lifecycle-preflight.d.ts +79 -0
  46. package/dist/src/codex-lifecycle-receipt.d.ts +53 -0
  47. package/dist/src/codex-lifecycle-restart.d.ts +88 -0
  48. package/dist/src/codex-login-share-guard.d.ts +146 -0
  49. package/dist/src/codex-menu.d.ts +99 -0
  50. package/dist/src/codex-model-default.d.ts +6 -0
  51. package/dist/src/codex-node-login.d.ts +98 -0
  52. package/dist/src/codex-pending-thread-restart.d.ts +69 -0
  53. package/dist/src/codex-reasoning-effort.d.ts +17 -0
  54. package/dist/src/codex-recovery-lease.d.ts +39 -0
  55. package/dist/src/codex-recovery-resource-gate.d.ts +15 -0
  56. package/dist/src/codex-resume.d.ts +89 -0
  57. package/dist/src/codex-rollout-history-guard.d.ts +84 -0
  58. package/dist/src/codex-tui-client-health.d.ts +30 -0
  59. package/dist/src/commhub-response.d.ts +1 -0
  60. package/dist/src/controlled-upload.d.ts +83 -0
  61. package/dist/src/copresence-deps.d.ts +22 -0
  62. package/dist/src/copresence-identity.d.ts +363 -0
  63. package/dist/src/copresence-startup-diagnosis.d.ts +17 -0
  64. package/dist/src/daemon-adopt.d.ts +14 -0
  65. package/dist/src/daemon-anet-bin.d.ts +32 -0
  66. package/dist/src/daemon-capability-display.d.ts +110 -0
  67. package/dist/src/daemon-capability-display.js +21 -0
  68. package/dist/src/daemon-codex-inventory.d.ts +65 -0
  69. package/dist/src/daemon-inherited-env.d.ts +9 -0
  70. package/dist/src/daemon-provider-account-custody.d.ts +28 -0
  71. package/dist/src/daemon-provider-account-readback.d.ts +3 -0
  72. package/dist/src/daemon-provider-application.d.ts +36 -0
  73. package/dist/src/daemon-provider-apply-command.d.ts +9 -0
  74. package/dist/src/daemon-provider-collect.d.ts +29 -0
  75. package/dist/src/daemon-provider-command.d.ts +7 -0
  76. package/dist/src/daemon-provider-initialize.d.ts +27 -0
  77. package/dist/src/daemon-provider-lifecycle.d.ts +4 -0
  78. package/dist/src/daemon-provider-store.d.ts +104 -0
  79. package/dist/src/daemon-runtime-path-preflight.d.ts +22 -0
  80. package/dist/src/daemon-runtime-staleness.d.ts +13 -0
  81. package/dist/src/dashboard-managed-process.d.ts +35 -0
  82. package/dist/src/display-width.d.ts +27 -0
  83. package/dist/src/doctor-node-count.d.ts +28 -0
  84. package/dist/src/grok-attach-client.d.ts +129 -0
  85. package/dist/src/grok-build-drift.d.ts +15 -0
  86. package/dist/src/grok-copresence-disclosure.d.ts +11 -0
  87. package/dist/src/grok-copresence-orchestration.d.ts +75 -0
  88. package/dist/src/grok-copresence-profile.d.ts +65 -0
  89. package/dist/src/grok-create-mode.d.ts +19 -0
  90. package/dist/src/host-telemetry.d.ts +14 -0
  91. package/dist/src/hub-health-timeout.d.ts +4 -0
  92. package/dist/src/hub-server-version.d.ts +64 -0
  93. package/dist/src/hub-stop.d.ts +74 -0
  94. package/dist/src/hub-time-display.d.ts +20 -0
  95. package/dist/src/hub-version-skew.d.ts +19 -0
  96. package/dist/src/im/correlation-store.d.ts +34 -0
  97. package/dist/src/im/feishu/adapter.d.ts +43 -0
  98. package/dist/src/im/feishu/bridge.d.ts +78 -14
  99. package/dist/src/im/feishu/hub-upload.d.ts +1 -1
  100. package/dist/src/im/feishu/worker-lifecycle.d.ts +13 -0
  101. package/dist/src/im/feishu/worker.js +174 -161
  102. package/dist/src/inbox-drain.d.ts +20 -0
  103. package/dist/src/local-process-state.d.ts +12 -0
  104. package/dist/src/locale-diagnostic.d.ts +12 -0
  105. package/dist/src/login-client-label.d.ts +6 -0
  106. package/dist/src/ls-columns.d.ts +15 -0
  107. package/dist/src/mock-llm.d.ts +12 -0
  108. package/dist/src/node-activity-log.d.ts +4 -0
  109. package/dist/src/node-clone.d.ts +134 -0
  110. package/dist/src/node-delete-hub.d.ts +42 -0
  111. package/dist/src/node-files.d.ts +62 -0
  112. package/dist/src/node-locate.d.ts +60 -0
  113. package/dist/src/node-ls-all.d.ts +80 -0
  114. package/dist/src/node-menu.d.ts +40 -0
  115. package/dist/src/node-not-found.d.ts +1 -0
  116. package/dist/src/node-remote.d.ts +180 -0
  117. package/dist/src/node-running-guard.d.ts +9 -0
  118. package/dist/src/node-server-identity.d.ts +35 -0
  119. package/dist/src/node-server-payload.d.ts +66 -0
  120. package/dist/src/node-server-rules-file.d.ts +14 -0
  121. package/dist/src/node-server-version.d.ts +39 -0
  122. package/dist/src/node-server.js +8 -1
  123. package/dist/src/node-skills.d.ts +57 -0
  124. package/dist/src/normalize-runtime.d.ts +29 -2
  125. package/dist/src/offline-age.d.ts +29 -0
  126. package/dist/src/one-line-cell.d.ts +20 -0
  127. package/dist/src/opencode-agent-node-pair.d.ts +28 -0
  128. package/dist/src/opencode-auth-login.d.ts +43 -0
  129. package/dist/src/opencode-free-tier.d.ts +27 -0
  130. package/dist/src/opencode-generation-create.d.ts +27 -0
  131. package/dist/src/opencode-generation-record.d.ts +24 -0
  132. package/dist/src/opencode-launch-env.d.ts +13 -0
  133. package/dist/src/opencode-owner-mode.d.ts +6 -0
  134. package/dist/src/opencode-package-binary.d.ts +44 -0
  135. package/dist/src/opencode-pin.d.ts +61 -0
  136. package/dist/src/opencode-preset.d.ts +77 -0
  137. package/dist/src/opencode-runtime-binding.d.ts +30 -0
  138. package/dist/src/opencode-safe-root.d.ts +36 -0
  139. package/dist/src/opencode-shared-server-create.d.ts +5 -0
  140. package/dist/src/opencode-smoke-env.d.ts +1 -0
  141. package/dist/src/opencode-start-mode.d.ts +8 -0
  142. package/dist/src/opencode-v2-configured-model.d.ts +34 -0
  143. package/dist/src/opencode-v2-create-align.d.ts +18 -0
  144. package/dist/src/opencode-versions.d.ts +44 -0
  145. package/dist/src/outbound-attachments.d.ts +60 -0
  146. package/dist/src/outbound-tool-names.d.ts +1 -0
  147. package/dist/src/owned-roots.d.ts +58 -0
  148. package/dist/src/owner-env-file.d.ts +2 -0
  149. package/dist/src/package-mode-preflight.d.ts +41 -0
  150. package/dist/src/posix-codex-copresence.d.ts +33 -0
  151. package/dist/src/posix-modes.d.ts +36 -0
  152. package/dist/src/primary-network.d.ts +23 -0
  153. package/dist/src/private-state.d.ts +10 -0
  154. package/dist/src/process-telemetry.d.ts +12 -0
  155. package/dist/src/profile-serialize.d.ts +1 -0
  156. package/dist/src/project-key.d.ts +1 -0
  157. package/dist/src/provider-application-contract.d.ts +11 -0
  158. package/dist/src/provider-apply.d.ts +28 -0
  159. package/dist/src/provider-presets.d.ts +76 -0
  160. package/dist/src/reply-local-links.d.ts +47 -0
  161. package/dist/src/reply-originator.d.ts +20 -0
  162. package/dist/src/resume-runtime-infer.d.ts +18 -0
  163. package/dist/src/rules-file.d.ts +53 -0
  164. package/dist/src/scoped-secrets.d.ts +33 -0
  165. package/dist/src/secret-shell-guidance.d.ts +4 -0
  166. package/dist/src/session-status-class.d.ts +48 -0
  167. package/dist/src/shared/opencode-borrowed-launch-health.d.ts +29 -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 +3 -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,36 @@
1
+ import { spawnSync } from "child_process";
2
+ import { type FirstLineRead } from "./codex-rollout-history-guard";
3
+ export interface CopresenceRolloutGuardInput {
4
+ codexHome: string;
5
+ /** Threads this start may resume (recorded thread, pending candidate). Empty entries are skipped. */
6
+ threadIds: Array<string | undefined | null>;
7
+ /** The binary as the launch names it (probeVersion should run it the way the launch does). */
8
+ codexBin: string;
9
+ displayName: string;
10
+ probeVersion?: (bin: string) => string | null;
11
+ resolveRollout?: (codexHome: string, threadId: string) => string | null;
12
+ readFirstLine?: (path: string) => FirstLineRead;
13
+ }
14
+ export interface CopresenceRolloutGuardResult {
15
+ /** Non-null = refuse to start; print these lines. */
16
+ block: string[] | null;
17
+ /** Could-not-tell notes; print and continue. */
18
+ warnings: string[];
19
+ }
20
+ /**
21
+ * `codex --version` run through the SAME shell preamble the launch uses, so the
22
+ * probe sees the binary the launch will run: the launch command itself is never
23
+ * rewritten. The co-presence panes run `bash -lc "… exec <codexBin> app-server"`
24
+ * (login-shell PATH); external app-server panes run `bash -c "<source .env>; …;
25
+ * <codexBin> app-server"` (the workspace .env may set PATH). `script` must end in
26
+ * `exec <codexBin> --version`. Only a codex-identifying line counts; anything
27
+ * else (or any failure) is null = unknown, which never blocks.
28
+ */
29
+ export declare function probeCodexVersionViaShell(script: string, opts: {
30
+ loginShell: boolean;
31
+ env?: NodeJS.ProcessEnv;
32
+ run?: typeof spawnSync;
33
+ }): string | null;
34
+ /** The co-presence app-server pane's preamble (CODEX_HOME, then exec the binary), ending in `--version`. */
35
+ export declare function copresenceVersionProbeScript(codexHome: string, codexBin: string): string;
36
+ export declare function copresenceRolloutGuard(input: CopresenceRolloutGuardInput): CopresenceRolloutGuardResult;
@@ -0,0 +1,17 @@
1
+ import { type CodexRecoveryVerification } from "./codex-copresence-recovery";
2
+ export declare const SAFE_CODEX_THREAD_ID: RegExp;
3
+ export declare function defaultWebSocketCtor(maxPayload: number): Promise<any>;
4
+ /** Minimal JSON-RPC client used only while bringing up a co-presence app-server. */
5
+ export declare function createCodexCopresenceThread(ws: string, timeoutMs: number, resumeThreadId?: string, model?: string,
6
+ /** forkFirst (board #738): `thread/fork` the recorded thread, then resume the NEW thread. */
7
+ options?: {
8
+ webSocketCtor?: any;
9
+ rolloutBytes?: number | null;
10
+ forkFirst?: boolean;
11
+ modelProvider?: string;
12
+ }): Promise<{
13
+ threadId: string;
14
+ verification?: CodexRecoveryVerification;
15
+ freshDeferred: boolean;
16
+ resumedModel?: string;
17
+ }>;
@@ -0,0 +1,13 @@
1
+ export type CopresenceThreadPlan = {
2
+ method: "thread/resume";
3
+ params: {
4
+ threadId: string;
5
+ };
6
+ bootstrap: false;
7
+ } | {
8
+ method: "thread/start";
9
+ params: Record<string, never>;
10
+ bootstrap: true;
11
+ };
12
+ /** Restarting a node must preserve its conversation; only a virgin node starts one. */
13
+ export declare function copresenceThreadPlan(storedThreadId?: string): CopresenceThreadPlan;
@@ -0,0 +1,16 @@
1
+ /** API `flags.*` shape (client #815 / codexSdkYoloFlags). */
2
+ export declare const CODEX_COPRESENCE_YOLO_FLAGS: Readonly<{
3
+ approvalPolicy: "never";
4
+ sandboxMode: "danger-full-access";
5
+ skipGitRepoCheck: true;
6
+ }>;
7
+ /** Top-level Codex `config.toml` keys for the same posture. */
8
+ export declare const CODEX_COPRESENCE_YOLO_TOML: Readonly<{
9
+ approval_policy: "never";
10
+ sandbox_mode: "danger-full-access";
11
+ }>;
12
+ /** Fill missing yolo flags when a co-presence codex-app-server node is created. */
13
+ export declare function applyCodexCopresenceFlagDefaults(flags: Record<string, unknown>): void;
14
+ export declare function mergeCopresenceYoloIntoToml(existing: string): string;
15
+ /** Persist co-presence yolo posture under `<nodeDir>/codex-home/config.toml`. */
16
+ export declare function writeCopresenceYoloToCodexHome(codexHome: string): void;
@@ -0,0 +1,130 @@
1
+ export declare const EXTERNAL_APPSERVER_LAYOUT = "external-appserver";
2
+ export declare const READYZ_TIMEOUT_MS = 30000;
3
+ export interface ExternalAppserverProfile {
4
+ runtime?: string;
5
+ codexAppServerUrl?: string;
6
+ codexThreadId?: string;
7
+ codexProjectDir?: string;
8
+ codexCopresence?: boolean;
9
+ codexLaunchLayout?: string;
10
+ codexBin?: string;
11
+ codexHome?: string;
12
+ model?: string;
13
+ env?: Record<string, unknown>;
14
+ }
15
+ export interface ExternalAppserverSessions {
16
+ appsrv: string;
17
+ tui: string;
18
+ bridge: string;
19
+ }
20
+ export declare function externalAppserverSessions(alias: string): ExternalAppserverSessions;
21
+ /** Bridge first, so nothing is left attached to a server that is going away. */
22
+ export declare function externalAppserverStopOrder(alias: string): string[];
23
+ /**
24
+ * Does this start/stop/restart take the external-app-server lane?
25
+ * `runtime` is the already-normalized runtime name.
26
+ */
27
+ export declare function externalAppserverRequested(flagPassed: boolean, profile: ExternalAppserverProfile, runtime: string): boolean;
28
+ export interface ExternalAppserverPlan {
29
+ alias: string;
30
+ nodeDir: string;
31
+ configPath: string;
32
+ workspaceDir: string;
33
+ url: string;
34
+ host: string;
35
+ port: number;
36
+ readyzUrl: string;
37
+ projectDir: string;
38
+ /** True when config.codexProjectDir was empty and the workspace was used instead. */
39
+ projectDirFromWorkspace: boolean;
40
+ threadId: string;
41
+ model: string;
42
+ codexHome: string;
43
+ codexBin: string;
44
+ /** Start the `<alias>-tui` session (codexCopresence && codexThreadId). */
45
+ tui: boolean;
46
+ sessions: ExternalAppserverSessions;
47
+ }
48
+ export declare function planExternalAppserverNode(input: {
49
+ alias: string;
50
+ nodeDir: string;
51
+ workspaceDir: string;
52
+ profile: ExternalAppserverProfile;
53
+ }): {
54
+ ok: true;
55
+ plan: ExternalAppserverPlan;
56
+ } | {
57
+ ok: false;
58
+ error: string;
59
+ };
60
+ /** Names from `wanted` that exist in `existing` — compared as whole strings, never by tmux target rules. */
61
+ export declare function sessionsAlreadyPresent(existing: readonly string[], wanted: readonly string[]): string[];
62
+ /** `{id, name}` rows whose name equals one of `names` exactly, in the order of `names`. */
63
+ export declare function exactSessionRows(rows: readonly {
64
+ id: string;
65
+ name: string;
66
+ }[], names: readonly string[]): {
67
+ id: string;
68
+ name: string;
69
+ }[];
70
+ /**
71
+ * Read the node token from config.json INSIDE the session shell, into the env.
72
+ * The value never appears in tmux's argv, the pane's start command, or any
73
+ * process's /proc/<pid>/cmdline — only the config path does.
74
+ */
75
+ export declare function tokenInSessionSnippet(configPath: string, jsRuntime: string): string;
76
+ /** Same token handoff, via the standalone binary's internal argv (it is not `node -e`). */
77
+ export declare function standaloneBinTokenSnippet(configPath: string, anetBin: string): string;
78
+ export declare function appserverShellCommand(plan: ExternalAppserverPlan, jsRuntime: string, mode?: "js-eval" | "standalone-bin"): string;
79
+ /**
80
+ * Board #734 — `codex --version` with the app-server pane's exact preamble (workspace
81
+ * .env sourced the same way, same CODEX_HOME), run with `bash -c` like the pane, so the
82
+ * version probe sees the binary appserverShellCommand will run.
83
+ */
84
+ export declare function versionProbeShellCommand(plan: ExternalAppserverPlan): string;
85
+ export declare function tuiShellCommand(plan: ExternalAppserverPlan): string;
86
+ export declare function bridgeShellCommand(plan: ExternalAppserverPlan, launch: {
87
+ command: string;
88
+ argsPrefix: readonly string[];
89
+ }): string;
90
+ export declare function bridgeLogPath(plan: {
91
+ nodeDir: string;
92
+ }): string;
93
+ /**
94
+ * tmux `-c` for the product-started bridge (`anet node start` and
95
+ * `restart --bridge-only`). The node directory arrives as `--config` and
96
+ * `--log-dir`; agent-node derives NODE_DIR from that absolute config.
97
+ * Codex's app-server and TUI are separate sessions and pin the project
98
+ * with `-C` plus `CODEX_HOME`, so this directory is not their project.
99
+ * A hand-started agent-node never calls this and keeps the person's cwd.
100
+ */
101
+ export declare function externalAppserverBridgeCwd(plan: Pick<ExternalAppserverPlan, "workspaceDir" | "nodeDir">): string;
102
+ export type ResumedVerdict = {
103
+ state: "match";
104
+ seen: string;
105
+ } | {
106
+ state: "mismatch";
107
+ seen: string;
108
+ } | {
109
+ state: "new-thread";
110
+ seen: string;
111
+ } | {
112
+ state: "not-seen";
113
+ } | {
114
+ state: "no-thread-configured";
115
+ };
116
+ /**
117
+ * Did the bridge resume the configured thread? Reads only the log text written
118
+ * since this start. agent-node prints `[codex-app-server] resumed thread <12 chars>…`
119
+ * or `created thread <12 chars>…` (a silent new session). Registration alone
120
+ * proves nothing about which thread the node is on.
121
+ */
122
+ export declare function resumedThreadVerdict(logText: string, threadId: string): ResumedVerdict;
123
+ /** True when something is already bound to host:port (a listen attempt fails). */
124
+ export declare function portBusy(host: string, port: number): Promise<boolean>;
125
+ /** Poll `/readyz` until it answers 200 or `timeoutMs` passes. */
126
+ export declare function waitForReadyz(url: string, timeoutMs?: number, intervalMs?: number): Promise<{
127
+ ok: boolean;
128
+ status: number;
129
+ waitedMs: number;
130
+ }>;
@@ -0,0 +1,52 @@
1
+ export declare const FORK_RECOVERY_STATE_FILE = "codex-fork-recovery.json";
2
+ export declare const FORK_RECOVERY_SNAPSHOT_DIR = "rollout-snapshots";
3
+ export interface ForkRecoveryOptions {
4
+ /** --fork-on-resume-failure was passed. */
5
+ enabled: boolean;
6
+ /** Correlates a mapping with one Hub start request; never grants confirmation. */
7
+ requestId?: string;
8
+ /** --yes was passed (required when there is no terminal to ask). */
9
+ yes: boolean;
10
+ /** A human can answer a prompt (stdin is a TTY). */
11
+ interactive: boolean;
12
+ /** The recorded thread this start tried to resume. */
13
+ threadId: string | undefined;
14
+ codexHome: string;
15
+ /** <nodes dir>/<node id> — config.json lives here. */
16
+ nodeDir: string;
17
+ /** Display name, for messages. */
18
+ node: string;
19
+ /** Ask a y/N question; resolves true only for an explicit yes. */
20
+ confirm: (prompt: string) => Promise<boolean>;
21
+ now?: () => Date;
22
+ log?: (line: string) => void;
23
+ }
24
+ export interface ForkMapping {
25
+ requestId?: string;
26
+ oldThreadId: string;
27
+ newThreadId: string;
28
+ originalRollout: string;
29
+ snapshot: string;
30
+ sha256: string;
31
+ at: string;
32
+ }
33
+ /** Keep this opaque: the Hub owns ID generation, not the CLI. */
34
+ export declare function parseForkRecoveryRequestId(value: string | undefined): string | undefined;
35
+ export declare function sha256OfFile(path: string): string;
36
+ /** The rollout codex named in the error (when it exists), else the shared resolver's pick. */
37
+ export declare function rolloutForMissingOrdinal(message: string, codexHome: string, threadId: string): string | null;
38
+ /** Copy (never move) the rollout into <nodeDir>/rollout-snapshots/ and drop every write bit. */
39
+ export declare function snapshotRollout(original: string, nodeDir: string, now: Date): {
40
+ path: string;
41
+ sha256: string;
42
+ };
43
+ export declare function recordForkMapping(nodeDir: string, entry: ForkMapping): string;
44
+ export declare function forkConfirmationText(node: string, threadId: string, original: string): string[];
45
+ /**
46
+ * Resume as before; on the "missing an ordinal" failure, and only with the flag and a
47
+ * human's yes, fork instead. `start(false)` resumes the recorded thread; `start(true)`
48
+ * forks it and resumes the fork. Every other outcome re-throws the original error.
49
+ */
50
+ export declare function resumeOrForkOnMissingOrdinal<T extends {
51
+ threadId: string;
52
+ }>(start: (forkFirst: boolean) => Promise<T>, o: ForkRecoveryOptions): Promise<T>;
@@ -0,0 +1,88 @@
1
+ export type CodexHomeSource = "config.codexHome" | "node-codex-home" | "config.env" | "none";
2
+ export interface CodexHomeResolution {
3
+ /** null = 这台节点没有专属 CODEX_HOME(普通 codex 节点用 codex 自己的默认 ~/.codex)。 */
4
+ codexHome: string | null;
5
+ source: CodexHomeSource;
6
+ }
7
+ export interface ResolveNodeCodexHomeInput {
8
+ nodeDir: string;
9
+ /** 节点 config.json 的内容(只读其中三格:codexHome / codexCopresence / env.CODEX_HOME)。 */
10
+ config: Record<string, unknown> | null | undefined;
11
+ exists?: (path: string) => boolean;
12
+ }
13
+ /**
14
+ * 本节点的 CODEX_HOME,只由节点自己的配置/目录决定。优先级:
15
+ * ① config.codexHome(`--codex-home` 显式指定后持久化的那一格)
16
+ * ② <nodeDir>/codex-home(共存节点,或目录已经存在)
17
+ * ③ config.env.CODEX_HOME(节点 profile 自己写的,字面字符串)
18
+ * ④ 没有 → null
19
+ * **进程环境从不参与**:那正是本模块要挡掉的来源。
20
+ */
21
+ export declare function resolveNodeCodexHome(input: ResolveNodeCodexHomeInput): CodexHomeResolution;
22
+ export declare function looksLikeAnetNodeCodexHome(path: string): boolean;
23
+ export interface ApplyCodexHomeResult {
24
+ /** 实际交给子进程的值(undefined = 不设,交给 codex 默认)。 */
25
+ codexHome: string | undefined;
26
+ /** 给人看的一行;没有需要说的时候为 null。 */
27
+ note: string | null;
28
+ }
29
+ /**
30
+ * 把解析结果写进一份**将要交给子进程**的 env(原地修改并返回结论)。
31
+ * - 有专属值 → 强制写入,覆盖任何继承来的值。
32
+ * - 没有专属值、而继承来的值是**别的 anet 节点**的 codex-home → 删掉(那绝不是本节点的)。
33
+ * - 没有专属值、继承来的是运维自己 export 的普通路径 → 保留(不改变普通 codex 节点的既有行为),
34
+ * 并说一句它来自环境。
35
+ */
36
+ export declare function applyNodeCodexHome(env: Record<string, string | undefined>, resolution: CodexHomeResolution): ApplyCodexHomeResult;
37
+ export interface ProcReader {
38
+ /** /proc/<pid>/environ 的原始内容;读不到返回 null。 */
39
+ environ(pid: number): string | null;
40
+ /** 所有进程的 [pid, ppid];读不到返回 []。 */
41
+ parents(): Array<[number, number]>;
42
+ }
43
+ /**
44
+ * 一个 /proc 里的 NUL 分隔块(environ / cmdline)的**原始字节** → JS 字符串,逐条按 UTF-8 解码。
45
+ *
46
+ * 🔴 #448 回归:曾经是 `readFileSync(…, "latin1")`,每个字节变成一个 U+00xx。期望值是 JS 字符串
47
+ * (UTF-8 路径解码来的),于是**任何非 ASCII 路径**(如 `.anet/nodes/测试节点/codex-home`)
48
+ * 读出来都是 `æµè¯…` 这种乱码、永远不相等 → fail closed → 该节点每个任务都被拒。
49
+ *
50
+ * 某一条不是合法 UTF-8 时,不做有损替换(U+FFFD 可能碰巧和期望值里的 U+FFFD 相等):
51
+ * 把 `=` 之后的部分换成 INVALID_UTF8_MARK + 原字节的 latin1 —— 以一个孤立代理项开头,
52
+ * 而合法 UTF-8 解码出来的字符串绝不含孤立代理项,所以它**不可能**等于任何真实路径(fail closed)。
53
+ */
54
+ export declare const INVALID_UTF8_MARK = "\uDFFF";
55
+ export declare function decodeProcNulBlock(bytes: Uint8Array): string;
56
+ /** 合法 UTF-8 解码不出孤立代理项;含孤立代理项的值(INVALID_UTF8_MARK)不能拿来和任何东西比相等。 */
57
+ export declare function hasLoneSurrogate(s: string): boolean;
58
+ /** 读 /proc/<pid>/<file>(environ / cmdline)并逐条按 UTF-8 解码;读不到返回 null。 */
59
+ export declare function readProcNulBlock(pid: number, file: "environ" | "cmdline"): string | null;
60
+ export declare const linuxProcReader: ProcReader;
61
+ /** 环境块里某个变量的值:undefined = 环境读不到;null = 读到了但没有这个变量。 */
62
+ export declare function envVarFromEnviron(environ: string | null, name: string): string | null | undefined;
63
+ export declare function descendantPids(rootPid: number, parents: Array<[number, number]>): number[];
64
+ export type CodexHomeVerdict = {
65
+ ok: true;
66
+ checked: number[];
67
+ skipped?: string;
68
+ } | {
69
+ ok: false;
70
+ pid: number;
71
+ actual: string | null;
72
+ expected: string;
73
+ message: string;
74
+ };
75
+ /**
76
+ * 读 rootPid 及其全部后代的 /proc/<pid>/environ:
77
+ * - rootPid 自己的 CODEX_HOME 必须**正好等于** expected(缺失也算不符);
78
+ * - 后代里凡是带 CODEX_HOME 的,也必须等于 expected(某个后代自己 unset 掉不算错)。
79
+ * 不是 Linux、或 rootPid 的环境根本读不到(进程已退出/权限)→ ok:true + skipped,由调用方决定怎么说。
80
+ * 🔴 读不到 ≠ 核对通过:skipped 必须被调用方打印出来,不能当绿。
81
+ */
82
+ export declare function verifyProcessTreeCodexHome(opts: {
83
+ rootPid: number;
84
+ expected: string;
85
+ label: string;
86
+ platform?: string;
87
+ reader?: ProcReader;
88
+ }): CodexHomeVerdict;
@@ -0,0 +1,104 @@
1
+ import type { ReceiptCheck } from "./codex-lifecycle-receipt.js";
2
+ import type { RestartOutcome } from "./codex-lifecycle-restart.js";
3
+ export declare const SOURCE_KIND = "codex-login-profile";
4
+ /** `--source` 只接受 `codex-login:<profile-id>`。路径、`env:`、`-`(stdin)、绝对/相对路径都拒绝,错误里说清为什么。 */
5
+ export declare function parseSourceRef(raw: string): {
6
+ kind: typeof SOURCE_KIND;
7
+ profileId: string;
8
+ };
9
+ export declare function shortHash(value: string, length?: number): string;
10
+ /** host_id:machine-id(有则用)+ hostname 的不可逆摘要;registry entry 绑定它,拷到别的机器就不认。 */
11
+ export declare function hostIdOf(machineId: string | null, hostname: string): string;
12
+ export interface ChatgptAuthShape {
13
+ auth_mode?: unknown;
14
+ tokens?: {
15
+ account_id?: unknown;
16
+ } | null;
17
+ OPENAI_API_KEY?: unknown;
18
+ }
19
+ /** 只认 ChatGPT 登录:auth_mode=chatgpt 且 tokens.account_id 是 36 位 uuid;指纹 = sha256(account_id) 前 16 位。 */
20
+ export declare function accountFingerprint(auth: ChatgptAuthShape): string;
21
+ export interface RegistryEntry {
22
+ schema_version: 1;
23
+ profile_id: string;
24
+ provider: "openai-chatgpt";
25
+ host_id: string;
26
+ /** 由 registry 目录解析的相对引用;从不是绝对路径。 */
27
+ credential_ref: string;
28
+ account_fingerprint: string;
29
+ created_at: string;
30
+ last_model_probe_at: string | null;
31
+ last_model_probe_status: ProbeStatus | null;
32
+ revoked: boolean;
33
+ disabled: boolean;
34
+ }
35
+ export interface Registry {
36
+ schema_version: 1;
37
+ host_id: string;
38
+ profiles: Record<string, RegistryEntry>;
39
+ }
40
+ export type ProbeStatus = "ok" | "auth" | "quota" | "model" | "unknown";
41
+ export declare function credentialRefFor(profileId: string): string;
42
+ export declare function credentialPath(registryDir: string, entry: RegistryEntry): string;
43
+ export declare function readRegistry(registryDir: string, hostId: string): Registry;
44
+ export declare function writeRegistry(registryDir: string, reg: Registry): void;
45
+ /** 解析一个 profile:必须存在、未 revoked/disabled、host_id 一致、凭据文件在且 0600。返回凭据路径(只在进程内用,不进 receipt)。 */
46
+ export declare function resolveProfile(registryDir: string, reg: Registry, profileId: string, hostId: string): {
47
+ entry: RegistryEntry;
48
+ credentialFile: string;
49
+ };
50
+ /** 把一次 fresh 模型请求的结果归类;归不进已知类的一律 unknown(unknown 也 STOP,不猜)。 */
51
+ export declare function classifyProbe(exitCode: number | null, stdout: string, stderr: string, expected?: string): ProbeStatus;
52
+ export declare function backupRefFor(receiptId: string): string;
53
+ /** rollback 只认 `receipt:<id>`,且只在该节点的 receipts/ 目录里解析;调用方不能另指文件。 */
54
+ export declare function backupPathFor(nodeDir: string, backupRef: string): string;
55
+ export interface InstallActions {
56
+ /** 目标节点 before 核对:返回 fail 的 key(空 = 可继续)。 */
57
+ preflightBlocks(): Promise<string[]>;
58
+ /** 目标当前 auth 指纹(没有 auth.json → null)。 */
59
+ currentFingerprint(): Promise<string | null>;
60
+ /** 在隔离 staging HOME 里用该 profile 发一次 fresh 模型请求。 */
61
+ probe(): Promise<{
62
+ status: ProbeStatus;
63
+ detail: string;
64
+ }>;
65
+ /** 备份目标 auth.json → backup_ref(0600)。 */
66
+ backup(): Promise<{
67
+ backupRef: string;
68
+ }>;
69
+ /** 把 profile 凭据装进目标 CODEX_HOME(0600,原子)。 */
70
+ install(): Promise<void>;
71
+ /** 完整重启(PR-B 状态机),返回其 outcome。 */
72
+ restart(): Promise<RestartOutcome>;
73
+ /** 从 backup_ref 恢复 auth.json。 */
74
+ restore(backupRef: string): Promise<void>;
75
+ /** 探针在 registry 里的回写(时间 + 状态)。 */
76
+ recordProbe(status: ProbeStatus): Promise<void>;
77
+ }
78
+ export interface InstallInput {
79
+ profileId: string;
80
+ sourceFingerprint: string;
81
+ }
82
+ export interface InstallOutcome {
83
+ checks: ReceiptCheck[];
84
+ stoppedAt: string;
85
+ rolledBack: boolean;
86
+ backupRef: string | null;
87
+ }
88
+ /**
89
+ * account install 状态机:preflight → fresh 探针(401/quota/模型不兼容/unknown 都 STOP,目标一字未动)→ 备份 → 安装 →
90
+ * 完整重启(含 verify)→ 目标指纹 == 源指纹。安装后任一步失败 → 恢复备份 + 再重启一次(回滚),receipt 记两段。
91
+ */
92
+ export declare function runAccountInstall(input: InstallInput, a: InstallActions): Promise<InstallOutcome>;
93
+ export interface RollbackActions {
94
+ /** 读原 install receipt;返回它的 backup_ref 与当时的 target_previous_fingerprint。 */
95
+ readInstallReceipt(): Promise<{
96
+ backupRef: string;
97
+ targetPreviousFingerprint: string | null;
98
+ } | null>;
99
+ backupExists(backupRef: string): Promise<boolean>;
100
+ restore(backupRef: string): Promise<void>;
101
+ restart(): Promise<RestartOutcome>;
102
+ currentFingerprint(): Promise<string | null>;
103
+ }
104
+ export declare function runRollback(a: RollbackActions): Promise<InstallOutcome>;
@@ -0,0 +1,20 @@
1
+ /**
2
+ * #1856 PR-E — `anet node codex canary <alias>...`:批量只读体检,**顺序跑、第一个 FAIL 即停**。
3
+ * 批量重启 / 换账号之前先 canary;后面的节点一个都不碰,汇总里明确写"未跑"。纯逻辑,verify 由调用方注入。
4
+ */
5
+ export interface CanaryNodeResult {
6
+ readonly alias: string;
7
+ readonly verdict: "PASS" | "FAIL";
8
+ readonly blocking: readonly string[];
9
+ readonly receiptPath: string | null;
10
+ readonly ms: number;
11
+ }
12
+ export interface CanarySummary {
13
+ readonly verdict: "PASS" | "FAIL";
14
+ readonly ran: readonly CanaryNodeResult[];
15
+ /** 因前面 FAIL 而没跑的节点(顺序保留)。 */
16
+ readonly skipped: readonly string[];
17
+ readonly stoppedAt: string | null;
18
+ }
19
+ export declare function runCanary(aliases: readonly string[], verifyOne: (alias: string) => Promise<Omit<CanaryNodeResult, "alias" | "ms">>, now?: () => number): Promise<CanarySummary>;
20
+ export declare function formatCanarySummary(s: CanarySummary): string;
@@ -0,0 +1,53 @@
1
+ import type { PreflightFacts, ProcessFact, RolloutFact } from "./codex-lifecycle-preflight";
2
+ export interface FactPrimitives {
3
+ /** tmux pane pid of a session, or null when the session is not running. */
4
+ tmuxPanePid(session: string): number | null;
5
+ /** all pids (Linux /proc); [] elsewhere */
6
+ listPids(): number[];
7
+ procStatPpid(pid: number): number | null;
8
+ procCwd(pid: number): string | null;
9
+ procArgv(pid: number): string[] | null;
10
+ procEnviron(pid: number): Record<string, string> | null;
11
+ /** pid listening on a loopback TCP port, or null (free / unknown) */
12
+ listeningPid(port: number): number | null;
13
+ /** hub roster: alias → node_id, or null when unreachable */
14
+ hubNodeIdFor(alias: string): Promise<string | null>;
15
+ }
16
+ export declare function realPrimitives(opts: {
17
+ hub: string;
18
+ token: string;
19
+ networkId?: string;
20
+ }): FactPrimitives;
21
+ export declare function envFileTokenFingerprint(codexHome: string): string | null;
22
+ /** rollout-*-<threadId>.jsonl under CODEX_HOME/sessions/**;精确后缀匹配,不做前缀/最近猜测。 */
23
+ export declare function findRollouts(codexHome: string, threadId: string | null): RolloutFact[];
24
+ /** 从 pane pid 往下找子孙进程(含自身),按 pid 升序。 */
25
+ export declare function descendants(prim: FactPrimitives, rootPid: number): number[];
26
+ export declare function processFact(prim: FactPrimitives, pid: number): ProcessFact;
27
+ export interface GatherInput {
28
+ alias: string;
29
+ nodeId: string | null;
30
+ nodeDir: string;
31
+ codexHome: string;
32
+ configToken: string | null;
33
+ codexProjectDir: string | null;
34
+ codexThreadId: string | null;
35
+ codexAppServerUrl: string | null;
36
+ sessions: {
37
+ appsrv: string;
38
+ bridge: string;
39
+ tui: string;
40
+ };
41
+ recordedPids: {
42
+ appsrv: number | null;
43
+ bridge: number | null;
44
+ tui: number | null;
45
+ };
46
+ markerUuid: string | null;
47
+ }
48
+ /** ⑨ goals.json → 状态摘要 + 内容指纹。没有文件 = none(没派过目标);有文件但 schema 不认识/读不到 = unknown(restart 必须 STOP)。 */
49
+ export declare function goalsFileState(nodeDir: string): {
50
+ state: "active" | "stalled" | "paused" | "achieved" | "none" | "unknown";
51
+ fingerprint: string | null;
52
+ };
53
+ export declare function gatherCodexFacts(prim: FactPrimitives, input: GatherInput): Promise<PreflightFacts>;
@@ -0,0 +1,91 @@
1
+ import type { ReceiptCheck } from "./codex-lifecycle-receipt.js";
2
+ /** Codex 的 thread id 是 UUIDv7(时间有序);fork 出的新 id 也按 v7 生成,便于按文件名/id 排序时落在源之后。 */
3
+ export declare function uuidV7(nowMs: number, rand: Uint8Array): string;
4
+ /** codex 的 rollout 路径:sessions/YYYY/MM/DD/rollout-YYYY-MM-DDTHH-MM-SS-<id>.jsonl(UTC)。 */
5
+ export declare function forkRolloutPath(codexHome: string, now: Date, threadId: string): string;
6
+ /** CODEX_HOME 里哪些文件随 fork 走。显式白名单;env 文件(含源节点 CommHub token)、历史、sqlite、缓存一律不带。 */
7
+ export declare const FORK_HOME_COPY: readonly {
8
+ name: string;
9
+ required: boolean;
10
+ mode: number;
11
+ }[];
12
+ export declare const FORK_HOME_NEVER_COPY: readonly string[];
13
+ export interface RolloutRewriteResult {
14
+ readonly lines: number;
15
+ readonly bytesIn: number;
16
+ readonly bytesOut: number;
17
+ /** 源 thread id 改写次数(定长,不改字节数)。 */
18
+ readonly replacements: number;
19
+ /** `"cwd":"<源目录>"` 改写次数(session_meta + 每个 turn_context 都带;改成新 workdir,字节数按长度差变化)。 */
20
+ readonly cwdReplacements: number;
21
+ /** = bytesIn + cwdReplacements × (新 cwd 编码长度 − 旧 cwd 编码长度);fork_isolation 用它核对复制没有丢字节。 */
22
+ readonly expectedBytesOut: number;
23
+ }
24
+ /**
25
+ * 流式复制 rollout 并把源 thread id 逐处改成新 id(两者定长 36 字符 → 字节数不变,可作 fork_isolation 的证据)。
26
+ * 第一行校验失败时目标文件不存在(先读第一行再开写)。
27
+ */
28
+ export declare function rewriteRollout(src: string, dst: string, oldId: string, newId: string, cwd?: {
29
+ from: string;
30
+ to: string;
31
+ }): Promise<RolloutRewriteResult>;
32
+ export interface ForkSides {
33
+ readonly source: {
34
+ nodeId: string | null;
35
+ homeReal: string | null;
36
+ threadId: string | null;
37
+ alias: string;
38
+ rolloutInode: number | bigint | null;
39
+ rolloutBytes: number | null;
40
+ };
41
+ readonly target: {
42
+ nodeId: string | null;
43
+ homeReal: string | null;
44
+ threadId: string | null;
45
+ alias: string;
46
+ rolloutInode: number | bigint | null;
47
+ rolloutBytes: number | null;
48
+ envFilePresent: boolean;
49
+ };
50
+ readonly rewrite: RolloutRewriteResult | null;
51
+ }
52
+ /** fork_isolation:身份 / HOME / thread / rollout 文件 / tmux 名五处都不同,且 rollout 是等长复制、没带 token 文件。 */
53
+ export declare function checkForkIsolation(s: ForkSides): ReceiptCheck;
54
+ /** gap 1 — `--workdir` used to have to pre-exist. Create it (recursively) when missing; still refuse a path that exists
55
+ * but is not a directory. Returns whether this call created it, so the receipt can say so. */
56
+ export declare function ensureForkWorkdir(path: string): {
57
+ created: boolean;
58
+ };
59
+ /**
60
+ * gap 2 — codex records trust per workspace as `[projects."<abs path>"]` tables in config.toml. A copied config still
61
+ * names the **source** workspace, so the target keeps trusting (and, in the TUI, offering) the wrong directory.
62
+ * Rewrite only the table headers whose quoted path equals `from`, to `to`; every other line is left byte-identical.
63
+ * If a `[projects."<to>"]` table already exists, the source table is dropped instead of duplicated (TOML forbids
64
+ * defining a table twice). Line-aware on purpose: no global substitution of the path string elsewhere in the file.
65
+ */
66
+ export declare function rewriteTrustedProjects(toml: string, from: string, to: string): {
67
+ text: string;
68
+ rewritten: number;
69
+ dropped: number;
70
+ };
71
+ /**
72
+ * gap 3 — the last `turn_context` in a rollout names the model (and provider) the source ran on; codex resumes with
73
+ * that unless the target config says otherwise. Read it from the tail of the file (rollouts reach hundreds of MB;
74
+ * never load the whole thing) so `fork --model` can warn when the override differs.
75
+ */
76
+ export declare function readLastTurnContextModel(rolloutPath: string, tailBytes?: number): {
77
+ model: string | null;
78
+ provider: string | null;
79
+ };
80
+ /** What the fork receipt records for the #1951 gaps, as one informational check (never blocks; `port` is the
81
+ * loopback port pre-assigned for the app-server, first start uses it as its preferred port and re-probes if taken). */
82
+ export interface ForkGapFacts {
83
+ readonly workdir_created: boolean;
84
+ readonly trusted_rewritten: number;
85
+ readonly trusted_dropped: number;
86
+ readonly model_override: string | null;
87
+ readonly source_last_model: string | null;
88
+ readonly port: number | null;
89
+ readonly agents_md_carried: boolean;
90
+ }
91
+ export declare function forkGapsCheck(f: ForkGapFacts): ReceiptCheck;