@m1a0rz/agent-identity 0.3.4 → 0.4.1

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.
Files changed (34) hide show
  1. package/README-cn.md +44 -8
  2. package/README.md +44 -8
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/index.js +30 -3
  5. package/dist/src/actions/identity-actions.d.ts.map +1 -1
  6. package/dist/src/actions/identity-actions.js +6 -1
  7. package/dist/src/gateway/identity-session-methods.d.ts +67 -0
  8. package/dist/src/gateway/identity-session-methods.d.ts.map +1 -0
  9. package/dist/src/gateway/identity-session-methods.js +130 -0
  10. package/dist/src/hooks/before-agent-start.d.ts +4 -0
  11. package/dist/src/hooks/before-agent-start.d.ts.map +1 -1
  12. package/dist/src/hooks/before-agent-start.js +62 -5
  13. package/dist/src/services/identity-client.d.ts +5 -8
  14. package/dist/src/services/identity-client.d.ts.map +1 -1
  15. package/dist/src/services/identity-client.js +24 -81
  16. package/dist/src/services/identity-credentials.d.ts +1 -1
  17. package/dist/src/services/identity-credentials.d.ts.map +1 -1
  18. package/dist/src/services/identity-credentials.js +96 -89
  19. package/dist/src/services/tip-with-refresh.d.ts +4 -0
  20. package/dist/src/services/tip-with-refresh.d.ts.map +1 -1
  21. package/dist/src/services/tip-with-refresh.js +5 -1
  22. package/dist/src/store/sender-session-store.d.ts.map +1 -1
  23. package/dist/src/store/sender-session-store.js +13 -11
  24. package/dist/src/tools/identity-config-suggest.js +1 -1
  25. package/dist/src/types.d.ts +5 -1
  26. package/dist/src/types.d.ts.map +1 -1
  27. package/dist/src/utils/derive-session-key.d.ts +10 -1
  28. package/dist/src/utils/derive-session-key.d.ts.map +1 -1
  29. package/dist/src/utils/derive-session-key.js +18 -2
  30. package/dist/src/utils/sts-signer.d.ts +25 -0
  31. package/dist/src/utils/sts-signer.d.ts.map +1 -0
  32. package/dist/src/utils/sts-signer.js +153 -0
  33. package/openclaw.plugin.json +12 -2
  34. package/package.json +23 -5
package/README-cn.md CHANGED
@@ -109,11 +109,11 @@ openclaw plugins install --link .
109
109
  - `workloadPoolName` / `workloadName`:用于签发 TIP Token。默认:`default`、`openclaw-agent`。
110
110
  - `audience` / `durationSeconds`:可选,令牌受众与有效期。
111
111
  - `credentialsFile`:凭据 JSON 文件路径。默认:`VOLCENGINE_CREDENTIALS_FILE` 环境变量或 `/var/run/secrets/iam/credential`。
112
- - `credentialsMetadataUrl`:远程 STS 凭据拉取的 base URL。与 `roleTrn` 同时配置时,从 `{url}/{roleName}` 拉取。响应格式:`AccessKeyId`、`SecretAccessKey`、`SessionToken`、`ExpiredTime`。404 时回退到凭据文件。按过期时间缓存并刷新。需显式配置。
113
- - `roleTrn`:STS AssumeRole 的 Role TRN。设置后(且未设置 `workloadName`)不传 workload name,后端使用 roleName。优先级:`workloadName` > `roleTrn` > params。与 `credentialsMetadataUrl` 配合时,从 TRN 解析 role 名(如 `role/openclaw-agent` → `openclaw-agent`)。
112
+ - `credentialsMetadataUrl`:远程凭据拉取的完整 URL。与 `roleTrn` 同时配置时,从 URL 拉取(响应:`AccessKeyId`、`SecretAccessKey`、`SessionToken`),再用 `roleTrn` 做 AssumeRole 获取最终凭据。流程与 AK/SK + roleTrn 一致。404 时回退到凭据文件。按 ExpiredTime 缓存。需显式配置。
113
+ - `roleTrn`:STS AssumeRole 的 Role TRN。设置后(且未设置 `workloadName`)不传 workload name,后端使用 roleName。优先级:`workloadName` > `roleTrn` > params。与 `credentialsMetadataUrl` 配合时用于 AssumeRole,或与显式 AK/SK 配合。
114
114
  - `sessionToken`:STS 会话令牌(或使用 `VOLCENGINE_SESSION_TOKEN` 环境变量)。
115
115
 
116
- **凭据解析顺序**(AK/SK):1)显式 config → 2)环境变量(`VOLCENGINE_ACCESS_KEY`、`VOLCENGINE_SECRET_KEY`、`VOLCENGINE_SESSION_TOKEN`)→ 3)远程元数据(`credentialsMetadataUrl` + `roleTrn`,从 `{url}/{roleName}` 拉取;404 时回退)→ 4)凭据文件(config 的 `credentialsFile`,或 `VOLCENGINE_CREDENTIALS_FILE` 环境变量,或 `/var/run/secrets/iam/credential`)。凭据文件格式(VeFaaS):`access_key_id`、`secret_access_key`、`session_token`(可选)、`role_trn`(可选,用于 AssumeRole)。`RUNTIME_IAM_ROLE_TRN` 环境变量可在从文件加载时提供 role TRN。
116
+ **凭据解析顺序**(AK/SK):1)显式 config → 2)环境变量(`VOLCENGINE_ACCESS_KEY`、`VOLCENGINE_SECRET_KEY`、`VOLCENGINE_SESSION_TOKEN`)→ 3)远程元数据(`credentialsMetadataUrl` + `roleTrn`,从完整 URL 拉取后做 AssumeRole;404 时回退)→ 4)凭据文件(config 的 `credentialsFile`,或 `VOLCENGINE_CREDENTIALS_FILE` 环境变量,或 `/var/run/secrets/iam/credential`)。凭据文件格式(VeFaaS):`access_key_id`、`secret_access_key`、`session_token`(可选)、`role_trn`(可选,用于 AssumeRole)。`RUNTIME_IAM_ROLE_TRN` 环境变量可在从文件加载时提供 role TRN。
117
117
 
