@m1a0rz/agent-identity 0.2.5 → 0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README-cn.md +19 -9
- package/README.md +22 -12
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +62 -22
- package/dist/src/actions/identity-actions.d.ts +7 -1
- package/dist/src/actions/identity-actions.d.ts.map +1 -1
- package/dist/src/actions/identity-actions.js +82 -34
- package/dist/src/commands/identity-commands.d.ts.map +1 -1
- package/dist/src/commands/identity-commands.js +14 -5
- package/dist/src/hooks/after-tool-call.d.ts +12 -0
- package/dist/src/hooks/after-tool-call.d.ts.map +1 -0
- package/dist/src/hooks/after-tool-call.js +31 -0
- package/dist/src/hooks/before-agent-start.d.ts +3 -3
- package/dist/src/hooks/before-agent-start.d.ts.map +1 -1
- package/dist/src/hooks/before-agent-start.js +10 -22
- package/dist/src/hooks/before-tool-call.d.ts +20 -14
- package/dist/src/hooks/before-tool-call.d.ts.map +1 -1
- package/dist/src/hooks/before-tool-call.js +207 -127
- package/dist/src/hooks/llm-input.d.ts +2 -0
- package/dist/src/hooks/llm-input.d.ts.map +1 -1
- package/dist/src/hooks/llm-input.js +15 -4
- package/dist/src/hooks/sessions-send-propagation.d.ts +1 -0
- package/dist/src/hooks/sessions-send-propagation.d.ts.map +1 -1
- package/dist/src/hooks/sessions-send-propagation.js +4 -2
- package/dist/src/hooks/sessions-spawn-propagation.d.ts.map +1 -1
- package/dist/src/hooks/sessions-spawn-propagation.js +4 -2
- package/dist/src/hooks/subagent-ended-cleanup.d.ts +1 -0
- package/dist/src/hooks/subagent-ended-cleanup.d.ts.map +1 -1
- package/dist/src/hooks/subagent-ended-cleanup.js +4 -1
- package/dist/src/risk/low-risk-tools.d.ts.map +1 -1
- package/dist/src/risk/low-risk-tools.js +0 -2
- package/dist/src/services/tip-acquisition.d.ts +0 -1
- package/dist/src/services/tip-acquisition.d.ts.map +1 -1
- package/dist/src/services/tip-acquisition.js +2 -2
- package/dist/src/services/tip-propagation.d.ts.map +1 -1
- package/dist/src/services/tip-propagation.js +1 -2
- package/dist/src/services/tip-with-refresh.d.ts +1 -1
- package/dist/src/services/tip-with-refresh.d.ts.map +1 -1
- package/dist/src/services/tip-with-refresh.js +3 -5
- package/dist/src/store/credential-env-snapshot.d.ts +38 -0
- package/dist/src/store/credential-env-snapshot.d.ts.map +1 -0
- package/dist/src/store/credential-env-snapshot.js +101 -0
- package/dist/src/store/encryption.d.ts +30 -0
- package/dist/src/store/encryption.d.ts.map +1 -0
- package/dist/src/store/encryption.js +147 -0
- package/dist/src/store/group-sender-store.d.ts +35 -0
- package/dist/src/store/group-sender-store.d.ts.map +1 -0
- package/dist/src/store/group-sender-store.js +112 -0
- package/dist/src/store/session-store.d.ts.map +1 -1
- package/dist/src/store/session-store.js +91 -8
- package/dist/src/store/tip-store.d.ts +11 -6
- package/dist/src/store/tip-store.d.ts.map +1 -1
- package/dist/src/store/tip-store.js +23 -54
- package/dist/src/tools/identity-approve-tool.d.ts.map +1 -1
- package/dist/src/tools/identity-approve-tool.js +3 -1
- package/dist/src/tools/identity-fetch.d.ts.map +1 -1
- package/dist/src/tools/identity-fetch.js +3 -1
- package/dist/src/tools/identity-list-credentials.d.ts +2 -0
- package/dist/src/tools/identity-list-credentials.d.ts.map +1 -1
- package/dist/src/tools/identity-list-credentials.js +8 -4
- package/dist/src/tools/identity-login.d.ts.map +1 -1
- package/dist/src/tools/identity-login.js +2 -1
- package/dist/src/tools/identity-logout.d.ts.map +1 -1
- package/dist/src/tools/identity-logout.js +2 -1
- package/dist/src/tools/identity-set-binding.d.ts.map +1 -1
- package/dist/src/tools/identity-set-binding.js +2 -1
- package/dist/src/tools/identity-status.d.ts.map +1 -1
- package/dist/src/tools/identity-status.js +2 -1
- package/dist/src/tools/identity-unset-binding.d.ts.map +1 -1
- package/dist/src/tools/identity-unset-binding.js +2 -1
- package/dist/src/tools/identity-whoami.d.ts.map +1 -1
- package/dist/src/tools/identity-whoami.js +2 -1
- package/dist/src/utils/derive-session-key.d.ts +7 -0
- package/dist/src/utils/derive-session-key.d.ts.map +1 -1
- package/dist/src/utils/derive-session-key.js +84 -15
- package/package.json +1 -1
- package/skills/SKILL.md +75 -150
package/README-cn.md
CHANGED
|
@@ -11,7 +11,9 @@ UserPool OIDC 登录、TIP (Trusted Identity Provider) 令牌(通过 Identity
|
|
|
11
11
|
- **OIDC 登录**:`/identity login` 返回 IdP 授权 URL。用户打开 URL 后,IdP 重定向到 `/identity/oauth/callback`。
|
|
12
12
|
- **TIP 令牌**:当会话中有已登录用户时,`before_agent_start` 钩子会获取 TIP 令牌。
|
|
13
13
|
- **凭据 3LO**:`/identity fetch <provider>` 返回授权 URL。IdP 重定向到 Identity 提供的回调地址(控制台配置)。
|
|
14
|
-
- **凭据绑定**:`/identity set <provider> <envVar>`
|
|
14
|
+
- **凭据绑定**:`/identity set <provider> <envVar>` 将存储的凭据绑定到环境变量。凭据按工具调用粒度安全注入,并发多用户会话之间互相隔离。
|
|
15
|
+
- **加密会话存储**:`sessions.json` 使用 AES-256-GCM 加密存储在磁盘上。旧版明文文件首次加载时自动迁移。
|
|
16
|
+
- **内存 TIP 缓存**:TIP 令牌仅存储在内存中(不持久化到磁盘)。TIP 是短效令牌,可随时从用户 session token 重新获取。
|
|
15
17
|
- **动态 UserPool**:通过 `userPoolName` + `clientName` 解析 OIDC 配置(无需手动配置 clientId)。
|
|
16
18
|
- **凭证加载**:从环境变量、文件或 STS AssumeRole 加载 AK/SK(veadk 风格)。
|
|
17
19
|
|
|
@@ -251,16 +253,24 @@ TIP token 通过 `GetWorkloadAccessTokenForJWT` 获取。工作负载行为:
|
|
|
251
253
|
|
|
252
254
|
## 钩子
|
|
253
255
|
|
|
254
|
-
- **before_agent_start** - 获取 TIP token
|
|
255
|
-
- **subagent_spawned** - 在子 agent 创建时将 TIP
|
|
256
|
-
- **before_tool_call** -
|
|
256
|
+
- **before_agent_start** - 仅为主 agent 获取 TIP token。
|
|
257
|
+
- **subagent_spawned** - 在子 agent 创建时将 TIP 传播到子会话。
|
|
258
|
+
- **before_tool_call** - 群组上下文注入、可选 AuthZ(TIP 检查、CheckPermission、风险审批)、工具调用级凭据注入。
|
|
259
|
+
- **after_tool_call** - 清理工具调用级凭据注入状态。
|
|
257
260
|
|
|
258
261
|
## 数据存储
|
|
259
262
|
|
|
260
263
|
插件数据位于 `~/.openclaw/plugins/identity/`:
|
|
261
264
|
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
265
|
+
| 文件 | 描述 |
|
|
266
|
+
|------|------|
|
|
267
|
+
| `sessions.json` | 加密存储的 sessionKey → userToken 映射。加载/保存时清理过期条目。 |
|
|
268
|
+
| `credential-env-bindings.json` | 按 session:`{ [sessionKey]: { [provider]: envVar } }` |
|
|
269
|
+
|
|
270
|
+
**仅内存存储(不持久化到磁盘):**
|
|
271
|
+
|
|
272
|
+
| 数据 | 描述 |
|
|
273
|
+
|------|------|
|
|
274
|
+
| TIP 令牌 | sessionKey → TIP token 缓存。短效,按需从 session token 重新获取。 |
|
|
275
|
+
| 凭据 | 按 session(api_key、oauth2)。gateway 重启后丢失;logout 时清除。 |
|
|
276
|
+
| OIDC state | 临时数据,5 分钟 TTL。 |
|
package/README.md
CHANGED
|
@@ -9,11 +9,13 @@ Integrates with [Volcengine Agent Identity and Permission Management](https://ww
|
|
|
9
9
|
## Features
|
|
10
10
|
|
|
11
11
|
- **OIDC Login**: `/identity login` returns IdP auth URL (no HTTP start endpoint). User opens URL, IdP redirects to `/identity/oauth/callback`.
|
|
12
|
-
- **TIP Token**: `before_agent_start` hook fetches TIP token when session has a logged-in user
|
|
12
|
+
- **TIP Token**: `before_agent_start` hook fetches TIP token when session has a logged-in user.
|
|
13
13
|
- **Credential 3LO**: `/identity fetch <provider>` returns auth URL. IdP redirects to Identity-provided callback (control-plane config).
|
|
14
|
-
- **Credential Binding**: `/identity set <provider> <envVar>` binds stored credential to env var. Credentials are injected
|
|
15
|
-
- **
|
|
16
|
-
- **
|
|
14
|
+
- **Credential Binding**: `/identity set <provider> <envVar>` binds stored credential to env var. Credentials are securely injected per-tool-call, isolated between concurrent multi-user sessions.
|
|
15
|
+
- **Encrypted Session Storage**: `sessions.json` is encrypted at rest (AES-256-GCM). Plaintext sessions from older versions are auto-migrated on first load.
|
|
16
|
+
- **In-memory TIP Cache**: TIP tokens are stored only in memory (no disk persistence). They are short-lived and re-obtained from the user's session token on demand.
|
|
17
|
+
- **Dynamic UserPool**: Resolve OIDC config by `userPoolName` + `clientName` (no manual clientId).
|
|
18
|
+
- **Credentials**: Load AK/SK from env, file, or STS AssumeRole (veadk-style).
|
|
17
19
|
|
|
18
20
|
## HTTP Endpoints
|
|
19
21
|
|
|
@@ -251,16 +253,24 @@ Follow-up messages (login success, credential fetch done) are not delivered when
|
|
|
251
253
|
|
|
252
254
|
## Hooks
|
|
253
255
|
|
|
254
|
-
- **before_agent_start** - Fetch TIP token
|
|
255
|
-
- **subagent_spawned** - Propagate TIP to child session on subagent spawn
|
|
256
|
-
- **before_tool_call** -
|
|
256
|
+
- **before_agent_start** - Fetch TIP token for main agent only.
|
|
257
|
+
- **subagent_spawned** - Propagate TIP to child session on subagent spawn.
|
|
258
|
+
- **before_tool_call** - Group context injection, optional AuthZ (TIP check, CheckPermission, risk approval), and per-tool-call credential injection.
|
|
259
|
+
- **after_tool_call** - Clean up per-tool-call credential injection state.
|
|
257
260
|
|
|
258
261
|
## Data Storage
|
|
259
262
|
|
|
260
263
|
Plugin data at `~/.openclaw/plugins/identity/`:
|
|
261
264
|
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
265
|
+
| File | Description |
|
|
266
|
+
|------|-------------|
|
|
267
|
+
| `sessions.json` | Encrypted sessionKey → userToken mapping. Expired entries pruned on load/save. |
|
|
268
|
+
| `credential-env-bindings.json` | Per-session: `{ [sessionKey]: { [provider]: envVar } }` |
|
|
269
|
+
|
|
270
|
+
**In-memory only (not persisted to disk):**
|
|
271
|
+
|
|
272
|
+
| Data | Description |
|
|
273
|
+
|------|-------------|
|
|
274
|
+
| TIP tokens | sessionKey → TIP token cache. Short-lived, re-obtained from session token on demand. |
|
|
275
|
+
| Credentials | Per-session (api_key, oauth2). Lost on gateway restart; cleared on logout. |
|
|
276
|
+
| OIDC state | Ephemeral, 5 min TTL. |
|
package/dist/index.d.ts.map
CHANGED
|
@@ -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;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAgBA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAqE7D,MAAM,CAAC,OAAO,UAAU,QAAQ,CAAC,GAAG,EAAE,iBAAiB,QA0YtD"}
|
package/dist/index.js
CHANGED
|
@@ -19,7 +19,10 @@ import { createLlmInputHandler } from "./src/hooks/llm-input.js";
|
|
|
19
19
|
import { createSessionsSendPropagationHandler } from "./src/hooks/sessions-send-propagation.js";
|
|
20
20
|
import { createSessionsSpawnPropagationHandler } from "./src/hooks/sessions-spawn-propagation.js";
|
|
21
21
|
import { createSubagentEndedCleanupHandler } from "./src/hooks/subagent-ended-cleanup.js";
|
|
22
|
+
import { setSender, clearSender } from "./src/store/group-sender-store.js";
|
|
23
|
+
import { deriveSessionKey, isGroupOrChannelSessionKey, } from "./src/utils/derive-session-key.js";
|
|
22
24
|
import { createBeforeToolCallHandler } from "./src/hooks/before-tool-call.js";
|
|
25
|
+
import { createAfterToolCallHandler } from "./src/hooks/after-tool-call.js";
|
|
23
26
|
import * as skillPathStore from "./src/store/skill-path-store.js";
|
|
24
27
|
import { createOIDCCallbackHandler, createOIDCCallbackHandlerLazy, } from "./src/routes/oidc-login.js";
|
|
25
28
|
import { IdentityClient, resolveOIDCConfig, } from "./src/services/identity-client.js";
|
|
@@ -41,6 +44,7 @@ import { createIdentityUnsetBindingTool } from "./src/tools/identity-unset-bindi
|
|
|
41
44
|
import { createIdentityWhoamiTool } from "./src/tools/identity-whoami.js";
|
|
42
45
|
import { parseSessionKeyToDeliveryTarget, } from "./src/utils/derive-session-key.js";
|
|
43
46
|
import { logInfo, logWarn } from "./src/utils/logger.js";
|
|
47
|
+
import { initEncryptionKey } from "./src/store/encryption.js";
|
|
44
48
|
const PLUGIN_STORE_DIR = "~/.openclaw/plugins/identity";
|
|
45
49
|
/**
|
|
46
50
|
* Whether Identity should be enabled.
|
|
@@ -62,6 +66,7 @@ function hasAnyIdentityConfig(identity) {
|
|
|
62
66
|
export default function register(api) {
|
|
63
67
|
const pluginConfig = (api.pluginConfig ?? {});
|
|
64
68
|
const storeDir = api.resolvePath(PLUGIN_STORE_DIR);
|
|
69
|
+
initEncryptionKey(storeDir);
|
|
65
70
|
const identityCfg = pluginConfig.identity;
|
|
66
71
|
const hasIdentity = hasAnyIdentityConfig(identityCfg);
|
|
67
72
|
const userpool = pluginConfig.userpool;
|
|
@@ -293,10 +298,47 @@ export default function register(api) {
|
|
|
293
298
|
api.registerTool(createIdentityListRiskPatternsTool(), { optional: true });
|
|
294
299
|
const authz = pluginConfig.authz;
|
|
295
300
|
const approvalTtlMs = (authz?.approvalTtlSeconds ?? 300) * 1000;
|
|
296
|
-
// Optional: agent must NOT have this (would self-approve). Use /identity approve for human approval.
|
|
297
301
|
api.registerTool(createIdentityApproveTool({ approvalTtlMs, logger: api.logger }), {
|
|
298
302
|
optional: true,
|
|
299
303
|
});
|
|
304
|
+
// Capture group sender on every inbound message so before_tool_call can
|
|
305
|
+
// identify which user triggered the current run.
|
|
306
|
+
api.on("message_received", (event, ctx) => {
|
|
307
|
+
const channel = ctx.channelId ??
|
|
308
|
+
event.metadata?.provider;
|
|
309
|
+
if (!channel)
|
|
310
|
+
return;
|
|
311
|
+
const to = ctx.conversationId ??
|
|
312
|
+
event.metadata?.to;
|
|
313
|
+
const from = event.from;
|
|
314
|
+
const metadata = event.metadata;
|
|
315
|
+
const senderId = metadata?.senderId;
|
|
316
|
+
if (!senderId)
|
|
317
|
+
return;
|
|
318
|
+
const sessionKey = deriveSessionKey({
|
|
319
|
+
channel,
|
|
320
|
+
senderId,
|
|
321
|
+
from,
|
|
322
|
+
to,
|
|
323
|
+
accountId: ctx.accountId,
|
|
324
|
+
config: api.runtime.config.loadConfig(),
|
|
325
|
+
});
|
|
326
|
+
if (!sessionKey || !isGroupOrChannelSessionKey(sessionKey))
|
|
327
|
+
return;
|
|
328
|
+
setSender(sessionKey, {
|
|
329
|
+
senderId,
|
|
330
|
+
senderName: metadata?.senderName,
|
|
331
|
+
from,
|
|
332
|
+
channelId: channel,
|
|
333
|
+
messageId: metadata?.messageId,
|
|
334
|
+
capturedAt: Date.now(),
|
|
335
|
+
});
|
|
336
|
+
logInfo(api.logger, `group sender captured session=${sessionKey} sender=${senderId}`);
|
|
337
|
+
}, { priority: 200 });
|
|
338
|
+
api.on("session_end", (_event, ctx) => {
|
|
339
|
+
if (ctx.sessionKey)
|
|
340
|
+
clearSender(ctx.sessionKey);
|
|
341
|
+
});
|
|
300
342
|
// Hooks
|
|
301
343
|
if (hasIdentity) {
|
|
302
344
|
api.on("before_agent_start", createBeforeAgentStartHandler({
|
|
@@ -327,32 +369,30 @@ export default function register(api) {
|
|
|
327
369
|
logger: api.logger,
|
|
328
370
|
}));
|
|
329
371
|
}
|
|
330
|
-
const toolCheck = authz?.toolCheck ?? false;
|
|
331
372
|
const skillReadCheck = authz?.skillReadCheck ?? false;
|
|
332
|
-
|
|
333
|
-
|
|
373
|
+
api.on("llm_input", createLlmInputHandler({
|
|
374
|
+
enabled: skillReadCheck,
|
|
375
|
+
logger: api.logger,
|
|
376
|
+
}));
|
|
334
377
|
if (skillReadCheck) {
|
|
335
|
-
api.on("llm_input", createLlmInputHandler({
|
|
336
|
-
enabled: true,
|
|
337
|
-
logger: api.logger,
|
|
338
|
-
}));
|
|
339
378
|
api.on("session_end", (_event, ctx) => {
|
|
340
379
|
if (ctx.sessionId)
|
|
341
380
|
skillPathStore.clearSessionById(ctx.sessionId);
|
|
342
381
|
});
|
|
343
382
|
}
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
383
|
+
// before_tool_call: authz, credential injection, group sender context
|
|
384
|
+
api.on("before_tool_call", createBeforeToolCallHandler({
|
|
385
|
+
storeDir,
|
|
386
|
+
identityClient: hasIdentity ? identityClient : undefined,
|
|
387
|
+
namespaceName: authz?.namespaceName ?? "default",
|
|
388
|
+
logger: api.logger,
|
|
389
|
+
sendToSession,
|
|
390
|
+
authz,
|
|
391
|
+
approvalTtlMs,
|
|
392
|
+
identityService: hasIdentity ? identityService : undefined,
|
|
393
|
+
getOidcConfigForRefresh: getOidcConfigForRefresh ?? undefined,
|
|
394
|
+
configWorkloadName: identityCfg?.workloadName,
|
|
395
|
+
}));
|
|
396
|
+
// Companion after_tool_call: restore env snapshot set by credential injection
|
|
397
|
+
api.on("after_tool_call", createAfterToolCallHandler({ logger: api.logger }));
|
|
358
398
|
}
|
|
@@ -86,7 +86,11 @@ export type ListCredentialsResult = {
|
|
|
86
86
|
hasMore: boolean;
|
|
87
87
|
totalCount?: number;
|
|
88
88
|
};
|
|
89
|
-
export
|
|
89
|
+
export type ListCredentialsFilter = {
|
|
90
|
+
name?: string;
|
|
91
|
+
flow?: string;
|
|
92
|
+
};
|
|
93
|
+
export declare function runListCredentials(deps: IdentityActionsDeps, sessionKey: string, page?: number, filter?: ListCredentialsFilter): Promise<ListCredentialsResult>;
|
|
90
94
|
export type ListTipsResult = {
|
|
91
95
|
tips: Array<{
|
|
92
96
|
sessionKey: string;
|
|
@@ -124,6 +128,8 @@ export declare function runFetch(deps: IdentityActionsDeps, sessionKey: string,
|
|
|
124
128
|
scopes?: string[];
|
|
125
129
|
deliveryTarget?: SessionKeyDeliveryTarget | null;
|
|
126
130
|
config?: OpenClawConfig;
|
|
131
|
+
/** "tool" = agent tool call, "command" = slash command. Defaults to "command". */
|
|
132
|
+
source?: "tool" | "command";
|
|
127
133
|
}): Promise<FetchResult>;
|
|
128
134
|
export type SetBindingResult = {
|
|
129
135
|
ok: boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"identity-actions.d.ts","sourceRoot":"","sources":["../../../src/actions/identity-actions.ts"],"names":[],"mappings":"AAgBA;;;GAGG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAE1D,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;AAC3E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,gCAAgC,CAAC;AAc/E,OAAO,EAKL,KAAK,eAAe,EACrB,MAAM,8BAA8B,CAAC;AAUtC,MAAM,MAAM,oBAAoB,GAAG;IACjC,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG;IAClC,IAAI,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7B,IAAI,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7B,KAAK,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;CAC/B,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,eAAe,EAAE,eAAe,CAAC;IACjC,aAAa,EAAE,MAAM,OAAO,CAAC,oBAAoB,CAAC,CAAC;IACnD,uBAAuB,CAAC,EAAE,MAAM,OAAO,CAAC,oBAAoB,CAAC,CAAC;IAC9D,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,cAAc,CAAC,EAAE,uBAAuB,CAAC;IACzC,MAAM,CAAC,EAAE,qBAAqB,CAAC;IAC/B,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,qBAAqB,CAAC,EAAE,CACtB,kBAAkB,EAAE,wBAAwB,GAAG,MAAM,EACrD,IAAI,EAAE,MAAM,KACT,OAAO,CAAC,IAAI,CAAC,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,SAAS,GAAG,aAAa,GAAG,YAAY,GAAG,QAAQ,CAAC;
|
|
1
|
+
{"version":3,"file":"identity-actions.d.ts","sourceRoot":"","sources":["../../../src/actions/identity-actions.ts"],"names":[],"mappings":"AAgBA;;;GAGG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAE1D,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;AAC3E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,gCAAgC,CAAC;AAc/E,OAAO,EAKL,KAAK,eAAe,EACrB,MAAM,8BAA8B,CAAC;AAUtC,MAAM,MAAM,oBAAoB,GAAG;IACjC,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG;IAClC,IAAI,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7B,IAAI,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7B,KAAK,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;CAC/B,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,eAAe,EAAE,eAAe,CAAC;IACjC,aAAa,EAAE,MAAM,OAAO,CAAC,oBAAoB,CAAC,CAAC;IACnD,uBAAuB,CAAC,EAAE,MAAM,OAAO,CAAC,oBAAoB,CAAC,CAAC;IAC9D,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,cAAc,CAAC,EAAE,uBAAuB,CAAC;IACzC,MAAM,CAAC,EAAE,qBAAqB,CAAC;IAC/B,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,qBAAqB,CAAC,EAAE,CACtB,kBAAkB,EAAE,wBAAwB,GAAG,MAAM,EACrD,IAAI,EAAE,MAAM,KACT,OAAO,CAAC,IAAI,CAAC,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,SAAS,GAAG,aAAa,GAAG,YAAY,GAAG,QAAQ,CAAC;AAgFhE,MAAM,MAAM,YAAY,GAAG;IACzB,QAAQ,EAAE,OAAO,CAAC;IAClB,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,MAAM,EAAE,OAAO,CAAC;IAChB,2CAA2C;IAC3C,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,wDAAwD;IACxD,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,4BAA4B;IAC5B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,uBAAuB;IACvB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,wCAAwC;IACxC,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;IAC7C,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC,CAAC;AAEF,wBAAsB,SAAS,CAC7B,IAAI,EAAE,mBAAmB,EACzB,UAAU,EAAE,MAAM,EAClB,MAAM,CAAC,EAAE,cAAc,GACtB,OAAO,CAAC,YAAY,CAAC,CAsCvB;AAED,MAAM,MAAM,WAAW,GACnB;IAAE,IAAI,EAAE,mBAAmB,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GAC1C;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACrC;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAEvC,wBAAsB,QAAQ,CAC5B,IAAI,EAAE,mBAAmB,EACzB,UAAU,EAAE,MAAM,EAClB,OAAO,CAAC,EAAE;IAAE,MAAM,CAAC,EAAE,cAAc,CAAC;IAAC,cAAc,CAAC,EAAE,wBAAwB,GAAG,IAAI,CAAA;CAAE,GACtF,OAAO,CAAC,WAAW,CAAC,CAqDtB;AAED,MAAM,MAAM,YAAY,GAAG;IAAE,EAAE,EAAE,OAAO,CAAA;CAAE,CAAC;AAE3C,wBAAsB,SAAS,CAC7B,IAAI,EAAE,mBAAmB,EACzB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,YAAY,CAAC,CASvB;AAID,MAAM,MAAM,qBAAqB,GAAG;IAClC,SAAS,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAClG,UAAU,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACtE,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG;IAClC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,wBAAsB,kBAAkB,CACtC,IAAI,EAAE,mBAAmB,EACzB,UAAU,EAAE,MAAM,EAClB,IAAI,GAAE,MAAU,EAChB,MAAM,CAAC,EAAE,qBAAqB,GAC7B,OAAO,CAAC,qBAAqB,CAAC,CAqFhC;AAED,MAAM,MAAM,cAAc,GAAG;IAC3B,IAAI,EAAE,KAAK,CAAC;QACV,UAAU,EAAE,MAAM,CAAC;QACnB,GAAG,EAAE,MAAM,CAAC;QACZ,KAAK,EAAE,MAAM,EAAE,CAAC;QAChB,SAAS,EAAE,MAAM,CAAC;QAClB,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC,CAAC;IACH,oDAAoD;IACpD,iBAAiB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;CAC3D,CAAC;AAEF,wBAAsB,WAAW,CAAC,IAAI,EAAE,mBAAmB,GAAG,OAAO,CAAC,cAAc,CAAC,CAsBpF;AAED,MAAM,MAAM,YAAY,GAAG;IACzB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACnC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACnC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACjC,CAAC;AAEF,wBAAsB,SAAS,CAAC,IAAI,EAAE,mBAAmB,GAAG,OAAO,CAAC,YAAY,CAAC,CA2ChF;AAED,MAAM,MAAM,WAAW,GACnB;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACpC;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACtD;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAEvC,wBAAsB,QAAQ,CAC5B,IAAI,EAAE,mBAAmB,EACzB,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE;IACN,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,SAAS,CAAC;IAChB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,cAAc,CAAC,EAAE,wBAAwB,GAAG,IAAI,CAAC;IACjD,MAAM,CAAC,EAAE,cAAc,CAAC;IACxB,kFAAkF;IAClF,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC7B,GACA,OAAO,CAAC,WAAW,CAAC,CA4JtB;AAED,MAAM,MAAM,gBAAgB,GAAG;IAAE,EAAE,EAAE,OAAO,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAEjF,wBAAsB,aAAa,CACjC,IAAI,EAAE,mBAAmB,EACzB,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAC3C,OAAO,CAAC,gBAAgB,CAAC,CAkC3B;AAED,MAAM,MAAM,kBAAkB,GAAG;IAAE,EAAE,EAAE,OAAO,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAEnF,wBAAsB,eAAe,CACnC,IAAI,EAAE,mBAAmB,EACzB,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,GAC3B,OAAO,CAAC,kBAAkB,CAAC,CAW7B"}
|
|
@@ -20,7 +20,7 @@ import { loadCredentialEnvBindings, loadAllCredentialEnvBindings, setCredentialE
|
|
|
20
20
|
import { loadCredentials, setCredential, getCredential, deleteCredentialsForSession, } from "../store/credential-store.js";
|
|
21
21
|
import { getSession, deleteSession } from "../store/session-store.js";
|
|
22
22
|
import { createState } from "../store/oidc-state-store.js";
|
|
23
|
-
import {
|
|
23
|
+
import { getAllTIPTokens, deleteTIPToken } from "../store/tip-store.js";
|
|
24
24
|
import { extractDelegationChainFromJwt } from "../utils/auth.js";
|
|
25
25
|
import { resolveAgentId, } from "../utils/derive-session-key.js";
|
|
26
26
|
function inferFlowFromProvider(info) {
|
|
@@ -32,6 +32,7 @@ function inferFlowFromProvider(info) {
|
|
|
32
32
|
}
|
|
33
33
|
const OAUTH_POLL_INTERVAL_MS = 2500;
|
|
34
34
|
const OAUTH_POLL_TIMEOUT_MS = 10 * 60 * 1000;
|
|
35
|
+
const OAUTH_QUICK_RETRY_MS = 1000;
|
|
35
36
|
function sleep(ms) {
|
|
36
37
|
return new Promise((r) => setTimeout(r, ms));
|
|
37
38
|
}
|
|
@@ -156,30 +157,40 @@ export async function runLogout(deps, sessionKey) {
|
|
|
156
157
|
const { storeDir, logger } = deps;
|
|
157
158
|
logDebug(logger, `logout sessionKey=${sessionKey.slice(0, 24)}...`);
|
|
158
159
|
await deleteSession(storeDir, sessionKey);
|
|
159
|
-
|
|
160
|
-
delete tokens[sessionKey];
|
|
161
|
-
await saveTIPTokens(storeDir, tokens);
|
|
160
|
+
deleteTIPToken(sessionKey);
|
|
162
161
|
deleteCredentialsForSession(storeDir, sessionKey);
|
|
163
162
|
return { ok: true };
|
|
164
163
|
}
|
|
165
164
|
const LIST_PAGE_SIZE = 10;
|
|
166
|
-
export async function runListCredentials(deps, sessionKey, page = 1) {
|
|
167
|
-
const { storeDir, identityClient, logger } = deps;
|
|
165
|
+
export async function runListCredentials(deps, sessionKey, page = 1, filter) {
|
|
166
|
+
const { storeDir, identityClient, identityService, logger } = deps;
|
|
168
167
|
const creds = await loadCredentials(storeDir, sessionKey);
|
|
169
168
|
const bindings = await loadCredentialEnvBindings(storeDir, sessionKey);
|
|
170
169
|
let providers = [];
|
|
171
170
|
let totalCount = 0;
|
|
172
171
|
if (identityClient) {
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
PageSize: LIST_PAGE_SIZE,
|
|
177
|
-
});
|
|
178
|
-
providers = result.CredentialProviders ?? result.Data ?? [];
|
|
179
|
-
totalCount = result.TotalCount ?? 0;
|
|
172
|
+
const session = await getSession(storeDir, sessionKey);
|
|
173
|
+
if (!session || !identityService.parseUserToken(session.userToken).valid) {
|
|
174
|
+
logWarn(logger, `list-credentials: no valid session for key=${sessionKey.slice(0, 24)}...`);
|
|
180
175
|
}
|
|
181
|
-
|
|
182
|
-
|
|
176
|
+
else {
|
|
177
|
+
try {
|
|
178
|
+
const apiFilter = {};
|
|
179
|
+
if (filter?.name)
|
|
180
|
+
apiFilter.Name = filter.name;
|
|
181
|
+
if (filter?.flow)
|
|
182
|
+
apiFilter.Flow = filter.flow;
|
|
183
|
+
const result = await identityClient.listCredentialProviders({
|
|
184
|
+
PageNumber: page,
|
|
185
|
+
PageSize: LIST_PAGE_SIZE,
|
|
186
|
+
...(Object.keys(apiFilter).length > 0 ? { Filter: apiFilter } : {}),
|
|
187
|
+
});
|
|
188
|
+
providers = result.CredentialProviders ?? result.Data ?? [];
|
|
189
|
+
totalCount = result.TotalCount ?? 0;
|
|
190
|
+
}
|
|
191
|
+
catch (e) {
|
|
192
|
+
logWarn(logger, `list-credentials API error: ${String(e)}`);
|
|
193
|
+
}
|
|
183
194
|
}
|
|
184
195
|
}
|
|
185
196
|
const providerNames = new Set(providers.map((p) => p.Name));
|
|
@@ -232,7 +243,7 @@ export async function runListCredentials(deps, sessionKey, page = 1) {
|
|
|
232
243
|
}
|
|
233
244
|
export async function runListTips(deps) {
|
|
234
245
|
const { storeDir } = deps;
|
|
235
|
-
const tokens =
|
|
246
|
+
const tokens = getAllTIPTokens();
|
|
236
247
|
const bindingsBySession = await loadAllCredentialEnvBindings(storeDir);
|
|
237
248
|
const now = Date.now();
|
|
238
249
|
const tips = [];
|
|
@@ -292,27 +303,10 @@ export async function runConfig(deps) {
|
|
|
292
303
|
}
|
|
293
304
|
export async function runFetch(deps, sessionKey, params) {
|
|
294
305
|
const { identityClient, storeDir, sendCredentialMessage, logger } = deps;
|
|
295
|
-
const { provider, flow, flowExplicit, redirectUrl, scopes, deliveryTarget, config } = params;
|
|
306
|
+
const { provider, flow, flowExplicit, redirectUrl, scopes, deliveryTarget, config, source = "command" } = params;
|
|
296
307
|
if (!identityClient) {
|
|
297
308
|
return { kind: "error", message: "Identity service not configured. Cannot add credentials." };
|
|
298
309
|
}
|
|
299
|
-
let effectiveFlow = flow;
|
|
300
|
-
if (!flowExplicit) {
|
|
301
|
-
try {
|
|
302
|
-
const listResult = await identityClient.listCredentialProviders({
|
|
303
|
-
PageNumber: 1,
|
|
304
|
-
PageSize: 20,
|
|
305
|
-
Filter: { Name: provider },
|
|
306
|
-
});
|
|
307
|
-
const list = listResult.CredentialProviders ?? listResult.Data ?? [];
|
|
308
|
-
const info = list.find((p) => p.Name === provider);
|
|
309
|
-
if (info)
|
|
310
|
-
effectiveFlow = inferFlowFromProvider(info);
|
|
311
|
-
}
|
|
312
|
-
catch {
|
|
313
|
-
// keep default
|
|
314
|
-
}
|
|
315
|
-
}
|
|
316
310
|
const ctxAgentId = resolveAgentId({ sessionKey, config: config });
|
|
317
311
|
const tipRefreshOptions = deps.getOidcConfigForRefresh
|
|
318
312
|
? {
|
|
@@ -330,6 +324,23 @@ export async function runFetch(deps, sessionKey, params) {
|
|
|
330
324
|
message: "Login first with `/identity login` to establish identity before adding credentials.",
|
|
331
325
|
};
|
|
332
326
|
}
|
|
327
|
+
let effectiveFlow = flow;
|
|
328
|
+
if (!flowExplicit) {
|
|
329
|
+
try {
|
|
330
|
+
const listResult = await identityClient.listCredentialProviders({
|
|
331
|
+
PageNumber: 1,
|
|
332
|
+
PageSize: 20,
|
|
333
|
+
Filter: { Name: provider },
|
|
334
|
+
});
|
|
335
|
+
const list = listResult.CredentialProviders ?? listResult.Data ?? [];
|
|
336
|
+
const info = list.find((p) => p.Name === provider);
|
|
337
|
+
if (info)
|
|
338
|
+
effectiveFlow = inferFlowFromProvider(info);
|
|
339
|
+
}
|
|
340
|
+
catch {
|
|
341
|
+
// keep default
|
|
342
|
+
}
|
|
343
|
+
}
|
|
333
344
|
try {
|
|
334
345
|
if (effectiveFlow === "apikey") {
|
|
335
346
|
const result = await identityClient.getResourceApiKey({
|
|
@@ -361,6 +372,43 @@ export async function runFetch(deps, sessionKey, params) {
|
|
|
361
372
|
return { kind: "success", message: `✓ Credential for \`${provider}\` added (direct token).` };
|
|
362
373
|
}
|
|
363
374
|
if (oauthResult.authorizationUrl) {
|
|
375
|
+
// Quick retry: the server may have a cached token that wasn't ready on
|
|
376
|
+
// the first call (e.g. user previously authorized). A short pause then
|
|
377
|
+
// re-check avoids unnecessary polling / returning authUrl to the user.
|
|
378
|
+
await sleep(OAUTH_QUICK_RETRY_MS);
|
|
379
|
+
try {
|
|
380
|
+
const retry = await identityClient.getResourceOauth2Token({
|
|
381
|
+
providerName: provider,
|
|
382
|
+
identityToken: tip.token,
|
|
383
|
+
flow: oauth2Flow,
|
|
384
|
+
redirectUrl,
|
|
385
|
+
scopes: scopes?.length ? scopes : undefined,
|
|
386
|
+
});
|
|
387
|
+
if (retry.accessToken) {
|
|
388
|
+
await setCredential(storeDir, sessionKey, provider, {
|
|
389
|
+
type: "oauth2",
|
|
390
|
+
status: "authenticated",
|
|
391
|
+
accessToken: retry.accessToken,
|
|
392
|
+
expiresAt: Date.now() + 3600 * 1000,
|
|
393
|
+
});
|
|
394
|
+
return { kind: "success", message: `✓ Credential for \`${provider}\` added (cached token).` };
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
catch {
|
|
398
|
+
// quick retry failed — proceed with authUrl flow
|
|
399
|
+
}
|
|
400
|
+
if (source === "tool") {
|
|
401
|
+
// Agent tool context: return authUrl for the agent to display.
|
|
402
|
+
// No background polling — the agent should re-call identity_fetch
|
|
403
|
+
// after the user completes authorization in the browser.
|
|
404
|
+
logInfo(logger, `fetch returning auth URL for provider=${provider} (tool, no poll)`);
|
|
405
|
+
return {
|
|
406
|
+
kind: "auth_url",
|
|
407
|
+
authUrl: oauthResult.authorizationUrl,
|
|
408
|
+
message: `Open this URL to authorize \`${provider}\`. After you complete authorization in the browser, tell me and I will fetch the credential.`,
|
|
409
|
+
};
|
|
410
|
+
}
|
|
411
|
+
// Slash command context: start background polling and notify via channel message.
|
|
364
412
|
logInfo(logger, `fetch returning auth URL for provider=${provider}, starting poll`);
|
|
365
413
|
const target = deliveryTarget ?? sessionKey;
|
|
366
414
|
pollOAuthAndNotify({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"identity-commands.d.ts","sourceRoot":"","sources":["../../../src/commands/identity-commands.ts"],"names":[],"mappings":"AAgBA;;;GAGG;AAEH,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AACxD,OAAO,EAUL,KAAK,mBAAmB,EACxB,KAAK,oBAAoB,EACzB,KAAK,SAAS,EACf,MAAM,gCAAgC,CAAC;
|
|
1
|
+
{"version":3,"file":"identity-commands.d.ts","sourceRoot":"","sources":["../../../src/commands/identity-commands.ts"],"names":[],"mappings":"AAgBA;;;GAGG;AAEH,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AACxD,OAAO,EAUL,KAAK,mBAAmB,EACxB,KAAK,oBAAoB,EACzB,KAAK,SAAS,EACf,MAAM,gCAAgC,CAAC;AAYxC,YAAY,EAAE,oBAAoB,EAAE,SAAS,EAAE,CAAC;AAEhD,MAAM,MAAM,sBAAsB,GAAG;IACnC,IAAI,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7B,IAAI,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7B,KAAK,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;CAC/B,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG,mBAAmB,CAAC;AAyoBvD,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,oBAAoB;;;;;mBAlf3C,oBAAoB,KAAG,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;EA2fpE;AAED,0CAA0C;AAC1C,wBAAgB,eAAe,CAAC,IAAI,EAAE,oBAAoB;;;;;mBA9frC,oBAAoB,KAAG,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;EAugBpE"}
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
*/
|
|
16
16
|
import { runStatus, runLogin, runLogout, runListCredentials, runListTips, runConfig, runFetch, runSetBinding, runUnsetBinding, } from "../actions/identity-actions.js";
|
|
17
17
|
import { deriveSessionKey, deriveDeliveryTargetFromContext, } from "../utils/derive-session-key.js";
|
|
18
|
+
import { buildEffectiveSessionKey } from "../store/group-sender-store.js";
|
|
18
19
|
import { logDebug } from "../utils/logger.js";
|
|
19
20
|
import { diagnoseRisk } from "../risk/diagnose-risk.js";
|
|
20
21
|
import { getRiskPatterns } from "../risk/classify-risk.js";
|
|
@@ -87,7 +88,7 @@ function parseSubcommand(args) {
|
|
|
87
88
|
rest: raw.slice(space + 1).trim(),
|
|
88
89
|
};
|
|
89
90
|
}
|
|
90
|
-
/** Parse list args: optional page. E.g. "list", "list 2", "list --
|
|
91
|
+
/** Parse list args: optional page and filters. E.g. "list", "list 2", "list --name=github --flow=M2M". */
|
|
91
92
|
function parseListArgs(rest) {
|
|
92
93
|
const parts = rest.split(/\s+/).filter(Boolean);
|
|
93
94
|
const flags = {};
|
|
@@ -103,7 +104,11 @@ function parseListArgs(rest) {
|
|
|
103
104
|
}
|
|
104
105
|
}
|
|
105
106
|
const page = flags.page ? parseInt(flags.page, 10) : positional[0];
|
|
106
|
-
return {
|
|
107
|
+
return {
|
|
108
|
+
page: Number.isFinite(page) && page >= 1 ? page : 1,
|
|
109
|
+
name: flags.name || undefined,
|
|
110
|
+
flow: flags.flow || undefined,
|
|
111
|
+
};
|
|
107
112
|
}
|
|
108
113
|
/** Parse fetch args: provider and flags (--flow, --redirectUrl, --scopes). flow can be omitted to auto-infer from provider. */
|
|
109
114
|
function parseFetchArgs(rest) {
|
|
@@ -155,7 +160,7 @@ function createIdentityHandler(deps) {
|
|
|
155
160
|
return async (ctx) => {
|
|
156
161
|
const { sub, rest } = parseSubcommand(ctx.args);
|
|
157
162
|
logDebug(logger, `command sub=${sub} rest=${rest.slice(0, 40)}...`);
|
|
158
|
-
const
|
|
163
|
+
const baseSessionKey = deriveSessionKey({
|
|
159
164
|
channel: ctx.channel,
|
|
160
165
|
senderId: ctx.senderId,
|
|
161
166
|
from: ctx.from,
|
|
@@ -163,6 +168,9 @@ function createIdentityHandler(deps) {
|
|
|
163
168
|
accountId: ctx.accountId,
|
|
164
169
|
config: ctx.config,
|
|
165
170
|
});
|
|
171
|
+
const sessionKey = baseSessionKey
|
|
172
|
+
? buildEffectiveSessionKey(baseSessionKey, ctx.senderId)
|
|
173
|
+
: null;
|
|
166
174
|
const needsSession = [
|
|
167
175
|
"login",
|
|
168
176
|
"logout",
|
|
@@ -327,8 +335,9 @@ async function handleLogout(deps, sessionKey) {
|
|
|
327
335
|
return { text: "✓ Logged out." };
|
|
328
336
|
}
|
|
329
337
|
async function handleListCredentials(deps, sessionKey, rest) {
|
|
330
|
-
const { page } = parseListArgs(rest);
|
|
331
|
-
const
|
|
338
|
+
const { page, name, flow } = parseListArgs(rest);
|
|
339
|
+
const filter = name || flow ? { name, flow } : undefined;
|
|
340
|
+
const result = await runListCredentials(deps, sessionKey, page, filter);
|
|
332
341
|
const lines = [];
|
|
333
342
|
if (result.providers.length > 0) {
|
|
334
343
|
lines.push(`**Available (page ${result.page}):**`);
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type PluginLogger } from "../utils/logger.js";
|
|
2
|
+
export type AfterToolCallDeps = {
|
|
3
|
+
logger?: PluginLogger;
|
|
4
|
+
};
|
|
5
|
+
export declare function createAfterToolCallHandler(deps: AfterToolCallDeps): (event: {
|
|
6
|
+
toolName: string;
|
|
7
|
+
runId?: string;
|
|
8
|
+
toolCallId?: string;
|
|
9
|
+
}, _ctx: {
|
|
10
|
+
sessionKey?: string;
|
|
11
|
+
}) => void;
|
|
12
|
+
//# sourceMappingURL=after-tool-call.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"after-tool-call.d.ts","sourceRoot":"","sources":["../../../src/hooks/after-tool-call.ts"],"names":[],"mappings":"AAsBA,OAAO,EAAY,KAAK,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAEjE,MAAM,MAAM,iBAAiB,GAAG;IAC9B,MAAM,CAAC,EAAE,YAAY,CAAC;CACvB,CAAC;AAEF,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,iBAAiB,IAI9D,OAAO;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,EAChE,MAAM;IAAE,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,KAC5B,IAAI,CASR"}
|
|
@@ -0,0 +1,31 @@
|
|
|
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
|
+
/**
|
|
17
|
+
* after_tool_call hook: restore process.env snapshot and release per-key locks
|
|
18
|
+
* set by before_tool_call credential injection.
|
|
19
|
+
*/
|
|
20
|
+
import { hasSnapshot, restoreEnvSnapshot } from "../store/credential-env-snapshot.js";
|
|
21
|
+
import { logDebug } from "../utils/logger.js";
|
|
22
|
+
export function createAfterToolCallHandler(deps) {
|
|
23
|
+
const { logger } = deps;
|
|
24
|
+
return (event, _ctx) => {
|
|
25
|
+
if (!hasSnapshot(event.runId, event.toolCallId))
|
|
26
|
+
return;
|
|
27
|
+
logDebug(logger, `restoring env snapshot for tool=${event.toolName} ` +
|
|
28
|
+
`run=${event.runId ?? "?"} toolCallId=${event.toolCallId ?? "?"}`);
|
|
29
|
+
restoreEnvSnapshot(event.runId, event.toolCallId);
|
|
30
|
+
};
|
|
31
|
+
}
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* before_agent_start hook: fetch TIP token for main agent only.
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* 3. Main: getOrRefreshTIPToken (fetches TIP, refreshes userToken if expired)
|
|
3
|
+
* Credential env injection is handled per-tool-call in before_tool_call
|
|
4
|
+
* to avoid process.env race conditions between concurrent runs.
|
|
6
5
|
*/
|
|
7
6
|
import type { IdentityService } from "../services/identity-service.js";
|
|
8
7
|
import type { OIDCConfigForRefresh } from "../services/session-refresh.js";
|
|
@@ -13,6 +12,7 @@ export type BeforeAgentStartDeps = {
|
|
|
13
12
|
getOidcConfigForRefresh?: () => Promise<OIDCConfigForRefresh>;
|
|
14
13
|
logger: {
|
|
15
14
|
info?: (msg: string) => void;
|
|
15
|
+
debug?: (msg: string) => void;
|
|
16
16
|
warn?: (msg: string) => void;
|
|
17
17
|
};
|
|
18
18
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"before-agent-start.d.ts","sourceRoot":"","sources":["../../../src/hooks/before-agent-start.ts"],"names":[],"mappings":"AAgBA
|
|
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"}
|