@byokit/openclaw 0.3.2 → 0.3.4
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 +19 -0
- package/README.md +37 -11
- package/SECURITY.md +7 -0
- package/dist/auth-status.d.ts +17 -0
- package/dist/auth-status.js +13 -0
- package/dist/auth-store.js +11 -1
- package/dist/config.js +3 -1
- package/dist/engine.d.ts +3 -1
- package/dist/engine.js +29 -3
- package/dist/index.d.ts +1 -1
- package/dist/kit.d.ts +2 -5
- package/dist/kit.js +1 -1
- package/dist/link.js +6 -1
- package/dist/routes.d.ts +3 -2
- package/dist/routes.js +3 -2
- package/dist/routes.json +18 -9
- package/dist/runs.js +2 -1
- package/dist/signin.d.ts +3 -6
- package/dist/signin.js +88 -14
- package/dist/types.d.ts +12 -3
- package/dist/words.js +1 -0
- package/dist/words.json +2 -0
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,25 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
## 0.3.4 (2026-09-30)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
- FIX: Device-code sign-in waits for the engine’s code expiry instead of failing after two minutes; caller cancellation and expiry return typed outcomes with plain words.
|
|
10
|
+
- Offer the native Claude Code / Agent SDK subscription route (`claude-cli`, plugin `anthropic`), keeping login in Claude Code in the isolated engine HOME. Sign-in uses engine detection and live activation; `oc.state` reports native login readiness.
|
|
11
|
+
- Support explicit Anthropic API key activation with a per-use billing label and secret-safe views; never offer an API-key fallback. Direct Claude.ai OAuth and setup-token offers remain excluded.
|
|
12
|
+
- Verify native and API per-run provider/model forwarding, tool events and strict refusal of `@profile` pins.
|
|
13
|
+
|
|
14
|
+
## 0.3.3 (2026-09-30)
|
|
15
|
+
|
|
16
|
+
- Dependency update: pins @byokit/secrets 0.5.0.
|
|
17
|
+
|
|
18
|
+
- SECURITY: Opt-in dual-wrap credential upgrades are authenticated and atomically replaced under the store lock; protection is only as strong as the owner-only host-key file, which must stay out of sealed-store backups.
|
|
19
|
+
- FIX: A locked or unresponsive keyring no longer throws from prepare or start. The kit reports a locked saved sign-in in plain words, preserves the sealed store and retries normally on a later start after unlock; dual-wrapped stores open through their host key without prompting.
|
|
20
|
+
|
|
21
|
+
- FIX: ChatGPT subscription device pairing was blocked by the plugin allowlist unless the app added the provider plugin itself. The kit now merges every offered route's provider plugin with the bridge and caller-provided plugins, without adding plugins for unoffered routes.
|
|
22
|
+
- Label the explicit Anthropic route as API key (billed per use), keeping API and plan routes off by default.
|
|
23
|
+
|
|
5
24
|
## 0.3.2 (2026-09-30)
|
|
6
25
|
|
|
7
26
|
- Dependency update: pins @byokit/secrets 0.4.0.
|
package/README.md
CHANGED
|
@@ -33,21 +33,36 @@ the pinned engine and needs a real ChatGPT sign-in, so it is not run here):
|
|
|
33
33
|
```ts
|
|
34
34
|
import { OpenClawKit } from '@byokit/openclaw';
|
|
35
35
|
|
|
36
|
-
const kit = new OpenClawKit({ stateDir: './openclaw-state' });
|
|
36
|
+
const kit = new OpenClawKit({ stateDir: './openclaw-state', config: { plugins: { allow: ['openai'] } } });
|
|
37
37
|
await kit.start(); // installs the pinned engine under stateDir, spawns it, connects
|
|
38
38
|
|
|
39
|
-
await kit.ensureMember('
|
|
40
|
-
const
|
|
41
|
-
|
|
39
|
+
await kit.ensureMember('umer');
|
|
40
|
+
const controller = new AbortController(); // call controller.abort() when Umer cancels
|
|
41
|
+
const signIn = kit.signIn('umer', {
|
|
42
|
+
authChoice: 'openai-device-code', via: 'code', signal: controller.signal,
|
|
43
|
+
}, (view) => { if (view.code) console.log('Open', view.url, 'and enter', view.code); });
|
|
44
|
+
const signedIn = await signIn.done;
|
|
45
|
+
if (signedIn.state !== 'done') {
|
|
46
|
+
console.log(signedIn.error); // plain words; why is 'expired' or 'declined' on expiry or cancellation
|
|
47
|
+
await kit.stop();
|
|
48
|
+
process.exit(0);
|
|
49
|
+
}
|
|
42
50
|
|
|
43
51
|
const end = await kit.run(
|
|
44
|
-
{ member: '
|
|
52
|
+
{ member: 'umer', sessionKey: 'agent:umer:main', message: 'Say hello.' },
|
|
45
53
|
(e) => { if (e.type === 'text') console.log(e.text); },
|
|
46
54
|
);
|
|
47
55
|
console.log(end);
|
|
48
56
|
await kit.stop();
|
|
49
57
|
```
|
|
50
58
|
|
|
59
|
+
Device approval can take longer than two minutes. The kit waits through the engine's advertised code lifetime
|
|
60
|
+
(`expiresInMinutes` on the pin, or `expires_in` seconds when supplied), including progress pulls. If the engine
|
|
61
|
+
supplies no lifetime, it owns the deadline. Ordinary wizard requests keep their 120-second timeout.
|
|
62
|
+
`signIn.cancel()` or the optional caller `signal` cancels this sign-in and releases its wizard session.
|
|
63
|
+
`done` returns a typed `SignInView`: `why: 'expired'` for an expired code, `why: 'declined'` for cancellation,
|
|
64
|
+
with a plain sentence in `error`. `SignInOptions` is exported from the host entry.
|
|
65
|
+
|
|
51
66
|
To choose which of a member's accounts a run uses, pass `model: 'provider/model'` in the run spec (for example
|
|
52
67
|
`'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
|
|
53
68
|
provider or model. If the member isn't signed in to it, the run ends `{ ok: false, kind: 'signed-out' }` and the
|
|
@@ -77,9 +92,9 @@ const kit = new OpenClawKit({ stateDir, spawnEngine: false, transport: fakeGatew
|
|
|
77
92
|
try {
|
|
78
93
|
await kit.start();
|
|
79
94
|
console.log('state:', kit.state.phase, '| protocol:', kit.hello?.protocol);
|
|
80
|
-
await kit.ensureMember('
|
|
95
|
+
await kit.ensureMember('umer');
|
|
81
96
|
const end = await kit.run(
|
|
82
|
-
{ member: '
|
|
97
|
+
{ member: 'umer', sessionKey: 'agent:umer:main', message: 'Say hello.' },
|
|
83
98
|
(e) => console.log('event:', JSON.stringify(e)),
|
|
84
99
|
);
|
|
85
100
|
console.log('end:', JSON.stringify(end));
|
|
@@ -172,8 +187,16 @@ The pinned engine has no supported hook for sealing OAuth profile writes. Its `a
|
|
|
172
187
|
credential JSON in agent SQLite databases and a shared state database, and doctor imports leave migration
|
|
173
188
|
archives. `authSeal` therefore protects the complete isolated `state` and `home` directories, including SQLite
|
|
174
189
|
journals. It uses the injected `SealingAdapter` from `@byokit/secrets`. `osKeyringSeal()` automatically
|
|
175
|
-
|
|
176
|
-
|
|
190
|
+
uses a persistent private file key for new stores when no non-interactive keyring is available.
|
|
191
|
+
Opening follows the saved envelope's mode. A locked or unresponsive keyring-only store leaves
|
|
192
|
+
`kit.state.phase === 'locked'`: `prepare()` and `start()` resolve, show `stateWords(kit.state)` for
|
|
193
|
+
recovery, and keep the sealed snapshot unchanged without launching the engine. Call `start()` again
|
|
194
|
+
after unlock to restore the same credentials, even if a fallback key directory now exists.
|
|
195
|
+
|
|
196
|
+
For hosts whose keyring stays locked, opt into `osKeyringSeal({ service, dualWrap: true })`.
|
|
197
|
+
While unlocked, reading an existing keyring-only snapshot atomically upgrades it to dual-wrap.
|
|
198
|
+
Later starts and stops can use the host wrap without prompting. Default off: **protection is only
|
|
199
|
+
as strong as the owner-only host-key file**, which must stay outside sealed-store backups.
|
|
177
200
|
|
|
178
201
|
```ts
|
|
179
202
|
import { osKeyringSeal, hostKeySeal } from '@byokit/secrets';
|
|
@@ -187,7 +210,7 @@ await kit.prepare(); // seals an existing plaintext store and migration archives
|
|
|
187
210
|
await kit.start(); // authenticates and restores the isolated files for the engine
|
|
188
211
|
await kit.stop(); // waits for exit, verifies an atomic sealed snapshot, then removes plaintext
|
|
189
212
|
|
|
190
|
-
// Inspect the adapter's mode
|
|
213
|
+
// Inspect the adapter's write mode: 'keyring', 'host-key-file' or opt-in 'dual-wrap'.
|
|
191
214
|
// Hosts can also explicitly supply a 32-byte key kept outside stateDir and its backups:
|
|
192
215
|
declare const hostKey: Uint8Array;
|
|
193
216
|
const server = new OpenClawKit({
|
|
@@ -200,7 +223,8 @@ The automatic key lives in the platform state directory, separate from the engin
|
|
|
200
223
|
on the same disk protects copied stores/backups only when the key directory is excluded; it does
|
|
201
224
|
not protect against code running as the same OS user. See [secrets' rotation and threat model](../secrets/README.md#servers-and-headless-node).
|
|
202
225
|
Stop the kit, acquire the host writer lock and call `seal.rotate()` with `auth-store.sealed` plus
|
|
203
|
-
every retained sealed migration archive before retiring an automatic key.
|
|
226
|
+
every retained sealed migration archive before retiring an automatic key. Rotate each envelope mode
|
|
227
|
+
separately; dual-wrap rotation retains old wrapping keys for backups.
|
|
204
228
|
|
|
205
229
|
Without `authSeal`, engine credentials remain plaintext. With it, successful `prepare()` and `stop()` leave
|
|
206
230
|
only a sealed snapshot, `auth-store.sealed`, for those directories. The adapter authenticates the snapshot
|
|
@@ -250,3 +274,5 @@ frozen (docs/runtime-kits.md §5).
|
|
|
250
274
|
## License
|
|
251
275
|
|
|
252
276
|
Apache-2.0. See [LICENSE](LICENSE) and [NOTICE](../../NOTICE).
|
|
277
|
+
|
|
278
|
+
Claude: `anthropic-cli` uses your own unmodified Claude Code login on this machine (provider `claude-cli`, plugin `anthropic`; subscription billing), with login kept in Claude Code under the kit’s isolated `HOME=<stateDir>/openclaw/home` and `CLAUDE_CONFIG_DIR=<stateDir>/openclaw/home/.claude`; sign in there with `claude auth login`, then call `signIn`. Activation live-tests the route; native sign-out is through Claude Code. `apiKey` is explicit API billing (“API key (billed per use)”, `offer: false`): `signIn` asks for the key through `paste`, then engine activation verifies it. The kit never imports Claude credentials or implements direct Claude.ai OAuth; [Anthropic’s terms](https://code.claude.com/docs/en/legal-and-compliance#authentication-and-credential-use) apply.
|
package/SECURITY.md
CHANGED
|
@@ -23,6 +23,13 @@ running as the app's user, a compromised host/engine/plugin, or readable backups
|
|
|
23
23
|
The isolated environment and tool gate are not an OS filesystem/network sandbox.
|
|
24
24
|
The app must sandbox `ToolHost.call` and judge requests in `ToolHost.gate`.
|
|
25
25
|
|
|
26
|
+
A locked or unresponsive keyring leaves the sealed snapshot unchanged. `prepare()` and `start()`
|
|
27
|
+
resolve with `phase: 'locked'`, do not restore plaintext or launch the engine, and a later start
|
|
28
|
+
retries after unlock. Opt-in dual wrapping opens through an owner-only host key without prompting;
|
|
29
|
+
its protection is only as strong as that file, which must stay outside sealed-store backups.
|
|
30
|
+
Unlocked keyring-only snapshots upgrade atomically under the store's exclusive lock after verifying
|
|
31
|
+
the replacement decrypts to identical contents. Other sealing failures still reject.
|
|
32
|
+
|
|
26
33
|
## Secrets at rest and in memory
|
|
27
34
|
|
|
28
35
|
| Asset | Location relative to `stateDir` | Protection and consequence of theft |
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { GatewayTransport } from './types.ts';
|
|
2
|
+
export type AuthStatus = {
|
|
3
|
+
providers?: (string | {
|
|
4
|
+
provider?: unknown;
|
|
5
|
+
status?: unknown;
|
|
6
|
+
profiles?: {
|
|
7
|
+
status?: unknown;
|
|
8
|
+
}[];
|
|
9
|
+
usage?: unknown;
|
|
10
|
+
})[];
|
|
11
|
+
unavailable?: {
|
|
12
|
+
message?: unknown;
|
|
13
|
+
};
|
|
14
|
+
};
|
|
15
|
+
/** Native Claude login stays in Claude Code. The pin's profile status does not include this synthetic auth;
|
|
16
|
+
* setup detection asks the CLI itself, without handing credentials to the kit. */
|
|
17
|
+
export declare function authStatus(request: GatewayTransport['request'], agentId: string, refresh?: boolean, native?: boolean): Promise<AuthStatus>;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/** Native Claude login stays in Claude Code. The pin's profile status does not include this synthetic auth;
|
|
2
|
+
* setup detection asks the CLI itself, without handing credentials to the kit. */
|
|
3
|
+
export async function authStatus(request, agentId, refresh = false, native = false) {
|
|
4
|
+
const status = await request('models.authStatus', { agentId, ...(refresh ? { refresh: true } : {}) }, { timeoutMs: 20_000 });
|
|
5
|
+
if (!native)
|
|
6
|
+
return status;
|
|
7
|
+
const detected = await request('openclaw.setup.detect', { agentId }, { timeoutMs: 20_000 }).catch(() => ({}));
|
|
8
|
+
const rows = (status.providers ?? []).filter((row) => (typeof row === 'string' ? row : row.provider) !== 'claude-cli');
|
|
9
|
+
if (detected.candidates?.some((candidate) => candidate.kind === 'claude-cli' && candidate.credentials === true)) {
|
|
10
|
+
return { providers: [...rows, { provider: 'claude-cli', status: 'ok' }] };
|
|
11
|
+
}
|
|
12
|
+
return { ...status, providers: rows };
|
|
13
|
+
}
|
package/dist/auth-store.js
CHANGED
|
@@ -149,7 +149,17 @@ export class AuthStore {
|
|
|
149
149
|
if (!existsSync(this.file))
|
|
150
150
|
return undefined;
|
|
151
151
|
regular(this.file);
|
|
152
|
-
|
|
152
|
+
const seal = this.o.seal;
|
|
153
|
+
const bytes = readFileSync(this.file);
|
|
154
|
+
const text = seal.decryptString(bytes);
|
|
155
|
+
const saved = snapshot(text);
|
|
156
|
+
const upgraded = seal.upgrade?.(bytes);
|
|
157
|
+
if (upgraded) {
|
|
158
|
+
if (seal.decryptString(Buffer.from(upgraded)) !== text)
|
|
159
|
+
throw new Error('credential upgrade verification failed');
|
|
160
|
+
put(this.file, upgraded);
|
|
161
|
+
}
|
|
162
|
+
return saved;
|
|
153
163
|
}
|
|
154
164
|
collect() {
|
|
155
165
|
const s = { v: 1, dirs: [], files: [] };
|
package/dist/config.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { dirname, join } from 'node:path';
|
|
2
|
+
import { routes } from "./routes.js";
|
|
2
3
|
const object = (v) => !!v && typeof v === 'object' && !Array.isArray(v);
|
|
3
4
|
const merge = (a, b) => {
|
|
4
5
|
for (const [k, v] of Object.entries(b))
|
|
@@ -53,7 +54,8 @@ export function reconcileConfig(saved, o) {
|
|
|
53
54
|
c.plugins ??= {};
|
|
54
55
|
c.plugins.load ??= {};
|
|
55
56
|
c.plugins.load.paths = [...new Set([...(c.plugins.load.paths ?? []).filter((p) => !p.includes('byokit-openclaw-bridge')), o.pluginDir])];
|
|
56
|
-
c.plugins.allow = [...new Set([...(c.plugins.allow ?? []), o.pluginId
|
|
57
|
+
c.plugins.allow = [...new Set([...(c.plugins.allow ?? []), o.pluginId,
|
|
58
|
+
...routes().filter(route => route.offer && route.plugin).map(route => route.plugin)])];
|
|
57
59
|
c.plugins.entries ??= {};
|
|
58
60
|
c.plugins.entries[o.pluginId] = merge(c.plugins.entries[o.pluginId] ?? {}, { hooks: { timeouts: { before_tool_call: 200_000 } } });
|
|
59
61
|
c.security ??= {};
|
package/dist/engine.d.ts
CHANGED
|
@@ -16,6 +16,7 @@ export declare class Engine {
|
|
|
16
16
|
private starting?;
|
|
17
17
|
private readonly authStore;
|
|
18
18
|
private stopping;
|
|
19
|
+
private credentialsLocked;
|
|
19
20
|
private repaired;
|
|
20
21
|
private prepared?;
|
|
21
22
|
private port;
|
|
@@ -40,7 +41,8 @@ export declare class Engine {
|
|
|
40
41
|
port: number;
|
|
41
42
|
token: string;
|
|
42
43
|
identityPath: string;
|
|
43
|
-
}>;
|
|
44
|
+
} | undefined>;
|
|
45
|
+
private locked;
|
|
44
46
|
private startOnce;
|
|
45
47
|
private launch;
|
|
46
48
|
withAuthStore<T>(task: () => Promise<T>): Promise<T>;
|
package/dist/engine.js
CHANGED
|
@@ -52,6 +52,7 @@ export class Engine {
|
|
|
52
52
|
starting;
|
|
53
53
|
authStore;
|
|
54
54
|
stopping = false;
|
|
55
|
+
credentialsLocked = false;
|
|
55
56
|
repaired = false;
|
|
56
57
|
prepared;
|
|
57
58
|
port = 0;
|
|
@@ -94,7 +95,15 @@ export class Engine {
|
|
|
94
95
|
throw new Error('authSeal required for sealed credential store');
|
|
95
96
|
for (const d of [this.root, ...(!this.o.authSeal ? [join(this.root, 'home'), join(this.root, 'state')] : []), join(this.root, 'tmp'), join(this.root, 'install-home'), join(this.root, 'npm-cache'), join(this.o.stateDir, 'logs'), this.dir])
|
|
96
97
|
mkdirSync(d, { recursive: true, mode: 0o700 });
|
|
97
|
-
|
|
98
|
+
try {
|
|
99
|
+
await this.authStore.prepare();
|
|
100
|
+
this.credentialsLocked = false;
|
|
101
|
+
}
|
|
102
|
+
catch (error) {
|
|
103
|
+
if (this.locked(error))
|
|
104
|
+
return;
|
|
105
|
+
throw error;
|
|
106
|
+
}
|
|
98
107
|
if (this.o.spawnEngine) {
|
|
99
108
|
const versionPath = join(this.dir, 'node_modules', 'openclaw', 'package.json');
|
|
100
109
|
if (!existsSync(this.entry) || !installMatches(this.dir)) {
|
|
@@ -183,9 +192,25 @@ export class Engine {
|
|
|
183
192
|
this.starting = undefined; }).catch(() => { });
|
|
184
193
|
return pending;
|
|
185
194
|
}
|
|
195
|
+
locked(error) {
|
|
196
|
+
if (!(error instanceof Error) || error.name !== 'KeystoreError' || !('code' in error) || error.code !== 'keyring-locked')
|
|
197
|
+
return false;
|
|
198
|
+
this.credentialsLocked = true;
|
|
199
|
+
this.state('locked');
|
|
200
|
+
return true;
|
|
201
|
+
}
|
|
186
202
|
async startOnce() {
|
|
187
203
|
await this.prepare();
|
|
188
|
-
|
|
204
|
+
if (this.credentialsLocked)
|
|
205
|
+
return undefined;
|
|
206
|
+
try {
|
|
207
|
+
await this.authStore.start();
|
|
208
|
+
}
|
|
209
|
+
catch (error) {
|
|
210
|
+
if (this.locked(error))
|
|
211
|
+
return undefined;
|
|
212
|
+
throw error;
|
|
213
|
+
}
|
|
189
214
|
try {
|
|
190
215
|
return this.launch();
|
|
191
216
|
}
|
|
@@ -275,7 +300,8 @@ export class Engine {
|
|
|
275
300
|
throw new Error('engine did not stop; credential store still in use');
|
|
276
301
|
this.child = undefined;
|
|
277
302
|
rmSync(join(this.root, 'gateway.pid'), { force: true });
|
|
278
|
-
|
|
303
|
+
if (!this.credentialsLocked)
|
|
304
|
+
await this.authStore.stop();
|
|
279
305
|
rmSync(this.bridgeSock, { force: true });
|
|
280
306
|
this.state('stopped');
|
|
281
307
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export { ENGINE_VERSION, OPERATOR_SCOPES, PROTOCOL_VERSION } from './constants.ts';
|
|
2
|
-
export type { Approval, CallOptions, Decision, GatewayEventName, GatewayEventPayload, GatewayMethod, GatewayParams, GatewayResult, GatewayTransport, GateResult, Hello, KitState, Member, PlanWindow, Route, RunEnd, RunEvent, RunRef, RunSpec, RunUsage, SignInView, ToolHost, ToolSpec, } from './types.ts';
|
|
2
|
+
export type { Approval, CallOptions, Decision, GatewayEventName, GatewayEventPayload, GatewayMethod, GatewayParams, GatewayResult, GatewayTransport, GateResult, Hello, KitState, Member, PlanWindow, Route, RunEnd, RunEvent, RunRef, RunSpec, RunUsage, SignInOptions, SignInView, ToolHost, ToolSpec, } from './types.ts';
|
|
3
3
|
export { OpenClawKit, type KitOptions, type RetainedLogin } from './kit.ts';
|
|
4
4
|
export { stateWords, toAccountView, words, type AccountView, type WordKey } from './words.ts';
|
package/dist/kit.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { SealingAdapter } from '@byokit/secrets';
|
|
2
|
-
import type { Approval, CallOptions, Decision, GatewayEventName, GatewayEventPayload, GatewayMethod, GatewayParams, GatewayResult, GatewayTransport, Hello, KitState, Member, Route, RunEnd, RunEvent, RunSpec, SignInView, ToolHost, ToolSpec } from './types.ts';
|
|
2
|
+
import type { Approval, CallOptions, Decision, GatewayEventName, GatewayEventPayload, GatewayMethod, GatewayParams, GatewayResult, GatewayTransport, Hello, KitState, Member, Route, RunEnd, RunEvent, RunSpec, SignInOptions, SignInView, ToolHost, ToolSpec } from './types.ts';
|
|
3
3
|
export type KitOptions = {
|
|
4
4
|
stateDir: string;
|
|
5
5
|
authSeal?: SealingAdapter;
|
|
@@ -75,10 +75,7 @@ export declare class OpenClawKit {
|
|
|
75
75
|
routes(): Route[];
|
|
76
76
|
providers(member: Member): Promise<string[]>;
|
|
77
77
|
signedIn(member: Member, provider: string): Promise<boolean>;
|
|
78
|
-
signIn(member: Member, o: {
|
|
79
|
-
authChoice: string;
|
|
80
|
-
via?: 'browser' | 'code';
|
|
81
|
-
}, on: (v: SignInView) => void): {
|
|
78
|
+
signIn(member: Member, o: SignInOptions, on: (v: SignInView) => void): {
|
|
82
79
|
paste(text: string): void;
|
|
83
80
|
cancel(): void;
|
|
84
81
|
done: Promise<SignInView>;
|
package/dist/kit.js
CHANGED
|
@@ -468,7 +468,7 @@ export class OpenClawKit {
|
|
|
468
468
|
let transport;
|
|
469
469
|
try {
|
|
470
470
|
const ctx = await this.engine.start();
|
|
471
|
-
if (this.stopping)
|
|
471
|
+
if (!ctx || this.stopping)
|
|
472
472
|
return;
|
|
473
473
|
this.setState({ phase: 'starting' });
|
|
474
474
|
transport = (this.o.transport ?? gatewayTransport)({ ...ctx, bridgeSock: this.engine.bridgeSock });
|
package/dist/link.js
CHANGED
|
@@ -9,6 +9,7 @@ import { reach } from '@byokit/reach';
|
|
|
9
9
|
import { ENGINE_VERSION } from "./constants.js";
|
|
10
10
|
import { b64urlDecode, sealNotice } from "./notices.js";
|
|
11
11
|
import { routeFor } from "./routes.js";
|
|
12
|
+
import { authStatus } from "./auth-status.js";
|
|
12
13
|
import { signedInProviders } from "./runs.js";
|
|
13
14
|
import { stateWords, words } from "./words.js";
|
|
14
15
|
const VIEW_OPS = new Set(['oc.state', 'oc.routes', 'oc.signin.view', 'oc.sessions', 'oc.approvals', 'oc.events']);
|
|
@@ -99,7 +100,11 @@ export function openclawLink(kit, o) {
|
|
|
99
100
|
const signIns = async (member) => {
|
|
100
101
|
try {
|
|
101
102
|
const { agentId } = await kit.ensureMember(member);
|
|
102
|
-
const status = await
|
|
103
|
+
const status = await authStatus((method, params, options) => {
|
|
104
|
+
if (method === 'models.authStatus')
|
|
105
|
+
return kit.call(method, params, options);
|
|
106
|
+
return kit.call('openclaw.setup.detect', params, options);
|
|
107
|
+
}, agentId, false, true);
|
|
103
108
|
return signedInProviders(status);
|
|
104
109
|
}
|
|
105
110
|
catch {
|
package/dist/routes.d.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import type { Route } from './types.ts';
|
|
2
2
|
/** The pin's auth-choice table. `provider` is the id a person's account is known by (the doc's matrix), which for
|
|
3
3
|
* MiniMax's portal routes is the account-visible `minimax`, not the wizard's internal `minimax-portal`. `plugin` is
|
|
4
|
-
* the bundled plugin
|
|
4
|
+
* the bundled plugin needed for that route to start (5.6); the kit allows offered routes, and the app allows any
|
|
5
|
+
* unoffered route it explicitly uses. Only the pin's bundled provider contracts are
|
|
5
6
|
* listed: install-catalog plugins (external providers needing their own install) are not contracted by the pin and
|
|
6
7
|
* are deliberately absent. */
|
|
7
8
|
export declare function routes(): Route[];
|
|
8
|
-
/** The route an app should use: only an offered route counts
|
|
9
|
+
/** The route an app should use: only an offered route counts; API billing is never picked as a fallback. */
|
|
9
10
|
export declare function routeFor(provider: string, via: 'browser' | 'code'): Route | undefined;
|
package/dist/routes.js
CHANGED
|
@@ -3,13 +3,14 @@ import routesJson from './routes.json' with { type: 'json' };
|
|
|
3
3
|
const table = routesJson;
|
|
4
4
|
/** The pin's auth-choice table. `provider` is the id a person's account is known by (the doc's matrix), which for
|
|
5
5
|
* MiniMax's portal routes is the account-visible `minimax`, not the wizard's internal `minimax-portal`. `plugin` is
|
|
6
|
-
* the bundled plugin
|
|
6
|
+
* the bundled plugin needed for that route to start (5.6); the kit allows offered routes, and the app allows any
|
|
7
|
+
* unoffered route it explicitly uses. Only the pin's bundled provider contracts are
|
|
7
8
|
* listed: install-catalog plugins (external providers needing their own install) are not contracted by the pin and
|
|
8
9
|
* are deliberately absent. */
|
|
9
10
|
export function routes() {
|
|
10
11
|
return table;
|
|
11
12
|
}
|
|
12
|
-
/** The route an app should use: only an offered route counts
|
|
13
|
+
/** The route an app should use: only an offered route counts; API billing is never picked as a fallback. */
|
|
13
14
|
export function routeFor(provider, via) {
|
|
14
15
|
return table.find((route) => route.offer && route.provider === provider && route.via === via);
|
|
15
16
|
}
|
package/dist/routes.json
CHANGED
|
@@ -111,14 +111,17 @@
|
|
|
111
111
|
},
|
|
112
112
|
{
|
|
113
113
|
"choice": "anthropic-cli",
|
|
114
|
-
"provider": "
|
|
114
|
+
"provider": "claude-cli",
|
|
115
115
|
"plugin": "anthropic",
|
|
116
116
|
"billing": "subscription",
|
|
117
117
|
"via": "browser",
|
|
118
|
-
"prerequisite": "
|
|
119
|
-
"offer":
|
|
120
|
-
"reason": "
|
|
121
|
-
"source": "dist/extensions/anthropic/openclaw.plugin.json (2026.8.1)"
|
|
118
|
+
"prerequisite": "Sign in through unmodified Claude Code on this machine using the kit's isolated HOME and CLAUDE_CONFIG_DIR; the login stays in Claude Code.",
|
|
119
|
+
"offer": true,
|
|
120
|
+
"reason": "Claude subscription via your own Claude Code login on this machine (Agent SDK runtime).",
|
|
121
|
+
"source": "dist/extensions/anthropic/openclaw.plugin.json (2026.8.1)",
|
|
122
|
+
"auth": "cli",
|
|
123
|
+
"terms": "allowed",
|
|
124
|
+
"termsUrl": "https://code.claude.com/docs/en/legal-and-compliance#authentication-and-credential-use"
|
|
122
125
|
},
|
|
123
126
|
{
|
|
124
127
|
"choice": "apiKey",
|
|
@@ -128,8 +131,11 @@
|
|
|
128
131
|
"via": "browser",
|
|
129
132
|
"prerequisite": null,
|
|
130
133
|
"offer": false,
|
|
131
|
-
"reason": "API
|
|
132
|
-
"source": "dist/extensions/anthropic/openclaw.plugin.json (2026.8.1)"
|
|
134
|
+
"reason": "API key (billed per use)",
|
|
135
|
+
"source": "dist/extensions/anthropic/openclaw.plugin.json (2026.8.1)",
|
|
136
|
+
"auth": "api_key",
|
|
137
|
+
"terms": "allowed",
|
|
138
|
+
"termsUrl": "https://code.claude.com/docs/en/legal-and-compliance#authentication-and-credential-use"
|
|
133
139
|
},
|
|
134
140
|
{
|
|
135
141
|
"choice": "clawrouter-api-key",
|
|
@@ -348,8 +354,11 @@
|
|
|
348
354
|
"via": "browser",
|
|
349
355
|
"prerequisite": null,
|
|
350
356
|
"offer": false,
|
|
351
|
-
"reason": "
|
|
352
|
-
"source": "dist/extensions/anthropic/openclaw.plugin.json (2026.8.1)"
|
|
357
|
+
"reason": "Token import is not the native Claude Code login route; direct Claude.ai OAuth remains excluded.",
|
|
358
|
+
"source": "dist/extensions/anthropic/openclaw.plugin.json (2026.8.1)",
|
|
359
|
+
"auth": "token",
|
|
360
|
+
"terms": "grey",
|
|
361
|
+
"termsUrl": "https://code.claude.com/docs/en/legal-and-compliance#authentication-and-credential-use"
|
|
353
362
|
},
|
|
354
363
|
{
|
|
355
364
|
"choice": "sglang",
|
package/dist/runs.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// Runs: one Gateway run per spec, streamed through typed events, ending in a classified RunEnd (5.8, O8).
|
|
2
2
|
import { randomUUID } from 'node:crypto';
|
|
3
3
|
import { setTimeout as delay } from 'node:timers/promises';
|
|
4
|
+
import { authStatus } from "./auth-status.js";
|
|
4
5
|
import { classify } from "./classify.js";
|
|
5
6
|
// The gateway gives up on a silent run after an hour; we wait ten minutes longer for the reply frame itself.
|
|
6
7
|
const WAIT_MS = 3_600_000;
|
|
@@ -125,7 +126,7 @@ export function createRuns(ctx) {
|
|
|
125
126
|
// The picked account must be the one called: check it is signed in for this member before the run, since
|
|
126
127
|
// the engine would otherwise fail the run only after admitting it. An explicit provider/model is strict on
|
|
127
128
|
// the pinned engine (never another provider or model), so this check plus the override is the guarantee.
|
|
128
|
-
const status = (refresh) => ctx.request
|
|
129
|
+
const status = (refresh) => authStatus(ctx.request, agentId, refresh, picked.provider === 'claude-cli');
|
|
129
130
|
let auth = await status(false);
|
|
130
131
|
if (auth.unavailable)
|
|
131
132
|
auth = await status(true); // no prepared snapshot yet: build it once
|
package/dist/signin.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { GatewayTransport, Member, SignInView } from './types.ts';
|
|
1
|
+
import type { GatewayTransport, Member, SignInOptions, SignInView } from './types.ts';
|
|
2
2
|
export type SignInCtx = {
|
|
3
3
|
request: GatewayTransport['request'];
|
|
4
4
|
ensure(member: Member): Promise<{
|
|
@@ -11,14 +11,11 @@ export type SignInCtx = {
|
|
|
11
11
|
* `paste` hands a returned browser address to a waiting wizard text step. Every exit short of done cancels this
|
|
12
12
|
* session and its callback listener only.
|
|
13
13
|
*/
|
|
14
|
-
export declare function signIn(ctx: SignInCtx, member: Member, o: {
|
|
15
|
-
authChoice: string;
|
|
16
|
-
via?: 'browser' | 'code';
|
|
17
|
-
}, on: (v: SignInView) => void): {
|
|
14
|
+
export declare function signIn(ctx: SignInCtx, member: Member, o: SignInOptions, on: (v: SignInView) => void): {
|
|
18
15
|
paste(text: string): void;
|
|
19
16
|
cancel(): void;
|
|
20
17
|
done: Promise<SignInView>;
|
|
21
18
|
};
|
|
22
|
-
/**
|
|
19
|
+
/** Usable provider profiles plus native Claude Code readiness reported by the engine. */
|
|
23
20
|
export declare function providers(ctx: SignInCtx, member: Member, refresh?: boolean): Promise<string[]>;
|
|
24
21
|
export declare function signOut(ctx: SignInCtx, member: Member, provider: string): Promise<void>;
|
package/dist/signin.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
// Sign-in: the kit drives OpenClaw's own setup wizard loop and holds the ChatGPT callback port during a browser
|
|
2
|
-
// sign-in; credentials
|
|
2
|
+
// sign-in; OAuth credentials stay in the engine/CLI. Explicit API keys go only to engine activation (D11).
|
|
3
3
|
import { randomUUID } from 'node:crypto';
|
|
4
4
|
import { createServer } from 'node:http';
|
|
5
|
+
import { authStatus } from "./auth-status.js";
|
|
6
|
+
import { signedInProviders } from "./runs.js";
|
|
5
7
|
import { words } from "./words.js";
|
|
6
8
|
// The pin's wizard contract (2026.8.1): steps arrive only from `wizard.next` (wizard.status answers {status, error}
|
|
7
9
|
// and never carries a step), and one session at a time holds the gateway's single setup admission.
|
|
@@ -31,6 +33,18 @@ export function signIn(ctx, member, o, on) {
|
|
|
31
33
|
let settleStart;
|
|
32
34
|
const startingSettled = new Promise((resolve) => { settleStart = resolve; });
|
|
33
35
|
let over = false;
|
|
36
|
+
let approval = false;
|
|
37
|
+
let sawDeviceCode = false;
|
|
38
|
+
let codeExpired = false;
|
|
39
|
+
let codeTimer;
|
|
40
|
+
const stopApproval = () => {
|
|
41
|
+
approval = false;
|
|
42
|
+
if (codeTimer)
|
|
43
|
+
clearTimeout(codeTimer);
|
|
44
|
+
codeTimer = undefined;
|
|
45
|
+
};
|
|
46
|
+
const cancelled = () => ({ state: 'failed', via, why: 'declined', error: words('signin.cancelled') });
|
|
47
|
+
const expired = () => ({ state: 'failed', via, why: 'expired', error: words('signin.expired') });
|
|
34
48
|
let settle;
|
|
35
49
|
let pasteIn;
|
|
36
50
|
let returned;
|
|
@@ -46,7 +60,11 @@ export function signIn(ctx, member, o, on) {
|
|
|
46
60
|
if (over)
|
|
47
61
|
return;
|
|
48
62
|
over = true;
|
|
63
|
+
stopApproval();
|
|
64
|
+
o.signal?.removeEventListener('abort', cancel);
|
|
49
65
|
owner.abort();
|
|
66
|
+
returned = undefined;
|
|
67
|
+
pasteIn = undefined;
|
|
50
68
|
await closeCallback();
|
|
51
69
|
on(view);
|
|
52
70
|
settle(view);
|
|
@@ -63,6 +81,8 @@ export function signIn(ctx, member, o, on) {
|
|
|
63
81
|
return releasing;
|
|
64
82
|
};
|
|
65
83
|
const paste = (text) => {
|
|
84
|
+
if (over)
|
|
85
|
+
return;
|
|
66
86
|
if (pasteIn)
|
|
67
87
|
pasteIn(text);
|
|
68
88
|
else
|
|
@@ -71,9 +91,14 @@ export function signIn(ctx, member, o, on) {
|
|
|
71
91
|
const cancel = () => {
|
|
72
92
|
// Stop the drive now; the start itself is never aborted, and release waits for it to settle before cancelling,
|
|
73
93
|
// so the gateway's one setup admission is freed by a cancel that the engine can actually find.
|
|
94
|
+
if (signal.aborted)
|
|
95
|
+
return;
|
|
74
96
|
owner.abort();
|
|
75
|
-
void (async () => { await release(); await finish(
|
|
97
|
+
void (async () => { await release(); await finish(cancelled()); })();
|
|
76
98
|
};
|
|
99
|
+
o.signal?.addEventListener('abort', cancel, { once: true });
|
|
100
|
+
if (o.signal?.aborted)
|
|
101
|
+
cancel();
|
|
77
102
|
/** Hold 127.0.0.1:<callbackPort> for the sign-in's life; a taken port is why the sign-in cannot start. */
|
|
78
103
|
const holdCallback = () => {
|
|
79
104
|
let took = false;
|
|
@@ -111,8 +136,42 @@ export function signIn(ctx, member, o, on) {
|
|
|
111
136
|
return { state: 'failed', via, why: 'busy' };
|
|
112
137
|
}
|
|
113
138
|
const { agentId } = await ctx.ensure(member);
|
|
114
|
-
//
|
|
115
|
-
//
|
|
139
|
+
// Native login is completed by the person in unmodified Claude Code. The pin does not expose this
|
|
140
|
+
// choice via auth.start; activation verifies the CLI route and persists it only after a live test succeeds.
|
|
141
|
+
if (o.authChoice === 'anthropic-cli' || o.authChoice === 'apiKey') {
|
|
142
|
+
settleStart();
|
|
143
|
+
let apiKey;
|
|
144
|
+
if (o.authChoice === 'anthropic-cli') {
|
|
145
|
+
const detected = await ctx.request('openclaw.setup.detect', { agentId }, { timeoutMs: STATUS_MS });
|
|
146
|
+
if (!detected.candidates?.some((candidate) => candidate.kind === 'claude-cli' && candidate.credentials === true))
|
|
147
|
+
return { state: 'failed', via, why: 'failed', error: 'Sign in with Claude Code on this machine in the kit’s isolated HOME, then try again. The login stays in Claude Code.' };
|
|
148
|
+
}
|
|
149
|
+
else {
|
|
150
|
+
say({ prompt: 'API key (billed per use)' });
|
|
151
|
+
apiKey = returned ?? await new Promise((resolve) => {
|
|
152
|
+
const stop = (value) => { clearTimeout(timer); signal.removeEventListener('abort', abort); pasteIn = undefined; resolve(value); };
|
|
153
|
+
const abort = () => stop();
|
|
154
|
+
const timer = setTimeout(abort, PASTE_MS);
|
|
155
|
+
pasteIn = stop;
|
|
156
|
+
signal.addEventListener('abort', abort, { once: true });
|
|
157
|
+
if (signal.aborted)
|
|
158
|
+
abort();
|
|
159
|
+
});
|
|
160
|
+
returned = undefined;
|
|
161
|
+
if (!apiKey)
|
|
162
|
+
return { state: 'failed', via, why: signal.aborted ? 'declined' : 'expired' };
|
|
163
|
+
}
|
|
164
|
+
if (signal.aborted)
|
|
165
|
+
return { state: 'failed', via, why: 'declined' };
|
|
166
|
+
const result = await ctx.request('openclaw.setup.activate', {
|
|
167
|
+
agentId, kind: apiKey === undefined ? 'claude-cli' : 'api-key',
|
|
168
|
+
...(apiKey === undefined ? {} : { authChoice: 'apiKey', apiKey }),
|
|
169
|
+
}, { timeoutMs: PULL_MS, signal });
|
|
170
|
+
// API secrets must never be echoed in a view, even if the gateway returns an error containing one.
|
|
171
|
+
return result.ok ? { state: 'done', via } : { state: 'failed', via, why: 'failed',
|
|
172
|
+
error: apiKey === undefined ? cut(result.error ?? 'Claude Code activation failed') : 'API key activation failed' };
|
|
173
|
+
}
|
|
174
|
+
// The client chooses the wizard id; cancellation waits for the engine to register it.
|
|
116
175
|
sessionId = `byokit-${randomUUID()}`;
|
|
117
176
|
let started;
|
|
118
177
|
try {
|
|
@@ -125,8 +184,9 @@ export function signIn(ctx, member, o, on) {
|
|
|
125
184
|
if (started.done)
|
|
126
185
|
return { state: 'done', via };
|
|
127
186
|
// wizard.next, never wizard.status: the status method answers {status, error} and carries no step.
|
|
128
|
-
const
|
|
129
|
-
const
|
|
187
|
+
const options = () => approval ? { timeoutMs: null, signal } : pullOptions(signal);
|
|
188
|
+
const pull = () => ctx.request('wizard.next', { sessionId }, options());
|
|
189
|
+
const answer = (step, value) => ctx.request('wizard.next', { sessionId, answer: { stepId: step.id, ...(value === undefined ? {} : { value }) } }, options());
|
|
130
190
|
const waitForPaste = () => new Promise((resolve) => {
|
|
131
191
|
if (returned !== undefined) {
|
|
132
192
|
const text = returned;
|
|
@@ -166,6 +226,16 @@ export function signIn(ctx, member, o, on) {
|
|
|
166
226
|
const current = step;
|
|
167
227
|
step = undefined;
|
|
168
228
|
if (current.deviceCode) {
|
|
229
|
+
stopApproval();
|
|
230
|
+
approval = true;
|
|
231
|
+
sawDeviceCode = true;
|
|
232
|
+
// The pin converts its provider duration to minutes. Prefer exact seconds if the engine supplies them.
|
|
233
|
+
const duration = current.deviceCode.expires_in !== undefined
|
|
234
|
+
? Number(current.deviceCode.expires_in) * 1_000
|
|
235
|
+
: Number(current.deviceCode.expiresInMinutes) * 60_000;
|
|
236
|
+
if (Number.isFinite(duration) && duration >= 0) {
|
|
237
|
+
codeTimer = setTimeout(() => { codeExpired = true; owner.abort(); }, duration);
|
|
238
|
+
}
|
|
169
239
|
// The code is on the card; acknowledging it lets the engine poll the provider itself.
|
|
170
240
|
say({ ...(current.deviceCode.code ? { code: current.deviceCode.code } : {}), ...(current.externalUrl ? { url: current.externalUrl } : {}) });
|
|
171
241
|
const next = await answer(current);
|
|
@@ -176,10 +246,12 @@ export function signIn(ctx, member, o, on) {
|
|
|
176
246
|
step = next.step;
|
|
177
247
|
continue;
|
|
178
248
|
}
|
|
249
|
+
if (current.type !== 'progress')
|
|
250
|
+
stopApproval();
|
|
179
251
|
if (current.type === 'text' && !current.sensitive) {
|
|
180
252
|
const value = await waitForPaste();
|
|
181
253
|
if (value === undefined)
|
|
182
|
-
return
|
|
254
|
+
return signal.aborted ? cancelled() : expired();
|
|
183
255
|
const next = await answer(current, value);
|
|
184
256
|
if (next.done) {
|
|
185
257
|
terminal = next;
|
|
@@ -212,10 +284,12 @@ export function signIn(ctx, member, o, on) {
|
|
|
212
284
|
step = next.step;
|
|
213
285
|
}
|
|
214
286
|
if (signal.aborted)
|
|
215
|
-
return
|
|
287
|
+
return codeExpired ? expired() : cancelled();
|
|
216
288
|
if (!terminal)
|
|
217
289
|
return { state: 'failed', via, why: 'expired' };
|
|
218
290
|
const error = String(terminal.error ?? (terminal.status === 'error' ? 'Sign-in failed' : ''));
|
|
291
|
+
if (sawDeviceCode && /expired_token|code.*expired|device.*(?:expired|timed out)/i.test(error))
|
|
292
|
+
return expired();
|
|
219
293
|
return error ? { state: 'failed', via, why: 'failed', error: cut(error) } : { state: 'done', via };
|
|
220
294
|
};
|
|
221
295
|
void (async () => {
|
|
@@ -225,11 +299,13 @@ export function signIn(ctx, member, o, on) {
|
|
|
225
299
|
}
|
|
226
300
|
catch (error) {
|
|
227
301
|
if (signal.aborted)
|
|
228
|
-
view =
|
|
302
|
+
view = codeExpired ? expired() : cancelled();
|
|
303
|
+
else if (sawDeviceCode && /expired_token|code.*expired|device.*(?:expired|timed out)/i.test(cut(error)))
|
|
304
|
+
view = expired();
|
|
229
305
|
else if (BUSY.test(cut(error)))
|
|
230
306
|
view = { state: 'failed', via, why: 'busy' };
|
|
231
307
|
else
|
|
232
|
-
view = { state: 'failed', via, why: 'failed', error: cut(error) };
|
|
308
|
+
view = { state: 'failed', via, why: 'failed', error: o.authChoice === 'apiKey' ? 'API key activation failed' : cut(error) };
|
|
233
309
|
}
|
|
234
310
|
settleStart();
|
|
235
311
|
if (view.state !== 'done')
|
|
@@ -238,12 +314,10 @@ export function signIn(ctx, member, o, on) {
|
|
|
238
314
|
})();
|
|
239
315
|
return { paste, cancel, done };
|
|
240
316
|
}
|
|
241
|
-
/**
|
|
317
|
+
/** Usable provider profiles plus native Claude Code readiness reported by the engine. */
|
|
242
318
|
export async function providers(ctx, member, refresh) {
|
|
243
319
|
const { agentId } = await ctx.ensure(member);
|
|
244
|
-
|
|
245
|
-
const names = (status?.providers ?? []).map((entry) => (typeof entry === 'string' ? entry : entry?.provider));
|
|
246
|
-
return [...new Set(names.filter((name) => typeof name === 'string' && name !== ''))];
|
|
320
|
+
return signedInProviders(await authStatus(ctx.request, agentId, refresh, true)) ?? [];
|
|
247
321
|
}
|
|
248
322
|
export async function signOut(ctx, member, provider) {
|
|
249
323
|
const { agentId } = await ctx.ensure(member);
|
package/dist/types.d.ts
CHANGED
|
@@ -83,11 +83,17 @@ export type RunEnd = {
|
|
|
83
83
|
until?: number;
|
|
84
84
|
message: string;
|
|
85
85
|
};
|
|
86
|
+
export type SignInOptions = {
|
|
87
|
+
authChoice: string;
|
|
88
|
+
via?: 'browser' | 'code';
|
|
89
|
+
signal?: AbortSignal;
|
|
90
|
+
};
|
|
86
91
|
export type SignInView = {
|
|
87
92
|
state: 'waiting' | 'done' | 'failed';
|
|
88
93
|
via: 'browser' | 'code';
|
|
89
94
|
url?: string;
|
|
90
95
|
code?: string;
|
|
96
|
+
prompt?: string;
|
|
91
97
|
error?: string;
|
|
92
98
|
why?: 'busy' | 'declined' | 'expired' | 'failed';
|
|
93
99
|
};
|
|
@@ -108,7 +114,7 @@ export type Decision = {
|
|
|
108
114
|
answer?: unknown;
|
|
109
115
|
};
|
|
110
116
|
export type KitState = {
|
|
111
|
-
phase: 'stopped' | 'installing' | 'starting' | 'repairing' | 'ready' | 'restarting' | 'failed' | 'needs-update';
|
|
117
|
+
phase: 'stopped' | 'installing' | 'starting' | 'repairing' | 'ready' | 'restarting' | 'failed' | 'needs-update' | 'locked';
|
|
112
118
|
why?: 'install' | 'handshake' | 'exited' | 'port' | 'version';
|
|
113
119
|
retryAt?: number;
|
|
114
120
|
};
|
|
@@ -125,6 +131,9 @@ export type Route = {
|
|
|
125
131
|
provider: string;
|
|
126
132
|
plugin: string;
|
|
127
133
|
billing: 'subscription' | 'api' | 'local';
|
|
134
|
+
auth?: 'cli' | 'api_key' | 'token';
|
|
135
|
+
terms?: 'allowed' | 'grey';
|
|
136
|
+
termsUrl?: string;
|
|
128
137
|
via: 'browser' | 'code';
|
|
129
138
|
prerequisite: string | null;
|
|
130
139
|
offer: boolean;
|
|
@@ -134,7 +143,7 @@ export type Route = {
|
|
|
134
143
|
export interface GatewayTransport {
|
|
135
144
|
start(): Promise<Hello>;
|
|
136
145
|
request(method: string, params?: unknown, o?: {
|
|
137
|
-
timeoutMs?: number;
|
|
146
|
+
timeoutMs?: number | null;
|
|
138
147
|
signal?: AbortSignal;
|
|
139
148
|
expectFinal?: boolean;
|
|
140
149
|
onAccepted?: (payload: unknown) => void;
|
|
@@ -147,7 +156,7 @@ export interface GatewayTransport {
|
|
|
147
156
|
stop(): Promise<void>;
|
|
148
157
|
}
|
|
149
158
|
export type CallOptions = {
|
|
150
|
-
timeoutMs?: number;
|
|
159
|
+
timeoutMs?: number | null;
|
|
151
160
|
signal?: AbortSignal;
|
|
152
161
|
};
|
|
153
162
|
export type { GatewayMethod, GatewayParams, GatewayResult } from './generated/methods.ts';
|
package/dist/words.js
CHANGED
package/dist/words.json
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
"engine.installing": "Getting things ready on this computer. The first time takes a few minutes.",
|
|
3
3
|
"engine.starting": "Starting up…",
|
|
4
4
|
"engine.repairing": "Fixing a small problem with the setup. This takes a moment.",
|
|
5
|
+
"engine.locked": "Your saved sign-in is locked. Unlock your password storage, then try again.",
|
|
5
6
|
"engine.ready": "Ready.",
|
|
6
7
|
"engine.restarting": "Something stopped. Starting it again by itself.",
|
|
7
8
|
"engine.failed": "This computer couldn't start the helper. Restart the app to try again.",
|
|
@@ -12,6 +13,7 @@
|
|
|
12
13
|
"member.network": "Can't reach {name} right now. This keeps trying by itself.",
|
|
13
14
|
"signin.returned": "Thanks. Finishing the sign-in — you can go back to the app now.",
|
|
14
15
|
"signin.busy": "Another sign-in is already in progress. Finish or cancel it, then try again.",
|
|
16
|
+
"signin.cancelled": "Sign-in cancelled. You can start again whenever you are ready.",
|
|
15
17
|
"signin.expired": "The sign-in took too long. Start it again.",
|
|
16
18
|
"approval.ask": "{helper} wants to {summary}. Allow it?",
|
|
17
19
|
"approval.expired": "Nobody answered in time, so this wasn't allowed.",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@byokit/openclaw",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.4",
|
|
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",
|
|
@@ -56,7 +56,7 @@
|
|
|
56
56
|
"@byokit/relay": "0.4.2",
|
|
57
57
|
"@byokit/reach": "0.4.0",
|
|
58
58
|
"@byokit/seal": "0.2.0",
|
|
59
|
-
"@byokit/secrets": "0.
|
|
59
|
+
"@byokit/secrets": "0.5.0",
|
|
60
60
|
"@openclaw/gateway-client": "2026.8.1",
|
|
61
61
|
"@openclaw/gateway-protocol": "2026.8.1",
|
|
62
62
|
"ws": "8.21.3"
|