@cjhyy/code-shell-core 0.6.0-rc.9 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/THIRD_PARTY_NOTICES.md +206 -0
- package/dist/automation/scheduler.d.ts +13 -7
- package/dist/automation/scheduler.js +116 -37
- package/dist/capability-control/service.d.ts +2 -0
- package/dist/capability-control/service.js +4 -2
- package/dist/cc-orchestrator/agent-adapter.d.ts +4 -0
- package/dist/cc-orchestrator/agent-adapter.js +11 -1
- package/dist/cc-orchestrator/codex-session-history.d.ts +14 -1
- package/dist/cc-orchestrator/codex-session-history.js +65 -5
- package/dist/cc-orchestrator/cwd-normalize.d.ts +2 -0
- package/dist/cc-orchestrator/cwd-normalize.js +19 -0
- package/dist/cc-orchestrator/external-agent-bindings.d.ts +27 -0
- package/dist/cc-orchestrator/external-agent-bindings.js +150 -0
- package/dist/cc-orchestrator/external-agent-changes.js +22 -5
- package/dist/cc-orchestrator/external-agent-driver.d.ts +1 -0
- package/dist/cc-orchestrator/external-agent-driver.js +265 -50
- package/dist/cc-orchestrator/external-agent-session-store.d.ts +23 -0
- package/dist/cc-orchestrator/external-agent-session-store.js +146 -0
- package/dist/cc-orchestrator/session-history.d.ts +35 -0
- package/dist/cc-orchestrator/session-history.js +98 -15
- package/dist/cli/agent-server-stdio.js +9 -2
- package/dist/context/compaction.d.ts +8 -1
- package/dist/context/compaction.js +49 -4
- package/dist/context/manager.d.ts +16 -2
- package/dist/context/manager.js +103 -19
- package/dist/credentials/access.d.ts +57 -0
- package/dist/credentials/access.js +185 -0
- package/dist/credentials/index.d.ts +3 -1
- package/dist/credentials/index.js +2 -0
- package/dist/credentials/inject-credential-tool.d.ts +3 -1
- package/dist/credentials/inject-credential-tool.js +30 -11
- package/dist/credentials/oauth.d.ts +20 -0
- package/dist/credentials/oauth.js +114 -0
- package/dist/credentials/store.d.ts +1 -0
- package/dist/credentials/store.js +3 -1
- package/dist/credentials/types.d.ts +49 -3
- package/dist/credentials/use-credential-tool.d.ts +9 -1
- package/dist/credentials/use-credential-tool.js +58 -45
- package/dist/engine/engine.d.ts +23 -3
- package/dist/engine/engine.js +380 -255
- package/dist/engine/goal.d.ts +17 -0
- package/dist/engine/goal.js +16 -6
- package/dist/engine/image-policy.d.ts +6 -0
- package/dist/engine/image-policy.js +17 -6
- package/dist/engine/input-attachments.d.ts +13 -0
- package/dist/engine/input-attachments.js +398 -0
- package/dist/engine/model-facade.d.ts +5 -2
- package/dist/engine/model-facade.js +4 -4
- package/dist/engine/parse-task.d.ts +10 -0
- package/dist/engine/parse-task.js +5 -0
- package/dist/engine/run-image-input.d.ts +22 -0
- package/dist/engine/run-image-input.js +195 -0
- package/dist/engine/steer-queue.d.ts +3 -1
- package/dist/engine/steer-queue.js +10 -2
- package/dist/engine/streaming-tool-queue.d.ts +11 -7
- package/dist/engine/streaming-tool-queue.js +11 -7
- package/dist/engine/turn-loop.d.ts +37 -2
- package/dist/engine/turn-loop.js +228 -43
- package/dist/engine/types.d.ts +8 -0
- package/dist/git/worktree/crud.d.ts +69 -0
- package/dist/git/worktree/crud.js +206 -0
- package/dist/git/worktree/diff.d.ts +14 -0
- package/dist/git/worktree/diff.js +82 -0
- package/dist/git/worktree/git-exec.d.ts +7 -0
- package/dist/git/worktree/git-exec.js +51 -0
- package/dist/git/worktree/index.d.ts +5 -0
- package/dist/git/worktree/index.js +5 -0
- package/dist/git/worktree/query.d.ts +42 -0
- package/dist/git/worktree/query.js +121 -0
- package/dist/git/worktree/slug.d.ts +11 -0
- package/dist/git/worktree/slug.js +58 -0
- package/dist/git/worktree.d.ts +1 -84
- package/dist/git/worktree.js +5 -230
- package/dist/hooks/goal-stop-hook.d.ts +33 -1
- package/dist/hooks/goal-stop-hook.js +202 -34
- package/dist/index.d.ts +31 -28
- package/dist/index.js +27 -25
- package/dist/logging/logger.js +6 -6
- package/dist/logging/sanitize-messages.d.ts +10 -2
- package/dist/logging/sanitize-messages.js +21 -6
- package/dist/plugins/installer/checkUpdate.d.ts +4 -1
- package/dist/plugins/installer/checkUpdate.js +4 -2
- package/dist/plugins/installer/install.js +2 -0
- package/dist/plugins/installer/installFromSource.js +9 -1
- package/dist/plugins/installer/parseSource.d.ts +4 -1
- package/dist/plugins/installer/parseSource.js +28 -10
- package/dist/plugins/installer/sourcePath.d.ts +9 -0
- package/dist/plugins/installer/sourcePath.js +50 -0
- package/dist/plugins/installer/update.d.ts +4 -1
- package/dist/plugins/installer/update.js +5 -3
- package/dist/plugins/parseMarketplaceInput.d.ts +4 -1
- package/dist/plugins/parseMarketplaceInput.js +4 -3
- package/dist/plugins/pluginInstaller.js +24 -22
- package/dist/preset/index.d.ts +1 -0
- package/dist/preset/index.js +30 -13
- package/dist/prompt/sections/base.md +1 -1
- package/dist/protocol/chat-session-manager.d.ts +2 -0
- package/dist/protocol/chat-session-manager.js +38 -2
- package/dist/protocol/chat-session.d.ts +3 -0
- package/dist/protocol/chat-session.js +1 -0
- package/dist/protocol/client.d.ts +9 -4
- package/dist/protocol/client.js +18 -1
- package/dist/protocol/server.d.ts +30 -0
- package/dist/protocol/server.js +247 -47
- package/dist/protocol/types.d.ts +49 -0
- package/dist/protocol/types.js +6 -0
- package/dist/run/FileRunStore.js +10 -1
- package/dist/run/Heartbeat.js +12 -0
- package/dist/run/RunApprovalBackend.d.ts +3 -0
- package/dist/run/RunApprovalBackend.js +41 -6
- package/dist/run/RunLock.js +2 -0
- package/dist/run/RunManager.d.ts +2 -0
- package/dist/run/RunManager.js +64 -24
- package/dist/run/ids.d.ts +2 -0
- package/dist/run/ids.js +23 -0
- package/dist/runtime/background-shell.d.ts +1 -0
- package/dist/runtime/background-shell.js +23 -13
- package/dist/runtime/spawn-common.js +10 -0
- package/dist/services/auto-dream.d.ts +15 -4
- package/dist/services/auto-dream.js +20 -20
- package/dist/services/dream-consolidation.d.ts +2 -3
- package/dist/services/dream-consolidation.js +65 -15
- package/dist/services/extract-memories.d.ts +14 -5
- package/dist/services/extract-memories.js +20 -3
- package/dist/services/global-dream-promotion.d.ts +23 -0
- package/dist/services/global-dream-promotion.js +112 -0
- package/dist/services/memory-orchestrator.js +347 -34
- package/dist/session/memory.d.ts +61 -18
- package/dist/session/memory.js +342 -79
- package/dist/session/session-manager.d.ts +35 -1
- package/dist/session/session-manager.js +224 -4
- package/dist/session/transcript.d.ts +1 -1
- package/dist/session/transcript.js +17 -5
- package/dist/settings/manager.d.ts +1 -0
- package/dist/settings/manager.js +87 -37
- package/dist/settings/schema-export.d.ts +2 -3
- package/dist/settings/schema-export.js +2 -3
- package/dist/settings/schema.d.ts +21 -0
- package/dist/settings/schema.js +12 -0
- package/dist/skills/scanner.d.ts +3 -2
- package/dist/skills/scanner.js +12 -9
- package/dist/tool-system/builtin/agent-notifications.d.ts +11 -4
- package/dist/tool-system/builtin/agent-notifications.js +19 -7
- package/dist/tool-system/builtin/background-jobs.d.ts +35 -6
- package/dist/tool-system/builtin/background-jobs.js +116 -7
- package/dist/tool-system/builtin/background-work.d.ts +17 -18
- package/dist/tool-system/builtin/background-work.js +51 -5
- package/dist/tool-system/builtin/config.d.ts +2 -1
- package/dist/tool-system/builtin/config.js +16 -11
- package/dist/tool-system/builtin/cron-list.definition.d.ts +3 -0
- package/dist/tool-system/builtin/cron-list.definition.js +6 -0
- package/dist/tool-system/builtin/cron.d.ts +1 -2
- package/dist/tool-system/builtin/cron.js +9 -7
- package/dist/tool-system/builtin/drive-claude-code.d.ts +23 -2
- package/dist/tool-system/builtin/drive-claude-code.js +589 -48
- package/dist/tool-system/builtin/edit.js +5 -2
- package/dist/tool-system/builtin/generate-video.d.ts +1 -0
- package/dist/tool-system/builtin/generate-video.js +13 -4
- package/dist/tool-system/builtin/index.d.ts +8 -3
- package/dist/tool-system/builtin/index.js +50 -22
- package/dist/tool-system/builtin/lsp.d.ts +2 -1
- package/dist/tool-system/builtin/lsp.js +6 -3
- package/dist/tool-system/builtin/memory.js +40 -8
- package/dist/tool-system/builtin/notebook-edit.js +5 -2
- package/dist/tool-system/builtin/powershell.d.ts +5 -2
- package/dist/tool-system/builtin/powershell.js +11 -7
- package/dist/tool-system/builtin/read.js +118 -6
- package/dist/tool-system/builtin/sleep.d.ts +1 -2
- package/dist/tool-system/builtin/sleep.definition.d.ts +8 -0
- package/dist/tool-system/builtin/sleep.definition.js +28 -0
- package/dist/tool-system/builtin/sleep.js +1 -22
- package/dist/tool-system/builtin/view-image.d.ts +2 -2
- package/dist/tool-system/builtin/view-image.js +109 -19
- package/dist/tool-system/builtin/worktree.d.ts +4 -4
- package/dist/tool-system/builtin/worktree.js +297 -74
- package/dist/tool-system/builtin/write.js +5 -3
- package/dist/tool-system/context.d.ts +41 -1
- package/dist/tool-system/executor.d.ts +1 -5
- package/dist/tool-system/executor.js +94 -115
- package/dist/tool-system/mcp-manager.d.ts +31 -6
- package/dist/tool-system/mcp-manager.js +193 -78
- package/dist/tool-system/path-policy.d.ts +2 -0
- package/dist/tool-system/path-policy.js +41 -12
- package/dist/tool-system/permission.d.ts +28 -7
- package/dist/tool-system/permission.js +130 -49
- package/dist/tool-system/registry.js +11 -4
- package/dist/tool-system/tool-result-redaction.d.ts +7 -0
- package/dist/tool-system/tool-result-redaction.js +48 -0
- package/dist/tool-system/workspace-bridge.d.ts +11 -0
- package/dist/tool-system/workspace-bridge.js +1 -0
- package/dist/types.d.ts +78 -11
- package/dist/utils/toolDisplay.js +1 -1
- package/package.json +4 -3
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
import { existsSync, readdirSync, rmSync, statSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { randomUUID } from "node:crypto";
|
|
3
|
+
import { tmpdir } from "node:os";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
import { CredentialStore } from "./store.js";
|
|
6
|
+
import { formatNetscapeCookies, parseCookieJar } from "./cookie-jar.js";
|
|
7
|
+
import { summarizeOAuthCredentialSecret } from "./oauth.js";
|
|
8
|
+
const COOKIE_FILE_PREFIX = "codeshell-cred-cookie-";
|
|
9
|
+
const COOKIE_FILE_MAX_AGE_MS = 30 * 60 * 1000;
|
|
10
|
+
let defaultCredentialAccess = null;
|
|
11
|
+
export function setDefaultCredentialAccess(access) {
|
|
12
|
+
defaultCredentialAccess = access ?? null;
|
|
13
|
+
}
|
|
14
|
+
export function getCredentialAccess() {
|
|
15
|
+
return defaultCredentialAccess ?? localCredentialAccess;
|
|
16
|
+
}
|
|
17
|
+
export function createIpcCredentialAccess(transport) {
|
|
18
|
+
let snapshot = { revision: 0, entries: [] };
|
|
19
|
+
let nextId = 1;
|
|
20
|
+
const pending = new Map();
|
|
21
|
+
transport.onMessage((msg) => {
|
|
22
|
+
if ("method" in msg && msg.method === "desktop/credentialSnapshot") {
|
|
23
|
+
const params = msg.params;
|
|
24
|
+
if (params && typeof params.revision === "number" && Array.isArray(params.entries)) {
|
|
25
|
+
snapshot = {
|
|
26
|
+
revision: params.revision,
|
|
27
|
+
entries: params.entries,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
if (!("id" in msg) || "method" in msg)
|
|
33
|
+
return;
|
|
34
|
+
const id = String(msg.id);
|
|
35
|
+
const waiter = pending.get(id);
|
|
36
|
+
if (!waiter)
|
|
37
|
+
return;
|
|
38
|
+
pending.delete(id);
|
|
39
|
+
clearTimeout(waiter.timer);
|
|
40
|
+
if ("error" in msg && msg.error) {
|
|
41
|
+
waiter.reject(new Error(msg.error.message));
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
waiter.resolve(msg.result);
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
const request = (method, params) => {
|
|
48
|
+
const id = `cred-${nextId++}`;
|
|
49
|
+
return new Promise((resolve, reject) => {
|
|
50
|
+
const timer = setTimeout(() => {
|
|
51
|
+
pending.delete(id);
|
|
52
|
+
reject(new Error(`${method} timed out`));
|
|
53
|
+
}, 30_000);
|
|
54
|
+
pending.set(id, { resolve, reject, timer });
|
|
55
|
+
transport.send({ jsonrpc: "2.0", id, method, params });
|
|
56
|
+
});
|
|
57
|
+
};
|
|
58
|
+
const entryFor = (cwd) => {
|
|
59
|
+
const key = cwd ?? "";
|
|
60
|
+
return snapshot.entries.find((entry) => (entry.cwd ?? "") === key);
|
|
61
|
+
};
|
|
62
|
+
return {
|
|
63
|
+
listMasked(cwd, scope) {
|
|
64
|
+
const entry = entryFor(cwd);
|
|
65
|
+
if (!entry)
|
|
66
|
+
return [];
|
|
67
|
+
return scope === "project" ? cloneMetadata(entry.project) : cloneMetadata(entry.full);
|
|
68
|
+
},
|
|
69
|
+
resolveMeta(cwd, id, scope) {
|
|
70
|
+
const entry = entryFor(cwd);
|
|
71
|
+
if (!entry)
|
|
72
|
+
return undefined;
|
|
73
|
+
const list = scope === "project" ? entry.project : entry.full;
|
|
74
|
+
return cloneMetadata(list).find((cred) => cred.id === id);
|
|
75
|
+
},
|
|
76
|
+
envExposures(cwd, scope) {
|
|
77
|
+
const entry = entryFor(cwd);
|
|
78
|
+
if (!entry)
|
|
79
|
+
return {};
|
|
80
|
+
return { ...(scope === "project" ? entry.envProject : entry.envFull) };
|
|
81
|
+
},
|
|
82
|
+
async resolveValue(req) {
|
|
83
|
+
const result = (await request("desktop/credentialResolve", req));
|
|
84
|
+
if (typeof result?.value !== "string")
|
|
85
|
+
throw new Error(`credential "${req.id}" is unavailable`);
|
|
86
|
+
return result.value;
|
|
87
|
+
},
|
|
88
|
+
async materializeCookie(req) {
|
|
89
|
+
const result = (await request("desktop/credentialMaterializeCookie", req));
|
|
90
|
+
if (typeof result?.cookiesFile !== "string" || typeof result.count !== "number") {
|
|
91
|
+
throw new Error(`cookie credential "${req.id}" is unavailable`);
|
|
92
|
+
}
|
|
93
|
+
return { cookiesFile: result.cookiesFile, count: result.count };
|
|
94
|
+
},
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
export function credentialAccessScope(scope) {
|
|
98
|
+
return scope === "full" || scope === undefined ? "full" : "project";
|
|
99
|
+
}
|
|
100
|
+
export function isCredentialSecretAvailable(secret) {
|
|
101
|
+
return typeof secret === "string" && secret.length > 0 && !secret.startsWith("enc:");
|
|
102
|
+
}
|
|
103
|
+
function toMetadata(cred) {
|
|
104
|
+
const secret = cred.secret;
|
|
105
|
+
const available = isCredentialSecretAvailable(secret);
|
|
106
|
+
const { secret: _secret, ...rest } = cred;
|
|
107
|
+
return {
|
|
108
|
+
...rest,
|
|
109
|
+
hasSecret: available,
|
|
110
|
+
secretHint: available ? (secret.length > 4 ? `****${secret.slice(-4)}` : "****") : undefined,
|
|
111
|
+
...(cred.type === "oauth" ? { oauthStatus: summarizeOAuthCredentialSecret(secret) } : {}),
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
function cloneMetadata(list) {
|
|
115
|
+
return list.map((cred) => ({ ...cred, meta: cred.meta ? { ...cred.meta } : undefined }));
|
|
116
|
+
}
|
|
117
|
+
function storeFor(cwd) {
|
|
118
|
+
return new CredentialStore(cwd);
|
|
119
|
+
}
|
|
120
|
+
export const localCredentialAccess = {
|
|
121
|
+
listMasked(cwd, scope) {
|
|
122
|
+
return storeFor(cwd).list(scope).map(toMetadata);
|
|
123
|
+
},
|
|
124
|
+
resolveMeta(cwd, id, scope) {
|
|
125
|
+
const cred = storeFor(cwd).resolve(id, scope);
|
|
126
|
+
return cred ? toMetadata(cred) : undefined;
|
|
127
|
+
},
|
|
128
|
+
envExposures(cwd, scope) {
|
|
129
|
+
const out = {};
|
|
130
|
+
const creds = storeFor(cwd).list(scope);
|
|
131
|
+
for (const cred of creds) {
|
|
132
|
+
const name = cred.exposeAsEnv?.trim();
|
|
133
|
+
if (name && isCredentialSecretAvailable(cred.secret))
|
|
134
|
+
out[name] = cred.secret;
|
|
135
|
+
}
|
|
136
|
+
return out;
|
|
137
|
+
},
|
|
138
|
+
async resolveValue(req) {
|
|
139
|
+
const cred = storeFor(req.cwd).resolve(req.id, req.scope);
|
|
140
|
+
if (!cred || !isCredentialSecretAvailable(cred.secret)) {
|
|
141
|
+
throw new Error(`credential "${req.id}" is unavailable`);
|
|
142
|
+
}
|
|
143
|
+
return cred.secret;
|
|
144
|
+
},
|
|
145
|
+
async materializeCookie(req) {
|
|
146
|
+
const cred = storeFor(req.cwd).resolve(req.id, req.scope);
|
|
147
|
+
if (!cred || cred.type !== "cookie" || !isCredentialSecretAvailable(cred.secret)) {
|
|
148
|
+
throw new Error(`cookie credential "${req.id}" is unavailable`);
|
|
149
|
+
}
|
|
150
|
+
return materializeCookieSecret(cred.id, cred.secret);
|
|
151
|
+
},
|
|
152
|
+
};
|
|
153
|
+
export function materializeCookieSecret(credentialId, secret) {
|
|
154
|
+
const jar = parseCookieJar(secret);
|
|
155
|
+
if (jar.length === 0)
|
|
156
|
+
throw new Error("cookie jar is empty or invalid");
|
|
157
|
+
const file = join(tmpdir(), `${COOKIE_FILE_PREFIX}${safeFileName(credentialId)}-${process.pid}-${randomUUID()}.txt`);
|
|
158
|
+
writeFileSync(file, formatNetscapeCookies(jar), { mode: 0o600 });
|
|
159
|
+
return { cookiesFile: file, count: jar.length };
|
|
160
|
+
}
|
|
161
|
+
export function sweepStaleCredentialCookieFiles(now = Date.now()) {
|
|
162
|
+
const dir = tmpdir();
|
|
163
|
+
try {
|
|
164
|
+
if (!existsSync(dir))
|
|
165
|
+
return;
|
|
166
|
+
for (const f of readdirSync(dir)) {
|
|
167
|
+
if (!f.startsWith(COOKIE_FILE_PREFIX))
|
|
168
|
+
continue;
|
|
169
|
+
const p = join(dir, f);
|
|
170
|
+
try {
|
|
171
|
+
if (now - statSync(p).mtimeMs > COOKIE_FILE_MAX_AGE_MS)
|
|
172
|
+
rmSync(p, { force: true });
|
|
173
|
+
}
|
|
174
|
+
catch {
|
|
175
|
+
/* skip */
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
catch {
|
|
180
|
+
/* best-effort */
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
function safeFileName(s) {
|
|
184
|
+
return s.replace(/[^a-zA-Z0-9_.-]/g, "_");
|
|
185
|
+
}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
export { CredentialStore } from "./store.js";
|
|
2
2
|
export type { CredentialScope, MaskedCredential } from "./store.js";
|
|
3
3
|
export { type EncryptionCipher, PlaintextCipher, setDefaultCredentialCipher, getDefaultCredentialCipher, } from "./cipher.js";
|
|
4
|
-
export type
|
|
4
|
+
export { getCredentialAccess, setDefaultCredentialAccess, createIpcCredentialAccess, localCredentialAccess, credentialAccessScope, isCredentialSecretAvailable, materializeCookieSecret, type CredentialAccess, type CredentialAccessScope, type CredentialMetadata, type CredentialSnapshot, type CredentialSnapshotEntry, } from "./access.js";
|
|
5
|
+
export type { Credential, CredentialType, CredentialStoreFile, OAuthCredentialPublicStatus, OAuthCredentialSecret, } from "./types.js";
|
|
6
|
+
export { buildOAuthRefreshRequest, isOAuthAccessTokenExpired, oauthCredentialStatus, parseOAuthCredentialSecret, summarizeOAuthCredentialSecret, type OAuthClockOptions, type OAuthRefreshHandler, type OAuthRefreshRequest, } from "./oauth.js";
|
|
5
7
|
export { formatNetscapeCookies, parseCookieJar, type CookieLike } from "./cookie-jar.js";
|
|
6
8
|
export { useCredentialToolDef, useCredentialToolDefFor, useCredentialTool, sweepStaleCredentialCookies, } from "./use-credential-tool.js";
|
|
7
9
|
export { credentialUseGate } from "./use-gate.js";
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
export { CredentialStore } from "./store.js";
|
|
2
2
|
export { PlaintextCipher, setDefaultCredentialCipher, getDefaultCredentialCipher, } from "./cipher.js";
|
|
3
|
+
export { getCredentialAccess, setDefaultCredentialAccess, createIpcCredentialAccess, localCredentialAccess, credentialAccessScope, isCredentialSecretAvailable, materializeCookieSecret, } from "./access.js";
|
|
4
|
+
export { buildOAuthRefreshRequest, isOAuthAccessTokenExpired, oauthCredentialStatus, parseOAuthCredentialSecret, summarizeOAuthCredentialSecret, } from "./oauth.js";
|
|
3
5
|
export { formatNetscapeCookies, parseCookieJar } from "./cookie-jar.js";
|
|
4
6
|
export { useCredentialToolDef, useCredentialToolDefFor, useCredentialTool, sweepStaleCredentialCookies, } from "./use-credential-tool.js";
|
|
5
7
|
export { credentialUseGate } from "./use-gate.js";
|
|
@@ -12,9 +12,11 @@
|
|
|
12
12
|
*/
|
|
13
13
|
import type { ToolDefinition } from "../types.js";
|
|
14
14
|
import type { ToolContext } from "../tool-system/context.js";
|
|
15
|
+
import { type SettingsScope } from "../settings/manager.js";
|
|
15
16
|
export declare const injectCredentialToolDef: ToolDefinition;
|
|
16
17
|
/** 该工具仅在有 cookie 凭证 且 宿主接了注入回调时才可见(BUILTIN_TOOL_GUARDS)。 */
|
|
17
|
-
export declare function isInjectCredentialAvailable(cwd: string): boolean;
|
|
18
|
+
export declare function isInjectCredentialAvailable(cwd: string, settingsScope?: SettingsScope): boolean;
|
|
18
19
|
export declare function injectCredentialTool(args: Record<string, unknown>, ctx?: ToolContext): Promise<string>;
|
|
19
20
|
/** 测试钩子:清空会话 allow 集。 */
|
|
20
21
|
export declare function __resetInjectCredentialSessionAllowForTests(): void;
|
|
22
|
+
export declare function clearInjectCredentialSessionAllow(sessionId: string): void;
|
|
@@ -10,9 +10,9 @@
|
|
|
10
10
|
* 跨进程:实际的 restoreCookiesToBrowser 在 desktop main(core 够不到 Electron
|
|
11
11
|
* session),经 `ctx.injectCredentialToBrowser` 回调(宿主注入,镜像 askUser)触发。
|
|
12
12
|
*/
|
|
13
|
-
import { CredentialStore } from "./store.js";
|
|
14
13
|
import { credentialUseGate, } from "./use-gate.js";
|
|
15
14
|
import { SettingsManager } from "../settings/manager.js";
|
|
15
|
+
import { credentialAccessScope, getCredentialAccess } from "./access.js";
|
|
16
16
|
const TOOL_NAME = "InjectCredential";
|
|
17
17
|
const BASE_DESCRIPTION = "Inject a stored COOKIE credential into the built-in browser to restore its " +
|
|
18
18
|
"login state, so you can then drive the page as that logged-in account with the " +
|
|
@@ -62,9 +62,14 @@ function sessionAllowFor(ctx) {
|
|
|
62
62
|
}
|
|
63
63
|
return set;
|
|
64
64
|
}
|
|
65
|
-
|
|
65
|
+
// CredentialStore only distinguishes full user+project from project-only.
|
|
66
|
+
// Isolated engines must be at least as restrictive as project-scoped engines.
|
|
67
|
+
function credentialScope(scope) {
|
|
68
|
+
return credentialAccessScope(scope);
|
|
69
|
+
}
|
|
70
|
+
function readAutoApprove(cwd, scope) {
|
|
66
71
|
try {
|
|
67
|
-
const s = new SettingsManager(cwd, "full").get();
|
|
72
|
+
const s = new SettingsManager(cwd, scope === "full" ? "full" : "project").get();
|
|
68
73
|
return s.credentialUse?.autoApprove === true;
|
|
69
74
|
}
|
|
70
75
|
catch {
|
|
@@ -72,9 +77,11 @@ function readAutoApprove(cwd) {
|
|
|
72
77
|
}
|
|
73
78
|
}
|
|
74
79
|
/** 该工具仅在有 cookie 凭证 且 宿主接了注入回调时才可见(BUILTIN_TOOL_GUARDS)。 */
|
|
75
|
-
export function isInjectCredentialAvailable(cwd) {
|
|
80
|
+
export function isInjectCredentialAvailable(cwd, settingsScope) {
|
|
76
81
|
try {
|
|
77
|
-
return
|
|
82
|
+
return getCredentialAccess()
|
|
83
|
+
.listMasked(cwd, credentialScope(settingsScope))
|
|
84
|
+
.some((c) => c.type === "cookie");
|
|
78
85
|
}
|
|
79
86
|
catch {
|
|
80
87
|
return false;
|
|
@@ -82,10 +89,14 @@ export function isInjectCredentialAvailable(cwd) {
|
|
|
82
89
|
}
|
|
83
90
|
export async function injectCredentialTool(args, ctx) {
|
|
84
91
|
const cwd = ctx?.cwd ?? process.cwd();
|
|
92
|
+
const scope = credentialScope(ctx?.settingsScope);
|
|
85
93
|
const id = typeof args.id === "string" ? args.id.trim() : "";
|
|
86
94
|
const purpose = typeof args.purpose === "string" ? args.purpose : undefined;
|
|
87
95
|
if (!id) {
|
|
88
|
-
return json({
|
|
96
|
+
return json({
|
|
97
|
+
kind: "error",
|
|
98
|
+
error: "缺少 id。先用 UseCredential(无参)列出凭证,再用 cookie 凭证的 id 调本工具。",
|
|
99
|
+
});
|
|
89
100
|
}
|
|
90
101
|
if (!ctx?.injectCredentialToBrowser) {
|
|
91
102
|
return json({
|
|
@@ -93,17 +104,22 @@ export async function injectCredentialTool(args, ctx) {
|
|
|
93
104
|
error: "当前环境无内置浏览器(headless/无面板),无法注入。请改用 UseCredential 取 cookie 走 HTTP 请求。",
|
|
94
105
|
});
|
|
95
106
|
}
|
|
96
|
-
const cred =
|
|
107
|
+
const cred = getCredentialAccess().resolveMeta(cwd, id, scope);
|
|
97
108
|
if (!cred) {
|
|
98
|
-
return json({
|
|
109
|
+
return json({
|
|
110
|
+
kind: "error",
|
|
111
|
+
error: `凭证不存在: "${id}"。调用 UseCredential(无参)可列出可用凭证。`,
|
|
112
|
+
});
|
|
99
113
|
}
|
|
100
114
|
if (cred.type !== "cookie") {
|
|
101
115
|
return json({ kind: "error", error: `凭证「${cred.label}」不是 cookie 类型,不能注入浏览器。` });
|
|
102
116
|
}
|
|
103
117
|
// 过门:复用三档,但用该凭证的 autoInjectByAI(不是 autoUseByAI)。
|
|
104
|
-
const ask = ctx.askUser
|
|
118
|
+
const ask = ctx.askUser
|
|
119
|
+
? (q, opts) => ctx.askUser(q, opts)
|
|
120
|
+
: undefined;
|
|
105
121
|
const decision = await credentialUseGate({ id: cred.id, label: cred.label, purpose }, {
|
|
106
|
-
autoApprove: readAutoApprove(cwd),
|
|
122
|
+
autoApprove: readAutoApprove(cwd, scope),
|
|
107
123
|
credentialAutoUse: cred.autoInjectByAI === true,
|
|
108
124
|
sessionAllow: sessionAllowFor(ctx),
|
|
109
125
|
ask,
|
|
@@ -115,7 +131,7 @@ export async function injectCredentialTool(args, ctx) {
|
|
|
115
131
|
return json({ kind: "error", error: msg });
|
|
116
132
|
}
|
|
117
133
|
// 跨进程触发宿主注入。
|
|
118
|
-
const res = await ctx.injectCredentialToBrowser(cred.id);
|
|
134
|
+
const res = await ctx.injectCredentialToBrowser(cred.id, scope);
|
|
119
135
|
if (!res.ok) {
|
|
120
136
|
return json({ kind: "error", error: res.error ?? "注入浏览器失败(宿主未返回成功)。" });
|
|
121
137
|
}
|
|
@@ -128,3 +144,6 @@ function json(r) {
|
|
|
128
144
|
export function __resetInjectCredentialSessionAllowForTests() {
|
|
129
145
|
injectSessionAllowByEngine.clear();
|
|
130
146
|
}
|
|
147
|
+
export function clearInjectCredentialSessionAllow(sessionId) {
|
|
148
|
+
injectSessionAllowByEngine.delete(sessionId);
|
|
149
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { OAuthCredentialPublicStatus, OAuthCredentialSecret } from "./types.js";
|
|
2
|
+
export interface OAuthClockOptions {
|
|
3
|
+
now?: number | (() => number);
|
|
4
|
+
skewMs?: number;
|
|
5
|
+
}
|
|
6
|
+
export interface OAuthRefreshRequest {
|
|
7
|
+
credentialId: string;
|
|
8
|
+
tokenEndpoint: string;
|
|
9
|
+
refreshToken: string;
|
|
10
|
+
clientId?: string;
|
|
11
|
+
clientSecret?: string;
|
|
12
|
+
scope?: string;
|
|
13
|
+
scopes?: string[];
|
|
14
|
+
}
|
|
15
|
+
export type OAuthRefreshHandler = (req: OAuthRefreshRequest) => Promise<OAuthCredentialSecret>;
|
|
16
|
+
export declare function parseOAuthCredentialSecret(secret: string): OAuthCredentialSecret;
|
|
17
|
+
export declare function isOAuthAccessTokenExpired(secret: Pick<OAuthCredentialSecret, "accessToken" | "expiresAt">, opts?: OAuthClockOptions): boolean;
|
|
18
|
+
export declare function oauthCredentialStatus(secret: Pick<OAuthCredentialSecret, "accessToken" | "expiresAt">, opts?: OAuthClockOptions): Pick<OAuthCredentialPublicStatus, "state" | "expiresAt" | "expiresInMs">;
|
|
19
|
+
export declare function buildOAuthRefreshRequest(credentialId: string, secret: OAuthCredentialSecret): OAuthRefreshRequest | undefined;
|
|
20
|
+
export declare function summarizeOAuthCredentialSecret(secret: string | undefined, opts?: OAuthClockOptions): OAuthCredentialPublicStatus;
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
const DEFAULT_OAUTH_REFRESH_SKEW_MS = 60_000;
|
|
2
|
+
function nowMs(opts = {}) {
|
|
3
|
+
if (typeof opts.now === "function")
|
|
4
|
+
return opts.now();
|
|
5
|
+
if (typeof opts.now === "number")
|
|
6
|
+
return opts.now;
|
|
7
|
+
return Date.now();
|
|
8
|
+
}
|
|
9
|
+
function optionalString(value) {
|
|
10
|
+
return typeof value === "string" && value.length > 0 ? value : undefined;
|
|
11
|
+
}
|
|
12
|
+
function optionalStringArray(value) {
|
|
13
|
+
if (!Array.isArray(value))
|
|
14
|
+
return undefined;
|
|
15
|
+
const out = value.filter((x) => typeof x === "string" && x.length > 0);
|
|
16
|
+
return out.length > 0 ? out : undefined;
|
|
17
|
+
}
|
|
18
|
+
function parseExpiresAt(value) {
|
|
19
|
+
if (!value)
|
|
20
|
+
return undefined;
|
|
21
|
+
const ms = Date.parse(value);
|
|
22
|
+
if (!Number.isFinite(ms)) {
|
|
23
|
+
throw new Error(`OAuth credential secret has invalid expiresAt: ${value}`);
|
|
24
|
+
}
|
|
25
|
+
return ms;
|
|
26
|
+
}
|
|
27
|
+
export function parseOAuthCredentialSecret(secret) {
|
|
28
|
+
let parsed;
|
|
29
|
+
try {
|
|
30
|
+
parsed = JSON.parse(secret);
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
throw new Error("OAuth credential secret must be a JSON object");
|
|
34
|
+
}
|
|
35
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
36
|
+
throw new Error("OAuth credential secret must be a JSON object");
|
|
37
|
+
}
|
|
38
|
+
const raw = parsed;
|
|
39
|
+
if (raw.version !== undefined && raw.version !== 1) {
|
|
40
|
+
throw new Error("OAuth credential secret version must be 1");
|
|
41
|
+
}
|
|
42
|
+
const accessToken = optionalString(raw.accessToken);
|
|
43
|
+
if (!accessToken) {
|
|
44
|
+
throw new Error("OAuth credential secret must include accessToken");
|
|
45
|
+
}
|
|
46
|
+
const expiresAt = optionalString(raw.expiresAt);
|
|
47
|
+
parseExpiresAt(expiresAt);
|
|
48
|
+
return {
|
|
49
|
+
version: raw.version === 1 ? 1 : undefined,
|
|
50
|
+
accessToken,
|
|
51
|
+
refreshToken: optionalString(raw.refreshToken),
|
|
52
|
+
expiresAt,
|
|
53
|
+
tokenType: optionalString(raw.tokenType),
|
|
54
|
+
scope: optionalString(raw.scope),
|
|
55
|
+
scopes: optionalStringArray(raw.scopes),
|
|
56
|
+
tokenEndpoint: optionalString(raw.tokenEndpoint),
|
|
57
|
+
clientId: optionalString(raw.clientId),
|
|
58
|
+
clientSecret: optionalString(raw.clientSecret),
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
export function isOAuthAccessTokenExpired(secret, opts = {}) {
|
|
62
|
+
const expiresAtMs = parseExpiresAt(secret.expiresAt);
|
|
63
|
+
if (expiresAtMs === undefined)
|
|
64
|
+
return false;
|
|
65
|
+
const skewMs = opts.skewMs ?? DEFAULT_OAUTH_REFRESH_SKEW_MS;
|
|
66
|
+
return expiresAtMs <= nowMs(opts) + skewMs;
|
|
67
|
+
}
|
|
68
|
+
export function oauthCredentialStatus(secret, opts = {}) {
|
|
69
|
+
const expiresAtMs = parseExpiresAt(secret.expiresAt);
|
|
70
|
+
if (expiresAtMs === undefined) {
|
|
71
|
+
return { state: "valid", expiresAt: undefined, expiresInMs: undefined };
|
|
72
|
+
}
|
|
73
|
+
const expiresInMs = expiresAtMs - nowMs(opts);
|
|
74
|
+
return {
|
|
75
|
+
state: isOAuthAccessTokenExpired(secret, opts) ? "expired" : "valid",
|
|
76
|
+
expiresAt: secret.expiresAt,
|
|
77
|
+
expiresInMs,
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
export function buildOAuthRefreshRequest(credentialId, secret) {
|
|
81
|
+
if (!secret.refreshToken || !secret.tokenEndpoint)
|
|
82
|
+
return undefined;
|
|
83
|
+
return {
|
|
84
|
+
credentialId,
|
|
85
|
+
tokenEndpoint: secret.tokenEndpoint,
|
|
86
|
+
refreshToken: secret.refreshToken,
|
|
87
|
+
clientId: secret.clientId,
|
|
88
|
+
clientSecret: secret.clientSecret,
|
|
89
|
+
scope: secret.scope,
|
|
90
|
+
scopes: secret.scopes,
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
export function summarizeOAuthCredentialSecret(secret, opts = {}) {
|
|
94
|
+
if (!secret)
|
|
95
|
+
return { state: "missing" };
|
|
96
|
+
try {
|
|
97
|
+
const parsed = parseOAuthCredentialSecret(secret);
|
|
98
|
+
const status = oauthCredentialStatus(parsed, opts);
|
|
99
|
+
return {
|
|
100
|
+
...status,
|
|
101
|
+
hasRefreshToken: Boolean(parsed.refreshToken),
|
|
102
|
+
tokenEndpoint: parsed.tokenEndpoint,
|
|
103
|
+
clientId: parsed.clientId,
|
|
104
|
+
scope: parsed.scope,
|
|
105
|
+
scopes: parsed.scopes,
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
catch (err) {
|
|
109
|
+
return {
|
|
110
|
+
state: "invalid",
|
|
111
|
+
error: err instanceof Error ? err.message : String(err),
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
}
|
|
@@ -5,6 +5,7 @@ export interface MaskedCredential extends Omit<Credential, "secret"> {
|
|
|
5
5
|
hasSecret: boolean;
|
|
6
6
|
/** 形如 `****abcd`,绝不含完整明文。 */
|
|
7
7
|
secretHint?: string;
|
|
8
|
+
oauthStatus?: import("./types.js").OAuthCredentialPublicStatus;
|
|
8
9
|
}
|
|
9
10
|
/**
|
|
10
11
|
* 两层凭证库,镜像 SettingsManager 的 user(~/.code-shell)/ project(<cwd>/.code-shell)
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { existsSync, mkdirSync, readFileSync, writeFileSync, renameSync
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync, renameSync } from "node:fs";
|
|
2
2
|
import { join, dirname } from "node:path";
|
|
3
3
|
import { homedir } from "node:os";
|
|
4
4
|
import { getDefaultCredentialCipher } from "./cipher.js";
|
|
5
5
|
import { logger } from "../logging/logger.js";
|
|
6
|
+
import { summarizeOAuthCredentialSecret } from "./oauth.js";
|
|
6
7
|
/** 测试可经 process.env.HOME 覆盖(镜像 settings/manager.ts userHome)。 */
|
|
7
8
|
function userHome() {
|
|
8
9
|
return process.env.HOME ?? homedir();
|
|
@@ -178,6 +179,7 @@ export class CredentialStore {
|
|
|
178
179
|
// than 4, so those chars aren't the whole secret. `"ab".slice(-4)` is
|
|
179
180
|
// "ab", so a short secret would otherwise leak in full through the hint.
|
|
180
181
|
secretHint: secret ? (secret.length > 4 ? `****${secret.slice(-4)}` : "****") : undefined,
|
|
182
|
+
...(c.type === "oauth" ? { oauthStatus: summarizeOAuthCredentialSecret(secret) } : {}),
|
|
181
183
|
};
|
|
182
184
|
});
|
|
183
185
|
}
|
|
@@ -3,7 +3,40 @@
|
|
|
3
3
|
* - token/link 第一期已有;cookie 第二期改为「具名 cookie 凭证」进库
|
|
4
4
|
* (用户主动按域拓取存,支持同域多账号),见 credential-use-gate 设计稿。
|
|
5
5
|
*/
|
|
6
|
-
export type CredentialType = "token" | "link" | "cookie";
|
|
6
|
+
export type CredentialType = "token" | "link" | "cookie" | "oauth";
|
|
7
|
+
export interface OAuthCredentialSecret {
|
|
8
|
+
/** Schema version for the JSON stored in Credential.secret. */
|
|
9
|
+
version?: 1;
|
|
10
|
+
/** Current access token. MCP HTTP auth sends this as Authorization: Bearer. */
|
|
11
|
+
accessToken: string;
|
|
12
|
+
/** Optional refresh token. Stored encrypted with the credential secret. */
|
|
13
|
+
refreshToken?: string;
|
|
14
|
+
/** ISO-8601 expiry time for accessToken. Missing means "unknown", not expired. */
|
|
15
|
+
expiresAt?: string;
|
|
16
|
+
/** Upstream token type, usually Bearer. Stored for round-trip/debugging. */
|
|
17
|
+
tokenType?: string;
|
|
18
|
+
/** Space-delimited OAuth scope string returned by many token endpoints. */
|
|
19
|
+
scope?: string;
|
|
20
|
+
/** Structured scopes used by first-party UI/catalog metadata. */
|
|
21
|
+
scopes?: string[];
|
|
22
|
+
/** Token endpoint to use when a future refresh flow is wired. */
|
|
23
|
+
tokenEndpoint?: string;
|
|
24
|
+
/** OAuth client id associated with this token. */
|
|
25
|
+
clientId?: string;
|
|
26
|
+
/** Optional confidential client secret, if the integration requires it. */
|
|
27
|
+
clientSecret?: string;
|
|
28
|
+
}
|
|
29
|
+
export interface OAuthCredentialPublicStatus {
|
|
30
|
+
state: "valid" | "expired" | "missing" | "invalid";
|
|
31
|
+
expiresAt?: string;
|
|
32
|
+
expiresInMs?: number;
|
|
33
|
+
hasRefreshToken?: boolean;
|
|
34
|
+
tokenEndpoint?: string;
|
|
35
|
+
clientId?: string;
|
|
36
|
+
scope?: string;
|
|
37
|
+
scopes?: string[];
|
|
38
|
+
error?: string;
|
|
39
|
+
}
|
|
7
40
|
export interface Credential {
|
|
8
41
|
/**
|
|
9
42
|
* 引用键,kebab-case,全局/项目两层内唯一。
|
|
@@ -19,6 +52,7 @@ export interface Credential {
|
|
|
19
52
|
* 密文(UI 只显示掩码):
|
|
20
53
|
* - token: token 值;
|
|
21
54
|
* - link: client id/secret 等的 JSON 字符串;
|
|
55
|
+
* - oauth: OAuthCredentialSecret JSON 字符串(access/refresh/expiry/client info);
|
|
22
56
|
* - cookie: 序列化的 cookie jar(JSON.stringify 的 ElectronCookieLike[])。
|
|
23
57
|
*/
|
|
24
58
|
secret?: string;
|
|
@@ -39,8 +73,8 @@ export interface Credential {
|
|
|
39
73
|
/**
|
|
40
74
|
* link: 业务方 app 注册地址;cookie: 拓取所用平台与主域 + 抓取范围 + 切换策略。
|
|
41
75
|
* - scope="all" 表示该 jar 是整分区全量抓的(切换时整包导回);缺省/"domain" = 仅该域。
|
|
42
|
-
* - switchMode 决定「切换」时怎么写回浏览器:"
|
|
43
|
-
* "
|
|
76
|
+
* - switchMode 决定「切换」时怎么写回浏览器:"merge"(默认)只覆盖同名 cookie、保留
|
|
77
|
+
* 分区里其他站(不踢掉别的登录态);"clear" 先清空整分区再注入(干净换号,需显式选)。
|
|
44
78
|
*/
|
|
45
79
|
meta?: {
|
|
46
80
|
appUrl?: string;
|
|
@@ -48,6 +82,18 @@ export interface Credential {
|
|
|
48
82
|
domain?: string;
|
|
49
83
|
scope?: "domain" | "all";
|
|
50
84
|
switchMode?: "clear" | "merge";
|
|
85
|
+
/** OAuth provider/integration id, e.g. "figma". */
|
|
86
|
+
oauthProvider?: string;
|
|
87
|
+
/** OAuth authorization endpoint, used by UI/login launchers. */
|
|
88
|
+
authUrl?: string;
|
|
89
|
+
/** OAuth token endpoint, duplicated from secret for non-secret UI display. */
|
|
90
|
+
tokenEndpoint?: string;
|
|
91
|
+
/** OAuth client id, duplicated from secret for non-secret UI display. */
|
|
92
|
+
clientId?: string;
|
|
93
|
+
/** OAuth scopes requested for this credential. */
|
|
94
|
+
scopes?: string[];
|
|
95
|
+
/** Last successful refresh time; refresh wiring is reserved for a later step. */
|
|
96
|
+
lastRefreshAt?: string;
|
|
51
97
|
};
|
|
52
98
|
}
|
|
53
99
|
export interface CredentialStoreFile {
|
|
@@ -7,7 +7,8 @@
|
|
|
7
7
|
* - token/link → `{ kind: "value", value }`
|
|
8
8
|
* - cookie → 就地写临时 cookies.txt(0600),返回 `{ kind: "cookie", cookiesFile, count }`
|
|
9
9
|
*
|
|
10
|
-
*
|
|
10
|
+
* desktop 下通过 host credential access IPC 按需解析 secret;headless/SDK
|
|
11
|
+
* 仍可使用本地 CredentialStore。
|
|
11
12
|
* 集中在 core/src/credentials/ 下,只经 ToolDefinition 注册 + ToolContext.askUser 耦合 core,
|
|
12
13
|
* 满足设计稿 §1「可整块外移」约束。
|
|
13
14
|
*/
|
|
@@ -25,5 +26,12 @@ export declare function useCredentialToolDefFor(cwd: string): ToolDefinition;
|
|
|
25
26
|
*/
|
|
26
27
|
export declare function sweepStaleCredentialCookies(now?: number): void;
|
|
27
28
|
export declare function useCredentialTool(args: Record<string, unknown>, ctx?: ToolContext): Promise<string>;
|
|
29
|
+
export declare function useCredentialBuiltinTool(args: Record<string, unknown>, ctx?: ToolContext): Promise<string | {
|
|
30
|
+
result: string;
|
|
31
|
+
sensitive: true;
|
|
32
|
+
displayResult: string;
|
|
33
|
+
transcriptResult: string;
|
|
34
|
+
}>;
|
|
28
35
|
/** 测试钩子:清空会话 allow 集(避免跨用例污染)。 */
|
|
29
36
|
export declare function __resetCredentialSessionAllowForTests(): void;
|
|
37
|
+
export declare function clearCredentialSessionAllow(sessionId: string): void;
|