@byokit/openclaw 0.22.1 → 0.23.0

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/CHANGELOG.md CHANGED
@@ -2,6 +2,15 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## 0.23.0 (2026-10-20)
6
+
7
+ - FEATURE: A signed-out `claude-cli` run now says why: its end carries `cause: { code: 'needs_cli_login', cli: 'claude', home, configDir?, signIn }` (the new `CliLoginCause` type, also on `./device`). `signIn: true` means `kit.signIn(member, { authChoice: 'anthropic-cli' })` runs the Claude Code login into the kit's own folder (subscription billing); `signIn: false` means the engine reads the person's own Claude Code login, so they run `claude` on that machine. An `anthropic-cli` sign-in the kit cannot run carries the same `cause` on its failed view. `kind`, `message` and every other run end are unchanged.
8
+
9
+ ## 0.22.2 (2026-10-19)
10
+
11
+ - Dependency update: pins @byokit/accounts 0.28.2.
12
+ - FIX: (from @byokit/accounts 0.28.2) MiniMax (Global and CN) now offers `MiniMax-M3.1-Flash-Preview` as its fast model, replacing `MiniMax-M2.7-highspeed`.
13
+
5
14
  ## 0.22.1 (2026-10-19)
6
15
 
7
16
  - FIX: a funded OpenRouter key now signs in and runs the model the person chooses. Before, `addKey` answered `{ status: 'not_included', reason: 'model' }` for every OpenRouter key, so apps showed a plan refusal and never reached the model: the pinned engine planned the key's live test on `openrouter/auto` but staged the route as the provider normalizes it, and refused the key as unavailable before sending it. A bundled engine patch now plans the test on the staged route; a key whose account has no credits (OpenRouter's HTTP 402) now answers `{ status: 'invalid', reason: 'billing' }`, never a plan refusal. An OpenRouter key pasted under OpenRouter's browser sign-in choice (`addKey(member, { authChoice: 'openrouter-oauth', apiKey })`) also takes OpenRouter's one key route (`openrouter-api-key`); a choice of a provider with exactly one key route billed alike maps the same way, and any other choice that takes no key throws its cause (`openai takes no API key: add the key with openai-api-key.`) instead of a plan refusal.
package/README.md CHANGED
@@ -131,7 +131,9 @@ API key (billed per use) entry still requires explicit selection; there is no su
131
131
  To choose the model for a run, pass `model: 'provider/model'` in the run spec (for example
132
132
  `'openai/gpt-5.1'`, where `provider` is an id `kit.providers(member)` lists). That provider is the one called and billed for this run only, with no fallback to another
133
133
  provider or model. If the member isn't signed in to it, the run ends `{ ok: false, kind: 'signed-out' }` and the
134
- engine is never called. Leave `model` out to keep the engine's own choice. A specific sign-in (`@profile`) can't be
134
+ engine is never called. A signed-out `claude-cli` run also carries `cause: { code: 'needs_cli_login', cli: 'claude', home, configDir?, signIn }`:
135
+ with `signIn: true` offer `kit.signIn(member, { authChoice: 'anthropic-cli' })`, which runs the Claude Code login; with
136
+ `signIn: false` ask the person to run `claude` on this machine to sign in. Leave `model` out to keep the engine's own choice. A specific sign-in (`@profile`) can't be
135
137
  picked per run: the pinned engine may still switch to another sign-in for the same provider.
136
138
 
137
139
  To let the kit choose among a member's accounts, pass `account: 'auto'` (the account with the most room left, decided
package/dist/device.d.ts CHANGED
@@ -4,7 +4,7 @@ import type { RouteView } from './routes.ts';
4
4
  import { type AccountView } from './words.ts';
5
5
  import type { Approval, Decision, GatewayEventName, GatewayEventPayload, GatewayMethod, GatewayParams, GatewayResult, KitState, RunEnd, OutputSchema, SchemaOutput, RunEvent, RunFrame, SignInView, AccountRef } from './types.ts';
