@evermore.work/adapter-gemini-local 2026.509.0-canary.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.
Files changed (61) hide show
  1. package/dist/cli/format-event.d.ts +2 -0
  2. package/dist/cli/format-event.d.ts.map +1 -0
  3. package/dist/cli/format-event.js +218 -0
  4. package/dist/cli/format-event.js.map +1 -0
  5. package/dist/cli/index.d.ts +2 -0
  6. package/dist/cli/index.d.ts.map +1 -0
  7. package/dist/cli/index.js +2 -0
  8. package/dist/cli/index.js.map +1 -0
  9. package/dist/index.d.ts +12 -0
  10. package/dist/index.d.ts.map +1 -0
  11. package/dist/index.js +58 -0
  12. package/dist/index.js.map +1 -0
  13. package/dist/server/execute.d.ts +3 -0
  14. package/dist/server/execute.d.ts.map +1 -0
  15. package/dist/server/execute.js +513 -0
  16. package/dist/server/execute.js.map +1 -0
  17. package/dist/server/execute.remote.test.d.ts +2 -0
  18. package/dist/server/execute.remote.test.d.ts.map +1 -0
  19. package/dist/server/execute.remote.test.js +285 -0
  20. package/dist/server/execute.remote.test.js.map +1 -0
  21. package/dist/server/index.d.ts +7 -0
  22. package/dist/server/index.d.ts.map +1 -0
  23. package/dist/server/index.js +62 -0
  24. package/dist/server/index.js.map +1 -0
  25. package/dist/server/parse.d.ts +38 -0
  26. package/dist/server/parse.d.ts.map +1 -0
  27. package/dist/server/parse.js +260 -0
  28. package/dist/server/parse.js.map +1 -0
  29. package/dist/server/parse.test.d.ts +2 -0
  30. package/dist/server/parse.test.d.ts.map +1 -0
  31. package/dist/server/parse.test.js +117 -0
  32. package/dist/server/parse.test.js.map +1 -0
  33. package/dist/server/skills.d.ts +8 -0
  34. package/dist/server/skills.d.ts.map +1 -0
  35. package/dist/server/skills.js +69 -0
  36. package/dist/server/skills.js.map +1 -0
  37. package/dist/server/test.d.ts +3 -0
  38. package/dist/server/test.d.ts.map +1 -0
  39. package/dist/server/test.js +247 -0
  40. package/dist/server/test.js.map +1 -0
  41. package/dist/server/utils.d.ts +2 -0
  42. package/dist/server/utils.d.ts.map +1 -0
  43. package/dist/server/utils.js +7 -0
  44. package/dist/server/utils.js.map +1 -0
  45. package/dist/ui/build-config.d.ts +3 -0
  46. package/dist/ui/build-config.d.ts.map +1 -0
  47. package/dist/ui/build-config.js +80 -0
  48. package/dist/ui/build-config.js.map +1 -0
  49. package/dist/ui/index.d.ts +3 -0
  50. package/dist/ui/index.d.ts.map +1 -0
  51. package/dist/ui/index.js +3 -0
  52. package/dist/ui/index.js.map +1 -0
  53. package/dist/ui/parse-stdout.d.ts +3 -0
  54. package/dist/ui/parse-stdout.d.ts.map +1 -0
  55. package/dist/ui/parse-stdout.js +261 -0
  56. package/dist/ui/parse-stdout.js.map +1 -0
  57. package/dist/ui/parse-stdout.test.d.ts +2 -0
  58. package/dist/ui/parse-stdout.test.d.ts.map +1 -0
  59. package/dist/ui/parse-stdout.test.js +67 -0
  60. package/dist/ui/parse-stdout.test.js.map +1 -0
  61. package/package.json +54 -0