118
118
  **B. 用户登录配置(UserPool / OIDC)**:用于 `/identity login` 的用户登录与会话建立。
119
119
 
@@ -122,8 +122,9 @@ openclaw plugins install --link .
122
122
  - `callbackUrl`:OpenClaw 网关对外可访问的回调地址,例如 `http://127.0.0.1:18789/identity/oauth/callback`
123
123
  - `scope`:一般包含 `openid profile email`
124
124
 
125
- **C. 工具调用权限与风险审批(AuthZ,可选)**:用于 `before_tool_call` 时的 TIP + CheckPermission + 风险评估与用户审批。各开关独立,无统一 `enable`。
125
+ **C. 权限校验与风险审批(AuthZ,可选)**:用于 TIP + CheckPermission + 风险评估与用户审批。各开关独立,无统一 `enable`。
126
126
 
127
+ - `agentCheck`:在 `before_agent_start` 中对 agent 执行 CheckPermission(resource type agent)。校验已认证用户是否有权限调用当前 agent。使用 TIP 委托链最外层 actor 作为 resource id。默认 false。
127
128
  - `toolCheck`:对工具调用执行 CheckPermission(resource type tool)。默认 false。
128
129
  - `skillReadCheck`:对 SKILL.md 读取执行 CheckPermission(resource type skill)。解析 system prompt 中的 available_skills。默认 false。
129
130
  - `requireRiskApproval`:高风险工具调用需用户审批。默认 false。
@@ -134,7 +135,7 @@ openclaw plugins install --link .
134
135
  - `llmRiskCheck`:LLM 配置(`endpoint`、`api`、`model`、`apiKey`、`timeoutMs`、`cacheTtlMs`)。`enableLlmRiskCheck` 为 true 时必填。
135
136
  - `approvalTtlSeconds`:审批链接/命令的 TTL(秒)。默认 300。
136
137
 
137
- **预期结果**:配置完成后,插件可正常发起登录、获取 TIP Token。开启 AuthZ 相关开关后,工具/skill 权限检查与高风险审批生效;使用 `/identity approve <approval_id>` 审批被拦截的调用。
138
+ **预期结果**:配置完成后,插件可正常发起登录、获取 TIP Token。开启 AuthZ 相关开关后,agent/工具/skill 权限检查与高风险审批生效;使用 `/identity approve <approval_id>` 审批被拦截的调用。
138
139
 
139
140
  ---
140
141
 
@@ -159,6 +160,7 @@ openclaw plugins install --link .
159
160
  "scope": "openid profile email"
160
161
  },
