@ftarganski/omni-ai 0.1.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 (49) hide show
  1. package/dist/chunk-3RZELMF2.js +214 -0
  2. package/dist/chunk-5WELBZWN.js +70 -0
  3. package/dist/chunk-6APAA6WD.js +495 -0
  4. package/dist/chunk-6OPRALDC.js +163 -0
  5. package/dist/chunk-6YFFZMXY.js +104 -0
  6. package/dist/chunk-AG6NZIJ3.js +122 -0
  7. package/dist/chunk-AWMSN7OB.js +451 -0
  8. package/dist/chunk-JTXDF5KG.js +156 -0
  9. package/dist/chunk-M4QJF7CV.js +57 -0
  10. package/dist/chunk-PPTEJ2FH.js +102 -0
  11. package/dist/chunk-S5MK6LBH.js +136 -0
  12. package/dist/chunk-TFU437SW.js +107 -0
  13. package/dist/chunk-Y4EYGADJ.js +216 -0
  14. package/dist/cli/bin.js +2723 -0
  15. package/dist/index.d.ts +16 -0
  16. package/dist/index.js +42 -0
  17. package/dist/mcp.d.ts +1 -0
  18. package/dist/mcp.js +86 -0
  19. package/dist/memory.d.ts +1 -0
  20. package/dist/memory.js +320 -0
  21. package/dist/provider-anthropic.d.ts +1 -0
  22. package/dist/provider-anthropic.js +120 -0
  23. package/dist/provider-google.d.ts +1 -0
  24. package/dist/provider-google.js +141 -0
  25. package/dist/provider-openai.d.ts +1 -0
  26. package/dist/provider-openai.js +214 -0
  27. package/dist/skills/backend.d.ts +1 -0
  28. package/dist/skills/backend.js +12 -0
  29. package/dist/skills/code.d.ts +1 -0
  30. package/dist/skills/code.js +6 -0
  31. package/dist/skills/frontend.d.ts +1 -0
  32. package/dist/skills/frontend.js +10 -0
  33. package/dist/skills/fs.d.ts +1 -0
  34. package/dist/skills/fs.js +10 -0
  35. package/dist/skills/git.d.ts +1 -0
  36. package/dist/skills/git.js +12 -0
  37. package/dist/skills/http.d.ts +1 -0
  38. package/dist/skills/http.js +6 -0
  39. package/dist/skills/index.d.ts +1 -0
  40. package/dist/skills/index.js +60 -0
  41. package/dist/skills/multimodal.d.ts +1 -0
  42. package/dist/skills/multimodal.js +6 -0
  43. package/dist/skills/qa.d.ts +1 -0
  44. package/dist/skills/qa.js +8 -0
  45. package/dist/skills/ux.d.ts +1 -0
  46. package/dist/skills/ux.js +6 -0
  47. package/dist/src-6MUVU5ML.js +8 -0
  48. package/dist/src-ZHTGR7T6.js +8 -0
  49. package/package.json +136 -0