6
6
  export type { GatewayEventName, GatewayEventPayload, GatewayMethod, GatewayParams, GatewayResult } from './types.ts';
7
- export type { Approval, Decision, KitState, PlanWindow, Route, RunEnd, RunEvent, RunFrame, RunUsage, SignInView, OutputSchema, SchemaOutput } from './types.ts';
7
+ export type { Approval, CliLoginCause, Decision, KitState, PlanWindow, Route, RunEnd, RunEvent, RunFrame, RunUsage, SignInView, OutputSchema, SchemaOutput } from './types.ts';
8
8
  /** One `oc.events` frame: a member's Gateway event, typed by name, or an approval add/resolve (7.2). */
9
9
  export type OpenClawLinkEvent = {
10
10
  [E in GatewayEventName]: {
package/dist/engine.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { remoteCliHost } from '@byokit/accounts/cli';
2
2
  import { AuthStore, AuthStoreSealSizeError } from './auth-store.ts';
3
3
  import type { KitOptions } from './kit.ts';
4
- import type { KitState, ToolSpec } from './types.ts';
4
+ import type { CliLoginCause, KitState, ToolSpec } from './types.ts';
5
5
  /** The app's stateDir as an absolute path with no symlinked ancestor (macOS /tmp and /var are symlinks):
6
6
  * the native Claude login's accounts store refuses any other, so a relative or symlinked stateDir failed it. */
7
7
  export declare function canonicalStateDir(dir: string): string;
@@ -83,9 +83,10 @@ export declare class Engine {
83
83
  refreshInstalledClaudeLogin(): Promise<boolean>;
84
84
  /** The fallback Claude sign-in for a machine whose installed Claude Code is signed out: it signs into the engine's folder. */
85
85
  nativeClaudeLogin(): ReturnType<typeof remoteCliHost>;
86
- /** Whether a fallback sign-in would write a folder this engine's gateway does not read: it started on the person's
87
- * login location (installed sign-in, or a probe with no answer), and an in-process restart keeps that env. */
88
- claudeLoginUnread(): boolean;
86
+ /** Where a Claude Code login must be for this engine's gateway to read it. `signIn: false` when a fallback sign-in
87
+ * would write a folder the gateway does not read: it started on the person's login location (installed sign-in, or
88
+ * a probe with no answer), and an in-process restart keeps that env. */
89
+ claudeLoginCause(): CliLoginCause;
89
90
  resetNativeClaudeLogin(): Promise<void>;
90
91
  doctor(timeoutMs: number): {
91
92
  status: number | null;
package/dist/engine.js CHANGED
@@ -528,9 +528,16 @@ export class Engine {
528
528
  this.claudeLogin = remoteCliHost({ cli, bins });
529
529
  return this.claudeLogin;
530
530
  }
531
- /** Whether a fallback sign-in would write a folder this engine's gateway does not read: it started on the person's
532
- * login location (installed sign-in, or a probe with no answer), and an in-process restart keeps that env. */
533
- claudeLoginUnread() { return Boolean(this.o.spawnEngine) && !this.claudeFallback; }
531
+ /** Where a Claude Code login must be for this engine's gateway to read it. `signIn: false` when a fallback sign-in
532
+ * would write a folder the gateway does not read: it started on the person's login location (installed sign-in, or
533
+ * a probe with no answer), and an in-process restart keeps that env. */
534
+ claudeLoginCause() {
535
+ if (this.o.spawnEngine && !this.claudeFallback) {
536
+ const { HOME, CLAUDE_CONFIG_DIR } = personal();
537
+ return { code: 'needs_cli_login', cli: 'claude', home: HOME, ...CLAUDE_CONFIG_DIR ? { configDir: CLAUDE_CONFIG_DIR } : {}, signIn: false };
538
+ }
539
+ return { code: 'needs_cli_login', cli: 'claude', home: join(this.root, 'home'), configDir: this.claudeFolder, signIn: true };
540
+ }
534
541
  resetNativeClaudeLogin() {
535
542
  if (this.claudeReset)
536
543
  return this.claudeReset;
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  export { ENGINE_VERSION, OPERATOR_SCOPES, PROTOCOL_VERSION } from './constants.ts';
2
- export type { Account, AccountId, AccountPick, AccountRef, Approval, CallOptions, ChannelChat, ChannelMessage, Considered, Decision, Defaults, ModelInfo, MoveResult, PickWhy, Room, RoomSpan, RunSelection, SignInState, GatewayEventName, GatewayEventPayload, GatewayMethod, GatewayParams, GatewayResult, GatewayTransport, GateResult, Hello, KitState, KitEventName, KitEventPayload, BrowserPing, LearningCapture, LearningMode, Member, PlanWindow, Route, RunEnd, RunEvent, RunFrame, RunRef, Helper, DelegatedRun, DelegatedEvent, RunSpec, OutputSchema, SchemaOutput, RunUsage, ThinkingAsked, ThinkingReport, ThinkingUsed, SignInOptions, SignInView, TelegramChannel, ToolHost, ToolSpec, } from './types.ts';
2
+ export type { Account, AccountId, AccountPick, AccountRef, Approval, CallOptions, CliLoginCause, ChannelChat, ChannelMessage, Considered, Decision, Defaults, ModelInfo, MoveResult, PickWhy, Room, RoomSpan, RunSelection, SignInState, GatewayEventName, GatewayEventPayload, GatewayMethod, GatewayParams, GatewayResult, GatewayTransport, GateResult, Hello, KitState, KitEventName, KitEventPayload, BrowserPing, LearningCapture, LearningMode, Member, PlanWindow, Route, RunEnd, RunEvent, RunFrame, RunRef, Helper, DelegatedRun, DelegatedEvent, RunSpec, OutputSchema, SchemaOutput, RunUsage, ThinkingAsked, ThinkingReport, ThinkingUsed, SignInOptions, SignInView, TelegramChannel, ToolHost, ToolSpec, } from './types.ts';
3
3
  export type { GatewayMethods } from './generated/methods.ts';
4
4
  export type { JsonValue } from './output.ts';
5
5
  export type { RouteFacts, RouteView } from './routes.ts';
package/dist/kit.js CHANGED
@@ -1120,7 +1120,7 @@ export class OpenClawKit {
1120
1120
  ensure: (member) => this.ensureMember(member), callbackPort: this.o.callbackPort ?? 1455,
1121
1121
  nativeClaudeLogin: () => this.engine.nativeClaudeLogin(),
1122
1122
  resetNativeClaudeLogin: () => this.engine.resetNativeClaudeLogin(),
1123
- claudeLoginUnread: () => this.engine.claudeLoginUnread(),
1123
+ claudeLogin: () => this.engine.claudeLoginCause(),
1124
1124
  onDisconnect: (fn) => { this.signInDisconnects.add(fn); return () => { this.signInDisconnects.delete(fn); }; },
1125
1125
  stopSignal: this.engine.stopSignal,
1126
1126
  authConfig: () => this.authSnapshot(),
@@ -1387,6 +1387,7 @@ export class OpenClawKit {
1387
1387
  request: (method, params, o) => this.request()(method, params, o),
1388
1388
  authStatus: this.admission.read,
1389
1389
  invalidateAuth: this.admission.invalidate,
1390
+ claudeLogin: () => this.engine.claudeLoginCause(),
1390
1391
  onEvent: (fn) => {
1391
1392
  this.listeners.add(fn);
1392
1393
  return () => {
package/dist/runs.d.ts CHANGED
@@ -5,7 +5,7 @@ import type { createAccounts } from './accounts.ts';
5
5
  import type { createLocks } from './locks.ts';
6
6
  import { authStatus } from './auth-status.ts';
7
7
  import { outputSchema, type OutputSchema, type SchemaOutput } from './output.ts';
8
- import type { GatewayTransport, Member, RunEnd, RunEvent, RunFrame, RunSpec } from './types.ts';
8
+ import type { CliLoginCause, GatewayTransport, Member, RunEnd, RunEvent, RunFrame, RunSpec } from './types.ts';
9
9
  export declare const USABLE: Set<string>;
10
10
  /**
11
11
  * The providers a `models.authStatus` answer shows usable (the rule a picked account is checked by), lowercased and
@@ -35,6 +35,7 @@ export declare function createRuns(ctx: {
35
35
  request: GatewayTransport['request'];
36
36
  authStatus?: (agentId: string, refresh: boolean, native: boolean) => ReturnType<typeof authStatus>;
37
37
  invalidateAuth?: () => void;
38
+ claudeLogin?: () => CliLoginCause;
38
39
  onEvent: GatewayTransport['onEvent'];
39
40
  ensure(member: Member): Promise<{
40
41
  agentId: string;
package/dist/runs.js CHANGED
@@ -154,11 +154,14 @@ export function createRuns(ctx) {
154
154
  return undefined;
155
155
  }
156
156
  };
157
- const failure = (message) => {
157
+ // A signed-out claude-cli run names where its Claude Code login is missing (`cause`).
158
+ const cause = (provider) => provider === 'claude-cli' && ctx.claudeLogin ? { cause: ctx.claudeLogin() } : {};
159
+ const signedOut = (provider, message) => ({ ok: false, kind: 'signed-out', message, ...cause(provider) });
160
+ const failure = (message, provider) => {
158
161
  const classified = classify(message);
159
162
  if (classified.kind === 'signed-out')
160
163
  ctx.invalidateAuth?.();
161
- return { ok: false, ...classified, message };
164
+ return { ok: false, ...classified, message, ...classified.kind === 'signed-out' ? cause(provider) : {} };
162
165
  };
163
166
  const execute = async (spec, on, keyAgent, preparedOutput) => {
164
167
  // Member boundary first: a member never speaks in another member's session, refused before any request. A key
@@ -268,7 +271,7 @@ export function createRuns(ctx) {
268
271
  try {
269
272
  on?.({ type: 'account', account: pick.account.id, model: pick.model, sessionKey, how: pick.how, why: pick.why, considered: pick.considered });
270
273
  if (!ready)
271
- return { ok: false, kind: 'signed-out', message: `${pick.account.name} is not signed in` };
274
+ return signedOut(pick.account.provider, `${pick.account.name} is not signed in`);
272
275
  return await start(spec, on, { agentId: agent, sessionKey, idempotencyKey, system,
273
276
  picked: pick.model ? await accountOf(pick.model) : undefined, output, chosen: pick }); // '' = no override
274
277
  }
@@ -359,7 +362,7 @@ export function createRuns(ctx) {
359
362
  return { ok: false, kind: 'other', message: String(auth.unavailable.message ?? 'account status unavailable') };
360
363
  const row = (auth.providers ?? []).find((e) => (typeof e === 'string' ? e : e?.provider) === picked.provider);
361
364
  if (!row || !usable(row))
362
- return { ok: false, kind: 'signed-out', message: `${picked.provider} is not signed in for ${spec.member}` };
365
+ return signedOut(picked.provider, `${picked.provider} is not signed in for ${spec.member}`);
363
366
  }
364
367
  // One `agent` request: its interim `accepted` frame names the run, its final frame (after the run) carries the
365
368
  // run's usage. The wait below still decides how the run ended. Thinking is clamped to the catalog before the
@@ -425,11 +428,11 @@ export function createRuns(ctx) {
425
428
  return { ok: false, aborted: true };
426
429
  const message = typeof result.error === 'string' ? result.error
427
430
  : typeof result.message === 'string' ? result.message : '';
428
- return failure(message);
431
+ return failure(message, picked?.provider);
429
432
  }
430
433
  catch (error) {
431
434
  const message = error instanceof Error ? error.message : String(error);
432
- return failure(message);
435
+ return failure(message, picked?.provider);
433
436
  }
434
437
  finally {
435
438
  ended = true;
package/dist/signin.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import type { remoteCliHost } from '@byokit/accounts/cli';
2
2
  import { authStatus } from './auth-status.ts';
3
- import type { GatewayTransport, Member, SignInOptions, SignInView } from './types.ts';
3
+ import type { CliLoginCause, GatewayTransport, Member, SignInOptions, SignInView } from './types.ts';
4
4
  export type SignInCtx = {
5
5
  request: GatewayTransport['request'];
6
6
  authStatus?: (agentId: string, refresh: boolean, native: boolean) => ReturnType<typeof authStatus>;
@@ -10,7 +10,7 @@ export type SignInCtx = {
10
10
  callbackPort: number;
11
11
  nativeClaudeLogin?(): ReturnType<typeof remoteCliHost>;
12
12
  resetNativeClaudeLogin?(): Promise<void>;
13
- claudeLoginUnread?(): boolean;
13
+ claudeLogin?(): CliLoginCause;
14
14
  onDisconnect?(fn: () => void): () => void;
15
15
  authConfig(): string;
16
16
  restarted(authBefore: string | undefined, signal?: AbortSignal): Promise<boolean>;
package/dist/signin.js CHANGED
@@ -241,8 +241,9 @@ export function signIn(ctx, member, o, on) {
241
241
  };
242
242
  native = ctx.nativeClaudeLogin?.();
243
243
  if (!await detected()) {
244
- if (ctx.claudeLoginUnread?.())
245
- return { state: 'failed', via, why: 'failed', error: 'Claude Code is installed here, but its sign-in could not be checked. Run claude once on this machine to sign in, then try again.' };
244
+ const cause = ctx.claudeLogin?.();
245
+ if (cause?.signIn === false)
246
+ return { state: 'failed', via, why: 'failed', error: 'Claude Code is installed here, but its sign-in could not be checked. Run claude once on this machine to sign in, then try again.', cause };
246
247
  if (!native)
247
248
  return { state: 'failed', via, why: 'failed', error: 'Claude Code sign-in is not available on this engine.' };
248
249
  let started = await native.start('claude', { signal });
package/dist/types.d.ts CHANGED
@@ -180,6 +180,18 @@ export type RunEnd<T = unknown> = {
180
180
  kind: 'signed-out' | 'resting' | 'plan' | 'network' | 'other' | 'output';
181
181
  until?: number;
182
182
  message: string;
183
+ cause?: CliLoginCause;
184
+ };
185
+ /** Why a `claude-cli` run or `anthropic-cli` sign-in failed: Claude Code has no login where this engine reads it (5.5).
186
+ * `signIn` true: `signIn(member, { authChoice: 'anthropic-cli' })` runs that login into `configDir` (subscription
187
+ * billing, the person's Claude plan). False: the engine reads the person's own login, which the kit never writes; the
188
+ * person runs `claude` on this machine, as `home`, to sign in (`configDir` only when they set CLAUDE_CONFIG_DIR). */
189
+ export type CliLoginCause = {
190
+ code: 'needs_cli_login';
191
+ cli: 'claude';
192
+ home: string;
193
+ configDir?: string;
194
+ signIn: boolean;
183
195
  };
184
196
  export type SignInOptions = {
185
197
  authChoice: string;
@@ -196,6 +208,7 @@ export type SignInView = {
196
208
  prompt?: string;
197
209
  error?: string;
198
210
  why?: 'busy' | 'declined' | 'expired' | 'failed';
211
+ cause?: CliLoginCause;
199
212
  };
200
213
  export type Approval = {
201
214
  id: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@byokit/openclaw",
3
- "version": "0.22.1",
3
+ "version": "0.23.0",
4
4
  "description": "The OpenClaw runtime kit: the pinned engine's full operator surface with plain-words helpers for members, sign-in, runs and approvals.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -60,7 +60,7 @@
60
60
  "prepack": "tsc -b && node ../../scripts/fix-words-dts.cjs"
61
61
  },
62
62
  "dependencies": {
63
- "@byokit/accounts": "0.28.1",
63
+ "@byokit/accounts": "0.28.2",
64
64
  "@byokit/pair": "0.10.4",
65
65
  "@byokit/relay": "0.8.2",
66
66
  "@byokit/discover": "0.8.4",