@ztimson/ai-agents 0.1.2 → 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -37,9 +37,12 @@ AI-powered Gitea agents for automating reviews and administration
37
37
 
38
38
  ## About
39
39
 
40
- Only supports Gitea
40
+ AI-powered Gitea agents for automating administration of code repos:
41
+ - Code Review
42
+ - Release Notes
43
+ - Ticket Refinement
41
44
 
42
- Use LLM models from Anthropic, OpenAI, or Ollama to automate ticket refinement, code reviews, and releases.
45
+ Only supports Gitea, copy the relevant `.github/workflows/______.yml` action to start using it
43
46
 
44
47
  ### Built With
45
48
  [![Docker](https://img.shields.io/badge/Docker-384d54?style=for-the-badge&logo=docker)](https://docker.com/)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ztimson/ai-agents",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "description": "AI agents",
5
5
  "keywords": ["ai", "review"],
6
6
  "author": "ztimson",
@@ -8,6 +8,7 @@
8
8
  "type": "module",
9
9
  "bin": {
10
10
  "refine": "./src/refine.mjs",
11
+ "release": "./src/release.mjs",
11
12
  "review": "./src/review.mjs"
12
13
  },
13
14
  "dependencies": {
@@ -0,0 +1,90 @@
1
+ #!/usr/bin/env node
2
+ import {Ai} from '@ztimson/ai';
3
+ import * as dotenv from 'dotenv';
4
+ import {$} from '@ztimson/node-utils';
5
+
6
+ dotenv.config({quiet: true, debug: false});
7
+ dotenv.config({path: '.env.local', override: true, quiet: true, debug: false});
8
+
9
+ (async () => {
10
+ const git = process.env['GIT_HOST'],
11
+ owner = process.env['GIT_OWNER'],
12
+ repo = process.env['GIT_REPO'],
13
+ auth = process.env['GIT_TOKEN'],
14
+ milestone = process.env['MILESTONE'],
15
+ host = process.env['AI_HOST'] || 'ollama',
16
+ model = process.env['AI_MODEL'] || 'llama3',
17
+ token = process.env['AI_TOKEN'];
18
+
19
+ // Get milestone info
20
+ const milestoneData = await fetch(`${git}/api/v1/repos/${owner}/${repo}/milestones/${milestone}`, {
21
+ headers: {'Authorization': `token ${auth}`}
22
+ }).then(resp => resp.ok ? resp.json() : {});
23
+
24
+ // Get closed issues
25
+ const issues = await fetch(`${git}/api/v1/repos/${owner}/${repo}/issues?state=closed&milestone=${milestone}`, {
26
+ headers: {'Authorization': `token ${auth}`}
27
+ }).then(resp => resp.ok ? resp.json() : []);
28
+
29
+ // Get closed PRs
30
+ const prs = await fetch(`${git}/api/v1/repos/${owner}/${repo}/pulls?state=closed&milestone=${milestone}`, {
31
+ headers: {'Authorization': `token ${auth}`}
32
+ }).then(resp => resp.ok ? resp.json() : []);
33
+
34
+ // Get latest tag
35
+ const latestTag = await $`git describe --tags --abbrev=0`.text();
36
+ if(!latestTag) {
37
+ console.error('At least one Git tag is required');
38
+ process.exit(1);
39
+ }
40
+
41
+ // Build context
42
+ let context = `Milestone: ${milestoneData.title}
43
+ Description:
44
+ \`\`\`md
45
+ ${milestoneData.description || ''}
46
+ \`\`\`
47
+
48
+ PRs:
49
+ ${prs.map(pr => `- ${pr.title}\n${pr.body || ''}`).join('\n\n')}
50
+
51
+ Issues:
52
+ ${issues.filter(i => !i.pull_request).map(i => `- ${i.title}\n${i.body || ''}`).join('\n\n')}`;
53
+
54
+ // Generate release notes
55
+ let options = {ollama: {model, host}};
56
+ if(host === 'anthropic') options = {anthropic: {model, token}};
57
+ else if(host === 'openai') options = {openAi: {model, token}};
58
+
59
+ const ai = new Ai({
60
+ ...options,
61
+ model: [host, model],
62
+ system: `You are a release notes writer. Format the provided milestone info, PRs, and issues into clean, organized release notes. Use markdown with sections like "Features", "Bug Fixes", "Breaking Changes", etc. Be concise but informative. Include issue/PR numbers in format #123.`
63
+ });
64
+
65
+ const body = (await ai.chat(context)).pop()?.content;
66
+ if(!body) {
67
+ console.error('No release notes were generated');
68
+ process.exit(1);
69
+ }
70
+
71
+ // Create release
72
+ const name = latestTag.trim();
73
+ await fetch(`${git}/api/v1/repos/${owner}/${repo}/releases`, {
74
+ method: 'POST',
75
+ headers: {
76
+ 'Authorization': `token ${auth}`,
77
+ 'Content-Type': 'application/json'
78
+ },
79
+ body: JSON.stringify({
80
+ name,
81
+ tag_name: name,
82
+ body
83
+ })
84
+ }).then(resp => { if(!resp.ok) throw new Error(resp.status + ' ' + resp.statusText) });
85
+
86
+ console.log(`Title: ${name}\nDescription:\n${body}`);
87
+ })().catch(err => {
88
+ console.error(`Error: ${err.message || err.toString()}`);
89
+ process.exit(1);
90
+ });
package/src/review.mjs CHANGED
@@ -25,7 +25,7 @@ dotenv.config({path: '.env.local', override: true, quiet: true, debug: false});
25
25
  model = process.env['AI_MODEL'],
26
26
  token = process.env['AI_TOKEN'];
27
27
 
28
- console.log(`Reviewing: ${root}\n`);
28
+ console.log(`Reviewing: ${root}`);
29
29
  const info = await fetch(`${git}/api/v1/repos/${owner}/${repo}/pulls/${pr}`)
30
30
  .then(async resp => {
31
31
  if(resp.ok) return resp.json();