aemeathcli 1.0.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 (102) hide show
  1. package/README.md +607 -0
  2. package/dist/App-P4MYD4QY.js +2719 -0
  3. package/dist/App-P4MYD4QY.js.map +1 -0
  4. package/dist/api-key-fallback-YQQBOQIL.js +11 -0
  5. package/dist/api-key-fallback-YQQBOQIL.js.map +1 -0
  6. package/dist/chunk-4IJD72YB.js +184 -0
  7. package/dist/chunk-4IJD72YB.js.map +1 -0
  8. package/dist/chunk-6PDJ45T4.js +325 -0
  9. package/dist/chunk-6PDJ45T4.js.map +1 -0
  10. package/dist/chunk-CARHU3DO.js +562 -0
  11. package/dist/chunk-CARHU3DO.js.map +1 -0
  12. package/dist/chunk-CGEV3ARR.js +80 -0
  13. package/dist/chunk-CGEV3ARR.js.map +1 -0
  14. package/dist/chunk-CS5X3BWX.js +27 -0
  15. package/dist/chunk-CS5X3BWX.js.map +1 -0
  16. package/dist/chunk-CYQNBB25.js +44 -0
  17. package/dist/chunk-CYQNBB25.js.map +1 -0
  18. package/dist/chunk-DAHGLHNR.js +657 -0
  19. package/dist/chunk-DAHGLHNR.js.map +1 -0
  20. package/dist/chunk-H66O5Z2V.js +305 -0
  21. package/dist/chunk-H66O5Z2V.js.map +1 -0
  22. package/dist/chunk-HCIHOHLX.js +322 -0
  23. package/dist/chunk-HCIHOHLX.js.map +1 -0
  24. package/dist/chunk-HMJRPNPZ.js +1031 -0
  25. package/dist/chunk-HMJRPNPZ.js.map +1 -0
  26. package/dist/chunk-I5PZ4JTS.js +119 -0
  27. package/dist/chunk-I5PZ4JTS.js.map +1 -0
  28. package/dist/chunk-IYW62KKR.js +255 -0
  29. package/dist/chunk-IYW62KKR.js.map +1 -0
  30. package/dist/chunk-JAXXTYID.js +51 -0
  31. package/dist/chunk-JAXXTYID.js.map +1 -0
  32. package/dist/chunk-LSOYPSAT.js +183 -0
  33. package/dist/chunk-LSOYPSAT.js.map +1 -0
  34. package/dist/chunk-MFBHNWGV.js +416 -0
  35. package/dist/chunk-MFBHNWGV.js.map +1 -0
  36. package/dist/chunk-MXZSI3AY.js +311 -0
  37. package/dist/chunk-MXZSI3AY.js.map +1 -0
  38. package/dist/chunk-NBR3GHMT.js +72 -0
  39. package/dist/chunk-NBR3GHMT.js.map +1 -0
  40. package/dist/chunk-O3ZF22SW.js +246 -0
  41. package/dist/chunk-O3ZF22SW.js.map +1 -0
  42. package/dist/chunk-SUSJPZU2.js +181 -0
  43. package/dist/chunk-SUSJPZU2.js.map +1 -0
  44. package/dist/chunk-TEVZS4FA.js +310 -0
  45. package/dist/chunk-TEVZS4FA.js.map +1 -0
  46. package/dist/chunk-UY2SYSEZ.js +211 -0
  47. package/dist/chunk-UY2SYSEZ.js.map +1 -0
  48. package/dist/chunk-WAHVZH7V.js +260 -0
  49. package/dist/chunk-WAHVZH7V.js.map +1 -0
  50. package/dist/chunk-WPP3PEDE.js +234 -0
  51. package/dist/chunk-WPP3PEDE.js.map +1 -0
  52. package/dist/chunk-Y5XVD2CD.js +1610 -0
  53. package/dist/chunk-Y5XVD2CD.js.map +1 -0
  54. package/dist/chunk-YL5XFHR3.js +56 -0
  55. package/dist/chunk-YL5XFHR3.js.map +1 -0
  56. package/dist/chunk-ZGOHARPV.js +122 -0
  57. package/dist/chunk-ZGOHARPV.js.map +1 -0
  58. package/dist/claude-adapter-QMLFMSP3.js +6 -0
  59. package/dist/claude-adapter-QMLFMSP3.js.map +1 -0
  60. package/dist/claude-login-5WELXPKT.js +324 -0
  61. package/dist/claude-login-5WELXPKT.js.map +1 -0
  62. package/dist/cli.d.ts +1 -0
  63. package/dist/cli.js +703 -0
  64. package/dist/cli.js.map +1 -0
  65. package/dist/codex-login-7HHLJHBF.js +164 -0
  66. package/dist/codex-login-7HHLJHBF.js.map +1 -0
  67. package/dist/config-store-W6FBCQAQ.js +6 -0
  68. package/dist/config-store-W6FBCQAQ.js.map +1 -0
  69. package/dist/executor-6RIKIGXK.js +4 -0
  70. package/dist/executor-6RIKIGXK.js.map +1 -0
  71. package/dist/gemini-adapter-6JIHZ7WI.js +6 -0
  72. package/dist/gemini-adapter-6JIHZ7WI.js.map +1 -0
  73. package/dist/gemini-login-ZZLYC3J6.js +346 -0
  74. package/dist/gemini-login-ZZLYC3J6.js.map +1 -0
  75. package/dist/index.d.ts +2210 -0
  76. package/dist/index.js +1419 -0
  77. package/dist/index.js.map +1 -0
  78. package/dist/kimi-adapter-JN4HFFHU.js +6 -0
  79. package/dist/kimi-adapter-JN4HFFHU.js.map +1 -0
  80. package/dist/kimi-login-CZPS63NK.js +149 -0
  81. package/dist/kimi-login-CZPS63NK.js.map +1 -0
  82. package/dist/native-cli-adapters-OLW3XX57.js +6 -0
  83. package/dist/native-cli-adapters-OLW3XX57.js.map +1 -0
  84. package/dist/ollama-adapter-OJQ3FKWK.js +6 -0
  85. package/dist/ollama-adapter-OJQ3FKWK.js.map +1 -0
  86. package/dist/openai-adapter-XU46EN7B.js +6 -0
  87. package/dist/openai-adapter-XU46EN7B.js.map +1 -0
  88. package/dist/registry-4KD24ZC3.js +6 -0
  89. package/dist/registry-4KD24ZC3.js.map +1 -0
  90. package/dist/registry-H7B3AHPQ.js +5 -0
  91. package/dist/registry-H7B3AHPQ.js.map +1 -0
  92. package/dist/server-manager-PTGBHCLS.js +5 -0
  93. package/dist/server-manager-PTGBHCLS.js.map +1 -0
  94. package/dist/session-manager-ECEEACGY.js +12 -0
  95. package/dist/session-manager-ECEEACGY.js.map +1 -0
  96. package/dist/team-manager-HC4XGCFY.js +11 -0
  97. package/dist/team-manager-HC4XGCFY.js.map +1 -0
  98. package/dist/tmux-manager-GPYZ3WQH.js +6 -0
  99. package/dist/tmux-manager-GPYZ3WQH.js.map +1 -0
  100. package/dist/tools-TSMXMHIF.js +6 -0
  101. package/dist/tools-TSMXMHIF.js.map +1 -0
  102. package/package.json +89 -0