@@ -0,0 +1,260 @@
1
+ import { asNumber, asString, parseJson, parseObject } from "@evermore.work/adapter-utils/server-utils";
2
+ function collectMessageText(message) {
3
+ if (typeof message === "string") {
4
+ const trimmed = message.trim();
5
+ return trimmed ? [trimmed] : [];
6
+ }
7
+ const record = parseObject(message);
8
+ const direct = asString(record.text, "").trim();
9
+ const lines = direct ? [direct] : [];
10
+ const content = Array.isArray(record.content) ? record.content : [];
11
+ for (const partRaw of content) {
12
+ const part = parseObject(partRaw);
13
+ const type = asString(part.type, "").trim();
14
+ if (type === "output_text" || type === "text" || type === "content") {
15
+ const text = asString(part.text, "").trim() || asString(part.content, "").trim();
16
+ if (text)
17
+ lines.push(text);
18
+ }
19
+ }
20
+ return lines;
21
+ }
22
+ function readSessionId(event) {
23
+ return (asString(event.session_id, "").trim() ||
24
+ asString(event.sessionId, "").trim() ||
25
+ asString(event.sessionID, "").trim() ||
26
+ asString(event.checkpoint_id, "").trim() ||
27
+ asString(event.thread_id, "").trim() ||
28
+ null);
29
+ }
30
+ function asErrorText(value) {
31
+ if (typeof value === "string")
32
+ return value;
33
+ const rec = parseObject(value);
34
+ const message = asString(rec.message, "") ||
35
+ asString(rec.error, "") ||
36
+ asString(rec.code, "") ||
37
+ asString(rec.detail, "");
38
+ if (message)
39
+ return message;
40
+ try {
41
+ return JSON.stringify(rec);
42
+ }
43
+ catch {
44
+ return "";
45
+ }
46
+ }
47
+ function accumulateUsage(target, usageRaw) {
48
+ const usage = parseObject(usageRaw);
49
+ const usageMetadata = parseObject(usage.usageMetadata);
50
+ const source = Object.keys(usageMetadata).length > 0 ? usageMetadata : usage;
51
+ target.inputTokens += asNumber(source.input_tokens, asNumber(source.inputTokens, asNumber(source.promptTokenCount, 0)));
52
+ target.cachedInputTokens += asNumber(source.cached_input_tokens, asNumber(source.cachedInputTokens, asNumber(source.cachedContentTokenCount, asNumber(source.cached, 0))));
53
+ target.outputTokens += asNumber(source.output_tokens, asNumber(source.outputTokens, asNumber(source.candidatesTokenCount, 0)));
54
+ }
55
+ export function parseGeminiJsonl(stdout) {
56
+ let sessionId = null;
57
+ const messages = [];
58
+ let errorMessage = null;
59
+ let costUsd = null;
60
+ let resultEvent = null;
61
+ let question = null;
62
+ const usage = {
63
+ inputTokens: 0,
64
+ cachedInputTokens: 0,
65
+ outputTokens: 0,
66
+ };
67
+ for (const rawLine of stdout.split(/\r?\n/)) {
68
+ const line = rawLine.trim();
69
+ if (!line)
70
+ continue;
71
+ const event = parseJson(line);
72
+ if (!event)
73
+ continue;
74
+ const foundSessionId = readSessionId(event);
75
+ if (foundSessionId)
76
+ sessionId = foundSessionId;
77
+ const type = asString(event.type, "").trim();
78
+ if (type === "assistant") {
79
+ messages.push(...collectMessageText(event.message));
80
+ const messageObj = parseObject(event.message);
81
+ const content = Array.isArray(messageObj.content) ? messageObj.content : [];
82
+ for (const partRaw of content) {
83
+ const part = parseObject(partRaw);
84
+ if (asString(part.type, "").trim() === "question") {
85
+ question = {
86
+ prompt: asString(part.prompt, "").trim(),
87
+ choices: (Array.isArray(part.choices) ? part.choices : []).map((choiceRaw) => {
88
+ const choice = parseObject(choiceRaw);
89
+ return {
90
+ key: asString(choice.key, "").trim(),
91
+ label: asString(choice.label, "").trim(),
92
+ description: asString(choice.description, "").trim() || undefined,
93
+ };
94
+ }),
95
+ };
96
+ break; // only one question per message
97
+ }
98
+ }
99
+ continue;
100
+ }
101
+ // Gemini CLI v0.38+ stream-json schema emits assistant turns as:
102
+ // {"type":"message","role":"assistant","content":"...","delta":true}
103
+ // These are discrete final messages (one per assistant turn), not
104
+ // cumulative streaming tokens, so collecting all of them produces the
105
+ // expected concatenated turn-by-turn summary rather than duplicated text.
106
+ if (type === "message") {
107
+ const role = asString(event.role, "").trim().toLowerCase();
108
+ if (role === "assistant") {
109
+ messages.push(...collectMessageText(event.content));
110
+ }
111
+ continue;
112
+ }
113
+ if (type === "result") {
114
+ resultEvent = event;
115
+ accumulateUsage(usage, event.usage ?? event.usageMetadata ?? event.stats);
116
+ const resultText = asString(event.result, "").trim() ||
117
+ asString(event.text, "").trim() ||
118
+ asString(event.response, "").trim();
119
+ if (resultText && messages.length === 0)
120
+ messages.push(resultText);
121
+ costUsd = asNumber(event.total_cost_usd, asNumber(event.cost_usd, asNumber(event.cost, costUsd ?? 0))) || costUsd;
122
+ const status = asString(event.status, "").toLowerCase();
123
+ const isError = event.is_error === true ||
124
+ asString(event.subtype, "").toLowerCase() === "error" ||
125
+ status === "error" ||
126
+ status === "failed";
127
+ if (isError) {
128
+ const text = asErrorText(event.error ?? event.message ?? event.result).trim();
129
+ if (text)
130
+ errorMessage = text;
131
+ }
132
+ continue;
133
+ }
134
+ if (type === "error") {
135
+ const text = asErrorText(event.error ?? event.message ?? event.detail).trim();
136
+ if (text)
137
+ errorMessage = text;
138
+ continue;
139
+ }
140
+ if (type === "system") {
141
+ const subtype = asString(event.subtype, "").trim().toLowerCase();
142
+ if (subtype === "error") {
143
+ const text = asErrorText(event.error ?? event.message ?? event.detail).trim();
144
+ if (text)
145
+ errorMessage = text;
146
+ }
147
+ continue;
148
+ }
149
+ if (type === "text") {
150
+ const part = parseObject(event.part);
151
+ const text = asString(part.text, "").trim();
152
+ if (text)
153
+ messages.push(text);
154
+ continue;
155
+ }
156
+ if (type === "step_finish" || event.usage || event.usageMetadata) {
157
+ accumulateUsage(usage, event.usage ?? event.usageMetadata);
158
+ costUsd = asNumber(event.total_cost_usd, asNumber(event.cost_usd, asNumber(event.cost, costUsd ?? 0))) || costUsd;
159
+ continue;
160
+ }
161
+ }
162
+ return {
163
+ sessionId,
164
+ summary: messages.join("\n\n").trim(),
165
+ usage,
166
+ costUsd,
167
+ errorMessage,
168
+ resultEvent,
169
+ question,
170
+ };
171
+ }
172
+ export function isGeminiUnknownSessionError(stdout, stderr) {
173
+ const haystack = `${stdout}\n${stderr}`
174
+ .split(/\r?\n/)
175
+ .map((line) => line.trim())
176
+ .filter(Boolean)
177
+ .join("\n");
178
+ return /unknown\s+session|session\s+.*\s+not\s+found|resume\s+.*\s+not\s+found|checkpoint\s+.*\s+not\s+found|cannot\s+resume|failed\s+to\s+resume/i.test(haystack);
179
+ }
180
+ function extractGeminiErrorMessages(parsed) {
181
+ const messages = [];
182
+ const errorMsg = asString(parsed.error, "").trim();
183
+ if (errorMsg)
184
+ messages.push(errorMsg);
185
+ const raw = Array.isArray(parsed.errors) ? parsed.errors : [];
186
+ for (const entry of raw) {
187
+ if (typeof entry === "string") {
188
+ const msg = entry.trim();
189
+ if (msg)
190
+ messages.push(msg);
191
+ continue;
192
+ }
193
+ if (typeof entry !== "object" || entry === null || Array.isArray(entry))
194
+ continue;
195
+ const obj = entry;
196
+ const msg = asString(obj.message, "") || asString(obj.error, "") || asString(obj.code, "");
197
+ if (msg) {
198
+ messages.push(msg);
199
+ continue;
200
+ }
201
+ try {
202
+ messages.push(JSON.stringify(obj));
203
+ }
204
+ catch {
205
+ // skip non-serializable entry
206
+ }
207
+ }
208
+ return messages;
209
+ }
210
+ export function describeGeminiFailure(parsed) {
211
+ const status = asString(parsed.status, "");
212
+ const errors = extractGeminiErrorMessages(parsed);
213
+ const detail = errors[0] ?? "";
214
+ const parts = ["Gemini run failed"];
215
+ if (status)
216
+ parts.push(`status=${status}`);
217
+ if (detail)
218
+ parts.push(detail);
219
+ return parts.length > 1 ? parts.join(": ") : null;
220
+ }
221
+ const GEMINI_AUTH_REQUIRED_RE = /(?:not\s+authenticated|please\s+authenticate|api[_ ]?key\s+(?:required|missing|invalid)|authentication\s+required|unauthorized|invalid\s+credentials|not\s+logged\s+in|login\s+required|run\s+`?gemini\s+auth(?:\s+login)?`?\s+first)/i;
222
+ const GEMINI_QUOTA_EXHAUSTED_RE = /(?:resource_exhausted|quota|rate[-\s]?limit|too many requests|\b429\b|billing details)/i;
223
+ export function detectGeminiAuthRequired(input) {
224
+ const errors = extractGeminiErrorMessages(input.parsed ?? {});
225
+ const messages = [...errors, input.stdout, input.stderr]
226
+ .join("\n")
227
+ .split(/\r?\n/)
228
+ .map((line) => line.trim())
229
+ .filter(Boolean);
230
+ const requiresAuth = messages.some((line) => GEMINI_AUTH_REQUIRED_RE.test(line));
231
+ return { requiresAuth };
232
+ }
233
+ export function detectGeminiQuotaExhausted(input) {
234
+ const errors = extractGeminiErrorMessages(input.parsed ?? {});
235
+ const messages = [...errors, input.stdout, input.stderr]
236
+ .join("\n")
237
+ .split(/\r?\n/)
238
+ .map((line) => line.trim())
239
+ .filter(Boolean);
240
+ const exhausted = messages.some((line) => GEMINI_QUOTA_EXHAUSTED_RE.test(line));
241
+ return { exhausted };
242
+ }
243
+ export function isGeminiTurnLimitResult(parsed, exitCode) {
244
+ if (exitCode === 53)
245
+ return true;
246
+ if (!parsed)
247
+ return false;
248
+ const structuredStopReasons = [
249
+ parsed.status,
250
+ parsed.stopReason,
251
+ parsed.stop_reason,
252
+ parsed.errorCode,
253
+ parsed.error_code,
254
+ ].map((value) => asString(value, "").trim().toLowerCase());
255
+ return structuredStopReasons.some((reason) => reason === "turn_limit" ||
256
+ reason === "max_turns" ||
257
+ reason === "max_turns_exhausted" ||
258
+ reason === "turn_limit_exhausted");
259
+ }
260
+ //# sourceMappingURL=parse.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse.js","sourceRoot":"","sources":["../../src/server/parse.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=parse.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse.test.d.ts","sourceRoot":"","sources":["../../src/server/parse.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,117 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { parseGeminiJsonl } from "./parse.js";
3
+ describe("parseGeminiJsonl", () => {
4
+ it("collects assistant text from message events with string content", () => {
5
+ const stdout = [
6
+ '{"type":"init","session_id":"session-1"}',
7
+ '{"type":"message","role":"user","content":"Respond with hello."}',
8
+ '{"type":"message","role":"assistant","content":"hello","delta":true}',
9
+ '{"type":"result","status":"success"}',
10
+ ].join("\n");
11
+ const parsed = parseGeminiJsonl(stdout);
12
+ expect(parsed.sessionId).toBe("session-1");
13
+ expect(parsed.summary).toBe("hello");
14
+ expect(parsed.errorMessage).toBeNull();
15
+ });
16
+ it("collects assistant text from message events with structured object content", () => {
17
+ const stdout = [
18
+ '{"type":"init","session_id":"session-2"}',
19
+ '{"type":"message","role":"assistant","content":{"content":[{"type":"text","text":"first part"},{"type":"text","text":"second part"}]}}',
20
+ '{"type":"result","status":"success"}',
21
+ ].join("\n");
22
+ const parsed = parseGeminiJsonl(stdout);
23
+ expect(parsed.sessionId).toBe("session-2");
24
+ expect(parsed.summary).toBe("first part\n\nsecond part");
25
+ expect(parsed.errorMessage).toBeNull();
26
+ });
27
+ it("ignores non-assistant message events", () => {
28
+ const stdout = [
29
+ '{"type":"message","role":"user","content":"hidden user input"}',
30
+ '{"type":"message","role":"system","content":"hidden system note"}',
31
+ '{"type":"message","role":"assistant","content":"visible response"}',
32
+ '{"type":"result","status":"success"}',
33
+ ].join("\n");
34
+ const parsed = parseGeminiJsonl(stdout);
35
+ expect(parsed.summary).toBe("visible response");
36
+ });
37
+ it("captures assistant text from gemini CLI v0.38 stream-json schema", () => {
38
+ const stdout = [
39
+ JSON.stringify({
40
+ type: "init",
41
+ timestamp: "2026-05-04T05:43:41.203Z",
42
+ session_id: "session-abc",
43
+ model: "auto-gemini-3",
44
+ }),
45
+ JSON.stringify({
46
+ type: "message",
47
+ timestamp: "2026-05-04T05:43:41.205Z",
48
+ role: "user",
49
+ content: "Respond with hello.",
50
+ }),
51
+ JSON.stringify({
52
+ type: "message",
53
+ timestamp: "2026-05-04T05:43:45.198Z",
54
+ role: "assistant",
55
+ content: "hello.",
56
+ delta: true,
57
+ }),
58
+ JSON.stringify({
59
+ type: "result",
60
+ timestamp: "2026-05-04T05:43:45.819Z",
61
+ status: "success",
62
+ stats: {
63
+ total_tokens: 9468,
64
+ input_tokens: 9095,
65
+ output_tokens: 29,
66
+ cached: 8132,
67
+ duration_ms: 4616,
68
+ },
69
+ }),
70
+ ].join("\n");
71
+ const result = parseGeminiJsonl(stdout);
72
+ expect(result.summary).toBe("hello.");
73
+ expect(result.sessionId).toBe("session-abc");
74
+ expect(result.errorMessage).toBeNull();
75
+ expect(result.usage.inputTokens).toBe(9095);
76
+ expect(result.usage.outputTokens).toBe(29);
77
+ expect(result.usage.cachedInputTokens).toBe(8132);
78
+ });
79
+ it("ignores user messages and only collects assistant content", () => {
80
+ const stdout = [
81
+ JSON.stringify({ type: "message", role: "user", content: "ignore me" }),
82
+ JSON.stringify({ type: "message", role: "assistant", content: "first" }),
83
+ JSON.stringify({ type: "message", role: "assistant", content: "second" }),
84
+ ].join("\n");
85
+ const result = parseGeminiJsonl(stdout);
86
+ expect(result.summary).toBe("first\n\nsecond");
87
+ });
88
+ it("preserves the legacy claude-style `assistant` event handler", () => {
89
+ const stdout = [
90
+ JSON.stringify({
91
+ type: "system",
92
+ subtype: "init",
93
+ session_id: "legacy-session",
94
+ }),
95
+ JSON.stringify({
96
+ type: "assistant",
97
+ message: { content: [{ type: "output_text", text: "legacy hello" }] },
98
+ }),
99
+ JSON.stringify({ type: "result", subtype: "success", result: "legacy hello" }),
100
+ ].join("\n");
101
+ const result = parseGeminiJsonl(stdout);
102
+ expect(result.summary).toBe("legacy hello");
103
+ expect(result.sessionId).toBe("legacy-session");
104
+ });
105
+ it("flags result events with status=error", () => {
106
+ const stdout = [
107
+ JSON.stringify({
108
+ type: "result",
109
+ status: "error",
110
+ error: "boom",
111
+ }),
112
+ ].join("\n");
113
+ const result = parseGeminiJsonl(stdout);
114
+ expect(result.errorMessage).toBe("boom");
115
+ });
116
+ });
117
+ //# sourceMappingURL=parse.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse.test.js","sourceRoot":"","sources":["../../src/server/parse.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ import type { AdapterSkillContext, AdapterSkillSnapshot } from "@evermore.work/adapter-utils";
2
+ export declare function listGeminiSkills(ctx: AdapterSkillContext): Promise<AdapterSkillSnapshot>;
3
+ export declare function syncGeminiSkills(ctx: AdapterSkillContext, desiredSkills: string[]): Promise<AdapterSkillSnapshot>;
4
+ export declare function resolveGeminiDesiredSkillNames(config: Record<string, unknown>, availableEntries: Array<{
5
+ key: string;
6
+ required?: boolean;
7
+ }>): string[];
8
+ //# sourceMappingURL=skills.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skills.d.ts","sourceRoot":"","sources":["../../src/server/skills.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,mBAAmB,EACnB,oBAAoB,EACrB,MAAM,8BAA8B,CAAC;AA2CtC,wBAAsB,gBAAgB,CAAC,GAAG,EAAE,mBAAmB,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAE9F;AAED,wBAAsB,gBAAgB,CACpC,GAAG,EAAE,mBAAmB,EACxB,aAAa,EAAE,MAAM,EAAE,GACtB,OAAO,CAAC,oBAAoB,CAAC,CA0B/B;AAED,wBAAgB,8BAA8B,CAC5C,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,gBAAgB,EAAE,KAAK,CAAC;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC,YAG7D"}
@@ -0,0 +1,69 @@
1
+ import fs from "node:fs/promises";
2
+ import os from "node:os";
3
+ import path from "node:path";
4
+ import { fileURLToPath } from "node:url";
5
+ import { buildPersistentSkillSnapshot, ensureEvermoreSkillSymlink, readEvermoreRuntimeSkillEntries, readInstalledSkillTargets, resolveEvermoreDesiredSkillNames, } from "@evermore.work/adapter-utils/server-utils";
6
+ const __moduleDir = path.dirname(fileURLToPath(import.meta.url));
7
+ function asString(value) {
8
+ return typeof value === "string" && value.trim().length > 0 ? value.trim() : null;
9
+ }
10
+ function resolveGeminiSkillsHome(config) {
11
+ const env = typeof config.env === "object" && config.env !== null && !Array.isArray(config.env)
12
+ ? config.env
13
+ : {};
14
+ const configuredHome = asString(env.HOME);
15
+ const home = configuredHome ? path.resolve(configuredHome) : os.homedir();
16
+ return path.join(home, ".gemini", "skills");
17
+ }
18
+ async function buildGeminiSkillSnapshot(config) {
19
+ const availableEntries = await readEvermoreRuntimeSkillEntries(config, __moduleDir);
20
+ const desiredSkills = resolveEvermoreDesiredSkillNames(config, availableEntries);
21
+ const skillsHome = resolveGeminiSkillsHome(config);
22
+ const installed = await readInstalledSkillTargets(skillsHome);
23
+ return buildPersistentSkillSnapshot({
24
+ adapterType: "gemini_local",
25
+ availableEntries,
26
+ desiredSkills,
27
+ installed,
28
+ skillsHome,
29
+ locationLabel: "~/.gemini/skills",
30
+ missingDetail: "Configured but not currently linked into the Gemini skills home.",
31
+ externalConflictDetail: "Skill name is occupied by an external installation.",
32
+ externalDetail: "Installed outside Evermore management.",
33
+ });
34
+ }
35
+ export async function listGeminiSkills(ctx) {
36
+ return buildGeminiSkillSnapshot(ctx.config);
37
+ }
38
+ export async function syncGeminiSkills(ctx, desiredSkills) {
39
+ const availableEntries = await readEvermoreRuntimeSkillEntries(ctx.config, __moduleDir);
40
+ const desiredSet = new Set([
41
+ ...desiredSkills,
42
+ ...availableEntries.filter((entry) => entry.required).map((entry) => entry.key),
43
+ ]);
44
+ const skillsHome = resolveGeminiSkillsHome(ctx.config);
45
+ await fs.mkdir(skillsHome, { recursive: true });
46
+ const installed = await readInstalledSkillTargets(skillsHome);
47
+ const availableByRuntimeName = new Map(availableEntries.map((entry) => [entry.runtimeName, entry]));
48
+ for (const available of availableEntries) {
49
+ if (!desiredSet.has(available.key))
50
+ continue;
51
+ const target = path.join(skillsHome, available.runtimeName);
52
+ await ensureEvermoreSkillSymlink(available.source, target);
53
+ }
54
+ for (const [name, installedEntry] of installed.entries()) {
55
+ const available = availableByRuntimeName.get(name);
56
+ if (!available)
57
+ continue;
58
+ if (desiredSet.has(available.key))
59
+ continue;
60
+ if (installedEntry.targetPath !== available.source)
61
+ continue;
62
+ await fs.unlink(path.join(skillsHome, name)).catch(() => { });
63
+ }
64
+ return buildGeminiSkillSnapshot(ctx.config);
65
+ }
66
+ export function resolveGeminiDesiredSkillNames(config, availableEntries) {
67
+ return resolveEvermoreDesiredSkillNames(config, availableEntries);
68
+ }
69
+ //# sourceMappingURL=skills.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skills.js","sourceRoot":"","sources":["../../src/server/skills.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { AdapterEnvironmentTestContext, AdapterEnvironmentTestResult } from "@evermore.work/adapter-utils";
2
+ export declare function testEnvironment(ctx: AdapterEnvironmentTestContext): Promise<AdapterEnvironmentTestResult>;
3
+ //# sourceMappingURL=test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test.d.ts","sourceRoot":"","sources":["../../src/server/test.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAEV,6BAA6B,EAC7B,4BAA4B,EAC7B,MAAM,8BAA8B,CAAC;AA4CtC,wBAAsB,eAAe,CACnC,GAAG,EAAE,6BAA6B,GACjC,OAAO,CAAC,4BAA4B,CAAC,CA4NvC"}