@sleep2agi/agent-network 2.3.0-preview.13 → 2.3.0-preview.131

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 (135) 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-exit.d.ts +11 -0
  18. package/dist/src/cli-version-display.d.ts +16 -0
  19. package/dist/src/client-task-trace.d.ts +9 -0
  20. package/dist/src/client.js +1 -1
  21. package/dist/src/codex-auth-fingerprint.d.ts +211 -0
  22. package/dist/src/codex-copresence-model.d.ts +23 -0
  23. package/dist/src/codex-copresence-preflight.d.ts +65 -0
  24. package/dist/src/codex-copresence-profile.d.ts +125 -0
  25. package/dist/src/codex-copresence-recovery.d.ts +58 -0
  26. package/dist/src/codex-copresence-thread.d.ts +13 -0
  27. package/dist/src/codex-home-enforce.d.ts +71 -0
  28. package/dist/src/codex-lifecycle-account.d.ts +104 -0
  29. package/dist/src/codex-lifecycle-canary.d.ts +20 -0
  30. package/dist/src/codex-lifecycle-facts.d.ts +53 -0
  31. package/dist/src/codex-lifecycle-fork.d.ts +91 -0
  32. package/dist/src/codex-lifecycle-preflight.d.ts +77 -0
  33. package/dist/src/codex-lifecycle-receipt.d.ts +44 -0
  34. package/dist/src/codex-lifecycle-restart.d.ts +86 -0
  35. package/dist/src/codex-login-share-guard.d.ts +146 -0
  36. package/dist/src/codex-model-default.d.ts +6 -0
  37. package/dist/src/codex-tui-client-health.d.ts +30 -0
  38. package/dist/src/commhub-response.d.ts +1 -0
  39. package/dist/src/controlled-upload.d.ts +83 -0
  40. package/dist/src/copresence-deps.d.ts +22 -0
  41. package/dist/src/copresence-identity.d.ts +353 -0
  42. package/dist/src/copresence-startup-diagnosis.d.ts +17 -0
  43. package/dist/src/daemon-anet-bin.d.ts +32 -0
  44. package/dist/src/daemon-capability-display.d.ts +110 -0
  45. package/dist/src/daemon-capability-display.js +21 -0
  46. package/dist/src/daemon-runtime-path-preflight.d.ts +22 -0
  47. package/dist/src/daemon-runtime-staleness.d.ts +13 -0
  48. package/dist/src/dashboard-managed-process.d.ts +35 -0
  49. package/dist/src/display-width.d.ts +27 -0
  50. package/dist/src/doctor-node-count.d.ts +28 -0
  51. package/dist/src/environ-alias.d.ts +14 -0
  52. package/dist/src/grok-attach-client.d.ts +129 -0
  53. package/dist/src/grok-build-drift.d.ts +15 -0
  54. package/dist/src/grok-copresence-disclosure.d.ts +11 -0
  55. package/dist/src/grok-copresence-orchestration.d.ts +75 -0
  56. package/dist/src/grok-copresence-profile.d.ts +65 -0
  57. package/dist/src/grok-create-mode.d.ts +19 -0
  58. package/dist/src/host-telemetry.d.ts +14 -0
  59. package/dist/src/hub-health-timeout.d.ts +4 -0
  60. package/dist/src/hub-server-version.d.ts +64 -0
  61. package/dist/src/hub-stop.d.ts +74 -0
  62. package/dist/src/hub-time-display.d.ts +20 -0
  63. package/dist/src/hub-version-skew.d.ts +19 -0
  64. package/dist/src/im/correlation-store.d.ts +34 -0
  65. package/dist/src/im/feishu/adapter.d.ts +80 -0
  66. package/dist/src/im/feishu/bridge.d.ts +78 -14
  67. package/dist/src/im/feishu/config.d.ts +31 -0
  68. package/dist/src/im/feishu/hub-upload.d.ts +88 -0
  69. package/dist/src/im/feishu/outbound-route.d.ts +62 -0
  70. package/dist/src/im/feishu/worker-lifecycle.d.ts +13 -0
  71. package/dist/src/im/feishu/worker.js +187 -144
  72. package/dist/src/im/types.d.ts +30 -1
  73. package/dist/src/inbox-drain.d.ts +20 -0
  74. package/dist/src/local-process-state.d.ts +12 -0
  75. package/dist/src/locale-diagnostic.d.ts +12 -0
  76. package/dist/src/login-client-label.d.ts +6 -0
  77. package/dist/src/ls-columns.d.ts +15 -0
  78. package/dist/src/mock-llm.d.ts +12 -0
  79. package/dist/src/node-activity-log.d.ts +4 -0
  80. package/dist/src/node-clone.d.ts +134 -0
  81. package/dist/src/node-files.d.ts +62 -0
  82. package/dist/src/node-not-found.d.ts +1 -0
  83. package/dist/src/node-running-guard.d.ts +9 -0
  84. package/dist/src/node-server-identity.d.ts +35 -0
  85. package/dist/src/node-server-payload.d.ts +66 -0
  86. package/dist/src/node-server-rules-file.d.ts +14 -0
  87. package/dist/src/node-server.js +7 -1
  88. package/dist/src/node-skills.d.ts +32 -0
  89. package/dist/src/normalize-runtime.d.ts +29 -2
  90. package/dist/src/offline-age.d.ts +29 -0
  91. package/dist/src/one-line-cell.d.ts +20 -0
  92. package/dist/src/opencode-agent-node-pair.d.ts +25 -0
  93. package/dist/src/opencode-auth-login.d.ts +43 -0
  94. package/dist/src/opencode-launch-env.d.ts +13 -0
  95. package/dist/src/opencode-owner-mode.d.ts +6 -0
  96. package/dist/src/opencode-package-binary.d.ts +26 -0
  97. package/dist/src/opencode-pin.d.ts +44 -0
  98. package/dist/src/opencode-preset.d.ts +73 -0
  99. package/dist/src/opencode-runtime-binding.d.ts +30 -0
  100. package/dist/src/opencode-safe-root.d.ts +36 -0
  101. package/dist/src/opencode-smoke-env.d.ts +1 -0
  102. package/dist/src/outbound-attachments.d.ts +60 -0
  103. package/dist/src/outbound-tool-names.d.ts +1 -0
  104. package/dist/src/owned-roots.d.ts +58 -0
  105. package/dist/src/owner-env-file.d.ts +2 -0
  106. package/dist/src/package-mode-preflight.d.ts +41 -0
  107. package/dist/src/posix-codex-copresence.d.ts +35 -0
  108. package/dist/src/posix-modes.d.ts +36 -0
  109. package/dist/src/primary-network.d.ts +23 -0
  110. package/dist/src/private-state.d.ts +10 -0
  111. package/dist/src/process-telemetry.d.ts +12 -0
  112. package/dist/src/profile-serialize.d.ts +1 -0
  113. package/dist/src/project-key.d.ts +1 -0
  114. package/dist/src/reply-local-links.d.ts +47 -0
  115. package/dist/src/reply-originator.d.ts +20 -0
  116. package/dist/src/resume-runtime-infer.d.ts +18 -0
  117. package/dist/src/rules-file.d.ts +53 -0
  118. package/dist/src/secret-shell-guidance.d.ts +3 -0
  119. package/dist/src/session-status-class.d.ts +48 -0
  120. package/dist/src/sibling-agent-node.d.ts +23 -0
  121. package/dist/src/stale-socket.d.ts +118 -0
  122. package/dist/src/subcommand-redirect.d.ts +26 -0
  123. package/dist/src/task-trace.d.ts +33 -0
  124. package/dist/src/tmux-attach.d.ts +8 -0
  125. package/dist/src/tmux-capability.d.ts +58 -0
  126. package/dist/src/tmux-exact-target.d.ts +34 -0
  127. package/dist/src/tmux-pane-prompt.d.ts +22 -0
  128. package/dist/src/tmux.d.ts +44 -0
  129. package/dist/src/token-cli.d.ts +13 -0
  130. package/dist/src/tool-allowlist.d.ts +28 -0
  131. package/dist/src/unsafe-package-path-reason.d.ts +17 -0
  132. package/dist/src/upgrade-channel.d.ts +31 -0
  133. package/dist/src/win-launcher.d.ts +20 -0
  134. package/dist/src/windows-codex-copresence.d.ts +60 -0
  135. package/package.json +11 -6