@@ -0,0 +1,310 @@
1
+ import { getUserSkillsDir, getProjectSkillsDir } from './chunk-NBR3GHMT.js';
2
+ import { logger } from './chunk-JAXXTYID.js';
3
+ import { readFile, readdir, stat } from 'fs/promises';
4
+ import { join, dirname } from 'path';
5
+ import { fileURLToPath } from 'url';
6
+ import { parse } from 'yaml';
7
+ import { z } from 'zod';
8
+
9
+ var MODEL_ROLE_VALUES = [
10
+ "planning",
11
+ "coding",
12
+ "review",
13
+ "testing",
14
+ "bugfix",
15
+ "documentation"
16
+ ];
17
+ var skillFrontmatterSchema = z.object({
18
+ name: z.string().min(1, "Skill name is required"),
19
+ description: z.string().min(1, "Skill description is required"),
20
+ version: z.string().regex(/^\d+\.\d+\.\d+$/, "Version must be semver (e.g. 1.0.0)"),
21
+ "allowed-tools": z.array(z.string().min(1)).optional(),
22
+ triggers: z.array(z.string().min(1)).min(1, "At least one trigger is required"),
23
+ "model-requirements": z.object({
24
+ "preferred-role": z.enum(MODEL_ROLE_VALUES).optional(),
25
+ "min-context": z.number().int().positive().optional()
26
+ }).optional()
27
+ });
28
+ var FRONTMATTER_DELIMITER = "---";
29
+ var SkillLoader = class {
30
+ /**
31
+ * Parse a single SKILL.md file into an ISkillDefinition.
32
+ * Returns null if the file is malformed or invalid.
33
+ */
34
+ async loadSkillFile(filePath) {
35
+ let raw;
36
+ try {
37
+ raw = await readFile(filePath, "utf-8");
38
+ } catch (error) {
39
+ const message = error instanceof Error ? error.message : String(error);
40
+ logger.warn({ filePath, error: message }, "Failed to read skill file");
41
+ return null;
42
+ }
43
+ return this.parseSkillContent(raw, filePath);
44
+ }
45
+ /**
46
+ * Parse raw SKILL.md content string into an ISkillDefinition.
47
+ */
48
+ parseSkillContent(raw, filePath) {
49
+ const extracted = this.extractFrontmatter(raw);
50
+ if (!extracted) {
51
+ logger.warn({ filePath }, "Skill file missing valid YAML frontmatter delimiters");
52
+ return null;
53
+ }
54
+ const { yamlContent, body } = extracted;
55
+ let rawFrontmatter;
56
+ try {
57
+ rawFrontmatter = parse(yamlContent);
58
+ } catch (error) {
59
+ const message = error instanceof Error ? error.message : String(error);
60
+ logger.warn({ filePath, error: message }, "Failed to parse YAML frontmatter");
61
+ return null;
62
+ }
63
+ const result = skillFrontmatterSchema.safeParse(rawFrontmatter);
64
+ if (!result.success) {
65
+ logger.warn(
66
+ { filePath, errors: result.error.flatten().fieldErrors },
67
+ "Skill frontmatter validation failed"
68
+ );
69
+ return null;
70
+ }
71
+ const validated = result.data;
72
+ const modelReqs = validated["model-requirements"];
73
+ const frontmatter = {
74
+ name: validated.name,
75
+ description: validated.description,
76
+ version: validated.version,
77
+ triggers: validated.triggers,
78
+ // Only include optional properties when they are defined (not undefined)
79
+ ...validated["allowed-tools"] !== void 0 ? { "allowed-tools": validated["allowed-tools"] } : {},
80
+ ...modelReqs !== void 0 ? {
81
+ "model-requirements": {
82
+ ...modelReqs["preferred-role"] !== void 0 ? { "preferred-role": modelReqs["preferred-role"] } : {},
83
+ ...modelReqs["min-context"] !== void 0 ? { "min-context": modelReqs["min-context"] } : {}
84
+ }
85
+ } : {}
86
+ };
87
+ return {
88
+ frontmatter,
89
+ body: body.trim(),
90
+ filePath
91
+ };
92
+ }
93
+ /**
94
+ * Extract only name and description for progressive loading (~100 tokens).
95
+ */
96
+ async loadSkillSummary(filePath) {
97
+ const definition = await this.loadSkillFile(filePath);
98
+ if (!definition) return null;
99
+ return {
100
+ name: definition.frontmatter.name,
101
+ description: definition.frontmatter.description
102
+ };
103
+ }
104
+ /**
105
+ * Split raw content into YAML frontmatter and Markdown body.
106
+ * Frontmatter is delimited by `---` at the start and a subsequent `---`.
107
+ */
108
+ extractFrontmatter(raw) {
109
+ const trimmed = raw.trimStart();
110
+ if (!trimmed.startsWith(FRONTMATTER_DELIMITER)) {
111
+ return null;
112
+ }
113
+ const afterOpening = trimmed.slice(FRONTMATTER_DELIMITER.length);
114
+ if (!afterOpening.startsWith("\n")) {
115
+ return null;
116
+ }
117
+ const contentAfterOpening = afterOpening.slice(1);
118
+ const closingIndex = contentAfterOpening.indexOf(`
119
+ ${FRONTMATTER_DELIMITER}`);
120
+ if (closingIndex === -1) {
121
+ return null;
122
+ }
123
+ const yamlContent = contentAfterOpening.slice(0, closingIndex);
124
+ const afterClosing = contentAfterOpening.slice(
125
+ closingIndex + 1 + FRONTMATTER_DELIMITER.length
126
+ );
127
+ const body = afterClosing.startsWith("\n") ? afterClosing.slice(1) : afterClosing;
128
+ return { yamlContent, body };
129
+ }
130
+ };
131
+
132
+ // src/skills/registry.ts
133
+ var SKILL_FILENAME = "SKILL.md";
134
+ var SkillRegistry = class {
135
+ loader;
136
+ skills = /* @__PURE__ */ new Map();
137
+ triggerIndex = /* @__PURE__ */ new Map();
138
+ initialized = false;
139
+ constructor(loader) {
140
+ this.loader = loader ?? new SkillLoader();
141
+ }
142
+ /**
143
+ * Initialize the registry by scanning all skill directories.
144
+ * Loads in priority order so higher-priority sources override lower ones.
145
+ */
146
+ async initialize(projectRoot) {
147
+ if (this.initialized) return;
148
+ const builtInDir = this.getBuiltInSkillsDir();
149
+ await this.scanDirectory(builtInDir, "built-in");
150
+ const userDir = getUserSkillsDir();
151
+ await this.scanDirectory(userDir, "user");
152
+ if (projectRoot) {
153
+ const projectDir = getProjectSkillsDir(projectRoot);
154
+ await this.scanDirectory(projectDir, "project");
155
+ }
156
+ this.initialized = true;
157
+ logger.info(
158
+ { totalSkills: this.skills.size, totalTriggers: this.triggerIndex.size },
159
+ "Skill registry initialized"
160
+ );
161
+ }
162
+ /**
163
+ * Get a full skill definition by name. Loads content on demand.
164
+ */
165
+ async getByName(name) {
166
+ const entry = this.skills.get(name);
167
+ if (!entry) return null;
168
+ if (!entry.definition) {
169
+ const filePath = join(entry.summary.dirPath, SKILL_FILENAME);
170
+ entry.definition = await this.loader.loadSkillFile(filePath);
171
+ }
172
+ return entry.definition;
173
+ }
174
+ /**
175
+ * Find a skill by trigger string (e.g. "$review" or "review").
176
+ */
177
+ async getByTrigger(trigger) {
178
+ const normalized = trigger.startsWith("$") ? trigger.slice(1) : trigger;
179
+ const withPrefix = `$${normalized}`;
180
+ const name = this.triggerIndex.get(withPrefix) ?? this.triggerIndex.get(normalized) ?? this.triggerIndex.get(trigger);
181
+ if (!name) return null;
182
+ return this.getByName(name);
183
+ }
184
+ /**
185
+ * Resolve a trigger string to a skill name without loading the full definition.
186
+ */
187
+ resolveTriger(trigger) {
188
+ const normalized = trigger.startsWith("$") ? trigger.slice(1) : trigger;
189
+ const withPrefix = `$${normalized}`;
190
+ return this.triggerIndex.get(withPrefix) ?? this.triggerIndex.get(normalized) ?? this.triggerIndex.get(trigger);
191
+ }
192
+ /**
193
+ * List all registered skill summaries.
194
+ */
195
+ listAll() {
196
+ return Array.from(this.skills.values()).map((entry) => entry.summary);
197
+ }
198
+ /**
199
+ * Check if a skill exists by name.
200
+ */
201
+ has(name) {
202
+ return this.skills.has(name);
203
+ }
204
+ /**
205
+ * Get the count of registered skills.
206
+ */
207
+ get size() {
208
+ return this.skills.size;
209
+ }
210
+ /**
211
+ * Reset the registry for re-initialization.
212
+ */
213
+ reset() {
214
+ this.skills.clear();
215
+ this.triggerIndex.clear();
216
+ this.initialized = false;
217
+ }
218
+ // ── Private Helpers ──────────────────────────────────────────────────
219
+ /**
220
+ * Scan a directory for skill subdirectories containing SKILL.md.
221
+ */
222
+ async scanDirectory(dirPath, source) {
223
+ let entries;
224
+ try {
225
+ entries = await readdir(dirPath);
226
+ } catch {
227
+ logger.debug({ dirPath, source }, "Skill directory not found, skipping");
228
+ return;
229
+ }
230
+ for (const entry of entries) {
231
+ const skillDir = join(dirPath, entry);
232
+ try {
233
+ const info = await stat(skillDir);
234
+ if (!info.isDirectory()) continue;
235
+ } catch {
236
+ continue;
237
+ }
238
+ const skillFile = join(skillDir, SKILL_FILENAME);
239
+ try {
240
+ await stat(skillFile);
241
+ } catch {
242
+ logger.debug({ skillDir }, "No SKILL.md found in directory, skipping");
243
+ continue;
244
+ }
245
+ await this.registerSkillFromFile(skillFile, skillDir, source);
246
+ }
247
+ }
248
+ /**
249
+ * Register a single skill from its SKILL.md file path.
250
+ */
251
+ async registerSkillFromFile(skillFile, skillDir, source) {
252
+ const definition = await this.loader.loadSkillFile(skillFile);
253
+ if (!definition) return;
254
+ const { frontmatter } = definition;
255
+ const summary = {
256
+ name: frontmatter.name,
257
+ description: frontmatter.description,
258
+ version: frontmatter.version,
259
+ source,
260
+ dirPath: skillDir
261
+ };
262
+ const existing = this.skills.get(summary.name);
263
+ if (existing) {
264
+ this.removeTriggers(existing.summary.name);
265
+ logger.debug(
266
+ {
267
+ skill: summary.name,
268
+ oldSource: existing.summary.source,
269
+ newSource: source
270
+ },
271
+ "Skill overridden by higher-priority source"
272
+ );
273
+ }
274
+ this.skills.set(summary.name, { summary, definition });
275
+ this.registerTriggers(definition);
276
+ }
277
+ /**
278
+ * Index all triggers for a skill definition.
279
+ */
280
+ registerTriggers(definition) {
281
+ for (const trigger of definition.frontmatter.triggers) {
282
+ this.triggerIndex.set(trigger, definition.frontmatter.name);
283
+ }
284
+ }
285
+ /**
286
+ * Remove all trigger mappings associated with a skill name.
287
+ */
288
+ removeTriggers(skillName) {
289
+ const toDelete = [];
290
+ for (const [trigger, name] of this.triggerIndex) {
291
+ if (name === skillName) {
292
+ toDelete.push(trigger);
293
+ }
294
+ }
295
+ for (const trigger of toDelete) {
296
+ this.triggerIndex.delete(trigger);
297
+ }
298
+ }
299
+ /**
300
+ * Resolve the built-in skills directory relative to this module.
301
+ */
302
+ getBuiltInSkillsDir() {
303
+ const currentFilePath = fileURLToPath(import.meta.url);
304
+ return join(dirname(currentFilePath), "built-in");
305
+ }
306
+ };
307
+
308
+ export { SkillLoader, SkillRegistry };
309
+ //# sourceMappingURL=chunk-TEVZS4FA.js.map
310
+ //# sourceMappingURL=chunk-TEVZS4FA.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/skills/loader.ts","../src/skills/registry.ts"],"names":["parseYaml"],"mappings":"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","file":"chunk-TEVZS4FA.js","sourcesContent":["/**\n * SkillLoader — Parses YAML frontmatter + Markdown body from SKILL.md files.\n * Per PRD section 10.2-10.3: YAML skill file format with Zod validation.\n */\n\nimport { readFile } from \"node:fs/promises\";\nimport { parse as parseYaml } from \"yaml\";\nimport { z } from \"zod\";\nimport { logger } from \"../utils/logger.js\";\nimport type { ISkillFrontmatter, ISkillDefinition } from \"../types/config.js\";\nimport type { ModelRole } from \"../types/model.js\";\n\n// ── Zod Schema ──────────────────────────────────────────────────────────\n\nconst MODEL_ROLE_VALUES: readonly [ModelRole, ...ModelRole[]] = [\n \"planning\",\n \"coding\",\n \"review\",\n \"testing\",\n \"bugfix\",\n \"documentation\",\n];\n\nconst skillFrontmatterSchema = z.object({\n name: z.string().min(1, \"Skill name is required\"),\n description: z.string().min(1, \"Skill description is required\"),\n version: z.string().regex(/^\\d+\\.\\d+\\.\\d+$/, \"Version must be semver (e.g. 1.0.0)\"),\n \"allowed-tools\": z.array(z.string().min(1)).optional(),\n triggers: z.array(z.string().min(1)).min(1, \"At least one trigger is required\"),\n \"model-requirements\": z\n .object({\n \"preferred-role\": z.enum(MODEL_ROLE_VALUES).optional(),\n \"min-context\": z.number().int().positive().optional(),\n })\n .optional(),\n});\n\nconst FRONTMATTER_DELIMITER = \"---\";\n\n// ── SkillLoader Class ───────────────────────────────────────────────────\n\nexport class SkillLoader {\n /**\n * Parse a single SKILL.md file into an ISkillDefinition.\n * Returns null if the file is malformed or invalid.\n */\n async loadSkillFile(filePath: string): Promise<ISkillDefinition | null> {\n let raw: string;\n try {\n raw = await readFile(filePath, \"utf-8\");\n } catch (error: unknown) {\n const message = error instanceof Error ? error.message : String(error);\n logger.warn({ filePath, error: message }, \"Failed to read skill file\");\n return null;\n }\n\n return this.parseSkillContent(raw, filePath);\n }\n\n /**\n * Parse raw SKILL.md content string into an ISkillDefinition.\n */\n parseSkillContent(raw: string, filePath: string): ISkillDefinition | null {\n const extracted = this.extractFrontmatter(raw);\n if (!extracted) {\n logger.warn({ filePath }, \"Skill file missing valid YAML frontmatter delimiters\");\n return null;\n }\n\n const { yamlContent, body } = extracted;\n\n let rawFrontmatter: unknown;\n try {\n rawFrontmatter = parseYaml(yamlContent);\n } catch (error: unknown) {\n const message = error instanceof Error ? error.message : String(error);\n logger.warn({ filePath, error: message }, \"Failed to parse YAML frontmatter\");\n return null;\n }\n\n const result = skillFrontmatterSchema.safeParse(rawFrontmatter);\n if (!result.success) {\n logger.warn(\n { filePath, errors: result.error.flatten().fieldErrors },\n \"Skill frontmatter validation failed\",\n );\n return null;\n }\n\n const validated = result.data;\n\n // Build frontmatter with conditional spreads for exactOptionalPropertyTypes\n const modelReqs = validated[\"model-requirements\"];\n const frontmatter: ISkillFrontmatter = {\n name: validated.name,\n description: validated.description,\n version: validated.version,\n triggers: validated.triggers,\n // Only include optional properties when they are defined (not undefined)\n ...(validated[\"allowed-tools\"] !== undefined\n ? { \"allowed-tools\": validated[\"allowed-tools\"] }\n : {}),\n ...(modelReqs !== undefined\n ? {\n \"model-requirements\": {\n ...(modelReqs[\"preferred-role\"] !== undefined\n ? { \"preferred-role\": modelReqs[\"preferred-role\"] }\n : {}),\n ...(modelReqs[\"min-context\"] !== undefined\n ? { \"min-context\": modelReqs[\"min-context\"] }\n : {}),\n },\n }\n : {}),\n };\n\n return {\n frontmatter,\n body: body.trim(),\n filePath,\n };\n }\n\n /**\n * Extract only name and description for progressive loading (~100 tokens).\n */\n async loadSkillSummary(\n filePath: string,\n ): Promise<{ name: string; description: string } | null> {\n const definition = await this.loadSkillFile(filePath);\n if (!definition) return null;\n\n return {\n name: definition.frontmatter.name,\n description: definition.frontmatter.description,\n };\n }\n\n /**\n * Split raw content into YAML frontmatter and Markdown body.\n * Frontmatter is delimited by `---` at the start and a subsequent `---`.\n */\n private extractFrontmatter(\n raw: string,\n ): { yamlContent: string; body: string } | null {\n const trimmed = raw.trimStart();\n if (!trimmed.startsWith(FRONTMATTER_DELIMITER)) {\n return null;\n }\n\n // Find the line after the opening delimiter\n const afterOpening = trimmed.slice(FRONTMATTER_DELIMITER.length);\n // The opening delimiter must be followed by a newline\n if (!afterOpening.startsWith(\"\\n\")) {\n return null;\n }\n\n const contentAfterOpening = afterOpening.slice(1); // skip the \\n\n const closingIndex = contentAfterOpening.indexOf(`\\n${FRONTMATTER_DELIMITER}`);\n if (closingIndex === -1) {\n return null;\n }\n\n const yamlContent = contentAfterOpening.slice(0, closingIndex);\n // Body starts after the closing delimiter line\n const afterClosing = contentAfterOpening.slice(\n closingIndex + 1 + FRONTMATTER_DELIMITER.length,\n );\n // Skip optional newline after closing delimiter\n const body = afterClosing.startsWith(\"\\n\") ? afterClosing.slice(1) : afterClosing;\n\n return { yamlContent, body };\n }\n}\n","/**\n * SkillRegistry — Discovers, indexes, and resolves skill definitions.\n * Resolution priority: project > user > built-in (PRD section 10.4).\n * Progressive loading: only name + description loaded initially (~100 tokens each).\n */\n\nimport { readdir, stat } from \"node:fs/promises\";\nimport { join, dirname } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { logger } from \"../utils/logger.js\";\nimport { getUserSkillsDir, getProjectSkillsDir } from \"../utils/pathResolver.js\";\nimport { SkillLoader } from \"./loader.js\";\nimport type { ISkillDefinition } from \"../types/config.js\";\n\n// ── Constants ───────────────────────────────────────────────────────────\n\nconst SKILL_FILENAME = \"SKILL.md\";\n\n// ── Types ───────────────────────────────────────────────────────────────\n\nexport type SkillSource = \"project\" | \"user\" | \"built-in\";\n\nexport interface ISkillSummary {\n readonly name: string;\n readonly description: string;\n readonly version: string;\n readonly source: SkillSource;\n readonly dirPath: string;\n}\n\ninterface ISkillEntry {\n readonly summary: ISkillSummary;\n definition: ISkillDefinition | null;\n}\n\n// ── SkillRegistry Class ─────────────────────────────────────────────────\n\nexport class SkillRegistry {\n private readonly loader: SkillLoader;\n private readonly skills: Map<string, ISkillEntry> = new Map();\n private readonly triggerIndex: Map<string, string> = new Map();\n private initialized = false;\n\n constructor(loader?: SkillLoader) {\n this.loader = loader ?? new SkillLoader();\n }\n\n /**\n * Initialize the registry by scanning all skill directories.\n * Loads in priority order so higher-priority sources override lower ones.\n */\n async initialize(projectRoot?: string): Promise<void> {\n if (this.initialized) return;\n\n // 1. Built-in skills (lowest priority)\n const builtInDir = this.getBuiltInSkillsDir();\n await this.scanDirectory(builtInDir, \"built-in\");\n\n // 2. User-level skills\n const userDir = getUserSkillsDir();\n await this.scanDirectory(userDir, \"user\");\n\n // 3. Project-level skills (highest priority)\n if (projectRoot) {\n const projectDir = getProjectSkillsDir(projectRoot);\n await this.scanDirectory(projectDir, \"project\");\n }\n\n this.initialized = true;\n logger.info(\n { totalSkills: this.skills.size, totalTriggers: this.triggerIndex.size },\n \"Skill registry initialized\",\n );\n }\n\n /**\n * Get a full skill definition by name. Loads content on demand.\n */\n async getByName(name: string): Promise<ISkillDefinition | null> {\n const entry = this.skills.get(name);\n if (!entry) return null;\n\n if (!entry.definition) {\n const filePath = join(entry.summary.dirPath, SKILL_FILENAME);\n entry.definition = await this.loader.loadSkillFile(filePath);\n }\n\n return entry.definition;\n }\n\n /**\n * Find a skill by trigger string (e.g. \"$review\" or \"review\").\n */\n async getByTrigger(trigger: string): Promise<ISkillDefinition | null> {\n const normalized = trigger.startsWith(\"$\") ? trigger.slice(1) : trigger;\n const withPrefix = `$${normalized}`;\n\n // Try both forms: with and without $ prefix\n const name =\n this.triggerIndex.get(withPrefix) ??\n this.triggerIndex.get(normalized) ??\n this.triggerIndex.get(trigger);\n\n if (!name) return null;\n return this.getByName(name);\n }\n\n /**\n * Resolve a trigger string to a skill name without loading the full definition.\n */\n resolveTriger(trigger: string): string | undefined {\n const normalized = trigger.startsWith(\"$\") ? trigger.slice(1) : trigger;\n const withPrefix = `$${normalized}`;\n\n return (\n this.triggerIndex.get(withPrefix) ??\n this.triggerIndex.get(normalized) ??\n this.triggerIndex.get(trigger)\n );\n }\n\n /**\n * List all registered skill summaries.\n */\n listAll(): readonly ISkillSummary[] {\n return Array.from(this.skills.values()).map((entry) => entry.summary);\n }\n\n /**\n * Check if a skill exists by name.\n */\n has(name: string): boolean {\n return this.skills.has(name);\n }\n\n /**\n * Get the count of registered skills.\n */\n get size(): number {\n return this.skills.size;\n }\n\n /**\n * Reset the registry for re-initialization.\n */\n reset(): void {\n this.skills.clear();\n this.triggerIndex.clear();\n this.initialized = false;\n }\n\n // ── Private Helpers ──────────────────────────────────────────────────\n\n /**\n * Scan a directory for skill subdirectories containing SKILL.md.\n */\n private async scanDirectory(dirPath: string, source: SkillSource): Promise<void> {\n let entries: string[];\n try {\n entries = await readdir(dirPath);\n } catch {\n logger.debug({ dirPath, source }, \"Skill directory not found, skipping\");\n return;\n }\n\n for (const entry of entries) {\n const skillDir = join(dirPath, entry);\n\n try {\n const info = await stat(skillDir);\n if (!info.isDirectory()) continue;\n } catch {\n continue;\n }\n\n const skillFile = join(skillDir, SKILL_FILENAME);\n try {\n await stat(skillFile);\n } catch {\n logger.debug({ skillDir }, \"No SKILL.md found in directory, skipping\");\n continue;\n }\n\n await this.registerSkillFromFile(skillFile, skillDir, source);\n }\n }\n\n /**\n * Register a single skill from its SKILL.md file path.\n */\n private async registerSkillFromFile(\n skillFile: string,\n skillDir: string,\n source: SkillSource,\n ): Promise<void> {\n const definition = await this.loader.loadSkillFile(skillFile);\n if (!definition) return;\n\n const { frontmatter } = definition;\n const summary: ISkillSummary = {\n name: frontmatter.name,\n description: frontmatter.description,\n version: frontmatter.version,\n source,\n dirPath: skillDir,\n };\n\n // Remove previous trigger mappings if overriding\n const existing = this.skills.get(summary.name);\n if (existing) {\n this.removeTriggers(existing.summary.name);\n logger.debug(\n {\n skill: summary.name,\n oldSource: existing.summary.source,\n newSource: source,\n },\n \"Skill overridden by higher-priority source\",\n );\n }\n\n this.skills.set(summary.name, { summary, definition });\n this.registerTriggers(definition);\n }\n\n /**\n * Index all triggers for a skill definition.\n */\n private registerTriggers(definition: ISkillDefinition): void {\n for (const trigger of definition.frontmatter.triggers) {\n this.triggerIndex.set(trigger, definition.frontmatter.name);\n }\n }\n\n /**\n * Remove all trigger mappings associated with a skill name.\n */\n private removeTriggers(skillName: string): void {\n const toDelete: string[] = [];\n for (const [trigger, name] of this.triggerIndex) {\n if (name === skillName) {\n toDelete.push(trigger);\n }\n }\n for (const trigger of toDelete) {\n this.triggerIndex.delete(trigger);\n }\n }\n\n /**\n * Resolve the built-in skills directory relative to this module.\n */\n private getBuiltInSkillsDir(): string {\n const currentFilePath = fileURLToPath(import.meta.url);\n return join(dirname(currentFilePath), \"built-in\");\n }\n}\n"]}
@@ -0,0 +1,211 @@
1
+ import { SUPPORTED_MODELS } from './chunk-HCIHOHLX.js';
2
+ import { ModelNotFoundError, AuthenticationError, RateLimitError } from './chunk-ZGOHARPV.js';
3
+ import { logger } from './chunk-JAXXTYID.js';
4
+ import { generateText, streamText } from 'ai';
5
+ import { createGoogleGenerativeAI } from '@ai-sdk/google';
6
+
7
+ var PROVIDER_NAME = "google";
8
+ var GEMINI_MODELS = [
9
+ "gemini-3-pro-preview",
10
+ "gemini-3-flash-preview",
11
+ "gemini-2.5-pro",
12
+ "gemini-2.5-flash",
13
+ "gemini-2.5-flash-lite"
14
+ ];
15
+ var CHARS_PER_TOKEN_ESTIMATE = 4;
16
+ function convertTools(tools) {
17
+ if (tools === void 0 || tools.length === 0) {
18
+ return void 0;
19
+ }
20
+ const result = {};
21
+ for (const tool of tools) {
22
+ const properties = {};
23
+ const required = [];
24
+ for (const param of tool.parameters) {
25
+ const prop = {
26
+ type: param.type,
27
+ description: param.description
28
+ };
29
+ if (param.enum !== void 0) {
30
+ prop["enum"] = param.enum;
31
+ }
32
+ if (param.default !== void 0) {
33
+ prop["default"] = param.default;
34
+ }
35
+ properties[param.name] = prop;
36
+ if (param.required) {
37
+ required.push(param.name);
38
+ }
39
+ }
40
+ result[tool.name] = {
41
+ description: tool.description,
42
+ parameters: { type: "object", properties, required }
43
+ };
44
+ }
45
+ return result;
46
+ }
47
+ function buildMessages(messages) {
48
+ return messages.map((msg) => ({
49
+ role: msg.role,
50
+ content: msg.content
51
+ }));
52
+ }
53
+ function computeCost(modelInfo, inputTokens, outputTokens) {
54
+ return inputTokens / 1e6 * modelInfo.inputPricePerMToken + outputTokens / 1e6 * modelInfo.outputPricePerMToken;
55
+ }
56
+ function classifyError(error, model) {
57
+ const message = error instanceof Error ? error.message : String(error);
58
+ const lower = message.toLowerCase();
59
+ if (lower.includes("401") || lower.includes("403") || lower.includes("unauthorized") || lower.includes("invalid api key")) {
60
+ throw new AuthenticationError(PROVIDER_NAME, message);
61
+ }
62
+ if (lower.includes("429") || lower.includes("rate limit") || lower.includes("resource exhausted")) {
63
+ const match = /(\d+)\s*s/i.exec(message);
64
+ const retryMs = match?.[1] !== void 0 ? parseInt(match[1], 10) * 1e3 : 6e4;
65
+ throw new RateLimitError(PROVIDER_NAME, retryMs);
66
+ }
67
+ if (lower.includes("model") && lower.includes("not found")) {
68
+ throw new ModelNotFoundError(model);
69
+ }
70
+ throw error instanceof Error ? error : new Error(message);
71
+ }
72
+ var GeminiAdapter = class {
73
+ name = PROVIDER_NAME;
74
+ supportedModels = GEMINI_MODELS;
75
+ google;
76
+ constructor(options) {
77
+ const apiKey = options?.apiKey ?? process.env["GOOGLE_API_KEY"];
78
+ this.google = createGoogleGenerativeAI({
79
+ ...apiKey !== void 0 ? { apiKey } : {},
80
+ ...options?.baseUrl !== void 0 ? { baseURL: options.baseUrl } : {}
81
+ });
82
+ }
83
+ async chat(request) {
84
+ const modelInfo = this.getModelInfo(request.model);
85
+ const messages = buildMessages(request.messages);
86
+ const tools = convertTools(request.tools);
87
+ try {
88
+ const result = await generateText({
89
+ model: this.google(request.model),
90
+ messages,
91
+ ...request.system !== void 0 ? { system: request.system } : {},
92
+ tools,
93
+ maxTokens: request.maxTokens ?? modelInfo.maxOutputTokens,
94
+ ...request.temperature !== void 0 ? { temperature: request.temperature } : {}
95
+ });
96
+ const toolCalls = extractToolCalls(result);
97
+ const inputTokens = result.usage?.promptTokens ?? 0;
98
+ const outputTokens = result.usage?.completionTokens ?? 0;
99
+ const usage = {
100
+ inputTokens,
101
+ outputTokens,
102
+ totalTokens: inputTokens + outputTokens,
103
+ costUsd: computeCost(modelInfo, inputTokens, outputTokens)
104
+ };
105
+ const responseMessage = {
106
+ id: result.response?.id ?? crypto.randomUUID(),
107
+ role: "assistant",
108
+ content: result.text,
109
+ model: request.model,
110
+ provider: PROVIDER_NAME,
111
+ toolCalls: toolCalls.length > 0 ? toolCalls : void 0,
112
+ tokenUsage: usage,
113
+ createdAt: /* @__PURE__ */ new Date()
114
+ };
115
+ return {
116
+ id: result.response?.id ?? crypto.randomUUID(),
117
+ model: request.model,
118
+ provider: PROVIDER_NAME,
119
+ message: responseMessage,
120
+ usage,
121
+ finishReason: mapFinishReason(result.finishReason)
122
+ };
123
+ } catch (error) {
124
+ classifyError(error, request.model);
125
+ }
126
+ }
127
+ async *stream(request) {
128
+ const modelInfo = this.getModelInfo(request.model);
129
+ const messages = buildMessages(request.messages);
130
+ const tools = convertTools(request.tools);
131
+ try {
132
+ const result = streamText({
133
+ model: this.google(request.model),
134
+ messages,
135
+ ...request.system !== void 0 ? { system: request.system } : {},
136
+ tools,
137
+ maxTokens: request.maxTokens ?? modelInfo.maxOutputTokens,
138
+ ...request.temperature !== void 0 ? { temperature: request.temperature } : {}
139
+ });
140
+ for await (const part of result.fullStream) {
141
+ if (part.type === "text-delta") {
142
+ yield { type: "text", content: part.textDelta };
143
+ } else if (part.type === "tool-call") {
144
+ const toolCall = {
145
+ id: part.toolCallId,
146
+ name: part.toolName,
147
+ arguments: part.args
148
+ };
149
+ yield { type: "tool_call", toolCall };
150
+ } else if (part.type === "finish") {
151
+ const inTok = part.usage?.promptTokens ?? 0;
152
+ const outTok = part.usage?.completionTokens ?? 0;
153
+ yield {
154
+ type: "usage",
155
+ usage: {
156
+ inputTokens: inTok,
157
+ outputTokens: outTok,
158
+ totalTokens: inTok + outTok,
159
+ costUsd: computeCost(modelInfo, inTok, outTok)
160
+ }
161
+ };
162
+ } else if (part.type === "error") {
163
+ const errMsg = part.error instanceof Error ? part.error.message : String(part.error);
164
+ yield { type: "error", error: errMsg };
165
+ }
166
+ }
167
+ yield { type: "done" };
168
+ } catch (error) {
169
+ const errMsg = error instanceof Error ? error.message : String(error);
170
+ logger.error({ error: errMsg, model: request.model }, "Gemini stream error");
171
+ yield { type: "error", error: errMsg };
172
+ yield { type: "done" };
173
+ }
174
+ }
175
+ async countTokens(text, _model) {
176
+ return Math.ceil(text.length / CHARS_PER_TOKEN_ESTIMATE);
177
+ }
178
+ getModelInfo(model) {
179
+ const info = SUPPORTED_MODELS[model];
180
+ if (info === void 0 || info.provider !== PROVIDER_NAME) {
181
+ throw new ModelNotFoundError(model);
182
+ }
183
+ return info;
184
+ }
185
+ };
186
+ function extractToolCalls(result) {
187
+ if (result.toolCalls === void 0 || result.toolCalls.length === 0) {
188
+ return [];
189
+ }
190
+ return result.toolCalls.map((tc) => ({
191
+ id: tc.toolCallId,
192
+ name: tc.toolName,
193
+ arguments: tc.args
194
+ }));
195
+ }
196
+ function mapFinishReason(reason) {
197
+ switch (reason) {
198
+ case "stop":
199
+ return "stop";
200
+ case "tool-calls":
201
+ return "tool_calls";
202
+ case "length":
203
+ return "max_tokens";
204
+ default:
205
+ return "stop";
206
+ }
207
+ }
208
+
209
+ export { GeminiAdapter };
210
+ //# sourceMappingURL=chunk-UY2SYSEZ.js.map
211
+ //# sourceMappingURL=chunk-UY2SYSEZ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/providers/gemini-adapter.ts"],"names":[],"mappings":";;;;;;AA0BA,IAAM,aAAA,GAA8B,QAAA;AAEpC,IAAM,aAAA,GAAmC;AAAA,EACvC,sBAAA;AAAA,EACA,wBAAA;AAAA,EACA,gBAAA;AAAA,EACA,kBAAA;AAAA,EACA;AACF,CAAA;AAEA,IAAM,wBAAA,GAA2B,CAAA;AAEjC,SAAS,aACP,KAAA,EAC0F;AAC1F,EAAA,IAAI,KAAA,KAAU,MAAA,IAAa,KAAA,CAAM,MAAA,KAAW,CAAA,EAAG;AAC7C,IAAA,OAAO,MAAA;AAAA,EACT;AACA,EAAA,MAAM,SAAuF,EAAC;AAC9F,EAAA,KAAA,MAAW,QAAQ,KAAA,EAAO;AACxB,IAAA,MAAM,aAAsC,EAAC;AAC7C,IAAA,MAAM,WAAqB,EAAC;AAC5B,IAAA,KAAA,MAAW,KAAA,IAAS,KAAK,UAAA,EAAY;AACnC,MAAA,MAAM,IAAA,GAAgC;AAAA,QACpC,MAAM,KAAA,CAAM,IAAA;AAAA,QACZ,aAAa,KAAA,CAAM;AAAA,OACrB;AACA,MAAA,IAAI,KAAA,CAAM,SAAS,MAAA,EAAW;AAC5B,QAAA,IAAA,CAAK,MAAM,IAAI,KAAA,CAAM,IAAA;AAAA,MACvB;AACA,MAAA,IAAI,KAAA,CAAM,YAAY,MAAA,EAAW;AAC/B,QAAA,IAAA,CAAK,SAAS,IAAI,KAAA,CAAM,OAAA;AAAA,MAC1B;AACA,MAAA,UAAA,CAAW,KAAA,CAAM,IAAI,CAAA,GAAI,IAAA;AACzB,MAAA,IAAI,MAAM,QAAA,EAAU;AAClB,QAAA,QAAA,CAAS,IAAA,CAAK,MAAM,IAAI,CAAA;AAAA,MAC1B;AAAA,IACF;AACA,IAAA,MAAA,CAAO,IAAA,CAAK,IAAI,CAAA,GAAI;AAAA,MAClB,aAAa,IAAA,CAAK,WAAA;AAAA,MAClB,UAAA,EAAY,EAAE,IAAA,EAAM,QAAA,EAAU,YAAY,QAAA;AAAS,KACrD;AAAA,EACF;AACA,EAAA,OAAO,MAAA;AACT;AAEA,SAAS,cACP,QAAA,EACe;AACf,EAAA,OAAO,QAAA,CAAS,GAAA,CAAI,CAAC,GAAA,MAAS;AAAA,IAC5B,MAAM,GAAA,CAAI,IAAA;AAAA,IACV,SAAS,GAAA,CAAI;AAAA,GACf,CAAE,CAAA;AACJ;AAEA,SAAS,WAAA,CAAY,SAAA,EAAuB,WAAA,EAAqB,YAAA,EAA8B;AAC7F,EAAA,OACG,cAAc,GAAA,GAAa,SAAA,CAAU,mBAAA,GACrC,YAAA,GAAe,MAAa,SAAA,CAAU,oBAAA;AAE3C;AAEA,SAAS,aAAA,CAAc,OAAgB,KAAA,EAAsB;AAC3D,EAAA,MAAM,UAAU,KAAA,YAAiB,KAAA,GAAQ,KAAA,CAAM,OAAA,GAAU,OAAO,KAAK,CAAA;AACrE,EAAA,MAAM,KAAA,GAAQ,QAAQ,WAAA,EAAY;AAClC,EAAA,IAAI,KAAA,CAAM,QAAA,CAAS,KAAK,CAAA,IAAK,MAAM,QAAA,CAAS,KAAK,CAAA,IAAK,KAAA,CAAM,SAAS,cAAc,CAAA,IAAK,KAAA,CAAM,QAAA,CAAS,iBAAiB,CAAA,EAAG;AACzH,IAAA,MAAM,IAAI,mBAAA,CAAoB,aAAA,EAAe,OAAO,CAAA;AAAA,EACtD;AACA,EAAA,IAAI,KAAA,CAAM,QAAA,CAAS,KAAK,CAAA,IAAK,KAAA,CAAM,QAAA,CAAS,YAAY,CAAA,IAAK,KAAA,CAAM,QAAA,CAAS,oBAAoB,CAAA,EAAG;AACjG,IAAA,MAAM,KAAA,GAAQ,YAAA,CAAa,IAAA,CAAK,OAAO,CAAA;AACvC,IAAA,MAAM,OAAA,GAAU,KAAA,GAAQ,CAAC,CAAA,KAAM,MAAA,GAAY,QAAA,CAAS,KAAA,CAAM,CAAC,CAAA,EAAG,EAAE,CAAA,GAAI,GAAA,GAAO,GAAA;AAC3E,IAAA,MAAM,IAAI,cAAA,CAAe,aAAA,EAAe,OAAO,CAAA;AAAA,EACjD;AACA,EAAA,IAAI,MAAM,QAAA,CAAS,OAAO,KAAK,KAAA,CAAM,QAAA,CAAS,WAAW,CAAA,EAAG;AAC1D,IAAA,MAAM,IAAI,mBAAmB,KAAK,CAAA;AAAA,EACpC;AACA,EAAA,MAAM,KAAA,YAAiB,KAAA,GAAQ,KAAA,GAAQ,IAAI,MAAM,OAAO,CAAA;AAC1D;AAEO,IAAM,gBAAN,MAA8C;AAAA,EAC1C,IAAA,GAAO,aAAA;AAAA,EACP,eAAA,GAAkB,aAAA;AAAA,EACV,MAAA;AAAA,EAEjB,YAAY,OAAA,EAA4B;AACtC,IAAA,MAAM,MAAA,GAAS,OAAA,EAAS,MAAA,IAAU,OAAA,CAAQ,IAAI,gBAAgB,CAAA;AAC9D,IAAA,IAAA,CAAK,SAAS,wBAAA,CAAyB;AAAA,MACrC,GAAI,MAAA,KAAW,MAAA,GAAY,EAAE,MAAA,KAAW,EAAC;AAAA,MACzC,GAAI,SAAS,OAAA,KAAY,MAAA,GAAY,EAAE,OAAA,EAAS,OAAA,CAAQ,OAAA,EAAQ,GAAI;AAAC,KACtE,CAAA;AAAA,EACH;AAAA,EAEA,MAAM,KAAK,OAAA,EAA+C;AACxD,IAAA,MAAM,SAAA,GAAY,IAAA,CAAK,YAAA,CAAa,OAAA,CAAQ,KAAK,CAAA;AACjD,IAAA,MAAM,QAAA,GAAW,aAAA,CAAc,OAAA,CAAQ,QAAQ,CAAA;AAC/C,IAAA,MAAM,KAAA,GAAQ,YAAA,CAAa,OAAA,CAAQ,KAAK,CAAA;AACxC,IAAA,IAAI;AACF,MAAA,MAAM,MAAA,GAAS,MAAM,YAAA,CAAa;AAAA,QAChC,KAAA,EAAO,IAAA,CAAK,MAAA,CAAO,OAAA,CAAQ,KAAK,CAAA;AAAA,QAChC,QAAA;AAAA,QACA,GAAI,QAAQ,MAAA,KAAW,KAAA,CAAA,GAAY,EAAE,MAAA,EAAQ,OAAA,CAAQ,MAAA,EAAO,GAAI,EAAC;AAAA,QACjE,KAAA;AAAA,QACA,SAAA,EAAW,OAAA,CAAQ,SAAA,IAAa,SAAA,CAAU,eAAA;AAAA,QAC1C,GAAI,QAAQ,WAAA,KAAgB,KAAA,CAAA,GAAY,EAAE,WAAA,EAAa,OAAA,CAAQ,WAAA,EAAY,GAAI;AAAC,OACjF,CAAA;AACD,MAAA,MAAM,SAAA,GAAY,iBAAiB,MAAM,CAAA;AACzC,MAAA,MAAM,WAAA,GAAc,MAAA,CAAO,KAAA,EAAO,YAAA,IAAgB,CAAA;AAClD,MAAA,MAAM,YAAA,GAAe,MAAA,CAAO,KAAA,EAAO,gBAAA,IAAoB,CAAA;AACvD,MAAA,MAAM,KAAA,GAAqB;AAAA,QACzB,WAAA;AAAA,QACA,YAAA;AAAA,QACA,aAAa,WAAA,GAAc,YAAA;AAAA,QAC3B,OAAA,EAAS,WAAA,CAAY,SAAA,EAAW,WAAA,EAAa,YAAY;AAAA,OAC3D;AACA,MAAA,MAAM,eAAA,GAAgC;AAAA,QACpC,EAAA,EAAI,MAAA,CAAO,QAAA,EAAU,EAAA,IAAM,OAAO,UAAA,EAAW;AAAA,QAC7C,IAAA,EAAM,WAAA;AAAA,QACN,SAAS,MAAA,CAAO,IAAA;AAAA,QAChB,OAAO,OAAA,CAAQ,KAAA;AAAA,QACf,QAAA,EAAU,aAAA;AAAA,QACV,SAAA,EAAW,SAAA,CAAU,MAAA,GAAS,CAAA,GAAI,SAAA,GAAY,KAAA,CAAA;AAAA,QAC9C,UAAA,EAAY,KAAA;AAAA,QACZ,SAAA,sBAAe,IAAA;AAAK,OACtB;AACA,MAAA,OAAO;AAAA,QACL,EAAA,EAAI,MAAA,CAAO,QAAA,EAAU,EAAA,IAAM,OAAO,UAAA,EAAW;AAAA,QAC7C,OAAO,OAAA,CAAQ,KAAA;AAAA,QACf,QAAA,EAAU,aAAA;AAAA,QACV,OAAA,EAAS,eAAA;AAAA,QACT,KAAA;AAAA,QACA,YAAA,EAAc,eAAA,CAAgB,MAAA,CAAO,YAAY;AAAA,OACnD;AAAA,IACF,SAAS,KAAA,EAAgB;AACvB,MAAA,aAAA,CAAc,KAAA,EAAO,QAAQ,KAAK,CAAA;AAAA,IACpC;AAAA,EACF;AAAA,EAEA,OAAO,OAAO,OAAA,EAAoD;AAChE,IAAA,MAAM,SAAA,GAAY,IAAA,CAAK,YAAA,CAAa,OAAA,CAAQ,KAAK,CAAA;AACjD,IAAA,MAAM,QAAA,GAAW,aAAA,CAAc,OAAA,CAAQ,QAAQ,CAAA;AAC/C,IAAA,MAAM,KAAA,GAAQ,YAAA,CAAa,OAAA,CAAQ,KAAK,CAAA;AACxC,IAAA,IAAI;AACF,MAAA,MAAM,SAAS,UAAA,CAAW;AAAA,QACxB,KAAA,EAAO,IAAA,CAAK,MAAA,CAAO,OAAA,CAAQ,KAAK,CAAA;AAAA,QAChC,QAAA;AAAA,QACA,GAAI,QAAQ,MAAA,KAAW,KAAA,CAAA,GAAY,EAAE,MAAA,EAAQ,OAAA,CAAQ,MAAA,EAAO,GAAI,EAAC;AAAA,QACjE,KAAA;AAAA,QACA,SAAA,EAAW,OAAA,CAAQ,SAAA,IAAa,SAAA,CAAU,eAAA;AAAA,QAC1C,GAAI,QAAQ,WAAA,KAAgB,KAAA,CAAA,GAAY,EAAE,WAAA,EAAa,OAAA,CAAQ,WAAA,EAAY,GAAI;AAAC,OACjF,CAAA;AACD,MAAA,WAAA,MAAiB,IAAA,IAAQ,OAAO,UAAA,EAAY;AAC1C,QAAA,IAAI,IAAA,CAAK,SAAS,YAAA,EAAc;AAC9B,UAAA,MAAM,EAAE,IAAA,EAAM,MAAA,EAAQ,OAAA,EAAS,KAAK,SAAA,EAAU;AAAA,QAChD,CAAA,MAAA,IAAW,IAAA,CAAK,IAAA,KAAS,WAAA,EAAa;AACpC,UAAA,MAAM,QAAA,GAAsB;AAAA,YAC1B,IAAI,IAAA,CAAK,UAAA;AAAA,YACT,MAAM,IAAA,CAAK,QAAA;AAAA,YACX,WAAW,IAAA,CAAK;AAAA,WAClB;AACA,UAAA,MAAM,EAAE,IAAA,EAAM,WAAA,EAAa,QAAA,EAAS;AAAA,QACtC,CAAA,MAAA,IAAW,IAAA,CAAK,IAAA,KAAS,QAAA,EAAU;AACjC,UAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,KAAA,EAAO,YAAA,IAAgB,CAAA;AAC1C,UAAA,MAAM,MAAA,GAAS,IAAA,CAAK,KAAA,EAAO,gBAAA,IAAoB,CAAA;AAC/C,UAAA,MAAM;AAAA,YACJ,IAAA,EAAM,OAAA;AAAA,YACN,KAAA,EAAO;AAAA,cACL,WAAA,EAAa,KAAA;AAAA,cACb,YAAA,EAAc,MAAA;AAAA,cACd,aAAa,KAAA,GAAQ,MAAA;AAAA,cACrB,OAAA,EAAS,WAAA,CAAY,SAAA,EAAW,KAAA,EAAO,MAAM;AAAA;AAC/C,WACF;AAAA,QACF,CAAA,MAAA,IAAW,IAAA,CAAK,IAAA,KAAS,OAAA,EAAS;AAChC,UAAA,MAAM,MAAA,GAAS,KAAK,KAAA,YAAiB,KAAA,GAAQ,KAAK,KAAA,CAAM,OAAA,GAAU,MAAA,CAAO,IAAA,CAAK,KAAK,CAAA;AACnF,UAAA,MAAM,EAAE,IAAA,EAAM,OAAA,EAAS,KAAA,EAAO,MAAA,EAAO;AAAA,QACvC;AAAA,MACF;AACA,MAAA,MAAM,EAAE,MAAM,MAAA,EAAO;AAAA,IACvB,SAAS,KAAA,EAAgB;AACvB,MAAA,MAAM,SAAS,KAAA,YAAiB,KAAA,GAAQ,KAAA,CAAM,OAAA,GAAU,OAAO,KAAK,CAAA;AACpE,MAAA,MAAA,CAAO,KAAA,CAAM,EAAE,KAAA,EAAO,MAAA,EAAQ,OAAO,OAAA,CAAQ,KAAA,IAAS,qBAAqB,CAAA;AAC3E,MAAA,MAAM,EAAE,IAAA,EAAM,OAAA,EAAS,KAAA,EAAO,MAAA,EAAO;AACrC,MAAA,MAAM,EAAE,MAAM,MAAA,EAAO;AAAA,IACvB;AAAA,EACF;AAAA,EAEA,MAAM,WAAA,CAAY,IAAA,EAAc,MAAA,EAAiC;AAC/D,IAAA,OAAO,IAAA,CAAK,IAAA,CAAK,IAAA,CAAK,MAAA,GAAS,wBAAwB,CAAA;AAAA,EACzD;AAAA,EAEA,aAAa,KAAA,EAA2B;AACtC,IAAA,MAAM,IAAA,GAAO,iBAAiB,KAAK,CAAA;AACnC,IAAA,IAAI,IAAA,KAAS,MAAA,IAAa,IAAA,CAAK,QAAA,KAAa,aAAA,EAAe;AACzD,MAAA,MAAM,IAAI,mBAAmB,KAAK,CAAA;AAAA,IACpC;AACA,IAAA,OAAO,IAAA;AAAA,EACT;AACF;AAEA,SAAS,iBACP,MAAA,EACa;AACb,EAAA,IAAI,OAAO,SAAA,KAAc,MAAA,IAAa,MAAA,CAAO,SAAA,CAAU,WAAW,CAAA,EAAG;AACnE,IAAA,OAAO,EAAC;AAAA,EACV;AACA,EAAA,OAAO,MAAA,CAAO,SAAA,CAAU,GAAA,CAAI,CAAC,EAAA,MAAQ;AAAA,IACnC,IAAI,EAAA,CAAG,UAAA;AAAA,IACP,MAAM,EAAA,CAAG,QAAA;AAAA,IACT,WAAW,EAAA,CAAG;AAAA,GAChB,CAAE,CAAA;AACJ;AAEA,SAAS,gBACP,MAAA,EACgD;AAChD,EAAA,QAAQ,MAAA;AAAQ,IACd,KAAK,MAAA;AACH,MAAA,OAAO,MAAA;AAAA,IACT,KAAK,YAAA;AACH,MAAA,OAAO,YAAA;AAAA,IACT,KAAK,QAAA;AACH,MAAA,OAAO,YAAA;AAAA,IACT;AACE,MAAA,OAAO,MAAA;AAAA;AAEb","file":"chunk-UY2SYSEZ.js","sourcesContent":["/**\n * Gemini (Google) adapter via Vercel AI SDK per PRD section 7.1\n * Supports Gemini 2.5 Pro, Gemini 2.5 Flash\n */\n\nimport { generateText, streamText, type CoreMessage } from \"ai\";\nimport { createGoogleGenerativeAI } from \"@ai-sdk/google\";\nimport { logger } from \"../utils/logger.js\";\nimport {\n AuthenticationError,\n RateLimitError,\n ModelNotFoundError,\n} from \"../types/errors.js\";\nimport { SUPPORTED_MODELS } from \"../types/model.js\";\nimport type { IModelInfo, ProviderName } from \"../types/model.js\";\nimport type {\n IChatRequest,\n IChatResponse,\n IChatMessage,\n IStreamChunk,\n IToolCall,\n IToolDefinition,\n ITokenUsage,\n} from \"../types/message.js\";\nimport type { IModelProvider, IProviderOptions } from \"./types.js\";\n\nconst PROVIDER_NAME: ProviderName = \"google\";\n\nconst GEMINI_MODELS: readonly string[] = [\n \"gemini-3-pro-preview\",\n \"gemini-3-flash-preview\",\n \"gemini-2.5-pro\",\n \"gemini-2.5-flash\",\n \"gemini-2.5-flash-lite\",\n] as const;\n\nconst CHARS_PER_TOKEN_ESTIMATE = 4;\n\nfunction convertTools(\n tools: readonly IToolDefinition[] | undefined,\n): Record<string, { description: string; parameters: Record<string, unknown> }> | undefined {\n if (tools === undefined || tools.length === 0) {\n return undefined;\n }\n const result: Record<string, { description: string; parameters: Record<string, unknown> }> = {};\n for (const tool of tools) {\n const properties: Record<string, unknown> = {};\n const required: string[] = [];\n for (const param of tool.parameters) {\n const prop: Record<string, unknown> = {\n type: param.type,\n description: param.description,\n };\n if (param.enum !== undefined) {\n prop[\"enum\"] = param.enum;\n }\n if (param.default !== undefined) {\n prop[\"default\"] = param.default;\n }\n properties[param.name] = prop;\n if (param.required) {\n required.push(param.name);\n }\n }\n result[tool.name] = {\n description: tool.description,\n parameters: { type: \"object\", properties, required },\n };\n }\n return result;\n}\n\nfunction buildMessages(\n messages: readonly IChatMessage[],\n): CoreMessage[] {\n return messages.map((msg) => ({\n role: msg.role as \"user\" | \"assistant\" | \"system\" | \"tool\",\n content: msg.content,\n })) as CoreMessage[];\n}\n\nfunction computeCost(modelInfo: IModelInfo, inputTokens: number, outputTokens: number): number {\n return (\n (inputTokens / 1_000_000) * modelInfo.inputPricePerMToken +\n (outputTokens / 1_000_000) * modelInfo.outputPricePerMToken\n );\n}\n\nfunction classifyError(error: unknown, model: string): never {\n const message = error instanceof Error ? error.message : String(error);\n const lower = message.toLowerCase();\n if (lower.includes(\"401\") || lower.includes(\"403\") || lower.includes(\"unauthorized\") || lower.includes(\"invalid api key\")) {\n throw new AuthenticationError(PROVIDER_NAME, message);\n }\n if (lower.includes(\"429\") || lower.includes(\"rate limit\") || lower.includes(\"resource exhausted\")) {\n const match = /(\\d+)\\s*s/i.exec(message);\n const retryMs = match?.[1] !== undefined ? parseInt(match[1], 10) * 1000 : 60_000;\n throw new RateLimitError(PROVIDER_NAME, retryMs);\n }\n if (lower.includes(\"model\") && lower.includes(\"not found\")) {\n throw new ModelNotFoundError(model);\n }\n throw error instanceof Error ? error : new Error(message);\n}\n\nexport class GeminiAdapter implements IModelProvider {\n readonly name = PROVIDER_NAME;\n readonly supportedModels = GEMINI_MODELS;\n private readonly google: ReturnType<typeof createGoogleGenerativeAI>;\n\n constructor(options?: IProviderOptions) {\n const apiKey = options?.apiKey ?? process.env[\"GOOGLE_API_KEY\"];\n this.google = createGoogleGenerativeAI({\n ...(apiKey !== undefined ? { apiKey } : {}),\n ...(options?.baseUrl !== undefined ? { baseURL: options.baseUrl } : {}),\n });\n }\n\n async chat(request: IChatRequest): Promise<IChatResponse> {\n const modelInfo = this.getModelInfo(request.model);\n const messages = buildMessages(request.messages);\n const tools = convertTools(request.tools);\n try {\n const result = await generateText({\n model: this.google(request.model),\n messages,\n ...(request.system !== undefined ? { system: request.system } : {}),\n tools: tools as Record<string, never>,\n maxTokens: request.maxTokens ?? modelInfo.maxOutputTokens,\n ...(request.temperature !== undefined ? { temperature: request.temperature } : {}),\n });\n const toolCalls = extractToolCalls(result);\n const inputTokens = result.usage?.promptTokens ?? 0;\n const outputTokens = result.usage?.completionTokens ?? 0;\n const usage: ITokenUsage = {\n inputTokens,\n outputTokens,\n totalTokens: inputTokens + outputTokens,\n costUsd: computeCost(modelInfo, inputTokens, outputTokens),\n };\n const responseMessage: IChatMessage = {\n id: result.response?.id ?? crypto.randomUUID(),\n role: \"assistant\",\n content: result.text,\n model: request.model,\n provider: PROVIDER_NAME,\n toolCalls: toolCalls.length > 0 ? toolCalls : undefined,\n tokenUsage: usage,\n createdAt: new Date(),\n };\n return {\n id: result.response?.id ?? crypto.randomUUID(),\n model: request.model,\n provider: PROVIDER_NAME,\n message: responseMessage,\n usage,\n finishReason: mapFinishReason(result.finishReason),\n };\n } catch (error: unknown) {\n classifyError(error, request.model);\n }\n }\n\n async *stream(request: IChatRequest): AsyncIterable<IStreamChunk> {\n const modelInfo = this.getModelInfo(request.model);\n const messages = buildMessages(request.messages);\n const tools = convertTools(request.tools);\n try {\n const result = streamText({\n model: this.google(request.model),\n messages,\n ...(request.system !== undefined ? { system: request.system } : {}),\n tools: tools as Record<string, never>,\n maxTokens: request.maxTokens ?? modelInfo.maxOutputTokens,\n ...(request.temperature !== undefined ? { temperature: request.temperature } : {}),\n });\n for await (const part of result.fullStream) {\n if (part.type === \"text-delta\") {\n yield { type: \"text\", content: part.textDelta };\n } else if (part.type === \"tool-call\") {\n const toolCall: IToolCall = {\n id: part.toolCallId,\n name: part.toolName,\n arguments: part.args as Record<string, unknown>,\n };\n yield { type: \"tool_call\", toolCall };\n } else if (part.type === \"finish\") {\n const inTok = part.usage?.promptTokens ?? 0;\n const outTok = part.usage?.completionTokens ?? 0;\n yield {\n type: \"usage\",\n usage: {\n inputTokens: inTok,\n outputTokens: outTok,\n totalTokens: inTok + outTok,\n costUsd: computeCost(modelInfo, inTok, outTok),\n },\n };\n } else if (part.type === \"error\") {\n const errMsg = part.error instanceof Error ? part.error.message : String(part.error);\n yield { type: \"error\", error: errMsg };\n }\n }\n yield { type: \"done\" };\n } catch (error: unknown) {\n const errMsg = error instanceof Error ? error.message : String(error);\n logger.error({ error: errMsg, model: request.model }, \"Gemini stream error\");\n yield { type: \"error\", error: errMsg };\n yield { type: \"done\" };\n }\n }\n\n async countTokens(text: string, _model: string): Promise<number> {\n return Math.ceil(text.length / CHARS_PER_TOKEN_ESTIMATE);\n }\n\n getModelInfo(model: string): IModelInfo {\n const info = SUPPORTED_MODELS[model];\n if (info === undefined || info.provider !== PROVIDER_NAME) {\n throw new ModelNotFoundError(model);\n }\n return info;\n }\n}\n\nfunction extractToolCalls(\n result: { toolCalls?: ReadonlyArray<{ toolCallId: string; toolName: string; args: unknown }> },\n): IToolCall[] {\n if (result.toolCalls === undefined || result.toolCalls.length === 0) {\n return [];\n }\n return result.toolCalls.map((tc) => ({\n id: tc.toolCallId,\n name: tc.toolName,\n arguments: tc.args as Record<string, unknown>,\n }));\n}\n\nfunction mapFinishReason(\n reason: string | undefined,\n): \"stop\" | \"tool_calls\" | \"max_tokens\" | \"error\" {\n switch (reason) {\n case \"stop\":\n return \"stop\";\n case \"tool-calls\":\n return \"tool_calls\";\n case \"length\":\n return \"max_tokens\";\n default:\n return \"stop\";\n }\n}\n"]}