161
162
  "authz": {
163
+ "agentCheck": false,
162
164
  "toolCheck": false,
163
165
  "skillReadCheck": false,
164
166
  "requireRiskApproval": false,
@@ -189,12 +191,14 @@ openclaw plugins install --link .
189
191
  | `durationSeconds` | number | 否 | TIP token 有效期(秒),默认 3600 |
190
192
  | `roleTrn` | string | 否 | STS AssumeRole 的 Role TRN。设置后(且未设置 workloadName)不传 workload name,后端使用 roleName。优先级:workloadName > roleTrn > params |
191
193
  | `credentialsFile` | string | 否 | 凭证 JSON 文件路径。默认 `VOLCENGINE_CREDENTIALS_FILE` 或 `/var/run/secrets/iam/credential` |
192
- | `credentialsMetadataUrl` | string | 否 | 远程 STS 拉取的 base URL。与 `roleTrn` 同时配置时从 `{url}/{roleName}` 拉取。404 时回退到 `credentialsFile` |
194
+ | `credentialsMetadataUrl` | string | 否 | 远程凭据拉取的完整 URL。与 `roleTrn` 同时配置时拉取后做 AssumeRole。404 时回退到 `credentialsFile` |
193
195
  | `sessionToken` | string | 否 | STS 临时会话令牌(或 `VOLCENGINE_SESSION_TOKEN`) |
196
+ | `subagentTipPropagation` | boolean | 否 | 将 TIP 和 session 传播到子 agent。默认 false |
197
+ | `webchatSessionExchange` | boolean | 否 | 启用 `identity.session.put` / `identity.session.get` gateway WS 方法供 webchat 客户端使用。默认 false |
194
198
 
195
199
  \* AK/SK 至少通过 `accessKeyId`+`secretAccessKey`、环境变量、`credentialsMetadataUrl`+`roleTrn` 或 `credentialsFile` 之一提供。
196
200
 
197
- **环境变量**:`VOLCENGINE_ACCESS_KEY`、`VOLCENGINE_SECRET_KEY`、`VOLCENGINE_SESSION_TOKEN`、`VOLCENGINE_CREDENTIALS_FILE`、`RUNTIME_IAM_ROLE_TRN`(从文件加载时用于 AssumeRole)。
201
+ **环境变量**:`VOLCENGINE_ACCESS_KEY`、`VOLCENGINE_SECRET_KEY`、`VOLCENGINE_SESSION_TOKEN`、`VOLCENGINE_CREDENTIALS_FILE`、`RUNTIME_IAM_ROLE_TRN`(从文件加载时用于 AssumeRole)。设置 `IDENTITY_STS_DEBUG=1` 可打印完整 STS AssumeRole 请求/响应用于调试。
198
202
 
199
203
  ### userpool 配置(OIDC 登录)
200
204
 
@@ -208,6 +212,7 @@ OAuth2 credential fetch 使用控制台配置的 redirect URL 和 scopes。可
208
212
 
209
213
  | 参数 | 类型 | 含义 |
210
214
  |------|------|------|
215
+ | `agentCheck` | boolean | 在 `before_agent_start` 中对 agent 执行 CheckPermission(resource type agent)。校验用户是否有权限调用当前 agent,使用 TIP 委托链最外层 actor 作为 resource id。默认 false。 |
211
216
  | `toolCheck` | boolean | 对工具调用执行 CheckPermission(resource type tool)。默认 false。 |
212
217
  | `skillReadCheck` | boolean | 对 SKILL.md 读取执行 CheckPermission(resource type skill)。默认 false。 |
213
218
  | `requireRiskApproval` | boolean | 高风险工具调用需用户审批。默认 false。 |
@@ -232,6 +237,37 @@ TIP token 通过 `GetWorkloadAccessTokenForJWT` 获取。工作负载行为:
232
237
 
233
238
  **审批消息**(当高风险工具被拦截时):若要向飞书(或 Telegram、Slack 等)推送审批请求,请在 openclaw.json 中将 `session.dmScope` 设置为 `per-channel-peer` 或 `per-account-channel-peer`。默认 `session.dmScope: "main"` 时,sessionKey 不包含 channel/peer 信息,插件无法推导推送目标,审批消息不会推送。用户仍可在 agent 的错误回复中看到 block/approval_id;使用 `/identity approve <id>` 审批。
234
239
 
240
+ ### WebChat Session Exchange(Gateway WS 方法)
241
+
242
+ 当 `identity.webchatSessionExchange` 为 `true` 时,插件注册两个 gateway WebSocket 方法,允许 webchat 客户端直接注入和获取 session token,无需走 OIDC 重定向流程:
243
+
244
+ | 方法 | 参数 | 响应 | 描述 |
245
+ | --- | --- | --- | --- |
246
+ | `identity.session.put` | `{ sessionKey, idToken, senderId?, channel? }` | `{ sub, expiresAt, effectiveSessionKey, hasTip }` | 将 OIDC id_token 注入到插件 session。通过 `buildEffectiveSessionKey` 解析实际存储 key(与 hooks/commands 相同的隔离逻辑)。 |
247
+ | `identity.session.get` | `{ sessionKey, senderId?, channel? }` | `{ userToken, sub, expiresAt, effectiveSessionKey }` | 获取指定 session 已存储的 user token。 |
248
+
249
+ - `senderId` 默认值为 `"openclaw-control-ui"`。对于 main session,实际存储 key 为 `agent:main:main:user:<senderId>`。
250
+ - `channel` 可选;当 session 来源于可发送消息的渠道(feishu、telegram 等)时传入,可启用 per-channel-peer key 提升。
251
+
252
+ 两个方法均**限制为 webchat WS 连接**(`isWebchatConnect` 检查),非 webchat 客户端会收到 `FORBIDDEN` 错误。
253
+
254
+ **配置:**
255
+
256
+ ```json
257
+ {
258
+ "identity": {
259
+ "webchatSessionExchange": true
260
+ }
261
+ }
262
+ ```
263
+
264
+ **典型流程(BFF → webchat → plugin):**
265
+
266
+ 1. BFF 完成 3LO 登录并获取用户的 OIDC `id_token`
267
+ 2. Webchat 客户端调用 `identity.session.put`,传入 session key 和 `id_token`
268
+ 3. 插件校验 token,存储 session,并获取 TIP
269
+ 4. 后续该 session 中的 agent 运行拥有有效身份——无需手动登录
270
+
235
271
  ### WebChat / TUI
236
272
 
237
273
  用户从 WebChat 或 TUI 运行 `/identity` 时,跟进消息不会投递;插件无 API 推送至这些渠道。请使用 `/identity status` 确认结果。
@@ -255,7 +291,7 @@ TIP token 通过 `GetWorkloadAccessTokenForJWT` 获取。工作负载行为:
255
291
 
256
292
  ## 钩子
257
293
 
258
- - **before_agent_start** - 仅为主 agent 获取 TIP token。
294
+ - **before_agent_start** - 仅为主 agent 获取 TIP token。开启 `authz.agentCheck` 后,会执行 CheckPermission 校验用户是否有权调用该 agent
259
295
  - **subagent_spawned** - 在子 agent 创建时将 TIP 传播到子会话。
260
296
  - **before_tool_call** - 群组上下文注入、可选 AuthZ(TIP 检查、CheckPermission、风险审批)、工具调用级凭据注入。
261
297
  - **after_tool_call** - 清理工具调用级凭据注入状态。
package/README.md CHANGED
@@ -109,11 +109,11 @@ The plugin typically needs three types of config:
109
109
  - `workloadPoolName` / `workloadName`: For issuing TIP Token. Defaults: `default`, `openclaw-agent`.
110
110
  - `audience` / `durationSeconds`: Optional, token audience and validity.
111
111
  - `credentialsFile`: Path to credential JSON. Default: `VOLCENGINE_CREDENTIALS_FILE` env or `/var/run/secrets/iam/credential`.
112
- - `credentialsMetadataUrl`: Base URL for remote STS credential fetch. When set with `roleTrn`, fetches from `{url}/{roleName}`. Response format: `AccessKeyId`, `SecretAccessKey`, `SessionToken`, `ExpiredTime`. 404 falls through to credential file. Cached and refreshed by expiry. Must be explicitly configured.
113
- - `roleTrn`: Role TRN for STS AssumeRole. When set (and `workloadName` not set), workload name is omitted; backend uses roleName. Priority: `workloadName` > `roleTrn` > params. Also used with `credentialsMetadataUrl` (role name parsed from TRN, e.g. `role/openclaw-agent` → `openclaw-agent`).
112
+ - `credentialsMetadataUrl`: Full URL for remote credential fetch. When set with `roleTrn`, fetches from URL (response: `AccessKeyId`, `SecretAccessKey`, `SessionToken`), then AssumeRole with `roleTrn` to get final credentials. Same flow as AK/SK + roleTrn. 404 falls through to credential file. Cached by ExpiredTime. Must be explicitly configured.
113
+ - `roleTrn`: Role TRN for STS AssumeRole. When set (and `workloadName` not set), workload name is omitted; backend uses roleName. Priority: `workloadName` > `roleTrn` > params. Used with `credentialsMetadataUrl` (AssumeRole after fetch) or explicit AK/SK.
114
114
  - `sessionToken`: STS session token (or use `VOLCENGINE_SESSION_TOKEN` env).
115
115
 
116
- **Credential resolution order** (AK/SK): 1) Explicit config → 2) Env vars (`VOLCENGINE_ACCESS_KEY`, `VOLCENGINE_SECRET_KEY`, `VOLCENGINE_SESSION_TOKEN`) → 3) Remote metadata (`credentialsMetadataUrl` + `roleTrn`, fetches from `{url}/{roleName}`; 404 falls through) → 4) Credential file (`credentialsFile` config, or `VOLCENGINE_CREDENTIALS_FILE` env, or `/var/run/secrets/iam/credential`). Credential file format (VeFaaS): `access_key_id`, `secret_access_key`, `session_token` (optional), `role_trn` (optional for AssumeRole). `RUNTIME_IAM_ROLE_TRN` env can supply role TRN when loading from file.
116
+ **Credential resolution order** (AK/SK): 1) Explicit config → 2) Env vars (`VOLCENGINE_ACCESS_KEY`, `VOLCENGINE_SECRET_KEY`, `VOLCENGINE_SESSION_TOKEN`) → 3) Remote metadata (`credentialsMetadataUrl` + `roleTrn`, fetches from full URL then AssumeRole; 404 falls through) → 4) Credential file (`credentialsFile` config, or `VOLCENGINE_CREDENTIALS_FILE` env, or `/var/run/secrets/iam/credential`). Credential file format (VeFaaS): `access_key_id`, `secret_access_key`, `session_token` (optional), `role_trn` (optional for AssumeRole). `RUNTIME_IAM_ROLE_TRN` env can supply role TRN when loading from file.
117
117
 
