qlogicagent 2.15.7 → 2.15.9

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.
@@ -46,6 +46,13 @@ export declare function handleAgentsConfig(this: AgentsHandlerHost, msg: AgentRp
46
46
  export declare function handleAgentsSetConfig(this: AgentsHandlerHost, msg: AgentRpcRequest): Promise<void>;
47
47
  export declare function handleAgentsGetConfig(this: AgentsHandlerHost, msg: AgentRpcRequest): Promise<void>;
48
48
  export declare function handleAgentsRemoveConfig(this: AgentsHandlerHost, msg: AgentRpcRequest): Promise<void>;
49
+ /**
50
+ * Log out / switch account for an `account`-mode agent: clear the CLI's own native credential store
51
+ * (where we know it — e.g. codex's ~/.codex/auth.json) and invalidate the resident pool so the next
52
+ * turn re-evaluates auth (and re-prompts login). For agents whose store we don't manage, returns a
53
+ * hint to run the CLI's own `logout`. "Switch account" = logout, then log in again.
54
+ */
55
+ export declare function handleAgentsLogout(this: AgentsHandlerHost, msg: AgentRpcRequest): Promise<void>;
49
56
  export declare function handleAgentsSetGateway(this: AgentsHandlerHost, msg: AgentRpcRequest): Promise<void>;
50
57
  export declare function handleAgentsGetGateway(this: AgentsHandlerHost, msg: AgentRpcRequest): Promise<void>;
51
58
  export declare function handleAgentsListConfigured(this: AgentsHandlerHost, msg: AgentRpcRequest): Promise<void>;
@@ -5,7 +5,7 @@
5
5
  * external ACP-compatible agent CLIs alongside qlogicagent's internal agents.
6
6
  */
7
7
  import type { AgentCapabilities, CustomAgentDef, AgentConfig, ProductTaskStatus, ProductInstanceDef, ProductTaskDef } from "./agent-methods.js";
8
- export type { AgentCategory, AgentProtocol, AgentStatus, AgentCapabilities, AgentDescriptor, CustomAgentDef, AgentConfig, SoloState, SoloAgentState, SoloAgentResult, SoloStatus, ProductPhase, ProductTaskStatus, ProductInstanceDef, ProductTaskDef, ProductStatus, ProductSummary, } from "./agent-methods.js";
8
+ export type { AgentCategory, AgentProtocol, AgentStatus, AgentCapabilities, AgentDescriptor, CustomAgentDef, AgentConfig, AuthPreference, SoloState, SoloAgentState, SoloAgentResult, SoloStatus, ProductPhase, ProductTaskStatus, ProductInstanceDef, ProductTaskDef, ProductStatus, ProductSummary, } from "./agent-methods.js";
9
9
  /** Pre-defined configuration for a known ACP backend. */
10
10
  export interface AcpBackendConfig {
11
11
  /** Backend ID, e.g. "claude" | "codex" | "goose". */
@@ -71,6 +71,13 @@ export interface ExternalAgentDescriptor {
71
71
  acpArgs: string[];
72
72
  /** Extra environment variables for spawn. */
73
73
  env?: Record<string, string>;
74
+ /**
75
+ * Env var names the spawn layer must DELETE from the merged child env (after Object.assign of `env`),
76
+ * so a forwarded/stale shell key cannot override the CLI's own native login. Set in `account` mode
77
+ * (the load-bearing fix for the env-injection-override bug — buildBackendEnv alone cannot unset a
78
+ * whitelisted forwarded key). See acp-detector.resolveSuppressEnvKeys.
79
+ */
80
+ suppressEnvKeys?: string[];
74
81
  /** Communication protocol. */
75
82
  protocol: "acp";
76
83
  }
@@ -46,6 +46,15 @@ export interface CustomAgentDef {
46
46
  skillsDirs?: string[];
47
47
  supportsBaseUrlOverride?: boolean;
48
48
  }
49
+ /**
50
+ * Per-agent credential source preference (BYO-account/key axis).
51
+ * - "auto" : ladder — detected native account → user's own key → managed gateway (default; reproduces legacy behavior).
52
+ * - "managed" : force the platform gateway (sk-qllm); guarantees a first conversation, ignores any user key.
53
+ * - "account" : use the CLI's own native account/subscription login; inject NO key (the spawn layer also deletes any
54
+ * forwarded key) so the CLI's own credential store wins. Not available for claude (Anthropic bans 3rd-party OAuth).
55
+ * - "userKey" : use the user's own provider API key against the official endpoint (no gateway baseUrl override).
56
+ */
57
+ export type AuthPreference = "auto" | "managed" | "account" | "userKey";
49
58
  /** Persisted per-agent configuration. */
50
59
  export interface AgentConfig {
51
60
  apiKey?: string;
@@ -55,6 +64,8 @@ export interface AgentConfig {
55
64
  customArgs?: string[];
56
65
  customCliPath?: string;
57
66
  modelIdMap?: Record<string, string>;
67
+ /** Credential-source preference (undefined ⇒ "auto"; see AuthPreference). No migration needed. */
68
+ authPreference?: AuthPreference;
58
69
  }
59
70
  export type SoloState = "running" | "evaluating" | "completed" | "cancelled" | "failed";
60
71
  export type SoloAgentState = "pending" | "running" | "completed" | "failed" | "idle";
@@ -643,6 +643,16 @@ export interface AgentCallOptions {
643
643
  idempotencyKey?: string;
644
644
  traceId?: string;
645
645
  }
646
- export type AgentCall = <M extends keyof GatewayRpcMethodMap>(method: M, params: GatewayRpcMethodMap[M]["params"], options?: AgentCallOptions) => Promise<GatewayRpcMethodMap[M]["result"]>;
646
+ /**
647
+ * Gateway → agent RPC. The gateway is a GENERIC proxy: alongside the strongly-typed methods in
648
+ * GatewayRpcMethodMap (first call signature — params/result inferred), it must forward arbitrary
649
+ * methods by name — dynamic dispatch, and methods not (yet) in the map — via the second signature
650
+ * (opaque params/result). The typed signature is listed first so known method literals resolve to
651
+ * it; a plain `string` method falls through to the proxy signature.
652
+ */
653
+ export type AgentCall = {
654
+ <M extends keyof GatewayRpcMethodMap>(method: M, params: GatewayRpcMethodMap[M]["params"], options?: AgentCallOptions): Promise<GatewayRpcMethodMap[M]["result"]>;
655
+ (method: string, params?: Record<string, unknown>, options?: AgentCallOptions): Promise<unknown>;
656
+ };
647
657
  /** All gateway-facing RPC method names (runtime array). */
648
658
  export declare const GATEWAY_RPC_METHODS: (keyof GatewayRpcMethodMap)[];
@@ -6,7 +6,7 @@
6
6
  *
7
7
  * Reference: AionUI AcpDetector + ACP_BACKENDS_ALL registry.
8
8
  */
9
- import type { AcpBackendConfig, AgentDescriptor, AgentConfigStoreData } from "../../protocol/wire/acp-agent-management.js";
9
+ import type { AcpBackendConfig, AgentDescriptor, AgentConfigStoreData, AuthPreference } from "../../protocol/wire/acp-agent-management.js";
10
10
  export declare const ACP_BACKENDS: Record<string, AcpBackendConfig>;
11
11
  export declare const AGENT_CATALOG_IDS: readonly ["claude", "codex", "gemini", "copilot", "cursor", "qwen", "kimi", "glm", "opencode", "kiro", "qoder", "openclaw", "hermes"];
12
12
  /** Merged catalog entry (base ACP config + grid/install metadata) for one id. */
@@ -85,16 +85,40 @@ export interface CatalogKeySources {
85
85
  baseUrl?: string;
86
86
  model?: string;
87
87
  };
88
+ /** Probe: does this agent have a usable native account/subscription login (e.g. ~/.codex/auth.json,
89
+ * present + not expired)? Drives `account`-mode readiness and `auto`'s account-first preference.
90
+ * Tri-state: true = detected login, false = probeable but not logged in (blocks readiness), undefined
91
+ * = no probe for this agent (treated as ready-if-installed; auto does NOT pick account). Wired in Cut 4. */
92
+ hasSubscription?: (agentId: string) => boolean | undefined;
88
93
  }
94
+ /** Resolve the effective mode, coercing unsupported combinations (claude.account → auto). */
95
+ export declare function effectiveAuthPreference(entry: AcpBackendConfig, mode: AuthPreference): AuthPreference;
89
96
  /**
90
- * Resolve the login-free key env for a catalog agent from the unified key sources.
91
- * "set key once in our system → all agents" the user never logs into each CLI.
92
- * - authMode "oauth" / keySource "none" {} (no bypass; account required)
93
- * - keySource "llmrouter" gateway sk-qllm + gateway baseUrl (agent calls our gateway)
94
- * - keySource "direct" → the user's provider key (agent calls the provider directly)
95
- * Only emits env vars the backend actually declares (apiKeyEnvVar / baseUrlEnvVar).
97
+ * The credential-source modes the UI should offer for an agent (derived from catalog metadata, the
98
+ * single source of truthspec §4.2/§8.2/§15). Never includes a permanently-dead option:
99
+ * - oauth / keyless (copilot/cursor/kimi/…): ["account"] only (no gateway endpoint to repoint)
100
+ * - claude (Anthropic bans subscription): ["managed","userKey"] no account
101
+ * - codex (llmrouter + account-capable): ["account","userKey","managed"]
102
+ * - other llmrouter agents: ["userKey","managed"]
103
+ * - direct agents (qwen/glm/…): ["userKey"] (managed wiring for qwen/opencode is Cut 7)
96
104
  */
97
- export declare function resolveCatalogKeyEnv(entry: AcpBackendConfig | undefined, sources: CatalogKeySources): Record<string, string>;
105
+ export declare function getAvailableAuthModes(entry: AcpBackendConfig): AuthPreference[];
106
+ /**
107
+ * Resolve the login-free key env for a catalog agent, honoring the per-agent `authPreference`.
108
+ * - "account" → {} (inject nothing; the spawn layer also deletes the forwarded key, see resolveSuppressEnvKeys)
109
+ * - "userKey" → the user's own provider key against the official endpoint (no gateway baseUrl/model)
110
+ * - "managed" → force the gateway sk-qllm + baseUrl (ignores any user key) — guarantees a first conversation
111
+ * - "auto" → ladder: user's own key (if present) → managed gateway → host-model passthrough
112
+ * oauth / keyless agents never get a key injected. Only emits env vars the backend declares.
113
+ */
114
+ export declare function resolveCatalogKeyEnv(entry: AcpBackendConfig | undefined, sources: CatalogKeySources, mode?: AuthPreference): Record<string, string>;
115
+ /**
116
+ * Env var names the spawn layer must DELETE from the merged child env (account mode), so a
117
+ * forwarded/stale shell key cannot override the CLI's own native login. This is the load-bearing
118
+ * half of the §1.3 override-bug fix: buildBackendEnv alone cannot unset a whitelist-forwarded key.
119
+ * Returns [] when not in account mode (or the agent has no account path — claude is coerced to auto).
120
+ */
121
+ export declare function resolveSuppressEnvKeys(entry: AcpBackendConfig | undefined, mode: AuthPreference, sources?: CatalogKeySources): string[];
98
122
  export declare class AcpDetector {
99
123
  private cache;
100
124
  private configStore;
@@ -62,7 +62,30 @@ export interface AcpAuthMethod {
62
62
  id?: string;
63
63
  name?: string;
64
64
  description?: string;
65
+ /**
66
+ * ACP auth-method discriminator (when the agent follows the discriminated schema):
67
+ * - "agent" : the agent self-drives login (opens its own browser / prints a device code)
68
+ * - "env_var" : the user supplies a key — surface a key dialog (≈ userKey)
69
+ * - "terminal" : run an interactive login command (the agent's own `login` subcommand)
70
+ * Drives how the host routes the login affordance (see classifyAuthMethod). Absent on agents that
71
+ * don't tag their methods — those fall back to guide-only.
72
+ */
73
+ type?: "agent" | "env_var" | "terminal" | string;
74
+ /** For a terminal-type method: the command + args the host runs to start the interactive login. */
75
+ args?: string[];
76
+ /** For a terminal-type method: extra env for the login command. */
77
+ env?: Record<string, string>;
65
78
  }
79
+ /** How the host should surface a login for an advertised auth method (spec §7). */
80
+ export type AuthMethodRouting = "agent" | "key" | "terminal" | "guide";
81
+ /**
82
+ * Route an advertised auth method to the right login affordance:
83
+ * agent → drive the ACP `authenticate` request; env_var → open a key dialog (userKey); terminal →
84
+ * run the agent's interactive login command; otherwise guide-only (show the command, user runs it).
85
+ * Gating login on a concrete classified method (never a heuristic) prevents firing an uncompletable
86
+ * login (e.g. claude's key-only method) — spec §7 risk.
87
+ */
88
+ export declare function classifyAuthMethod(method: AcpAuthMethod | undefined): AuthMethodRouting;
66
89
  /**
67
90
  * Thrown when an agent rejects session setup because the user must authenticate first — e.g. kimi
68
91
  * returns -32000 "Authentication required" with a `kimi login` authMethod. Carries the agent's
@@ -141,6 +141,17 @@ export interface AgentProcessCallbacks {
141
141
  sessionDir?: string;
142
142
  }
143
143
  export declare function ensureLoopbackNoProxy(env: Record<string, string>): Record<string, string>;
144
+ /**
145
+ * Merge an external descriptor's env onto the forwarded base env, then DELETE any `suppressEnvKeys`
146
+ * (account mode). This is the load-bearing half of the env-injection-override fix: `Object.assign` can
147
+ * only add/overwrite, so a whitelist-forwarded `ANTHROPIC_API_KEY`/`OPENAI_API_KEY` (from the gateway's
148
+ * own shell) would otherwise survive into the child and override the CLI's native subscription login.
149
+ * Deleting after the merge guarantees `account` mode hands credential control to the CLI's own store.
150
+ */
151
+ export declare function applyExternalDescriptorEnv(env: Record<string, string>, ext: {
152
+ env?: Record<string, string>;
153
+ suppressEnvKeys?: string[];
154
+ }): Record<string, string>;
144
155
  /**
145
156
  * Build LLM-related environment variables for an external ACP teammate.
146
157
  *
@@ -30,6 +30,13 @@ export interface PooledAgentEntry {
30
30
  current: PooledTurnCtx | null;
31
31
  };
32
32
  lastUsed: number;
33
+ /**
34
+ * Set when a credential-mode change (authPreference / key / login) arrived while this process was
35
+ * mid-turn. The env is baked at spawn, so the switch can only take effect by respawning — but we must
36
+ * not abort the in-flight turn (D2: "下条消息生效"). The turn-runner evicts the entry once the turn
37
+ * settles (settlePooledTurn), so the NEXT turn respawns with the new credentials.
38
+ */
39
+ pendingRecredential?: boolean;
33
40
  }
34
41
  /** Pool key: same agent + workspace + session ⇒ same resident process (and shared memory). */
35
42
  export declare function poolKey(agentId: string, cwd: string, sessionId?: string): string;
@@ -47,6 +54,22 @@ export declare function adoptWarmedAgent(warmKey: string, sessionKey: string): P
47
54
  export declare const WARM_SESSION = "__warm__";
48
55
  /** Drop + dispose a single entry (e.g. after a turn errors and the process is suspect). */
49
56
  export declare function evictPooledAgent(key: string): void;
57
+ /**
58
+ * Invalidate every resident process for an agent after a credential-mode change (authPreference / key /
59
+ * login). The spawn env is baked at spawn time and reused across turns, so a switch only takes effect by
60
+ * respawning. Idle/warm entries are evicted immediately; a busy entry (turn in flight) is flagged
61
+ * `pendingRecredential` and evicted by settlePooledTurn when its turn settles (D2: never abort the
62
+ * in-flight turn — the switch lands on the next message). Returns counts for UI messaging.
63
+ */
64
+ export declare function evictPooledAgentsByAgentId(agentId: string): {
65
+ evicted: number;
66
+ deferred: number;
67
+ };
68
+ /**
69
+ * Call when a pooled turn settles (success or error). If a credential change arrived mid-turn
70
+ * (pendingRecredential), evict now so the next turn respawns with the new credentials.
71
+ */
72
+ export declare function settlePooledTurn(key: string): void;
50
73
  /** Kill + dispose every pooled agent and stop the reaper. Call on agent shutdown. */
51
74
  export declare function disposeAllPooledAgents(): void;
52
75
  export declare function pooledAgentCount(): number;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "qlogicagent",
3
- "version": "2.15.7",
3
+ "version": "2.15.9",
4
4
  "description": "XiaozhiClaw Agent CLI — subprocess architecture (JSON-RPC over stdio)",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",