vskill 0.5.104 → 0.5.106
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 +123 -2
- package/agents.json +1 -1
- package/dist/agents/agents-registry.d.ts +0 -1
- package/dist/agents/agents-registry.js +10 -30
- package/dist/agents/agents-registry.js.map +1 -1
- package/dist/api/client.d.ts +21 -0
- package/dist/api/client.js +39 -5
- package/dist/api/client.js.map +1 -1
- package/dist/commands/diff.d.ts +2 -5
- package/dist/commands/diff.js +82 -117
- package/dist/commands/diff.js.map +1 -1
- package/dist/commands/eval/serve.js +4 -0
- package/dist/commands/eval/serve.js.map +1 -1
- package/dist/commands/keys.d.ts +14 -0
- package/dist/commands/keys.js +166 -0
- package/dist/commands/keys.js.map +1 -0
- package/dist/commands/masked-stdin.d.ts +14 -0
- package/dist/commands/masked-stdin.js +79 -0
- package/dist/commands/masked-stdin.js.map +1 -0
- package/dist/commands/skill.d.ts +3 -29
- package/dist/commands/skill.js +6 -32
- package/dist/commands/skill.js.map +1 -1
- package/dist/eval/anthropic-catalog.d.ts +49 -0
- package/dist/eval/anthropic-catalog.js +238 -0
- package/dist/eval/anthropic-catalog.js.map +1 -0
- package/dist/eval/llm.d.ts +1 -1
- package/dist/eval/llm.js +68 -10
- package/dist/eval/llm.js.map +1 -1
- package/dist/eval/mcp-detector.js +24 -3
- package/dist/eval/mcp-detector.js.map +1 -1
- package/dist/eval/model-resolver.d.ts +39 -0
- package/dist/eval/model-resolver.js +94 -0
- package/dist/eval/model-resolver.js.map +1 -0
- package/dist/eval/pricing.js +42 -16
- package/dist/eval/pricing.js.map +1 -1
- package/dist/eval-server/api-routes.d.ts +9 -0
- package/dist/eval-server/api-routes.js +241 -73
- package/dist/eval-server/api-routes.js.map +1 -1
- package/dist/eval-server/authoring-routes.js +21 -1
- package/dist/eval-server/authoring-routes.js.map +1 -1
- package/dist/eval-server/boot-preflight.js +8 -10
- package/dist/eval-server/boot-preflight.js.map +1 -1
- package/dist/eval-server/darwin-migrator.d.ts +57 -0
- package/dist/eval-server/darwin-migrator.js +169 -0
- package/dist/eval-server/darwin-migrator.js.map +1 -0
- package/dist/eval-server/eval-server.d.ts +1 -0
- package/dist/eval-server/eval-server.js +21 -0
- package/dist/eval-server/eval-server.js.map +1 -1
- package/dist/eval-server/integration-routes.js +7 -0
- package/dist/eval-server/integration-routes.js.map +1 -1
- package/dist/eval-server/platform-proxy.d.ts +18 -0
- package/dist/eval-server/platform-proxy.js +153 -0
- package/dist/eval-server/platform-proxy.js.map +1 -0
- package/dist/eval-server/providers.d.ts +7 -12
- package/dist/eval-server/providers.js +13 -15
- package/dist/eval-server/providers.js.map +1 -1
- package/dist/eval-server/settings-store.d.ts +31 -26
- package/dist/eval-server/settings-store.js +246 -143
- package/dist/eval-server/settings-store.js.map +1 -1
- package/dist/eval-server/skill-create-routes.js +18 -0
- package/dist/eval-server/skill-create-routes.js.map +1 -1
- package/dist/eval-server/skill-name-resolver.d.ts +35 -0
- package/dist/eval-server/skill-name-resolver.js +146 -0
- package/dist/eval-server/skill-name-resolver.js.map +1 -0
- package/dist/eval-ui/assets/{CommandPalette-DiPALzlG.js → CommandPalette-COqdrmRl.js} +1 -1
- package/dist/eval-ui/assets/CreateSkillPage-C3IjO8es.js +12 -0
- package/dist/eval-ui/assets/UpdateDropdown-DnKKMBBN.js +1 -0
- package/dist/eval-ui/assets/index-Dmja1p3A.css +1 -0
- package/dist/eval-ui/assets/index-KIcQ5e5a.js +102 -0
- package/dist/eval-ui/index.html +2 -2
- package/dist/first-run-onboarding.d.ts +19 -0
- package/dist/first-run-onboarding.js +104 -0
- package/dist/first-run-onboarding.js.map +1 -0
- package/dist/index.js +18 -0
- package/dist/index.js.map +1 -1
- package/dist/installer/canonical.js +12 -13
- package/dist/installer/canonical.js.map +1 -1
- package/dist/utils/resolve-binary.js +7 -8
- package/dist/utils/resolve-binary.js.map +1 -1
- package/package.json +5 -2
- package/dist/eval-ui/assets/CreateSkillPage-BMrFELep.js +0 -12
- package/dist/eval-ui/assets/UpdateDropdown-Bj8kZzuR.js +0 -1
- package/dist/eval-ui/assets/_shimNode-D3bBqrAh.js +0 -1
- package/dist/eval-ui/assets/index-BSPDkfZG.js +0 -102
- package/dist/eval-ui/assets/index-C0Gc_4KC.css +0 -1
- package/dist/eval-ui/assets/resolve-binary-DIxhrZ6O.js +0 -2
|
@@ -1,39 +1,44 @@
|
|
|
1
|
-
import * as
|
|
2
|
-
|
|
3
|
-
export type Provider =
|
|
4
|
-
export type
|
|
1
|
+
import * as nodeFs from "node:fs";
|
|
2
|
+
import { type ProviderId } from "./providers.js";
|
|
3
|
+
export type Provider = ProviderId;
|
|
4
|
+
export type { ProviderId } from "./providers.js";
|
|
5
5
|
export interface KeyMetadata {
|
|
6
6
|
stored: boolean;
|
|
7
7
|
updatedAt: string | null;
|
|
8
|
-
tier: Tier;
|
|
9
8
|
}
|
|
10
9
|
export interface ListKeysResponse {
|
|
11
10
|
anthropic: KeyMetadata;
|
|
11
|
+
openai: KeyMetadata;
|
|
12
12
|
openrouter: KeyMetadata;
|
|
13
13
|
}
|
|
14
|
-
export
|
|
15
|
-
constructor(message: string);
|
|
16
|
-
}
|
|
17
|
-
export declare function redactKey(key: string): string;
|
|
18
|
-
type Logger = {
|
|
14
|
+
export interface Logger {
|
|
19
15
|
warn: (msg: string) => void;
|
|
20
16
|
error: (msg: string) => void;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
17
|
+
}
|
|
18
|
+
interface FsFacade {
|
|
19
|
+
writeFileSync: typeof nodeFs.writeFileSync;
|
|
20
|
+
renameSync: typeof nodeFs.renameSync;
|
|
21
|
+
chmodSync: typeof nodeFs.chmodSync;
|
|
22
|
+
readFileSync: typeof nodeFs.readFileSync;
|
|
23
|
+
existsSync: typeof nodeFs.existsSync;
|
|
24
|
+
unlinkSync: typeof nodeFs.unlinkSync;
|
|
25
|
+
mkdirSync: typeof nodeFs.mkdirSync;
|
|
26
|
+
statSync: typeof nodeFs.statSync;
|
|
27
|
+
}
|
|
28
|
+
export declare function getKeysFilePath(): string;
|
|
29
|
+
export declare function redactKey(key: string): string;
|
|
30
|
+
export declare function saveKey(provider: ProviderId, key: string): Promise<{
|
|
29
31
|
updatedAt: string;
|
|
30
|
-
tier: Tier;
|
|
31
32
|
}>;
|
|
32
|
-
export declare function readKey(provider:
|
|
33
|
-
|
|
34
|
-
export declare function
|
|
35
|
-
|
|
36
|
-
export declare function hasKeySync(provider: Provider): boolean;
|
|
37
|
-
export declare function removeKey(provider: Provider): Promise<void>;
|
|
33
|
+
export declare function readKey(provider: ProviderId): string | null;
|
|
34
|
+
export declare function readKeySync(provider: ProviderId): string | null;
|
|
35
|
+
export declare function hasKeySync(provider: ProviderId): boolean;
|
|
36
|
+
export declare function removeKey(provider: ProviderId): Promise<void>;
|
|
38
37
|
export declare function listKeys(): ListKeysResponse;
|
|
39
|
-
export
|
|
38
|
+
export declare function mergeStoredKeysIntoEnv(): void;
|
|
39
|
+
export interface ResetOptions {
|
|
40
|
+
logger?: Logger;
|
|
41
|
+
fs?: FsFacade;
|
|
42
|
+
configDir?: string | null;
|
|
43
|
+
}
|
|
44
|
+
export declare function resetSettingsStore(opts?: ResetOptions): void;
|
|
@@ -1,195 +1,298 @@
|
|
|
1
1
|
// ---------------------------------------------------------------------------
|
|
2
|
-
// settings-store.ts —
|
|
2
|
+
// settings-store.ts — File-backed credential store for vSkill Studio.
|
|
3
3
|
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
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.
|
|
4
|
+
// Single on-disk file at `<configDir>/keys.env` (default configDir:
|
|
5
|
+
// `~/.vskill`, overridable via VSKILL_CONFIG_DIR). KEY=VALUE dotenv format.
|
|
6
|
+
// Atomic write via temp-file + rename; POSIX writes explicit 0600.
|
|
10
7
|
//
|
|
11
8
|
// Contract:
|
|
12
|
-
// -
|
|
13
|
-
//
|
|
14
|
-
// - `
|
|
15
|
-
//
|
|
16
|
-
//
|
|
17
|
-
//
|
|
9
|
+
// - Raw keys NEVER appear in any log, error message, toast, or stdout.
|
|
10
|
+
// Only `redactKey()` output (`****<last-4>`) may be emitted.
|
|
11
|
+
// - `readKey()` consults `process.env` FIRST, then the raw-key `memoryMap`.
|
|
12
|
+
// After `mergeStoredKeysIntoEnv()` the `memoryMap` is cleared; subsequent
|
|
13
|
+
// reads hit process.env directly, minimizing plaintext dwell time.
|
|
14
|
+
// - `listKeys()` returns { stored, updatedAt } metadata only. A parallel
|
|
15
|
+
// `metadataMap` holds `{ updatedAt }` and SURVIVES merge, so listKeys()
|
|
16
|
+
// stays truthful across a boot cycle without keeping key bytes around.
|
|
17
|
+
// - `removeKey()` is idempotent; clears memoryMap, metadataMap, and the
|
|
18
|
+
// process.env entry (post-merge, env is where the live key lives).
|
|
19
|
+
// - Malformed lines in keys.env never crash parse — they are skipped with
|
|
20
|
+
// exactly ONE aggregated warning.
|
|
18
21
|
//
|
|
19
|
-
// Tests inject
|
|
20
|
-
//
|
|
21
|
-
|
|
22
|
-
import * as
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
//
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
super(message);
|
|
30
|
-
this.name = "UnsupportedTierError";
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
export function redactKey(key) {
|
|
34
|
-
if (!key || key.length <= 4)
|
|
35
|
-
return "****";
|
|
36
|
-
return "****" + key.slice(-4);
|
|
37
|
-
}
|
|
38
|
-
const store = new Map();
|
|
39
|
-
let currentTier = "browser";
|
|
40
|
-
let logger = {
|
|
22
|
+
// Tests inject `{logger, fs, configDir}` via `resetSettingsStore(opts)`.
|
|
23
|
+
// ---------------------------------------------------------------------------
|
|
24
|
+
import * as nodeFs from "node:fs";
|
|
25
|
+
import * as os from "node:os";
|
|
26
|
+
import * as path from "node:path";
|
|
27
|
+
import { PROVIDERS, } from "./providers.js";
|
|
28
|
+
// ---------------------------------------------------------------------------
|
|
29
|
+
// Module-level state. Tests reset via `resetSettingsStore()`.
|
|
30
|
+
// ---------------------------------------------------------------------------
|
|
31
|
+
const defaultLogger = {
|
|
41
32
|
warn: (m) => console.warn(m),
|
|
42
33
|
error: (m) => console.error(m),
|
|
43
34
|
};
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
35
|
+
// Wrappers read through the nodeFs namespace at CALL time so test files that
|
|
36
|
+
// mock `node:fs` without exporting every member (e.g. comparison-sse-events
|
|
37
|
+
// which only mocks existsSync/readFileSync/writeFileSync) don't fail at
|
|
38
|
+
// module-load time. Direct property access happens only inside the call.
|
|
39
|
+
const defaultFs = {
|
|
40
|
+
writeFileSync: (...args) => nodeFs.writeFileSync(...args),
|
|
41
|
+
renameSync: (...args) => nodeFs.renameSync(...args),
|
|
42
|
+
chmodSync: (...args) => nodeFs.chmodSync(...args),
|
|
43
|
+
readFileSync: ((...args) => nodeFs.readFileSync(...args)),
|
|
44
|
+
existsSync: (...args) => nodeFs.existsSync(...args),
|
|
45
|
+
unlinkSync: (...args) => nodeFs.unlinkSync(...args),
|
|
46
|
+
mkdirSync: ((...args) => nodeFs.mkdirSync(...args)),
|
|
47
|
+
statSync: ((...args) => nodeFs.statSync(...args)),
|
|
48
|
+
};
|
|
49
|
+
let logger = defaultLogger;
|
|
50
|
+
let fsImpl = defaultFs;
|
|
51
|
+
let configDirOverride = null;
|
|
52
|
+
const memoryMap = new Map();
|
|
53
|
+
// metadataMap retains `{ updatedAt }` after mergeStoredKeysIntoEnv() clears
|
|
54
|
+
// the raw-key memoryMap. Keeps listKeys() truthful across a boot cycle without
|
|
55
|
+
// extending plaintext dwell time.
|
|
56
|
+
const metadataMap = new Map();
|
|
57
|
+
let loaded = false;
|
|
58
|
+
// ---------------------------------------------------------------------------
|
|
59
|
+
// Path resolution
|
|
60
|
+
// ---------------------------------------------------------------------------
|
|
61
|
+
function resolveConfigDir() {
|
|
62
|
+
if (configDirOverride)
|
|
63
|
+
return configDirOverride;
|
|
64
|
+
const fromEnv = process.env.VSKILL_CONFIG_DIR;
|
|
65
|
+
if (fromEnv && fromEnv.length > 0)
|
|
66
|
+
return fromEnv;
|
|
67
|
+
return path.join(os.homedir(), ".vskill");
|
|
48
68
|
}
|
|
49
|
-
export function
|
|
50
|
-
|
|
69
|
+
export function getKeysFilePath() {
|
|
70
|
+
return path.join(resolveConfigDir(), "keys.env");
|
|
51
71
|
}
|
|
52
|
-
|
|
53
|
-
|
|
72
|
+
// ---------------------------------------------------------------------------
|
|
73
|
+
// Redaction
|
|
74
|
+
// ---------------------------------------------------------------------------
|
|
75
|
+
export function redactKey(key) {
|
|
76
|
+
if (!key || key.length <= 4)
|
|
77
|
+
return "****";
|
|
78
|
+
return "****" + key.slice(-4);
|
|
54
79
|
}
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
80
|
+
// ---------------------------------------------------------------------------
|
|
81
|
+
// Parser — lenient, single aggregated warning
|
|
82
|
+
// ---------------------------------------------------------------------------
|
|
83
|
+
function parseFile(contents) {
|
|
84
|
+
const entries = new Map();
|
|
85
|
+
let malformedCount = 0;
|
|
86
|
+
// Strip BOM.
|
|
87
|
+
const stripped = contents.replace(/^\uFEFF/, "");
|
|
88
|
+
const lines = stripped.split(/\r?\n/);
|
|
89
|
+
const envToId = new Map(PROVIDERS.map((p) => [p.envVarName, p.id]));
|
|
90
|
+
for (const rawLine of lines) {
|
|
91
|
+
const line = rawLine.trim();
|
|
92
|
+
if (line.length === 0)
|
|
93
|
+
continue;
|
|
94
|
+
if (line.startsWith("#"))
|
|
95
|
+
continue;
|
|
96
|
+
try {
|
|
97
|
+
const eq = line.indexOf("=");
|
|
98
|
+
if (eq <= 0) {
|
|
99
|
+
malformedCount++;
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
const name = line.slice(0, eq).trim();
|
|
103
|
+
const value = line.slice(eq + 1).trim();
|
|
104
|
+
if (name.length === 0 || value.length === 0) {
|
|
105
|
+
malformedCount++;
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
const pid = envToId.get(name);
|
|
109
|
+
if (!pid) {
|
|
110
|
+
// Unknown env var name — skip silently (not "malformed", just
|
|
111
|
+
// unrelated). Do NOT count toward malformedCount.
|
|
112
|
+
continue;
|
|
113
|
+
}
|
|
114
|
+
entries.set(pid, { key: value, updatedAt: new Date().toISOString() });
|
|
115
|
+
}
|
|
116
|
+
catch {
|
|
117
|
+
malformedCount++;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
return { entries, malformedCount };
|
|
64
121
|
}
|
|
65
|
-
function
|
|
66
|
-
|
|
122
|
+
function loadIfNeeded() {
|
|
123
|
+
if (loaded)
|
|
124
|
+
return;
|
|
125
|
+
loaded = true;
|
|
126
|
+
const filePath = getKeysFilePath();
|
|
127
|
+
if (!fsImpl.existsSync(filePath))
|
|
128
|
+
return;
|
|
129
|
+
try {
|
|
130
|
+
const contents = fsImpl.readFileSync(filePath, "utf8");
|
|
131
|
+
const { entries, malformedCount } = parseFile(contents);
|
|
132
|
+
for (const [pid, entry] of entries)
|
|
133
|
+
memoryMap.set(pid, entry);
|
|
134
|
+
if (malformedCount > 0) {
|
|
135
|
+
logger.warn(`[settings-store] ${malformedCount} malformed line(s) in ${filePath} were skipped`);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
catch (err) {
|
|
139
|
+
logger.warn(`[settings-store] failed to read ${filePath}: ${err.message}`);
|
|
140
|
+
}
|
|
67
141
|
}
|
|
68
142
|
// ---------------------------------------------------------------------------
|
|
69
|
-
//
|
|
143
|
+
// Serialization
|
|
70
144
|
// ---------------------------------------------------------------------------
|
|
71
|
-
|
|
72
|
-
|
|
145
|
+
function serialize(entries) {
|
|
146
|
+
const lines = [
|
|
147
|
+
"# vskill credentials — do not commit. Managed by `vskill keys` or Skill Studio Settings.",
|
|
148
|
+
];
|
|
149
|
+
for (const p of PROVIDERS) {
|
|
150
|
+
const entry = entries.get(p.id);
|
|
151
|
+
if (entry)
|
|
152
|
+
lines.push(`${p.envVarName}=${entry.key}`);
|
|
153
|
+
}
|
|
154
|
+
return lines.join("\n") + "\n";
|
|
73
155
|
}
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
156
|
+
function atomicWrite(contents) {
|
|
157
|
+
const filePath = getKeysFilePath();
|
|
158
|
+
const dir = path.dirname(filePath);
|
|
159
|
+
fsImpl.mkdirSync(dir, { recursive: true });
|
|
160
|
+
const tmpPath = `${filePath}.tmp-${process.pid}-${Date.now()}`;
|
|
161
|
+
try {
|
|
162
|
+
fsImpl.writeFileSync(tmpPath, contents, "utf8");
|
|
163
|
+
if (process.platform !== "win32") {
|
|
164
|
+
try {
|
|
165
|
+
fsImpl.chmodSync(tmpPath, 0o600);
|
|
166
|
+
}
|
|
167
|
+
catch {
|
|
168
|
+
/* non-fatal; rename will still proceed */
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
fsImpl.renameSync(tmpPath, filePath);
|
|
77
172
|
}
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
if (tier === "keychain") {
|
|
84
|
-
await keychainAdd(provider, entry.key);
|
|
85
|
-
store.set(provider, { ...entry, tier });
|
|
173
|
+
catch (err) {
|
|
174
|
+
// Clean up tmp if present.
|
|
175
|
+
try {
|
|
176
|
+
if (fsImpl.existsSync(tmpPath))
|
|
177
|
+
fsImpl.unlinkSync(tmpPath);
|
|
86
178
|
}
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
// keychain entry so it doesn't linger.
|
|
90
|
-
await keychainDelete(provider).catch(() => { });
|
|
91
|
-
store.set(provider, { ...entry, tier });
|
|
179
|
+
catch {
|
|
180
|
+
/* swallow */
|
|
92
181
|
}
|
|
182
|
+
throw err;
|
|
93
183
|
}
|
|
94
|
-
currentTier = tier;
|
|
95
184
|
}
|
|
96
185
|
// ---------------------------------------------------------------------------
|
|
97
186
|
// Public API — save / read / remove / list
|
|
98
187
|
// ---------------------------------------------------------------------------
|
|
99
|
-
export async function saveKey(provider, key
|
|
188
|
+
export async function saveKey(provider, key) {
|
|
100
189
|
if (!key || typeof key !== "string" || key.trim().length === 0) {
|
|
101
190
|
throw new Error("key must be non-empty string");
|
|
102
191
|
}
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
}
|
|
192
|
+
loadIfNeeded();
|
|
193
|
+
// Build the full entry set: current memory snapshot + new entry.
|
|
106
194
|
const updatedAt = new Date().toISOString();
|
|
195
|
+
const next = new Map(memoryMap);
|
|
196
|
+
next.set(provider, { key, updatedAt });
|
|
107
197
|
try {
|
|
108
|
-
|
|
109
|
-
await keychainAdd(provider, key);
|
|
110
|
-
}
|
|
111
|
-
store.set(provider, { key, updatedAt, tier });
|
|
112
|
-
currentTier = tier;
|
|
113
|
-
return { updatedAt, tier };
|
|
198
|
+
atomicWrite(serialize(next));
|
|
114
199
|
}
|
|
115
200
|
catch (err) {
|
|
116
|
-
// NEVER
|
|
117
|
-
|
|
118
|
-
|
|
201
|
+
// NEVER include the raw key in the error message.
|
|
202
|
+
const redacted = redactKey(key);
|
|
203
|
+
logger.error(`[settings-store] saveKey(${provider}, ${redacted}) failed: ${err.message}`);
|
|
204
|
+
throw new Error(`saveKey(${provider}, ${redacted}) failed: ${err.message}`);
|
|
119
205
|
}
|
|
206
|
+
memoryMap.set(provider, { key, updatedAt });
|
|
207
|
+
metadataMap.set(provider, { updatedAt });
|
|
208
|
+
return { updatedAt };
|
|
120
209
|
}
|
|
121
210
|
export function readKey(provider) {
|
|
122
|
-
|
|
211
|
+
loadIfNeeded();
|
|
212
|
+
const descriptor = PROVIDERS.find((p) => p.id === provider);
|
|
213
|
+
if (descriptor) {
|
|
214
|
+
const fromEnv = process.env[descriptor.envVarName];
|
|
215
|
+
if (fromEnv && fromEnv.length > 0)
|
|
216
|
+
return fromEnv;
|
|
217
|
+
}
|
|
218
|
+
return memoryMap.get(provider)?.key ?? null;
|
|
123
219
|
}
|
|
124
|
-
/** Synchronous accessor used by detectAvailableProviders — safe, same semantics. */
|
|
125
220
|
export function readKeySync(provider) {
|
|
126
221
|
return readKey(provider);
|
|
127
222
|
}
|
|
128
|
-
/** Has-key predicate exposed for synchronous availability checks. */
|
|
129
223
|
export function hasKeySync(provider) {
|
|
130
|
-
return
|
|
224
|
+
return readKey(provider) !== null;
|
|
131
225
|
}
|
|
132
226
|
export async function removeKey(provider) {
|
|
133
|
-
|
|
134
|
-
if
|
|
227
|
+
loadIfNeeded();
|
|
228
|
+
// Idempotent: short-circuit only if neither map has the provider AND the
|
|
229
|
+
// on-disk file won't have it either. Post-merge, memoryMap is empty but
|
|
230
|
+
// metadataMap is the source of truth for "was it stored?".
|
|
231
|
+
if (!memoryMap.has(provider) && !metadataMap.has(provider))
|
|
135
232
|
return;
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
catch (err) {
|
|
141
|
-
logger.warn(`[settings-store] keychain remove for ${provider} failed: ${err.message}`);
|
|
142
|
-
}
|
|
233
|
+
const next = new Map(memoryMap);
|
|
234
|
+
next.delete(provider);
|
|
235
|
+
try {
|
|
236
|
+
atomicWrite(serialize(next));
|
|
143
237
|
}
|
|
144
|
-
|
|
238
|
+
catch (err) {
|
|
239
|
+
logger.error(`[settings-store] removeKey(${provider}) failed: ${err.message}`);
|
|
240
|
+
throw err;
|
|
241
|
+
}
|
|
242
|
+
memoryMap.delete(provider);
|
|
243
|
+
metadataMap.delete(provider);
|
|
244
|
+
// Clear the process.env copy too — post-merge, this is where the live key
|
|
245
|
+
// lives. Without this, a "remove" followed by a readKey() would still
|
|
246
|
+
// resolve the removed provider from process.env.
|
|
247
|
+
const descriptor = PROVIDERS.find((p) => p.id === provider);
|
|
248
|
+
if (descriptor)
|
|
249
|
+
delete process.env[descriptor.envVarName];
|
|
145
250
|
}
|
|
146
251
|
export function listKeys() {
|
|
252
|
+
loadIfNeeded();
|
|
147
253
|
const read = (p) => {
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
254
|
+
// memoryMap wins if present (freshest), else fall back to retained
|
|
255
|
+
// metadata from a prior mergeStoredKeysIntoEnv() call.
|
|
256
|
+
const live = memoryMap.get(p);
|
|
257
|
+
if (live)
|
|
258
|
+
return { stored: true, updatedAt: live.updatedAt };
|
|
259
|
+
const meta = metadataMap.get(p);
|
|
260
|
+
if (meta)
|
|
261
|
+
return { stored: true, updatedAt: meta.updatedAt };
|
|
262
|
+
return { stored: false, updatedAt: null };
|
|
263
|
+
};
|
|
264
|
+
return {
|
|
265
|
+
anthropic: read("anthropic"),
|
|
266
|
+
openai: read("openai"),
|
|
267
|
+
openrouter: read("openrouter"),
|
|
152
268
|
};
|
|
153
|
-
return { anthropic: read("anthropic"), openrouter: read("openrouter") };
|
|
154
269
|
}
|
|
155
270
|
// ---------------------------------------------------------------------------
|
|
156
|
-
//
|
|
157
|
-
// ---------------------------------------------------------------------------
|
|
158
|
-
function
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
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
|
-
});
|
|
271
|
+
// Boot-time env merge
|
|
272
|
+
// ---------------------------------------------------------------------------
|
|
273
|
+
export function mergeStoredKeysIntoEnv() {
|
|
274
|
+
loadIfNeeded();
|
|
275
|
+
for (const p of PROVIDERS) {
|
|
276
|
+
const entry = memoryMap.get(p.id);
|
|
277
|
+
if (!entry)
|
|
278
|
+
continue;
|
|
279
|
+
// Nullish coalescing: real env vars always win.
|
|
280
|
+
if (process.env[p.envVarName] === undefined) {
|
|
281
|
+
process.env[p.envVarName] = entry.key;
|
|
282
|
+
}
|
|
283
|
+
// Retain metadata so listKeys() can report `stored: true` post-merge
|
|
284
|
+
// without keeping the raw key plaintext around.
|
|
285
|
+
metadataMap.set(p.id, { updatedAt: entry.updatedAt });
|
|
286
|
+
}
|
|
287
|
+
// Shrink plaintext dwell time.
|
|
288
|
+
memoryMap.clear();
|
|
182
289
|
}
|
|
183
|
-
function
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
else
|
|
191
|
-
resolve(); // be lenient — delete must not block removeKey
|
|
192
|
-
});
|
|
193
|
-
});
|
|
290
|
+
export function resetSettingsStore(opts = {}) {
|
|
291
|
+
memoryMap.clear();
|
|
292
|
+
metadataMap.clear();
|
|
293
|
+
loaded = false;
|
|
294
|
+
logger = opts.logger ?? defaultLogger;
|
|
295
|
+
fsImpl = opts.fs ?? defaultFs;
|
|
296
|
+
configDirOverride = opts.configDir ?? null;
|
|
194
297
|
}
|
|
195
298
|
//# 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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"}
|
|
@@ -1030,6 +1030,24 @@ export function registerSkillCreateRoutes(router, root) {
|
|
|
1030
1030
|
if (ac.signal.aborted)
|
|
1031
1031
|
return;
|
|
1032
1032
|
const result = attachSuggestedPlugin(parsed, root);
|
|
1033
|
+
// 0711: emit provenance as a SEPARATE SSE event before `done` so the
|
|
1034
|
+
// GenerateSkillResult schema stays clean (parity tests assert on the
|
|
1035
|
+
// legacy shape). The UI's useCreateSkill listens for the `provenance`
|
|
1036
|
+
// event and stamps aiMeta. Best-effort — never blocks generation.
|
|
1037
|
+
if (wantsSSE && (resolved.provider === "anthropic" || resolved.provider === "claude-cli")) {
|
|
1038
|
+
try {
|
|
1039
|
+
const { resolveAnthropicModel } = await import("../eval/model-resolver.js");
|
|
1040
|
+
const r = resolveAnthropicModel(resolved.model);
|
|
1041
|
+
sendSSE(res, "provenance", {
|
|
1042
|
+
resolvedModelId: r.resolvedId || null,
|
|
1043
|
+
snapshotDate: r.snapshotDate,
|
|
1044
|
+
source: r.source,
|
|
1045
|
+
});
|
|
1046
|
+
}
|
|
1047
|
+
catch {
|
|
1048
|
+
/* provenance is best-effort; never block generation */
|
|
1049
|
+
}
|
|
1050
|
+
}
|
|
1033
1051
|
if (wantsSSE)
|
|
1034
1052
|
sendSSEDone(res, result);
|
|
1035
1053
|
else
|