@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.
- 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-exit.d.ts +11 -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-auth-fingerprint.d.ts +211 -0
- package/dist/src/codex-copresence-model.d.ts +23 -0
- package/dist/src/codex-copresence-preflight.d.ts +65 -0
- package/dist/src/codex-copresence-profile.d.ts +125 -0
- package/dist/src/codex-copresence-recovery.d.ts +58 -0
- package/dist/src/codex-copresence-thread.d.ts +13 -0
- package/dist/src/codex-home-enforce.d.ts +71 -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 +44 -0
- package/dist/src/codex-lifecycle-restart.d.ts +86 -0
- package/dist/src/codex-login-share-guard.d.ts +146 -0
- package/dist/src/codex-model-default.d.ts +6 -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 +353 -0
- package/dist/src/copresence-startup-diagnosis.d.ts +17 -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-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 +80 -0
- package/dist/src/im/feishu/bridge.d.ts +78 -14
- package/dist/src/im/feishu/config.d.ts +31 -0
- package/dist/src/im/feishu/hub-upload.d.ts +88 -0
- package/dist/src/im/feishu/outbound-route.d.ts +62 -0
- package/dist/src/im/feishu/worker-lifecycle.d.ts +13 -0
- package/dist/src/im/feishu/worker.js +187 -144
- package/dist/src/im/types.d.ts +30 -1
- 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-files.d.ts +62 -0
- package/dist/src/node-not-found.d.ts +1 -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.js +7 -1
- package/dist/src/node-skills.d.ts +32 -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 +25 -0
- package/dist/src/opencode-auth-login.d.ts +43 -0
- package/dist/src/opencode-launch-env.d.ts +13 -0
- package/dist/src/opencode-owner-mode.d.ts +6 -0
- package/dist/src/opencode-package-binary.d.ts +26 -0
- package/dist/src/opencode-pin.d.ts +44 -0
- package/dist/src/opencode-preset.d.ts +73 -0
- package/dist/src/opencode-runtime-binding.d.ts +30 -0
- package/dist/src/opencode-safe-root.d.ts +36 -0
- package/dist/src/opencode-smoke-env.d.ts +1 -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 +35 -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 +3 -0
- package/dist/src/session-status-class.d.ts +48 -0
- package/dist/src/sibling-agent-node.d.ts +23 -0
- package/dist/src/stale-socket.d.ts +118 -0
- package/dist/src/subcommand-redirect.d.ts +26 -0
- package/dist/src/task-trace.d.ts +33 -0
- package/dist/src/tmux-attach.d.ts +8 -0
- package/dist/src/tmux-capability.d.ts +58 -0
- package/dist/src/tmux-exact-target.d.ts +34 -0
- package/dist/src/tmux-pane-prompt.d.ts +22 -0
- package/dist/src/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 +17 -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 +11 -6
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export interface WakeLogEntryShape {
|
|
2
|
+
ts?: string;
|
|
3
|
+
status?: string;
|
|
4
|
+
summary?: string;
|
|
5
|
+
task_id?: string;
|
|
6
|
+
}
|
|
7
|
+
export interface WakeLogGoalShape {
|
|
8
|
+
goal_id: string;
|
|
9
|
+
progress_log?: WakeLogEntryShape[];
|
|
10
|
+
}
|
|
11
|
+
export interface WakeLogRenderOpts {
|
|
12
|
+
/** Trim to the last N entries. undefined = all. */
|
|
13
|
+
tail?: number;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Format progress_log as a JSON object suitable for `--json` output.
|
|
17
|
+
* Pure. Never reads/writes filesystem. Legacy goals without
|
|
18
|
+
* progress_log render as empty array (not error).
|
|
19
|
+
*/
|
|
20
|
+
export declare function renderWakeLogJson(goal: WakeLogGoalShape, opts?: WakeLogRenderOpts): {
|
|
21
|
+
goal_id: string;
|
|
22
|
+
total: number;
|
|
23
|
+
returned: number;
|
|
24
|
+
entries: WakeLogEntryShape[];
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* Format progress_log as a table for human console output.
|
|
28
|
+
* Column layout mirrors printGoalShow so the two commands read
|
|
29
|
+
* consistently. Empty log renders a single "(none)" line, not an error.
|
|
30
|
+
*/
|
|
31
|
+
export declare function renderWakeLogText(goal: WakeLogGoalShape, opts?: WakeLogRenderOpts): string;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export interface ActiveNetworkTask {
|
|
2
|
+
taskId: string;
|
|
3
|
+
from: string;
|
|
4
|
+
startedAt: number;
|
|
5
|
+
}
|
|
6
|
+
/** 运行时崩溃没来得及删标记时的兜底:超过这个年龄的标记当不存在。 */
|
|
7
|
+
export declare const ACTIVE_NETWORK_TASK_MAX_AGE_MS: number;
|
|
8
|
+
export declare function parseActiveNetworkTask(raw: string | null | undefined, now: number, maxAgeMs?: number): ActiveNetworkTask | null;
|
|
9
|
+
export type OutboundTool = "commhub_send_task" | "commhub_send_message";
|
|
10
|
+
export type OutboundRewrite = {
|
|
11
|
+
kind: "pass";
|
|
12
|
+
} | {
|
|
13
|
+
kind: "progress_of_active_task";
|
|
14
|
+
taskId: string;
|
|
15
|
+
from: string;
|
|
16
|
+
text: string;
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* 只在「目标 alias 恰好是当前网络任务的发起方」时改写;发给别人的照常放行——
|
|
20
|
+
* 模型替任务派活给第三方是合法的协作,不能一刀切。
|
|
21
|
+
*/
|
|
22
|
+
export declare function decideOutboundRewrite(tool: OutboundTool, args: {
|
|
23
|
+
alias?: unknown;
|
|
24
|
+
task?: unknown;
|
|
25
|
+
message?: unknown;
|
|
26
|
+
} | null | undefined, active: ActiveNetworkTask | null): OutboundRewrite;
|
|
27
|
+
/** outbound-only 模式下模型不能自选 high(#1770 第三条):降为 normal,其余原样。 */
|
|
28
|
+
export declare function clampOutboundPriority(priority: unknown, outboundOnly: boolean): "high" | "normal" | "low" | undefined;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolve one batch workdir before any mkdir/chdir loop starts.
|
|
3
|
+
*
|
|
4
|
+
* Node does not expand shell tildes. Leaving `~/team` relative means every
|
|
5
|
+
* iteration can resolve it from the previous node's cwd and create paths such
|
|
6
|
+
* as `/work/~/team/~/team`. Only the current user's `~` form is supported;
|
|
7
|
+
* `~other` is rejected instead of being written as a literal directory.
|
|
8
|
+
*/
|
|
9
|
+
export declare function normalizeBatchWorkdir(input: string, cwd?: string, home?: string): string;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export interface BootstrapPasswordUpdateInvocation {
|
|
2
|
+
argv: string[];
|
|
3
|
+
env: NodeJS.ProcessEnv;
|
|
4
|
+
script: string;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Resolve the database selected for the local Hub into an explicit absolute
|
|
8
|
+
* path before launching the bootstrap helper. The helper must never infer a
|
|
9
|
+
* database from its own HOME/cwd: those can differ from the parent process.
|
|
10
|
+
*/
|
|
11
|
+
export declare function resolveBootstrapDatabasePath(env: NodeJS.ProcessEnv, home: string, cwd: string): string;
|
|
12
|
+
export declare const BOOTSTRAP_PASSWORD_UPDATE_SCRIPT: string;
|
|
13
|
+
export declare function buildBootstrapPasswordUpdateInvocation(userId: string, dbPath: string, baseEnv?: NodeJS.ProcessEnv): BootstrapPasswordUpdateInvocation;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
interface AttachmentDescriptor {
|
|
2
|
+
type?: unknown;
|
|
3
|
+
file_id?: unknown;
|
|
4
|
+
path?: unknown;
|
|
5
|
+
mime?: unknown;
|
|
6
|
+
name?: unknown;
|
|
7
|
+
size?: unknown;
|
|
8
|
+
}
|
|
9
|
+
export interface ChannelAttachmentDeps {
|
|
10
|
+
hubUrl: string;
|
|
11
|
+
authToken: string;
|
|
12
|
+
cacheDir: string;
|
|
13
|
+
fetch?: typeof fetch;
|
|
14
|
+
maxBytes?: number;
|
|
15
|
+
}
|
|
16
|
+
export interface ChannelAttachmentResult {
|
|
17
|
+
paths: string[];
|
|
18
|
+
failures: Array<{
|
|
19
|
+
fileId: string;
|
|
20
|
+
code: string;
|
|
21
|
+
message: string;
|
|
22
|
+
}>;
|
|
23
|
+
}
|
|
24
|
+
export declare function readableAttachmentsFromInbox(message: any): AttachmentDescriptor[];
|
|
25
|
+
export declare function channelAttachmentCacheDir(home: string, alias: string): string;
|
|
26
|
+
export declare function downloadChannelAttachments(message: any, deps: ChannelAttachmentDeps): Promise<ChannelAttachmentResult>;
|
|
27
|
+
export declare const downloadChannelImageAttachments: typeof downloadChannelAttachments;
|
|
28
|
+
export declare function appendChannelAttachmentPaths(content: string, paths: readonly string[]): string;
|
|
29
|
+
export {};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/** SSE event types that mean "there is something new in your inbox". */
|
|
2
|
+
export declare const INBOX_WAKE_EVENTS: ReadonlySet<string>;
|
|
3
|
+
export declare function isInboxWakeEvent(type: unknown): boolean;
|
|
4
|
+
/**
|
|
5
|
+
* Single-flight runner: at most one drain runs at a time, and wakeups that
|
|
6
|
+
* arrive mid-drain collapse into exactly one rerun. Two concurrent drains
|
|
7
|
+
* would both fetch the same unacked rows and inject each task twice.
|
|
8
|
+
*/
|
|
9
|
+
export declare function createSingleFlight(run: () => Promise<void>): () => Promise<void>;
|
|
10
|
+
export declare const DEFAULT_INBOX_POLL_MS = 60000;
|
|
11
|
+
/** ANET_CHANNEL_INBOX_POLL_MS: poll period in ms; "0" disables the safety net. */
|
|
12
|
+
export declare function inboxPollIntervalMs(raw: string | undefined): number;
|
|
13
|
+
/**
|
|
14
|
+
* Periodically run the drain so a missed push costs at most one period.
|
|
15
|
+
* Returns a stop function. The timer never keeps the process alive.
|
|
16
|
+
*/
|
|
17
|
+
export declare function startInboxSafetyNet(opts: {
|
|
18
|
+
intervalMs: number;
|
|
19
|
+
drain: () => Promise<void>;
|
|
20
|
+
onError?: (error: unknown) => void;
|
|
21
|
+
}): () => void;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/** One inbound inbox row → the meta Claude Code renders as `<channel …>` attrs.
|
|
2
|
+
*
|
|
3
|
+
* Pure so the attribute set is assertable; it used to be inline in the SSE
|
|
4
|
+
* handler, where nothing could see it. */
|
|
5
|
+
export declare function inboundChannelMeta(msg: {
|
|
6
|
+
id: string;
|
|
7
|
+
from_session?: string | null;
|
|
8
|
+
priority?: string | null;
|
|
9
|
+
created_at?: string | null;
|
|
10
|
+
}): Record<string, string>;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
export declare const PEER_REPLY_TOOL_NAME = "commhub_send_peer_reply";
|
|
2
|
+
export interface ChannelPeerReplyInput {
|
|
3
|
+
task_id?: unknown;
|
|
4
|
+
text?: unknown;
|
|
5
|
+
status?: unknown;
|
|
6
|
+
alias?: unknown;
|
|
7
|
+
}
|
|
8
|
+
export interface ChannelPeerReplyDeps {
|
|
9
|
+
/** One Hub MCP tool call. Returns the parsed tool payload (ok:false on rejection); may throw on transport failure. */
|
|
10
|
+
call: (tool: string, args: Record<string, unknown>) => Promise<any>;
|
|
11
|
+
fromAlias: string;
|
|
12
|
+
/** Sender alias the channel recorded when it injected this task_id (in-memory; may be unknown after a restart). */
|
|
13
|
+
originatorOf?: (taskId: string) => string | undefined;
|
|
14
|
+
/** channel meta task_id is the inbox ROW id; map it to the logical tasks.task_id when known. */
|
|
15
|
+
logicalTaskIdOf?: (taskId: string) => string | undefined;
|
|
16
|
+
}
|
|
17
|
+
export type ChannelPeerReplyRoute = "atomic" | "wake-then-close" | "reply-only";
|
|
18
|
+
export interface ChannelPeerReplyResult {
|
|
19
|
+
ok: boolean;
|
|
20
|
+
route?: ChannelPeerReplyRoute;
|
|
21
|
+
/** The original task is now terminal. */
|
|
22
|
+
closed: boolean;
|
|
23
|
+
/** A wake was delivered to the peer (atomic result row or fallback send_task). */
|
|
24
|
+
woke: boolean;
|
|
25
|
+
task_id?: string;
|
|
26
|
+
error?: string;
|
|
27
|
+
message?: string;
|
|
28
|
+
wake_task_id?: string | null;
|
|
29
|
+
fallback_reason?: string;
|
|
30
|
+
upstream?: unknown;
|
|
31
|
+
}
|
|
32
|
+
/** The Hub rejected the ATOMIC route for a capability reason and wrote nothing. */
|
|
33
|
+
export declare function peerReplyFallbackReason(payload: any): string | null;
|
|
34
|
+
export declare function validatePeerReplyInput(input: ChannelPeerReplyInput): {
|
|
35
|
+
ok: true;
|
|
36
|
+
taskId: string;
|
|
37
|
+
text: string;
|
|
38
|
+
status: "completed" | "failed";
|
|
39
|
+
alias?: string;
|
|
40
|
+
} | ChannelPeerReplyResult;
|
|
41
|
+
export declare function sendChannelPeerReply(input: ChannelPeerReplyInput, deps: ChannelPeerReplyDeps): Promise<ChannelPeerReplyResult>;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export declare function sendChannelTaskWithTrace(input: {
|
|
2
|
+
alias: string;
|
|
3
|
+
task: string;
|
|
4
|
+
priority?: string;
|
|
5
|
+
fromAlias: string;
|
|
6
|
+
networkId?: string | null;
|
|
7
|
+
/** Structured task metadata forwarded verbatim, e.g. { attachments: [...] }.
|
|
8
|
+
* Omitted from the outbound body when absent, so a call without it is
|
|
9
|
+
* unchanged. */
|
|
10
|
+
meta?: Record<string, unknown>;
|
|
11
|
+
}, deps: {
|
|
12
|
+
send: (args: Record<string, unknown>) => Promise<any>;
|
|
13
|
+
log: (line: string) => void;
|
|
14
|
+
}): Promise<any>;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export declare const CLAUDE_VENDOR_ENV_KEYS: readonly ["ANTHROPIC_BASE_URL", "ANTHROPIC_AUTH_TOKEN", "ANTHROPIC_API_KEY"];
|
|
2
|
+
export type PlainSecretEnvRewrite = {
|
|
3
|
+
key: string;
|
|
4
|
+
refName: string;
|
|
5
|
+
value: string;
|
|
6
|
+
};
|
|
7
|
+
/**
|
|
8
|
+
* Plan the values that the node-create writer will move into its line-oriented
|
|
9
|
+
* `.env` file. This is deliberately side-effect free: callers can run it as a
|
|
10
|
+
* preflight before creating a node directory, changing process.env, or writing
|
|
11
|
+
* config.json. Keeping the line-break rejection here makes it cover every
|
|
12
|
+
* caller of the dotenv writer, including the no-name interactive wizard.
|
|
13
|
+
*/
|
|
14
|
+
export declare function planPlainSecretEnvRewrites(input: {
|
|
15
|
+
env: unknown;
|
|
16
|
+
nodeId: string;
|
|
17
|
+
}): PlainSecretEnvRewrite[];
|
|
18
|
+
/**
|
|
19
|
+
* Persist the exact Anthropic-compatible vendor environment used by an
|
|
20
|
+
* explicit claude-agent-sdk create. Explicit --env values retain precedence;
|
|
21
|
+
* ambient shell values only fill missing known keys. Other environment values
|
|
22
|
+
* are intentionally ignored so node create never snapshots the whole shell.
|
|
23
|
+
*/
|
|
24
|
+
export declare function collectClaudeVendorEnvForCreate(input: {
|
|
25
|
+
runtime: string;
|
|
26
|
+
explicitEnv: readonly string[];
|
|
27
|
+
shellEnv: Readonly<Record<string, string | undefined>>;
|
|
28
|
+
}): string[];
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export type ParsedCliOptions = {
|
|
2
|
+
[key: string]: string | string[];
|
|
3
|
+
_channels: string[];
|
|
4
|
+
_envs: string[];
|
|
5
|
+
};
|
|
6
|
+
export declare const BOOLEAN_FLAGS: Set<string>;
|
|
7
|
+
export declare function parseCliOptions(argv: string[]): ParsedCliOptions;
|
|
8
|
+
export declare function positionalArgs(argv: string[]): string[];
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
export type RevokeOutcome =
|
|
2
|
+
/** 服务端已撤销 */
|
|
3
|
+
{
|
|
4
|
+
kind: "revoked";
|
|
5
|
+
tokenId: string;
|
|
6
|
+
}
|
|
7
|
+
/** Hub 回 401:这个 token 在服务端本来就无效了(过期/已撤/改过密码),没东西可撤 */
|
|
8
|
+
| {
|
|
9
|
+
kind: "already_invalid";
|
|
10
|
+
}
|
|
11
|
+
/** 不是登录会话(显式 API 令牌 / 节点令牌):按设计不撤,仍有效 */
|
|
12
|
+
| {
|
|
13
|
+
kind: "not_a_session";
|
|
14
|
+
tokenId?: string;
|
|
15
|
+
}
|
|
16
|
+
/** Hub 没有 /api/auth/sessions(早于 #2114 的旧版本 → 404) */
|
|
17
|
+
| {
|
|
18
|
+
kind: "unsupported";
|
|
19
|
+
status: number;
|
|
20
|
+
}
|
|
21
|
+
/** 连不上 Hub(DNS / 拒绝连接 / 超时) */
|
|
22
|
+
| {
|
|
23
|
+
kind: "unreachable";
|
|
24
|
+
error: string;
|
|
25
|
+
}
|
|
26
|
+
/** 其他意外响应 */
|
|
27
|
+
| {
|
|
28
|
+
kind: "failed";
|
|
29
|
+
status?: number;
|
|
30
|
+
error: string;
|
|
31
|
+
};
|
|
32
|
+
export type FetchLike = (input: string, init?: RequestInit) => Promise<Response>;
|
|
33
|
+
export declare function normalizeHubUrl(url: string): string;
|
|
34
|
+
export declare function sameHub(a?: string | null, b?: string | null): boolean;
|
|
35
|
+
/** 本地登录态字段。hub 不在里面:退出登录不等于忘掉 Hub 地址。 */
|
|
36
|
+
export declare const LOCAL_CREDENTIAL_KEYS: readonly ["token", "user", "network_id", "network_name"];
|
|
37
|
+
export declare function clearLocalCredentials(gc: Record<string, any>): Record<string, any>;
|
|
38
|
+
/** 在 `hub` 上撤销 `token` 所代表的登录会话。只把 token 发给 `hub` 本身。 */
|
|
39
|
+
export declare function revokeCurrentLoginSession(hub: string, token: string, opts?: {
|
|
40
|
+
fetchImpl?: FetchLike;
|
|
41
|
+
timeoutMs?: number;
|
|
42
|
+
}): Promise<RevokeOutcome>;
|
|
43
|
+
/** 把撤销结果翻成给人看的行。`ok=false` 表示服务端令牌**仍然有效**,调用方按警告打印。 */
|
|
44
|
+
export declare function describeRevokeOutcome(o: RevokeOutcome, hub: string): {
|
|
45
|
+
ok: boolean;
|
|
46
|
+
lines: string[];
|
|
47
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export declare const ANET_EXIT: {
|
|
2
|
+
readonly OK: 0;
|
|
3
|
+
readonly FAILURE: 1;
|
|
4
|
+
readonly USAGE: 2;
|
|
5
|
+
};
|
|
6
|
+
/** 命令打印了错误、不再继续 —— 记下失败码,让 main() 的终结器用它退出。 */
|
|
7
|
+
export declare function markFailed(): void;
|
|
8
|
+
/** 用法错误(缺参数 / 未知子命令 / 非法取值)。 */
|
|
9
|
+
export declare function markUsageError(): void;
|
|
10
|
+
/** main() 正常返回后的退出码:命令记下过的码,没记过就是 0。 */
|
|
11
|
+
export declare function finalExitCode(): number;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* #1645 —— `anet doctor` 原先对三个 runtime CLI **只检查「在不在」**:
|
|
3
|
+
*
|
|
4
|
+
* try { execSync("codex --version", …); check("Codex CLI", true); } catch { … }
|
|
5
|
+
*
|
|
6
|
+
* 于是一个**装着、但太旧**的 CLI 会拿到一个 ✅。实测过一次:`codex-cli 0.149.1`
|
|
7
|
+
* 解不动上游 models 响应(`unknown variant \`max\``,它只认到 `xhigh`),
|
|
8
|
+
* rmcp worker 致命退出,用户看到的是 300s 超时 —— 而 doctor 说一切正常。
|
|
9
|
+
*
|
|
10
|
+
* 🔴 **这里只把版本摆出来,不做最低版本判定。**
|
|
11
|
+
* 「多少版本才够」由上游返回什么决定,不是我们能钉死的常量;猜一个下限,
|
|
12
|
+
* 会在别人升级 CLI、上游又改动之后变成误报。而一个会误报的检查,
|
|
13
|
+
* 第一周就会被人关掉。摆出实际版本,让读的人自己对得上号,是这一格
|
|
14
|
+
* 现在能诚实做到的全部。
|
|
15
|
+
*/
|
|
16
|
+
export declare function formatCliVersion(raw: unknown): string;
|
package/dist/src/client.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
const a0_0xf1c06c=a0_0x2fb6;(function(_0x24f5d0,_0x46255b){const _0x55a99b=a0_0x2fb6,_0x3a2bc6=_0x24f5d0();while(!![]){try{const _0x44d267=parseInt(_0x55a99b(0x1b3))/0x1+-parseInt(_0x55a99b(0x1da))/0x2*(parseInt(_0x55a99b(0x205))/0x3)+parseInt(_0x55a99b(0x1d8))/0x4*(-parseInt(_0x55a99b(0x1d0))/0x5)+-parseInt(_0x55a99b(0x1e3))/0x6*(-parseInt(_0x55a99b(0x1e6))/0x7)+parseInt(_0x55a99b(0x1f4))/0x8*(-parseInt(_0x55a99b(0x1eb))/0x9)+-parseInt(_0x55a99b(0x203))/0xa*(-parseInt(_0x55a99b(0x1c1))/0xb)+parseInt(_0x55a99b(0x1b6))/0xc*(-parseInt(_0x55a99b(0x1f6))/0xd);if(_0x44d267===_0x46255b)break;else _0x3a2bc6['push'](_0x3a2bc6['shift']());}catch(_0x45778e){_0x3a2bc6['push'](_0x3a2bc6['shift']());}}}(a0_0x10c1,0xee739));import{EventEmitter as a0_0x1aefac}from'events';import{hostname as a0_0x9816c1}from'os';class T extends a0_0x1aefac{[a0_0xf1c06c(0x208)];[a0_0xf1c06c(0x1cd)];[a0_0xf1c06c(0x1f2)];[a0_0xf1c06c(0x1d1)];[a0_0xf1c06c(0x1f1)];[a0_0xf1c06c(0x1c2)];[a0_0xf1c06c(0x1d5)];['heartbeatTimer'];[a0_0xf1c06c(0x1d4)];['running']=!0x1;constructor(_0xa28ffe){const _0x2f4640=a0_0xf1c06c;super();if(this[_0x2f4640(0x208)]=_0xa28ffe[_0x2f4640(0x208)][_0x2f4640(0x1bf)](/\/$/,''),this[_0x2f4640(0x1cd)]=_0xa28ffe[_0x2f4640(0x1cd)],this['token']=_0xa28ffe[_0x2f4640(0x1f2)],this[_0x2f4640(0x1d1)]=_0xa28ffe[_0x2f4640(0x1d1)]||_0x2f4640(0x1ba),this['resumeId']=_0x2f4640(0x1ca)+_0xa28ffe[_0x2f4640(0x1cd)]+'-'+Date['now']()[_0x2f4640(0x1f3)](0x24),this[_0x2f4640(0x1c2)]=_0xa28ffe[_0x2f4640(0x1c2)]??0x2bf20,this[_0x2f4640(0x1d5)]=_0xa28ffe['reconnectDelay']??0xbb8,_0xa28ffe[_0x2f4640(0x1f7)]!==!0x1)this['connect']();}[a0_0xf1c06c(0x1ef)](_0x5514ed){const _0x40161b=a0_0xf1c06c;console['log']('['+new Date()[_0x40161b(0x1de)]()[_0x40161b(0x1fc)](0x0,0x8)+_0x40161b(0x1fa)+this[_0x40161b(0x1cd)]+']\x20'+_0x5514ed);}async['call'](_0x435db5,_0xb0bcfc){const _0x566ce9=a0_0xf1c06c;let _0xa14dce={'Content-Type':_0x566ce9(0x1c0),'Accept':'application/json,\x20text/event-stream'};if(this[_0x566ce9(0x1f2)])_0xa14dce[_0x566ce9(0x1bd)]=_0x566ce9(0x1df)+this['token'];let _0x5f0e8c=await(await fetch(this[_0x566ce9(0x208)]+_0x566ce9(0x1c7),{'method':'POST','headers':_0xa14dce,'body':JSON['stringify']({'jsonrpc':_0x566ce9(0x20c),'id':Date['now'](),'method':_0x566ce9(0x1ce),'params':{'name':_0x435db5,'arguments':_0xb0bcfc}})}))[_0x566ce9(0x1cf)](),_0x1fd6ff=_0x5f0e8c[_0x566ce9(0x1c3)](/data: (.+)/),_0x32c202=_0x1fd6ff?JSON['parse'](_0x1fd6ff[0x1]):JSON[_0x566ce9(0x209)](_0x5f0e8c),_0x1569a9=_0x32c202?.[_0x566ce9(0x1c8)]?.['content']?.[0x0]?.[_0x566ce9(0x1cf)];return _0x1569a9?JSON['parse'](_0x1569a9):_0x32c202;}async['connect'](){const _0x63b9df=a0_0xf1c06c;if(this['running'])return;this[_0x63b9df(0x1bc)]=!0x0,await this[_0x63b9df(0x1dd)]('idle'),this[_0x63b9df(0x1ef)](_0x63b9df(0x1ed)),this[_0x63b9df(0x1b8)]=setInterval(()=>{const _0x4bb546=_0x63b9df;this[_0x4bb546(0x1dd)](_0x4bb546(0x1fe))[_0x4bb546(0x1b7)](_0x3c7c19=>this[_0x4bb546(0x1ef)](_0x4bb546(0x1c6)+_0x3c7c19['message']));},this[_0x63b9df(0x1c2)]),this['connectSSE']();}async[a0_0xf1c06c(0x206)](){const _0xf8a9e9=a0_0xf1c06c;if(this[_0xf8a9e9(0x1bc)]=!0x1,this[_0xf8a9e9(0x1d4)]?.['abort'](),this[_0xf8a9e9(0x1b8)])clearInterval(this[_0xf8a9e9(0x1b8)]);await this[_0xf8a9e9(0x1dd)](_0xf8a9e9(0x201))[_0xf8a9e9(0x1b7)](()=>{}),this[_0xf8a9e9(0x1ef)](_0xf8a9e9(0x1f5));}async['send'](_0x5799b8,_0xb54cb0,_0x24ed41=a0_0xf1c06c(0x207)){const _0x1e3a77=a0_0xf1c06c;return this[_0x1e3a77(0x1f8)]('send_task',{'alias':_0x5799b8,'task':_0xb54cb0,'priority':_0x24ed41,'from_session':this[_0x1e3a77(0x1cd)]});}async[a0_0xf1c06c(0x1cc)](_0x4bdfb4,_0x52ff34){const _0x2b341d=a0_0xf1c06c;return this[_0x2b341d(0x1f8)](_0x2b341d(0x1cb),{'alias':_0x4bdfb4,'message':_0x52ff34,'from_session':this[_0x2b341d(0x1cd)]});}async[a0_0xf1c06c(0x1ff)](_0x3c83d9,_0x5a06ec,_0xc8aa36=a0_0xf1c06c(0x1ec)){const _0x188c2b=a0_0xf1c06c;return this[_0x188c2b(0x1f8)](_0x188c2b(0x1c5),{'in_reply_to':_0x3c83d9,'text':_0x5a06ec,'status':_0xc8aa36});}async['status'](_0x53a109,_0x37edbd){const _0x1091ea=a0_0xf1c06c;return this['call'](_0x1091ea(0x202),{'resume_id':this[_0x1091ea(0x1f1)],'alias':this[_0x1091ea(0x1cd)],'status':_0x53a109,'server':a0_0x9816c1(),'hostname':a0_0x9816c1(),'agent':this[_0x1091ea(0x1d1)],'project_dir':process['cwd'](),..._0x37edbd});}async['getAllStatus'](){const _0x472c60=a0_0xf1c06c;return this[_0x472c60(0x1f8)](_0x472c60(0x1d6),{});}async[a0_0xf1c06c(0x1d3)](_0x59bff9,_0xc555a9){const _0x2bf5d0=a0_0xf1c06c;return this[_0x2bf5d0(0x1f8)]('broadcast',{'message':_0x59bff9,'filter_server':_0xc555a9?.['server'],'filter_status':_0xc555a9?.['status']});}async[a0_0xf1c06c(0x1e2)](){const _0x1c67a8=a0_0xf1c06c;let _0x5c0588=encodeURIComponent(this[_0x1c67a8(0x1cd)]),_0x26c11b=this['url']+_0x1c67a8(0x200)+_0x5c0588,_0x3e5be0=this[_0x1c67a8(0x1d5)];while(this[_0x1c67a8(0x1bc)]){try{this[_0x1c67a8(0x1d4)]=new AbortController();let _0x5dac57={'Accept':_0x1c67a8(0x1e1)};if(this['token'])_0x5dac57[_0x1c67a8(0x1bd)]=_0x1c67a8(0x1df)+this[_0x1c67a8(0x1f2)];let _0x3a096f=await fetch(_0x26c11b,{'headers':_0x5dac57,'signal':this[_0x1c67a8(0x1d4)][_0x1c67a8(0x1ee)]});if(!_0x3a096f['ok']||!_0x3a096f[_0x1c67a8(0x1c4)]){this['log'](_0x1c67a8(0x204)+_0x3a096f[_0x1c67a8(0x1dd)]),await this['sleep'](_0x3e5be0),_0x3e5be0=Math[_0x1c67a8(0x1e5)](_0x3e5be0*1.5,0xea60);continue;}_0x3e5be0=this[_0x1c67a8(0x1d5)];let _0x297609=_0x3a096f[_0x1c67a8(0x1c4)][_0x1c67a8(0x1b9)](),_0x3c4588=new TextDecoder(),_0x371de5='';while(this[_0x1c67a8(0x1bc)]){let {done:_0x38b805,value:_0x23dbec}=await _0x297609[_0x1c67a8(0x1e0)]();if(_0x38b805)break;_0x371de5+=_0x3c4588[_0x1c67a8(0x1f9)](_0x23dbec,{'stream':!0x0});let _0x39d447=_0x371de5[_0x1c67a8(0x1fd)]('\x0a');_0x371de5=_0x39d447['pop']()||'';for(let _0x16a83e of _0x39d447){if(!_0x16a83e['startsWith'](_0x1c67a8(0x1c9)))continue;try{let _0x4ba2c1=JSON[_0x1c67a8(0x209)](_0x16a83e[_0x1c67a8(0x1fc)](0x6));if(_0x4ba2c1[_0x1c67a8(0x1fb)]==='connected'){this['log'](_0x1c67a8(0x1f0)),this[_0x1c67a8(0x20d)](_0x1c67a8(0x1bb));continue;}if(_0x4ba2c1[_0x1c67a8(0x1fb)]===_0x1c67a8(0x1d7)||_0x4ba2c1[_0x1c67a8(0x1fb)]===_0x1c67a8(0x1e9)||_0x4ba2c1[_0x1c67a8(0x1fb)]===_0x1c67a8(0x1d3))await this[_0x1c67a8(0x20a)]();}catch{}}}}catch(_0x40632e){if(_0x40632e['name']===_0x1c67a8(0x1db))break;this['emit'](_0x1c67a8(0x1b4),_0x40632e),this['log'](_0x1c67a8(0x1dc)+_0x40632e[_0x1c67a8(0x1cc)]);}if(this[_0x1c67a8(0x1bc)])this[_0x1c67a8(0x20d)](_0x1c67a8(0x1f5)),this[_0x1c67a8(0x1ef)](_0x1c67a8(0x1d9)+_0x3e5be0/0x3e8+_0x1c67a8(0x1e7)),await this[_0x1c67a8(0x1e4)](_0x3e5be0),_0x3e5be0=Math['min'](_0x3e5be0*1.5,0xea60);}}async[a0_0xf1c06c(0x20a)](){const _0xc52ce6=a0_0xf1c06c;try{let _0x2515a3=(await this['call'](_0xc52ce6(0x20b),{'alias':this[_0xc52ce6(0x1cd)],'limit':0xa}))?.[_0xc52ce6(0x1be)]||[];for(let _0x334a8d of _0x2515a3)await this['call'](_0xc52ce6(0x1d2),{'alias':this[_0xc52ce6(0x1cd)],'message_id':_0x334a8d['id']}),this[_0xc52ce6(0x1ef)]('←\x20'+_0x334a8d[_0xc52ce6(0x1e8)]+':\x20'+_0x334a8d['content']['slice'](0x0,0x3c)),this[_0xc52ce6(0x20d)](_0xc52ce6(0x1b5),_0x334a8d),this['emit'](_0xc52ce6(0x1cc),_0x334a8d);}catch(_0x4aadd2){this['log'](_0xc52ce6(0x1ea)+_0x4aadd2[_0xc52ce6(0x1cc)]);}}[a0_0xf1c06c(0x1e4)](_0x1b31d3){return new Promise(_0x3661e1=>setTimeout(_0x3661e1,_0x1b31d3));}}function a0_0x2fb6(_0x13ed3c,_0x1f9da5){_0x13ed3c=_0x13ed3c-0x1b3;const _0x10c166=a0_0x10c1();let _0x2fb6e8=_0x10c166[_0x13ed3c];return _0x2fb6e8;}function a0_0x10c1(){const _0x509aab=['log','SSE\x20connected','resumeId','token','toString','24856cExImL','disconnected','117EeDmKL','autoConnect','call','decode',']\x20[commhub:','type','slice','split','idle','reply','/events/','offline','report_status','20whfLXo','SSE\x20failed:\x20','104724ZLoDSu','disconnect','normal','url','parse','processInbox','get_inbox','2.0','emit','1830591SdfYRp','error','task','716712GJYvvZ','catch','heartbeatTimer','getReader','sdk','connected','running','Authorization','messages','replace','application/json','3402487xYzowj','heartbeatInterval','match','body','send_reply','heartbeat\x20failed:\x20','/mcp','result','data:\x20','sdk-','send_message','message','alias','tools/call','text','19165TAbOWU','agent','ack_inbox','broadcast','sseAbort','reconnectDelay','get_all_status','new_task','244ZWUyeI','SSE\x20reconnecting\x20in\x20','38savXng','AbortError','SSE\x20error:\x20','status','toTimeString','Bearer\x20','read','text/event-stream','connectSSE','300PBUSRe','sleep','min','80381qpLuBM','s...','from_session','new_message','inbox\x20error:\x20','1773OkknaX','completed','registered','signal'];a0_0x10c1=function(){return _0x509aab;};return a0_0x10c1();}var $=T;export{$ as default,T as CommHub};
|
|
1
|
+
const a0_0x15d04e=a0_0x2533;function a0_0x2533(_0x133ede,_0x3c028c){_0x133ede=_0x133ede-0x16d;const _0x12772d=a0_0x1277();let _0x253375=_0x12772d[_0x133ede];return _0x253375;}(function(_0x134b15,_0x48f95b){const _0x309395=a0_0x2533,_0x5dab1f=_0x134b15();while(!![]){try{const _0x56f200=parseInt(_0x309395(0x1b5))/0x1+parseInt(_0x309395(0x1b9))/0x2+parseInt(_0x309395(0x1d3))/0x3+-parseInt(_0x309395(0x1b3))/0x4*(parseInt(_0x309395(0x1a0))/0x5)+-parseInt(_0x309395(0x1ab))/0x6*(-parseInt(_0x309395(0x184))/0x7)+parseInt(_0x309395(0x17e))/0x8+-parseInt(_0x309395(0x1a4))/0x9;if(_0x56f200===_0x48f95b)break;else _0x5dab1f['push'](_0x5dab1f['shift']());}catch(_0x24ae49){_0x5dab1f['push'](_0x5dab1f['shift']());}}}(a0_0x1277,0x74efa));import{EventEmitter as a0_0x293d8c}from'events';import{hostname as a0_0x458de4}from'os';var K=/(?:atok|ntok|utok|ghp|github_pat)_[A-Za-z0-9_-]+|Bearer\s+\S+/gi,L=(_0x29b2f8,_0x569852)=>(_0x29b2f8??_0x569852)[a0_0x15d04e(0x1d9)](/[\r\n\x00-\x1f\x7f]/g,'\x20')[a0_0x15d04e(0x1ea)](0x0,0xf0);function N(_0x159db5){const _0x1e8d27=a0_0x15d04e;return(_0x159db5 instanceof Error?_0x159db5[_0x1e8d27(0x172)]:String(_0x159db5??'unknown\x20error'))['replace'](K,_0x1e8d27(0x16f))[_0x1e8d27(0x1d9)](/[\r\n\x00-\x1f\x7f]/g,'\x20')[_0x1e8d27(0x1ea)](0x0,0xf0);}function O(_0x13f4f2,_0x724dfe=process.env.ANET_TASK_TRACE_FORMAT===a0_0x15d04e(0x188)){const _0x195916=a0_0x15d04e;if(_0x724dfe)return JSON[_0x195916(0x195)](_0x13f4f2);let _0x5152ae=L(_0x13f4f2[_0x195916(0x1be)],'<missing>'),_0x5b12e9=L(_0x13f4f2[_0x195916(0x19a)],_0x195916(0x1a5)),_0x7e6f56=_0x13f4f2[_0x195916(0x1b7)]?'\x20error='+_0x13f4f2['error_code']+':'+(_0x13f4f2[_0x195916(0x197)]??''):'';return _0x195916(0x1bb)+_0x13f4f2[_0x195916(0x173)]+_0x195916(0x170)+L(_0x13f4f2[_0x195916(0x1d6)],'<unknown>')+_0x195916(0x189)+L(_0x13f4f2[_0x195916(0x1e5)],_0x195916(0x1c7))+_0x195916(0x191)+_0x5b12e9+_0x195916(0x1a2)+_0x5152ae+'\x20network_id='+L(_0x13f4f2[_0x195916(0x17b)],_0x195916(0x1c7))+'\x20transport='+_0x13f4f2[_0x195916(0x1e1)]+_0x195916(0x1c0)+_0x13f4f2['duration_ms']+_0x195916(0x1de)+_0x13f4f2[_0x195916(0x1ad)]+_0x7e6f56;}function U(_0x27eed8){const _0x5927ff=a0_0x15d04e;return{'event':{'sending':_0x5927ff(0x1b8),'delivered':_0x5927ff(0x1b0),'failed':_0x5927ff(0x175),'acked':_0x5927ff(0x1bf),'started':_0x5927ff(0x1d1),'replied':_0x5927ff(0x1c6),'expired':'task.expired'}[_0x27eed8['status']],..._0x27eed8};}function j(_0x5f596c){const _0x27841c=a0_0x15d04e;let _0x50400f=_0x5f596c?.[_0x27841c(0x19a)]||_0x5f596c?.[_0x27841c(0x171)]||_0x5f596c?.['id'];if(_0x50400f)return String(_0x50400f);let _0x50f8f0=_0x5f596c?.[_0x27841c(0x1c4)]?.[0x0]?.[_0x27841c(0x1c1)];if(typeof _0x50f8f0!=='string')return null;try{let _0x1a1c99=JSON[_0x27841c(0x1a3)](_0x50f8f0);return _0x1a1c99?.[_0x27841c(0x19a)]||_0x1a1c99?.[_0x27841c(0x171)]||_0x1a1c99?.['id']||null;}catch{return null;}}async function X(_0x300f0d,_0x2a95de){const _0x28df19=a0_0x15d04e;let _0x3b5a52=_0x2a95de[_0x28df19(0x1e4)]??Date[_0x28df19(0x1e4)],_0x39a220=_0x3b5a52(),_0x47161f=(_0x499364,_0x19bdb3,_0x19a080,_0x418b8d)=>{const _0x1010bc=_0x28df19;_0x2a95de[_0x1010bc(0x185)](O(U({'from_alias':_0x300f0d[_0x1010bc(0x1c2)],'to_alias':_0x300f0d[_0x1010bc(0x1ba)],'task_id':_0x19bdb3,'parent_task_id':_0x300f0d[_0x1010bc(0x1c5)],'network_id':_0x300f0d[_0x1010bc(0x1a1)],'transport':_0x300f0d[_0x1010bc(0x1e1)],'status':_0x499364,'duration_ms':_0x3b5a52()-_0x39a220,'lifecycle_tracking':_0x300f0d[_0x1010bc(0x198)],..._0x19a080!==void 0x0?{'error_code':_0x418b8d||'send_failed','error_message':N(_0x19a080)}:{}})));};_0x47161f(_0x28df19(0x1c9),null);try{let _0x46bf0f=await _0x2a95de['send'](),_0x4ee81d=j(_0x46bf0f);if(_0x4ee81d)_0x47161f('delivered',_0x4ee81d);else{if(_0x46bf0f?.['ok']===!0x1||_0x46bf0f?.[_0x28df19(0x1d0)])_0x47161f('failed',_0x4ee81d,_0x46bf0f?.['error']||'CommHub\x20rejected\x20task',_0x28df19(0x1c3));else _0x47161f(_0x28df19(0x192),null,'CommHub\x20response\x20omitted\x20task_id','missing_task_id');}return _0x46bf0f;}catch(_0x50ca8d){throw _0x47161f('failed',null,_0x50ca8d,_0x28df19(0x1e8)),_0x50ca8d;}}function a0_0x1277(){const _0x3ea333=['type','\x20task_id=','failed','resumeId','data:\x20','stringify','min','error_message','lifecycleTracking','broadcast','task_id','Bearer\x20','token','connect','read','name','452940rpTDOP','networkId','\x20parent_task_id=','parse','13660479BGmlFu','<pending>','from_session','emit','signal','call','disconnected','2470410ZkwYza','connectSSE','lifecycle_tracking','normal','heartbeatInterval','task.send.delivered','completed','startsWith','8eCjDQq','2.0','131705pcVLAW','sleep','error_code','task.send.start','1848378vyMvEU','toAlias','[commhub:task]\x20','POST','idle','parent_task_id','task.ack','\x20duration_ms=','text','fromAlias','send_rejected','content','parentTaskId','task.replied','<unknown>','abort','sending','new_message','mcp_http','sdk','SSE\x20reconnecting\x20in\x20','/events/','connected','error','task.started','send','1949091pnVAbm',']\x20[commhub:','getAllStatus','from_alias','match','toTimeString','replace','SSE\x20connected','heartbeat\x20failed:\x20','reconnectDelay','agent','\x20lifecycle=','not_tracked','url','transport','ack_inbox','getReader','now','to_alias','body','send_reply','send_failed','registered','slice','SSE\x20failed:\x20','catch','[REDACTED]','\x20from=','message_id','message','status','inbox\x20error:\x20','task.send.failed','result','task','s...','new_task','get_inbox','network_id','sseAbort','tools/call','485208UYCQJh','cwd','heartbeatTimer','running','Authorization','send_task','7IiVMNN','log','SSE\x20error:\x20','sdk-','json','\x20to=','messages','server','processInbox','alias','/mcp','reply'];a0_0x1277=function(){return _0x3ea333;};return a0_0x1277();}async function Y(_0x536b46,_0x14838b){const _0x152032=a0_0x15d04e;return X({'fromAlias':_0x536b46[_0x152032(0x1c2)],'toAlias':_0x536b46[_0x152032(0x18d)],'parentTaskId':_0x536b46['parentTaskId']||null,'networkId':_0x536b46[_0x152032(0x1a1)]||null,'transport':_0x152032(0x1cb),'lifecycleTracking':_0x152032(0x1df)},_0x14838b);}class $ extends a0_0x293d8c{['url'];['alias'];[a0_0x15d04e(0x19c)];[a0_0x15d04e(0x1dd)];[a0_0x15d04e(0x193)];['heartbeatInterval'];[a0_0x15d04e(0x1dc)];['heartbeatTimer'];[a0_0x15d04e(0x17c)];[a0_0x15d04e(0x181)]=!0x1;constructor(_0x2ceb4a){const _0x3b8f3e=a0_0x15d04e;super();if(this['url']=_0x2ceb4a[_0x3b8f3e(0x1e0)][_0x3b8f3e(0x1d9)](/\/$/,''),this['alias']=_0x2ceb4a[_0x3b8f3e(0x18d)],this[_0x3b8f3e(0x19c)]=_0x2ceb4a[_0x3b8f3e(0x19c)],this[_0x3b8f3e(0x1dd)]=_0x2ceb4a['agent']||_0x3b8f3e(0x1cc),this[_0x3b8f3e(0x193)]=_0x3b8f3e(0x187)+_0x2ceb4a[_0x3b8f3e(0x18d)]+'-'+Date['now']()['toString'](0x24),this[_0x3b8f3e(0x1af)]=_0x2ceb4a['heartbeatInterval']??0x2bf20,this[_0x3b8f3e(0x1dc)]=_0x2ceb4a[_0x3b8f3e(0x1dc)]??0xbb8,_0x2ceb4a['autoConnect']!==!0x1)this[_0x3b8f3e(0x19d)]();}[a0_0x15d04e(0x185)](_0x1d2477){const _0x4684ae=a0_0x15d04e;console[_0x4684ae(0x185)]('['+new Date()[_0x4684ae(0x1d8)]()[_0x4684ae(0x1ea)](0x0,0x8)+_0x4684ae(0x1d4)+this['alias']+']\x20'+_0x1d2477);}async[a0_0x15d04e(0x1a9)](_0x3a2b84,_0x1fd039){const _0x261624=a0_0x15d04e;let _0x13c12f={'Content-Type':'application/json','Accept':'application/json,\x20text/event-stream'};if(this[_0x261624(0x19c)])_0x13c12f[_0x261624(0x182)]='Bearer\x20'+this['token'];let _0x5cdd46=await(await fetch(this[_0x261624(0x1e0)]+_0x261624(0x18e),{'method':_0x261624(0x1bc),'headers':_0x13c12f,'body':JSON[_0x261624(0x195)]({'jsonrpc':_0x261624(0x1b4),'id':Date[_0x261624(0x1e4)](),'method':_0x261624(0x17d),'params':{'name':_0x3a2b84,'arguments':_0x1fd039}})}))[_0x261624(0x1c1)](),_0x3937bc=_0x5cdd46[_0x261624(0x1d7)](/data: (.+)/),_0x59dc7e=_0x3937bc?JSON['parse'](_0x3937bc[0x1]):JSON[_0x261624(0x1a3)](_0x5cdd46),_0x3b2b18=_0x59dc7e?.[_0x261624(0x176)]?.['content']?.[0x0]?.[_0x261624(0x1c1)];return _0x3b2b18?JSON[_0x261624(0x1a3)](_0x3b2b18):_0x59dc7e;}async[a0_0x15d04e(0x19d)](){const _0x1ec597=a0_0x15d04e;if(this['running'])return;this['running']=!0x0,await this[_0x1ec597(0x173)](_0x1ec597(0x1bd)),this['log'](_0x1ec597(0x1e9)),this[_0x1ec597(0x180)]=setInterval(()=>{const _0x4916a8=_0x1ec597;this[_0x4916a8(0x173)](_0x4916a8(0x1bd))['catch'](_0x41cb59=>this[_0x4916a8(0x185)](_0x4916a8(0x1db)+_0x41cb59[_0x4916a8(0x172)]));},this[_0x1ec597(0x1af)]),this[_0x1ec597(0x1ac)]();}async['disconnect'](){const _0x27cf01=a0_0x15d04e;if(this[_0x27cf01(0x181)]=!0x1,this[_0x27cf01(0x17c)]?.[_0x27cf01(0x1c8)](),this[_0x27cf01(0x180)])clearInterval(this[_0x27cf01(0x180)]);await this['status']('offline')[_0x27cf01(0x16e)](()=>{}),this[_0x27cf01(0x185)](_0x27cf01(0x1aa));}async[a0_0x15d04e(0x1d2)](_0x191137,_0x35c471,_0x28cd92=a0_0x15d04e(0x1ae)){const _0x1ea79a=a0_0x15d04e;return Y({'alias':_0x191137,'fromAlias':this[_0x1ea79a(0x18d)]},{'log':_0x33e3bc=>console[_0x1ea79a(0x185)](_0x33e3bc),'send':()=>this[_0x1ea79a(0x1a9)](_0x1ea79a(0x183),{'alias':_0x191137,'task':_0x35c471,'priority':_0x28cd92,'from_session':this['alias']})});}async[a0_0x15d04e(0x172)](_0x34b7ca,_0x39366c){const _0x997a9e=a0_0x15d04e;return this[_0x997a9e(0x1a9)]('send_message',{'alias':_0x34b7ca,'message':_0x39366c,'from_session':this[_0x997a9e(0x18d)]});}async[a0_0x15d04e(0x18f)](_0x587c2c,_0x50a3a6,_0xbef49c=a0_0x15d04e(0x1b1)){const _0x598b6e=a0_0x15d04e;return this[_0x598b6e(0x1a9)](_0x598b6e(0x1e7),{'in_reply_to':_0x587c2c,'text':_0x50a3a6,'status':_0xbef49c});}async[a0_0x15d04e(0x173)](_0x223ea8,_0x496e84){const _0x15a59e=a0_0x15d04e;return this[_0x15a59e(0x1a9)]('report_status',{'resume_id':this[_0x15a59e(0x193)],'alias':this[_0x15a59e(0x18d)],'status':_0x223ea8,'server':a0_0x458de4(),'hostname':a0_0x458de4(),'agent':this[_0x15a59e(0x1dd)],'project_dir':process[_0x15a59e(0x17f)](),..._0x496e84});}async[a0_0x15d04e(0x1d5)](){const _0xb43964=a0_0x15d04e;return this[_0xb43964(0x1a9)]('get_all_status',{});}async[a0_0x15d04e(0x199)](_0x28b497,_0x67fed6){const _0x311df3=a0_0x15d04e;return this[_0x311df3(0x1a9)](_0x311df3(0x199),{'message':_0x28b497,'filter_server':_0x67fed6?.[_0x311df3(0x18b)],'filter_status':_0x67fed6?.[_0x311df3(0x173)]});}async[a0_0x15d04e(0x1ac)](){const _0x56a87f=a0_0x15d04e;let _0x5c6eb0=encodeURIComponent(this[_0x56a87f(0x18d)]),_0x36273b=this[_0x56a87f(0x1e0)]+_0x56a87f(0x1ce)+_0x5c6eb0,_0x32b7b7=this[_0x56a87f(0x1dc)];while(this[_0x56a87f(0x181)]){try{this['sseAbort']=new AbortController();let _0x205207={'Accept':'text/event-stream'};if(this[_0x56a87f(0x19c)])_0x205207[_0x56a87f(0x182)]=_0x56a87f(0x19b)+this[_0x56a87f(0x19c)];let _0x469ba5=await fetch(_0x36273b,{'headers':_0x205207,'signal':this['sseAbort'][_0x56a87f(0x1a8)]});if(!_0x469ba5['ok']||!_0x469ba5['body']){this[_0x56a87f(0x185)](_0x56a87f(0x16d)+_0x469ba5[_0x56a87f(0x173)]),await this[_0x56a87f(0x1b6)](_0x32b7b7),_0x32b7b7=Math['min'](_0x32b7b7*1.5,0xea60);continue;}_0x32b7b7=this[_0x56a87f(0x1dc)];let _0x5cc4d9=_0x469ba5[_0x56a87f(0x1e6)][_0x56a87f(0x1e3)](),_0xcfe664=new TextDecoder(),_0xab3674='';while(this['running']){let {done:_0x46419e,value:_0x12544d}=await _0x5cc4d9[_0x56a87f(0x19e)]();if(_0x46419e)break;_0xab3674+=_0xcfe664['decode'](_0x12544d,{'stream':!0x0});let _0x31f78b=_0xab3674['split']('\x0a');_0xab3674=_0x31f78b['pop']()||'';for(let _0x5e0df1 of _0x31f78b){if(!_0x5e0df1[_0x56a87f(0x1b2)](_0x56a87f(0x194)))continue;try{let _0x4c32bc=JSON[_0x56a87f(0x1a3)](_0x5e0df1[_0x56a87f(0x1ea)](0x6));if(_0x4c32bc[_0x56a87f(0x190)]==='connected'){this['log'](_0x56a87f(0x1da)),this[_0x56a87f(0x1a7)](_0x56a87f(0x1cf));continue;}if(_0x4c32bc[_0x56a87f(0x190)]===_0x56a87f(0x179)||_0x4c32bc['type']===_0x56a87f(0x1ca)||_0x4c32bc['type']===_0x56a87f(0x199))await this[_0x56a87f(0x18c)]();}catch{}}}}catch(_0x4ce3a6){if(_0x4ce3a6[_0x56a87f(0x19f)]==='AbortError')break;this['emit'](_0x56a87f(0x1d0),_0x4ce3a6),this['log'](_0x56a87f(0x186)+_0x4ce3a6[_0x56a87f(0x172)]);}if(this[_0x56a87f(0x181)])this[_0x56a87f(0x1a7)]('disconnected'),this[_0x56a87f(0x185)](_0x56a87f(0x1cd)+_0x32b7b7/0x3e8+_0x56a87f(0x178)),await this[_0x56a87f(0x1b6)](_0x32b7b7),_0x32b7b7=Math[_0x56a87f(0x196)](_0x32b7b7*1.5,0xea60);}}async[a0_0x15d04e(0x18c)](){const _0x146592=a0_0x15d04e;try{let _0xe851f9=(await this[_0x146592(0x1a9)](_0x146592(0x17a),{'alias':this[_0x146592(0x18d)],'limit':0xa}))?.[_0x146592(0x18a)]||[];for(let _0x327636 of _0xe851f9)await this[_0x146592(0x1a9)](_0x146592(0x1e2),{'alias':this[_0x146592(0x18d)],'message_id':_0x327636['id']}),this[_0x146592(0x185)]('←\x20'+_0x327636[_0x146592(0x1a6)]+':\x20'+_0x327636['content'][_0x146592(0x1ea)](0x0,0x3c)),this[_0x146592(0x1a7)](_0x146592(0x177),_0x327636),this[_0x146592(0x1a7)](_0x146592(0x172),_0x327636);}catch(_0x5c35d5){this[_0x146592(0x185)](_0x146592(0x174)+_0x5c35d5[_0x146592(0x172)]);}}['sleep'](_0x55af54){return new Promise(_0x145925=>setTimeout(_0x145925,_0x55af54));}}var F=$;export{F as default,$ as CommHub};
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
/** Per-node record, written into the node dir next to the other state files. */
|
|
2
|
+
export declare const CODEX_AUTH_FINGERPRINT_FILE = ".codex-auth-fingerprint.json";
|
|
3
|
+
/**
|
|
4
|
+
* Host-wide index of the same records — the read side's source of truth.
|
|
5
|
+
*
|
|
6
|
+
* Under `~/.anet/` because that is already this repo's host-scoped state
|
|
7
|
+
* directory (global config lives there) and it does not move with `cwd`, which
|
|
8
|
+
* is the entire point: the nodes that need to see each other are in different
|
|
9
|
+
* workspaces.
|
|
10
|
+
*/
|
|
11
|
+
export declare function codexFingerprintIndexDir(home?: string): string;
|
|
12
|
+
/**
|
|
13
|
+
* Index filename for a node.
|
|
14
|
+
*
|
|
15
|
+
* 🔴 Derived from the node's DIRECTORY, never its alias. Aliases are not unique
|
|
16
|
+
* across workspaces — the reference fleet runs a node beside its own `2号`
|
|
17
|
+
* twin, and nothing stops two workspaces from using one name — so an
|
|
18
|
+
* alias-keyed file would let one node silently overwrite another's record,
|
|
19
|
+
* re-creating the very blindness this index fixes. A directory cannot be two
|
|
20
|
+
* nodes.
|
|
21
|
+
*
|
|
22
|
+
* 🔴 And derived from the directory rather than from `node_id`, even though the
|
|
23
|
+
* CLI has one handy: agent-node's `NODE_ID` can be empty (older configs), so
|
|
24
|
+
* a node_id key would need a fallback — and then the same node would write
|
|
25
|
+
* one filename from one launch path and a different one from the other,
|
|
26
|
+
* leaving two records that look like two nodes sharing a credential. One
|
|
27
|
+
* deterministic key from an input both call sites already have is worth more
|
|
28
|
+
* than a prettier name. `node_id` is still recorded, for humans.
|
|
29
|
+
*/
|
|
30
|
+
export declare function codexFingerprintIndexFile(nodeDir: string): string;
|
|
31
|
+
/** Length of the stored fingerprint. Collisions at 8 hex are ~1 in 4 billion;
|
|
32
|
+
* a false "these two share a login" warning costs a second look, while the
|
|
33
|
+
* value staying short keeps it obviously non-reversible in logs. */
|
|
34
|
+
export declare const FINGERPRINT_LENGTH = 8;
|
|
35
|
+
/** Access tokens measured on the reference fleet: `exp - iat` was exactly this,
|
|
36
|
+
* on 29 of 29 samples, with no jitter. Used only to phrase "how long until the
|
|
37
|
+
* shared copy dies" when we have an `exp` but no `iat`. */
|
|
38
|
+
export declare const ACCESS_TOKEN_LIFETIME_SECONDS = 864000;
|
|
39
|
+
/** Past this, a published record's age is shown beside the alias. It does not
|
|
40
|
+
* suppress the warning: a node that has not started in a week still holds the
|
|
41
|
+
* shared credential. See the liveness note on `checkCodexCredentialSharing`. */
|
|
42
|
+
export declare const STALE_RECORD_NOTICE_MS: number;
|
|
43
|
+
export interface CodexAuthFingerprintRecord {
|
|
44
|
+
readonly schema_version: 1 | 2 | 3;
|
|
45
|
+
readonly alias: string;
|
|
46
|
+
/** sha256(refresh_token) truncated — never the token. */
|
|
47
|
+
readonly fingerprint: string;
|
|
48
|
+
readonly written_at: string;
|
|
49
|
+
/** v2: when this copy's ACCESS token expires, ISO-8601, or null if unreadable.
|
|
50
|
+
* A timestamp, not a credential. Two nodes holding one copied file share this
|
|
51
|
+
* instant exactly — which is how "they stop together" becomes observable. */
|
|
52
|
+
readonly access_expires_at?: string | null;
|
|
53
|
+
/** v2: the CODEX_HOME this record was read from. Distinguishes "two copies of
|
|
54
|
+
* one credential" from "two nodes pointed at one directory", which need
|
|
55
|
+
* different fixes. */
|
|
56
|
+
readonly codex_home?: string | null;
|
|
57
|
+
/** v3: the node directory this record describes, canonical. Three jobs: it is
|
|
58
|
+
* the identity used to de-duplicate the index against the sibling scan and to
|
|
59
|
+
* exclude self; and it is the liveness test — if this directory is gone, the
|
|
60
|
+
* node is gone and the record must not accuse anyone. */
|
|
61
|
+
readonly node_dir?: string;
|
|
62
|
+
/** v3: recorded for humans reading the index by hand. Never the key: it can be
|
|
63
|
+
* absent, and a key that is sometimes absent produces two records per node. */
|
|
64
|
+
readonly node_id?: string | null;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Hash the refresh token out of an auth.json body.
|
|
68
|
+
*
|
|
69
|
+
* Accepts both shapes seen in the wild: the current codex layout nests it
|
|
70
|
+
* under `tokens` (`{auth_mode, tokens:{id_token, access_token, refresh_token,
|
|
71
|
+
* account_id}, last_refresh}`), and older/plain bodies put `refresh_token` at
|
|
72
|
+
* the top level. Anything else — unparsable, absent, empty, non-string —
|
|
73
|
+
* returns null, because "we cannot tell" must not be reported as "no
|
|
74
|
+
* collision".
|
|
75
|
+
*/
|
|
76
|
+
export declare function fingerprintRefreshToken(authJsonText: string): string | null;
|
|
77
|
+
/**
|
|
78
|
+
* When this copy's access token expires, read out of the JWT's own payload.
|
|
79
|
+
*
|
|
80
|
+
* The signature is NOT verified and nothing here authenticates: we are reading
|
|
81
|
+
* a timestamp the token states about itself, the same way `jwt.io` would. A
|
|
82
|
+
* token that is not a JWT, or carries no numeric `exp`, yields null — unknown
|
|
83
|
+
* stays unknown.
|
|
84
|
+
*/
|
|
85
|
+
export declare function accessTokenExpiry(authJsonText: string): Date | null;
|
|
86
|
+
export interface NodeFingerprint {
|
|
87
|
+
readonly alias: string;
|
|
88
|
+
/** null when the node has no auth.json, or one we could not read. */
|
|
89
|
+
readonly fingerprint: string | null;
|
|
90
|
+
/** When the record was written; used to say how stale a claim is. */
|
|
91
|
+
readonly writtenAt?: string | null;
|
|
92
|
+
/** When this copy's access token expires, if we could read it. */
|
|
93
|
+
readonly accessExpiresAt?: Date | null;
|
|
94
|
+
/** The CODEX_HOME this fingerprint came from, if known. */
|
|
95
|
+
readonly codexHome?: string | null;
|
|
96
|
+
/** Canonical node directory — identity for de-duplication and self-exclusion. */
|
|
97
|
+
readonly nodeDir?: string | null;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Other nodes holding the same credential chain as `self`.
|
|
101
|
+
*
|
|
102
|
+
* Records with no fingerprint are skipped rather than grouped: "unknown" is
|
|
103
|
+
* not a match.
|
|
104
|
+
*
|
|
105
|
+
* 🔴 Self is excluded by node DIRECTORY when both sides carry one, and only
|
|
106
|
+
* falls back to alias for pre-v3 records. Once the read side is host-wide,
|
|
107
|
+
* alias stops being an identity: two workspaces may each hold a node called
|
|
108
|
+
* the same thing, and excluding by name would hide a genuine collision
|
|
109
|
+
* between them — the exact failure this index was added to fix.
|
|
110
|
+
*/
|
|
111
|
+
export declare function collidingNodes(records: readonly NodeFingerprint[], self: NodeFingerprint): NodeFingerprint[];
|
|
112
|
+
/**
|
|
113
|
+
* The warning an operator sees at start. Returns [] when nothing collides —
|
|
114
|
+
* callers print exactly what they get, so silence is representable and the
|
|
115
|
+
* "no collision" path cannot accidentally print a scary empty banner.
|
|
116
|
+
*
|
|
117
|
+
* Deliberately a warning and never a refusal: every node on a host shares one
|
|
118
|
+
* login today, so refusing to start would take the whole box down at once
|
|
119
|
+
* over a condition that is survivable until the next refresh.
|
|
120
|
+
*
|
|
121
|
+
* 🔴 Two outcomes, and the wrong one is actively misleading. The default text
|
|
122
|
+
* ("whichever node refreshes first keeps working") assumes refresh WORKS.
|
|
123
|
+
* On a host that cannot reach the OAuth token endpoint — egress blocked, or
|
|
124
|
+
* a proxy that allowlists the model API and 403s everything else — nobody
|
|
125
|
+
* refreshes, and the nodes holding one copy do not degrade one at a time:
|
|
126
|
+
* they stop together the moment the shared access token expires. Field case:
|
|
127
|
+
* three nodes whose auth.json files were byte-identical, carrying one access
|
|
128
|
+
* token, all expired at the same instant.
|
|
129
|
+
*
|
|
130
|
+
* We do NOT probe the network to tell these apart — a start path is the wrong
|
|
131
|
+
* place to open a socket, and a probe would answer for this moment rather
|
|
132
|
+
* than for the window that matters. We branch on evidence already in the
|
|
133
|
+
* file: an access token whose `exp` has passed is a copy that demonstrably
|
|
134
|
+
* stopped being refreshed, which is the observable the field case exhibits.
|
|
135
|
+
* When `exp` is still in the future we cannot prove reachability either way,
|
|
136
|
+
* and the default wording is the right one to print.
|
|
137
|
+
*/
|
|
138
|
+
export declare function sharedCredentialWarningLines(self: NodeFingerprint, colliding: readonly NodeFingerprint[], now?: Date): string[];
|
|
139
|
+
/**
|
|
140
|
+
* Two different things both read as "codex cannot refresh", and they need
|
|
141
|
+
* opposite remedies. Telling them apart is the whole value of this mapping:
|
|
142
|
+
* treating a transport failure as a rotation conflict sends an operator to
|
|
143
|
+
* copy someone else's auth.json, which is precisely how a shared-credential
|
|
144
|
+
* chain gets created.
|
|
145
|
+
*/
|
|
146
|
+
export type CodexRefreshFailureKind =
|
|
147
|
+
/** Someone else spent this refresh token first. */
|
|
148
|
+
"rotation-conflict"
|
|
149
|
+
/** The token endpoint is unreachable — nobody's token is rotating. */
|
|
150
|
+
| "token-endpoint-unreachable";
|
|
151
|
+
export interface CodexRefreshFailure {
|
|
152
|
+
readonly kind: CodexRefreshFailureKind;
|
|
153
|
+
readonly lines: string[];
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Name what actually went wrong with a codex refresh, and say what to do.
|
|
157
|
+
*
|
|
158
|
+
* Returns null for anything else, so callers fall through to whatever they
|
|
159
|
+
* printed before — an unrelated error must pass through unchanged.
|
|
160
|
+
*
|
|
161
|
+
* Order matters: a reuse rejection is a server answer and is checked first; a
|
|
162
|
+
* transport failure means no answer arrived at all.
|
|
163
|
+
*/
|
|
164
|
+
export declare function describeCodexRefreshFailure(text: string, colliding?: readonly NodeFingerprint[]): CodexRefreshFailure | null;
|
|
165
|
+
export interface CodexCredentialSharingCheck {
|
|
166
|
+
/** This node's own directory — where its record is written. */
|
|
167
|
+
readonly nodeDir: string;
|
|
168
|
+
/** Shown to the operator; also how a node recognises its own record. */
|
|
169
|
+
readonly alias: string;
|
|
170
|
+
/** The CODEX_HOME whose auth.json this node will actually use. */
|
|
171
|
+
readonly codexHome: string;
|
|
172
|
+
/** Recorded for humans reading the index; never used as a key. Optional
|
|
173
|
+
* because agent-node's can be empty on older configs. */
|
|
174
|
+
readonly nodeId?: string | null;
|
|
175
|
+
/** Where the warning goes. Defaults to stderr. */
|
|
176
|
+
readonly say?: (message: string) => void;
|
|
177
|
+
/** Injected for tests; production passes nothing. */
|
|
178
|
+
readonly now?: Date;
|
|
179
|
+
/** Injected for tests; production uses the real host index under `~/.anet`. */
|
|
180
|
+
readonly indexDir?: string;
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* The whole operation: read this node's credential, publish an 8-hex record,
|
|
184
|
+
* read what the *other* nodes published, and warn if any of them is on the
|
|
185
|
+
* same chain. Returns the colliding nodes so a caller can name them again if
|
|
186
|
+
* codex later fails to refresh.
|
|
187
|
+
*
|
|
188
|
+
* 🔴 Reads the neighbours' published fingerprint files, never their
|
|
189
|
+
* credentials. A guard against credential sharing must not itself become a
|
|
190
|
+
* reason to open every node's auth.json.
|
|
191
|
+
*
|
|
192
|
+
* 🔴 Always recomputes. The fingerprint changes every time codex refreshes in
|
|
193
|
+
* place, so a stale record is a wrong answer; both call paths may run for
|
|
194
|
+
* one node in sequence, and whichever runs last must leave the current
|
|
195
|
+
* value, never an older one.
|
|
196
|
+
*
|
|
197
|
+
* 🔴 Liveness is EXISTENCE, not age. An index record outlives the node that
|
|
198
|
+
* wrote it, and a stale one accusing a node that no longer exists is worse
|
|
199
|
+
* than silence — it teaches operators to ignore the warning. So a record
|
|
200
|
+
* whose `node_dir` is gone is dropped and its index entry deleted.
|
|
201
|
+
* Age deliberately does NOT filter: on the reference fleet two of the three
|
|
202
|
+
* nodes in the worst-affected group were not running at all, and six of 29
|
|
203
|
+
* credential files had not been touched in days, while still holding the
|
|
204
|
+
* shared copy. An age cutoff would have hidden precisely the collisions
|
|
205
|
+
* worth reporting. Age is surfaced in the warning instead, so the operator
|
|
206
|
+
* can judge how old the claim is.
|
|
207
|
+
*
|
|
208
|
+
* Never throws and never refuses: observability must not be the reason a node
|
|
209
|
+
* will not start.
|
|
210
|
+
*/
|
|
211
|
+
export declare function checkCodexCredentialSharing(opts: CodexCredentialSharingCheck): NodeFingerprint[];
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* #512 — which model a codex co-presence start runs on, and why.
|
|
3
|
+
*
|
|
4
|
+
* Order: explicit `--model` flag > the node's own config (`model` in
|
|
5
|
+
* .anet/nodes/<id>/config.json, written by `anet node create --model` /
|
|
6
|
+
* `anet node edit --model`) > DEFAULT_CODEX_MODEL.
|
|
7
|
+
*
|
|
8
|
+
* The bug this replaces: the start path computed `opts.model || DEFAULT`
|
|
9
|
+
* where `opts.model` was ONLY the CLI flag, so every start that did not
|
|
10
|
+
* repeat `--model` — the plain `anet node start <name>`, the boot sweep, and
|
|
11
|
+
* `anet node codex start|restart|resume` (which re-invoke `node start`
|
|
12
|
+
* without `--model`) — silently put the node on the default.
|
|
13
|
+
*
|
|
14
|
+
* One resolved value feeds all three pieces (app-server `-c model=`, the
|
|
15
|
+
* thread/resume `model` override, TUI `-m`), so they cannot disagree.
|
|
16
|
+
*/
|
|
17
|
+
export type CodexModelSource = "flag" | "node-config" | "default";
|
|
18
|
+
export interface ResolvedCodexModel {
|
|
19
|
+
model: string;
|
|
20
|
+
source: CodexModelSource;
|
|
21
|
+
}
|
|
22
|
+
export declare function resolveCodexCopresenceModel(flagModel: unknown, nodeConfigModel: unknown, fallback?: string): ResolvedCodexModel;
|
|
23
|
+
export declare function describeCodexModelSource(r: ResolvedCodexModel): string;
|