@sleep2agi/agent-network 2.3.0-preview.16 → 2.3.0-preview.160
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +35 -324
- package/dist/bin/anet.cjs +101 -0
- package/dist/bin/cli.d.ts +1 -0
- package/dist/bin/cli.js +20 -1
- package/dist/bin/goal-wake-log-render.d.ts +31 -0
- package/dist/src/active-network-task.d.ts +28 -0
- package/dist/src/batch-workdir.d.ts +9 -0
- package/dist/src/bootstrap-password-db.d.ts +13 -0
- package/dist/src/channel-attachments.d.ts +29 -0
- package/dist/src/channel-inbox-wake.d.ts +21 -0
- package/dist/src/channel-meta.d.ts +10 -0
- package/dist/src/channel-peer-reply.d.ts +41 -0
- package/dist/src/channel-task-trace.d.ts +14 -0
- package/dist/src/claude-vendor-env.d.ts +28 -0
- package/dist/src/cli-args.d.ts +8 -0
- package/dist/src/cli-auth-session.d.ts +47 -0
- package/dist/src/cli-errors.d.ts +41 -0
- package/dist/src/cli-exit.d.ts +11 -0
- package/dist/src/cli-help.d.ts +10 -0
- package/dist/src/cli-version-display.d.ts +16 -0
- package/dist/src/client-task-trace.d.ts +9 -0
- package/dist/src/client.js +1 -1
- package/dist/src/codex-adopt.d.ts +46 -0
- package/dist/src/codex-auth-fingerprint.d.ts +211 -0
- package/dist/src/codex-bin-pin.d.ts +23 -0
- package/dist/src/codex-commhub-mcp.d.ts +22 -0
- package/dist/src/codex-copresence-bridge-log.d.ts +44 -0
- package/dist/src/codex-copresence-env.d.ts +5 -0
- package/dist/src/codex-copresence-login-gate.d.ts +16 -0
- package/dist/src/codex-copresence-model.d.ts +23 -0
- package/dist/src/codex-copresence-preflight.d.ts +78 -0
- package/dist/src/codex-copresence-profile.d.ts +125 -0
- package/dist/src/codex-copresence-recovery.d.ts +67 -0
- package/dist/src/codex-copresence-resume-timeout.d.ts +28 -0
- package/dist/src/codex-copresence-rollout-guard.d.ts +36 -0
- package/dist/src/codex-copresence-rpc.d.ts +15 -0
- package/dist/src/codex-copresence-thread.d.ts +13 -0
- package/dist/src/codex-external-appserver.d.ts +128 -0
- package/dist/src/codex-fork-recovery.d.ts +47 -0
- package/dist/src/codex-home-enforce.d.ts +88 -0
- package/dist/src/codex-lifecycle-account.d.ts +104 -0
- package/dist/src/codex-lifecycle-canary.d.ts +20 -0
- package/dist/src/codex-lifecycle-facts.d.ts +53 -0
- package/dist/src/codex-lifecycle-fork.d.ts +91 -0
- package/dist/src/codex-lifecycle-preflight.d.ts +77 -0
- package/dist/src/codex-lifecycle-receipt.d.ts +53 -0
- package/dist/src/codex-lifecycle-restart.d.ts +88 -0
- package/dist/src/codex-login-share-guard.d.ts +146 -0
- package/dist/src/codex-menu.d.ts +99 -0
- package/dist/src/codex-model-default.d.ts +6 -0
- package/dist/src/codex-node-login.d.ts +98 -0
- package/dist/src/codex-pending-thread-restart.d.ts +69 -0
- package/dist/src/codex-recovery-lease.d.ts +39 -0
- package/dist/src/codex-recovery-resource-gate.d.ts +15 -0
- package/dist/src/codex-resume.d.ts +89 -0
- package/dist/src/codex-rollout-history-guard.d.ts +84 -0
- package/dist/src/codex-tui-client-health.d.ts +30 -0
- package/dist/src/commhub-response.d.ts +1 -0
- package/dist/src/controlled-upload.d.ts +83 -0
- package/dist/src/copresence-deps.d.ts +22 -0
- package/dist/src/copresence-identity.d.ts +363 -0
- package/dist/src/copresence-startup-diagnosis.d.ts +17 -0
- package/dist/src/daemon-adopt.d.ts +14 -0
- package/dist/src/daemon-anet-bin.d.ts +32 -0
- package/dist/src/daemon-capability-display.d.ts +110 -0
- package/dist/src/daemon-capability-display.js +21 -0
- package/dist/src/daemon-inherited-env.d.ts +9 -0
- package/dist/src/daemon-runtime-path-preflight.d.ts +22 -0
- package/dist/src/daemon-runtime-staleness.d.ts +13 -0
- package/dist/src/dashboard-managed-process.d.ts +35 -0
- package/dist/src/display-width.d.ts +27 -0
- package/dist/src/doctor-node-count.d.ts +28 -0
- package/dist/src/environ-alias.d.ts +14 -0
- package/dist/src/grok-attach-client.d.ts +129 -0
- package/dist/src/grok-build-drift.d.ts +15 -0
- package/dist/src/grok-copresence-disclosure.d.ts +11 -0
- package/dist/src/grok-copresence-orchestration.d.ts +75 -0
- package/dist/src/grok-copresence-profile.d.ts +65 -0
- package/dist/src/grok-create-mode.d.ts +19 -0
- package/dist/src/host-telemetry.d.ts +14 -0
- package/dist/src/hub-health-timeout.d.ts +4 -0
- package/dist/src/hub-server-version.d.ts +64 -0
- package/dist/src/hub-stop.d.ts +74 -0
- package/dist/src/hub-time-display.d.ts +20 -0
- package/dist/src/hub-version-skew.d.ts +19 -0
- package/dist/src/im/correlation-store.d.ts +34 -0
- package/dist/src/im/feishu/adapter.d.ts +54 -0
- package/dist/src/im/feishu/bridge.d.ts +78 -14
- package/dist/src/im/feishu/hub-upload.d.ts +1 -1
- package/dist/src/im/feishu/outbound-route.d.ts +62 -0
- package/dist/src/im/feishu/worker-lifecycle.d.ts +13 -0
- package/dist/src/im/feishu/worker.js +180 -153
- package/dist/src/inbox-drain.d.ts +20 -0
- package/dist/src/local-process-state.d.ts +12 -0
- package/dist/src/locale-diagnostic.d.ts +12 -0
- package/dist/src/login-client-label.d.ts +6 -0
- package/dist/src/ls-columns.d.ts +15 -0
- package/dist/src/mock-llm.d.ts +12 -0
- package/dist/src/node-activity-log.d.ts +4 -0
- package/dist/src/node-clone.d.ts +134 -0
- package/dist/src/node-delete-hub.d.ts +42 -0
- package/dist/src/node-files.d.ts +62 -0
- package/dist/src/node-locate.d.ts +60 -0
- package/dist/src/node-ls-all.d.ts +80 -0
- package/dist/src/node-menu.d.ts +40 -0
- package/dist/src/node-not-found.d.ts +1 -0
- package/dist/src/node-remote.d.ts +180 -0
- package/dist/src/node-running-guard.d.ts +9 -0
- package/dist/src/node-server-identity.d.ts +35 -0
- package/dist/src/node-server-payload.d.ts +66 -0
- package/dist/src/node-server-rules-file.d.ts +14 -0
- package/dist/src/node-server-version.d.ts +39 -0
- package/dist/src/node-server.js +8 -1
- package/dist/src/node-skills.d.ts +57 -0
- package/dist/src/normalize-runtime.d.ts +29 -2
- package/dist/src/offline-age.d.ts +29 -0
- package/dist/src/one-line-cell.d.ts +20 -0
- package/dist/src/opencode-agent-node-pair.d.ts +28 -0
- package/dist/src/opencode-auth-login.d.ts +43 -0
- package/dist/src/opencode-free-tier.d.ts +27 -0
- package/dist/src/opencode-generation-create.d.ts +27 -0
- package/dist/src/opencode-generation-record.d.ts +24 -0
- package/dist/src/opencode-launch-env.d.ts +13 -0
- package/dist/src/opencode-owner-mode.d.ts +6 -0
- package/dist/src/opencode-package-binary.d.ts +44 -0
- package/dist/src/opencode-pin.d.ts +61 -0
- package/dist/src/opencode-preset.d.ts +73 -0
- package/dist/src/opencode-runtime-binding.d.ts +30 -0
- package/dist/src/opencode-safe-root.d.ts +36 -0
- package/dist/src/opencode-smoke-env.d.ts +1 -0
- package/dist/src/opencode-versions.d.ts +44 -0
- package/dist/src/outbound-attachments.d.ts +60 -0
- package/dist/src/outbound-tool-names.d.ts +1 -0
- package/dist/src/owned-roots.d.ts +58 -0
- package/dist/src/owner-env-file.d.ts +2 -0
- package/dist/src/package-mode-preflight.d.ts +41 -0
- package/dist/src/posix-codex-copresence.d.ts +33 -0
- package/dist/src/posix-modes.d.ts +36 -0
- package/dist/src/primary-network.d.ts +23 -0
- package/dist/src/private-state.d.ts +10 -0
- package/dist/src/process-telemetry.d.ts +12 -0
- package/dist/src/profile-serialize.d.ts +1 -0
- package/dist/src/project-key.d.ts +1 -0
- package/dist/src/reply-local-links.d.ts +47 -0
- package/dist/src/reply-originator.d.ts +20 -0
- package/dist/src/resume-runtime-infer.d.ts +18 -0
- package/dist/src/rules-file.d.ts +53 -0
- package/dist/src/secret-shell-guidance.d.ts +4 -0
- package/dist/src/session-status-class.d.ts +48 -0
- package/dist/src/shared/reserved-env.d.ts +3 -0
- package/dist/src/sibling-agent-node.d.ts +23 -0
- package/dist/src/stale-socket.d.ts +118 -0
- package/dist/src/start-resource-gate.d.ts +146 -0
- package/dist/src/stopped-receipt.d.ts +8 -0
- package/dist/src/subcommand-redirect.d.ts +26 -0
- package/dist/src/task-trace.d.ts +33 -0
- package/dist/src/tmux-attach.d.ts +11 -0
- package/dist/src/tmux-capability.d.ts +58 -0
- package/dist/src/tmux-exact-target.d.ts +36 -0
- package/dist/src/tmux-format.d.ts +20 -0
- package/dist/src/tmux-pane-prompt.d.ts +22 -0
- package/dist/src/tmux.d.ts +44 -0
- package/dist/src/token-cli.d.ts +13 -0
- package/dist/src/tool-allowlist.d.ts +28 -0
- package/dist/src/unsafe-package-path-reason.d.ts +31 -0
- package/dist/src/upgrade-channel.d.ts +31 -0
- package/dist/src/win-launcher.d.ts +20 -0
- package/dist/src/windows-codex-copresence.d.ts +60 -0
- package/package.json +14 -7
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
export declare const START_GATE_DEFAULT_MIN_MEM_MB = 4096;
|
|
2
|
+
export declare const START_GATE_DEFAULT_MEM_FRACTION = 0.15;
|
|
3
|
+
export declare const START_GATE_DEFAULT_MAX_LOAD_PER_CPU = 4;
|
|
4
|
+
export declare const START_GATE_DEFAULT_MAX_WAIT_SEC = 600;
|
|
5
|
+
export declare const START_GATE_DEFAULT_MAX_CONCURRENT = 2;
|
|
6
|
+
export declare const START_GATE_SINGLE_LANE_CONCURRENT = 1;
|
|
7
|
+
export declare const START_GATE_RECHECK_MS = 15000;
|
|
8
|
+
/** Jitter added to each re-check while still inside the max wait: uniform [0, RECHECK_JITTER_MS). */
|
|
9
|
+
export declare const START_GATE_RECHECK_JITTER_MS = 5000;
|
|
10
|
+
export declare const START_GATE_WAITING_MEMORY_STATUS = "\u7B49\u5F85\u5185\u5B58";
|
|
11
|
+
export declare const START_GATE_WAITING_LOAD_STATUS = "\u7B49\u5F85\u8D1F\u8F7D";
|
|
12
|
+
export declare const START_GATE_WAITING_BOTH_STATUS = "\u7B49\u5F85\u5185\u5B58\u548C\u8D1F\u8F7D";
|
|
13
|
+
export declare const START_GATE_WAITING_PROBE_STATUS = "\u7B49\u5F85\u8D44\u6E90\u63A2\u6D4B";
|
|
14
|
+
/** #686 compatibility alias for callers that used the original memory-only status. */
|
|
15
|
+
export declare const START_GATE_WAITING_STATUS = "\u7B49\u5F85\u5185\u5B58";
|
|
16
|
+
export declare const START_GATE_SINGLE_LANE_STATUS = "\u5DF2\u8D85\u65F6\uFF0C\u6309\u5355\u8DEF\u653E\u884C";
|
|
17
|
+
/** Logged when one waiter atomically replaces a stuck lease. The wait cap must not admit without this. */
|
|
18
|
+
export declare const START_GATE_TAKEOVER_STATUS = "\u63A5\u7BA1\u5361\u6B7B\u79DF\u7EA6";
|
|
19
|
+
/** Startup leases older than this are not live. ANET_START_LEASE_TTL_SEC overrides it. */
|
|
20
|
+
export declare const START_GATE_LEASE_TTL_MS: number;
|
|
21
|
+
/** A healthy holder renews well before the default lease expiry. */
|
|
22
|
+
export declare const START_GATE_LEASE_HEARTBEAT_MS = 30000;
|
|
23
|
+
/** An empty or unreadable lock younger than this is still being published, not dead. */
|
|
24
|
+
export declare const START_GATE_LOCK_STALE_MS = 30000;
|
|
25
|
+
/**
|
|
26
|
+
* A live matching lock is an orphan when the monotonic timestamp stored in
|
|
27
|
+
* the lock is older than this. Legacy locks with no stamp still use wall
|
|
28
|
+
* mtime, which a clock step can age out. The critical section only renames
|
|
29
|
+
* and writes a few files, so a live holder past this window is stuck.
|
|
30
|
+
*/
|
|
31
|
+
export declare const START_GATE_LOCK_ORPHAN_MS = 60000;
|
|
32
|
+
export interface StartGateDeps {
|
|
33
|
+
env?: NodeJS.ProcessEnv;
|
|
34
|
+
platform?: string;
|
|
35
|
+
/** Returns file contents, or null when unreadable. */
|
|
36
|
+
readFile?: (path: string) => string | null;
|
|
37
|
+
cpuCount?: () => number;
|
|
38
|
+
sleep?: (ms: number) => Promise<void>;
|
|
39
|
+
now?: () => number;
|
|
40
|
+
random?: () => number;
|
|
41
|
+
log?: (msg: string) => void;
|
|
42
|
+
warn?: (msg: string) => void;
|
|
43
|
+
/** Hub/task text. Errors are swallowed so a report failure cannot block a start. */
|
|
44
|
+
report?: (text: string) => void;
|
|
45
|
+
/** Host lease directory. Tests must inject this; the default is ~/.anet/run/start-slots. */
|
|
46
|
+
slotsDir?: string;
|
|
47
|
+
/** Lease key. Alias is not unique across workspaces; pass the node id. */
|
|
48
|
+
nodeId?: string;
|
|
49
|
+
/** Pid written into the lease. Default: this process. */
|
|
50
|
+
holderPid?: number;
|
|
51
|
+
/** ESRCH = dead, EPERM = alive. Injected so tests never signal a real pid. */
|
|
52
|
+
isPidAlive?: (pid: number) => boolean;
|
|
53
|
+
/** /proc/<pid>/stat field 22. null means unknown — do not treat that as a mismatch. */
|
|
54
|
+
readProcessStartTicks?: (pid: number) => string | null;
|
|
55
|
+
/** Override the 15s re-check. With jitterMs 0 the single-lane retry uses this as-is. */
|
|
56
|
+
recheckMs?: number;
|
|
57
|
+
/** Override the 0–5s jitter span. 0 keeps the sleep exactly recheckMs. */
|
|
58
|
+
jitterMs?: number;
|
|
59
|
+
/** Lease lifetime. Default 10 minutes, or ANET_START_LEASE_TTL_SEC. */
|
|
60
|
+
leaseTtlMs?: number;
|
|
61
|
+
/** @internal deterministic short-TTL seam. Defaults to min(30s, TTL/3). */
|
|
62
|
+
leaseHeartbeatMs?: number;
|
|
63
|
+
/** Empty/unreadable locks younger than this are held, not dead. */
|
|
64
|
+
lockStaleMs?: number;
|
|
65
|
+
/** A live matching lock older than this is an orphan. Default 60s. */
|
|
66
|
+
lockOrphanMs?: number;
|
|
67
|
+
/**
|
|
68
|
+
* Monotonic milliseconds shared by every process on this host.
|
|
69
|
+
* Default reads /proc/uptime. null means unknown: a stamped lock is kept.
|
|
70
|
+
*/
|
|
71
|
+
monotonicNow?: () => number | null;
|
|
72
|
+
}
|
|
73
|
+
export type StartGateOutcome = "disabled" | "unsupported" | "ok" | "waited" | "single-lane";
|
|
74
|
+
export interface StartGateResult {
|
|
75
|
+
outcome: StartGateOutcome;
|
|
76
|
+
waitedMs: number;
|
|
77
|
+
checks: number;
|
|
78
|
+
/** Always callable and idempotent. Drops the lease only if this call created it. */
|
|
79
|
+
release: () => void;
|
|
80
|
+
}
|
|
81
|
+
export interface HostSample {
|
|
82
|
+
/** Effective free MiB: min(MemAvailable, cgroup free) when a real cgroup limit exists. */
|
|
83
|
+
memAvailableMb: number;
|
|
84
|
+
/** /proc MemAvailable, before the cgroup min. */
|
|
85
|
+
procAvailableMb: number;
|
|
86
|
+
/** Cgroup free MiB, or null when there is no real limit. */
|
|
87
|
+
cgroupFreeMb: number | null;
|
|
88
|
+
/** Cgroup limit MiB, or null when there is no real limit. The floor uses this, not the host alone. */
|
|
89
|
+
cgroupLimitMb: number | null;
|
|
90
|
+
/** 0 when MemTotal could not be read (the floor then falls back to 4096). */
|
|
91
|
+
memTotalMb: number;
|
|
92
|
+
load1: number;
|
|
93
|
+
cpuCount: number;
|
|
94
|
+
}
|
|
95
|
+
export interface StartGateStatusSnapshot {
|
|
96
|
+
status: string;
|
|
97
|
+
task?: string;
|
|
98
|
+
}
|
|
99
|
+
/** True only for blocked text owned by this gate, including single-lane wait. */
|
|
100
|
+
export declare function isStartGateBlockedStatus(task: string | undefined): boolean;
|
|
101
|
+
/**
|
|
102
|
+
* Once admission returns, restore the pre-gate status only if the live status
|
|
103
|
+
* is still ours. A concurrent task/status update must win over stale restore.
|
|
104
|
+
*/
|
|
105
|
+
export declare function startGateStatusToRestore(live: StartGateStatusSnapshot, previous: StartGateStatusSnapshot): StartGateStatusSnapshot | null;
|
|
106
|
+
/** MemAvailable in MiB from /proc/meminfo text, or null. */
|
|
107
|
+
export declare function parseMemAvailableMb(meminfo: string): number | null;
|
|
108
|
+
/** MemTotal in MiB from /proc/meminfo text, or null. */
|
|
109
|
+
export declare function parseMemTotalMb(meminfo: string): number | null;
|
|
110
|
+
/** 1-minute load average from /proc/loadavg text, or null. */
|
|
111
|
+
export declare function parseLoad1(loadavg: string): number | null;
|
|
112
|
+
/**
|
|
113
|
+
* Field 22 of /proc/<pid>/stat (starttime, clock ticks since boot).
|
|
114
|
+
* The comm field is in parentheses and may contain spaces; everything after the
|
|
115
|
+
* last ")" is field 3 onward, so field 22 is index 19 of that tail.
|
|
116
|
+
*/
|
|
117
|
+
export declare function parseProcStartTicks(statText: string): string | null;
|
|
118
|
+
/**
|
|
119
|
+
* Default free-memory floor. A fixed 4 GiB is too high for a small machine
|
|
120
|
+
* or a small container, so the floor is min(4 GiB, 15% of the effective total).
|
|
121
|
+
* The effective total is min(MemTotal, cgroup limit) when a real cgroup limit
|
|
122
|
+
* exists — a container must not be judged against the host's MemTotal.
|
|
123
|
+
* Missing/invalid numbers fall back to 4 GiB. ANET_START_MIN_MEM_MB replaces
|
|
124
|
+
* this when set.
|
|
125
|
+
*/
|
|
126
|
+
export declare function defaultStartMinMemMb(memTotalMb: number, cgroupLimitMb?: number | null): number;
|
|
127
|
+
/** Reasons the host is too busy to start, empty when it is fine. */
|
|
128
|
+
export declare function startGateReasons(s: HostSample, minMemMb: number, maxLoadPerCpu: number): string[];
|
|
129
|
+
/** User-facing blocked status. Keep this structured instead of parsing the diagnostic reasons. */
|
|
130
|
+
export declare function startGateWaitingStatus(s: HostSample | null, minMemMb: number, maxLoadPerCpu: number): string | null;
|
|
131
|
+
/**
|
|
132
|
+
* Free MiB inside a real cgroup limit, or null when the limit is missing/unlimited.
|
|
133
|
+
* `memory.current` counts page cache; inactive_file (v1: total_inactive_file) is subtracted.
|
|
134
|
+
* statText null keeps the old arithmetic so existing fixtures stay valid.
|
|
135
|
+
*/
|
|
136
|
+
export declare function cgroupFreeMb(maxText: string, currentText: string, memTotalMb: number, statText?: string | null, v1?: boolean): number | null;
|
|
137
|
+
/** Real cgroup limit in MiB, or null when the limit is missing/unlimited. */
|
|
138
|
+
export declare function cgroupLimitMb(maxText: string, memTotalMb: number): number | null;
|
|
139
|
+
/**
|
|
140
|
+
* Block until this host may start one heavy process.
|
|
141
|
+
* Returns a release() the caller must invoke once that process is up or has failed.
|
|
142
|
+
* Never throws (except when the injected sleep rejects — tests use that to stop a wait).
|
|
143
|
+
*/
|
|
144
|
+
export declare function waitForStartResources(label: string, deps?: StartGateDeps): Promise<StartGateResult>;
|
|
145
|
+
/** Run `fn` while holding one start lease. Release runs on success and on failure. */
|
|
146
|
+
export declare function withHeavyStartAdmission<T>(label: string, deps: StartGateDeps, fn: () => Promise<T>): Promise<T>;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/** Capture BEFORE asynchronous manual start. Successful start supersedes only
|
|
2
|
+
* this exact receipt, without unlinking it: check-then-unlink would race another
|
|
3
|
+
* process writing a new stop. A late certificate can never supersede that new
|
|
4
|
+
* receipt, even if its JSON is identical (inode/ctime are part of identity). */
|
|
5
|
+
export declare function stoppedReceiptAtStart(nodeDir: string, nodeId: unknown): () => void;
|
|
6
|
+
/** Missing stop => runnable. Unreadable/unsafe/legacy stop => stay stopped.
|
|
7
|
+
* Keep the fleet boot probe's wire format in sync (Docker parity test). */
|
|
8
|
+
export declare function isHubStopped(nodeDir: string, nodeId: unknown): boolean;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `anet daemon <sub>` 认不出子命令时,原先只走 `suggestSimilar`,而它的候选集
|
|
3
|
+
* 是 `["init","start","restart","up","list"]` —— **全是会改变状态的命令**。
|
|
4
|
+
*
|
|
5
|
+
* 🔴 实测(用仓里那个 `suggestSimilar` 本身跑的,不是推的):
|
|
6
|
+
*
|
|
7
|
+
* anet daemon rm → 建议 "up" 想删,被指去「创建 + 启动」
|
|
8
|
+
* anet daemon state → 建议 "start" 想看状态,被指去「启动」
|
|
9
|
+
* anet daemon stat → 建议 "start" 同上
|
|
10
|
+
* anet daemon stop → 建议 null (levenshtein("stop","start") = 3)
|
|
11
|
+
*
|
|
12
|
+
* 一个「你是不是想 X」的提示,把只读/销毁意图导向一个会动世界的命令,
|
|
13
|
+
* 比不给提示更贵。
|
|
14
|
+
*
|
|
15
|
+
* 而这些动作**本来就有**:daemon 就是一个 role=host_supervisor 的 agent-node,
|
|
16
|
+
* `anet daemon restart` 内部调的正是 `anet node stop` 用的那个 stopCommand()。
|
|
17
|
+
* 缺的从来不是功能,是**可发现性**。
|
|
18
|
+
*/
|
|
19
|
+
/** 这些是 `anet daemon` 自己的子命令 —— 它们**会改变状态**,所以任何
|
|
20
|
+
* 只读/销毁意图都不该被导向它们。测试用它做对照。 */
|
|
21
|
+
export declare const DAEMON_STATE_CHANGING: readonly ["init", "start", "restart", "up"];
|
|
22
|
+
export declare const PROJECT_STATE_CHANGING: readonly ["up", "restart"];
|
|
23
|
+
export declare const NODE_STATE_CHANGING: readonly ["create", "start", "restart", "resume", "rename", "loop"];
|
|
24
|
+
export declare const daemonSubcommandRedirect: (sub: unknown, name?: unknown) => string[] | null;
|
|
25
|
+
export declare const projectSubcommandRedirect: (sub: unknown, name?: unknown) => string[] | null;
|
|
26
|
+
export declare const nodeSubcommandRedirect: (sub: unknown, name?: unknown) => string[] | null;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
export type TaskTraceTransport = "mcp_http" | "sdk_mcp_proxy" | "channel_mcp_proxy";
|
|
2
|
+
export type TaskTraceStatus = "sending" | "delivered" | "failed" | "acked" | "started" | "replied" | "expired";
|
|
3
|
+
export interface TaskTraceEvent {
|
|
4
|
+
event: string;
|
|
5
|
+
from_alias: string;
|
|
6
|
+
to_alias: string;
|
|
7
|
+
task_id: string | null;
|
|
8
|
+
parent_task_id: string | null;
|
|
9
|
+
network_id: string | null;
|
|
10
|
+
transport: TaskTraceTransport;
|
|
11
|
+
status: TaskTraceStatus;
|
|
12
|
+
duration_ms: number;
|
|
13
|
+
lifecycle_tracking: "tracked" | "not_tracked";
|
|
14
|
+
error_code?: string;
|
|
15
|
+
error_message?: string;
|
|
16
|
+
}
|
|
17
|
+
export declare function safeTaskTraceError(value: unknown): string;
|
|
18
|
+
export declare function renderTaskTrace(event: TaskTraceEvent, json?: boolean): string;
|
|
19
|
+
export declare function taskTraceEvent(input: Omit<TaskTraceEvent, "event">): TaskTraceEvent;
|
|
20
|
+
export interface SendTaskTraceInput {
|
|
21
|
+
fromAlias: string;
|
|
22
|
+
toAlias: string;
|
|
23
|
+
parentTaskId: string | null;
|
|
24
|
+
networkId: string | null;
|
|
25
|
+
transport: TaskTraceTransport;
|
|
26
|
+
lifecycleTracking: "tracked" | "not_tracked";
|
|
27
|
+
}
|
|
28
|
+
export interface SendTaskTraceDependencies {
|
|
29
|
+
send: () => Promise<any>;
|
|
30
|
+
log: (line: string) => void;
|
|
31
|
+
now?: () => number;
|
|
32
|
+
}
|
|
33
|
+
export declare function sendTaskWithTrace(input: SendTaskTraceInput, dependencies: SendTaskTraceDependencies): Promise<any>;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export type TmuxSession = {
|
|
2
|
+
id: string;
|
|
3
|
+
name: string;
|
|
4
|
+
};
|
|
5
|
+
/** argv for `execTmux`: `-u list-sessions -F '#{session_id}|ANETSEP|#{session_name}'` (#533). */
|
|
6
|
+
export declare const SESSION_LIST_ARGS: readonly string[];
|
|
7
|
+
/** Parse SESSION_LIST_ARGS output (legacy `id\tname` rows still accepted). */
|
|
8
|
+
export declare function parseTmuxSessions(output: string): TmuxSession[];
|
|
9
|
+
/** Resolve by exact decoded session name, then attach by tmux's opaque ID.
|
|
10
|
+
* This avoids tmux target prefix matching and works for Unicode names. */
|
|
11
|
+
export declare function findExactTmuxSession(output: string, expectedName: string): TmuxSession | null;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/** Lowest tmux version whose `new-session` understands `-e KEY=VALUE`. */
|
|
2
|
+
export declare const MIN_TMUX_MAJOR = 3;
|
|
3
|
+
export declare const MIN_TMUX_MINOR = 2;
|
|
4
|
+
export interface TmuxVersion {
|
|
5
|
+
major: number;
|
|
6
|
+
minor: number;
|
|
7
|
+
/** Trailing letter suffix, e.g. the "a" of "3.0a". Not used for ordering. */
|
|
8
|
+
suffix: string;
|
|
9
|
+
raw: string;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Parse the output of `tmux -V`, e.g.:
|
|
13
|
+
* "tmux 3.2a" → { major: 3, minor: 2, suffix: "a" }
|
|
14
|
+
* "tmux 3.0a" → { major: 3, minor: 0, suffix: "a" }
|
|
15
|
+
* "tmux 3.4" → { major: 3, minor: 4, suffix: "" }
|
|
16
|
+
* "tmux next-3.4" → { major: 3, minor: 4, suffix: "" }
|
|
17
|
+
* "tmux 2.9" → { major: 2, minor: 9, suffix: "" }
|
|
18
|
+
*
|
|
19
|
+
* Returns null when no version can be extracted (unknown build, empty
|
|
20
|
+
* output, `tmux master` with no numbers). Callers must treat null as
|
|
21
|
+
* "unknown" and NOT as "too old" — refusing to start on an unparseable
|
|
22
|
+
* version string would break hosts whose tmux is perfectly capable.
|
|
23
|
+
*/
|
|
24
|
+
export declare function parseTmuxVersion(raw: string): TmuxVersion | null;
|
|
25
|
+
/**
|
|
26
|
+
* True when this version's `new-session` supports `-e KEY=VALUE` (>= 3.2).
|
|
27
|
+
* Note 3.0a / 3.1c sort BELOW 3.2 — the letter suffix is a patch marker,
|
|
28
|
+
* never a minor bump, so it must not participate in the comparison.
|
|
29
|
+
*/
|
|
30
|
+
export declare function tmuxSupportsSessionEnv(v: TmuxVersion): boolean;
|
|
31
|
+
export type TmuxCapabilityVerdict = {
|
|
32
|
+
kind: "ok";
|
|
33
|
+
version: TmuxVersion;
|
|
34
|
+
} | {
|
|
35
|
+
kind: "unknown";
|
|
36
|
+
detail: string;
|
|
37
|
+
} | {
|
|
38
|
+
kind: "too_old";
|
|
39
|
+
version: TmuxVersion;
|
|
40
|
+
detail: string;
|
|
41
|
+
remedy: string[];
|
|
42
|
+
} | {
|
|
43
|
+
kind: "missing";
|
|
44
|
+
detail: string;
|
|
45
|
+
remedy: string[];
|
|
46
|
+
};
|
|
47
|
+
/**
|
|
48
|
+
* Pure decision function — `runVersionCmd` returns `tmux -V` output, or
|
|
49
|
+
* throws if tmux is absent/unrunnable. Split from the printing/exiting
|
|
50
|
+
* wrapper so tests drive every branch without a tmux binary.
|
|
51
|
+
*/
|
|
52
|
+
export declare function checkTmuxCapability(runVersionCmd: () => string): TmuxCapabilityVerdict;
|
|
53
|
+
/**
|
|
54
|
+
* cli.ts wrapper: run the check, print an actionable message, and exit
|
|
55
|
+
* non-zero when tmux cannot carry the marker. `unknown` is deliberately
|
|
56
|
+
* permissive — we log and continue.
|
|
57
|
+
*/
|
|
58
|
+
export declare function assertTmuxSupportsSessionEnv(runVersionCmd: () => string, log: (msg: string) => void, fail: (msg: string) => never): void;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Exact-match tmux target for a session name.
|
|
3
|
+
*
|
|
4
|
+
* tmux treats a leading `=` as "this exact name, no prefix matching". Names are
|
|
5
|
+
* passed to tmux as argv entries, never through a shell, so no quoting belongs
|
|
6
|
+
* here — callers that build a copy-pasteable command for a human should shell-
|
|
7
|
+
* quote the result themselves.
|
|
8
|
+
*/
|
|
9
|
+
export declare function exactSession(name: string): string;
|
|
10
|
+
/**
|
|
11
|
+
* True when this target is already pinned to an exact session.
|
|
12
|
+
*
|
|
13
|
+
* Applying the prefix twice would look for a session literally named `=x`.
|
|
14
|
+
*/
|
|
15
|
+
export declare function isExactTarget(target: string): boolean;
|
|
16
|
+
/** Idempotent form, for call sites that may receive either shape. */
|
|
17
|
+
export declare function ensureExactSession(nameOrTarget: string): string;
|
|
18
|
+
/** One row of `tmux -u list-panes -a -F PANE_LIST_FORMAT` (session, `window.pane`). */
|
|
19
|
+
export interface PaneRow {
|
|
20
|
+
session: string;
|
|
21
|
+
/** `window.pane`, e.g. `0.0`. */
|
|
22
|
+
coord: string;
|
|
23
|
+
}
|
|
24
|
+
export declare function parsePaneRows(listOutput: string): PaneRow[];
|
|
25
|
+
/**
|
|
26
|
+
* Pane target for a session, or null when that exact session has no pane.
|
|
27
|
+
*
|
|
28
|
+
* Matching is exact string equality on the session name — the whole point is to
|
|
29
|
+
* not hand tmux a name it might prefix-match, and to not hand it a `=` form it
|
|
30
|
+
* cannot resolve for non-ASCII names.
|
|
31
|
+
*/
|
|
32
|
+
export declare function paneTargetFor(listOutput: string, sessionName: string): string | null;
|
|
33
|
+
/** The format string the two functions above expect. */
|
|
34
|
+
export declare const PANE_LIST_FORMAT: string;
|
|
35
|
+
/** Full argv (`-u list-panes -a -F …`) for `execTmux`; locale-proof (#533). */
|
|
36
|
+
export declare const PANE_LIST_ARGS: readonly string[];
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/** Field separator inside a `-F` format. Printable, so tmux never rewrites it. */
|
|
2
|
+
export declare const TMUX_FIELD_SEP = "|ANETSEP|";
|
|
3
|
+
/** Prefix tmux argv with `-u` so its output keeps UTF-8 names in any locale. */
|
|
4
|
+
export declare function tmuxUtf8Args(args: readonly string[]): string[];
|
|
5
|
+
/** The `-F` format string for these fields. */
|
|
6
|
+
export declare function tmuxFormat(fields: readonly string[]): string;
|
|
7
|
+
/**
|
|
8
|
+
* argv for a tmux listing whose output anet parses:
|
|
9
|
+
* `tmuxListArgs(["list-sessions"], ["#{session_id}", "#{session_name}"])`
|
|
10
|
+
* → `["-u", "list-sessions", "-F", "#{session_id}|ANETSEP|#{session_name}"]`.
|
|
11
|
+
* Pass the result to `execTmux` (which adds `-S` isolation in front).
|
|
12
|
+
*/
|
|
13
|
+
export declare function tmuxListArgs(command: readonly string[], fields: readonly string[]): string[];
|
|
14
|
+
/**
|
|
15
|
+
* Split tmux format output into rows of exactly `fieldCount` fields.
|
|
16
|
+
* Lines with a different field count are dropped (never guessed at).
|
|
17
|
+
* A line without the separator is read as a legacy TAB-separated row, so
|
|
18
|
+
* fixtures and callers that captured the old wire shape still parse.
|
|
19
|
+
*/
|
|
20
|
+
export declare function parseTmuxRows(output: string, fieldCount: number): string[][];
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/** A prompt the watcher knows how to answer, or null. */
|
|
2
|
+
export type PanePrompt = "dev-channels" | "folder-trust";
|
|
3
|
+
/**
|
|
4
|
+
* Which known prompt (if any) the pane is currently blocking on.
|
|
5
|
+
*
|
|
6
|
+
* Dev-channels is checked FIRST, even though it appears second in time. The two
|
|
7
|
+
* prompts are sequential — trust, then channels — so a capture showing both
|
|
8
|
+
* means the trust prompt is already answered and only its text is still sitting
|
|
9
|
+
* in the pane. Classifying that as "folder-trust" would make a watcher that has
|
|
10
|
+
* already answered trust ignore the prompt it was waiting for, and the node
|
|
11
|
+
* would hang exactly as if the fix had never been made. Preferring the later
|
|
12
|
+
* prompt keeps a stale line of scrollback from outranking the live prompt.
|
|
13
|
+
*/
|
|
14
|
+
export declare function classifyPanePrompt(pane: string): PanePrompt | null;
|
|
15
|
+
/**
|
|
16
|
+
* Best-effort one-line explanation of why a detached start died, taken from the
|
|
17
|
+
* dead pane's own output.
|
|
18
|
+
*
|
|
19
|
+
* Returns null when the pane holds nothing that looks like a refusal — the
|
|
20
|
+
* caller must then fall back to a generic message rather than inventing one.
|
|
21
|
+
*/
|
|
22
|
+
export declare function extractStartFailureReason(pane: string): string | null;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { type ChildProcess, type ExecFileSyncOptions, type ExecFileSyncOptionsWithBufferEncoding, type ExecFileSyncOptionsWithStringEncoding, type SpawnOptions, type SpawnSyncOptions, type SpawnSyncReturns } from "node:child_process";
|
|
2
|
+
export type TmuxEnv = Record<string, string | undefined>;
|
|
3
|
+
export interface TmuxIsolation {
|
|
4
|
+
/** Socket path passed to tmux as `-S`. */
|
|
5
|
+
socket: string;
|
|
6
|
+
/** Which variable asked for isolation. */
|
|
7
|
+
source: "ANET_TMUX_SOCKET" | "TMUX_TMPDIR";
|
|
8
|
+
}
|
|
9
|
+
export declare class TmuxKillServerRefused extends Error {
|
|
10
|
+
constructor(args: readonly string[]);
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Where tmux should talk to, or null for "today's default behaviour".
|
|
14
|
+
* `TMUX_TMPDIR` resolves the same way tmux itself does: `$TMUX_TMPDIR/tmux-<uid>/default`.
|
|
15
|
+
*/
|
|
16
|
+
export declare function resolveTmuxIsolation(env?: TmuxEnv, uid?: number): TmuxIsolation | null;
|
|
17
|
+
/** The socket path inside `$TMUX` (`<socket>,<server pid>,<session idx>`), or null. */
|
|
18
|
+
export declare function socketOfTmuxVar(value: string | undefined): string | null;
|
|
19
|
+
/**
|
|
20
|
+
* True when argv asks tmux to kill its server, including `a ; kill-server`
|
|
21
|
+
* chains and the unambiguous prefixes tmux accepts (`kill-ser`, `kill-serv`, …).
|
|
22
|
+
*/
|
|
23
|
+
export declare function isKillServer(args: readonly string[]): boolean;
|
|
24
|
+
export interface TmuxInvocation {
|
|
25
|
+
file: "tmux";
|
|
26
|
+
args: string[];
|
|
27
|
+
/** undefined ⇒ inherit the caller's env exactly as before (no isolation requested). */
|
|
28
|
+
env: TmuxEnv | undefined;
|
|
29
|
+
isolation: TmuxIsolation | null;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Pure argv/env builder. Throws TmuxKillServerRefused for kill-server.
|
|
33
|
+
* `env` is the env the child would otherwise get (the caller's `options.env`,
|
|
34
|
+
* else process.env); isolation is decided from it.
|
|
35
|
+
*/
|
|
36
|
+
export declare function buildTmuxInvocation(args: readonly string[], env?: TmuxEnv, uid?: number): TmuxInvocation;
|
|
37
|
+
/** `execFileSync("tmux", args, options)` through the #505 rules. */
|
|
38
|
+
export declare function execTmux(args: readonly string[], options: ExecFileSyncOptionsWithStringEncoding): string;
|
|
39
|
+
export declare function execTmux(args: readonly string[], options?: ExecFileSyncOptionsWithBufferEncoding): Buffer;
|
|
40
|
+
export declare function execTmux(args: readonly string[], options?: ExecFileSyncOptions): string | Buffer;
|
|
41
|
+
/** `spawnSync("tmux", args, options)` through the #505 rules. */
|
|
42
|
+
export declare function spawnSyncTmux(args: readonly string[], options?: SpawnSyncOptions): SpawnSyncReturns<string | Buffer>;
|
|
43
|
+
/** `spawn("tmux", args, options)` through the #505 rules. */
|
|
44
|
+
export declare function spawnTmux(args: readonly string[], options?: SpawnOptions): ChildProcess;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export type TokenCreateNameResult = {
|
|
2
|
+
ok: true;
|
|
3
|
+
name: string;
|
|
4
|
+
} | {
|
|
5
|
+
ok: false;
|
|
6
|
+
error: string;
|
|
7
|
+
};
|
|
8
|
+
/** Parse only `anet token create` operands.
|
|
9
|
+
*
|
|
10
|
+
* The legacy positional form stays supported, while flag parsing is strict so
|
|
11
|
+
* a typo cannot become the name of a newly issued credential.
|
|
12
|
+
*/
|
|
13
|
+
export declare function parseTokenCreateName(argv: readonly string[]): TokenCreateNameResult;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export declare const CLAUDE_KNOWN_TOOLS: readonly string[];
|
|
2
|
+
type Runtime = string;
|
|
3
|
+
/** Parse the comma-joined --tools string, validate each token, return the
|
|
4
|
+
* trimmed list. Runtime-scoped:
|
|
5
|
+
*
|
|
6
|
+
* Claude-lineage → each token must be in CLAUDE_KNOWN_TOOLS OR match
|
|
7
|
+
* the MCP pattern (mcp__<server>__<tool>).
|
|
8
|
+
* Other runtimes → only the basic per-token format check runs, so grok /
|
|
9
|
+
* codex / opencode tools flow through unchanged and get
|
|
10
|
+
* validated by their own downstream layers.
|
|
11
|
+
*
|
|
12
|
+
* Throws on the first offense with a message naming the bad token and,
|
|
13
|
+
* for Claude-side violations, the expected set. Never returns a
|
|
14
|
+
* partially-cleaned list — a typo must surface, not silently reshape the
|
|
15
|
+
* persisted profile.
|
|
16
|
+
*/
|
|
17
|
+
export declare function parseAndValidateTools(raw: string, runtime: Runtime): string[];
|
|
18
|
+
/** Minimal --model validation: non-empty after trim, no whitespace inside.
|
|
19
|
+
*
|
|
20
|
+
* We do NOT enforce a known-model allowlist — models are vendor-defined,
|
|
21
|
+
* evolve independently, and a strict list would break the first time
|
|
22
|
+
* MiniMax/DeepSeek/GLM/etc. ships a new variant. This catches the obvious
|
|
23
|
+
* user-side typos (`--model " claude-3 " `, `--model ""`) without
|
|
24
|
+
* over-restricting legitimate values. Vendor-side model resolution
|
|
25
|
+
* (defaultCodexModelForRuntime etc.) already validates its own contract.
|
|
26
|
+
*/
|
|
27
|
+
export declare function validateModel(raw: string): string;
|
|
28
|
+
export {};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export interface PathModeFacts {
|
|
2
|
+
/** Owner uid of the path. */
|
|
3
|
+
uid: number;
|
|
4
|
+
/** Permission bits (st_mode & 0o777). */
|
|
5
|
+
mode: number;
|
|
6
|
+
/** uid of the process doing the check. */
|
|
7
|
+
processUid: number;
|
|
8
|
+
}
|
|
9
|
+
export type UnsafePathReason = "owner" | "group-writable" | "world-writable" | null;
|
|
10
|
+
/** Which condition makes this path unsafe to execute from, if any. */
|
|
11
|
+
export declare function classifyUnsafePath(facts: PathModeFacts): UnsafePathReason;
|
|
12
|
+
export declare function describeUnsafePath(path: string, facts: PathModeFacts): string;
|
|
13
|
+
export interface DirectoryModeFacts {
|
|
14
|
+
uid: number;
|
|
15
|
+
/** Full st_mode (the sticky bit 0o1000 matters here). */
|
|
16
|
+
mode: number;
|
|
17
|
+
processUid: number;
|
|
18
|
+
/** Is this the package root itself or one of its ancestors? Only changes the wording. */
|
|
19
|
+
ancestorOf?: string;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* #535 (audit P1-2) — the DIRECTORY branch of the agent-node package check used
|
|
23
|
+
* to throw a bare "unsafe ownership or mode" with no path at all. In the audit
|
|
24
|
+
* the offender was an ANCESTOR, `/tmp` (1777), because the npx cache lived
|
|
25
|
+
* under a HOME in /tmp — and nothing in the message said so.
|
|
26
|
+
*
|
|
27
|
+
* Names the exact directory, what is wrong with it, and the command that fixes
|
|
28
|
+
* it. For a sticky world-writable directory (/tmp-like) the fix is NOT chmod —
|
|
29
|
+
* changing /tmp breaks the machine — but moving the npm cache out from under it.
|
|
30
|
+
*/
|
|
31
|
+
export declare function describeUnsafeDirectory(path: string, facts: DirectoryModeFacts): string;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export type ReleaseChannel = "preview" | "latest";
|
|
2
|
+
export interface DistTags {
|
|
3
|
+
latest?: string | null;
|
|
4
|
+
preview?: string | null;
|
|
5
|
+
}
|
|
6
|
+
export type ChannelResolution = {
|
|
7
|
+
ok: true;
|
|
8
|
+
channel: ReleaseChannel;
|
|
9
|
+
source: "flag" | "detected";
|
|
10
|
+
reason: string;
|
|
11
|
+
} | {
|
|
12
|
+
ok: false;
|
|
13
|
+
error: string;
|
|
14
|
+
};
|
|
15
|
+
export interface ResolveUpgradeChannelInput {
|
|
16
|
+
/** Installed anet version (full string, prerelease preserved). */
|
|
17
|
+
installed: string | null | undefined;
|
|
18
|
+
/** Value of `--channel`. `"true"` means the flag was given without a value. */
|
|
19
|
+
flag?: string | null;
|
|
20
|
+
/** dist-tags of @sleep2agi/agent-network, or null when the lookup failed. */
|
|
21
|
+
distTags: DistTags | null;
|
|
22
|
+
}
|
|
23
|
+
interface ParsedSemver {
|
|
24
|
+
core: [number, number, number];
|
|
25
|
+
pre: string[];
|
|
26
|
+
}
|
|
27
|
+
export declare function parseSemver(version: string | null | undefined): ParsedSemver | null;
|
|
28
|
+
/** semver §11 precedence. Returns <0, 0, >0. */
|
|
29
|
+
export declare function compareSemver(a: ParsedSemver, b: ParsedSemver): number;
|
|
30
|
+
export declare function resolveUpgradeChannel(input: ResolveUpgradeChannelInput): ChannelResolution;
|
|
31
|
+
export {};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { type ExecFileSyncOptions, type ExecFileSyncOptionsWithStringEncoding, type SpawnOptions } from "child_process";
|
|
2
|
+
/** Windows needs a command interpreter to run a .cmd; POSIX runs the file. */
|
|
3
|
+
export declare function launcherNeedsShell(platform?: NodeJS.Platform): boolean;
|
|
4
|
+
/**
|
|
5
|
+
* Quote one argument for `cmd.exe /c`.
|
|
6
|
+
*
|
|
7
|
+
* cmd's rules are not the shell's: a double quote is escaped by doubling it,
|
|
8
|
+
* and the metacharacters below must be quoted or cmd will act on them. Anything
|
|
9
|
+
* safe is left bare, so the common case stays readable in a process listing.
|
|
10
|
+
*/
|
|
11
|
+
export declare function quoteForCmd(arg: string): string;
|
|
12
|
+
/** The argv to hand to execFile/spawn so `cmd args…` runs on this platform. */
|
|
13
|
+
export declare function launcherArgv(cmd: string, args: readonly string[], platform?: NodeJS.Platform, comspec?: string | undefined): {
|
|
14
|
+
file: string;
|
|
15
|
+
argv: string[];
|
|
16
|
+
};
|
|
17
|
+
export declare function runLauncherSync(cmd: string, args: readonly string[], options: ExecFileSyncOptionsWithStringEncoding): string;
|
|
18
|
+
export declare function runLauncherSync(cmd: string, args: readonly string[], options?: ExecFileSyncOptions): Buffer;
|
|
19
|
+
/** spawn for a launcher, correct on Windows. */
|
|
20
|
+
export declare function spawnLauncher(cmd: string, args: readonly string[], options?: SpawnOptions): import("node:child_process").ChildProcess;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
export type WindowsCopresenceRole = "appsrv" | "bridge";
|
|
2
|
+
export interface WindowsManagedProcess {
|
|
3
|
+
role: WindowsCopresenceRole;
|
|
4
|
+
pid: number;
|
|
5
|
+
creationDate: string;
|
|
6
|
+
logPath: string;
|
|
7
|
+
}
|
|
8
|
+
export interface WindowsCopresenceRecord {
|
|
9
|
+
version: 1 | 2;
|
|
10
|
+
nodeId: string;
|
|
11
|
+
createdAt: string;
|
|
12
|
+
marker?: string;
|
|
13
|
+
processes: WindowsManagedProcess[];
|
|
14
|
+
}
|
|
15
|
+
export declare function windowsCopresenceRecordPath(nodesDir: string, nodeId: string): string;
|
|
16
|
+
export declare function windowsCopresenceLogPath(nodesDir: string, nodeId: string, role: WindowsCopresenceRole): string;
|
|
17
|
+
export declare function openPrivateAppendLog(path: string): number;
|
|
18
|
+
/** Protect credential-bearing state with native Windows ACLs. */
|
|
19
|
+
export declare function ensureWindowsPrivateDirectory(path: string): void;
|
|
20
|
+
export declare function closeLog(fd: number): void;
|
|
21
|
+
export type CreationDateProbe = (pid: number) => string | null;
|
|
22
|
+
/** Uses CIM instead of locale-dependent tasklist output. */
|
|
23
|
+
export declare function probeWindowsCreationDate(pid: number): string | null;
|
|
24
|
+
/**
|
|
25
|
+
* Attribute an ESTABLISHED loopback connection to the launched TUI process
|
|
26
|
+
* tree. This is deliberately stronger than counting listeners/connections:
|
|
27
|
+
* an unrelated local client cannot satisfy it.
|
|
28
|
+
*/
|
|
29
|
+
export declare function probeWindowsOwnedLoopbackConnection(rootPid: number, expectedCreationDate: string, port: number, runPowerShell?: (script: string) => string): boolean;
|
|
30
|
+
/**
|
|
31
|
+
* #1342 —— 只在健康检查**即将失败**时跑一次,用来回答一个此前没人量过的问题:
|
|
32
|
+
* 那 10.5 秒到底花在 **PowerShell 启动**上,还是花在 `Get-CimInstance Win32_Process`
|
|
33
|
+
* 这个全表查询上?
|
|
34
|
+
*
|
|
35
|
+
* 实测背景(由 #1628/#1637 加的 probeMs 量到,2026-08-31):
|
|
36
|
+
* probes=1 waited=10897ms probeMsLast=10490 ← 单次探测吃掉 96% 的预算
|
|
37
|
+
* 而 #1636 把全表枚举提到循环外之后这个数**没有变小**(9963 → 10490),
|
|
38
|
+
* 说明成本不在"重复枚举",而在那一次调用本身。但"那一次调用"包含两段:
|
|
39
|
+
* 起一个 powershell 进程,和在里面跑 CIM 查询。**这两段要查的东西完全不同** ——
|
|
40
|
+
* 前者是 runner/镜像的问题,后者是查询写法的问题。
|
|
41
|
+
*
|
|
42
|
+
* 🔴 这里跑的是一个**什么都不做**的脚本(`'x'`),所以它测到的就是启动那一段的下界。
|
|
43
|
+
* 只在失败路径调用一次,不进探测循环 —— 不给正常路径增加任何成本,
|
|
44
|
+
* 也**不可能**改变探测的返回值。
|
|
45
|
+
*
|
|
46
|
+
* 拿不到就返回 null(未知),不返回 0 —— 0 会被读成「启动不花时间」。
|
|
47
|
+
*/
|
|
48
|
+
export declare function measurePowerShellStartupMs(): number | null;
|
|
49
|
+
export declare function writeWindowsCopresenceRecord(nodesDir: string, nodeId: string, processes: WindowsManagedProcess[], marker?: string): void;
|
|
50
|
+
export declare function readWindowsCopresenceRecord(nodesDir: string, nodeId: string): WindowsCopresenceRecord | null;
|
|
51
|
+
export interface WindowsStopDecision {
|
|
52
|
+
safe: WindowsManagedProcess[];
|
|
53
|
+
refused: Array<{
|
|
54
|
+
process: WindowsManagedProcess;
|
|
55
|
+
reason: "missing" | "pid-reused";
|
|
56
|
+
}>;
|
|
57
|
+
}
|
|
58
|
+
/** PID alone is never authority: Windows reuses PIDs, so CreationDate must match. */
|
|
59
|
+
export declare function decideWindowsManagedStop(record: WindowsCopresenceRecord, probe: CreationDateProbe): WindowsStopDecision;
|
|
60
|
+
export declare function taskkillWindowsProcessTree(pid: number): void;
|