@@ -0,0 +1,495 @@
1
+ // ../core/src/middleware/compose.ts
2
+ function composeMiddleware(fns, skill) {
3
+ if (fns.length === 0) return skill;
4
+ return {
5
+ name: skill.name,
6
+ description: skill.description,
7
+ execute(input, ctx) {
8
+ let index = 0;
9
+ const dispatch = () => {
10
+ if (index < fns.length) {
11
+ const fn = fns[index++];
12
+ return fn(skill.name, input, ctx, dispatch);
13
+ }
14
+ return skill.execute(input, ctx);
15
+ };
16
+ return dispatch();
17
+ }
18
+ };
19
+ }
20
+
21
+ // ../core/src/types.ts
22
+ function contentToString(content) {
23
+ if (typeof content === "string") return content;
24
+ return content.map((p) => p.type === "text" ? p.text : `[image:${p.mimeType}]`).join("");
25
+ }
26
+
27
+ // ../core/src/agents/agent.ts
28
+ var Agent = class {
29
+ config;
30
+ provider;
31
+ skills;
32
+ constructor(config, provider, skills = []) {
33
+ this.config = config;
34
+ this.provider = provider;
35
+ this.skills = new Map(skills.map((s) => [s.name, s]));
36
+ }
37
+ async run(options) {
38
+ const memCfg = this.config.memory;
39
+ const session = options.session;
40
+ const store = memCfg?.store;
41
+ const compactor = memCfg?.compactor;
42
+ const maxCtxTokens = memCfg?.maxContextTokens ?? 8e4;
43
+ const history = session && store ? (await store.loadMessages(session)).map((e) => ({ role: e.role, content: e.content })) : [];
44
+ const messages = [...history];
45
+ const newMessages = [];
46
+ const firstMsg = { role: "user", content: options.input };
47
+ messages.push(firstMsg);
48
+ newMessages.push(firstMsg);
49
+ const tools = this.buildToolDefinitions();
50
+ const ctx = { provider: this.provider, config: options.context ?? {} };
51
+ const maxIterations = this.config.maxIterations ?? 10;
52
+ let iterations = 0;
53
+ let totalInput = 0;
54
+ let totalOutput = 0;
55
+ while (iterations < maxIterations) {
56
+ iterations++;
57
+ if (compactor?.shouldCompact(messages, maxCtxTokens)) {
58
+ const compacted = await compactor.compact(messages, this.provider);
59
+ messages.splice(0, messages.length, ...compacted);
60
+ }
61
+ const response = await this.provider.complete({
62
+ messages,
63
+ model: this.config.model,
64
+ systemPrompt: this.config.systemPrompt,
65
+ temperature: this.config.temperature,
66
+ tools: tools.length > 0 ? tools : void 0,
67
+ onToken: options.onToken
68
+ });
69
+ if (response.usage) {
70
+ totalInput += response.usage.inputTokens;
71
+ totalOutput += response.usage.outputTokens;
72
+ }
73
+ if (!response.toolCalls || response.toolCalls.length === 0) {
74
+ const finalMsg = { role: "assistant", content: response.content };
75
+ messages.push(finalMsg);
76
+ newMessages.push(finalMsg);
77
+ await this.persist(store, session, newMessages);
78
+ return {
79
+ output: response.content,
80
+ iterations,
81
+ usage: { inputTokens: totalInput, outputTokens: totalOutput }
82
+ };
83
+ }
84
+ const assistantMsg = { role: "assistant", content: response.content };
85
+ messages.push(assistantMsg);
86
+ newMessages.push(assistantMsg);
87
+ for (const call of response.toolCalls) {
88
+ const result = await this.executeToolCall(call, ctx);
89
+ const toolMsg = { role: "user", content: `[Tool ${call.name} result]: ${result}` };
90
+ messages.push(toolMsg);
91
+ newMessages.push(toolMsg);
92
+ }
93
+ }
94
+ await this.persist(store, session, newMessages);
95
+ throw new Error(`Agent "${this.config.name}" exceeded maxIterations (${maxIterations})`);
96
+ }
97
+ async persist(store, session, messages) {
98
+ if (!store || !session || messages.length === 0) return;
99
+ const entries = messages.map((m) => ({
100
+ role: m.role,
101
+ content: contentToString(m.content),
102
+ timestamp: Date.now()
103
+ }));
104
+ await store.saveMessages(session, entries);
105
+ }
106
+ buildToolDefinitions() {
107
+ return [...this.skills.values()].map((skill) => ({
108
+ name: skill.name,
109
+ description: skill.description,
110
+ parameters: { type: "object", properties: {}, additionalProperties: true }
111
+ }));
112
+ }
113
+ async executeToolCall(call, ctx) {
114
+ const skill = this.skills.get(call.name);
115
+ if (!skill) return `Error: skill "${call.name}" not found`;
116
+ try {
117
+ const middleware = this.config.middleware ?? [];
118
+ const wrapped = composeMiddleware(middleware, skill);
119
+ const result = await wrapped.execute(call.arguments, ctx);
120
+ return typeof result === "string" ? result : JSON.stringify(result);
121
+ } catch (err) {
122
+ return `Error: ${err instanceof Error ? err.message : String(err)}`;
123
+ }
124
+ }
125
+ };
126
+
127
+ // ../core/src/config/schema.ts
128
+ import { z } from "zod";
129
+ var RetryConfigSchema = z.object({
130
+ maxRetries: z.number().int().positive().default(3),
131
+ initialDelayMs: z.number().int().positive().default(500),
132
+ maxDelayMs: z.number().int().positive().default(3e4)
133
+ });
134
+ var ProviderConfigSchema = z.object({
135
+ name: z.string(),
136
+ type: z.enum(["anthropic", "openai", "copilot", "google", "groq", "ollama", "custom"]),
137
+ // nullish handles YAML empty value (parsed as null) and absent key (undefined)
138
+ apiKey: z.string().nullish().transform((v) => v ?? void 0),
139
+ baseUrl: z.string().url().nullish().transform((v) => v ?? void 0),
140
+ defaultModel: z.string().nullish().transform((v) => v ?? void 0),
141
+ options: z.record(z.unknown()).optional(),
142
+ retry: RetryConfigSchema.optional(),
143
+ fallback: z.string().optional()
144
+ });
145
+ var AgentConfigSchema = z.object({
146
+ name: z.string(),
147
+ description: z.string(),
148
+ provider: z.string().optional(),
149
+ model: z.string().optional(),
150
+ systemPrompt: z.string(),
151
+ skills: z.array(z.string()).optional(),
152
+ maxIterations: z.number().int().positive().default(10),
153
+ temperature: z.number().min(0).max(2).optional()
154
+ });
155
+ var ScaffoldPathsSchema = z.object({
156
+ agents: z.string().default("agents"),
157
+ skills: z.string().default("src/skills"),
158
+ providers: z.string().default("packages")
159
+ });
160
+ var OmniAiConfigSchema = z.object({
161
+ version: z.string().default("1"),
162
+ providers: z.array(ProviderConfigSchema).min(1, "At least one provider must be configured"),
163
+ defaultProvider: z.string(),
164
+ agentsDir: z.string().default("agents"),
165
+ scaffoldPaths: ScaffoldPathsSchema.optional(),
166
+ agents: z.array(AgentConfigSchema).optional()
167
+ });
168
+
169
+ // ../core/src/providers/fallback.ts
170
+ var FallbackProvider = class {
171
+ name;
172
+ capabilities;
173
+ providers;
174
+ constructor(providers) {
175
+ if (providers.length === 0) throw new Error("FallbackProvider requires at least one provider");
176
+ this.providers = providers;
177
+ this.name = providers.map((p) => p.name).join("|");
178
+ this.capabilities = providers.reduce(
179
+ (acc, p) => ({
180
+ chat: acc.chat || p.capabilities.chat,
181
+ embedding: acc.embedding || p.capabilities.embedding,
182
+ streaming: acc.streaming || p.capabilities.streaming,
183
+ toolUse: acc.toolUse || p.capabilities.toolUse,
184
+ vision: acc.vision || p.capabilities.vision
185
+ }),
186
+ { chat: false, embedding: false, streaming: false, toolUse: false, vision: false }
187
+ );
188
+ }
189
+ async complete(request) {
190
+ const errors = [];
191
+ for (const provider of this.providers) {
192
+ try {
193
+ return await provider.complete(request);
194
+ } catch (err) {
195
+ errors.push(err instanceof Error ? err : new Error(String(err)));
196
+ }
197
+ }
198
+ throw new Error(
199
+ `All providers failed:
200
+ ${errors.map((e, i) => ` [${this.providers[i].name}] ${e.message}`).join("\n")}`
201
+ );
202
+ }
203
+ async embed(request) {
204
+ const errors = [];
205
+ for (const provider of this.providers) {
206
+ if (!provider.embed) continue;
207
+ try {
208
+ return await provider.embed(request);
209
+ } catch (err) {
210
+ errors.push(err instanceof Error ? err : new Error(String(err)));
211
+ }
212
+ }
213
+ if (errors.length === 0) throw new Error(`No provider in "${this.name}" supports embeddings`);
214
+ throw new Error(
215
+ `All providers failed for embed:
216
+ ${errors.map((e, i) => ` [${this.providers[i].name}] ${e.message}`).join("\n")}`
217
+ );
218
+ }
219
+ };
220
+
221
+ // ../core/src/providers/retry.ts
222
+ function isRetryable(err) {
223
+ if (!(err instanceof Error)) return false;
224
+ const msg = err.message.toLowerCase();
225
+ return msg.includes("429") || msg.includes("rate limit") || msg.includes("too many requests") || msg.includes("500") || msg.includes("502") || msg.includes("503") || msg.includes("504") || msg.includes("econnreset") || msg.includes("etimedout") || msg.includes("enotfound");
226
+ }
227
+ function delay(ms) {
228
+ return new Promise((resolve3) => setTimeout(resolve3, ms));
229
+ }
230
+ var RetryProvider = class {
231
+ name;
232
+ capabilities;
233
+ inner;
234
+ maxRetries;
235
+ initialDelayMs;
236
+ maxDelayMs;
237
+ constructor(inner, options = {}) {
238
+ this.inner = inner;
239
+ this.name = inner.name;
240
+ this.capabilities = inner.capabilities;
241
+ this.maxRetries = options.maxRetries ?? 3;
242
+ this.initialDelayMs = options.initialDelayMs ?? 500;
243
+ this.maxDelayMs = options.maxDelayMs ?? 3e4;
244
+ }
245
+ async complete(request) {
246
+ return this.withRetry(() => this.inner.complete(request));
247
+ }
248
+ async embed(request) {
249
+ const embedFn = this.inner.embed;
250
+ if (!embedFn) throw new Error(`Provider "${this.name}" does not support embeddings`);
251
+ return this.withRetry(() => embedFn.call(this.inner, request));
252
+ }
253
+ async withRetry(fn) {
254
+ let attempt = 0;
255
+ while (true) {
256
+ try {
257
+ return await fn();
258
+ } catch (err) {
259
+ attempt++;
260
+ if (attempt > this.maxRetries || !isRetryable(err)) throw err;
261
+ const base = this.initialDelayMs * 2 ** (attempt - 1);
262
+ const jitter = Math.random() * base * 0.2;
263
+ const wait = Math.min(base + jitter, this.maxDelayMs);
264
+ await delay(wait);
265
+ }
266
+ }
267
+ }
268
+ };
269
+
270
+ // ../core/src/providers/registry.ts
271
+ var factories = /* @__PURE__ */ new Map();
272
+ function registerProvider(type, factory) {
273
+ factories.set(type, factory);
274
+ }
275
+ function createProvider(config) {
276
+ const factory = factories.get(config.type);
277
+ if (!factory) {
278
+ throw new Error(`Unknown provider type "${config.type}". Registered: ${[...factories.keys()].join(", ")}`);
279
+ }
280
+ return factory(config);
281
+ }
282
+ function buildProvider(cfg, allConfigs) {
283
+ let provider = createProvider(cfg);
284
+ if (cfg.retry) {
285
+ provider = new RetryProvider(provider, cfg.retry);
286
+ }
287
+ if (cfg.fallback) {
288
+ const fallbackCfg = allConfigs.find((p) => p.name === cfg.fallback);
289
+ if (!fallbackCfg) {
290
+ throw new Error(`Fallback provider "${cfg.fallback}" not found in config for provider "${cfg.name}"`);
291
+ }
292
+ let fallbackProvider = createProvider(fallbackCfg);
293
+ if (fallbackCfg.retry) {
294
+ fallbackProvider = new RetryProvider(fallbackProvider, fallbackCfg.retry);
295
+ }
296
+ provider = new FallbackProvider([provider, fallbackProvider]);
297
+ }
298
+ return provider;
299
+ }
300
+ function getRegisteredProviders() {
301
+ return [...factories.keys()];
302
+ }
303
+
304
+ // ../core/src/agents/loader.ts
305
+ import { readFile } from "fs/promises";
306
+ import YAML from "yaml";
307
+ async function loadAgent(yamlPath, config, skills) {
308
+ const raw = await readFile(yamlPath, "utf-8");
309
+ const data = YAML.parse(raw);
310
+ const agentConfig = AgentConfigSchema.parse(data);
311
+ const providerName = agentConfig.provider ?? config.defaultProvider;
312
+ const providerConfig = config.providers.find((p) => p.name === providerName);
313
+ if (!providerConfig) {
314
+ throw new Error(
315
+ `Provider "${providerName}" not found in config. Available: ${config.providers.map((p) => p.name).join(", ")}`
316
+ );
317
+ }
318
+ const provider = buildProvider(providerConfig, config.providers);
319
+ const resolvedSkills = (agentConfig.skills ?? []).map((name) => skills.get(name));
320
+ return new Agent(agentConfig, provider, resolvedSkills);
321
+ }
322
+
323
+ // ../core/src/config/loader.ts
324
+ import { readFile as readFile2 } from "fs/promises";
325
+ import { resolve } from "path";
326
+ import YAML2 from "yaml";
327
+ import { ZodError } from "zod";
328
+ function substituteEnvVars(text) {
329
+ return text.replace(/\$\{([^}]+)\}/g, (_, name) => process.env[name] ?? "");
330
+ }
331
+ function formatZodError(err) {
332
+ const lines = err.errors.map((e) => ` \u2022 ${e.path.join(".")}: ${e.message}`);
333
+ return `Invalid omni-ai.yaml configuration:
334
+ ${lines.join("\n")}`;
335
+ }
336
+ async function loadConfig(configPath) {
337
+ const filePath = configPath ?? resolve(process.cwd(), "config", "omni-ai.yaml");
338
+ const raw = await readFile2(filePath, "utf-8");
339
+ const substituted = substituteEnvVars(raw);
340
+ const data = YAML2.parse(substituted);
341
+ try {
342
+ return OmniAiConfigSchema.parse(data);
343
+ } catch (err) {
344
+ if (err instanceof ZodError) {
345
+ throw new Error(formatZodError(err));
346
+ }
347
+ throw err;
348
+ }
349
+ }
350
+
351
+ // ../core/src/skills/registry.ts
352
+ var SkillRegistry = class {
353
+ skills = /* @__PURE__ */ new Map();
354
+ register(skill) {
355
+ this.skills.set(skill.name, skill);
356
+ return this;
357
+ }
358
+ get(name) {
359
+ const skill = this.skills.get(name);
360
+ if (!skill) {
361
+ throw new Error(`Skill "${name}" not found. Available: ${[...this.skills.keys()].join(", ")}`);
362
+ }
363
+ return skill;
364
+ }
365
+ all() {
366
+ return [...this.skills.values()];
367
+ }
368
+ };
369
+
370
+ // ../core/src/bootstrap.ts
371
+ import { readFile as readFile3 } from "fs/promises";
372
+ import { dirname, resolve as resolve2 } from "path";
373
+ import { glob } from "glob";
374
+ import YAML3 from "yaml";
375
+ async function createRuntime(options) {
376
+ const config = await loadConfig(options?.configPath);
377
+ const skills = new SkillRegistry();
378
+ for (const skill of options?.skills ?? []) {
379
+ skills.register(skill);
380
+ }
381
+ const configDir = options?.configPath ? dirname(resolve2(options.configPath)) : resolve2(process.cwd(), "config");
382
+ const agentsBaseDir = resolve2(configDir, "..", config.agentsDir);
383
+ async function resolveAgent(nameOrPath) {
384
+ if (nameOrPath.includes("/") || nameOrPath.endsWith(".yaml")) {
385
+ return loadAgent(resolve2(nameOrPath), config, skills);
386
+ }
387
+ const inlineCfg = config.agents?.find((a) => a.name === nameOrPath);
388
+ if (inlineCfg) {
389
+ const providerName = inlineCfg.provider ?? config.defaultProvider;
390
+ const providerConfig = config.providers.find((p) => p.name === providerName);
391
+ if (!providerConfig) {
392
+ throw new Error(`Provider "${providerName}" not found in config for agent "${nameOrPath}"`);
393
+ }
394
+ const provider = buildProvider(providerConfig, config.providers);
395
+ const resolvedSkills = (inlineCfg.skills ?? []).map((n) => skills.get(n));
396
+ return new Agent(inlineCfg, provider, resolvedSkills);
397
+ }
398
+ const files = await glob("**/*.yaml", { cwd: agentsBaseDir, absolute: true });
399
+ for (const file of files) {
400
+ const raw = await readFile3(file, "utf-8");
401
+ const data = YAML3.parse(raw);
402
+ if (data?.name === nameOrPath) return loadAgent(file, config, skills);
403
+ }
404
+ throw new Error(`Agent "${nameOrPath}" not found in ${agentsBaseDir}`);
405
+ }
406
+ return {
407
+ config,
408
+ skills,
409
+ async run(nameOrPath, input, opts = {}) {
410
+ const agent = await resolveAgent(nameOrPath);
411
+ if (options?.memoryStore && opts.session && !agent.config.memory?.store) {
412
+ agent.config.memory = {
413
+ ...agent.config.memory ?? {},
414
+ store: options.memoryStore
415
+ };
416
+ }
417
+ return agent.run({ ...opts, input });
418
+ },
419
+ async listAgents(agentsDir) {
420
+ const summaries = [];
421
+ for (const a of config.agents ?? []) {
422
+ summaries.push({ name: a.name, description: a.description, path: "(config)" });
423
+ }
424
+ const dir = agentsDir ?? agentsBaseDir;
425
+ const files = await glob("**/*.yaml", { cwd: dir, absolute: true });
426
+ for (const file of files) {
427
+ try {
428
+ const raw = await readFile3(file, "utf-8");
429
+ const data = YAML3.parse(raw);
430
+ if (data?.name && !summaries.find((s) => s.name === data.name)) {
431
+ summaries.push({ name: data.name, description: data.description ?? "", path: file });
432
+ }
433
+ } catch {
434
+ }
435
+ }
436
+ return summaries.sort((a, b) => a.name.localeCompare(b.name));
437
+ }
438
+ };
439
+ }
440
+
441
+ // ../core/src/parallel.ts
442
+ async function parallel(runtime, opts) {
443
+ const runOpts = {
444
+ session: opts.session
445
+ };
446
+ const settled = await Promise.allSettled(
447
+ opts.agents.map((name) => {
448
+ const agentOpts = {
449
+ ...runOpts,
450
+ input: opts.input,
451
+ ...opts.onToken ? { onToken: (chunk) => opts.onToken?.(name, chunk) } : {}
452
+ };
453
+ return runtime.run(name, opts.input, agentOpts);
454
+ })
455
+ );
456
+ const results = {};
457
+ let totalInput = 0;
458
+ let totalOutput = 0;
459
+ for (let i = 0; i < opts.agents.length; i++) {
460
+ const name = opts.agents[i];
461
+ const outcome = settled[i];
462
+ if (outcome.status === "fulfilled") {
463
+ results[name] = outcome.value;
464
+ totalInput += outcome.value.usage?.inputTokens ?? 0;
465
+ totalOutput += outcome.value.usage?.outputTokens ?? 0;
466
+ } else {
467
+ results[name] = {
468
+ error: outcome.reason instanceof Error ? outcome.reason.message : String(outcome.reason)
469
+ };
470
+ }
471
+ }
472
+ return { results, usage: { inputTokens: totalInput, outputTokens: totalOutput } };
473
+ }
474
+
475
+ export {
476
+ composeMiddleware,
477
+ contentToString,
478
+ Agent,
479
+ RetryConfigSchema,
480
+ ProviderConfigSchema,
481
+ AgentConfigSchema,
482
+ ScaffoldPathsSchema,
483
+ OmniAiConfigSchema,
484
+ FallbackProvider,
485
+ RetryProvider,
486
+ registerProvider,
487
+ createProvider,
488
+ buildProvider,
489
+ getRegisteredProviders,
490
+ loadAgent,
491
+ loadConfig,
492
+ SkillRegistry,
493
+ createRuntime,
494
+ parallel
495
+ };
@@ -0,0 +1,163 @@
1
+ // ../skills/src/git/git-commit-message.ts
2
+ import { resolve } from "path";
3
+ import { z } from "zod";
4
+
5
+ // ../skills/src/git/shared.ts
6
+ import { spawn } from "child_process";
7
+ function runGit(args, cwd) {
8
+ return new Promise((resolve5, reject) => {
9
+ const proc = spawn("git", args, { cwd, shell: false });
10
+ const stdout = [];
11
+ const stderr = [];
12
+ proc.stdout.on("data", (chunk) => stdout.push(chunk));
13
+ proc.stderr.on("data", (chunk) => stderr.push(chunk));
14
+ proc.on("close", (code) => {
15
+ if (code !== 0) {
16
+ reject(new Error(Buffer.concat(stderr).toString().trim() || `git ${args[0]} exited with code ${code}`));
17
+ } else {
18
+ resolve5(Buffer.concat(stdout).toString());
19
+ }
20
+ });
21
+ proc.on("error", reject);
22
+ });
23
+ }
24
+
25
+ // ../skills/src/git/git-commit-message.ts
26
+ var InputSchema = z.object({
27
+ cwd: z.string().default(".").describe("Repository root directory"),
28
+ staged: z.boolean().default(true).describe("Use staged diff (true) or full working-tree diff (false)"),
29
+ hint: z.string().optional().describe("Optional free-text hint passed to the LLM, e.g. 'fix', 'feat', 'refactor'")
30
+ });
31
+ var SYSTEM = `You are an expert software engineer who writes concise, conventional commit messages.
32
+ Rules:
33
+ - Follow Conventional Commits: <type>(<scope>): <subject>
34
+ - Subject line \u2264 72 chars, imperative mood, no trailing period
35
+ - If changes span multiple concerns, add a short bullet body after a blank line
36
+ - Output ONLY the commit message \u2014 no explanation, no markdown fences`;
37
+ var gitCommitMessageSkill = {
38
+ name: "git-commit-message",
39
+ description: "Generate a conventional commit message for the current staged (or working-tree) changes using the configured LLM provider. Returns a ready-to-use commit message string.",
40
+ async execute(input, ctx) {
41
+ const { cwd, staged, hint } = InputSchema.parse(input);
42
+ const dir = resolve(cwd);
43
+ const diffArgs = ["diff"];
44
+ if (staged) diffArgs.push("--cached");
45
+ const diff = await runGit(diffArgs, dir);
46
+ if (!diff.trim()) {
47
+ return { message: "chore: no changes staged" };
48
+ }
49
+ const promptParts = [hint ? `Hint from the developer: ${hint}` : null, "--- GIT DIFF ---", diff.slice(0, 12e3)].filter(Boolean).join("\n");
50
+ const response = await ctx.provider.complete({
51
+ systemPrompt: SYSTEM,
52
+ messages: [{ role: "user", content: promptParts }],
53
+ temperature: 0.2,
54
+ maxTokens: 256
55
+ });
56
+ return { message: response.content.trim() };
57
+ }
58
+ };
59
+
60
+ // ../skills/src/git/git-diff.ts
61
+ import { resolve as resolve2 } from "path";
62
+ import { z as z2 } from "zod";
63
+ var InputSchema2 = z2.object({
64
+ cwd: z2.string().default(".").describe("Repository root directory"),
65
+ staged: z2.boolean().default(false).describe("Show staged (cached) diff instead of working-tree diff"),
66
+ file: z2.string().optional().describe("Limit diff to a specific file path"),
67
+ base: z2.string().optional().describe("Base ref to diff from (e.g. 'main', 'HEAD~1')")
68
+ });
69
+ var gitDiffSkill = {
70
+ name: "git-diff",
71
+ description: "Return the unified diff of uncommitted changes (or staged changes). Use this to understand what code changed before writing a commit message or performing a code review.",
72
+ async execute(input) {
73
+ const { cwd, staged, file, base } = InputSchema2.parse(input);
74
+ const dir = resolve2(cwd);
75
+ const diffArgs = ["diff"];
76
+ if (staged) diffArgs.push("--cached");
77
+ if (base) diffArgs.push(base);
78
+ if (file) diffArgs.push("--", file);
79
+ const nameArgs = ["diff", "--name-only"];
80
+ if (staged) nameArgs.push("--cached");
81
+ if (base) nameArgs.push(base);
82
+ if (file) nameArgs.push("--", file);
83
+ const [diff, names] = await Promise.all([runGit(diffArgs, dir), runGit(nameArgs, dir)]);
84
+ const changedFiles = names.split("\n").map((l) => l.trim()).filter(Boolean);
85
+ return { diff, changedFiles };
86
+ }
87
+ };
88
+
89
+ // ../skills/src/git/git-log.ts
90
+ import { resolve as resolve3 } from "path";
91
+ import { z as z3 } from "zod";
92
+ var InputSchema3 = z3.object({
93
+ cwd: z3.string().default(".").describe("Repository root directory"),
94
+ maxEntries: z3.number().int().positive().default(10).describe("Maximum number of commits to return"),
95
+ branch: z3.string().optional().describe("Branch or ref to read log from (defaults to HEAD)"),
96
+ since: z3.string().optional().describe("Show commits more recent than this date, e.g. '2 weeks ago'")
97
+ });
98
+ var SEP = "";
99
+ var FORMAT = [`%H${SEP}%h${SEP}%an${SEP}%ai${SEP}%s`].join("");
100
+ var gitLogSkill = {
101
+ name: "git-log",
102
+ description: "Return recent commit history with hash, author, date and subject. Use this to understand recent changes, find the last stable commit, or generate release notes.",
103
+ async execute(input) {
104
+ const { cwd, maxEntries, branch, since } = InputSchema3.parse(input);
105
+ const dir = resolve3(cwd);
106
+ const args = ["log", `--format=${FORMAT}`, `-n`, String(maxEntries)];
107
+ if (since) args.push(`--since=${since}`);
108
+ if (branch) args.push(branch);
109
+ const raw = await runGit(args, dir);
110
+ const commits = raw.split("\n").filter(Boolean).map((line) => {
111
+ const [hash, shortHash, author, date, ...rest] = line.split(SEP);
112
+ return { hash, shortHash, author, date, message: rest.join(SEP) };
113
+ });
114
+ return { commits };
115
+ }
116
+ };
117
+
118
+ // ../skills/src/git/git-status.ts
119
+ import { resolve as resolve4 } from "path";
120
+ import { z as z4 } from "zod";
121
+ var InputSchema4 = z4.object({
122
+ cwd: z4.string().default(".").describe("Repository root directory (defaults to process.cwd())")
123
+ });
124
+ function parsePorcelain(raw) {
125
+ const staged = [];
126
+ const unstaged = [];
127
+ const untracked = [];
128
+ for (const line of raw.split("\n")) {
129
+ if (!line || line.startsWith("##")) continue;
130
+ const x = line[0];
131
+ const y = line[1];
132
+ const path = line.slice(3);
133
+ if (x === "?" && y === "?") {
134
+ untracked.push(path);
135
+ } else {
136
+ if (x !== " " && x !== "?") staged.push({ path, status: x });
137
+ if (y !== " " && y !== "?") unstaged.push({ path, status: y });
138
+ }
139
+ }
140
+ return { staged, unstaged, untracked };
141
+ }
142
+ var gitStatusSkill = {
143
+ name: "git-status",
144
+ description: "Return the current git working-tree status: staged changes, unstaged modifications, untracked files and the active branch. Use this before generating a commit message or reviewing pending changes.",
145
+ async execute(input) {
146
+ const { cwd } = InputSchema4.parse(input);
147
+ const dir = resolve4(cwd);
148
+ const [porcelain, branchRaw] = await Promise.all([
149
+ runGit(["status", "--porcelain", "-b"], dir),
150
+ runGit(["rev-parse", "--abbrev-ref", "HEAD"], dir)
151
+ ]);
152
+ const branch = branchRaw.trim();
153
+ const { staged, unstaged, untracked } = parsePorcelain(porcelain);
154
+ return { branch, staged, unstaged, untracked };
155
+ }
156
+ };
157
+
158
+ export {
159
+ gitCommitMessageSkill,
160
+ gitDiffSkill,
161
+ gitLogSkill,
162
+ gitStatusSkill
163
+ };