118
118
  **B. User login (UserPool / OIDC)**: For `/identity login` and session setup.
119
119
 
@@ -122,8 +122,9 @@ The plugin typically needs three types of config:
122
122
  - `callbackUrl`: Public callback URL for OpenClaw gateway, e.g. `http://127.0.0.1:18789/identity/oauth/callback`
123
123
  - `scope`: Typically `openid profile email`
124
124
 
125
- **C. Tool call AuthZ and risk approval (optional)**: For TIP + CheckPermission + risk evaluation and user approval in `before_tool_call`. Each flag is independent; no single "enable" switch.
125
+ **C. AuthZ and risk approval (optional)**: For TIP + CheckPermission + risk evaluation. Each flag is independent; no single "enable" switch.
126
126
 
127
+ - `agentCheck`: Run CheckPermission for agents (resource type agent) in `before_agent_start`. Verifies the user can invoke the current agent. Uses the outermost actor from TIP delegation chain as resource id. Default false.
127
128
  - `toolCheck`: Run CheckPermission for tools (resource type tool). Default false.
128
129
  - `skillReadCheck`: Run CheckPermission for read of SKILL.md (resource type skill). Parses available_skills from system prompt. Default false.
129
130
  - `requireRiskApproval`: Require user approval for high-risk tool calls. Default false.
@@ -134,7 +135,7 @@ The plugin typically needs three types of config:
134
135
  - `llmRiskCheck`: LLM config (`endpoint`, `api`, `model`, `apiKey`, `timeoutMs`, `cacheTtlMs`). Required when `enableLlmRiskCheck` is true.
135
136
  - `approvalTtlSeconds`: Approval link/command TTL (seconds). Default 300.
136
137
 
137
- **Expected outcome**: After config, the plugin can initiate login and obtain TIP Token. With AuthZ flags enabled, tool/skill permission checks and high-risk approvals apply; use `/identity approve <approval_id>` to approve blocked calls.
138
+ **Expected outcome**: After config, the plugin can initiate login and obtain TIP Token. With AuthZ flags enabled, agent/tool/skill permission checks and high-risk approvals apply; use `/identity approve <approval_id>` to approve blocked calls.
138
139
 
139
140
  ---
140
141
 
@@ -159,6 +160,7 @@ Add to `openclaw.json` under `plugins.entries.agent-identity.config`:
159
160
  "scope": "openid profile email"
160
161
  },