@@ -0,0 +1,77 @@
1
+ import type { ReceiptCheck } from "./codex-lifecycle-receipt";
2
+ export interface RolloutFact {
3
+ readonly path: string;
4
+ readonly inode: number | bigint;
5
+ readonly bytes: number;
6
+ readonly mtimeMs: number;
7
+ }
8
+ export interface ProcessFact {
9
+ readonly pid: number;
10
+ readonly cwd: string | null;
11
+ /** 子进程实际环境里的 CODEX_HOME(不是 wrapper 继承的那份 —— wrapper 环境不能作承重证据)。 */
12
+ readonly codexHome: string | null;
13
+ /** 子进程实际环境里 CommHub token 的短指纹;null = 没读到或该进程不该持有。 */
14
+ readonly tokenFingerprint: string | null;
15
+ /** 子进程环境里的 ANET_NODE_MARKER(copresence-identity 的身份 uuid);null = 没有。 */
16
+ readonly markerUuid: string | null;
17
+ readonly argv: readonly string[];
18
+ }
19
+ export interface PreflightFacts {
20
+ readonly alias: string;
21
+ readonly configNodeId: string | null;
22
+ /** hub 名册按 alias 精确查到的 node_id;null = hub 不可达或没这个 alias。 */
23
+ readonly hubNodeId: string | null;
24
+ readonly home: {
25
+ readonly dir: string;
26
+ readonly dirMode: number | null;
27
+ readonly authMode: number | null;
28
+ readonly authBytes: number | null;
29
+ readonly configTokenFingerprint: string | null;
30
+ readonly envFileTokenFingerprint: string | null;
31
+ };
32
+ readonly workdir: {
33
+ readonly configProjectDir: string | null;
34
+ readonly tuiCwd: string | null;
35
+ readonly tuiArgvDir: string | null;
36
+ readonly bridgeProjectDir: string | null;
37
+ readonly statusBarDir: string | null;
38
+ };
39
+ readonly session: {
40
+ readonly threadId: string | null;
41
+ /** CODEX_HOME 里文件名以 <threadId>.jsonl 结尾的 rollout 全集。 */
42
+ readonly rolloutMatches: readonly RolloutFact[];
43
+ };
44
+ readonly port: {
45
+ readonly port: number | null;
46
+ readonly owner: ProcessFact | null;
47
+ };
48
+ readonly topology: {
49
+ /** copresence-identity.json 里的身份 uuid;null = 没有 marker 文件。 */
50
+ readonly markerUuid: string | null;
51
+ /** marker 里记的 pid(采集时的观测提示,**不是**身份来源)与现在 tmux pane 的 pid。 */
52
+ readonly recorded: Readonly<Record<"appsrv" | "bridge" | "tui", number | null>>;
53
+ readonly live: Readonly<Record<"appsrv" | "bridge" | "tui", number | null>>;
54
+ /** 每个 tmux 段下带环境的子进程各自的 ANET_NODE_MARKER。 */
55
+ readonly liveMarkers: Readonly<Record<"appsrv" | "bridge" | "tui", readonly (string | null)[]>>;
56
+ /** 每个 tmux 段下带环境的子进程各自的 CODEX_HOME(realpath)。 */
57
+ readonly liveHomes: Readonly<Record<"appsrv" | "bridge" | "tui", readonly (string | null)[]>>;
58
+ };
59
+ readonly goal: {
60
+ readonly state: "active" | "stalled" | "paused" | "achieved" | "none" | "unknown";
61
+ };
62
+ readonly children: readonly ProcessFact[];
63
+ readonly expectedTokenFingerprint: string | null;
64
+ }
65
+ export declare function checkIdentity(f: PreflightFacts): ReceiptCheck;
66
+ export declare function checkHome(f: PreflightFacts): ReceiptCheck;
67
+ export declare function checkWorkdir(f: PreflightFacts): ReceiptCheck;
68
+ export declare function checkSession(f: PreflightFacts): ReceiptCheck;
69
+ export declare function rolloutSnapshot(f: PreflightFacts): ReceiptCheck;
70
+ export declare function compareRollout(before: RolloutFact, after: RolloutFact | null): ReceiptCheck;
71
+ export declare function checkPortOwner(f: PreflightFacts): ReceiptCheck;
72
+ export declare function checkChildEnv(f: PreflightFacts): ReceiptCheck;
73
+ export declare function checkGoalState(f: PreflightFacts): ReceiptCheck;
74
+ export declare function checkTopology(f: PreflightFacts): ReceiptCheck;
75
+ export declare function evaluateCodexPreflight(f: PreflightFacts): ReceiptCheck[];
76
+ /** verify = preflight + 子进程环境 + 跨节点身份验收(identity_attested 由调用方注入;PR-A 里没有探针时给 unknown)。 */
77
+ export declare function evaluateCodexVerify(f: PreflightFacts, identityAttested: ReceiptCheck): ReceiptCheck[];
@@ -0,0 +1,44 @@
1
+ export type CheckStatus = "pass" | "fail" | "unknown";
2
+ export interface ReceiptCheck {
3
+ readonly key: string;
4
+ readonly status: CheckStatus;
5
+ /** 一句人话:pass 说核到了什么,fail 说差在哪,unknown 说为什么量不到。 */
6
+ readonly detail: string;
7
+ /** 可复核的证据(路径、inode、字节数、短指纹……);不得含凭据。 */
8
+ readonly evidence?: Readonly<Record<string, unknown>>;
9
+ }
10
+ export type LifecycleVerb = "preflight" | "verify" | "start" | "restart" | "resume" | "fork" | "account-install" | "rollback";
11
+ export interface LifecycleReceipt {
12
+ readonly format: "anet-codex-lifecycle-receipt/1";
13
+ readonly id: string;
14
+ readonly verb: LifecycleVerb;
15
+ readonly alias: string;
16
+ readonly nodeId: string | null;
17
+ readonly startedAt: string;
18
+ readonly finishedAt: string;
19
+ readonly verdict: "PASS" | "FAIL";
20
+ /** FAIL 时阻塞的 check key(fail 与 unknown 都算)。 */
21
+ readonly blocking: readonly string[];
22
+ readonly checks: readonly ReceiptCheck[];
23
+ }
24
+ /** 每个动词要求哪些 check 必须 pass。preflight 只读,不要求 identity_attested(那是 verify 的活)。 */
25
+ export declare const REQUIRED_CHECKS: Readonly<Record<LifecycleVerb, readonly string[]>>;
26
+ export declare function shortFingerprint(value: string | undefined | null, length?: number): string | null;
27
+ export declare function redactReceipt<T>(value: T, key?: string): T;
28
+ export declare const INFORMATIONAL_PREFIXES: readonly string[];
29
+ export declare function receiptVerdict(verb: LifecycleVerb, checks: readonly ReceiptCheck[]): {
30
+ verdict: "PASS" | "FAIL";
31
+ blocking: string[];
32
+ };
33
+ export declare function buildReceipt(opts: {
34
+ verb: LifecycleVerb;
35
+ alias: string;
36
+ nodeId: string | null;
37
+ startedAt: Date;
38
+ finishedAt?: Date;
39
+ checks: readonly ReceiptCheck[];
40
+ }): LifecycleReceipt;
41
+ /** receipts 落在节点目录下 receipts/<id>.json,0600,先写临时文件再 rename(原子)。返回绝对路径。 */
42
+ export declare function writeReceipt(nodeDir: string, receipt: LifecycleReceipt): string;
43
+ /** 终端摘要:一行一 check,PASS/FAIL 在最后;不打印 evidence 里的长值。 */
44
+ export declare function formatReceiptSummary(receipt: LifecycleReceipt): string;
@@ -0,0 +1,86 @@
1
+ /**
2
+ * #1856 PR-B — `anet node codex start|restart|resume` 的确定性状态机。
3
+ *
4
+ * 零 LLM:每一步是「读事实 → 判 → 动作 → 写 receipt check」,顺序固定;所有副作用都经 `RestartActions`
5
+ * 注入,所以这个文件可以在纯单测里跑完整个流程(含失败与回滚分支)。
6
+ *
7
+ * 停:Bridge → TUI → App Server(反向于依赖:先断任务入口,再让 TUI 把 rollout 刷完,最后放掉端口)。
8
+ * 起:交给 `anet node start <alias> --copresence --tui-first`(App Server → 端口就绪 → exact-session
9
+ * TUI 完全恢复 → Bridge),再用 preflight/verify 复核 —— 起的顺序由启动器保证,这里只验证结果。
10
+ * 任一步 fail → 不再往下;若已停掉进程则尝试一次「回滚」= 按原配置再起一次;仍失败就留在已停状态,
11
+ * receipt 记录到哪一步、为什么,exit 2。绝不猜、绝不 fallback 到别的线程。
12
+ */
13
+ import type { ReceiptCheck } from "./codex-lifecycle-receipt.js";
14
+ import type { RolloutFact } from "./codex-lifecycle-preflight.js";
15
+ export type RestartVerb = "start" | "restart" | "resume";
16
+ export type GoalState = "active" | "paused" | "stalled" | "achieved" | "none" | "unknown";
17
+ export type CopresenceRole = "bridge" | "tui" | "appsrv";
18
+ export interface GateResult {
19
+ /** 该阶段所有 check(preflight 或 verify 的输出)。 */
20
+ readonly checks: readonly ReceiptCheck[];
21
+ /** 该阶段 rollout 快照(session_exact 通过时才有)。 */
22
+ readonly rollout: RolloutFact | null;
23
+ /** 端口占用者(null = 空闲)。 */
24
+ readonly port: {
25
+ readonly port: number | null;
26
+ readonly ownerPid: number | null;
27
+ readonly ownerIsOurs: boolean | null;
28
+ };
29
+ }
30
+ export interface RestartActions {
31
+ /** 只读核对(PR-A 的 preflight;`after` 阶段可带 identity_attested 变 verify)。 */
32
+ gate(phase: "before" | "after"): Promise<GateResult>;
33
+ /** goals.json 的状态摘要 + 内容指纹(unknown = 读不到/不认识的 schema)。 */
34
+ goalState(): Promise<{
35
+ state: GoalState;
36
+ fingerprint: string | null;
37
+ }>;
38
+ /** 三个 tmux 会话谁还活着。 */
39
+ liveSessions(): Promise<Readonly<Record<CopresenceRole, boolean>>>;
40
+ /** 杀掉一个角色的 tmux 会话并等它消失;ok=false 时 detail 说为什么。 */
41
+ stopSession(role: CopresenceRole): Promise<{
42
+ ok: boolean;
43
+ detail: string;
44
+ }>;
45
+ /** 等 rollout 文件字节数稳定(TUI 退出后大 rollout 还在刷盘);返回最终快照。 */
46
+ waitRolloutSettled(before: RolloutFact | null): Promise<RolloutFact | null>;
47
+ /** 等端口空闲;超时仍被占用时给出占用者 pid 与「是不是我们自己的 app-server」。 */
48
+ waitPortFree(): Promise<{
49
+ free: boolean;
50
+ ownerPid: number | null;
51
+ ownerIsOurs: boolean | null;
52
+ }>;
53
+ /** 对已核实属于本节点的残留 pid 发 TERM(定向,绝不 pkill -f)。 */
54
+ termOwnedPid(pid: number): Promise<{
55
+ ok: boolean;
56
+ detail: string;
57
+ }>;
58
+ /** 跑启动器(`anet node start --copresence --tui-first`);ok=false 时 detail 是它的尾部输出。 */
59
+ start(): Promise<{
60
+ ok: boolean;
61
+ detail: string;
62
+ }>;
63
+ /** hub 上该 node_id 是否在超时内回到 online/idle。 */
64
+ waitHubOnline(): Promise<{
65
+ ok: boolean;
66
+ detail: string;
67
+ }>;
68
+ /** 跨节点 nonce 探针;未配置时返回 undefined(check 记 unknown)。 */
69
+ nonceProbe?: () => Promise<{
70
+ ok: boolean;
71
+ detail: string;
72
+ evidence?: Record<string, unknown>;
73
+ }>;
74
+ }
75
+ export interface RestartOutcome {
76
+ readonly verb: RestartVerb;
77
+ readonly checks: readonly ReceiptCheck[];
78
+ /** 走到哪一步停下(PASS 时 = "done")。 */
79
+ readonly stoppedAt: string;
80
+ readonly rolledBack: boolean;
81
+ }
82
+ /** before 阶段的门:required 里不许有 fail;unknown 允许(要重启的节点常常就是缺了一截进程)。 */
83
+ export declare function beforeGateBlocks(checks: readonly ReceiptCheck[]): string[];
84
+ /** 三个角色按依赖反向停;返回 stop_order check(顺序本身就是证据)。 */
85
+ export declare function orderedStop(actions: RestartActions, live: Readonly<Record<CopresenceRole, boolean>>): Promise<ReceiptCheck>;
86
+ export declare function runCodexRestart(verb: RestartVerb, actions: RestartActions): Promise<RestartOutcome>;
@@ -0,0 +1,146 @@
1
+ /** The explicit, documented-as-unsafe override. Spelled once so help, messages and tests agree. */
2
+ export declare const ALLOW_SHARED_CODEX_LOGIN_FLAG = "--allow-shared-codex-login";
3
+ /** Per-node record of where the node's codex credential came from. */
4
+ export declare const CODEX_AUTH_ORIGIN_FILE = ".codex-auth-origin.json";
5
+ /** Host-index filename for a node's origin record: same directory-derived key as
6
+ * #1918's record, different suffix, so neither overwrites the other. */
7
+ export declare function codexOriginIndexFile(nodeDir: string): string;
8
+ export type CodexLoginSource = {
9
+ kind: "host";
10
+ path: string;
11
+ } | {
12
+ kind: "fork";
13
+ sourceAlias: string;
14
+ } | {
15
+ kind: "account";
16
+ profileId: string;
17
+ };
18
+ export interface CodexLoginHolder {
19
+ readonly alias: string;
20
+ /** Canonical node directory — the identity. */
21
+ readonly nodeDir: string;
22
+ /** "current": its last published fingerprint; "origin": the credential it was given. */
23
+ readonly via: "current" | "origin";
24
+ }
25
+ /**
26
+ * Fingerprint of an auth.json on disk, or null when there is none or it carries
27
+ * no refresh token (an API-key login does not rotate, so sharing it is not this
28
+ * failure). The text is hashed and dropped; nothing here returns or logs it.
29
+ */
30
+ export declare function codexLoginFingerprintOfFile(authJsonPath: string): string | null;
31
+ export interface FindHoldersOptions {
32
+ readonly fingerprint: string;
33
+ /** The node being given the credential — excluded from the result. */
34
+ readonly selfNodeDir: string;
35
+ /** Injected for tests; production uses the host index under ~/.anet. */
36
+ readonly indexDir?: string;
37
+ /** `.anet/nodes` roots to scan besides the host index. Default: the parent of selfNodeDir. */
38
+ readonly siblingRoots?: readonly string[];
39
+ }
40
+ /**
41
+ * Every OTHER node on this host whose published fingerprint, or recorded
42
+ * credential origin, equals `fingerprint`. Read-only: it never deletes, never
43
+ * writes, and never opens another node's auth.json.
44
+ *
45
+ * A record whose node directory no longer exists describes a node that is
46
+ * gone and is ignored (#1918's liveness rule: existence, not age).
47
+ */
48
+ export declare function findCodexLoginHolders(opts: FindHoldersOptions): CodexLoginHolder[];
49
+ export interface StagingDecisionInput {
50
+ /** The node that would receive the credential. */
51
+ readonly alias: string;
52
+ /** Its codex-home — named in the fix instruction. */
53
+ readonly targetCodexHome: string;
54
+ /** Fingerprint of the credential about to be handed over; null = not a rotating login. */
55
+ readonly fingerprint: string | null;
56
+ readonly holders: readonly CodexLoginHolder[];
57
+ readonly source: CodexLoginSource;
58
+ readonly allowShared: boolean;
59
+ /** Extra "how to fix" line for this command (e.g. fork's --no-codex-login). */
60
+ readonly extraFix?: readonly string[];
61
+ }
62
+ export type StagingDecision = {
63
+ readonly kind: "ok";
64
+ readonly lines: string[];
65
+ } | {
66
+ readonly kind: "refuse";
67
+ readonly lines: string[];
68
+ } | {
69
+ readonly kind: "override";
70
+ readonly lines: string[];
71
+ };
72
+ /**
73
+ * Decide whether handing this credential to this node is allowed, and the exact
74
+ * text to print. Pure — the callers own the I/O and the exit code (1, per #2321).
75
+ */
76
+ export declare function decideCodexLoginStaging(i: StagingDecisionInput): StagingDecision;
77
+ export interface RecordOriginOptions {
78
+ readonly nodeDir: string;
79
+ readonly alias: string;
80
+ readonly fingerprint: string;
81
+ readonly source: CodexLoginSource;
82
+ readonly indexDir?: string;
83
+ readonly now?: Date;
84
+ }
85
+ /**
86
+ * Record which credential a node was handed (8-hex fingerprint + where from).
87
+ * Best effort: a failure is returned as a message, never thrown — a node must
88
+ * not fail to start because bookkeeping failed.
89
+ */
90
+ export declare function recordCodexLoginOrigin(o: RecordOriginOptions): string | null;
91
+ export interface SharedLoginGroup {
92
+ /** 8-hex refresh fingerprint — not a credential. */
93
+ readonly fingerprint: string;
94
+ readonly aliases: string[];
95
+ }
96
+ /**
97
+ * For `anet doctor`: groups of ≥2 live nodes whose CURRENT published
98
+ * fingerprint is the same. Read-only; aliases only.
99
+ */
100
+ export declare function sharedCodexLoginGroups(opts?: {
101
+ indexDir?: string;
102
+ nodeRoots?: readonly string[];
103
+ }): SharedLoginGroup[];
104
+ export interface EvaluateStagingOptions {
105
+ /** The node that would receive the credential (may not exist yet, e.g. a fork target). */
106
+ readonly nodeDir: string;
107
+ readonly alias: string;
108
+ readonly targetCodexHome: string;
109
+ /** The auth.json about to be copied. Read only to hash it. */
110
+ readonly sourceAuthPath: string;
111
+ readonly source: CodexLoginSource;
112
+ readonly allowShared: boolean;
113
+ readonly extraFix?: readonly string[];
114
+ /** Holders known without any record — a fork's source node always holds its own login. */
115
+ readonly knownHolders?: readonly CodexLoginHolder[];
116
+ readonly indexDir?: string;
117
+ readonly siblingRoots?: readonly string[];
118
+ }
119
+ export type EvaluatedStaging = StagingDecision & {
120
+ readonly fingerprint: string | null;
121
+ readonly holders: readonly CodexLoginHolder[];
122
+ };
123
+ /**
124
+ * Fingerprint → holders → decision, in one call, for every staging path.
125
+ * Writes nothing; the caller records the origin once the credential has
126
+ * actually been handed over (see recordCodexLoginOrigin).
127
+ */
128
+ export declare function evaluateCodexLoginStaging(o: EvaluateStagingOptions): EvaluatedStaging;
129
+ /**
130
+ * `anet node codex fork --no-codex-login` deliberately leaves the target without
131
+ * a credential, and home_isolated would fail on exactly that. The caller runs
132
+ * the real check with the credential treated as present (so every OTHER rule —
133
+ * directory mode, CommHub token, env-file token — is still evaluated) and passes
134
+ * the result here: a pass is re-worded to say what is still owed, a failure
135
+ * stays the failure it is.
136
+ */
137
+ export declare function homeCheckPendingOwnLogin<C extends {
138
+ status: string;
139
+ detail: string;
140
+ }>(checkAssumingLogin: C, codexHome: string): C;
141
+ /** The step of a host stage plan that newly hands a node a login: auth.json where the node has none.
142
+ * A "host-newer" re-stage is an existing node and is not gated (it still gets the #1918 warning). */
143
+ export declare function newLoginStep<T extends {
144
+ name: string;
145
+ reason: string;
146
+ }>(plan: readonly T[]): T | undefined;
@@ -0,0 +1,6 @@
1
+ export declare const DEFAULT_CODEX_MODEL = "gpt-5.6-sol";
2
+ export declare const CODEX_MODEL_CHOICES: ReadonlyArray<{
3
+ readonly id: string;
4
+ readonly default?: boolean;
5
+ }>;
6
+ export declare function defaultCodexModelForRuntime(runtime: string): string | undefined;
@@ -0,0 +1,30 @@
1
+ export declare function bridgeClientHealthReceipt(remote: string, threadId: string): string;
2
+ export interface MigratedCodexPendingThread {
3
+ version: 1;
4
+ threadId: string;
5
+ serverUrl: string;
6
+ marker: string;
7
+ }
8
+ /**
9
+ * Move a crash-window deferred candidate onto the launcher's new owned
10
+ * app-server generation. The old URL is an authority supplied by the same
11
+ * private node config, not by the pending object itself; every mismatch is a
12
+ * hard stop so restart never guesses or adopts a second thread.
13
+ */
14
+ export declare function migrateCodexPendingThread(value: unknown, oldServerUrl: unknown, expectedOldMarker: unknown, newServerUrl: string, newMarker: string): MigratedCodexPendingThread;
15
+ export declare function requirePromotedCodexPendingThread(value: unknown, pendingThreadId: string): string;
16
+ /**
17
+ * argv for the human TUI attached to the co-presence app-server.
18
+ *
19
+ * #505 — the permission override is only passed on the FRESH path. On
20
+ * `resume --remote <ws> <thread>` codex 0.155.1 exits immediately with
21
+ * "Error: Permission overrides are not supported when resuming a remote task."
22
+ * (anet then reports "TUI tmux session exited during startup"). Measured in
23
+ * Docker against a real app-server + real thread: 0.155.1 rejects
24
+ * resume + --dangerously-bypass-approvals-and-sandbox and accepts it fresh
25
+ * (TUI up, "permissions: YOLO mode"); 0.133.0 (agent-node's pin) accepts both.
26
+ * Nothing is lost by dropping it on resume: the app-server itself is started
27
+ * with `-c approval_policy=… -c sandbox_mode=…` from the same posture.
28
+ */
29
+ export declare function codexTuiLaunchArgs(remote: string, model: string, threadId?: string, dangerFullAccess?: boolean): string[];
30
+ export declare function assertPendingServerQuiesced(serverUrl: unknown, isListening: (port: number) => boolean | Promise<boolean>): Promise<void>;
@@ -0,0 +1 @@
1
+ export declare function parseCommhubToolResult(json: any): any;
@@ -0,0 +1,83 @@
1
+ /**
2
+ * #693 — token-bound node controlled local file → Hub /api/upload bridge.
3
+ *
4
+ * Security boundary (hard gates):
5
+ * 1. Cross-host: bytes travel over HTTP multipart; Hub never reads agent FS.
6
+ * 2. Identity: caller supplies the node's bearer token; ntok binds network.
7
+ * 3. Path safety: realpath + allowlisted roots; reject NUL, symlink, traversal.
8
+ * 4. Size ≤ 12 MiB enforced with same-fd fstat + bounded read (no full slurp).
9
+ * 5. Hub /api/upload is the sole write surface (atomic on hub side).
10
+ *
11
+ * Adversarial add-only (#694 DO-NOT-MERGE fixes):
12
+ * - TOCTOU: open O_NOFOLLOW → fstat(fd) → read(fd) only; no re-open by path.
13
+ * - Bounded read: never allocate/read past CONTROLLED_UPLOAD_MAX_BYTES.
14
+ * - NUL guard is live and reachable before any fs call.
15
+ */
16
+ /** Mirrors server/src/uploads.ts MAX_UPLOAD_BYTES. */
17
+ export declare const CONTROLLED_UPLOAD_MAX_BYTES: number;
18
+ /** Chunk size for bounded streaming read from a single fd. */
19
+ export declare const CONTROLLED_UPLOAD_READ_CHUNK: number;
20
+ export type ControlledUploadErrorCode = "path_required" | "path_nul" | "path_not_found" | "path_untrusted" | "path_symlink" | "path_not_regular" | "path_empty" | "payload_too_large" | "read_failed" | "auth_required" | "hub_url_required" | "upload_failed" | "bad_response" | "missing_file_id";
21
+ export type ControlledUploadFail = {
22
+ ok: false;
23
+ error: ControlledUploadErrorCode;
24
+ message: string;
25
+ };
26
+ export type ControlledUploadOk = {
27
+ ok: true;
28
+ file_id: string;
29
+ name: string;
30
+ mime: string;
31
+ size: number;
32
+ url?: string;
33
+ };
34
+ export type ControlledUploadResult = ControlledUploadOk | ControlledUploadFail;
35
+ export interface ControlledUploadDeps {
36
+ hubUrl: string;
37
+ authToken: string;
38
+ allowedRoots?: string[];
39
+ alias?: string;
40
+ nodeDir?: string;
41
+ fetch?: typeof fetch;
42
+ home?: string;
43
+ }
44
+ /** Normalize a client filename: basename only, strip controls, cap 255. */
45
+ export declare function normalizeUploadName(input: string | undefined | null, fallback?: string): string;
46
+ export declare function defaultControlledUploadRoots(opts?: {
47
+ home?: string;
48
+ alias?: string;
49
+ nodeDir?: string;
50
+ cwd?: string;
51
+ env?: NodeJS.ProcessEnv;
52
+ }): string[];
53
+ /** True iff canonicalPath is strictly inside one of the allowlisted roots. */
54
+ export declare function isPathInsideAllowedRoots(canonicalPath: string, allowedRoots: string[]): boolean;
55
+ /**
56
+ * Resolve a user-supplied path to a canonical path under an allowlisted root.
57
+ * Does not open the file for reading — open+fstat+read is a separate same-fd step.
58
+ */
59
+ export declare function resolveControlledUploadPath(rawPath: string, allowedRoots: string[]): {
60
+ ok: true;
61
+ canonicalPath: string;
62
+ } | ControlledUploadFail;
63
+ export type ControlledFileBytes = {
64
+ ok: true;
65
+ bytes: Buffer;
66
+ size: number;
67
+ canonicalPath: string;
68
+ } | ControlledUploadFail;
69
+ /**
70
+ * Open → fstat(fd) → bounded read(fd) on the **same fd** (TOCTOU hard gate).
71
+ * Uses O_NOFOLLOW when available so a symlink swap at open is rejected.
72
+ * Never uses path-based readFileSync after the initial open.
73
+ */
74
+ export declare function openFstatBoundedReadControlledFile(canonicalPath: string, allowedRoots: string[], maxBytes?: number): ControlledFileBytes;
75
+ /**
76
+ * Upload a controlled local file to Hub POST /api/upload.
77
+ * Returns file_id + metadata for send_reply attachments.
78
+ * Never falls back to sending a raw path to the Hub.
79
+ */
80
+ export declare function uploadControlledLocalFile(rawPath: string, deps: ControlledUploadDeps, opts?: {
81
+ name?: string;
82
+ mime?: string;
83
+ }): Promise<ControlledUploadResult>;
@@ -0,0 +1,22 @@
1
+ export interface CopresenceDep {
2
+ readonly name: string;
3
+ readonly present: boolean;
4
+ /** Exact command for this platform, or null when we cannot name one. */
5
+ readonly install: string | null;
6
+ readonly why: string;
7
+ }
8
+ export type CommandProbe = (cmd: string) => boolean;
9
+ /** Which agent binary this co-presence lane is built on. */
10
+ export type CopresenceAgent = "codex" | "grok";
11
+ export declare function copresenceDeps(probe: CommandProbe, platform?: NodeJS.Platform, agent?: CopresenceAgent): CopresenceDep[];
12
+ export declare function missingCopresenceDeps(probe: CommandProbe, platform?: NodeJS.Platform, agent?: CopresenceAgent): CopresenceDep[];
13
+ /** One block naming every gap and how to close it — never one gap at a time. */
14
+ export declare function describeMissingDeps(missing: readonly CopresenceDep[], displayName: string): string;
15
+ /**
16
+ * May we start this hub ourselves?
17
+ *
18
+ * Only a loopback hub. A remote URL that refuses the connection is somebody
19
+ * else's service — spawning a local one would silently point the node at a
20
+ * DIFFERENT hub than its profile names, which is worse than failing.
21
+ */
22
+ export declare function isLoopbackHub(hubUrl: string): boolean;