vskill 0.5.103 → 0.5.104
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.md +24 -2
- package/agents.json +1 -1
- package/dist/agents/agents-registry.d.ts +13 -2
- package/dist/agents/agents-registry.js +120 -57
- package/dist/agents/agents-registry.js.map +1 -1
- package/dist/commands/diff.d.ts +9 -0
- package/dist/commands/diff.js +139 -0
- package/dist/commands/diff.js.map +1 -0
- package/dist/commands/eval/serve.js +25 -83
- package/dist/commands/eval/serve.js.map +1 -1
- package/dist/commands/skill.d.ts +32 -0
- package/dist/commands/skill.js +392 -0
- package/dist/commands/skill.js.map +1 -0
- package/dist/commands/update.js +15 -4
- package/dist/commands/update.js.map +1 -1
- package/dist/core/skill-emitter.d.ts +37 -0
- package/dist/core/skill-emitter.js +333 -0
- package/dist/core/skill-emitter.js.map +1 -0
- package/dist/core/skill-generator.d.ts +27 -0
- package/dist/core/skill-generator.js +100 -0
- package/dist/core/skill-generator.js.map +1 -0
- package/dist/eval/skill-scanner.d.ts +0 -5
- package/dist/eval/skill-scanner.js +0 -12
- package/dist/eval/skill-scanner.js.map +1 -1
- package/dist/eval-server/api-routes.d.ts +0 -7
- package/dist/eval-server/api-routes.js +19 -52
- package/dist/eval-server/api-routes.js.map +1 -1
- package/dist/eval-server/settings-store.d.ts +26 -33
- package/dist/eval-server/settings-store.js +145 -245
- package/dist/eval-server/settings-store.js.map +1 -1
- package/dist/eval-server/skill-create-routes.d.ts +62 -0
- package/dist/eval-server/skill-create-routes.js +79 -132
- package/dist/eval-server/skill-create-routes.js.map +1 -1
- package/dist/eval-ui/assets/{CommandPalette-6cLEufX0.js → CommandPalette-DiPALzlG.js} +1 -1
- package/dist/eval-ui/assets/{CreateSkillPage-kn7xDaAP.js → CreateSkillPage-BMrFELep.js} +1 -1
- package/dist/eval-ui/assets/{UpdateDropdown-9qR5NxTi.js → UpdateDropdown-Bj8kZzuR.js} +1 -1
- package/dist/eval-ui/assets/_shimNode-D3bBqrAh.js +1 -0
- package/dist/eval-ui/assets/{index-4LdVR3Lo.js → index-BSPDkfZG.js} +37 -37
- package/dist/eval-ui/assets/resolve-binary-DIxhrZ6O.js +2 -0
- package/dist/eval-ui/index.html +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/installer/canonical.d.ts +2 -0
- package/dist/installer/canonical.js +35 -4
- package/dist/installer/canonical.js.map +1 -1
- package/dist/studio/lib/ops-log.js +1 -4
- package/dist/studio/lib/ops-log.js.map +1 -1
- package/dist/studio/lib/scope-transfer.d.ts +0 -10
- package/dist/studio/lib/scope-transfer.js +13 -116
- package/dist/studio/lib/scope-transfer.js.map +1 -1
- package/dist/studio/routes/ops.js +3 -26
- package/dist/studio/routes/ops.js.map +1 -1
- package/dist/studio/routes/promote.js +15 -9
- package/dist/studio/routes/promote.js.map +1 -1
- package/dist/studio/routes/test-install.js +11 -4
- package/dist/studio/routes/test-install.js.map +1 -1
- package/dist/utils/agent-filter.js +5 -4
- package/dist/utils/agent-filter.js.map +1 -1
- package/dist/utils/resolve-binary.d.ts +22 -0
- package/dist/utils/resolve-binary.js +44 -0
- package/dist/utils/resolve-binary.js.map +1 -1
- package/package.json +1 -1
- package/scripts/preuninstall.cjs +2 -9
|
@@ -1,46 +1,39 @@
|
|
|
1
|
-
import * as
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
export type
|
|
1
|
+
import * as childProcess from "node:child_process";
|
|
2
|
+
declare const realSpawn: typeof childProcess.spawn;
|
|
3
|
+
export type Provider = "anthropic" | "openrouter";
|
|
4
|
+
export type Tier = "browser" | "keychain";
|
|
5
5
|
export interface KeyMetadata {
|
|
6
6
|
stored: boolean;
|
|
7
7
|
updatedAt: string | null;
|
|
8
|
+
tier: Tier;
|
|
8
9
|
}
|
|
9
10
|
export interface ListKeysResponse {
|
|
10
11
|
anthropic: KeyMetadata;
|
|
11
|
-
openai: KeyMetadata;
|
|
12
12
|
openrouter: KeyMetadata;
|
|
13
13
|
}
|
|
14
|
-
export
|
|
14
|
+
export declare class UnsupportedTierError extends Error {
|
|
15
|
+
constructor(message: string);
|
|
16
|
+
}
|
|
17
|
+
export declare function redactKey(key: string): string;
|
|
18
|
+
type Logger = {
|
|
15
19
|
warn: (msg: string) => void;
|
|
16
20
|
error: (msg: string) => void;
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
export
|
|
21
|
+
};
|
|
22
|
+
export declare function _setLogger(l: Logger): void;
|
|
23
|
+
export declare function _setSpawn(s: typeof realSpawn): void;
|
|
24
|
+
export declare function _setPlatformOverride(p: NodeJS.Platform | null): void;
|
|
25
|
+
export declare function resetSettingsStore(): void;
|
|
26
|
+
export declare function getTier(): Tier;
|
|
27
|
+
export declare function setTier(tier: Tier): Promise<void>;
|
|
28
|
+
export declare function saveKey(provider: Provider, key: string, tier?: Tier): Promise<{
|
|
20
29
|
updatedAt: string;
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
existsSync: typeof nodeFs.existsSync;
|
|
30
|
-
mkdirSync: typeof nodeFs.mkdirSync;
|
|
31
|
-
statSync: typeof nodeFs.statSync;
|
|
32
|
-
}
|
|
33
|
-
export declare function getKeysFilePath(): string;
|
|
34
|
-
export declare function saveKey(provider: ProviderId | string, key: string): Promise<SaveKeyResult>;
|
|
35
|
-
export declare function readKey(provider: ProviderId | string): Promise<string | null>;
|
|
36
|
-
export declare function readKeySync(provider: ProviderId | string): string | null;
|
|
37
|
-
export declare function hasKeySync(provider: ProviderId | string): boolean;
|
|
38
|
-
export declare function removeKey(provider: ProviderId | string): Promise<void>;
|
|
30
|
+
tier: Tier;
|
|
31
|
+
}>;
|
|
32
|
+
export declare function readKey(provider: Provider): string | null;
|
|
33
|
+
/** Synchronous accessor used by detectAvailableProviders — safe, same semantics. */
|
|
34
|
+
export declare function readKeySync(provider: Provider): string | null;
|
|
35
|
+
/** Has-key predicate exposed for synchronous availability checks. */
|
|
36
|
+
export declare function hasKeySync(provider: Provider): boolean;
|
|
37
|
+
export declare function removeKey(provider: Provider): Promise<void>;
|
|
39
38
|
export declare function listKeys(): ListKeysResponse;
|
|
40
|
-
export declare function mergeStoredKeysIntoEnv(): void;
|
|
41
|
-
export declare function resetSettingsStore(opts?: {
|
|
42
|
-
logger?: Logger;
|
|
43
|
-
fs?: Partial<FsApi>;
|
|
44
|
-
}): void;
|
|
45
|
-
export declare function _internalMapSize(): number;
|
|
46
39
|
export {};
|
|
@@ -1,295 +1,195 @@
|
|
|
1
1
|
// ---------------------------------------------------------------------------
|
|
2
|
-
// settings-store.ts —
|
|
2
|
+
// settings-store.ts — Tiered API key storage for vSkill Studio (0682 / US-004).
|
|
3
3
|
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
//
|
|
4
|
+
// Two tiers:
|
|
5
|
+
// - "browser" (default, all platforms) — in-memory map keyed by provider.
|
|
6
|
+
// The browser mirrors the write into localStorage so a page
|
|
7
|
+
// reload does not require re-entry.
|
|
8
|
+
// - "keychain" (Darwin opt-in) — shells out to the `security` binary to
|
|
9
|
+
// store under `vskill-<provider>`. No native-module dep.
|
|
9
10
|
//
|
|
10
11
|
// Contract:
|
|
11
12
|
// - Keys NEVER appear in any log, error, toast, network URL, or stdout.
|
|
12
|
-
//
|
|
13
|
-
// -
|
|
14
|
-
//
|
|
15
|
-
// -
|
|
16
|
-
//
|
|
17
|
-
//
|
|
18
|
-
//
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
import * as
|
|
22
|
-
|
|
23
|
-
//
|
|
24
|
-
//
|
|
25
|
-
|
|
13
|
+
// The only redacted form ever emitted is `****<last-4>` via `redactKey`.
|
|
14
|
+
// - `listKeys()` returns metadata only (stored boolean, updatedAt, tier).
|
|
15
|
+
// - `removeKey()` is idempotent.
|
|
16
|
+
// - Tier switch (setTier) wipes the old tier's entry and re-saves into the
|
|
17
|
+
// new tier so the live state stays coherent.
|
|
18
|
+
//
|
|
19
|
+
// Tests inject a fake logger + a fake spawn factory so the Darwin path is
|
|
20
|
+
// exercisable on any host. See __tests__/settings-store.test.ts.
|
|
21
|
+
// ---------------------------------------------------------------------------
|
|
22
|
+
import * as childProcess from "node:child_process";
|
|
23
|
+
// Lazy accessor — some test files mock `node:child_process` without re-
|
|
24
|
+
// exporting `spawn`. Reading through the namespace at call time avoids
|
|
25
|
+
// touching the mock at module-load time, so those tests keep passing.
|
|
26
|
+
const realSpawn = ((...args) => childProcess.spawn(...args));
|
|
27
|
+
export class UnsupportedTierError extends Error {
|
|
28
|
+
constructor(message) {
|
|
29
|
+
super(message);
|
|
30
|
+
this.name = "UnsupportedTierError";
|
|
31
|
+
}
|
|
32
|
+
}
|
|
26
33
|
export function redactKey(key) {
|
|
27
34
|
if (!key || key.length <= 4)
|
|
28
35
|
return "****";
|
|
29
36
|
return "****" + key.slice(-4);
|
|
30
37
|
}
|
|
31
|
-
const
|
|
38
|
+
const store = new Map();
|
|
39
|
+
let currentTier = "browser";
|
|
40
|
+
let logger = {
|
|
32
41
|
warn: (m) => console.warn(m),
|
|
33
42
|
error: (m) => console.error(m),
|
|
34
|
-
info: (m) => console.info(m),
|
|
35
43
|
};
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
44
|
+
let spawn = realSpawn;
|
|
45
|
+
let platformOverride = null;
|
|
46
|
+
export function _setLogger(l) {
|
|
47
|
+
logger = l;
|
|
48
|
+
}
|
|
49
|
+
export function _setSpawn(s) {
|
|
50
|
+
spawn = s;
|
|
51
|
+
}
|
|
52
|
+
export function _setPlatformOverride(p) {
|
|
53
|
+
platformOverride = p;
|
|
54
|
+
}
|
|
55
|
+
export function resetSettingsStore() {
|
|
56
|
+
store.clear();
|
|
57
|
+
currentTier = "browser";
|
|
58
|
+
platformOverride = null;
|
|
59
|
+
logger = {
|
|
60
|
+
warn: (m) => console.warn(m),
|
|
61
|
+
error: (m) => console.error(m),
|
|
49
62
|
};
|
|
63
|
+
spawn = realSpawn;
|
|
50
64
|
}
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
let logger = defaultLogger;
|
|
54
|
-
let fsApi = defaultFs();
|
|
55
|
-
// ---------------------------------------------------------------------------
|
|
56
|
-
// Path resolution
|
|
57
|
-
// ---------------------------------------------------------------------------
|
|
58
|
-
function resolveConfigDir() {
|
|
59
|
-
return process.env.VSKILL_CONFIG_DIR ?? path.join(os.homedir(), ".vskill");
|
|
60
|
-
}
|
|
61
|
-
export function getKeysFilePath() {
|
|
62
|
-
return path.join(resolveConfigDir(), "keys.env");
|
|
63
|
-
}
|
|
64
|
-
const ENV_VAR_TO_PROVIDER = new Map(PROVIDERS.map((p) => [p.envVarName, p.id]));
|
|
65
|
-
function parseKeysEnv(content, fileMtime) {
|
|
66
|
-
// Strip BOM if present.
|
|
67
|
-
const body = content.replace(/^\uFEFF/, "");
|
|
68
|
-
const lines = body.split(/\r?\n/);
|
|
69
|
-
const entries = new Map();
|
|
70
|
-
let malformedCount = 0;
|
|
71
|
-
for (const raw of lines) {
|
|
72
|
-
const line = raw.trim();
|
|
73
|
-
// Skip blanks and comments silently — NOT malformed.
|
|
74
|
-
if (line.length === 0 || line.startsWith("#"))
|
|
75
|
-
continue;
|
|
76
|
-
const eqIdx = line.indexOf("=");
|
|
77
|
-
if (eqIdx <= 0) {
|
|
78
|
-
malformedCount++;
|
|
79
|
-
continue;
|
|
80
|
-
}
|
|
81
|
-
const key = line.slice(0, eqIdx).trim();
|
|
82
|
-
const value = line.slice(eqIdx + 1).trim();
|
|
83
|
-
if (key.length === 0 || value.length === 0) {
|
|
84
|
-
malformedCount++;
|
|
85
|
-
continue;
|
|
86
|
-
}
|
|
87
|
-
// Only accept known provider env var names — anything else is malformed.
|
|
88
|
-
const providerId = ENV_VAR_TO_PROVIDER.get(key);
|
|
89
|
-
if (!providerId) {
|
|
90
|
-
malformedCount++;
|
|
91
|
-
continue;
|
|
92
|
-
}
|
|
93
|
-
entries.set(providerId, { key: value, updatedAt: fileMtime });
|
|
94
|
-
}
|
|
95
|
-
return { entries, malformedCount };
|
|
65
|
+
function getPlatform() {
|
|
66
|
+
return platformOverride ?? process.platform;
|
|
96
67
|
}
|
|
97
68
|
// ---------------------------------------------------------------------------
|
|
98
|
-
//
|
|
69
|
+
// Tier management
|
|
99
70
|
// ---------------------------------------------------------------------------
|
|
100
|
-
function
|
|
101
|
-
|
|
102
|
-
if (loadedForPath === filePath)
|
|
103
|
-
return;
|
|
104
|
-
memoryMap.clear();
|
|
105
|
-
loadedForPath = filePath;
|
|
106
|
-
if (!fsApi.existsSync(filePath))
|
|
107
|
-
return;
|
|
108
|
-
let content;
|
|
109
|
-
let mtime;
|
|
110
|
-
try {
|
|
111
|
-
content = String(fsApi.readFileSync(filePath, "utf8"));
|
|
112
|
-
const stat = fsApi.statSync(filePath);
|
|
113
|
-
mtime = stat.mtime.toISOString();
|
|
114
|
-
}
|
|
115
|
-
catch (err) {
|
|
116
|
-
logger.warn(`[settings-store] could not read keys file: ${err.message}`);
|
|
117
|
-
return;
|
|
118
|
-
}
|
|
119
|
-
const parsed = parseKeysEnv(content, mtime);
|
|
120
|
-
for (const [id, entry] of parsed.entries) {
|
|
121
|
-
memoryMap.set(id, entry);
|
|
122
|
-
}
|
|
123
|
-
if (parsed.malformedCount > 0) {
|
|
124
|
-
logger.warn(`[settings-store] ${parsed.malformedCount} malformed line(s) in ${filePath} were skipped`);
|
|
125
|
-
}
|
|
71
|
+
export function getTier() {
|
|
72
|
+
return currentTier;
|
|
126
73
|
}
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
function writeToDisk() {
|
|
131
|
-
const filePath = getKeysFilePath();
|
|
132
|
-
const dir = path.dirname(filePath);
|
|
133
|
-
// Ensure the config directory exists.
|
|
134
|
-
try {
|
|
135
|
-
if (!fsApi.existsSync(dir)) {
|
|
136
|
-
fsApi.mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
137
|
-
}
|
|
74
|
+
export async function setTier(tier) {
|
|
75
|
+
if (tier === "keychain" && getPlatform() !== "darwin") {
|
|
76
|
+
throw new UnsupportedTierError("macOS Keychain tier is only supported on Darwin");
|
|
138
77
|
}
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
for (const p of PROVIDERS) {
|
|
148
|
-
const entry = memoryMap.get(p.id);
|
|
149
|
-
if (!entry)
|
|
150
|
-
continue;
|
|
151
|
-
lines.push(`${p.envVarName}=${entry.key}`);
|
|
152
|
-
}
|
|
153
|
-
const body = lines.join("\n") + "\n";
|
|
154
|
-
const tmpPath = `${filePath}.${process.pid}.${Date.now()}.tmp`;
|
|
155
|
-
try {
|
|
156
|
-
fsApi.writeFileSync(tmpPath, body, { mode: 0o600 });
|
|
157
|
-
if (process.platform !== "win32") {
|
|
158
|
-
try {
|
|
159
|
-
fsApi.chmodSync(tmpPath, 0o600);
|
|
160
|
-
}
|
|
161
|
-
catch {
|
|
162
|
-
// Windows and some exotic FSs don't support chmod — swallow.
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
fsApi.renameSync(tmpPath, filePath);
|
|
166
|
-
}
|
|
167
|
-
catch (err) {
|
|
168
|
-
// Cleanup tmp on any failure.
|
|
169
|
-
try {
|
|
170
|
-
if (fsApi.existsSync(tmpPath))
|
|
171
|
-
fsApi.unlinkSync(tmpPath);
|
|
78
|
+
if (tier === currentTier)
|
|
79
|
+
return;
|
|
80
|
+
// Move every stored key into the new tier.
|
|
81
|
+
const entries = Array.from(store.entries());
|
|
82
|
+
for (const [provider, entry] of entries) {
|
|
83
|
+
if (tier === "keychain") {
|
|
84
|
+
await keychainAdd(provider, entry.key);
|
|
85
|
+
store.set(provider, { ...entry, tier });
|
|
172
86
|
}
|
|
173
|
-
|
|
174
|
-
|
|
87
|
+
else {
|
|
88
|
+
// Switching browser → keychain → browser is also supported; clear the
|
|
89
|
+
// keychain entry so it doesn't linger.
|
|
90
|
+
await keychainDelete(provider).catch(() => { });
|
|
91
|
+
store.set(provider, { ...entry, tier });
|
|
175
92
|
}
|
|
176
|
-
// Never include the raw key in the error. Re-throw a sanitized error.
|
|
177
|
-
const sanitized = new Error(`[settings-store] atomic write to ${filePath} failed: ${err.message}`);
|
|
178
|
-
logger.error(sanitized.message);
|
|
179
|
-
throw sanitized;
|
|
180
93
|
}
|
|
94
|
+
currentTier = tier;
|
|
181
95
|
}
|
|
182
96
|
// ---------------------------------------------------------------------------
|
|
183
97
|
// Public API — save / read / remove / list
|
|
184
98
|
// ---------------------------------------------------------------------------
|
|
185
|
-
function
|
|
186
|
-
if (!PROVIDERS.some((p) => p.id === provider)) {
|
|
187
|
-
throw new Error(`unknown provider: ${String(provider)}`);
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
export async function saveKey(provider, key) {
|
|
99
|
+
export async function saveKey(provider, key, tier = currentTier) {
|
|
191
100
|
if (!key || typeof key !== "string" || key.trim().length === 0) {
|
|
192
101
|
throw new Error("key must be non-empty string");
|
|
193
102
|
}
|
|
194
|
-
|
|
195
|
-
|
|
103
|
+
if (tier === "keychain" && getPlatform() !== "darwin") {
|
|
104
|
+
throw new UnsupportedTierError("macOS Keychain tier is only supported on Darwin");
|
|
105
|
+
}
|
|
196
106
|
const updatedAt = new Date().toISOString();
|
|
197
|
-
memoryMap.set(provider, { key, updatedAt });
|
|
198
107
|
try {
|
|
199
|
-
|
|
108
|
+
if (tier === "keychain") {
|
|
109
|
+
await keychainAdd(provider, key);
|
|
110
|
+
}
|
|
111
|
+
store.set(provider, { key, updatedAt, tier });
|
|
112
|
+
currentTier = tier;
|
|
113
|
+
return { updatedAt, tier };
|
|
200
114
|
}
|
|
201
115
|
catch (err) {
|
|
202
|
-
//
|
|
203
|
-
|
|
204
|
-
// loadFromDisk will re-populate on next access if needed.
|
|
205
|
-
loadedForPath = null;
|
|
116
|
+
// NEVER log the raw key — only the redacted form.
|
|
117
|
+
logger.error(`[settings-store] saveKey(${provider}, ${redactKey(key)}) failed: ${err.message}`);
|
|
206
118
|
throw err;
|
|
207
119
|
}
|
|
208
|
-
return { updatedAt };
|
|
209
120
|
}
|
|
210
|
-
export
|
|
211
|
-
|
|
212
|
-
loadFromDisk();
|
|
213
|
-
// Favor the live process.env if it has been populated (e.g. after merge).
|
|
214
|
-
const p = PROVIDERS.find((x) => x.id === provider);
|
|
215
|
-
const envVal = process.env[p.envVarName];
|
|
216
|
-
if (envVal && envVal.length > 0)
|
|
217
|
-
return envVal;
|
|
218
|
-
return memoryMap.get(provider)?.key ?? null;
|
|
121
|
+
export function readKey(provider) {
|
|
122
|
+
return store.get(provider)?.key ?? null;
|
|
219
123
|
}
|
|
124
|
+
/** Synchronous accessor used by detectAvailableProviders — safe, same semantics. */
|
|
220
125
|
export function readKeySync(provider) {
|
|
221
|
-
|
|
222
|
-
loadFromDisk();
|
|
223
|
-
const p = PROVIDERS.find((x) => x.id === provider);
|
|
224
|
-
const envVal = process.env[p.envVarName];
|
|
225
|
-
if (envVal && envVal.length > 0)
|
|
226
|
-
return envVal;
|
|
227
|
-
return memoryMap.get(provider)?.key ?? null;
|
|
126
|
+
return readKey(provider);
|
|
228
127
|
}
|
|
128
|
+
/** Has-key predicate exposed for synchronous availability checks. */
|
|
229
129
|
export function hasKeySync(provider) {
|
|
230
|
-
|
|
231
|
-
loadFromDisk();
|
|
232
|
-
const p = PROVIDERS.find((x) => x.id === provider);
|
|
233
|
-
if (process.env[p.envVarName])
|
|
234
|
-
return true;
|
|
235
|
-
return memoryMap.has(provider);
|
|
130
|
+
return store.has(provider);
|
|
236
131
|
}
|
|
237
132
|
export async function removeKey(provider) {
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
if (!memoryMap.has(provider))
|
|
133
|
+
const entry = store.get(provider);
|
|
134
|
+
if (!entry)
|
|
241
135
|
return;
|
|
242
|
-
|
|
243
|
-
|
|
136
|
+
if (entry.tier === "keychain") {
|
|
137
|
+
try {
|
|
138
|
+
await keychainDelete(provider);
|
|
139
|
+
}
|
|
140
|
+
catch (err) {
|
|
141
|
+
logger.warn(`[settings-store] keychain remove for ${provider} failed: ${err.message}`);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
store.delete(provider);
|
|
244
145
|
}
|
|
245
146
|
export function listKeys() {
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
const e = memoryMap.get(id);
|
|
147
|
+
const read = (p) => {
|
|
148
|
+
const e = store.get(p);
|
|
249
149
|
return e
|
|
250
|
-
? { stored: true, updatedAt: e.updatedAt }
|
|
251
|
-
: { stored: false, updatedAt: null };
|
|
252
|
-
};
|
|
253
|
-
return {
|
|
254
|
-
anthropic: read("anthropic"),
|
|
255
|
-
openai: read("openai"),
|
|
256
|
-
openrouter: read("openrouter"),
|
|
150
|
+
? { stored: true, updatedAt: e.updatedAt, tier: e.tier }
|
|
151
|
+
: { stored: false, updatedAt: null, tier: currentTier };
|
|
257
152
|
};
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
//
|
|
261
|
-
//
|
|
262
|
-
//
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
153
|
+
return { anthropic: read("anthropic"), openrouter: read("openrouter") };
|
|
154
|
+
}
|
|
155
|
+
// ---------------------------------------------------------------------------
|
|
156
|
+
// Darwin Keychain bridge via `security` binary.
|
|
157
|
+
// ---------------------------------------------------------------------------
|
|
158
|
+
function keychainAdd(provider, key) {
|
|
159
|
+
return new Promise((resolve, reject) => {
|
|
160
|
+
const args = [
|
|
161
|
+
"add-generic-password",
|
|
162
|
+
"-s",
|
|
163
|
+
`vskill-${provider}`,
|
|
164
|
+
"-a",
|
|
165
|
+
"vskill-user",
|
|
166
|
+
"-w",
|
|
167
|
+
key,
|
|
168
|
+
"-U",
|
|
169
|
+
];
|
|
170
|
+
const opts = { stdio: ["ignore", "pipe", "pipe"] };
|
|
171
|
+
const child = spawn("security", args, opts);
|
|
172
|
+
let stderr = "";
|
|
173
|
+
child.stderr?.on("data", (d) => (stderr += String(d)));
|
|
174
|
+
child.on("error", (err) => reject(err));
|
|
175
|
+
child.on("close", (code) => {
|
|
176
|
+
if (code === 0)
|
|
177
|
+
resolve();
|
|
178
|
+
else
|
|
179
|
+
reject(new Error(`security add-generic-password exited ${code}: ${stderr.slice(0, 200)}`));
|
|
180
|
+
});
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
function keychainDelete(provider) {
|
|
184
|
+
return new Promise((resolve, reject) => {
|
|
185
|
+
const child = spawn("security", ["delete-generic-password", "-s", `vskill-${provider}`, "-a", "vskill-user"], { stdio: ["ignore", "pipe", "pipe"] });
|
|
186
|
+
child.on("error", (err) => reject(err));
|
|
187
|
+
child.on("close", (code) => {
|
|
188
|
+
if (code === 0 || code === 44)
|
|
189
|
+
resolve(); // 44 = not found, idempotent
|
|
190
|
+
else
|
|
191
|
+
resolve(); // be lenient — delete must not block removeKey
|
|
192
|
+
});
|
|
193
|
+
});
|
|
294
194
|
}
|
|
295
195
|
//# sourceMappingURL=settings-store.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"settings-store.js","sourceRoot":"","sources":["../../src/eval-server/settings-store.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,
|
|
1
|
+
{"version":3,"file":"settings-store.js","sourceRoot":"","sources":["../../src/eval-server/settings-store.ts"],"names":[],"mappings":"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"}
|