161
162
  "authz": {
163
+ "agentCheck": false,
162
164
  "toolCheck": false,
163
165
  "skillReadCheck": false,
164
166
  "requireRiskApproval": false,
@@ -189,12 +191,14 @@ Add to `openclaw.json` under `plugins.entries.agent-identity.config`:
189
191
  | `durationSeconds` | number | No | TIP token TTL (seconds), default 3600 |
190
192
  | `roleTrn` | string | No | Role TRN for STS AssumeRole. When set (and workloadName not set), workload name is omitted; backend uses roleName. Priority: workloadName > roleTrn > params |
191
193
  | `credentialsFile` | string | No | Path to credential JSON. Default: `VOLCENGINE_CREDENTIALS_FILE` or `/var/run/secrets/iam/credential` |
192
- | `credentialsMetadataUrl` | string | No | Base URL for remote STS fetch. When set with `roleTrn`, fetches from `{url}/{roleName}`. 404 falls through to `credentialsFile` |
194
+ | `credentialsMetadataUrl` | string | No | Full URL for remote credential fetch. When set with `roleTrn`, fetches then AssumeRole. 404 falls through to `credentialsFile` |
193
195
  | `sessionToken` | string | No | STS session token (or `VOLCENGINE_SESSION_TOKEN`) |
196
+ | `subagentTipPropagation` | boolean | No | Propagate TIP and session to subagents. Default false |
197
+ | `webchatSessionExchange` | boolean | No | Enable `identity.session.put` / `identity.session.get` gateway WS methods for webchat clients. Default false |
194
198
 
195
199
  \* AK/SK must be provided via `accessKeyId`+`secretAccessKey`, environment variables, `credentialsMetadataUrl`+`roleTrn`, or `credentialsFile`.
196
200
 
197
- **Environment variables**: `VOLCENGINE_ACCESS_KEY`, `VOLCENGINE_SECRET_KEY`, `VOLCENGINE_SESSION_TOKEN`, `VOLCENGINE_CREDENTIALS_FILE`, `RUNTIME_IAM_ROLE_TRN` (for AssumeRole when loading from file).
201
+ **Environment variables**: `VOLCENGINE_ACCESS_KEY`, `VOLCENGINE_SECRET_KEY`, `VOLCENGINE_SESSION_TOKEN`, `VOLCENGINE_CREDENTIALS_FILE`, `RUNTIME_IAM_ROLE_TRN` (for AssumeRole when loading from file). Set `IDENTITY_STS_DEBUG=1` to log full STS AssumeRole request/response for debugging.
198
202
 
199
203
  ### userpool config (OIDC login)
200
204
 
@@ -208,6 +212,7 @@ OAuth2 credential fetch uses control-plane redirect URL and scopes. Override via
208
212
 
209
213
  | Param | Type | Description |
210
214
  |-------|------|-------------|
215
+ | `agentCheck` | boolean | Run CheckPermission for agents (resource type agent) in `before_agent_start`. Verifies the user can invoke the current agent. Uses the outermost actor from TIP delegation chain as resource id. Default false. |
211
216
  | `toolCheck` | boolean | Run CheckPermission for tools (resource type tool). Default false. |
212
217
  | `skillReadCheck` | boolean | Run CheckPermission for read of SKILL.md (resource type skill). Default false. |
213
218
  | `requireRiskApproval` | boolean | Require user approval for high-risk tools. Default false. |
@@ -232,6 +237,37 @@ Login success and credential fetch follow-up messages (e.g. "✓ Credential for
232
237
 
233
238
  **Approval messages** (when a high-risk tool is blocked): For approval requests to be delivered to Feishu (or Telegram, Slack, etc.), set `session.dmScope` to `per-channel-peer` or `per-account-channel-peer` in openclaw.json. With default `session.dmScope: "main"`, the sessionKey does not include channel/peer info, so the plugin cannot derive a delivery target and approval messages are not pushed. The user will still see the block/approval_id in the agent's error reply; use `/identity approve <id>` to approve.
234
239
 
240
+ ### WebChat Session Exchange (Gateway WS Methods)
241
+
242
+ When `identity.webchatSessionExchange` is `true`, the plugin registers two gateway WebSocket methods for webchat clients to inject and retrieve session tokens without going through the OIDC redirect flow:
243
+
244
+ | Method | Params | Response | Description |
245
+ | --- | --- | --- | --- |
246
+ | `identity.session.put` | `{ sessionKey, idToken, senderId?, channel? }` | `{ sub, expiresAt, effectiveSessionKey, hasTip }` | Inject an OIDC id_token into a plugin session. Resolves effective storage key via `buildEffectiveSessionKey` (same sender isolation as hooks/commands). |
247
+ | `identity.session.get` | `{ sessionKey, senderId?, channel? }` | `{ userToken, sub, expiresAt, effectiveSessionKey }` | Retrieve the stored user token for a session. |
248
+
249
+ - `senderId` defaults to `"openclaw-control-ui"`. The effective storage key is `agent:main:main:user:<senderId>` for main sessions.
250
+ - `channel` is optional; when the session originates from a sendable channel (feishu, telegram, etc.), pass it to enable per-channel-peer key promotion.
251
+
252
+ Both methods are **restricted to webchat WS connections only** (`isWebchatConnect` check). Non-webchat clients receive a `FORBIDDEN` error.
253
+
254
+ **Config:**
255
+
256
+ ```json
257
+ {
258
+ "identity": {
259
+ "webchatSessionExchange": true
260
+ }
261
+ }
262
+ ```
263
+
264
+ **Typical flow (BFF → webchat → plugin):**
265
+
266
+ 1. BFF completes 3LO login and obtains an OIDC `id_token` for the user
267
+ 2. Webchat client calls `identity.session.put` with the session key and `id_token`
268
+ 3. Plugin verifies the token, stores the session, and acquires TIP
269
+ 4. Subsequent agent runs in that session have a valid identity — no manual login needed
270
+
235
271
  ### WebChat / TUI
236
272
 
237
273
  Follow-up messages (login success, credential fetch done) are not delivered when the user runs `/identity` from WebChat or TUI; the plugin has no API to push to those channels. Use `/identity status` to confirm results.
@@ -255,7 +291,7 @@ Follow-up messages (login success, credential fetch done) are not delivered when
255
291
 
256
292
  ## Hooks
257
293
 
258
- - **before_agent_start** - Fetch TIP token for main agent only.
294
+ - **before_agent_start** - Fetch TIP token for main agent only. When `authz.agentCheck` is enabled, runs CheckPermission to verify the user can invoke the agent.
259
295
  - **subagent_spawned** - Propagate TIP to child session on subagent spawn.
260
296
  - **before_tool_call** - Group context injection, optional AuthZ (TIP check, CheckPermission, risk approval), and per-tool-call credential injection.
261
297
  - **after_tool_call** - Clean up per-tool-call credential injection state.
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAgBA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAsE7D,MAAM,CAAC,OAAO,UAAU,QAAQ,CAAC,GAAG,EAAE,iBAAiB,QA2YtD"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAgBA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AA0E7D,MAAM,CAAC,OAAO,UAAU,QAAQ,CAAC,GAAG,EAAE,iBAAiB,QAyatD"}
package/dist/index.js CHANGED
@@ -43,6 +43,7 @@ import { createIdentityStatusTool } from "./src/tools/identity-status.js";
43
43
  import { createIdentityUnsetBindingTool } from "./src/tools/identity-unset-binding.js";
44
44
  import { createIdentityWhoamiTool } from "./src/tools/identity-whoami.js";
45
45
  import { parseSessionKeyToDeliveryTarget, } from "./src/utils/derive-session-key.js";
46
+ import { createSessionPutHandler, createSessionGetHandler, } from "./src/gateway/identity-session-methods.js";
46
47
  import { logDebug, logInfo, logWarn } from "./src/utils/logger.js";
47
48
  import { initEncryptionKey } from "./src/store/encryption.js";
48
49
  const PLUGIN_STORE_DIR = "~/.openclaw/plugins/identity";
@@ -308,15 +309,20 @@ export default function register(api) {
308
309
  api.on("message_received", (event, ctx) => {
309
310
  const channel = ctx.channelId ??
310
311
  event.metadata?.provider;
311
- if (!channel)
312
+ logInfo(api.logger, `message_received: channel=${channel ?? "(none)"} conversationId=${ctx.conversationId ?? "(none)"} accountId=${ctx.accountId ?? "(none)"}`);
313
+ if (!channel) {
314
+ logWarn(api.logger, `message_received: SKIP – no channel derived from ctx.channelId or event.metadata.provider`);
312
315
  return;
316
+ }
313
317
  const to = ctx.conversationId ??
314
318
  event.metadata?.to;
315
319
  const from = event.from;
316
320
  const metadata = event.metadata;
317
321
  const senderId = metadata?.senderId;
318
- if (!senderId)
322
+ if (!senderId) {
323
+ logWarn(api.logger, `message_received: SKIP – no senderId in event.metadata`);
319
324
  return;
325
+ }
320
326
  const sessionKey = deriveSessionKey({
321
327
  channel,
322
328
  senderId,
@@ -325,7 +331,12 @@ export default function register(api) {
325
331
  accountId: ctx.accountId,
326
332
  config: api.runtime.config.loadConfig(),
327
333
  });
328
- if (!sessionKey || !needsSenderIsolation(sessionKey))
334
+ if (!sessionKey) {
335
+ logWarn(api.logger, `message_received: SKIP – deriveSessionKey returned null (channel=${channel} senderId=${senderId})`);
336
+ return;
337
+ }
338
+ logInfo(api.logger, `message_received: sessionKey=${sessionKey.slice(0, 24)}... channel=${channel} conv=${to ?? "(none)"} senderId=${senderId}`);
339
+ if (!needsSenderIsolation(sessionKey))
329
340
  return;
330
341
  setSender(sessionKey, {
331
342
  senderId,
@@ -349,6 +360,9 @@ export default function register(api) {
349
360
  configWorkloadName: identityCfg?.workloadName,
350
361
  getOidcConfigForRefresh,
351
362
  logger: api.logger,
363
+ identityClient: hasIdentity ? identityClient : undefined,
364
+ namespaceName: authz?.namespaceName ?? "default",
365
+ agentCheck: authz?.agentCheck ?? false,
352
366
  }));
353
367
  api.on("before_tool_call", createSessionsSendPropagationHandler({
354
368
  storeDir,
@@ -397,4 +411,17 @@ export default function register(api) {
397
411
  }));
398
412
  // Companion after_tool_call: restore env snapshot set by credential injection
399
413
  api.on("after_tool_call", createAfterToolCallHandler({ logger: api.logger }));
414
+ // Gateway WS methods: webchat session exchange (inject / retrieve user token)
415
+ if (identityCfg?.webchatSessionExchange && hasIdentity) {
416
+ const sessionMethodDeps = {
417
+ storeDir,
418
+ identityService,
419
+ getOidcConfigForRefresh: getOidcConfigForRefresh ?? undefined,
420
+ configWorkloadName: identityCfg?.workloadName,
421
+ logger: api.logger,
422
+ };
423
+ api.registerGatewayMethod("identity.session.put", createSessionPutHandler(sessionMethodDeps));
424
+ api.registerGatewayMethod("identity.session.get", createSessionGetHandler(sessionMethodDeps));
425
+ logInfo(api.logger, "gateway methods: identity.session.put, identity.session.get (webchat session exchange)");
426
+ }
400
427
  }
@@ -1 +1 @@
1
- {"version":3,"file":"identity-actions.d.ts","sourceRoot":"","sources":["../../../src/actions/identity-actions.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"identity-actions.d.ts","sourceRoot":"","sources":["../../../src/actions/identity-actions.ts"],"names":[],"mappings":"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"}
@@ -112,6 +112,7 @@ export async function runLogin(deps, sessionKey, options) {
112
112
  const hasValidCred = session && identityService.parseUserToken(session.userToken).valid;
113
113
  if (hasValidCred && session) {
114
114
  const ctxAgentId = resolveAgentId({ sessionKey, config: config });
115
+ const errorHolder = {};
115
116
  const tipRefreshOptions = deps.getOidcConfigForRefresh
116
117
  ? {
117
118
  identityService,
@@ -119,15 +120,19 @@ export async function runLogin(deps, sessionKey, options) {
119
120
  configWorkloadName: deps.configWorkloadName,
120
121
  ctxAgentId,
121
122
  logger,
123
+ errorHolder,
122
124
  }
123
125
  : undefined;
124
126
  const tip = await getOrRefreshTIPToken(storeDir, sessionKey, tipRefreshOptions);
125
127
  if (tip) {
126
128
  return { kind: "already_logged_in", sub: session.sub };
127
129
  }
130
+ const detail = errorHolder.error
131
+ ? String(errorHolder.error.message ?? errorHolder.error)
132
+ : "Ensure userToken is valid or refresh token is available.";
128
133
  return {
129
134
  kind: "error",
130
- message: "Session valid but TIP refresh failed. Ensure userToken is valid or refresh token is available.",
135
+ message: `OIDC login failed: TIP acquisition failed: ${detail}`,
131
136
  };
132
137
  }
133
138
  try {
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Gateway WS methods for webchat session exchange:
3
+ *
4
+ * identity.session.put — inject an OIDC id_token into a plugin session
5
+ * identity.session.get — retrieve the stored user token for a session
6
+ *
7
+ * Both methods are restricted to webchat WS connections and gated by
8
+ * config.identity.webchatSessionExchange.
9
+ */
10
+ import type { IdentityService } from "../services/identity-service.js";
11
+ import type { OIDCConfigForRefresh } from "../services/session-refresh.js";
12
+ type RespondFn = (ok: boolean, payload?: unknown, error?: {
13
+ code: string;
14
+ message: string;
15
+ }) => void;
16
+ type GatewayMethodOptions = {
17
+ req: {
18
+ id: string;
19
+ method: string;
20
+ params?: unknown;
21
+ };
22
+ params: Record<string, unknown>;
23
+ client: {
24
+ connect?: {
25
+ client?: {
26
+ mode?: string;
27
+ };
28
+ };
29
+ } | null;
30
+ isWebchatConnect: (params: unknown) => boolean;
31
+ respond: RespondFn;
32
+ context: Record<string, unknown>;
33
+ };
34
+ export type GatewayMethodHandler = (opts: GatewayMethodOptions) => Promise<void> | void;
35
+ export type IdentitySessionMethodsDeps = {
36
+ storeDir: string;
37
+ identityService: IdentityService;
38
+ getOidcConfigForRefresh?: () => Promise<OIDCConfigForRefresh>;
39
+ configWorkloadName?: string;
40
+ logger: {
41
+ info?: (msg: string) => void;
42
+ debug?: (msg: string) => void;
43
+ warn?: (msg: string) => void;
44
+ };
45
+ };
46
+ /**
47
+ * identity.session.put — inject id_token into a session.
48
+ *
49
+ * Params: { sessionKey: string, idToken: string, senderId?: string, channel?: string }
50
+ * Response: { sub: string, expiresAt: number, effectiveSessionKey: string, hasTip: boolean }
51
+ *
52
+ * senderId defaults to "openclaw-control-ui". The effective storage key is derived
53
+ * via buildEffectiveSessionKey (same logic as hooks/commands) to ensure correct
54
+ * sender isolation.
55
+ */
56
+ export declare function createSessionPutHandler(deps: IdentitySessionMethodsDeps): GatewayMethodHandler;
57
+ /**
58
+ * identity.session.get — retrieve stored user token for a session.
59
+ *
60
+ * Params: { sessionKey: string, senderId?: string, channel?: string }
61
+ * Response: { userToken: string, sub: string, expiresAt: number | null, effectiveSessionKey: string }
62
+ *
63
+ * senderId defaults to "openclaw-control-ui".
64
+ */
65
+ export declare function createSessionGetHandler(deps: IdentitySessionMethodsDeps): GatewayMethodHandler;
66
+ export {};
67
+ //# sourceMappingURL=identity-session-methods.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"identity-session-methods.d.ts","sourceRoot":"","sources":["../../../src/gateway/identity-session-methods.ts"],"names":[],"mappings":"AAgBA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AACvE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,gCAAgC,CAAC;AAQ3E,KAAK,SAAS,GAAG,CAAC,EAAE,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,OAAO,EAAE,KAAK,CAAC,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,KAAK,IAAI,CAAC;AAErG,KAAK,oBAAoB,GAAG;IAC1B,GAAG,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC;IACtD,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,MAAM,EAAE;QAAE,OAAO,CAAC,EAAE;YAAE,MAAM,CAAC,EAAE;gBAAE,IAAI,CAAC,EAAE,MAAM,CAAA;aAAE,CAAA;SAAE,CAAA;KAAE,GAAG,IAAI,CAAC;IAC5D,gBAAgB,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,OAAO,CAAC;IAC/C,OAAO,EAAE,SAAS,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAClC,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG,CAAC,IAAI,EAAE,oBAAoB,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;AAExF,MAAM,MAAM,0BAA0B,GAAG;IACvC,QAAQ,EAAE,MAAM,CAAC;IACjB,eAAe,EAAE,eAAe,CAAC;IACjC,uBAAuB,CAAC,EAAE,MAAM,OAAO,CAAC,oBAAoB,CAAC,CAAC;IAC9D,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,MAAM,EAAE;QAAE,IAAI,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;QAAC,KAAK,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;QAAC,IAAI,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAA;KAAE,CAAC;CACvG,CAAC;AAUF;;;;;;;;;GASG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,0BAA0B,GAAG,oBAAoB,CA8D9F;AAED;;;;;;;GAOG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,0BAA0B,GAAG,oBAAoB,CAqC9F"}
@@ -0,0 +1,130 @@
1
+ /*
2
+ * Copyright (c) 2026 Beijing Volcano Engine Technology Co., Ltd. and/or its affiliates.
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+ import { getSession, setSession } from "../store/session-store.js";
17
+ import { buildEffectiveSessionKey } from "../store/sender-session-store.js";
18
+ import { getOrRefreshTIPToken } from "../services/tip-with-refresh.js";
19
+ import { logDebug, logInfo, logWarn } from "../utils/logger.js";
20
+ const DEFAULT_WEBCHAT_SENDER_ID = "openclaw-control-ui";
21
+ function respondError(respond, code, message) {
22
+ respond(false, undefined, { code, message });
23
+ }
24
+ function isWebchat(opts) {
25
+ return opts.isWebchatConnect(opts.client?.connect ?? null);
26
+ }
27
+ /**
28
+ * identity.session.put — inject id_token into a session.
29
+ *
30
+ * Params: { sessionKey: string, idToken: string, senderId?: string, channel?: string }
31
+ * Response: { sub: string, expiresAt: number, effectiveSessionKey: string, hasTip: boolean }
32
+ *
33
+ * senderId defaults to "openclaw-control-ui". The effective storage key is derived
34
+ * via buildEffectiveSessionKey (same logic as hooks/commands) to ensure correct
35
+ * sender isolation.
36
+ */
37
+ export function createSessionPutHandler(deps) {
38
+ const { storeDir, identityService, getOidcConfigForRefresh, configWorkloadName, logger } = deps;
39
+ return async (opts) => {
40
+ if (!isWebchat(opts)) {
41
+ return respondError(opts.respond, "FORBIDDEN", "identity.session.put is only available for webchat connections");
42
+ }
43
+ const { params } = opts;
44
+ const sessionKey = typeof params.sessionKey === "string" ? params.sessionKey.trim() : "";
45
+ const idToken = typeof params.idToken === "string" ? params.idToken.trim() : "";
46
+ const senderId = typeof params.senderId === "string" && params.senderId.trim()
47
+ ? params.senderId.trim()
48
+ : DEFAULT_WEBCHAT_SENDER_ID;
49
+ const channel = typeof params.channel === "string" && params.channel.trim()
50
+ ? params.channel.trim()
51
+ : undefined;
52
+ if (!sessionKey) {
53
+ return respondError(opts.respond, "INVALID_PARAMS", "sessionKey is required");
54
+ }
55
+ if (!idToken) {
56
+ return respondError(opts.respond, "INVALID_PARAMS", "idToken is required");
57
+ }
58
+ const effectiveKey = buildEffectiveSessionKey(sessionKey, senderId, channel);
59
+ const parsed = identityService.parseUserToken(idToken);
60
+ if (!parsed.valid || !parsed.sub) {
61
+ return respondError(opts.respond, "INVALID_TOKEN", "idToken is not a valid JWT or missing sub claim");
62
+ }
63
+ let expiresAt = Date.now() + 3600 * 1000;
64
+ try {
65
+ const payload = JSON.parse(Buffer.from(idToken.split(".")[1], "base64url").toString("utf-8"));
66
+ if (payload.exp)
67
+ expiresAt = payload.exp * 1000;
68
+ }
69
+ catch { /* use default */ }
70
+ await setSession(storeDir, effectiveKey, {
71
+ userToken: idToken,
72
+ sub: parsed.sub,
73
+ loginAt: Date.now(),
74
+ expiresAt,
75
+ });
76
+ logInfo(logger, `identity.session.put: session injected for effectiveKey=${effectiveKey} sub=${parsed.sub}`);
77
+ const tipRefreshOptions = getOidcConfigForRefresh
78
+ ? { identityService, getOidcConfigForRefresh, configWorkloadName, logger }
79
+ : undefined;
80
+ const tip = await getOrRefreshTIPToken(storeDir, effectiveKey, tipRefreshOptions).catch((err) => {
81
+ logWarn(logger, `identity.session.put: TIP acquisition failed after inject: ${String(err)}`);
82
+ return null;
83
+ });
84
+ opts.respond(true, {
85
+ sub: parsed.sub,
86
+ expiresAt,
87
+ effectiveSessionKey: effectiveKey,
88
+ hasTip: Boolean(tip),
89
+ });
90
+ };
91
+ }
92
+ /**
93
+ * identity.session.get — retrieve stored user token for a session.
94
+ *
95
+ * Params: { sessionKey: string, senderId?: string, channel?: string }
96
+ * Response: { userToken: string, sub: string, expiresAt: number | null, effectiveSessionKey: string }
97
+ *
98
+ * senderId defaults to "openclaw-control-ui".
99
+ */
100
+ export function createSessionGetHandler(deps) {
101
+ const { storeDir, logger } = deps;
102
+ return async (opts) => {
103
+ if (!isWebchat(opts)) {
104
+ return respondError(opts.respond, "FORBIDDEN", "identity.session.get is only available for webchat connections");
105
+ }
106
+ const { params } = opts;
107
+ const sessionKey = typeof params.sessionKey === "string" ? params.sessionKey.trim() : "";
108
+ const senderId = typeof params.senderId === "string" && params.senderId.trim()
109
+ ? params.senderId.trim()
110
+ : DEFAULT_WEBCHAT_SENDER_ID;
111
+ const channel = typeof params.channel === "string" && params.channel.trim()
112
+ ? params.channel.trim()
113
+ : undefined;
114
+ if (!sessionKey) {
115
+ return respondError(opts.respond, "INVALID_PARAMS", "sessionKey is required");
116
+ }
117
+ const effectiveKey = buildEffectiveSessionKey(sessionKey, senderId, channel);
118
+ const session = await getSession(storeDir, effectiveKey);
119
+ if (!session) {
120
+ return respondError(opts.respond, "NOT_FOUND", `No session found for effectiveKey=${effectiveKey}`);
121
+ }
122
+ logDebug(logger, `identity.session.get: returning token for effectiveKey=${effectiveKey} sub=${session.sub}`);
123
+ opts.respond(true, {
124
+ userToken: session.userToken,
125
+ sub: session.sub,
126
+ expiresAt: session.expiresAt ?? null,
127
+ effectiveSessionKey: effectiveKey,
128
+ });
129
+ };
130
+ }
@@ -3,6 +3,7 @@
3
3
  * Credential env injection is handled per-tool-call in before_tool_call
4
4
  * to avoid process.env race conditions between concurrent runs.
5
5
  */
6
+ import type { IdentityClientInterface } from "../services/identity-client.js";
6
7
  import type { IdentityService } from "../services/identity-service.js";
7
8
  import type { OIDCConfigForRefresh } from "../services/session-refresh.js";
8
9
  export type BeforeAgentStartDeps = {
@@ -15,6 +16,9 @@ export type BeforeAgentStartDeps = {
15
16
  debug?: (msg: string) => void;
16
17
  warn?: (msg: string) => void;
17
18
  };
19
+ identityClient?: IdentityClientInterface;
20
+ namespaceName?: string;
21
+ agentCheck?: boolean;
18
22
  };
19
23
  export declare function createBeforeAgentStartHandler(deps: BeforeAgentStartDeps): (_event: {
20
24
  prompt: string;
@@ -1 +1 @@
1
- {"version":3,"file":"before-agent-start.d.ts","sourceRoot":"","sources":["../../../src/hooks/before-agent-start.ts"],"names":[],"mappings":"AAgBA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AACvE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,gCAAgC,CAAC;AAM3E,MAAM,MAAM,oBAAoB,GAAG;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,eAAe,EAAE,eAAe,CAAC;IACjC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,uBAAuB,CAAC,EAAE,MAAM,OAAO,CAAC,oBAAoB,CAAC,CAAC;IAC9D,MAAM,EAAE;QAAE,IAAI,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;QAAC,KAAK,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;QAAC,IAAI,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAA;KAAE,CAAC;CACvG,CAAC;AAEF,wBAAgB,6BAA6B,CAAC,IAAI,EAAE,oBAAoB,IAWpE,QAAQ;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,EAAE,CAAA;CAAE,EAChD,KAAK;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,KAC7C,OAAO,CAAC;IAAE,cAAc,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAAC,CAuB/C"}
1
+ {"version":3,"file":"before-agent-start.d.ts","sourceRoot":"","sources":["../../../src/hooks/before-agent-start.ts"],"names":[],"mappings":"AAgBA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,gCAAgC,CAAC;AAC9E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AACvE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,gCAAgC,CAAC;AAqC3E,MAAM,MAAM,oBAAoB,GAAG;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,eAAe,EAAE,eAAe,CAAC;IACjC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,uBAAuB,CAAC,EAAE,MAAM,OAAO,CAAC,oBAAoB,CAAC,CAAC;IAC9D,MAAM,EAAE;QAAE,IAAI,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;QAAC,KAAK,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;QAAC,IAAI,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAA;KAAE,CAAC;IACtG,cAAc,CAAC,EAAE,uBAAuB,CAAC;IACzC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB,CAAC;AAEF,wBAAgB,6BAA6B,CAAC,IAAI,EAAE,oBAAoB,IAoBpE,QAAQ;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,EAAE,CAAA;CAAE,EAChD,KAAK;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,KAC7C,OAAO,CAAC;IAAE,cAAc,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAAC,CA8D/C"}